Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
7283737f8e | |||
|
4b652aac8d | ||
|
09d4686437 | ||
|
425113a0d7 | ||
|
ca2af73a2c | ||
|
5d3ce0ff12 | ||
|
3d39d38287 | ||
|
b5c8abcb56 | ||
|
b0712fac25 | ||
|
b0d73eaccd | ||
|
ea86e944cf | ||
|
4cba3c47d9 | ||
|
af0167a44b | ||
|
92b1551284 | ||
|
e5af2418b0 | ||
|
4ad326a9af | ||
|
2418b0caa3 | ||
|
37034552e4 | ||
|
f1257d99b6 | ||
|
095c5cd81c | ||
|
1d3938a1dd | ||
|
727dc88fb1 | ||
|
0d94b22820 | ||
|
929e5cb543 | ||
|
c8414d2e0b | ||
|
07ef5cf755 | ||
|
af61b6a96b | ||
|
dc8c32e678 | ||
|
c1c9c881f7 | ||
|
47047b9c65 | ||
|
6b1b64a05d | ||
|
f128cb7e6d | ||
|
89680d3754 | ||
|
28ff4ea2d9 | ||
|
b923963f44 | ||
|
1a37474eba | ||
|
374d2fe59c | ||
|
d8e5dcff50 | ||
|
6e08b61cf5 | ||
|
da5cea5321 | ||
|
ef4834517c | ||
|
8292b848d2 | ||
|
ef3e693e48 | ||
|
0101e2437e | ||
|
8df8c531e5 | ||
|
d5c2d9277c | ||
|
ba8d25a5ea | ||
|
da879d3c68 |
@ -2,9 +2,9 @@
|
||||
"name": "webman/admin",
|
||||
"type": "project",
|
||||
"license": "MIT",
|
||||
"description": "Webman Admin",
|
||||
"description": "基于Webman官方的Admin修改",
|
||||
"require": {
|
||||
"workerman/webman-framework": "^1.4",
|
||||
"workerman/webman-framework": ">=1.4",
|
||||
"illuminate/database": ">=7.30",
|
||||
"illuminate/pagination": ">=7.30",
|
||||
"illuminate/events": ">=7.30",
|
||||
|
@ -1,13 +1,14 @@
|
||||
<?php
|
||||
namespace plugin\admin\api;
|
||||
|
||||
use ReflectionException;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use Webman\MiddlewareInterface;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
/**
|
||||
* 对外提供的webman-admin鉴权中间件
|
||||
* 对外提供的鉴权中间件
|
||||
*/
|
||||
class Middleware implements MiddlewareInterface
|
||||
{
|
||||
@ -16,7 +17,7 @@ class Middleware implements MiddlewareInterface
|
||||
* @param Request $request
|
||||
* @param callable $handler
|
||||
* @return Response
|
||||
* @throws \ReflectionException
|
||||
* @throws ReflectionException
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function process(Request $request, callable $handler): Response
|
||||
@ -30,7 +31,20 @@ class Middleware implements MiddlewareInterface
|
||||
if ($request->expectsJson()) {
|
||||
$response = json(['code' => $code, 'msg' => $msg, 'type' => 'error']);
|
||||
} else {
|
||||
$response = \response($msg, 401);
|
||||
if ($code === 401) {
|
||||
$response = response(<<<EOF
|
||||
<script>
|
||||
if (self !== top) {
|
||||
parent.location.reload();
|
||||
}
|
||||
</script>
|
||||
EOF
|
||||
);
|
||||
} else {
|
||||
$request->app = '';
|
||||
$request->plugin = 'admin';
|
||||
$response = view('common/error/403')->withStatus(403);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
|
||||
@ -38,4 +52,4 @@ class Middleware implements MiddlewareInterface
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace plugin\admin\app\common;
|
||||
|
||||
use plugin\admin\app\common\Util;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class Layui
|
||||
@ -124,6 +125,31 @@ EOF;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入框模糊查询
|
||||
* @param $options
|
||||
* @return void
|
||||
*/
|
||||
public function inputLike($options)
|
||||
{
|
||||
[$label, $field, $value, $props, $verify_string, $required_string, $class] = $this->options($options);
|
||||
$type = $props['type'] ?? 'text';
|
||||
|
||||
$this->htmlContent .= <<<EOF
|
||||
|
||||
<div class="layui-form-item">
|
||||
$label
|
||||
<div class="$class">
|
||||
<div class="layui-input-block">
|
||||
<input type="hidden" autocomplete="off" name="{$field}[]" value="like" class="layui-input inline-block">
|
||||
<input type="$type" autocomplete="off" name="{$field}[]" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
@ -138,6 +164,17 @@ EOF;
|
||||
$this->inputRange($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字输入框模糊查询
|
||||
* @param $options
|
||||
* @return void
|
||||
*/
|
||||
public function inputNumberLike($options)
|
||||
{
|
||||
$options['props']['type'] = 'number';
|
||||
$this->inputLike($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码输入框
|
||||
* @param $options
|
||||
@ -170,6 +207,58 @@ EOF;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 富文本
|
||||
* @param $options
|
||||
* @return void
|
||||
*/
|
||||
public function richText($options)
|
||||
{
|
||||
[$label, $field, $value, $props, $verify_string, $required_string, $class] = $this->options($options);
|
||||
|
||||
$placeholder_string = !empty($props['placeholder']) ? ' placeholder="'.$props['placeholder'].'"' : '';
|
||||
$disabled_string = !empty($props['disabled']) ? ' disabled' : '';
|
||||
$id = $field;
|
||||
|
||||
$this->htmlContent .= <<<EOF
|
||||
|
||||
<div class="layui-form-item">
|
||||
$label
|
||||
<div class="$class">
|
||||
<textarea id="$id" name="$field"$required_string$verify_string$placeholder_string$disabled_string class="layui-textarea">$value</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
EOF;
|
||||
|
||||
$options_string = '';
|
||||
if (!isset($props['images_upload_url'])) {
|
||||
$props['images_upload_url'] = '/app/admin/upload/image';
|
||||
}
|
||||
foreach ($props as $key => $item) {
|
||||
if (is_array($item)) {
|
||||
$item = json_encode($item, JSON_UNESCAPED_UNICODE);
|
||||
$options_string .= "\n $key: $item,";
|
||||
} else {
|
||||
$options_string .= "\n $key: \"$item\",";
|
||||
}
|
||||
}
|
||||
$this->jsContent .= <<<EOF
|
||||
|
||||
// 字段 {$options['label']} $field
|
||||
layui.use(["tinymce"], function() {
|
||||
var tinymce = layui.tinymce
|
||||
var edit = tinymce.render({
|
||||
elem: "#$id",$options_string
|
||||
});
|
||||
edit.on("blur", function(){
|
||||
layui.$("#$id").val(edit.getContent());
|
||||
});
|
||||
});
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
@ -612,6 +701,9 @@ EOF;
|
||||
$default_value_string = isset($props['initValue']) && $props['initValue'] != '' ? $props['initValue'] : $value;
|
||||
$url = $props['url'] ?? '';
|
||||
$options_string = '';
|
||||
if (isset($props['lay-verify'])) {
|
||||
$props['layVerify'] = $props['lay-verify'];
|
||||
}
|
||||
unset($props['lay-verify'], $props['url']);
|
||||
foreach ($props as $key => $item) {
|
||||
if (is_array($item)) {
|
||||
@ -673,7 +765,7 @@ EOF;
|
||||
<div class="layui-form-item">
|
||||
$select_label
|
||||
<div class="$class">
|
||||
<div name="$field" id="$id"$verify_string$required_string value="$default_value_string" ></div>
|
||||
<div name="$field" id="$id"$required_string value="$default_value_string" ></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -707,6 +799,7 @@ EOF;
|
||||
$field = $info['field'];
|
||||
$default = $columns[$key]['default'];
|
||||
$control = strtolower($info['control']);
|
||||
$auto_increment = $columns[$key]['auto_increment'];
|
||||
// 搜索框里上传组件替换为input
|
||||
if ($type == 'search' && in_array($control, ['upload', 'uploadimg'])) {
|
||||
$control = 'input';
|
||||
@ -715,20 +808,34 @@ EOF;
|
||||
|
||||
$props = Util::getControlProps($control, $info['control_args']);
|
||||
// 增加修改记录验证必填项
|
||||
if ($filter == 'form_show' && !isset($props['lay-verify']) && !$columns[$key]['nullable'] && $default === null && ($field !== 'password' || $type === 'insert')) {
|
||||
$props['lay-verify'] = 'required';
|
||||
if ($filter == 'form_show' && !$columns[$key]['nullable'] && $default === null && ($field !== 'password' || $type === 'insert')) {
|
||||
if (!isset($props['lay-verify'])) {
|
||||
$props['lay-verify'] = 'required';
|
||||
// 非类似字符串类型不允许传空
|
||||
} elseif (!in_array($columns[$key]['type'], ['string', 'text', 'mediumText', 'longText', 'char', 'binary', 'json'])
|
||||
&& strpos($props['lay-verify'], 'required') === false) {
|
||||
$props['lay-verify'] = 'required|' . $props['lay-verify'];
|
||||
}
|
||||
}
|
||||
// 增加记录显示默认值
|
||||
if ($type === 'insert' && !isset($props['value']) && $default !== null) {
|
||||
$props['value'] = $default;
|
||||
}
|
||||
// 表单不显示主键
|
||||
if ($filter == 'form_show' && $primary_key && $field == $primary_key) {
|
||||
// 主键是自增字段或者表单是更新类型不显示主键
|
||||
if ($primary_key && $field == $primary_key && (($type == 'insert' && $auto_increment) || $type == 'update')) {
|
||||
continue;
|
||||
}
|
||||
// 范围查询
|
||||
if ($type == 'search' && $info['search_type'] == 'between' && method_exists($form, "{$control}Range")) {
|
||||
$control = "{$control}Range";
|
||||
// 查询类型
|
||||
if ($type == 'search') {
|
||||
if ($info['search_type'] == 'between' && method_exists($form, "{$control}Range")) {
|
||||
$control = "{$control}Range";
|
||||
} elseif ($info['search_type'] == 'like' && method_exists($form, "{$control}Like")) {
|
||||
$control = "{$control}Like";
|
||||
}
|
||||
}
|
||||
// 查询类型移除lay-verify
|
||||
if ($type == 'search' && !empty($props['lay-verify'])) {
|
||||
$props['lay-verify'] = '';
|
||||
}
|
||||
|
||||
$options = [
|
||||
|
@ -2,12 +2,15 @@
|
||||
|
||||
namespace plugin\admin\app\common;
|
||||
|
||||
use process\Monitor;
|
||||
use Throwable;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Schema\Builder;
|
||||
use plugin\admin\app\model\Option;
|
||||
use support\exception\BusinessException;
|
||||
use support\Db;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
|
||||
class Util
|
||||
{
|
||||
@ -312,6 +315,8 @@ class Util
|
||||
'char' => ['Input'],
|
||||
|
||||
'binary' => ['Input'],
|
||||
|
||||
'json' => ['input']
|
||||
];
|
||||
}
|
||||
|
||||
@ -370,7 +375,7 @@ class Util
|
||||
{
|
||||
Util::checkTableName($table);
|
||||
$database = config('database.connections')['plugin.admin.mysql']['database'];
|
||||
$schema_raw = $section !== 'table' ? Util::db()->select("select * from information_schema.COLUMNS where TABLE_SCHEMA = '$database' and table_name = '$table'") : [];
|
||||
$schema_raw = $section !== 'table' ? Util::db()->select("select * from information_schema.COLUMNS where TABLE_SCHEMA = '$database' and table_name = '$table' order by ORDINAL_POSITION") : [];
|
||||
$forms = [];
|
||||
$columns = [];
|
||||
foreach ($schema_raw as $item) {
|
||||
@ -519,7 +524,7 @@ class Util
|
||||
|
||||
|
||||
/**
|
||||
* reload webman (不支持windows)
|
||||
* Reload webman
|
||||
* @return bool
|
||||
*/
|
||||
public static function reloadWebman()
|
||||
@ -529,8 +534,34 @@ class Util
|
||||
posix_kill(posix_getppid(), SIGUSR1);
|
||||
return true;
|
||||
} catch (Throwable $e) {}
|
||||
} else {
|
||||
Timer::add(1, function () {
|
||||
Worker::stopAll();
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Pause file monitor
|
||||
* @return void
|
||||
*/
|
||||
public static function pauseFileMonitor()
|
||||
{
|
||||
if (method_exists(Monitor::class, 'pause')) {
|
||||
Monitor::pause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume file monitor
|
||||
* @return void
|
||||
*/
|
||||
public static function resumeFileMonitor()
|
||||
{
|
||||
if (method_exists(Monitor::class, 'resume')) {
|
||||
Monitor::resume();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -129,11 +129,19 @@ class Crud extends Base
|
||||
$model = $this->model;
|
||||
foreach ($where as $column => $value) {
|
||||
if (is_array($value)) {
|
||||
if (in_array($value[0], ['>', '=', '<', '<>', 'like'])) {
|
||||
if ($value[0] === 'like') {
|
||||
$model = $model->where($column, 'like', "%$value[1]%");
|
||||
} elseif (in_array($value[0], ['>', '=', '<', '<>', 'not like'])) {
|
||||
$model = $model->where($column, $value[0], $value[1]);
|
||||
} elseif ($value[0] == 'in') {
|
||||
$model = $model->whereIn($column, $value[1]);
|
||||
} else {
|
||||
} elseif ($value[0] == 'not in') {
|
||||
$model = $model->whereNotIn($column, $value[1]);
|
||||
} elseif ($value[0] == 'null') {
|
||||
$model = $model->whereNull($column, $value[1]);
|
||||
} elseif ($value[0] == 'not null') {
|
||||
$model = $model->whereNotNull($column, $value[1]);
|
||||
} elseif ($value[0] !== '' || $value[1] !== '') {
|
||||
$model = $model->whereBetween($column, $value);
|
||||
}
|
||||
} else {
|
||||
@ -268,7 +276,7 @@ class Crud extends Base
|
||||
protected function inputFilter(array $data): array
|
||||
{
|
||||
$table = config('plugin.admin.database.connections.mysql.prefix') . $this->model->getTable();
|
||||
$allow_column = Util::db()->select("desc `$table`");
|
||||
$allow_column = $this->model->getConnection()->select("desc `$table`");
|
||||
if (!$allow_column) {
|
||||
throw new BusinessException('表不存在', 2);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ namespace plugin\admin\app\controller;
|
||||
|
||||
use plugin\admin\app\common\Util;
|
||||
use plugin\admin\app\model\User;
|
||||
use support\Db;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
@ -61,7 +60,7 @@ class IndexController
|
||||
// 总用户数
|
||||
$user_count = User::count();
|
||||
// mysql版本
|
||||
$version = Db::select('select VERSION() as version');
|
||||
$version = Util::db()->select('select VERSION() as version');
|
||||
$mysql_version = $version[0]->version ?? 'unknown';
|
||||
|
||||
$day7_detail = [];
|
||||
|
@ -198,15 +198,17 @@ EOF;
|
||||
if ($password != $password_confirm) {
|
||||
return $this->json(1, '两次密码不一致');
|
||||
}
|
||||
if (Admin::first()) {
|
||||
return $this->json(1, '后台已经安装完毕,无法通过此页面创建管理员');
|
||||
}
|
||||
if (!is_file($config_file = base_path() . '/plugin/admin/config/database.php')) {
|
||||
return $this->json(1, '请先完成第一步数据库配置');
|
||||
}
|
||||
$config = include $config_file;
|
||||
$connection = $config['connections']['mysql'];
|
||||
$pdo = $this->getPdo($connection['host'], $connection['username'], $connection['password'], $connection['port'], $connection['database']);
|
||||
|
||||
if ($pdo->query('select * from `wa_admins`')->fetchAll()) {
|
||||
return $this->json(1, '后台已经安装完毕,无法通过此页面创建管理员');
|
||||
}
|
||||
|
||||
$smt = $pdo->prepare("insert into `wa_admins` (`username`, `password`, `nickname`, `created_at`, `updated_at`) values (:username, :password, :nickname, :created_at, :updated_at)");
|
||||
$time = date('Y-m-d H:i:s');
|
||||
$data = [
|
||||
@ -379,6 +381,7 @@ EOF;
|
||||
}
|
||||
$params = [
|
||||
\PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8mb4",
|
||||
\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
|
||||
\PDO::ATTR_EMULATE_PREPARES => false,
|
||||
\PDO::ATTR_TIMEOUT => 5,
|
||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||
|
@ -5,10 +5,18 @@ namespace plugin\admin\app\controller;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use plugin\admin\app\common\Util;
|
||||
use plugin\admin\app\controller\Base;
|
||||
use process\Monitor;
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use ZIPARCHIVE;
|
||||
use function array_diff;
|
||||
use function ini_get;
|
||||
use function scandir;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PATH_SEPARATOR;
|
||||
|
||||
class PluginController extends Base
|
||||
{
|
||||
@ -20,11 +28,14 @@ class PluginController extends Base
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @return string
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function index(Request $request): Response
|
||||
public function index(Request $request)
|
||||
{
|
||||
return view('plugin/index');
|
||||
$client = $this->httpClient();
|
||||
$response = $client->get("/webman-admin/apps");
|
||||
return (string)$response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,14 +46,7 @@ class PluginController extends Base
|
||||
*/
|
||||
public function list(Request $request): Response
|
||||
{
|
||||
$installed = [];
|
||||
clearstatcache();
|
||||
$plugin_names = \array_diff(\scandir(base_path() . '/plugin/'), array('.', '..')) ?: [];
|
||||
foreach ($plugin_names as $plugin_name) {
|
||||
if (is_dir(base_path() . "/plugin/$plugin_name") && $version = $this->getPluginVersion($plugin_name)) {
|
||||
$installed[$plugin_name] = $version;
|
||||
}
|
||||
}
|
||||
$installed = $this->getLocalPlugins();
|
||||
|
||||
$client = $this->httpClient();
|
||||
$query = $request->get();
|
||||
@ -57,75 +61,49 @@ class PluginController extends Base
|
||||
return $this->json(1, '获取数据出错');
|
||||
}
|
||||
$disabled = is_phar();
|
||||
foreach ($data['result']['items'] as $key => $item) {
|
||||
foreach ($data['data']['items'] as $key => $item) {
|
||||
$name = $item['name'];
|
||||
$data['result']['items'][$key]['installed'] = $installed[$name] ?? 0;
|
||||
$data['result']['items'][$key]['disabled'] = $disabled;
|
||||
$data['data']['items'][$key]['installed'] = $installed[$name] ?? 0;
|
||||
$data['data']['items'][$key]['disabled'] = $disabled;
|
||||
}
|
||||
$items = $data['result']['items'];
|
||||
$count = $data['result']['total'];
|
||||
return json(['code' =>0, 'msg' => 'ok', 'data' => $items, 'count' => $count]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 摘要
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function schema(Request $request): Response
|
||||
{
|
||||
$client = $this->httpClient();
|
||||
$response = $client->get('/api/app/schema', ['query' => $request->get()]);
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
$result = $data['result'];
|
||||
foreach ($result as &$item) {
|
||||
$item['field'] = $item['field'] ?? $item['dataIndex'];
|
||||
unset($item['dataIndex']);
|
||||
}
|
||||
return $this->json(0, 'ok', $result);
|
||||
$items = $data['data']['items'];
|
||||
$count = $data['data']['total'];
|
||||
return json(['code' => 0, 'msg' => 'ok', 'data' => $items, 'count' => $count]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws GuzzleException
|
||||
* @throws GuzzleException|BusinessException
|
||||
*/
|
||||
public function install(Request $request): Response
|
||||
{
|
||||
$name = $request->post('name');
|
||||
$version = $request->post('version');
|
||||
$installed_version = $this->getPluginVersion($name);
|
||||
$host = $request->host(true);
|
||||
if (!$name || !$version) {
|
||||
return $this->json(1, '缺少参数');
|
||||
}
|
||||
|
||||
$user = session('app-plugin-user');
|
||||
if (!$user) {
|
||||
return $this->json(0, '请登录', [
|
||||
'code' => 401,
|
||||
'msg' => '请登录'
|
||||
]);
|
||||
return $this->json(-1, '请登录');
|
||||
}
|
||||
|
||||
// 获取下载zip文件url
|
||||
$data = $this->getDownloadUrl($name, $user['uid'], $host, $version);
|
||||
if ($data['code'] == -1) {
|
||||
return $this->json(0, '请登录', [
|
||||
'code' => 401,
|
||||
'msg' => '请登录'
|
||||
]);
|
||||
$data = $this->getDownloadUrl($name, $version);
|
||||
if ($data['code'] != 0) {
|
||||
return $this->json($data['code'], $data['msg'], $data['data'] ?? []);
|
||||
}
|
||||
|
||||
// 下载zip文件
|
||||
$base_path = base_path() . "/plugin/$name";
|
||||
$zip_file = "$base_path.zip";
|
||||
$extract_to = base_path() . '/plugin/';
|
||||
$this->downloadZipFile($data['result']['url'], $zip_file);
|
||||
$this->downloadZipFile($data['data']['url'], $zip_file);
|
||||
|
||||
$has_zip_archive = class_exists(\ZipArchive::class, false);
|
||||
$has_zip_archive = class_exists(ZipArchive::class, false);
|
||||
if (!$has_zip_archive) {
|
||||
$cmd = $this->getUnzipCmd($zip_file, $extract_to);
|
||||
if (!$cmd) {
|
||||
@ -136,40 +114,45 @@ class PluginController extends Base
|
||||
}
|
||||
}
|
||||
|
||||
// 解压zip到plugin目录
|
||||
if ($has_zip_archive) {
|
||||
$zip = new \ZipArchive;
|
||||
$zip->open($zip_file, \ZIPARCHIVE::CHECKCONS);
|
||||
}
|
||||
|
||||
$context = null;
|
||||
$install_class = "\\plugin\\$name\\api\\Install";
|
||||
if ($installed_version) {
|
||||
// 执行beforeUpdate
|
||||
if (class_exists($install_class) && method_exists($install_class, 'beforeUpdate')) {
|
||||
$context = call_user_func([$install_class, 'beforeUpdate'], $installed_version, $version);
|
||||
Util::pauseFileMonitor();
|
||||
try {
|
||||
// 解压zip到plugin目录
|
||||
if ($has_zip_archive) {
|
||||
$zip = new ZipArchive;
|
||||
$zip->open($zip_file, ZIPARCHIVE::CHECKCONS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($zip)) {
|
||||
$zip->extractTo(base_path() . '/plugin/');
|
||||
unset($zip);
|
||||
} else {
|
||||
$this->unzipWithCmd($cmd);
|
||||
}
|
||||
|
||||
unlink($zip_file);
|
||||
|
||||
if ($installed_version) {
|
||||
// 执行update更新
|
||||
if (class_exists($install_class) && method_exists($install_class, 'update')) {
|
||||
call_user_func([$install_class, 'update'], $installed_version, $version, $context);
|
||||
$context = null;
|
||||
$install_class = "\\plugin\\$name\\api\\Install";
|
||||
if ($installed_version) {
|
||||
// 执行beforeUpdate
|
||||
if (class_exists($install_class) && method_exists($install_class, 'beforeUpdate')) {
|
||||
$context = call_user_func([$install_class, 'beforeUpdate'], $installed_version, $version);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 执行install安装
|
||||
if (class_exists($install_class) && method_exists($install_class, 'install')) {
|
||||
call_user_func([$install_class, 'install'], $version);
|
||||
|
||||
if (!empty($zip)) {
|
||||
$zip->extractTo(base_path() . '/plugin/');
|
||||
unset($zip);
|
||||
} else {
|
||||
$this->unzipWithCmd($cmd);
|
||||
}
|
||||
|
||||
unlink($zip_file);
|
||||
|
||||
if ($installed_version) {
|
||||
// 执行update更新
|
||||
if (class_exists($install_class) && method_exists($install_class, 'update')) {
|
||||
call_user_func([$install_class, 'update'], $installed_version, $version, $context);
|
||||
}
|
||||
} else {
|
||||
// 执行install安装
|
||||
if (class_exists($install_class) && method_exists($install_class, 'install')) {
|
||||
call_user_func([$install_class, 'install'], $version);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Util::resumeFileMonitor();
|
||||
}
|
||||
|
||||
Util::reloadWebman();
|
||||
@ -206,7 +189,17 @@ class PluginController extends Base
|
||||
// 删除目录
|
||||
clearstatcache();
|
||||
if (is_dir($path)) {
|
||||
$this->rmDir($path);
|
||||
$monitor_support_pause = method_exists(Monitor::class, 'pause');
|
||||
if ($monitor_support_pause) {
|
||||
Monitor::pause();
|
||||
}
|
||||
try {
|
||||
$this->rmDir($path);
|
||||
} finally {
|
||||
if ($monitor_support_pause) {
|
||||
Monitor::resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
clearstatcache();
|
||||
|
||||
@ -215,6 +208,27 @@ class PluginController extends Base
|
||||
return $this->json(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付
|
||||
* @param Request $request
|
||||
* @return string|Response
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function pay(Request $request)
|
||||
{
|
||||
$app = $request->get('app');
|
||||
if (!$app) {
|
||||
return response('app not found');
|
||||
}
|
||||
$token = session('app-plugin-token');
|
||||
if (!$token) {
|
||||
return 'Please login workerman.net';
|
||||
}
|
||||
$client = $this->httpClient();
|
||||
$response = $client->get("/payment/app/$app/$token");
|
||||
return (string)$response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录验证码
|
||||
* @param Request $request
|
||||
@ -226,7 +240,7 @@ class PluginController extends Base
|
||||
$client = $this->httpClient();
|
||||
$response = $client->get('/user/captcha?type=login');
|
||||
$sid_str = $response->getHeaderLine('Set-Cookie');
|
||||
if(preg_match('/PHPSID=([a-zA-z_0-9]+?);/', $sid_str, $match)) {
|
||||
if (preg_match('/PHPSID=([a-zA-Z_0-9]+?);/', $sid_str, $match)) {
|
||||
$sid = $match[1];
|
||||
session()->set('app-plugin-token', $sid);
|
||||
}
|
||||
@ -236,15 +250,17 @@ class PluginController extends Base
|
||||
/**
|
||||
* 登录官网
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @return Response|string
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function login(Request $request): Response
|
||||
public function login(Request $request)
|
||||
{
|
||||
if ($request->method() === 'GET') {
|
||||
return view('plugin/auth-login');
|
||||
}
|
||||
$client = $this->httpClient();
|
||||
if ($request->method() === 'GET') {
|
||||
$response = $client->get("/webman-admin/login");
|
||||
return (string)$response->getBody();
|
||||
}
|
||||
|
||||
$response = $client->post('/api/user/login', [
|
||||
'form_params' => [
|
||||
'email' => $request->post('username'),
|
||||
@ -272,37 +288,27 @@ class PluginController extends Base
|
||||
/**
|
||||
* 获取zip下载url
|
||||
* @param $name
|
||||
* @param $uid
|
||||
* @param $host
|
||||
* @param $version
|
||||
* @return mixed
|
||||
* @throws BusinessException
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
protected function getDownloadUrl($name, $uid, $host, $version)
|
||||
protected function getDownloadUrl($name, $version)
|
||||
{
|
||||
$client = $this->httpClient();
|
||||
$response = $client->post('/api/app/download', [
|
||||
'form_params' => [
|
||||
'name' => $name,
|
||||
'uid' => $uid,
|
||||
'token' => session('app-plugin-token'),
|
||||
'referer' => $host,
|
||||
'version' => $version,
|
||||
]
|
||||
]);
|
||||
$response = $client->get("/app/download/$name?version=$version");
|
||||
|
||||
$content = $response->getBody()->getContents();
|
||||
$data = json_decode($content, true);
|
||||
if (!$data) {
|
||||
$msg = "/api/app/download return $content";
|
||||
Log::error($msg);
|
||||
throw new BusinessException('访问官方接口失败');
|
||||
throw new BusinessException('访问官方接口失败 ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
|
||||
}
|
||||
if ($data['code'] && $data['code'] != -1) {
|
||||
throw new BusinessException($data['msg']);
|
||||
if ($data['code'] && $data['code'] != -1 && $data['code'] != -2) {
|
||||
throw new BusinessException($data['message']);
|
||||
}
|
||||
if ($data['code'] == 0 && !isset($data['result']['url'])) {
|
||||
if ($data['code'] == 0 && !isset($data['data']['url'])) {
|
||||
throw new BusinessException('官方接口返回数据错误');
|
||||
}
|
||||
return $data;
|
||||
@ -341,10 +347,10 @@ class PluginController extends Base
|
||||
protected function getUnzipCmd($zip_file, $extract_to)
|
||||
{
|
||||
if ($cmd = $this->findCmd('unzip')) {
|
||||
$cmd = "$cmd -qq $zip_file -d $extract_to";
|
||||
$cmd = "$cmd -o -qq $zip_file -d $extract_to";
|
||||
} else if ($cmd = $this->findCmd('7z')) {
|
||||
$cmd = "$cmd x -bb0 -y $zip_file -o$extract_to";
|
||||
} else if ($cmd= $this->findCmd('7zz')) {
|
||||
} else if ($cmd = $this->findCmd('7zz')) {
|
||||
$cmd = "$cmd x -bb0 -y $zip_file -o$extract_to";
|
||||
}
|
||||
return $cmd;
|
||||
@ -359,8 +365,8 @@ class PluginController extends Base
|
||||
protected function unzipWithCmd($cmd)
|
||||
{
|
||||
$desc = [
|
||||
0 => STDIN,
|
||||
1 => STDOUT,
|
||||
0 => ["pipe", "r"],
|
||||
1 => ["pipe", "w"],
|
||||
2 => ["pipe", "w"],
|
||||
];
|
||||
$handler = proc_open($cmd, $desc, $pipes);
|
||||
@ -375,6 +381,34 @@ class PluginController extends Base
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已安装的插件列表
|
||||
* @return array
|
||||
*/
|
||||
protected function getLocalPlugins(): array
|
||||
{
|
||||
clearstatcache();
|
||||
$installed = [];
|
||||
$plugin_names = array_diff(scandir(base_path() . '/plugin/'), array('.', '..')) ?: [];
|
||||
foreach ($plugin_names as $plugin_name) {
|
||||
if (is_dir(base_path() . "/plugin/$plugin_name") && $version = $this->getPluginVersion($plugin_name)) {
|
||||
$installed[$plugin_name] = $version;
|
||||
}
|
||||
}
|
||||
return $installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已安装的插件列表
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function getInstalledPlugins(Request $request): Response
|
||||
{
|
||||
return $this->json(0, 'ok', $this->getLocalPlugins());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取本地插件版本
|
||||
* @param $name
|
||||
@ -406,10 +440,10 @@ class PluginController extends Base
|
||||
protected function rmDir($src)
|
||||
{
|
||||
$dir = opendir($src);
|
||||
while(false !== ( $file = readdir($dir)) ) {
|
||||
if (( $file != '.' ) && ( $file != '..' )) {
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if (($file != '.') && ($file != '..')) {
|
||||
$full = $src . '/' . $file;
|
||||
if ( is_dir($full) ) {
|
||||
if (is_dir($full)) {
|
||||
$this->rmDir($full);
|
||||
} else {
|
||||
unlink($full);
|
||||
@ -435,7 +469,7 @@ class PluginController extends Base
|
||||
'http_errors' => false,
|
||||
'headers' => [
|
||||
'Referer' => \request()->fullUrl(),
|
||||
'User-Agent' => 'webman-app-plugin',
|
||||
'User-Agent' => 'webman-app-plugin',
|
||||
'Accept' => 'application/json;charset=UTF-8',
|
||||
]
|
||||
];
|
||||
@ -459,7 +493,7 @@ class PluginController extends Base
|
||||
'http_errors' => false,
|
||||
'headers' => [
|
||||
'Referer' => \request()->fullUrl(),
|
||||
'User-Agent' => 'webman-app-plugin',
|
||||
'User-Agent' => 'webman-app-plugin',
|
||||
]
|
||||
];
|
||||
if ($token = session('app-plugin-token')) {
|
||||
@ -477,8 +511,8 @@ class PluginController extends Base
|
||||
*/
|
||||
protected function findCmd(string $name, string $default = null, array $extraDirs = [])
|
||||
{
|
||||
if (\ini_get('open_basedir')) {
|
||||
$searchPath = array_merge(explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs);
|
||||
if (ini_get('open_basedir')) {
|
||||
$searchPath = array_merge(explode(PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
|
||||
$dirs = [];
|
||||
foreach ($searchPath as $path) {
|
||||
if (@is_dir($path)) {
|
||||
@ -491,19 +525,19 @@ class PluginController extends Base
|
||||
}
|
||||
} else {
|
||||
$dirs = array_merge(
|
||||
explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
|
||||
explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
|
||||
$extraDirs
|
||||
);
|
||||
}
|
||||
|
||||
$suffixes = [''];
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
$pathExt = getenv('PATHEXT');
|
||||
$suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
|
||||
$suffixes = array_merge($pathExt ? explode(PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com'], $suffixes);
|
||||
}
|
||||
foreach ($suffixes as $suffix) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
|
||||
if (@is_file($file = $dir . DIRECTORY_SEPARATOR . $name . $suffix) && ('\\' === DIRECTORY_SEPARATOR || @is_executable($file))) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +171,11 @@ class RoleController extends Crud
|
||||
if (!Auth::isSupperAdmin() && array_diff($ids, Auth::getScopeRoleIds())) {
|
||||
return $this->json(1, '无删除权限');
|
||||
}
|
||||
$tree = new Tree(Role::get());
|
||||
$descendants = $tree->getDescendant($ids);
|
||||
if ($descendants) {
|
||||
$ids = array_merge($ids, array_column($descendants, 'id'));
|
||||
}
|
||||
$this->doDelete($ids);
|
||||
return $this->json(0);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ use plugin\admin\app\model\Option;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use Throwable;
|
||||
|
||||
class TableController extends Base
|
||||
{
|
||||
@ -58,16 +59,20 @@ class TableController extends Base
|
||||
*/
|
||||
public function show(Request $request): Response
|
||||
{
|
||||
$limit = (int)$request->get('limit', 10);
|
||||
$page = (int)$request->get('page', 1);
|
||||
$offset = ($page - 1) * $limit;
|
||||
$database = config('database.connections')['plugin.admin.mysql']['database'];
|
||||
$field = $request->get('field', 'TABLE_NAME');
|
||||
$field = Util::filterAlphaNum($field);
|
||||
$order = $request->get('order', 'asc');
|
||||
$allow_column = ['TABLE_NAME','TABLE_COMMENT','ENGINE','TABLE_ROWS','CREATE_TIME','UPDATE_TIME','TABLE_COLLATION'];
|
||||
$allow_column = ['TABLE_NAME', 'TABLE_COMMENT', 'ENGINE', 'TABLE_ROWS', 'CREATE_TIME', 'UPDATE_TIME', 'TABLE_COLLATION'];
|
||||
if (!in_array($field, $allow_column)) {
|
||||
$field = 'TABLE_NAME';
|
||||
}
|
||||
$order = $order === 'asc' ? 'asc' : 'desc';
|
||||
$tables = Util::db()->select("SELECT TABLE_NAME,TABLE_COMMENT,ENGINE,TABLE_ROWS,CREATE_TIME,UPDATE_TIME,TABLE_COLLATION FROM information_schema.`TABLES` WHERE TABLE_SCHEMA='$database' order by $field $order");
|
||||
$total = Util::db()->select("SELECT count(*)total FROM information_schema.`TABLES` WHERE TABLE_SCHEMA='$database'")[0]->total ?? 0;
|
||||
$tables = Util::db()->select("SELECT TABLE_NAME,TABLE_COMMENT,ENGINE,TABLE_ROWS,CREATE_TIME,UPDATE_TIME,TABLE_COLLATION FROM information_schema.`TABLES` WHERE TABLE_SCHEMA='$database' order by $field $order limit $offset,$limit");
|
||||
|
||||
if ($tables) {
|
||||
$table_names = array_column($tables, 'TABLE_NAME');
|
||||
@ -80,7 +85,7 @@ class TableController extends Base
|
||||
}
|
||||
}
|
||||
|
||||
return $this->json(0, 'ok', $tables);
|
||||
return json(['code' => 0, 'msg' => 'ok', 'count' => $total, 'data' => $tables]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,6 +108,7 @@ class TableController extends Base
|
||||
|
||||
$primary_key_count = 0;
|
||||
foreach ($columns as $index => $item) {
|
||||
$columns[$index]['field'] = trim($item['field']);
|
||||
if (!$item['field']) {
|
||||
unset($columns[$index]);
|
||||
continue;
|
||||
@ -207,6 +213,7 @@ class TableController extends Base
|
||||
|
||||
$primary_key_count = $auto_increment_count = 0;
|
||||
foreach ($columns as $index => $item) {
|
||||
$columns[$index]['field'] = trim($item['field']);
|
||||
if (!$item['field']) {
|
||||
unset($columns[$index]);
|
||||
continue;
|
||||
@ -464,45 +471,50 @@ class TableController extends Base
|
||||
$app = strtolower($explode[1]) !== 'controller' ? $explode[1] : '';
|
||||
}
|
||||
|
||||
$model_class = $model_file_name;
|
||||
$model_namespace = str_replace('/' , '\\', trim($model_path, '/'));
|
||||
Util::pauseFileMonitor();
|
||||
try {
|
||||
$model_class = $model_file_name;
|
||||
$model_namespace = str_replace('/', '\\', trim($model_path, '/'));
|
||||
|
||||
// 创建model
|
||||
$this->createModel($model_class, $model_namespace, base_path($model_file), $table_name);
|
||||
// 创建model
|
||||
$this->createModel($model_class, $model_namespace, base_path($model_file), $table_name);
|
||||
|
||||
$controller_suffix = $plugin ? config("plugin.$plugin.app.controller_suffix") : config('app.controller_suffix');
|
||||
$controller_class = $controller_file_name;
|
||||
$controller_namespace = str_replace('/' , '\\', trim($controller_path, '/'));
|
||||
// 创建controller
|
||||
$controller_url_name = $controller_suffix && substr($controller_class, -strlen($controller_suffix)) === $controller_suffix ? substr($controller_class, 0, -strlen($controller_suffix)) : $controller_class;
|
||||
$controller_url_name = str_replace('_', '-', $inflector->tableize($controller_url_name));
|
||||
$controller_suffix = $plugin ? config("plugin.$plugin.app.controller_suffix") : config('app.controller_suffix');
|
||||
$controller_class = $controller_file_name;
|
||||
$controller_namespace = str_replace('/', '\\', trim($controller_path, '/'));
|
||||
// 创建controller
|
||||
$controller_url_name = $controller_suffix && substr($controller_class, -strlen($controller_suffix)) === $controller_suffix ? substr($controller_class, 0, -strlen($controller_suffix)) : $controller_class;
|
||||
$controller_url_name = str_replace('_', '-', $inflector->tableize($controller_url_name));
|
||||
|
||||
if ($plugin) {
|
||||
array_splice($explode, 0, 2);
|
||||
}
|
||||
array_shift($explode);
|
||||
if ($app) {
|
||||
array_shift($explode);
|
||||
}
|
||||
foreach ($explode as $index => $item) {
|
||||
if (strtolower($item) === 'controller') {
|
||||
unset($explode[$index]);
|
||||
if ($plugin) {
|
||||
array_splice($explode, 0, 2);
|
||||
}
|
||||
array_shift($explode);
|
||||
if ($app) {
|
||||
array_shift($explode);
|
||||
}
|
||||
foreach ($explode as $index => $item) {
|
||||
if (strtolower($item) === 'controller') {
|
||||
unset($explode[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
$controller_base = implode('/', $explode);
|
||||
$controller_class_with_namespace = "$controller_namespace\\$controller_class";
|
||||
$template_path = $controller_base ? "$controller_base/$controller_url_name" : $controller_url_name;
|
||||
$this->createController($controller_class, $controller_namespace, base_path($controller_file), $model_class, $model_namespace, $title, $template_path);
|
||||
|
||||
// 创建模版
|
||||
$template_file_path = ($plugin ? "/plugin/$plugin" : '') . '/app/' . ($app ? "$app/" : '') . 'view/' . $template_path;
|
||||
|
||||
$model_class_with_namespace = "$model_namespace\\$model_class";
|
||||
$primary_key = (new $model_class_with_namespace)->getKeyName();
|
||||
$url_path_base = ($plugin ? "/app/$plugin/" : '/') . ($app ? "$app/" : '') . $template_path;
|
||||
$this->createTemplate(base_path($template_file_path), $table_name, $url_path_base, $primary_key, "$controller_namespace\\$controller_class");
|
||||
} finally {
|
||||
Util::resumeFileMonitor();
|
||||
}
|
||||
|
||||
$controller_base = implode('/', $explode);
|
||||
$controller_class_with_namespace = "$controller_namespace\\$controller_class";
|
||||
$template_path = $controller_base ? "$controller_base/$controller_url_name" : $controller_url_name;
|
||||
$this->createController($controller_class, $controller_namespace, base_path($controller_file), $model_class, $model_namespace, $title, $template_path);
|
||||
|
||||
// 创建模版
|
||||
$template_file_path = ($plugin ? "/plugin/$plugin" : '') . '/app/' . ($app ? "$app/" : '') . 'view/' . $template_path;
|
||||
|
||||
$model_class_with_namespace = "$model_namespace\\$model_class";
|
||||
$primary_key = (new $model_class_with_namespace)->getKeyName();
|
||||
$url_path_base = ($plugin ? "/app/$plugin/" : '/') . ($app ? "$app/" : '') . $template_path;
|
||||
$this->createTemplate(base_path($template_file_path), $table_name, $url_path_base, $primary_key, "$controller_namespace\\$controller_class");
|
||||
|
||||
$menu = Rule::where('key', $controller_class_with_namespace)->first();
|
||||
if (!$menu) {
|
||||
$menu = new Rule;
|
||||
@ -551,20 +563,33 @@ class TableController extends Base
|
||||
$pk = 'id';
|
||||
$properties = '';
|
||||
$timestamps = '';
|
||||
$incrementing = '';
|
||||
$columns = [];
|
||||
try {
|
||||
$database = config('database.connections')['plugin.admin.mysql']['database'];
|
||||
//plugin.admin.mysql
|
||||
foreach (Util::db()->select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
|
||||
foreach (Util::db()->select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database' order by ORDINAL_POSITION") as $item) {
|
||||
if ($item->COLUMN_KEY === 'PRI') {
|
||||
$pk = $item->COLUMN_NAME;
|
||||
$item->COLUMN_COMMENT .= "(主键)";
|
||||
if (strpos(strtolower($item->DATA_TYPE), 'int') === false) {
|
||||
$incrementing = <<<EOF
|
||||
/**
|
||||
* Indicates if the model's ID is auto-incrementing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public \$incrementing = false;
|
||||
|
||||
EOF;
|
||||
;
|
||||
}
|
||||
}
|
||||
$type = $this->getType($item->DATA_TYPE);
|
||||
$properties .= " * @property $type \${$item->COLUMN_NAME} {$item->COLUMN_COMMENT}\n";
|
||||
$columns[$item->COLUMN_NAME] = $item->COLUMN_NAME;
|
||||
}
|
||||
} catch (\Throwable $e) {echo $e;}
|
||||
} catch (Throwable $e) {echo $e;}
|
||||
if (!isset($columns['created_at']) || !isset($columns['updated_at'])) {
|
||||
$timestamps = <<<EOF
|
||||
/**
|
||||
@ -573,6 +598,7 @@ class TableController extends Base
|
||||
* @var bool
|
||||
*/
|
||||
public \$timestamps = false;
|
||||
|
||||
EOF;
|
||||
|
||||
}
|
||||
@ -602,9 +628,8 @@ class $class extends Base
|
||||
* @var string
|
||||
*/
|
||||
protected \$primaryKey = '$pk';
|
||||
|
||||
$timestamps
|
||||
|
||||
$incrementing
|
||||
|
||||
}
|
||||
|
||||
@ -832,6 +857,9 @@ EOF
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
@ -843,6 +871,16 @@ EOF
|
||||
where: []
|
||||
})
|
||||
});
|
||||
|
||||
// 字段允许为空
|
||||
form.verify({
|
||||
phone: [/(^$)|^1\d{10}$/, "请输入正确的手机号"],
|
||||
email: [/(^$)|^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/, "邮箱格式不正确"],
|
||||
url: [/(^$)|(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/, "链接格式不正确"],
|
||||
number: [/(^$)|^\d+$/,'只能填写数字'],
|
||||
date: [/(^$)|^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/, "日期格式不正确"],
|
||||
identity: [/(^$)|(^\d{15}$)|(^\d{17}(x|X|\d)$)/, "请输入正确的身份证号"]
|
||||
});
|
||||
|
||||
// 表格排序事件
|
||||
table.on("sort(data-table)", function(obj){
|
||||
@ -982,6 +1020,15 @@ EOF;
|
||||
$js
|
||||
//提交事件
|
||||
layui.use(["form", "popup"], function () {
|
||||
// 字段验证允许为空
|
||||
layui.form.verify({
|
||||
phone: [/(^$)|^1\d{10}$/, "请输入正确的手机号"],
|
||||
email: [/(^$)|^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/, "邮箱格式不正确"],
|
||||
url: [/(^$)|(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/, "链接格式不正确"],
|
||||
number: [/(^$)|^\d+$/,'只能填写数字'],
|
||||
date: [/(^$)|^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/, "日期格式不正确"],
|
||||
identity: [/(^$)|(^\d{15}$)|(^\d{17}(x|X|\d)$)/, "请输入正确的身份证号"]
|
||||
});
|
||||
layui.form.on("submit(save)", function (data) {
|
||||
layui.$.ajax({
|
||||
url: INSERT_API,
|
||||
@ -1092,6 +1139,15 @@ EOF;
|
||||
|
||||
//提交事件
|
||||
layui.use(["form", "popup"], function () {
|
||||
// 字段验证允许为空
|
||||
layui.form.verify({
|
||||
phone: [/(^$)|^1\d{10}$/, "请输入正确的手机号"],
|
||||
email: [/(^$)|^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/, "邮箱格式不正确"],
|
||||
url: [/(^$)|(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/, "链接格式不正确"],
|
||||
number: [/(^$)|^\d+$/,'只能填写数字'],
|
||||
date: [/(^$)|^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/, "日期格式不正确"],
|
||||
identity: [/(^$)|(^\d{15}$)|(^\d{17}(x|X|\d)$)/, "请输入正确的身份证号"]
|
||||
});
|
||||
layui.form.on("submit(save)", function (data) {
|
||||
data.field[PRIMARY_KEY] = layui.url().search[PRIMARY_KEY];
|
||||
layui.$.ajax({
|
||||
@ -1170,17 +1226,21 @@ EOF;
|
||||
}
|
||||
if (isset($allow_column[$column])) {
|
||||
if (is_array($value)) {
|
||||
if (in_array($value[0], ['', 'undefined']) || in_array($value[1], ['', 'undefined'])) {
|
||||
continue;
|
||||
if ($value[0] === 'like') {
|
||||
$paginator = $paginator->where($column, 'like', "%$value[1]%");
|
||||
} elseif (in_array($value[0], ['>', '=', '<', '<>', 'not like'])) {
|
||||
$paginator = $paginator->where($column, $value[0], $value[1]);
|
||||
} else {
|
||||
if($value[0] !== '' || $value[1] !== '') {
|
||||
$paginator = $paginator->whereBetween($column, $value);
|
||||
}
|
||||
}
|
||||
$paginator = $paginator->whereBetween($column, $value);
|
||||
} else {
|
||||
$paginator = $paginator->where($column, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
$paginator = $paginator->orderBy($field, $order)->paginate($limit, '*', 'page', $page);
|
||||
|
||||
$items = $paginator->items();
|
||||
if ($format == 'tree') {
|
||||
$items_map = [];
|
||||
|
@ -27,13 +27,14 @@ class Handler extends \support\exception\Handler
|
||||
public function render(Request $request, Throwable $exception): Response
|
||||
{
|
||||
$code = $exception->getCode();
|
||||
$debug = $this->_debug ?? $this->debug;
|
||||
if ($request->expectsJson()) {
|
||||
$json = ['code' => $code ? $code : 500, 'msg' => $this->_debug ? $exception->getMessage() : 'Server internal error', 'type' => 'failed'];
|
||||
$this->_debug && $json['traces'] = (string)$exception;
|
||||
$json = ['code' => $code ?: 500, 'msg' => $debug ? $exception->getMessage() : 'Server internal error', 'type' => 'failed'];
|
||||
$debug && $json['traces'] = (string)$exception;
|
||||
return new Response(200, ['Content-Type' => 'application/json'],
|
||||
\json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
$error = $this->_debug ? \nl2br((string)$exception) : 'Server internal error';
|
||||
$error = $debug ? \nl2br((string)$exception) : 'Server internal error';
|
||||
return new Response(500, [], $error);
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,9 @@
|
||||
* Here is your custom functions.
|
||||
*/
|
||||
|
||||
use app\model\User;
|
||||
use plugin\admin\app\model\User;
|
||||
use plugin\admin\app\model\Admin;
|
||||
use plugin\admin\app\model\AdminRole;
|
||||
use plugin\admin\app\model\Role;
|
||||
use plugin\admin\app\model\Rule;
|
||||
|
||||
/**
|
||||
* 当前管理员id
|
||||
@ -138,4 +136,4 @@ function refresh_user_session(bool $force = false)
|
||||
unset($user['password']);
|
||||
$user['session_last_update_time'] = $time_now;
|
||||
$session->set('user', $user);
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ class AccessControl implements MiddlewareInterface
|
||||
EOF
|
||||
);
|
||||
} else {
|
||||
$request->app = '';
|
||||
$request->plugin = 'admin';
|
||||
$response = view('common/error/403')->withStatus(403);
|
||||
}
|
||||
}
|
||||
@ -49,4 +51,4 @@ EOF
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -300,6 +300,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -156,6 +156,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -1,69 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>登录 workerman.net 官网</title>
|
||||
<link rel="stylesheet" href="/app/admin/component/pear/css/pear.css" />
|
||||
<link rel="stylesheet" href="/app/admin/admin/css/pages/login.css" />
|
||||
</head>
|
||||
<body style="background: #fff !important;">
|
||||
<form class="layui-form" style="margin-top:36px !important;">
|
||||
<div class="layui-form-item pear-border" style="background:#ebf2f8;border:1px solid #ccddf6;padding:10px;border-radius: 4px;">
|
||||
<div class="pear-text">注意此处登录 <a class="pear-text" href="https://www.workerman.net" target="_blank"><b>workerman.net</b></a> 官网账号</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<input lay-verify="required" hover class="layui-input" type="text" name="username" value="" />
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<input lay-verify="required" hover class="layui-input" type="password" name="password" value="" />
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<input hover lay-verify="required" class="code layui-input layui-input-inline" name="captcha" />
|
||||
<img class="codeImage" width="120px"/>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button type="submit" class="pear-btn pear-btn-primary login" lay-submit lay-filter="login">
|
||||
登录
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="/app/admin/component/layui/layui.js"></script>
|
||||
<script src="/app/admin/component/pear/pear.js"></script>
|
||||
<script src="/app/admin/admin/js/permission.js"></script>
|
||||
<script>
|
||||
layui.use(["form", "button", "popup", "layer"], function() {
|
||||
var $ = layui.$, layer = layui.layer, form = layui.form;
|
||||
function switchCaptcha() {
|
||||
$(".codeImage").attr("src", "/app/admin/plugin/captcha?v=" + new Date().getTime());
|
||||
}
|
||||
switchCaptcha();
|
||||
form.on("submit(login)", function (data) {
|
||||
layer.load();
|
||||
$.ajax({
|
||||
url: "/app/admin/plugin/login",
|
||||
type: "POST",
|
||||
data: data.field,
|
||||
success: function (res) {
|
||||
layer.closeAll("loading");
|
||||
if (!res.code) {
|
||||
layui.popup.success("登录成功", function () {
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
})
|
||||
} else {
|
||||
layui.popup.failure(res.msg, function () {
|
||||
switchCaptcha();
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
$(".codeImage").on("click", function () {
|
||||
switchCaptcha();
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,145 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>应用插件管理</title>
|
||||
<link rel="stylesheet" href="/app/admin/component/pear/css/pear.css" />
|
||||
<link rel="stylesheet" href="/app/admin/admin/css/reset.css" />
|
||||
</head>
|
||||
<body class="pear-container">
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="data-table" lay-filter="data-table"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="install">
|
||||
{{# if(!d.installed){ }}
|
||||
<button class="pear-btn pear-btn-xs pear-btn-primary" onclick="install('{{ d.name }}','{{ d.version }}')">
|
||||
安装
|
||||
</button>
|
||||
{{# }else{ }}
|
||||
{{# if(d.installed !== d.version){ }}
|
||||
<button class="pear-btn pear-btn-xs pear-btn-success" onclick="install('{{ d.name }}','{{ d.version }}')">
|
||||
升级
|
||||
</button>
|
||||
{{# } }}
|
||||
{{# if(d.name !== "admin"){ }}
|
||||
<button class="pear-btn pear-btn-xs pear-btn-danger" onclick="uninstall('{{ d.name }}','{{ d.installed }}')">
|
||||
卸载
|
||||
</button>
|
||||
{{# } }}
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script src="/app/admin/component/layui/layui.js"></script>
|
||||
<script src="/app/admin/component/pear/pear.js"></script>
|
||||
<script src="/app/admin/admin/js/permission.js"></script>
|
||||
<script>
|
||||
|
||||
const SELECT_API = "/app/admin/plugin/list";
|
||||
const AUTH_URL = "/app/admin/plugin/login";
|
||||
const SCHEMA_API = "/app/admin/plugin/schema";
|
||||
|
||||
layui.use(["table", "form","common", "popup"], function() {
|
||||
let table = layui.table;
|
||||
let form = layui.form;
|
||||
let $ = layui.$;
|
||||
let common = layui.common;
|
||||
|
||||
$.ajax({
|
||||
url: SCHEMA_API,
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
let cols = res.data;
|
||||
layui.each(cols, function (k, v) {
|
||||
if (v.field === "installed") {
|
||||
cols[k].templet = "#install";
|
||||
}
|
||||
})
|
||||
function render()
|
||||
{
|
||||
table.render({
|
||||
elem: "#data-table",
|
||||
url: SELECT_API,
|
||||
page: true,
|
||||
cols: [cols],
|
||||
skin: "line",
|
||||
size: "lg",
|
||||
autoSort: false,
|
||||
defaultToolbar: [{
|
||||
title: "刷新",
|
||||
layEvent: "refresh",
|
||||
icon: "layui-icon-refresh",
|
||||
}, "filter", "print", "exports"]
|
||||
});
|
||||
}
|
||||
render();
|
||||
}
|
||||
});
|
||||
|
||||
window.install = function(name, version) {
|
||||
let loading = layer.load();
|
||||
$.ajax({
|
||||
url: "/app/admin/plugin/install",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: {name, version},
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
// 需要登录官网
|
||||
if (res.data && res.data.code === 401) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: "登录 workerman.net 官网",
|
||||
shade: 0.1,
|
||||
area: [common.isModile()?"100%":"500px", common.isModile()?"100%":"450px"],
|
||||
content: AUTH_URL
|
||||
});
|
||||
return;
|
||||
}
|
||||
return layui.popup.success("安装成功", function () {
|
||||
parent.location.reload();
|
||||
});
|
||||
},
|
||||
complete: function () {
|
||||
layer.close(loading);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.uninstall = function(name, version) {
|
||||
layer.confirm("确定卸载?", {
|
||||
icon: 3,
|
||||
title: "提示"
|
||||
}, function(index) {
|
||||
layer.close(index);
|
||||
let loading = layer.load();
|
||||
$.ajax({
|
||||
url: "/app/admin/plugin/uninstall",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: {name, version},
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
return layui.popup.success("卸载成功", function () {
|
||||
parent.location.reload();
|
||||
});
|
||||
},
|
||||
complete: function () {
|
||||
layer.close(loading);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -196,6 +196,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -96,7 +96,7 @@
|
||||
|
||||
<script type="text/html" id="col-type">
|
||||
<select name="columns[{{ d.LAY_INDEX-1 }}][type]" lay-verify="">
|
||||
{{# layui.each(["integer","string","text","date","enum","float","tinyInteger","smallInteger","mediumInteger","bigInteger","unsignedInteger","unsignedTinyInteger","unsignedSmallInteger","unsignedMediumInteger","unsignedBigInteger","decimal","double","mediumText","longText","dateTime","time","timestamp","char","binary"], function (index, item) { }}
|
||||
{{# layui.each(["integer","string","text","date","enum","float","tinyInteger","smallInteger","mediumInteger","bigInteger","unsignedInteger","unsignedTinyInteger","unsignedSmallInteger","unsignedMediumInteger","unsignedBigInteger","decimal","double","mediumText","longText","dateTime","time","timestamp","char","binary","json"], function (index, item) { }}
|
||||
<option value="{{ item }}" {{ d.type==item?"selected":""}}>{{ item }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
@ -132,7 +132,7 @@
|
||||
|
||||
<script type="text/html" id="form-control">
|
||||
<select name="forms[{{ d.LAY_INDEX-1 }}][control]" lay-verify="">
|
||||
{{# layui.each([["input", "文本框"],["inputNumber", "数字文本框"],["textArea", "多行文本"],["select", "下拉单选"],["selectMulti", "下拉多选"],["treeSelect", "树形单选"],["treeSelectMulti", "树形多选"],["datePicker", "日期选择"],["dateTimePicker", "日期时间选择"],["switch", "开关"],["upload", "上传文件"],["uploadImage", "上传图片"],["iconPicker", "图标选择"]], function (index, item) { }}
|
||||
{{# layui.each([["input", "文本框"],["inputNumber", "数字文本框"],["textArea", "多行文本"],["richText", "富文本"],["select", "下拉单选"],["selectMulti", "下拉多选"],["treeSelect", "树形单选"],["treeSelectMulti", "树形多选"],["datePicker", "日期选择"],["dateTimePicker", "日期时间选择"],["switch", "开关"],["upload", "上传文件"],["uploadImage", "上传图片"],["iconPicker", "图标选择"]], function (index, item) { }}
|
||||
<option value="{{ item[0] }}" {{ d.control.toLocaleLowerCase()==item[0].toLocaleLowerCase()?'selected':''}}>{{ item[1] }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
@ -160,7 +160,7 @@
|
||||
|
||||
<script type="text/html" id="form-search_type">
|
||||
<select name="forms[{{ d.LAY_INDEX-1 }}][search_type]" lay-verify="">
|
||||
{{# layui.each([["normal", "普通查询"], ["between", "范围查询"]], function (index, item) { }}
|
||||
{{# layui.each([["normal", "普通查询"], ["between", "范围查询"], ["like", "模糊查询"]], function (index, item) { }}
|
||||
<option value="{{ item[0] }}" {{ d.search_type==item[0]?'selected':''}}>{{ item[1] }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
|
@ -125,7 +125,6 @@
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
return layui.popup.success("操作成功", function () {
|
||||
parent.refreshTable();
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
});
|
||||
}
|
||||
|
@ -40,6 +40,17 @@
|
||||
<?=$form->js(3)?>
|
||||
|
||||
layui.use(["form", "popup"], function () {
|
||||
|
||||
// 字段验证允许为空
|
||||
layui.form.verify({
|
||||
phone: [/(^$)|^1\d{10}$/, "请输入正确的手机号"],
|
||||
email: [/(^$)|^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/, "邮箱格式不正确"],
|
||||
url: [/(^$)|(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/, "链接格式不正确"],
|
||||
number: [/(^$)|^\d+$/,'只能填写数字'],
|
||||
date: [/(^$)|^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/, "日期格式不正确"],
|
||||
identity: [/(^$)|(^\d{15}$)|(^\d{17}(x|X|\d)$)/, "请输入正确的身份证号"]
|
||||
});
|
||||
|
||||
//提交事件
|
||||
layui.form.on("submit(save)", function (data) {
|
||||
layui.$.ajax({
|
||||
|
@ -98,7 +98,7 @@
|
||||
|
||||
<script type="text/html" id="col-type">
|
||||
<select name="columns[{{ d.LAY_INDEX-1 }}][type]" lay-verify="">
|
||||
{{# layui.each(["integer","string","text","date","enum","float","tinyInteger","smallInteger","mediumInteger","bigInteger","unsignedInteger","unsignedTinyInteger","unsignedSmallInteger","unsignedMediumInteger","unsignedBigInteger","decimal","double","mediumText","longText","dateTime","time","timestamp","char","binary"], function (index, item) { }}
|
||||
{{# layui.each(["integer","string","text","date","enum","float","tinyInteger","smallInteger","mediumInteger","bigInteger","unsignedInteger","unsignedTinyInteger","unsignedSmallInteger","unsignedMediumInteger","unsignedBigInteger","decimal","double","mediumText","longText","dateTime","time","timestamp","char","binary","json"], function (index, item) { }}
|
||||
<option value="{{ item }}" {{ d.type==item?'selected':''}}>{{ item }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
@ -136,7 +136,7 @@
|
||||
|
||||
<script type="text/html" id="form-control">
|
||||
<select name="forms[{{ d.LAY_INDEX-1 }}][control]" lay-verify="">
|
||||
{{# layui.each([["input", "文本框"],["inputNumber", "数字文本框"],["textArea", "多行文本"],["select", "下拉单选"],["selectMulti", "下拉多选"],["treeSelect", "树形单选"],["treeSelectMulti", "树形多选"],["datePicker", "日期选择"],["dateTimePicker", "日期时间选择"],["switch", "开关"],["upload", "上传文件"],["uploadImage", "上传图片"],["iconPicker", "图标选择"]], function (index, item) { }}
|
||||
{{# layui.each([["input", "文本框"],["inputNumber", "数字文本框"],["textArea", "多行文本"],["richText", "富文本"],["select", "下拉单选"],["selectMulti", "下拉多选"],["treeSelect", "树形单选"],["treeSelectMulti", "树形多选"],["datePicker", "日期选择"],["dateTimePicker", "日期时间选择"],["switch", "开关"],["upload", "上传文件"],["uploadImage", "上传图片"],["iconPicker", "图标选择"]], function (index, item) { }}
|
||||
<option value="{{ item[0] }}" {{ d.control.toLocaleLowerCase()==item[0].toLocaleLowerCase()?'selected':''}}>{{ item[1] }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
@ -164,7 +164,7 @@
|
||||
|
||||
<script type="text/html" id="form-search_type">
|
||||
<select name="forms[{{ d.LAY_INDEX-1 }}][search_type]" lay-verify="">
|
||||
{{# layui.each([["normal", "普通查询"], ["between", "范围查询"]], function (index, item) { }}
|
||||
{{# layui.each([["normal", "普通查询"], ["between", "范围查询"], ["like", "模糊查询"]], function (index, item) { }}
|
||||
<option value="{{ item[0] }}" {{ d.search_type==item[0]?'selected':''}}>{{ item[1] }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
|
@ -76,6 +76,15 @@
|
||||
});
|
||||
|
||||
layui.use(["form", "popup"], function () {
|
||||
// 字段验证允许为空
|
||||
layui.form.verify({
|
||||
phone: [/(^$)|^1\d{10}$/, "请输入正确的手机号"],
|
||||
email: [/(^$)|^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/, "邮箱格式不正确"],
|
||||
url: [/(^$)|(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/, "链接格式不正确"],
|
||||
number: [/(^$)|^\d+$/,'只能填写数字'],
|
||||
date: [/(^$)|^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/, "日期格式不正确"],
|
||||
identity: [/(^$)|(^\d{15}$)|(^\d{17}(x|X|\d)$)/, "请输入正确的身份证号"]
|
||||
});
|
||||
//提交事件
|
||||
layui.form.on("submit(save)", function (data) {
|
||||
layui.$.ajax({
|
||||
|
@ -237,6 +237,16 @@
|
||||
}
|
||||
});
|
||||
|
||||
// 字段验证允许为空
|
||||
form.verify({
|
||||
phone: [/(^$)|^1\d{10}$/, "请输入正确的手机号"],
|
||||
email: [/(^$)|^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/, "邮箱格式不正确"],
|
||||
url: [/(^$)|(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/, "链接格式不正确"],
|
||||
number: [/(^$)|^\d+$/,'只能填写数字'],
|
||||
date: [/(^$)|^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/, "日期格式不正确"],
|
||||
identity: [/(^$)|(^\d{15}$)|(^\d{17}(x|X|\d)$)/, "请输入正确的身份证号"]
|
||||
});
|
||||
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
where: data.field
|
||||
|
@ -315,6 +315,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -305,6 +305,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -75,7 +75,7 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">余额(分)</label>
|
||||
<label class="layui-form-label">余额(元)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="money" value="" class="layui-input">
|
||||
</div>
|
||||
@ -287,7 +287,7 @@
|
||||
field: "birthday",
|
||||
hide: true,
|
||||
},{
|
||||
title: "余额(分)",
|
||||
title: "余额(元)",
|
||||
field: "money",
|
||||
hide: true,
|
||||
},{
|
||||
@ -442,6 +442,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -84,7 +84,7 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">余额(分)</label>
|
||||
<label class="layui-form-label">余额(元)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="money" value="0" class="layui-input">
|
||||
</div>
|
||||
|
@ -84,7 +84,7 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">余额(分)</label>
|
||||
<label class="layui-form-label">余额(元)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="money" value="" class="layui-input">
|
||||
</div>
|
||||
|
@ -17,5 +17,5 @@ return [
|
||||
'controller_suffix' => 'Controller',
|
||||
'controller_reuse' => false,
|
||||
'plugin_market_host' => 'https://www.workerman.net',
|
||||
'version' => '0.5.0'
|
||||
'version' => '0.6.12'
|
||||
];
|
||||
|
@ -21,5 +21,5 @@ return [
|
||||
// Fallback language
|
||||
'fallback_locale' => ['zh_CN', 'en'],
|
||||
// Folder where language files are stored
|
||||
'path' => base_path() . '/resource/translations',
|
||||
];
|
||||
'path' => base_path() . '/plugin/admin/resource/translations'
|
||||
];
|
||||
|
File diff suppressed because one or more lines are too long
@ -25,9 +25,9 @@ layui.define(['jquery'],function (exports) {
|
||||
}
|
||||
, success: function (res, succFun, failFun) {//图片上传完成回调 根据自己需要修改
|
||||
if (res[this.response.statusName] == this.response.statusCode.ok) {
|
||||
succFun(res[this.response.dataName]);
|
||||
succFun(res[this.response.dataName]["url"]);
|
||||
} else {
|
||||
failFun(res[this.response.msgName]);
|
||||
failFun(res[this.response.msgName]["url"]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user