Compare commits
105 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 | ||
|
17bf447521 | ||
|
c72cfdec8f | ||
|
3bb069cf65 | ||
|
a795555220 | ||
|
8dc51585e8 | ||
|
b5ca8b20b1 | ||
|
4e6cd56577 | ||
|
11370fbb7a | ||
|
5f5055283d | ||
|
58d754a90e | ||
|
b2fa0399d5 | ||
|
c9df58cacf | ||
|
cfa1d1296b | ||
|
1c1b2fb2c2 | ||
|
da6b3cc18e | ||
|
5660e16e99 | ||
|
64d4433aaa | ||
|
93ceaa4cb1 | ||
|
a0e348a422 | ||
|
e5c648a57f | ||
|
df1f319e57 | ||
|
58c0370eb4 | ||
|
5c9188a7ca | ||
|
f299d1e521 | ||
|
8032d26fb9 | ||
|
db97119704 | ||
|
e9a06cdf67 | ||
|
3402a1a936 | ||
|
d3e82c54f0 | ||
|
83151a50fc | ||
|
5fb38aa579 | ||
|
5ec88341e3 | ||
|
073ab4afcc | ||
|
4a8f901600 | ||
|
317d7b4fc8 | ||
|
846be6eecc | ||
|
f9b4394d20 | ||
|
e40adb0247 | ||
|
5bf2eabd0f | ||
|
5576a94f59 | ||
|
ddbe85c6c0 | ||
|
500a8f26b0 | ||
|
35a9e84b71 | ||
|
30508c0a68 | ||
|
3ee71065fb | ||
|
fe6abf93f4 | ||
|
da2ff4f09d | ||
|
24fd3951fe | ||
|
3a9162cc17 | ||
|
b37f360295 | ||
|
c42d7e5c0e | ||
|
525ac3c926 | ||
|
ac96903dc8 | ||
|
5cefdb2797 | ||
|
471c6770c5 | ||
|
4d9fb9c260 | ||
|
3a3586bd27 |
@ -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",
|
||||
|
@ -39,10 +39,9 @@ class Auth
|
||||
*/
|
||||
public static function canAccess(string $controller, string $action, int &$code = 0, string &$msg = ''): bool
|
||||
{
|
||||
// 无控制器信息说明是函数调用,函数不属于任何控制器,鉴权操作应该在函数内部完成。
|
||||
if (!$controller) {
|
||||
$msg = '无法识别当前控制器';
|
||||
$code = 3;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// 获取控制器鉴权信息
|
||||
$class = new \ReflectionClass($controller);
|
||||
@ -99,9 +98,9 @@ class Auth
|
||||
|
||||
// 如果action为index,规则里有任意一个以$controller开头的权限即可
|
||||
if (strtolower($action) === 'index') {
|
||||
$controller = str_replace('\\', '\\\\', $controller);
|
||||
$rule = Rule::where(function ($query) use ($controller, $action) {
|
||||
$query->where('key', 'like', "$controller@%")->orWhere('key', $controller);
|
||||
$controller_like = str_replace('\\', '\\\\', $controller);
|
||||
$query->where('key', 'like', "$controller_like@%")->orWhere('key', $controller);
|
||||
})->whereIn('id', $rule_ids)->first();
|
||||
if ($rule) {
|
||||
return true;
|
||||
|
@ -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);
|
||||
|
63
src/plugin/admin/app/common/Auth.php
Normal file
63
src/plugin/admin/app/common/Auth.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace plugin\admin\app\common;
|
||||
|
||||
|
||||
use plugin\admin\app\model\Admin;
|
||||
use plugin\admin\app\model\AdminRole;
|
||||
use plugin\admin\app\model\Role;
|
||||
use plugin\admin\app\model\Rule;
|
||||
|
||||
class Auth
|
||||
{
|
||||
/**
|
||||
* 获取权限范围内的所有角色id
|
||||
* @param bool $with_self
|
||||
* @return array
|
||||
*/
|
||||
public static function getScopeRoleIds(bool $with_self = false): array
|
||||
{
|
||||
if (!$admin = admin()) {
|
||||
return [];
|
||||
}
|
||||
$role_ids = $admin['roles'];
|
||||
$rules = Role::whereIn('id', $role_ids)->pluck('rules')->toArray();
|
||||
if ($rules && in_array('*', $rules)) {
|
||||
return Role::pluck('id')->toArray();
|
||||
}
|
||||
|
||||
$roles = Role::get();
|
||||
$tree = new Tree($roles);
|
||||
$descendants = $tree->getDescendant($role_ids, $with_self);
|
||||
return array_column($descendants, 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限范围内的所有管理员id
|
||||
* @param bool $with_self
|
||||
* @return array
|
||||
*/
|
||||
public static function getScopeAdminIds(bool $with_self = false): array
|
||||
{
|
||||
$role_ids = static::getScopeRoleIds($with_self);
|
||||
return AdminRole::whereIn('role_id', $role_ids)->pluck('admin_id')->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是超级管理员
|
||||
* @param int $admin_id
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupperAdmin(int $admin_id = 0): bool
|
||||
{
|
||||
if (!$admin_id) {
|
||||
if (!$roles = admin('roles')) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$roles = AdminRole::where('admin_id', $admin_id)->pluck('role_id');
|
||||
}
|
||||
$rules = Role::whereIn('id', $roles)->pluck('rules');
|
||||
return $rules && in_array('*', $rules->toArray());
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
@ -159,16 +196,69 @@ EOF;
|
||||
[$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' : '';
|
||||
|
||||
$this->htmlContent .= <<<EOF
|
||||
|
||||
<div class="layui-form-item">
|
||||
$label
|
||||
<div class="$class">
|
||||
<textarea name="$field"$required_string$verify_string$placeholder_string class="layui-textarea">$value</textarea>
|
||||
<textarea name="$field"$required_string$verify_string$placeholder_string$disabled_string class="layui-textarea">$value</textarea>
|
||||
</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;
|
||||
}
|
||||
|
||||
@ -274,7 +364,7 @@ EOF;
|
||||
<div class="layui-form-item">
|
||||
$label
|
||||
<div class="$class">
|
||||
<img style="max-width:90px;max-height:90px;" src=""/>
|
||||
<img class="img-3" src=""/>
|
||||
<input type="text" style="display:none" name="$field" value="$value" />
|
||||
<button type="button" class="pear-btn pear-btn-primary pear-btn-sm" id="$id" permission="app.admin.upload.image">
|
||||
<i class="layui-icon layui-icon-upload"></i>上传图片
|
||||
@ -611,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)) {
|
||||
@ -629,19 +722,22 @@ EOF;
|
||||
$this->jsContent .= <<<EOF
|
||||
|
||||
// 字段 {$options['label']} $field
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "$url",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#$id").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#$id",
|
||||
name: "$field",
|
||||
initValue: initValue,
|
||||
data: e.data, $options_string
|
||||
})
|
||||
data: res.data, $options_string
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -669,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>
|
||||
|
||||
@ -684,7 +780,7 @@ EOF;
|
||||
* @return Layui
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function buildForm($table, string $type = 'insert'): Layui
|
||||
public static function buildForm($table, string $type = 'insert'): Layui
|
||||
{
|
||||
if (!in_array($type, ['insert', 'update', 'search'])) {
|
||||
$type = 'insert';
|
||||
@ -703,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';
|
||||
@ -711,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')) {
|
||||
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")) {
|
||||
// 查询类型
|
||||
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 = [
|
||||
@ -745,7 +856,7 @@ EOF;
|
||||
* @return array|string|string[]
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function buildTable($table, int $indent = 0)
|
||||
public static function buildTable($table, int $indent = 0)
|
||||
{
|
||||
$schema = Util::getSchema($table);
|
||||
$forms = $schema['forms'];
|
||||
@ -783,7 +894,10 @@ EOF;
|
||||
$.post(UPDATE_API, postData, function (res) {
|
||||
layer.close(load);
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
return layui.popup.failure(res.msg, function () {
|
||||
data.elem.checked = !data.elem.checked;
|
||||
form.render();
|
||||
});
|
||||
}
|
||||
return layui.popup.success("操作成功");
|
||||
})
|
||||
@ -835,6 +949,8 @@ EOF;
|
||||
}
|
||||
}
|
||||
$api_result .= "\napiResults[\"$field\"] = " . json_encode($options, JSON_UNESCAPED_UNICODE) . ";";
|
||||
} else {
|
||||
$api_result .= "\napiResults[\"$field\"] = [];";
|
||||
}
|
||||
|
||||
$templet = <<<EOF
|
||||
@ -928,6 +1044,9 @@ layui.each(apis, function (k, item) {
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
|
187
src/plugin/admin/app/common/Tree.php
Normal file
187
src/plugin/admin/app/common/Tree.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
namespace plugin\admin\app\common;
|
||||
|
||||
|
||||
class Tree
|
||||
{
|
||||
|
||||
/**
|
||||
* 获取完整的树结构,包含祖先节点
|
||||
*/
|
||||
const INCLUDE_ANCESTORS = 1;
|
||||
|
||||
/**
|
||||
* 获取部分树,不包含祖先节点
|
||||
*/
|
||||
const EXCLUDE_ANCESTORS = 0;
|
||||
|
||||
/**
|
||||
* 数据
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* 哈希树
|
||||
* @var array
|
||||
*/
|
||||
protected $hashTree = [];
|
||||
|
||||
/**
|
||||
* 父级字段名
|
||||
* @var string
|
||||
*/
|
||||
protected $pidName = 'pid';
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @param string $pid_name
|
||||
*/
|
||||
public function __construct($data, string $pid_name = 'pid')
|
||||
{
|
||||
$this->pidName = $pid_name;
|
||||
if (is_object($data) && method_exists($data, 'toArray')) {
|
||||
$this->data = $data->toArray();
|
||||
} else {
|
||||
$this->data = (array)$data;
|
||||
}
|
||||
$this->hashTree = $this->getHashTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子孙节点
|
||||
* @param array $include
|
||||
* @param bool $with_self
|
||||
* @return array
|
||||
*/
|
||||
public function getDescendant(array $include, bool $with_self = false): array
|
||||
{
|
||||
$items = [];
|
||||
foreach ($include as $id) {
|
||||
if (!isset($this->hashTree[$id])) {
|
||||
return [];
|
||||
}
|
||||
if ($with_self) {
|
||||
$item = $this->hashTree[$id];
|
||||
unset($item['children']);
|
||||
$items[$item['id']] = $item;
|
||||
}
|
||||
foreach ($this->hashTree[$id]['children'] ?? [] as $item) {
|
||||
unset($item['children']);
|
||||
$items[$item['id']] = $item;
|
||||
foreach ($this->getDescendant([$item['id']]) as $it) {
|
||||
$items[$it['id']] = $it;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_values($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取哈希树
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function getHashTree(array $data = []): array
|
||||
{
|
||||
$data = $data ?: $this->data;
|
||||
$hash_tree = [];
|
||||
foreach ($data as $item) {
|
||||
$hash_tree[$item['id']] = $item;
|
||||
}
|
||||
foreach ($hash_tree as $index => $item) {
|
||||
if ($item[$this->pidName] && isset($hash_tree[$item[$this->pidName]])) {
|
||||
$hash_tree[$item[$this->pidName]]['children'][$hash_tree[$index]['id']] = &$hash_tree[$index];
|
||||
}
|
||||
}
|
||||
return $hash_tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树
|
||||
* @param array $include
|
||||
* @param int $type
|
||||
* @return array|null
|
||||
*/
|
||||
public function getTree(array $include = [], int $type = 1): ?array
|
||||
{
|
||||
// $type === static::EXCLUDE_ANCESTORS
|
||||
if ($type === static::EXCLUDE_ANCESTORS) {
|
||||
$items = [];
|
||||
$include = array_unique($include);
|
||||
foreach ($include as $id) {
|
||||
if (!isset($this->hashTree[$id])) {
|
||||
return [];
|
||||
}
|
||||
$items[] = $this->hashTree[$id];
|
||||
}
|
||||
return static::arrayValues($items);
|
||||
}
|
||||
|
||||
// $type === static::INCLUDE_ANCESTORS
|
||||
$hash_tree = $this->hashTree;
|
||||
$items = [];
|
||||
if ($include) {
|
||||
$map = [];
|
||||
foreach ($include as $id) {
|
||||
if (!isset($hash_tree[$id])) {
|
||||
continue;
|
||||
}
|
||||
$item = $hash_tree[$id];
|
||||
$max_depth = 100;
|
||||
while ($max_depth-- > 0 && $item[$this->pidName] && isset($hash_tree[$item[$this->pidName]])) {
|
||||
$last_item = $item;
|
||||
$pid = $item[$this->pidName];
|
||||
$item = $hash_tree[$pid];
|
||||
$item_id = $item['id'];
|
||||
if (empty($map[$item_id])) {
|
||||
$map[$item_id] = 1;
|
||||
$hash_tree[$pid]['children'] = [];
|
||||
}
|
||||
$hash_tree[$pid]['children'][$last_item['id']] = $last_item;
|
||||
$item = $hash_tree[$pid];
|
||||
}
|
||||
$items[$item['id']] = $item;
|
||||
}
|
||||
} else {
|
||||
$items = $hash_tree;
|
||||
}
|
||||
$formatted_items = [];
|
||||
foreach ($items as $item) {
|
||||
if (!$item[$this->pidName] || !isset($hash_tree[$item[$this->pidName]])) {
|
||||
$formatted_items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return static::arrayValues($formatted_items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归重建数组下标
|
||||
* @param $array
|
||||
* @return array
|
||||
*/
|
||||
public static function arrayValues($array): array
|
||||
{
|
||||
if (!$array) {
|
||||
return [];
|
||||
}
|
||||
if (!isset($array['children'])) {
|
||||
$current = current($array);
|
||||
if (!is_array($current) || !isset($current['children'])) {
|
||||
return $array;
|
||||
}
|
||||
$tree = array_values($array);
|
||||
foreach ($tree as $index => $item) {
|
||||
$tree[$index] = static::arrayValues($item);
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
$array['children'] = array_values($array['children']);
|
||||
foreach ($array['children'] as $index => $child) {
|
||||
$array['children'][$index] = static::arrayValues($child);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
}
|
@ -2,23 +2,25 @@
|
||||
|
||||
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\Db;
|
||||
use support\exception\BusinessException;
|
||||
use Throwable;
|
||||
use function config;
|
||||
use support\Db;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* 密码哈希
|
||||
* @param $password
|
||||
* @param $algo
|
||||
* @param string $algo
|
||||
* @return false|string|null
|
||||
*/
|
||||
static public function passwordHash($password, $algo = PASSWORD_DEFAULT)
|
||||
public static function passwordHash($password, string $algo = PASSWORD_DEFAULT)
|
||||
{
|
||||
return password_hash($password, $algo);
|
||||
}
|
||||
@ -29,7 +31,7 @@ class Util
|
||||
* @param $hash
|
||||
* @return bool
|
||||
*/
|
||||
static public function passwordVerify($password, $hash): bool
|
||||
public static function passwordVerify(string $password, string $hash): bool
|
||||
{
|
||||
return password_verify($password, $hash);
|
||||
}
|
||||
@ -38,7 +40,7 @@ class Util
|
||||
* 获取webman-admin数据库连接
|
||||
* @return Connection
|
||||
*/
|
||||
static function db(): Connection
|
||||
public static function db(): Connection
|
||||
{
|
||||
return Db::connection('plugin.admin.mysql');
|
||||
}
|
||||
@ -47,17 +49,65 @@ class Util
|
||||
* 获取SchemaBuilder
|
||||
* @return Builder
|
||||
*/
|
||||
static function schema(): Builder
|
||||
public static function schema(): Builder
|
||||
{
|
||||
return Db::schema('plugin.admin.mysql');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语义化时间
|
||||
* @param $time
|
||||
* @return false|string
|
||||
*/
|
||||
public static function humanDate($time)
|
||||
{
|
||||
$timestamp = is_numeric($time) ? $time : strtotime($time);
|
||||
$dur = time() - $timestamp;
|
||||
if ($dur < 0) {
|
||||
return date('Y-m-d', $timestamp);
|
||||
} else {
|
||||
if ($dur < 60) {
|
||||
return $dur . '秒前';
|
||||
} else {
|
||||
if ($dur < 3600) {
|
||||
return floor($dur / 60) . '分钟前';
|
||||
} else {
|
||||
if ($dur < 86400) {
|
||||
return floor($dur / 3600) . '小时前';
|
||||
} else {
|
||||
if ($dur < 2592000) { // 30天内
|
||||
return floor($dur / 86400) . '天前';
|
||||
} else {
|
||||
return date('Y-m-d', $timestamp);;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return date('Y-m-d', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
* @param $file_size
|
||||
* @return string
|
||||
*/
|
||||
public static function formatBytes($file_size): string
|
||||
{
|
||||
$size = sprintf("%u", $file_size);
|
||||
if($size == 0) {
|
||||
return("0 Bytes");
|
||||
}
|
||||
$size_name = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
|
||||
return round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . $size_name[$i];
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库字符串转义
|
||||
* @param $var
|
||||
* @return false|string
|
||||
*/
|
||||
static public function pdoQuote($var)
|
||||
public static function pdoQuote($var)
|
||||
{
|
||||
return Util::db()->getPdo()->quote($var, \PDO::PARAM_STR);
|
||||
}
|
||||
@ -68,7 +118,7 @@ class Util
|
||||
* @return string
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function checkTableName(string $table): string
|
||||
public static function checkTableName(string $table): string
|
||||
{
|
||||
if (!preg_match('/^[a-zA-Z_0-9]+$/', $table)) {
|
||||
throw new BusinessException('表名不合法');
|
||||
@ -82,7 +132,7 @@ class Util
|
||||
* @return mixed
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function filterAlphaNum($var)
|
||||
public static function filterAlphaNum($var)
|
||||
{
|
||||
$vars = (array)$var;
|
||||
array_walk_recursive($vars, function ($item) {
|
||||
@ -99,7 +149,7 @@ class Util
|
||||
* @return mixed
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function filterNum($var)
|
||||
public static function filterNum($var)
|
||||
{
|
||||
$vars = (array)$var;
|
||||
array_walk_recursive($vars, function ($item) {
|
||||
@ -116,7 +166,7 @@ class Util
|
||||
* @return string
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function filterUrlPath($var): string
|
||||
public static function filterUrlPath($var): string
|
||||
{
|
||||
if (!is_string($var) || !preg_match('/^[a-zA-Z0-9_\-\/&?.]+$/', $var)) {
|
||||
throw new BusinessException('参数不合法');
|
||||
@ -130,7 +180,7 @@ class Util
|
||||
* @return string
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function filterPath($var): string
|
||||
public static function filterPath($var): string
|
||||
{
|
||||
if (!is_string($var) || !preg_match('/^[a-zA-Z0-9_\-\/]+$/', $var)) {
|
||||
throw new BusinessException('参数不合法');
|
||||
@ -183,7 +233,7 @@ class Util
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
static public function camel(string $value): string
|
||||
public static function camel(string $value): string
|
||||
{
|
||||
static $cache = [];
|
||||
$key = $value;
|
||||
@ -202,7 +252,7 @@ class Util
|
||||
* @param $value
|
||||
* @return string
|
||||
*/
|
||||
static public function smCamel($value): string
|
||||
public static function smCamel($value): string
|
||||
{
|
||||
return lcfirst(static::camel($value));
|
||||
}
|
||||
@ -212,7 +262,7 @@ class Util
|
||||
* @param $comment
|
||||
* @return false|mixed|string
|
||||
*/
|
||||
static public function getCommentFirstLine($comment)
|
||||
public static function getCommentFirstLine($comment)
|
||||
{
|
||||
if ($comment === false) {
|
||||
return false;
|
||||
@ -229,7 +279,7 @@ class Util
|
||||
* 表单类型到插件的映射
|
||||
* @return \string[][]
|
||||
*/
|
||||
static public function methodControlMap(): array
|
||||
public static function methodControlMap(): array
|
||||
{
|
||||
return [
|
||||
//method=>[控件]
|
||||
@ -265,6 +315,8 @@ class Util
|
||||
'char' => ['Input'],
|
||||
|
||||
'binary' => ['Input'],
|
||||
|
||||
'json' => ['input']
|
||||
];
|
||||
}
|
||||
|
||||
@ -273,7 +325,7 @@ class Util
|
||||
* @param $type
|
||||
* @return string
|
||||
*/
|
||||
static public function typeToControl($type): string
|
||||
public static function typeToControl($type): string
|
||||
{
|
||||
if (stripos($type, 'int') !== false) {
|
||||
return 'inputNumber';
|
||||
@ -296,7 +348,7 @@ class Util
|
||||
* @param $unsigned
|
||||
* @return string
|
||||
*/
|
||||
static public function typeToMethod($type, $unsigned = false)
|
||||
public static function typeToMethod($type, $unsigned = false)
|
||||
{
|
||||
if (stripos($type, 'int') !== false) {
|
||||
$type = str_replace('int', 'Integer', $type);
|
||||
@ -319,11 +371,11 @@ class Util
|
||||
* @return array|mixed
|
||||
* @throws BusinessException
|
||||
*/
|
||||
static public function getSchema($table, $section = null)
|
||||
public static function getSchema($table, $section = null)
|
||||
{
|
||||
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) {
|
||||
@ -395,7 +447,7 @@ class Util
|
||||
* @param $schema
|
||||
* @return mixed|string
|
||||
*/
|
||||
static public function getLengthValue($schema)
|
||||
public static function getLengthValue($schema)
|
||||
{
|
||||
$type = $schema->DATA_TYPE;
|
||||
if (in_array($type, ['float', 'decimal', 'double'])) {
|
||||
@ -421,7 +473,7 @@ class Util
|
||||
* @param $control_args
|
||||
* @return array
|
||||
*/
|
||||
static public function getControlProps($control, $control_args): array
|
||||
public static function getControlProps($control, $control_args): array
|
||||
{
|
||||
if (!$control_args) {
|
||||
return [];
|
||||
@ -461,7 +513,7 @@ class Util
|
||||
* @param string $package
|
||||
* @return mixed|string
|
||||
*/
|
||||
static public function getPackageVersion(string $package)
|
||||
public static function getPackageVersion(string $package)
|
||||
{
|
||||
$installed_php = base_path('vendor/composer/installed.php');
|
||||
if (is_file($installed_php)) {
|
||||
@ -472,18 +524,44 @@ class Util
|
||||
|
||||
|
||||
/**
|
||||
* reload webman (不支持windows)
|
||||
* Reload webman
|
||||
* @return bool
|
||||
*/
|
||||
static public function reloadWebman()
|
||||
public static function reloadWebman()
|
||||
{
|
||||
if (function_exists('posix_kill')) {
|
||||
try {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace plugin\admin\app\controller;
|
||||
|
||||
use plugin\admin\app\common\Auth;
|
||||
use plugin\admin\app\common\Util;
|
||||
use plugin\admin\app\model\Admin;
|
||||
use support\exception\BusinessException;
|
||||
@ -72,11 +73,15 @@ class AccountController extends Crud
|
||||
if (!$admin || !Util::passwordVerify($password, $admin->password)) {
|
||||
return $this->json(1, '账户不存在或密码错误');
|
||||
}
|
||||
if ($admin->status != 0) {
|
||||
return $this->json(1, '当前账户暂时无法登录');
|
||||
}
|
||||
$admin->login_at = date('Y-m-d H:i:s');
|
||||
$admin->save();
|
||||
$this->removeLoginLimit($username);
|
||||
$admin = $admin->toArray();
|
||||
$session = $request->session();
|
||||
unset($admin['password']);
|
||||
$admin['roles'] = $admin['roles'] ? explode(',', $admin['roles']) : [];
|
||||
$session->set('admin', $admin);
|
||||
return $this->json(0, '登录成功', [
|
||||
'nickname' => $admin['nickname'],
|
||||
@ -107,15 +112,14 @@ class AccountController extends Crud
|
||||
return $this->json(1);
|
||||
}
|
||||
$info = [
|
||||
'nickname' => $admin['nickname'],
|
||||
'desc' => 'manager',
|
||||
'avatar' => $admin['avatar'],
|
||||
'token' => $request->sessionId(),
|
||||
'userId' => $admin['id'],
|
||||
'id' => $admin['id'],
|
||||
'username' => $admin['username'],
|
||||
'nickname' => $admin['nickname'],
|
||||
'avatar' => $admin['avatar'],
|
||||
'email' => $admin['email'],
|
||||
'mobile' => $admin['mobile'],
|
||||
'roles' => []
|
||||
'isSupperAdmin' => Auth::isSupperAdmin(),
|
||||
'token' => $request->sessionId(),
|
||||
];
|
||||
return $this->json(0, 'ok', $info);
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
namespace plugin\admin\app\controller;
|
||||
|
||||
use plugin\admin\app\common\Auth;
|
||||
use plugin\admin\app\model\Admin;
|
||||
use plugin\admin\app\model\AdminRole;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
@ -12,12 +14,29 @@ use support\Response;
|
||||
*/
|
||||
class AdminController extends Crud
|
||||
{
|
||||
/**
|
||||
* 不需要鉴权的方法
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedAuth = ['select'];
|
||||
|
||||
/**
|
||||
* @var Admin
|
||||
*/
|
||||
protected $model = null;
|
||||
|
||||
/**
|
||||
* 开启auth数据限制
|
||||
* @var string
|
||||
*/
|
||||
protected $dataLimit = 'auth';
|
||||
|
||||
/**
|
||||
* 以id为数据限制字段
|
||||
* @var string
|
||||
*/
|
||||
protected $dataLimitField = 'id';
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @return void
|
||||
@ -36,6 +55,36 @@ class AdminController extends Crud
|
||||
return view('admin/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function select(Request $request): Response
|
||||
{
|
||||
[$where, $format, $limit, $field, $order] = $this->selectInput($request);
|
||||
$query = $this->doSelect($where, $field, $order);
|
||||
if ($format === 'select') {
|
||||
return $this->formatSelect($query->get());
|
||||
}
|
||||
$paginator = $query->paginate($limit);
|
||||
$items = $paginator->items();
|
||||
$admin_ids = array_column($items, 'id');
|
||||
$roles = AdminRole::whereIn('admin_id', $admin_ids)->get();
|
||||
$roles_map = [];
|
||||
foreach ($roles as $role) {
|
||||
$roles_map[$role['admin_id']][] = $role['role_id'];
|
||||
}
|
||||
$login_admin_id = admin_id();
|
||||
foreach ($items as $index => $item) {
|
||||
$admin_id = $item['id'];
|
||||
$items[$index]['roles'] = isset($roles_map[$admin_id]) ? implode(',', $roles_map[$admin_id]) : '';
|
||||
$items[$index]['show_toolbar'] = $admin_id != $login_admin_id;
|
||||
}
|
||||
return json(['code' => 0, 'msg' => 'ok', 'count' => $paginator->total(), 'data' => $items]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入
|
||||
* @param Request $request
|
||||
@ -45,7 +94,24 @@ class AdminController extends Crud
|
||||
public function insert(Request $request): Response
|
||||
{
|
||||
if ($request->method() === 'POST') {
|
||||
return parent::insert($request);
|
||||
$data = $this->insertInput($request);
|
||||
$admin_id = $this->doInsert($data);
|
||||
$role_ids = $request->post('roles');
|
||||
$role_ids = $role_ids ? explode(',', $role_ids) : [];
|
||||
if (!$role_ids) {
|
||||
return $this->json(1, '至少选择一个角色组');
|
||||
}
|
||||
if (!Auth::isSupperAdmin() && array_diff($role_ids, Auth::getScopeRoleIds())) {
|
||||
return $this->json(1, '角色超出权限范围');
|
||||
}
|
||||
AdminRole::where('admin_id', $admin_id)->delete();
|
||||
foreach ($role_ids as $id) {
|
||||
$admin_role = new AdminRole;
|
||||
$admin_role->admin_id = $admin_id;
|
||||
$admin_role->role_id = $id;
|
||||
$admin_role->save();
|
||||
}
|
||||
return $this->json(0, 'ok', ['id' => $admin_id]);
|
||||
}
|
||||
return view('admin/insert');
|
||||
}
|
||||
@ -59,8 +125,53 @@ class AdminController extends Crud
|
||||
public function update(Request $request): Response
|
||||
{
|
||||
if ($request->method() === 'POST') {
|
||||
return parent::update($request);
|
||||
|
||||
[$id, $data] = $this->updateInput($request);
|
||||
$admin_id = $request->post('id');
|
||||
if (!$admin_id) {
|
||||
return $this->json(1, '缺少参数');
|
||||
}
|
||||
|
||||
// 不能禁用自己
|
||||
if (isset($data['status']) && $data['status'] == 1 && $id == admin_id()) {
|
||||
return $this->json(1, '不能禁用自己');
|
||||
}
|
||||
|
||||
// 需要更新角色
|
||||
$role_ids = $request->post('roles');
|
||||
if ($role_ids !== null) {
|
||||
if (!$role_ids) {
|
||||
return $this->json(1, '至少选择一个角色组');
|
||||
}
|
||||
$role_ids = explode(',', $role_ids);
|
||||
|
||||
$is_supper_admin = Auth::isSupperAdmin();
|
||||
$exist_role_ids = AdminRole::where('admin_id', $admin_id)->pluck('role_id')->toArray();
|
||||
$scope_role_ids = Auth::getScopeRoleIds();
|
||||
if (!$is_supper_admin && !array_intersect($exist_role_ids, $scope_role_ids)) {
|
||||
return $this->json(1, '无权限更改该记录');
|
||||
}
|
||||
if (!$is_supper_admin && array_diff($role_ids, $scope_role_ids)) {
|
||||
return $this->json(1, '角色超出权限范围');
|
||||
}
|
||||
|
||||
// 删除账户角色
|
||||
$delete_ids = array_diff($exist_role_ids, $role_ids);
|
||||
AdminRole::whereIn('role_id', $delete_ids)->where('admin_id', $admin_id)->delete();
|
||||
// 添加账户角色
|
||||
$add_ids = array_diff($role_ids, $exist_role_ids);
|
||||
foreach ($add_ids as $role_id) {
|
||||
$admin_role = new AdminRole;
|
||||
$admin_role->admin_id = $admin_id;
|
||||
$admin_role->role_id = $role_id;
|
||||
$admin_role->save();
|
||||
}
|
||||
}
|
||||
|
||||
$this->doUpdate($id, $data);
|
||||
return $this->json(0);
|
||||
}
|
||||
|
||||
return view('admin/update');
|
||||
}
|
||||
|
||||
@ -80,7 +191,11 @@ class AdminController extends Crud
|
||||
if (in_array(admin_id(), $ids)) {
|
||||
return $this->json(1, '不能删除自己');
|
||||
}
|
||||
if (!Auth::isSupperAdmin() && array_diff($ids, Auth::getScopeAdminIds())) {
|
||||
return $this->json(1, '无数据权限');
|
||||
}
|
||||
$this->model->whereIn($primary_key, $ids)->delete();
|
||||
AdminRole::whereIn('admin_id', $ids)->delete();
|
||||
return $this->json(0);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ namespace plugin\admin\app\controller;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use plugin\admin\app\common\Auth;
|
||||
use plugin\admin\app\common\Tree;
|
||||
use plugin\admin\app\common\Util;
|
||||
use support\exception\BusinessException;
|
||||
use support\Model;
|
||||
@ -26,9 +28,9 @@ class Crud extends Base
|
||||
*/
|
||||
public function select(Request $request): Response
|
||||
{
|
||||
[$where, $format, $page_size, $field, $order] = $this->selectInput($request);
|
||||
[$where, $format, $limit, $field, $order] = $this->selectInput($request);
|
||||
$query = $this->doSelect($where, $field, $order);
|
||||
return $this->doFormat($query, $format, $page_size);
|
||||
return $this->doFormat($query, $format, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,6 +63,7 @@ class Crud extends Base
|
||||
* 删除
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function delete(Request $request): Response
|
||||
{
|
||||
@ -69,24 +72,6 @@ class Crud extends Base
|
||||
return $this->json(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 摘要
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
/*public function schema(Request $request): Response
|
||||
{
|
||||
$table = $this->model->getTable();
|
||||
$data = Util::getSchema($table);
|
||||
|
||||
return $this->json(0, 'ok', [
|
||||
'table' => $data['table'],
|
||||
'columns' => array_values($data['columns']),
|
||||
'forms' => array_values($data['forms']),
|
||||
'keys' => array_values($data['keys']),
|
||||
]);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 查询前置
|
||||
* @param Request $request
|
||||
@ -98,10 +83,13 @@ class Crud extends Base
|
||||
$field = $request->get('field');
|
||||
$order = $request->get('order', 'asc');
|
||||
$format = $request->get('format', 'normal');
|
||||
$page_size = $request->get('limit', $format === 'tree' ? 1000 : 10);
|
||||
$limit = (int)$request->get('limit', $format === 'tree' ? 1000 : 10);
|
||||
$limit = $limit <= 0 ? 10 : $limit;
|
||||
$order = $order === 'asc' ? 'asc' : 'desc';
|
||||
$where = $request->get();
|
||||
$table = $this->model->getTable();
|
||||
$page = (int)$request->get('page');
|
||||
$page = $page > 0 ? $page : 1;
|
||||
$table = config('plugin.admin.database.connections.mysql.prefix') . $this->model->getTable();
|
||||
|
||||
$allow_column = Util::db()->select("desc `$table`");
|
||||
if (!$allow_column) {
|
||||
@ -120,9 +108,13 @@ class Crud extends Base
|
||||
// 按照数据限制字段返回数据
|
||||
if ($this->dataLimit === 'personal') {
|
||||
$where[$this->dataLimitField] = admin_id();
|
||||
} elseif ($this->dataLimit === 'auth') {
|
||||
$primary_key = $this->model->getKeyName();
|
||||
if (!Auth::isSupperAdmin() && (!isset($where[$primary_key]) || $this->dataLimitField != $primary_key)) {
|
||||
$where[$this->dataLimitField] = ['in', Auth::getScopeAdminIds(true)];
|
||||
}
|
||||
|
||||
return [$where, $format, $page_size, $field, $order];
|
||||
}
|
||||
return [$where, $format, $limit, $field, $order, $page];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,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 {
|
||||
@ -155,24 +155,25 @@ class Crud extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化数据
|
||||
* @param $query
|
||||
* @param $format
|
||||
* @param $page_size
|
||||
* @param $limit
|
||||
* @return Response
|
||||
*/
|
||||
protected function doFormat($query, $format, $page_size): Response
|
||||
protected function doFormat($query, $format, $limit): Response
|
||||
{
|
||||
if (in_array($format, ['select', 'tree', 'table_tree'])) {
|
||||
$items = $query->get();
|
||||
if ($format == 'select') {
|
||||
return $this->formatSelect($items);
|
||||
} elseif ($format == 'tree') {
|
||||
return $this->formatTree($items);
|
||||
}
|
||||
return $this->formatTableTree($items);
|
||||
}
|
||||
$paginator = $query->paginate($page_size);
|
||||
return json(['code' => 0, 'msg' => 'ok', 'count' => $paginator->total(), 'data' => $paginator->items()]);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$paginator = $query->paginate($limit);
|
||||
$total = $paginator->total();
|
||||
$items = $paginator->items();
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
return call_user_func([$this, $format_function], $items, $total);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,6 +189,15 @@ class Crud extends Base
|
||||
if (isset($data[$password_filed])) {
|
||||
$data[$password_filed] = Util::passwordHash($data[$password_filed]);
|
||||
}
|
||||
|
||||
if (!Auth::isSupperAdmin() && $this->dataLimit) {
|
||||
if (!empty($data[$this->dataLimitField])) {
|
||||
$admin_id = $data[$this->dataLimitField];
|
||||
if (!in_array($admin_id, Auth::getScopeAdminIds(true))) {
|
||||
throw new BusinessException('无数据权限');
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -219,6 +229,12 @@ class Crud extends Base
|
||||
$primary_key = $this->model->getKeyName();
|
||||
$id = $request->post($primary_key);
|
||||
$data = $this->inputFilter($request->post());
|
||||
if (!Auth::isSupperAdmin() && $this->dataLimit && !empty($data[$this->dataLimitField])) {
|
||||
$admin_id = $data[$this->dataLimitField];
|
||||
if (!in_array($admin_id, Auth::getScopeAdminIds(true))) {
|
||||
throw new BusinessException('无数据权限');
|
||||
}
|
||||
}
|
||||
$password_filed = 'password';
|
||||
if (isset($data[$password_filed])) {
|
||||
// 密码为空,则不更新密码
|
||||
@ -259,8 +275,8 @@ class Crud extends Base
|
||||
*/
|
||||
protected function inputFilter(array $data): array
|
||||
{
|
||||
$table = $this->model->getTable();
|
||||
$allow_column = Util::db()->select("desc `$table`");
|
||||
$table = config('plugin.admin.database.connections.mysql.prefix') . $this->model->getTable();
|
||||
$allow_column = $this->model->getConnection()->select("desc `$table`");
|
||||
if (!$allow_column) {
|
||||
throw new BusinessException('表不存在', 2);
|
||||
}
|
||||
@ -291,11 +307,22 @@ class Crud extends Base
|
||||
* 删除前置方法
|
||||
* @param Request $request
|
||||
* @return array
|
||||
* @throws BusinessException
|
||||
*/
|
||||
protected function deleteInput(Request $request): array
|
||||
{
|
||||
$primary_key = $this->model->getKeyName();
|
||||
return (array)$request->post($primary_key, []);
|
||||
if (!$primary_key) {
|
||||
throw new BusinessException('该表无主键,不支持删除');
|
||||
}
|
||||
$ids = (array)$request->post($primary_key, []);
|
||||
if (!Auth::isSupperAdmin() && $this->dataLimit) {
|
||||
$admin_ids = $this->model->where($primary_key, $ids)->pluck($this->dataLimitField)->toArray();
|
||||
if (array_diff($admin_ids, Auth::getScopeAdminIds(true))) {
|
||||
throw new BusinessException('无数据权限');
|
||||
}
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,26 +346,17 @@ class Crud extends Base
|
||||
*/
|
||||
protected function formatTree($items): Response
|
||||
{
|
||||
$items_map = [];
|
||||
$format_items = [];
|
||||
foreach ($items as $item) {
|
||||
$items_map[$item->id] = [
|
||||
$format_items[] = [
|
||||
'name' => $item->title ?? $item->name ?? $item->id,
|
||||
'value' => (string)$item->id,
|
||||
'id' => $item->id,
|
||||
'pid' => $item->pid,
|
||||
];
|
||||
}
|
||||
$formatted_items = [];
|
||||
foreach ($items_map as $index => $item) {
|
||||
if ($item['pid'] && isset($items_map[$item['pid']])) {
|
||||
$items_map[$item['pid']]['children'][] = &$items_map[$index];
|
||||
}
|
||||
}
|
||||
foreach ($items_map as $item) {
|
||||
if (!$item['pid']) {
|
||||
$formatted_items[] = $item;
|
||||
}
|
||||
}
|
||||
return $this->json(0, 'ok', $formatted_items);
|
||||
$tree = new Tree($format_items);
|
||||
return $this->json(0, 'ok', $tree->getTree());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,22 +366,8 @@ class Crud extends Base
|
||||
*/
|
||||
protected function formatTableTree($items): Response
|
||||
{
|
||||
$items_map = [];
|
||||
foreach ($items as $item) {
|
||||
$items_map[$item->id] = $item->toArray();
|
||||
}
|
||||
$formatted_items = [];
|
||||
foreach ($items_map as $index => $item) {
|
||||
if ($item['pid'] && isset($items_map[$item['pid']])) {
|
||||
$items_map[$item['pid']]['children'][] = &$items_map[$index];
|
||||
}
|
||||
}
|
||||
foreach ($items_map as $item) {
|
||||
if (!$item['pid']) {
|
||||
$formatted_items[] = $item;
|
||||
}
|
||||
}
|
||||
return $this->json(0, 'ok', $formatted_items);
|
||||
$tree = new Tree($items);
|
||||
return $this->json(0, 'ok', $tree->getTree());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -383,4 +387,15 @@ class Crud extends Base
|
||||
return $this->json(0, 'ok', $formatted_items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用格式化
|
||||
* @param $items
|
||||
* @param $total
|
||||
* @return Response
|
||||
*/
|
||||
protected function formatNormal($items, $total): Response
|
||||
{
|
||||
return json(['code' => 0, 'msg' => 'ok', 'count' => $total, 'data' => $items]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace plugin\admin\app\controller;
|
||||
|
||||
use plugin\admin\app\model\Dict;
|
||||
use plugin\admin\app\model\Option;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
@ -26,6 +27,25 @@ class DictController extends Base
|
||||
return view('dict/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function select(Request $request): Response
|
||||
{
|
||||
$name = $request->get('name', '');
|
||||
if ($name && is_string($name)) {
|
||||
$items = Option::where('name', 'like', "dict_$name%")->get()->toArray();
|
||||
} else {
|
||||
$items = Option::where('name', 'like', 'dict_%')->get()->toArray();
|
||||
}
|
||||
foreach ($items as &$item) {
|
||||
$item['name'] = Dict::optionNameTodictName($item['name']);
|
||||
}
|
||||
return $this->json(0, 'ok', $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入
|
||||
* @param Request $request
|
||||
@ -36,20 +56,11 @@ class DictController extends Base
|
||||
{
|
||||
if ($request->method() === 'POST') {
|
||||
$name = $request->post('name');
|
||||
if (!preg_match('/[a-zA-Z]/', $name)) {
|
||||
return $this->json(1, '字典名只能包含字母');
|
||||
}
|
||||
$option_name = $this->dictNameToOptionName($name);
|
||||
if (Option::where('name', $option_name)->first()) {
|
||||
return $this->json(1, '字典已经存在' . $option_name);
|
||||
if (Dict::get($name)) {
|
||||
return $this->json(1, '字典已经存在');
|
||||
}
|
||||
$values = (array)$request->post('value', []);
|
||||
$format_values = $this->filterValue($values);
|
||||
$option = new Option;
|
||||
$option->name = $option_name;
|
||||
$option->value = json_encode($format_values, JSON_UNESCAPED_UNICODE);
|
||||
$option->save();
|
||||
return $this->json(0);
|
||||
Dict::save($name, $values);
|
||||
}
|
||||
return view('dict/insert');
|
||||
}
|
||||
@ -64,55 +75,26 @@ class DictController extends Base
|
||||
{
|
||||
if ($request->method() === 'POST') {
|
||||
$name = $request->post('name');
|
||||
if (!preg_match('/[a-zA-Z]/', $name)) {
|
||||
return $this->json(1, '字典名只能包含字母');
|
||||
}
|
||||
$name = $this->dictNameToOptionName($name);
|
||||
$option = Option::where('name', $name)->first();
|
||||
if (!$option) {
|
||||
if (!Dict::get($name)) {
|
||||
return $this->json(1, '字典不存在');
|
||||
}
|
||||
$format_values = $this->filterValue($request->post('value'));
|
||||
$option->name = $this->dictNameToOptionName($request->post('name'));
|
||||
$option->value = json_encode($format_values, JSON_UNESCAPED_UNICODE);
|
||||
$option->save();
|
||||
Dict::save($name, $request->post('value'));
|
||||
}
|
||||
return view('dict/update');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function delete(Request $request)
|
||||
public function delete(Request $request): Response
|
||||
{
|
||||
$names = (array)$request->post('name');
|
||||
foreach ($names as $index => $name) {
|
||||
$names[$index] = $this->dictNameToOptionName($name);
|
||||
}
|
||||
Option::whereIn('name', $names)->delete();
|
||||
Dict::delete($names);
|
||||
return $this->json(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function select(Request $request): Response
|
||||
{
|
||||
$name = $request->get('name', '');
|
||||
if ($name && is_string($name)) {
|
||||
$items = Option::where('name', 'like', "dict_$name%")->get()->toArray();
|
||||
} else {
|
||||
$items = Option::where('name', 'like', 'dict_%')->get()->toArray();
|
||||
}
|
||||
foreach ($items as &$item) {
|
||||
$item['name'] = $this->optionNameTodictName($item['name']);
|
||||
}
|
||||
return $this->json(0, 'ok', $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取
|
||||
* @param Request $request
|
||||
@ -121,47 +103,7 @@ class DictController extends Base
|
||||
*/
|
||||
public function get(Request $request, $name): Response
|
||||
{
|
||||
$value = Option::where('name', $this->dictNameToOptionName($name))->value('value');
|
||||
if ($value === null) {
|
||||
return $this->json(1, '字典不存在');
|
||||
}
|
||||
return $this->json(1, 'ok', json_decode($value, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤字典选项
|
||||
* @param array $values
|
||||
* @return array
|
||||
* @throws BusinessException
|
||||
*/
|
||||
protected function filterValue(array $values): array
|
||||
{
|
||||
$format_values = [];
|
||||
foreach ($values as $item) {
|
||||
if (!isset($item['value']) || !isset($item['name'])) {
|
||||
throw new BusinessException('格式错误', 1);
|
||||
}
|
||||
$format_values[] = ['value' => $item['value'], 'name' => $item['name']];
|
||||
}
|
||||
return $format_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function dictNameToOptionName(string $name): string
|
||||
{
|
||||
return "dict_$name";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function optionNameTodictName(string $name): string
|
||||
{
|
||||
return substr($name, 5);
|
||||
return $this->json(0, 'ok', Dict::get($name));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 = [];
|
||||
|
@ -70,6 +70,7 @@ class InstallController extends Base
|
||||
|
||||
$tables_to_install = [
|
||||
'wa_admins',
|
||||
'wa_admin_roles',
|
||||
'wa_roles',
|
||||
'wa_rules',
|
||||
'wa_options',
|
||||
@ -77,18 +78,22 @@ class InstallController extends Base
|
||||
'wa_uploads',
|
||||
];
|
||||
|
||||
if (!$overwrite) {
|
||||
$tables_exist = [];
|
||||
foreach ($tables as $table) {
|
||||
$tables_exist[] = current($table);
|
||||
}
|
||||
$tables_conflict = array_intersect($tables_to_install, $tables_exist);
|
||||
if (!$overwrite) {
|
||||
if ($tables_conflict) {
|
||||
return $this->json(1, '以下表' . implode(',', $tables_conflict) . '已经存在,如需覆盖请选择强制覆盖');
|
||||
}
|
||||
} else {
|
||||
foreach ($tables_conflict as $table) {
|
||||
$db->exec("DROP TABLE `$table`");
|
||||
}
|
||||
}
|
||||
|
||||
$sql_file = base_path() . '/plugin/admin/webman-admin.sql';
|
||||
$sql_file = base_path() . '/plugin/admin/install.sql';
|
||||
if (!is_file($sql_file)) {
|
||||
return $this->json(1, '数据库SQL文件不存在');
|
||||
}
|
||||
@ -193,22 +198,23 @@ 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']);
|
||||
$smt = $pdo->prepare("insert into `wa_admins` (`username`, `password`, `nickname`, `roles`, `created_at`, `updated_at`) values (:username, :password, :nickname, :roles, :created_at, :updated_at)");
|
||||
|
||||
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 = [
|
||||
'username' => $username,
|
||||
'password' => Util::passwordHash($password),
|
||||
'nickname' => '超级管理员',
|
||||
'roles' => '1',
|
||||
'created_at' => $time,
|
||||
'updated_at' => $time
|
||||
];
|
||||
@ -216,6 +222,13 @@ EOF;
|
||||
$smt->bindValue($key, $value);
|
||||
}
|
||||
$smt->execute();
|
||||
$admin_id = $pdo->lastInsertId();
|
||||
|
||||
$smt = $pdo->prepare("insert into `wa_admin_roles` (`role_id`, `admin_id`) values (:role_id, :admin_id)");
|
||||
$smt->bindValue('role_id', 1);
|
||||
$smt->bindValue('admin_id', $admin_id);
|
||||
$smt->execute();
|
||||
|
||||
$request->session()->flush();
|
||||
return $this->json(0);
|
||||
}
|
||||
@ -368,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,10 +114,12 @@ class PluginController extends Base
|
||||
}
|
||||
}
|
||||
|
||||
Util::pauseFileMonitor();
|
||||
try {
|
||||
// 解压zip到plugin目录
|
||||
if ($has_zip_archive) {
|
||||
$zip = new \ZipArchive;
|
||||
$zip->open($zip_file, \ZIPARCHIVE::CHECKCONS);
|
||||
$zip = new ZipArchive;
|
||||
$zip->open($zip_file, ZIPARCHIVE::CHECKCONS);
|
||||
}
|
||||
|
||||
$context = null;
|
||||
@ -171,6 +151,9 @@ class PluginController extends Base
|
||||
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)) {
|
||||
$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);
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
namespace plugin\admin\app\controller;
|
||||
|
||||
use plugin\admin\app\common\Auth;
|
||||
use plugin\admin\app\common\Tree;
|
||||
use plugin\admin\app\model\Role;
|
||||
use plugin\admin\app\model\Rule;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
@ -12,6 +15,12 @@ use support\Response;
|
||||
*/
|
||||
class RoleController extends Crud
|
||||
{
|
||||
/**
|
||||
* 不需要鉴权的方法
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedAuth = ['select'];
|
||||
|
||||
/**
|
||||
* @var Role
|
||||
*/
|
||||
@ -34,6 +43,26 @@ class RoleController extends Crud
|
||||
return view('role/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function select(Request $request): Response
|
||||
{
|
||||
$id = $request->get('id');
|
||||
[$where, $format, $limit, $field, $order] = $this->selectInput($request);
|
||||
$role_ids = Auth::getScopeRoleIds(true);
|
||||
if (!$id) {
|
||||
$where['id'] = ['in', $role_ids];
|
||||
} elseif (!in_array($id, $role_ids)) {
|
||||
throw new BusinessException('无权限');
|
||||
}
|
||||
$query = $this->doSelect($where, $field, $order);
|
||||
return $this->doFormat($query, $format, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入
|
||||
* @param Request $request
|
||||
@ -43,7 +72,18 @@ class RoleController extends Crud
|
||||
public function insert(Request $request): Response
|
||||
{
|
||||
if ($request->method() === 'POST') {
|
||||
return parent::insert($request);
|
||||
$data = $this->insertInput($request);
|
||||
$pid = $data['pid'] ?? null;
|
||||
if (!$pid) {
|
||||
return $this->json(1, '请选择父级角色组');
|
||||
}
|
||||
if (!Auth::isSupperAdmin() && !in_array($pid, Auth::getScopeRoleIds(true))) {
|
||||
return $this->json(1, '父级角色组超出权限范围');
|
||||
}
|
||||
$this->checkRules($pid, $data['rules'] ?? '');
|
||||
|
||||
$id = $this->doInsert($data);
|
||||
return $this->json(0, 'ok', ['id' => $id]);
|
||||
}
|
||||
return view('role/insert');
|
||||
}
|
||||
@ -60,11 +100,59 @@ class RoleController extends Crud
|
||||
return view('role/update');
|
||||
}
|
||||
[$id, $data] = $this->updateInput($request);
|
||||
// id为1的管理员权限固定为*
|
||||
if (isset($data['rules']) && $id == 1) {
|
||||
$data['rules'] = '*';
|
||||
$is_supper_admin = Auth::isSupperAdmin();
|
||||
$descendant_role_ids = Auth::getScopeRoleIds();
|
||||
if (!$is_supper_admin && !in_array($id, $descendant_role_ids)) {
|
||||
return $this->json(1, '无数据权限');
|
||||
}
|
||||
|
||||
$role = Role::find($id);
|
||||
if (!$role) {
|
||||
return $this->json(1, '数据不存在');
|
||||
}
|
||||
$is_supper_role = $role->rules === '*';
|
||||
|
||||
// 超级角色组不允许更改rules pid 字段
|
||||
if ($is_supper_role) {
|
||||
unset($data['rules'], $data['pid']);
|
||||
}
|
||||
|
||||
if (key_exists('pid', $data)) {
|
||||
$pid = $data['pid'];
|
||||
if (!$pid) {
|
||||
return $this->json(1, '请选择父级角色组');
|
||||
}
|
||||
if ($pid == $id) {
|
||||
return $this->json(1, '父级不能是自己');
|
||||
}
|
||||
if (!$is_supper_admin && !in_array($pid, Auth::getScopeRoleIds(true))) {
|
||||
return $this->json(1, '父级超出权限范围');
|
||||
}
|
||||
} else {
|
||||
$pid = $role->pid;
|
||||
}
|
||||
|
||||
if (!$is_supper_role) {
|
||||
$this->checkRules($pid, $data['rules'] ?? '');
|
||||
}
|
||||
|
||||
$this->doUpdate($id, $data);
|
||||
|
||||
// 删除所有子角色组中已经不存在的权限
|
||||
if (!$is_supper_role) {
|
||||
$tree = new Tree(Role::select(['id', 'pid'])->get());
|
||||
$descendant_roles = $tree->getDescendant([$id]);
|
||||
$descendant_role_ids = array_column($descendant_roles, 'id');
|
||||
$rule_ids = $data['rules'] ? explode(',', $data['rules']) : [];
|
||||
foreach ($descendant_role_ids as $role_id) {
|
||||
$tmp_role = Role::find($role_id);
|
||||
$tmp_rule_ids = $role->getRuleIds();
|
||||
$tmp_rule_ids = array_intersect($rule_ids, $tmp_rule_ids);
|
||||
$tmp_role->rules = implode(',', $tmp_rule_ids);
|
||||
$tmp_role->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->json(0);
|
||||
}
|
||||
|
||||
@ -72,6 +160,7 @@ class RoleController extends Crud
|
||||
* 删除
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function delete(Request $request): Response
|
||||
{
|
||||
@ -79,8 +168,85 @@ class RoleController extends Crud
|
||||
if (in_array(1, $ids)) {
|
||||
return $this->json(1, '无法删除超级管理员角色');
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色权限
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function rules(Request $request): Response
|
||||
{
|
||||
$role_id = $request->get('id');
|
||||
if (empty($role_id)) {
|
||||
return $this->json(0, 'ok', []);
|
||||
}
|
||||
if (!Auth::isSupperAdmin() && !in_array($role_id, Auth::getScopeRoleIds(true))) {
|
||||
return $this->json(1, '角色组超出权限范围');
|
||||
}
|
||||
$rule_id_string = Role::where('id', $role_id)->value('rules');
|
||||
if ($rule_id_string === '') {
|
||||
return $this->json(0, 'ok', []);
|
||||
}
|
||||
$rules = Rule::get();
|
||||
$include = [];
|
||||
if ($rule_id_string !== '*') {
|
||||
$include = explode(',', $rule_id_string);
|
||||
}
|
||||
$items = [];
|
||||
foreach ($rules as $item) {
|
||||
$items[] = [
|
||||
'name' => $item->title ?? $item->name ?? $item->id,
|
||||
'value' => (string)$item->id,
|
||||
'id' => $item->id,
|
||||
'pid' => $item->pid,
|
||||
];
|
||||
}
|
||||
$tree = new Tree($items);
|
||||
return $this->json(0, 'ok', $tree->getTree($include));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查权限字典是否合法
|
||||
* @param int $role_id
|
||||
* @param $rule_ids
|
||||
* @return void
|
||||
* @throws BusinessException
|
||||
*/
|
||||
protected function checkRules(int $role_id, $rule_ids)
|
||||
{
|
||||
if ($rule_ids) {
|
||||
$rule_ids = explode(',', $rule_ids);
|
||||
if (in_array('*', $rule_ids)) {
|
||||
throw new BusinessException('非法数据');
|
||||
}
|
||||
$rule_exists = Rule::whereIn('id', $rule_ids)->pluck('id');
|
||||
if (count($rule_exists) != count($rule_ids)) {
|
||||
throw new BusinessException('权限不存在');
|
||||
}
|
||||
$rule_id_string = Role::where('id', $role_id)->value('rules');
|
||||
if ($rule_id_string === '') {
|
||||
throw new BusinessException('数据超出权限范围');
|
||||
}
|
||||
if ($rule_id_string === '*') {
|
||||
return;
|
||||
}
|
||||
$legal_rule_ids = explode(',', $rule_id_string);
|
||||
if (array_diff($rule_ids, $legal_rule_ids)) {
|
||||
throw new BusinessException('数据超出权限范围');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace plugin\admin\app\controller;
|
||||
|
||||
use plugin\admin\app\common\Tree;
|
||||
use plugin\admin\app\common\Util;
|
||||
use plugin\admin\app\model\Role;
|
||||
use plugin\admin\app\model\Rule;
|
||||
@ -19,7 +20,7 @@ class RuleController extends Crud
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $noNeedAuth = ['get', 'permissionCodes'];
|
||||
protected $noNeedAuth = ['get', 'permission'];
|
||||
|
||||
/**
|
||||
* @var Rule
|
||||
@ -59,54 +60,39 @@ class RuleController extends Crud
|
||||
* 获取菜单
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws BusinessException
|
||||
*/
|
||||
function get(Request $request): Response
|
||||
{
|
||||
$rules = $this->getRules(admin('roles'));
|
||||
$items = Rule::orderBy('weight', 'desc')->get()->toArray();
|
||||
$types = $request->get('type', '0,1');
|
||||
$types = is_string($types) ? explode(',', $types) : [0, 1];
|
||||
$items_map = [];
|
||||
$items = Rule::orderBy('weight', 'desc')->get()->toArray();
|
||||
|
||||
$formatted_items = [];
|
||||
foreach ($items as $item) {
|
||||
$item['pid'] = (int)$item['pid'];
|
||||
$item['name'] = $item['title'];
|
||||
$item['value'] = $item['id'];
|
||||
$items_map[$item['id']] = $item;
|
||||
}
|
||||
$formatted_items = [];
|
||||
foreach ($items_map as $index => $item) {
|
||||
//$items_map[$index]['type'] = $items_map[$index]['href'] ? 1 : 0;
|
||||
$items_map[$index]['icon'] = $items_map[$index]['icon'] ? "layui-icon {$items_map[$index]['icon']}" : '';
|
||||
if ($item['pid'] && isset($items_map[$item['pid']])) {
|
||||
$items_map[$item['pid']]['children'][] = &$items_map[$index];
|
||||
}
|
||||
}
|
||||
foreach ($items_map as $item) {
|
||||
if (!$item['pid']) {
|
||||
$item['icon'] = $item['icon'] ? "layui-icon {$item['icon']}" : '';
|
||||
$formatted_items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$tree = new Tree($formatted_items);
|
||||
$tree_items = $tree->getTree();
|
||||
// 超级管理员权限为 *
|
||||
if (!in_array('*', $rules)) {
|
||||
$this->removeUncontain($formatted_items, 'id', $rules);
|
||||
$this->removeNotContain($tree_items, 'id', $rules);
|
||||
}
|
||||
$this->removeUncontain($formatted_items, 'type', $types);
|
||||
$formatted_items = array_values($formatted_items);
|
||||
foreach ($formatted_items as &$item) {
|
||||
$this->arrayValues($item);
|
||||
}
|
||||
return $this->json(0, 'ok', $formatted_items);
|
||||
$this->removeNotContain($tree_items, 'type', $types);
|
||||
return $this->json(0, 'ok', Tree::arrayValues($tree_items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取控制器详细权限
|
||||
* 获取权限
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function permissionCodes(Request $request): Response
|
||||
public function permission(Request $request): Response
|
||||
{
|
||||
$rules = $this->getRules(admin('roles'));
|
||||
// 超级管理员
|
||||
@ -187,7 +173,7 @@ class RuleController extends Crud
|
||||
*/
|
||||
protected function selectInput(Request $request): array
|
||||
{
|
||||
[$where, $format, $page_size, $field, $order] = parent::selectInput($request);
|
||||
[$where, $format, $limit, $field, $order] = parent::selectInput($request);
|
||||
// 允许通过type=0,1格式传递菜单类型
|
||||
$types = $request->get('type');
|
||||
if ($types && is_string($types)) {
|
||||
@ -198,7 +184,7 @@ class RuleController extends Crud
|
||||
$field = 'weight';
|
||||
$order = 'desc';
|
||||
}
|
||||
return [$where, $format, $page_size, $field, $order];
|
||||
return [$where, $format, $limit, $field, $order];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -279,7 +265,7 @@ class RuleController extends Crud
|
||||
* @param $values
|
||||
* @return void
|
||||
*/
|
||||
protected function removeUncontain(&$array, $key, $values)
|
||||
protected function removeNotContain(&$array, $key, $values)
|
||||
{
|
||||
foreach ($array as $k => &$item) {
|
||||
if (!is_array($item)) {
|
||||
@ -291,7 +277,7 @@ class RuleController extends Crud
|
||||
if (!isset($item['children'])) {
|
||||
continue;
|
||||
}
|
||||
$this->removeUncontain($item['children'], $key, $values);
|
||||
$this->removeNotContain($item['children'], $key, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -322,25 +308,6 @@ class RuleController extends Crud
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归删除某些key
|
||||
* @param $array
|
||||
* @param $keys
|
||||
* @return void
|
||||
*/
|
||||
protected function recursiveRemove(&$array, $keys)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
return;
|
||||
}
|
||||
foreach ($keys as $key) {
|
||||
unset($array[$key]);
|
||||
}
|
||||
foreach ($array as &$item) {
|
||||
$this->recursiveRemove($item, $keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限规则
|
||||
* @param $roles
|
||||
@ -359,20 +326,4 @@ class RuleController extends Crud
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归重建数组下标
|
||||
* @return void
|
||||
*/
|
||||
protected function arrayValues(&$array)
|
||||
{
|
||||
if (!is_array($array) || !isset($array['children'])) {
|
||||
return;
|
||||
}
|
||||
$array['children'] = array_values($array['children']);
|
||||
|
||||
foreach ($array['children'] as &$child) {
|
||||
$this->arrayValues($child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
@ -195,7 +201,7 @@ class TableController extends Base
|
||||
$data = $request->post();
|
||||
$old_table_name = Util::filterAlphaNum($data['old_table']);
|
||||
$table_name = Util::filterAlphaNum($data['table']);
|
||||
$table_comment = Util::pdoQuote($data['table_comment']);
|
||||
$table_comment = $data['table_comment'];
|
||||
$columns = $data['columns'];
|
||||
$forms = $data['forms'];
|
||||
$keys = $data['keys'];
|
||||
@ -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;
|
||||
@ -284,6 +291,7 @@ class TableController extends Base
|
||||
|
||||
$table = Util::getSchema($table_name, 'table');
|
||||
if ($table_comment !== $table['comment']) {
|
||||
$table_comment = Util::pdoQuote($table_comment);
|
||||
Util::db()->statement("ALTER TABLE `$table_name` COMMENT $table_comment");
|
||||
}
|
||||
|
||||
@ -320,9 +328,10 @@ class TableController extends Base
|
||||
$key_name = $key['name'];
|
||||
$old_key = $old_keys[$key_name] ?? [];
|
||||
// 如果索引有变动,则删除索引,重新建立索引
|
||||
if ($old_key && ($key['type'] != $old_key['type'] || $key['columns'] != $old_key['columns'])) {
|
||||
if ($old_key && ($key['type'] != $old_key['type'] || $key['columns'] != implode(',', $old_key['columns']))) {
|
||||
$old_key = [];
|
||||
unset($old_keys[$key_name]);
|
||||
echo "Drop Index $key_name\n";
|
||||
$table->dropIndex($key_name);
|
||||
}
|
||||
// 重新建立索引
|
||||
@ -334,6 +343,7 @@ class TableController extends Base
|
||||
$table->unique($columns, $name);
|
||||
continue;
|
||||
}
|
||||
echo "Create Index $key_name\n";
|
||||
$table->index($columns, $name);
|
||||
}
|
||||
}
|
||||
@ -343,6 +353,7 @@ class TableController extends Base
|
||||
$old_keys_names = array_column($old_keys, 'name');
|
||||
$drop_keys_names = array_diff($old_keys_names, $exists_key_names);
|
||||
foreach ($drop_keys_names as $name) {
|
||||
echo "Drop Index $name\n";
|
||||
$table->dropIndex($name);
|
||||
}
|
||||
});
|
||||
@ -385,7 +396,8 @@ class TableController extends Base
|
||||
{
|
||||
$table_name = $request->input('table');
|
||||
Util::checkTableName($table_name);
|
||||
$table_basename = strpos($table_name, 'wa_') === 0 ? substr($table_name, 3) : $table_name;
|
||||
$prefix = 'wa_';
|
||||
$table_basename = strpos($table_name, $prefix) === 0 ? substr($table_name, strlen($prefix)) : $table_name;
|
||||
$inflector = InflectorFactory::create()->build();
|
||||
$model_class = $inflector->classify($inflector->singularize($table_basename));
|
||||
$base_path = '/plugin/admin/app';
|
||||
@ -459,15 +471,17 @@ class TableController extends Base
|
||||
$app = strtolower($explode[1]) !== 'controller' ? $explode[1] : '';
|
||||
}
|
||||
|
||||
Util::pauseFileMonitor();
|
||||
try {
|
||||
$model_class = $model_file_name;
|
||||
$model_namespace = str_replace('/' , '\\', trim($model_path, '/'));
|
||||
$model_namespace = str_replace('/', '\\', trim($model_path, '/'));
|
||||
|
||||
// 创建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_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));
|
||||
@ -497,6 +511,9 @@ class TableController extends Base
|
||||
$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();
|
||||
}
|
||||
|
||||
$menu = Rule::where('key', $controller_class_with_namespace)->first();
|
||||
if (!$menu) {
|
||||
@ -546,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
|
||||
/**
|
||||
@ -568,6 +598,7 @@ class TableController extends Base
|
||||
* @var bool
|
||||
*/
|
||||
public \$timestamps = false;
|
||||
|
||||
EOF;
|
||||
|
||||
}
|
||||
@ -597,9 +628,8 @@ class $class extends Base
|
||||
* @var string
|
||||
*/
|
||||
protected \$primaryKey = '$pk';
|
||||
|
||||
$timestamps
|
||||
|
||||
$incrementing
|
||||
|
||||
}
|
||||
|
||||
@ -827,6 +857,9 @@ EOF
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
@ -839,6 +872,16 @@ EOF
|
||||
})
|
||||
});
|
||||
|
||||
// 字段允许为空
|
||||
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){
|
||||
table.reload("data-table", {
|
||||
@ -947,7 +990,7 @@ EOF;
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
$html
|
||||
</div>
|
||||
</div>
|
||||
@ -977,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,
|
||||
@ -1023,7 +1075,7 @@ EOF;
|
||||
<form class="layui-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
$html
|
||||
</div>
|
||||
</div>
|
||||
@ -1053,15 +1105,15 @@ EOF;
|
||||
const UPDATE_API = "$url_path_base/update";
|
||||
|
||||
// 获取数据库记录
|
||||
layui.use(["form", "util"], function () {
|
||||
layui.use(["form", "util", "popup"], function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: SELECT_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
|
||||
// 给表单初始化数据
|
||||
layui.each(e.data[0], function (key, value) {
|
||||
layui.each(res.data[0], function (key, value) {
|
||||
let obj = $('*[name="'+key+'"]');
|
||||
if (key === "password") {
|
||||
obj.attr("placeholder", "不更新密码请留空");
|
||||
@ -1076,12 +1128,26 @@ EOF;
|
||||
});
|
||||
$js
|
||||
|
||||
// ajax返回失败
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//提交事件
|
||||
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({
|
||||
@ -1142,7 +1208,7 @@ EOF;
|
||||
$order = $request->get('order', 'asc');
|
||||
$table = Util::filterAlphaNum($request->get('table', ''));
|
||||
$format = $request->get('format', 'normal');
|
||||
$page_size = $request->get('limit', $format === 'tree' ? 5000 : 10);
|
||||
$limit = $request->get('limit', $format === 'tree' ? 5000 : 10);
|
||||
|
||||
$allow_column = Util::db()->select("desc $table");
|
||||
if (!$allow_column) {
|
||||
@ -1160,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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$paginator = $paginator->where($column, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
$paginator = $paginator->orderBy($field, $order)->paginate($page_size, '*', 'page', $page);
|
||||
|
||||
$paginator = $paginator->orderBy($field, $order)->paginate($limit, '*', 'page', $page);
|
||||
$items = $paginator->items();
|
||||
if ($format == 'tree') {
|
||||
$items_map = [];
|
||||
@ -1348,7 +1418,8 @@ EOF;
|
||||
if (!$tables) {
|
||||
return $this->json(0, 'not found');
|
||||
}
|
||||
$table_not_allow_drop = ['wa_admins', 'wa_users', 'wa_options', 'wa_roles', 'wa_rules'];
|
||||
$prefix = 'wa_';
|
||||
$table_not_allow_drop = ["{$prefix}admins", "{$prefix}users", "{$prefix}options", "{$prefix}roles", "{$prefix}rules", "{$prefix}admin_roles", "{$prefix}uploads"];
|
||||
if ($found = array_intersect($tables, $table_not_allow_drop)) {
|
||||
return $this->json(400, implode(',', $found) . '不允许删除');
|
||||
}
|
||||
@ -1447,7 +1518,7 @@ EOF;
|
||||
$field = Util::filterAlphaNum($column['field']);
|
||||
$old_field = Util::filterAlphaNum($column['old_field'] ?? null);
|
||||
$nullable = $column['nullable'];
|
||||
$default = Util::filterAlphaNum($column['default']);
|
||||
$default = $column['default'] !== null ? Util::pdoQuote($column['default']) : null;
|
||||
$comment = Util::pdoQuote($column['comment']);
|
||||
$auto_increment = $column['auto_increment'];
|
||||
$length = (int)$column['length'];
|
||||
@ -1457,9 +1528,9 @@ EOF;
|
||||
}
|
||||
|
||||
if ($old_field && $old_field !== $field) {
|
||||
$sql = "ALTER TABLE $table CHANGE COLUMN `$old_field` `$field` ";
|
||||
$sql = "ALTER TABLE `$table` CHANGE COLUMN `$old_field` `$field` ";
|
||||
} else {
|
||||
$sql = "ALTER TABLE $table MODIFY `$field` ";
|
||||
$sql = "ALTER TABLE `$table` MODIFY `$field` ";
|
||||
}
|
||||
|
||||
if (stripos($method, 'integer') !== false) {
|
||||
@ -1515,13 +1586,14 @@ EOF;
|
||||
}
|
||||
|
||||
if ($method != 'text' && $default !== null) {
|
||||
$sql .= "DEFAULT '$default' ";
|
||||
$sql .= "DEFAULT $default ";
|
||||
}
|
||||
|
||||
if ($comment !== null) {
|
||||
$sql .= "COMMENT $comment ";
|
||||
}
|
||||
|
||||
echo "$sql\n";
|
||||
Util::db()->statement($sql);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ class UploadController extends Crud
|
||||
*/
|
||||
public function select(Request $request): Response
|
||||
{
|
||||
[$where, $format, $page_size, $field, $order] = $this->selectInput($request);
|
||||
[$where, $format, $limit, $field, $order] = $this->selectInput($request);
|
||||
if (!empty($where['ext']) && is_string($where['ext'])) {
|
||||
$where['ext'] = ['in', explode(',', $where['ext'])];
|
||||
}
|
||||
@ -70,7 +70,7 @@ class UploadController extends Crud
|
||||
$where['name'] = ['like', "%{$where['name']}%"];
|
||||
}
|
||||
$query = $this->doSelect($where, $field, $order);
|
||||
return $this->doFormat($query, $format, $page_size);
|
||||
return $this->doFormat($query, $format, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,19 +306,4 @@ class UploadController extends Crud
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
* @param $file_size
|
||||
* @return string
|
||||
*/
|
||||
protected function formatSize($file_size): string
|
||||
{
|
||||
$size = sprintf("%u", $file_size);
|
||||
if($size == 0) {
|
||||
return("0 Bytes");
|
||||
}
|
||||
$size_name = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
|
||||
return round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . $size_name[$i];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,15 +3,15 @@
|
||||
* Here is your custom functions.
|
||||
*/
|
||||
|
||||
use app\model\User;
|
||||
use plugin\admin\app\model\User;
|
||||
use plugin\admin\app\model\Admin;
|
||||
use support\exception\BusinessException;
|
||||
use plugin\admin\app\model\AdminRole;
|
||||
|
||||
/**
|
||||
* 当前管理员id
|
||||
* @return integer|null
|
||||
*/
|
||||
function admin_id()
|
||||
function admin_id(): ?int
|
||||
{
|
||||
return session('admin.id');
|
||||
}
|
||||
@ -20,7 +20,6 @@ function admin_id()
|
||||
* 当前管理员
|
||||
* @param null|array|string $fields
|
||||
* @return array|mixed|null
|
||||
* @throws BusinessException
|
||||
*/
|
||||
function admin($fields = null)
|
||||
{
|
||||
@ -45,7 +44,7 @@ function admin($fields = null)
|
||||
* 当前登录用户id
|
||||
* @return integer|null
|
||||
*/
|
||||
function user_id()
|
||||
function user_id(): ?int
|
||||
{
|
||||
return session('user.id');
|
||||
}
|
||||
@ -54,7 +53,6 @@ function user_id()
|
||||
* 当前登录用户
|
||||
* @param null|array|string $fields
|
||||
* @return array|mixed|null
|
||||
* @throws BusinessException
|
||||
*/
|
||||
function user($fields = null)
|
||||
{
|
||||
@ -79,7 +77,6 @@ function user($fields = null)
|
||||
* 刷新当前管理员session
|
||||
* @param bool $force
|
||||
* @return void
|
||||
* @throws BusinessException
|
||||
*/
|
||||
function refresh_admin_session(bool $force = false)
|
||||
{
|
||||
@ -101,7 +98,12 @@ function refresh_admin_session(bool $force = false)
|
||||
}
|
||||
$admin = $admin->toArray();
|
||||
unset($admin['password']);
|
||||
$admin['roles'] = $admin['roles'] ? explode(',', $admin['roles']) : [];
|
||||
// 账户被禁用
|
||||
if ($admin['status'] != 0) {
|
||||
$session->forget('admin');
|
||||
return;
|
||||
}
|
||||
$admin['roles'] = AdminRole::where('admin_id', $admin_id)->pluck('role_id')->toArray();
|
||||
$admin['session_last_update_time'] = $time_now;
|
||||
$session->set('admin', $admin);
|
||||
}
|
||||
@ -111,7 +113,6 @@ function refresh_admin_session(bool $force = false)
|
||||
* 刷新当前用户session
|
||||
* @param bool $force
|
||||
* @return void
|
||||
* @throws BusinessException
|
||||
*/
|
||||
function refresh_user_session(bool $force = false)
|
||||
{
|
||||
|
@ -2,6 +2,8 @@
|
||||
namespace plugin\admin\app\middleware;
|
||||
|
||||
use plugin\admin\api\Auth;
|
||||
use ReflectionException;
|
||||
use support\exception\BusinessException;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use Webman\MiddlewareInterface;
|
||||
@ -12,7 +14,7 @@ class AccessControl implements MiddlewareInterface
|
||||
* @param Request $request
|
||||
* @param callable $handler
|
||||
* @return Response
|
||||
* @throws \ReflectionException
|
||||
* @throws ReflectionException|BusinessException
|
||||
*/
|
||||
public function process(Request $request, callable $handler): Response
|
||||
{
|
||||
@ -35,7 +37,9 @@ class AccessControl implements MiddlewareInterface
|
||||
EOF
|
||||
);
|
||||
} else {
|
||||
$response = view('common/error/403');
|
||||
$request->app = '';
|
||||
$request->plugin = 'admin';
|
||||
$response = view('common/error/403')->withStatus(403);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ use plugin\admin\app\model\Base;
|
||||
* @property string $mobile 手机
|
||||
* @property string $created_at 创建时间
|
||||
* @property string $updated_at 更新时间
|
||||
* @property string $login_at 登录时间
|
||||
* @property string $roles 角色
|
||||
* @property integer $status 状态 0正常 1禁用
|
||||
*/
|
||||
class Admin extends Base
|
||||
{
|
||||
|
31
src/plugin/admin/app/model/AdminRole.php
Normal file
31
src/plugin/admin/app/model/AdminRole.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\admin\app\model;
|
||||
|
||||
use plugin\admin\app\model\Base;
|
||||
|
||||
/**
|
||||
* @property integer $id ID(主键)
|
||||
* @property string $admin_id 管理员id
|
||||
* @property string $role_id 角色id
|
||||
*/
|
||||
class AdminRole extends Base
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'wa_admin_roles';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
}
|
96
src/plugin/admin/app/model/Dict.php
Normal file
96
src/plugin/admin/app/model/Dict.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\admin\app\model;
|
||||
|
||||
|
||||
use support\exception\BusinessException;
|
||||
|
||||
/**
|
||||
* 字典相关
|
||||
*/
|
||||
class Dict
|
||||
{
|
||||
/**
|
||||
* 获取字典
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function get($name)
|
||||
{
|
||||
$value = Option::where('name', static::dictNameToOptionName($name))->value('value');
|
||||
return $value ? json_decode($value, true) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存字典
|
||||
* @param $name
|
||||
* @param $values
|
||||
* @return void
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public static function save($name, $values)
|
||||
{
|
||||
if (!preg_match('/[a-zA-Z]/', $name)) {
|
||||
throw new BusinessException('字典名只能包含字母');
|
||||
}
|
||||
$option_name = static::dictNameToOptionName($name);
|
||||
if (!$option = Option::where('name', $option_name)->first()) {
|
||||
$option = new Option;
|
||||
}
|
||||
$format_values = static::filterValue($values);
|
||||
$option->name = $option_name;
|
||||
$option->value = json_encode($format_values, JSON_UNESCAPED_UNICODE);
|
||||
$option->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典
|
||||
* @param array $names
|
||||
* @return void
|
||||
*/
|
||||
public static function delete(array $names)
|
||||
{
|
||||
foreach ($names as $index => $name) {
|
||||
$names[$index] = static::dictNameToOptionName($name);
|
||||
}
|
||||
Option::whereIn('name', $names)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典名到option名转换
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public static function dictNameToOptionName(string $name): string
|
||||
{
|
||||
return "dict_$name";
|
||||
}
|
||||
|
||||
/**
|
||||
* option名到字典名转换
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public static function optionNameToDictName(string $name): string
|
||||
{
|
||||
return substr($name, 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤值
|
||||
* @param array $values
|
||||
* @return array
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public static function filterValue(array $values): array
|
||||
{
|
||||
$format_values = [];
|
||||
foreach ($values as $item) {
|
||||
if (!isset($item['value']) || !isset($item['name'])) {
|
||||
throw new BusinessException('字典格式错误', 1);
|
||||
}
|
||||
$format_values[] = ['value' => $item['value'], 'name' => $item['name']];
|
||||
}
|
||||
return $format_values;
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace plugin\admin\app\model;
|
||||
|
||||
use plugin\admin\app\model\Base;
|
||||
|
||||
/**
|
||||
* @property integer $id 主键(主键)
|
||||
@ -10,6 +9,7 @@ use plugin\admin\app\model\Base;
|
||||
* @property string $rules 权限
|
||||
* @property string $created_at 创建时间
|
||||
* @property string $updated_at 更新时间
|
||||
* @property integer $pid 上级id
|
||||
*/
|
||||
class Role extends Base
|
||||
{
|
||||
@ -27,7 +27,12 @@ class Role extends Base
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRuleIds()
|
||||
{
|
||||
return $this->rules ? explode(',', $this->rules) : [];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -89,8 +89,10 @@
|
||||
|
||||
<!-- 表格行工具栏 -->
|
||||
<script type="text/html" id="table-bar">
|
||||
{{# if(d.show_toolbar){ }}
|
||||
<button class="pear-btn pear-btn-xs tool-btn" lay-event="edit" permission="app.admin.admin.update">编辑</button>
|
||||
<button class="pear-btn pear-btn-xs tool-btn" lay-event="remove" permission="app.admin.admin.delete">删除</button>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script src="/app/admin/component/layui/layui.js"></script>
|
||||
@ -130,6 +132,8 @@
|
||||
},{
|
||||
title: "ID",
|
||||
field: "id",
|
||||
width: 100,
|
||||
sort: true,
|
||||
},{
|
||||
title: "用户名",
|
||||
field: "username",
|
||||
@ -145,13 +149,16 @@
|
||||
field: "avatar",
|
||||
templet: function (d) {
|
||||
return '<img src="'+encodeURI(d['avatar'])+'" style="max-width:32px;max-height:32px;" alt="" />'
|
||||
}
|
||||
},
|
||||
width: 90,
|
||||
},{
|
||||
title: "邮箱",
|
||||
field: "email",
|
||||
hide: true,
|
||||
},{
|
||||
title: "手机",
|
||||
field: "mobile",
|
||||
hide: true,
|
||||
},{
|
||||
title: "创建时间",
|
||||
field: "created_at",
|
||||
@ -160,6 +167,9 @@
|
||||
title: "更新时间",
|
||||
field: "updated_at",
|
||||
hide: true,
|
||||
},{
|
||||
title: "登录时间",
|
||||
field: "login_at",
|
||||
},{
|
||||
title: "角色",
|
||||
field: "roles",
|
||||
@ -172,6 +182,32 @@
|
||||
});
|
||||
return util.escape(items.join(","));
|
||||
}
|
||||
},{
|
||||
title: "禁用",
|
||||
field: "status",
|
||||
templet: function (d) {
|
||||
let field = "status";
|
||||
form.on("switch("+field+")", function (data) {
|
||||
let load = layer.load();
|
||||
let postData = {};
|
||||
postData[field] = data.elem.checked ? 1 : 0;
|
||||
postData[PRIMARY_KEY] = this.value;
|
||||
$.post(UPDATE_API, postData, function (res) {
|
||||
layer.close(load);
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg, function () {
|
||||
data.elem.checked = !data.elem.checked;
|
||||
form.render();
|
||||
});
|
||||
}
|
||||
return layui.popup.success("操作成功");
|
||||
})
|
||||
});
|
||||
let checked = d[field] === 1 ? "checked" : "";
|
||||
if (parent.Admin.Account.id === d.id) return '';
|
||||
return '<input type="checkbox" value="'+util.escape(d[PRIMARY_KEY])+'" lay-filter="'+util.escape(field)+'" lay-skin="switch" lay-text="'+util.escape('')+'" '+checked+'/>';
|
||||
},
|
||||
width: 90,
|
||||
},{
|
||||
title: "操作",
|
||||
toolbar: "#table-bar",
|
||||
@ -216,6 +252,9 @@
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
@ -261,6 +300,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -11,7 +11,14 @@
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">角色</label>
|
||||
<div class="layui-input-block">
|
||||
<div name="roles" id="roles" value=""></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">用户名</label>
|
||||
@ -37,7 +44,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-block">
|
||||
<img style="max-width:90px;max-height:90px;" src=""/>
|
||||
<img class="img-3" src=""/>
|
||||
<input type="text" style="display:none" name="avatar" value="/app/admin/avatar.png" />
|
||||
<button type="button" class="pear-btn pear-btn-primary pear-btn-sm" id="avatar">
|
||||
<i class="layui-icon layui-icon-upload"></i>上传图片
|
||||
@ -62,13 +69,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色</label>
|
||||
<div class="layui-input-block">
|
||||
<div name="roles" id="roles" value="" ></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -125,21 +125,30 @@
|
||||
});
|
||||
|
||||
// 字段 角色 roles
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/role/select?format=select",
|
||||
url: "/app/admin/role/select?format=tree",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#roles").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
if (!top.Admin.Account.isSupperAdmin) {
|
||||
layui.each(res.data, function (k, v) {
|
||||
v.disabled = true;
|
||||
});
|
||||
}
|
||||
layui.xmSelect.render({
|
||||
el: "#roles",
|
||||
name: "roles",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
tree: {"show":true},
|
||||
toolbar: {"show":true,"list":["ALL","CLEAR","REVERSE"]},
|
||||
})
|
||||
data: res.data,
|
||||
layVerify: "required",
|
||||
tree: {"show":true, expandedKeys:true, strict:false},
|
||||
toolbar: {show:true, list:["ALL","CLEAR","REVERSE"]},
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -11,7 +11,14 @@
|
||||
<form class="layui-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">角色</label>
|
||||
<div class="layui-input-block">
|
||||
<div name="roles" id="roles" value="" ></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">用户名</label>
|
||||
@ -37,7 +44,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-block">
|
||||
<img style="max-width:90px;max-height:90px;" src=""/>
|
||||
<img class="img-3" src=""/>
|
||||
<input type="text" style="display:none" name="avatar" value="" />
|
||||
<button type="button" class="pear-btn pear-btn-primary pear-btn-sm" id="avatar" permission="app.admin.upload.avatar">
|
||||
<i class="layui-icon layui-icon-upload"></i>上传图片
|
||||
@ -62,13 +69,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色</label>
|
||||
<div class="layui-input-block">
|
||||
<div name="roles" id="roles" value="" ></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -96,15 +96,15 @@
|
||||
const UPDATE_API = "/app/admin/admin/update";
|
||||
|
||||
// 获取数据库记录
|
||||
layui.use(["form", "util"], function () {
|
||||
layui.use(["form", "util", "popup"], function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: SELECT_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
|
||||
// 给表单初始化数据
|
||||
layui.each(e.data[0], function (key, value) {
|
||||
layui.each(res.data[0], function (key, value) {
|
||||
let obj = $('*[name="'+key+'"]');
|
||||
if (key === "password") {
|
||||
obj.attr("placeholder", "不更新密码请留空");
|
||||
@ -150,23 +150,36 @@
|
||||
// 字段 角色 roles
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/role/select?format=select",
|
||||
url: "/app/admin/role/select?format=tree",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#roles").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
if (!top.Admin.Account.isSupperAdmin) {
|
||||
layui.each(res.data, function (k, v) {
|
||||
v.disabled = true;
|
||||
});
|
||||
}
|
||||
layui.xmSelect.render({
|
||||
el: "#roles",
|
||||
name: "roles",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
tree: {show: true, expandedKeys: initValue},
|
||||
data: res.data,
|
||||
layVerify: "required",
|
||||
tree: {show: true, expandedKeys: true, strict: false},
|
||||
toolbar: {show: true, list: ["ALL","CLEAR","REVERSE"]},
|
||||
})
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ajax产生错误
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -38,7 +38,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站Logo</label>
|
||||
<div class="layui-input-block">
|
||||
<img style="max-width:90px;max-height:90px;" src=""/>
|
||||
<img class="img-3" src=""/>
|
||||
<input type="text" style="display:none" name="image" value="/app/admin/admin/avatar.png" />
|
||||
<button type="button" class="pear-btn pear-btn-primary pear-btn-sm" id="image" permission="app.admin.upload.avatar">
|
||||
<i class="layui-icon layui-icon-upload"></i>上传图片
|
||||
@ -290,6 +290,9 @@
|
||||
url: "/app/admin/config/get",
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
form.val("baseInfo", res.logo);
|
||||
$("#image").prev().val(res.logo.image).prev().attr("src", res.logo.image);
|
||||
form.val("menuInfo", res.menu);
|
||||
|
@ -156,6 +156,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -37,7 +37,7 @@
|
||||
<form class="layui-form" action="" lay-filter="create-dict-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
|
@ -37,7 +37,7 @@
|
||||
<form class="layui-form" action="" lay-filter="create-dict-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
@ -135,6 +135,10 @@
|
||||
layui.each(data, function (k, v) {
|
||||
data[k]["_field_id"] = _field_id++;
|
||||
})
|
||||
// ajax产生错误
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -5,13 +5,13 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>主页</title>
|
||||
<!-- 依 赖 样 式 -->
|
||||
<link rel="stylesheet" href="component/pear/css/pear.css" />
|
||||
<link rel="stylesheet" href="/app/admin/component/pear/css/pear.css" />
|
||||
<!-- 加 载 样 式 -->
|
||||
<link rel="stylesheet" href="admin/css/loader.css" />
|
||||
<link rel="stylesheet" href="/app/admin/admin/css/loader.css" />
|
||||
<!-- 布 局 样 式 -->
|
||||
<link rel="stylesheet" href="admin/css/admin.css" />
|
||||
<link rel="stylesheet" href="/app/admin/admin/css/admin.css" />
|
||||
<!-- 重置样式 -->
|
||||
<link rel="stylesheet" href="admin/css/reset.css" />
|
||||
<link rel="stylesheet" href="/app/admin/admin/css/reset.css" />
|
||||
</head>
|
||||
<!-- 结 构 代 码 -->
|
||||
<body class="layui-layout-body pear-admin">
|
||||
@ -43,7 +43,7 @@
|
||||
<a class="layui-icon layui-icon-username" href="javascript:;"></a>
|
||||
<!-- 功 能 菜 单 -->
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a user-menu-url="/app/admin/account/index" user-menu-id="11" user-menu-title="基本资料">基本资料</a></dd>
|
||||
<dd><a user-menu-url="/app/admin/account/index" user-menu-id="10" user-menu-title="基本资料">基本资料</a></dd>
|
||||
<dd><a href="javascript:void(0);" class="logout">注销登录</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
@ -90,10 +90,16 @@
|
||||
<a href="#" class="layui-icon layui-icon-shrink-right"></a>
|
||||
</div>
|
||||
<!-- 依 赖 脚 本 -->
|
||||
<script src="component/layui/layui.js"></script>
|
||||
<script src="component/pear/pear.js"></script>
|
||||
<script src="/app/admin/component/layui/layui.js"></script>
|
||||
<script src="/app/admin/component/pear/pear.js"></script>
|
||||
<!-- 框 架 初 始 化 -->
|
||||
<script>
|
||||
|
||||
// Admin
|
||||
window.Admin = {
|
||||
Account: {}
|
||||
};
|
||||
|
||||
layui.use(["admin","jquery","popup","drawer"], function() {
|
||||
var $ = layui.$;
|
||||
var admin = layui.admin;
|
||||
@ -121,9 +127,18 @@
|
||||
return false;
|
||||
})
|
||||
|
||||
$.ajax({
|
||||
url: "/app/admin/account/info",
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
window.Admin.Account = res.data;
|
||||
}
|
||||
});
|
||||
|
||||
// 消息点击回调
|
||||
//admin.message(function(id, title, context, form) {});
|
||||
})
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -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 (e) {
|
||||
let cols = e.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>
|
@ -10,44 +10,7 @@
|
||||
<body class="pear-container">
|
||||
|
||||
<!-- 顶部查询表单 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form top-search-from">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">创建时间</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-input-block" id="created_at">
|
||||
<input type="text" autocomplete="off" name="created_at[]" id="created_at-date-start" class="layui-input inline-block" placeholder="开始时间">
|
||||
-
|
||||
<input type="text" autocomplete="off" name="created_at[]" id="created_at-date-end" class="layui-input inline-block" placeholder="结束时间">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label"></label>
|
||||
<button class="pear-btn pear-btn-md pear-btn-primary" lay-submit lay-filter="table-query">
|
||||
<i class="layui-icon layui-icon-search"></i>查询
|
||||
</button>
|
||||
<button type="reset" class="pear-btn pear-btn-md" lay-submit lay-filter="table-reset">
|
||||
<i class="layui-icon layui-icon-refresh"></i>重置
|
||||
</button>
|
||||
</div>
|
||||
<div class="toggle-btn">
|
||||
<a class="layui-hide">展开<i class="layui-icon layui-icon-down"></i></a>
|
||||
<a class="layui-hide">收起<i class="layui-icon layui-icon-up"></i></a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="layui-card">
|
||||
@ -68,14 +31,17 @@
|
||||
|
||||
<!-- 表格行工具栏 -->
|
||||
<script type="text/html" id="table-bar">
|
||||
{{# if(d.id!==1&&d.pid&&!d.isRoot){ }}
|
||||
<button class="pear-btn pear-btn-xs tool-btn" lay-event="edit" permission="app.admin.role.update">编辑</button>
|
||||
<button class="pear-btn pear-btn-xs tool-btn" lay-event="remove" permission="app.admin.role.delete">删除</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 src="/app/admin/admin/js/common.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
// 相关常量
|
||||
@ -86,16 +52,9 @@
|
||||
const INSERT_URL = "/app/admin/role/insert";
|
||||
const UPDATE_URL = "/app/admin/role/update";
|
||||
|
||||
// 字段 创建时间 created_at
|
||||
layui.use(["laydate"], function() {
|
||||
layui.laydate.render({
|
||||
elem: "#created_at",
|
||||
range: ["#created_at-date-start", "#created_at-date-end"],
|
||||
});
|
||||
})
|
||||
|
||||
// 表格渲染
|
||||
layui.use(["table", "form", "common", "popup", "util"], function() {
|
||||
layui.use(["table", "treetable", "form", "common", "popup", "util"], function() {
|
||||
let treeTable = layui.treetable;
|
||||
let table = layui.table;
|
||||
let form = layui.form;
|
||||
let $ = layui.$;
|
||||
@ -106,13 +65,12 @@
|
||||
let cols = [
|
||||
{
|
||||
type: "checkbox"
|
||||
},{
|
||||
title: "角色组",
|
||||
field: "name",
|
||||
},{
|
||||
title: "主键",
|
||||
field: "id",
|
||||
hide: true,
|
||||
},{
|
||||
title: "角色名",
|
||||
field: "name",
|
||||
},{
|
||||
title: "权限",
|
||||
field: "rules",
|
||||
@ -124,50 +82,65 @@
|
||||
items.push(apiResults[field][v] || v);
|
||||
});
|
||||
return util.escape(items.join(","));
|
||||
}
|
||||
},
|
||||
hide: true,
|
||||
},{
|
||||
title: "创建时间",
|
||||
field: "created_at",
|
||||
},{
|
||||
title: "更新时间",
|
||||
field: "updated_at",
|
||||
},{
|
||||
title: "父级",
|
||||
field: "pid",
|
||||
templet: function (d) {
|
||||
let field = "pid";
|
||||
if (typeof d[field] == "undefined") return "";
|
||||
let items = [];
|
||||
layui.each((d[field] + "").split(","), function (k , v) {
|
||||
items.push(apiResults[field][v] || v);
|
||||
});
|
||||
return util.escape(items.join(","));
|
||||
},
|
||||
hide: true,
|
||||
},{
|
||||
title: "操作",
|
||||
toolbar: "#table-bar",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 130,
|
||||
width: 120,
|
||||
}
|
||||
];
|
||||
|
||||
// 渲染表格
|
||||
function render()
|
||||
{
|
||||
table.render({
|
||||
treeTable.render({
|
||||
elem: "#data-table",
|
||||
url: SELECT_API,
|
||||
page: true,
|
||||
treeColIndex: 1,
|
||||
treeIdName: "id",
|
||||
treePidName: "pid",
|
||||
treeDefaultClose: false,
|
||||
cols: [cols],
|
||||
skin: "line",
|
||||
size: "lg",
|
||||
toolbar: "#table-toolbar",
|
||||
autoSort: false,
|
||||
defaultToolbar: [{
|
||||
title: "刷新",
|
||||
layEvent: "refresh",
|
||||
icon: "layui-icon-refresh",
|
||||
}, "filter", "print", "exports"],
|
||||
done: function () {
|
||||
layer.photos({photos: 'div[lay-id="data-table"]', anim: 5});
|
||||
}
|
||||
}, "filter", "print", "exports"]
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格中下拉或树形组件数据
|
||||
let apis = [];
|
||||
apis.push(["rules", "/app/admin/rule/get?type=0,1,2"]);
|
||||
apis.push(["pid", "/app/admin/role/select?format=tree"]);
|
||||
let apiResults = {};
|
||||
apiResults["rules"] = [];
|
||||
apiResults["pid"] = [];
|
||||
let count = apis.length;
|
||||
layui.each(apis, function (k, item) {
|
||||
let [field, url] = item;
|
||||
@ -175,6 +148,9 @@
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
@ -220,6 +196,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
@ -310,9 +289,7 @@
|
||||
|
||||
// 刷新表格数据
|
||||
window.refreshTable = function(param) {
|
||||
table.reloadData("data-table", {
|
||||
scrollPos: "fixed"
|
||||
});
|
||||
treeTable.reload("#data-table");
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -11,7 +11,14 @@
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">父级</label>
|
||||
<div class="layui-input-block">
|
||||
<div name="pid" id="pid" value="1" ></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">角色名</label>
|
||||
@ -47,31 +54,73 @@
|
||||
<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 INSERT_API = "/app/admin/role/insert";
|
||||
|
||||
// 字段 权限 rules
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/rule/get?type=0,1,2",
|
||||
url: "/app/admin/role/rules?id=1",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#rules").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#rules",
|
||||
name: "rules",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
tree: {"show":true},
|
||||
toolbar: {"show":true,"list":["ALL","CLEAR","REVERSE"]},
|
||||
data: res.data,
|
||||
tree: {"show":true,expandedKeys:initValue},
|
||||
toolbar: {show:true,list:["ALL","CLEAR","REVERSE"]},
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 字段 父级 pid
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/role/select?format=tree",
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
let value = layui.$("#pid").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#pid",
|
||||
name: "pid",
|
||||
initValue: initValue,
|
||||
tips: "请选择",
|
||||
data: res.data,
|
||||
value: "0",
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
tree: {show: true,"strict":false,"clickCheck":true,"clickExpand":false,expandedKeys:true},
|
||||
on: function(data){
|
||||
let id = data.arr[0] ? data.arr[0].value : "";
|
||||
if (!id) return;
|
||||
layui.$.ajax({
|
||||
url: '/app/admin/role/rules?id=' + id,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
layui.xmSelect.get('#rules')[0].update({data:res.data});
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//提交事件
|
||||
layui.use(["form", "popup"], function () {
|
||||
layui.form.on("submit(save)", function (data) {
|
||||
|
@ -11,7 +11,14 @@
|
||||
<form class="layui-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">父级</label>
|
||||
<div class="layui-input-block">
|
||||
<div name="pid" id="pid" value="" ></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">角色名</label>
|
||||
@ -46,6 +53,7 @@
|
||||
<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>
|
||||
|
||||
// 相关接口
|
||||
@ -54,15 +62,15 @@
|
||||
const UPDATE_API = "/app/admin/role/update";
|
||||
|
||||
// 获取数据库记录
|
||||
layui.use(["form", "util"], function () {
|
||||
layui.use(["form", "util", "popup"], function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: SELECT_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
|
||||
// 给表单初始化数据
|
||||
layui.each(e.data[0], function (key, value) {
|
||||
layui.each(res.data[0], function (key, value) {
|
||||
let obj = $('*[name="'+key+'"]');
|
||||
if (key === "password") {
|
||||
obj.attr("placeholder", "不更新密码请留空");
|
||||
@ -77,25 +85,74 @@
|
||||
});
|
||||
|
||||
// 字段 权限 rules
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/rule/get?type=0,1,2",
|
||||
url: "/app/admin/role/rules?id=" + res.data[0].pid,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#rules").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#rules",
|
||||
name: "rules",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
tree: {show: true, expandedKeys: initValue},
|
||||
toolbar: {show: true, list: ["ALL","CLEAR","REVERSE"]},
|
||||
data: res.data,
|
||||
tree: {"show":true,expandedKeys:initValue},
|
||||
toolbar: {show:true,list:["ALL","CLEAR","REVERSE"]},
|
||||
})
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 字段 父级角色组 pid
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/role/select?format=tree",
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
let value = layui.$("#pid").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#pid",
|
||||
name: "pid",
|
||||
initValue: initValue,
|
||||
tips: "请选择",
|
||||
toolbar: {show: true, list: ["CLEAR"]},
|
||||
data: res.data,
|
||||
value: "0",
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
tree: {show: true,"strict":false,"clickCheck":true,"clickExpand":false,expandedKeys:true},
|
||||
on: function(data){
|
||||
let id = data.arr[0] ? data.arr[0].value : "";
|
||||
if (!id) return;
|
||||
layui.$.ajax({
|
||||
url: '/app/admin/role/rules?id=' + id,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
layui.xmSelect.get('#rules')[0].update({data:res.data});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ajax产生错误
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -9,33 +9,6 @@
|
||||
</head>
|
||||
<body class="pear-container">
|
||||
|
||||
<!-- 顶部搜索表单 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form top-search-from">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" value="" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label"></label>
|
||||
<button class="pear-btn pear-btn-md pear-btn-primary" lay-submit lay-filter="table-query">
|
||||
<i class="layui-icon layui-icon-search"></i>查询
|
||||
</button>
|
||||
<button type="reset" class="pear-btn pear-btn-md" lay-submit lay-filter="table-reset">
|
||||
<i class="layui-icon layui-icon-refresh"></i>重置
|
||||
</button>
|
||||
</div>
|
||||
<div class="toggle-btn">
|
||||
<a class="layui-hide">展开<i class="layui-icon layui-icon-down"></i></a>
|
||||
<a class="layui-hide">收起<i class="layui-icon layui-icon-up"></i></a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
@ -157,7 +130,6 @@
|
||||
elem: "#data-table",
|
||||
url: SELECT_API,
|
||||
treeColIndex: 1,
|
||||
treeSpid: 0,
|
||||
treeIdName: "id",
|
||||
treePidName: "pid",
|
||||
treeDefaultClose: true,
|
||||
@ -186,6 +158,9 @@
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
|
@ -18,7 +18,7 @@
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">标题</label>
|
||||
@ -103,11 +103,11 @@
|
||||
});
|
||||
|
||||
// 上级菜单
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/rule/select?format=tree&type=0,1",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#pid").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
@ -116,13 +116,16 @@
|
||||
initValue: initValue,
|
||||
tips: "无",
|
||||
toolbar: {show: true, list: ["CLEAR"]},
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
value: "0",
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
tree: {show: true,"strict":false,"clickCheck":true,"clickExpand":false},
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -18,7 +18,7 @@
|
||||
<form class="layui-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">标题</label>
|
||||
@ -95,15 +95,15 @@
|
||||
const UPDATE_API = "/app/admin/rule/update";
|
||||
|
||||
// 获取行数据
|
||||
layui.use(["form", "util"], function () {
|
||||
layui.use(["form", "util", "popup"], function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: SELECT_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
|
||||
// 赋值表单
|
||||
layui.each(e.data[0], function (key, value) {
|
||||
layui.each(res.data[0], function (key, value) {
|
||||
let obj = $('*[name="'+key+'"]');
|
||||
if (key === "password") {
|
||||
obj.attr("placeholder", "不更新密码请留空");
|
||||
@ -127,11 +127,11 @@
|
||||
});
|
||||
|
||||
// 获取上级菜单
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/rule/select?format=tree&type=0,1",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#pid").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
@ -140,12 +140,15 @@
|
||||
initValue: initValue,
|
||||
tips: "无",
|
||||
toolbar: {show: true, list: ["CLEAR"]},
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
tree: {show: true,"strict":false,"clickCheck":true,"clickExpand":false,expandedKeys: initValue},
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -165,6 +168,10 @@
|
||||
})
|
||||
});
|
||||
|
||||
// ajax产生错误
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -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>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
<input type="hidden" name="table" value="<?=htmlspecialchars($table)?>">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">菜单名</label>
|
||||
@ -78,11 +78,11 @@
|
||||
|
||||
const CRUD_API = "/app/admin/table/crud";
|
||||
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/rule/select?format=tree&type=0,1",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#pid").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
@ -90,13 +90,16 @@
|
||||
name: "pid",
|
||||
initValue: initValue,
|
||||
tips: "无",
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
toolbar: {show: true, list: ["CLEAR"]},
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
tree: {show:true, strict:false, clickCheck:true, clickExpand:false},
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -122,7 +125,6 @@
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
return layui.popup.success("操作成功", function () {
|
||||
parent.refreshTable();
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
});
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
<input type="hidden" name="table" value="<?=htmlspecialchars($table)?>">
|
||||
<?= $form->html(5)?>
|
||||
</div>
|
||||
@ -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>
|
||||
@ -226,12 +226,17 @@
|
||||
const SCHEMA_API = "/app/admin/table/schema";
|
||||
const TABLE_NAME = "<?=htmlspecialchars($table)?>";
|
||||
|
||||
layui.use(["jquery"], function () {
|
||||
layui.use(["popup"], function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: SCHEMA_API + "?table=" + TABLE_NAME,
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
|
||||
// 表信息
|
||||
$('input[name="table"]').val(res.data.table.name);
|
||||
$('input[name="table_comment"]').val(res.data.table.comment);
|
||||
|
@ -11,7 +11,7 @@
|
||||
<form class="layui-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<input type="hidden" name="<?=htmlspecialchars($primary_key)?>" value="<?=htmlspecialchars($value)?>">
|
||||
<input type="hidden" name="table" value="<?=htmlspecialchars($table)?>">
|
||||
@ -42,14 +42,15 @@
|
||||
const SELECT_API = "/app/admin/table/select" + location.search;
|
||||
const UPDATE_API = "/app/admin/table/update";
|
||||
|
||||
layui.use(["form", "util"], function () {
|
||||
layui.use(["form", "util", "popup"], function () {
|
||||
let $ = layui.$;
|
||||
let util = layui.util;
|
||||
$.ajax({
|
||||
url: SELECT_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
layui.each(e.data[0], function (key, value) {
|
||||
success: function (res) {
|
||||
|
||||
layui.each(res.data[0], function (key, value) {
|
||||
let obj = $('*[name="'+key+'"]');
|
||||
if (key === "password") {
|
||||
obj.attr("placeholder", "不更新密码请留空");
|
||||
@ -65,11 +66,25 @@
|
||||
|
||||
<?=$form->js(6)?>
|
||||
|
||||
// ajax返回失败
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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({
|
||||
|
@ -80,8 +80,11 @@
|
||||
$.ajax({
|
||||
url: SCHEMA_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
let forms = e.data.forms;
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
let forms = res.data.forms;
|
||||
let cols = [{
|
||||
type: "checkbox"
|
||||
}];
|
||||
@ -173,7 +176,10 @@
|
||||
title: "刷新",
|
||||
layEvent: "refresh",
|
||||
icon: "layui-icon-refresh",
|
||||
}, "filter", "print", "exports"]
|
||||
}, "filter", "print", "exports"],
|
||||
done: function () {
|
||||
layer.photos({photos: 'div[lay-id="data-table"]', anim: 5});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -185,6 +191,9 @@
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
@ -228,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
|
||||
|
@ -121,14 +121,14 @@
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/dict/get/upload",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#category").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#category",
|
||||
name: "category",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
@ -265,6 +265,9 @@
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
@ -312,6 +315,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -110,22 +110,25 @@
|
||||
})
|
||||
|
||||
// 字段 类别 category
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/dict/get/upload",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#category").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#category",
|
||||
name: "category",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -254,6 +257,9 @@
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
@ -299,6 +305,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -11,7 +11,7 @@
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类别</label>
|
||||
@ -66,18 +66,21 @@
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/dict/get/upload",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#category").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#category",
|
||||
name: "category",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -11,7 +11,7 @@
|
||||
<form class="layui-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="width:inherit">类别</label>
|
||||
@ -47,15 +47,15 @@
|
||||
const UPDATE_API = "/app/admin/upload/update";
|
||||
|
||||
// 获取数据库记录
|
||||
layui.use(["form", "util"], function () {
|
||||
layui.use(["form", "util", "popup"], function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: SELECT_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
|
||||
// 给表单初始化数据
|
||||
layui.each(e.data[0], function (key, value) {
|
||||
layui.each(res.data[0], function (key, value) {
|
||||
let obj = $('*[name="'+key+'"]');
|
||||
if (typeof obj[0] === "undefined" || !obj[0].nodeName) return;
|
||||
obj.attr("value", value);
|
||||
@ -78,26 +78,33 @@
|
||||
});
|
||||
|
||||
// 字段 类别 category
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/dict/get/upload",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#category").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#category",
|
||||
name: "category",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ajax产生错误
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -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>
|
||||
@ -179,22 +179,25 @@
|
||||
const UPDATE_URL = "/app/admin/user/update";
|
||||
|
||||
// 字段 性别 sex
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/dict/get/sex",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#sex").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#sex",
|
||||
name: "sex",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -284,7 +287,7 @@
|
||||
field: "birthday",
|
||||
hide: true,
|
||||
},{
|
||||
title: "余额(分)",
|
||||
title: "余额(元)",
|
||||
field: "money",
|
||||
hide: true,
|
||||
},{
|
||||
@ -336,7 +339,10 @@
|
||||
$.post(UPDATE_API, postData, function (res) {
|
||||
layer.close(load);
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
return layui.popup.failure(res.msg, function () {
|
||||
data.elem.checked = !data.elem.checked;
|
||||
form.render();
|
||||
});
|
||||
}
|
||||
return layui.popup.success("操作成功");
|
||||
})
|
||||
@ -388,6 +394,9 @@
|
||||
url: url,
|
||||
dateType: "json",
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
return layui.popup.failure(res.msg);
|
||||
}
|
||||
function travel(items) {
|
||||
for (let k in items) {
|
||||
let item = items[k];
|
||||
@ -433,6 +442,9 @@
|
||||
// 表格顶部搜索事件
|
||||
form.on("submit(table-query)", function(data) {
|
||||
table.reload("data-table", {
|
||||
page: {
|
||||
curr: 1
|
||||
},
|
||||
where: data.field
|
||||
})
|
||||
return false;
|
||||
|
@ -11,7 +11,7 @@
|
||||
<form class="layui-form" action="">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">用户名</label>
|
||||
@ -44,7 +44,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-block">
|
||||
<img style="max-width:90px;max-height:90px;" src=""/>
|
||||
<img class="img-3" src=""/>
|
||||
<input type="text" style="display:none" name="avatar" value="" />
|
||||
<button type="button" class="pear-btn pear-btn-primary pear-btn-sm" id="avatar" permission="app.admin.upload.avatar">
|
||||
<i class="layui-icon layui-icon-upload"></i>上传图片
|
||||
@ -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>
|
||||
@ -163,19 +163,22 @@
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/dict/get/sex",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#sex").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#sex",
|
||||
name: "sex",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
value: "1",
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -11,7 +11,7 @@
|
||||
<form class="layui-form">
|
||||
|
||||
<div class="mainBox">
|
||||
<div class="main-container">
|
||||
<div class="main-container mr-5">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">用户名</label>
|
||||
@ -44,7 +44,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-block">
|
||||
<img style="max-width:90px;max-height:90px;" src=""/>
|
||||
<img class="img-3" src=""/>
|
||||
<input type="text" style="display:none" name="avatar" value="" />
|
||||
<button type="button" class="pear-btn pear-btn-primary pear-btn-sm" id="avatar" permission="app.admin.upload.avatar">
|
||||
<i class="layui-icon layui-icon-upload"></i>上传图片
|
||||
@ -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>
|
||||
@ -160,15 +160,15 @@
|
||||
const UPDATE_API = "/app/admin/user/update";
|
||||
|
||||
// 获取数据库记录
|
||||
layui.use(["form", "util"], function () {
|
||||
layui.use(["form", "util", "popup"], function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: SELECT_API,
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
|
||||
// 给表单初始化数据
|
||||
layui.each(e.data[0], function (key, value) {
|
||||
layui.each(res.data[0], function (key, value) {
|
||||
let obj = $('*[name="'+key+'"]');
|
||||
if (key === "password") {
|
||||
obj.attr("placeholder", "不更新密码请留空");
|
||||
@ -183,22 +183,25 @@
|
||||
});
|
||||
|
||||
// 字段 性别 sex
|
||||
layui.use(["jquery", "xmSelect"], function() {
|
||||
layui.use(["jquery", "xmSelect", "popup"], function() {
|
||||
layui.$.ajax({
|
||||
url: "/app/admin/dict/get/sex",
|
||||
dataType: "json",
|
||||
success: function (e) {
|
||||
success: function (res) {
|
||||
let value = layui.$("#sex").attr("value");
|
||||
let initValue = value ? value.split(",") : [];
|
||||
layui.xmSelect.render({
|
||||
el: "#sex",
|
||||
name: "sex",
|
||||
initValue: initValue,
|
||||
data: e.data,
|
||||
data: res.data,
|
||||
model: {"icon":"hidden","label":{"type":"text"}},
|
||||
clickClose: true,
|
||||
radio: true,
|
||||
})
|
||||
});
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -264,6 +267,10 @@
|
||||
});
|
||||
})
|
||||
|
||||
// ajax产生错误
|
||||
if (res.code) {
|
||||
layui.popup.failure(res.msg);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -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'
|
||||
];
|
||||
|
@ -15,10 +15,12 @@
|
||||
use plugin\admin\app\controller\AccountController;
|
||||
use plugin\admin\app\controller\DictController;
|
||||
use Webman\Route;
|
||||
use support\Request;
|
||||
|
||||
Route::any('/app/admin/account/captcha/{type}', [AccountController::class, 'captcha']);
|
||||
Route::any('/app/admin', function () {
|
||||
return redirect('/app/admin/');
|
||||
});
|
||||
|
||||
Route::any('/app/admin/dict/get/{name}', [DictController::class, 'get']);
|
||||
|
||||
Route::fallback(function (Request $request) {
|
||||
return response($request->uri() . ' not found' , 404);
|
||||
}, 'admin');
|
||||
|
@ -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'
|
||||
];
|
117
src/plugin/admin/install.sql
Normal file
117
src/plugin/admin/install.sql
Normal file
File diff suppressed because one or more lines are too long
@ -1,4 +1,3 @@
|
||||
|
||||
button {
|
||||
line-height: 100% !important;
|
||||
}
|
||||
@ -96,6 +95,61 @@ a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width:768px) {
|
||||
/** **/
|
||||
.layui-table-tool-self .layui-inline:nth-child(3){
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/** 右间隔 **/
|
||||
.mr-1
|
||||
{
|
||||
margin-right: 4px;
|
||||
}
|
||||
.mr-2
|
||||
{
|
||||
margin-right: 8px;
|
||||
}
|
||||
.mr-3
|
||||
{
|
||||
margin-right: 16px;
|
||||
}
|
||||
.mr-4
|
||||
{
|
||||
margin-right: 24px;
|
||||
}
|
||||
.mr-5
|
||||
{
|
||||
margin-right: 48px;
|
||||
}
|
||||
|
||||
/** 图片尺寸 **/
|
||||
.img-1
|
||||
{
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.img-2
|
||||
{
|
||||
max-width: 32px;
|
||||
max-height: 32px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.img-3
|
||||
{
|
||||
max-width: 64px;
|
||||
max-height: 64px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.img-4
|
||||
{
|
||||
max-width: 128px;
|
||||
max-height: 128px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/** 左侧菜单 Start **/
|
||||
|
||||
.pear-nav-tree .layui-nav-item a span {
|
||||
|
@ -6,7 +6,7 @@ function toggleSearchFormShow()
|
||||
let $ = layui.$;
|
||||
let items = $('.top-search-from .layui-form-item');
|
||||
if (items.length <= 2) {
|
||||
if (items.length <= 1) $('.top-search-from').remove();
|
||||
if (items.length <= 1) $('.top-search-from').parent().parent().remove();
|
||||
return;
|
||||
}
|
||||
let btns = $('.top-search-from .toggle-btn a');
|
||||
|
@ -4,16 +4,24 @@
|
||||
layui.$(function () {
|
||||
let $ = layui.$;
|
||||
$.ajax({
|
||||
url: "/app/admin/rule/permission-codes",
|
||||
url: "/app/admin/rule/permission",
|
||||
dataType: "json",
|
||||
success: function (res) {
|
||||
let style = '';
|
||||
let codes = res.data || [];
|
||||
let isSupperAdmin = false;
|
||||
// codes里有*,说明是超级管理员,拥有所有权限
|
||||
if (codes.indexOf('*') !== -1) {
|
||||
$("head").append("<style>*[permission]{display: initial}</style>");
|
||||
return;
|
||||
isSupperAdmin = true;
|
||||
}
|
||||
if (self !== top) {
|
||||
top.Admin.Account.isSupperAdmin = isSupperAdmin;
|
||||
} else {
|
||||
window.Admin.Account.isSupperAdmin = isSupperAdmin;
|
||||
}
|
||||
if (isSupperAdmin) return;
|
||||
|
||||
// 细分权限
|
||||
layui.each(codes, function (k, code) {
|
||||
codes[k] = '*[permission^="'+code+'"]';
|
||||
|
@ -346,7 +346,7 @@ layui.define(['layer', 'form'], function(exports) {
|
||||
var html = ' <div class="layui-form-item">\n' +
|
||||
' <label class="layui-form-label">上传图片</label>\n' +
|
||||
' <div class="layui-input-' + size + '">\n' +
|
||||
' <img style="max-width:90px;max-height:90px;" src=""/>\n' +
|
||||
' <img class="img-3" src=""/>\n' +
|
||||
' <input type="text" style="display:none" name="'+key+'" value="" />\n' +
|
||||
' <button type="button" class="pear-btn pear-btn-primary pear-btn-sm" id="'+key+'" permission="app.admin.upload.image">\n' +
|
||||
' <i class="layui-icon layui-icon-upload"></i>'+uploadWords+'\n' +
|
||||
|
@ -61,7 +61,9 @@ layui.define(["jquery","layer"], function (exports) {
|
||||
style += 'xm-select > .xm-body .xm-option.selected.hide-icon{background-color:'+color+'!important;}';//变更
|
||||
style += 'xm-select > .xm-body .xm-toolbar .toolbar-tag:hover{color:'+color+'!important;}';//变更
|
||||
style += '.layui-layer-dialog .layui-layer-content .layui-icon-ok{color:'+color+'!important;}';//变更
|
||||
style += '.layui-layer-loading-icon{color:'+color+'!important;}';//变更
|
||||
style += '.layui-layer-dialog .layui-layer-content .layui-icon-ok{color:'+color+'!important;}';//变更
|
||||
style += 'a{color:'+color+';opacity:.8}';//变更
|
||||
style += 'a:hover{color:'+color+';opacity:1}';//变更
|
||||
style += '.pear-this,.pear-text{color:' + color + '!important}';
|
||||
style += '.pear-back{background-color:'+ color +'!important}';
|
||||
style += '.pear-collapsed-pe{background-color:'+color+'!important}'
|
||||
|
@ -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"]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -49,7 +49,7 @@ layui.define(['layer', 'table'], function (exports) {
|
||||
}
|
||||
}
|
||||
|
||||
var sort = function (s_pid, data) {
|
||||
/*var sort = function (s_pid, data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (data[i].pid == s_pid) {
|
||||
var len = mData.length;
|
||||
@ -61,7 +61,41 @@ layui.define(['layer', 'table'], function (exports) {
|
||||
}
|
||||
}
|
||||
};
|
||||
sort(param.treeSpid, tNodes);
|
||||
sort(param.treeSpid, tNodes);*/
|
||||
|
||||
var map = {}; // 变更
|
||||
for (var k in data) {
|
||||
map[data[k].id] = data[k];
|
||||
}
|
||||
for (var j in map) {
|
||||
if(map[j].pid && map[map[j].pid]) {
|
||||
var parent = map[map[j].pid];
|
||||
if (!parent.children) {
|
||||
parent.children = [];
|
||||
parent.isParent = true;
|
||||
}
|
||||
parent.children.push(map[j]);
|
||||
}
|
||||
}
|
||||
var tree = [];
|
||||
for (var l in map) {
|
||||
if (!map[l].pid || !map[map[l].pid]) {
|
||||
map[l].isRoot = true;
|
||||
tree.push(map[l]);
|
||||
}
|
||||
}
|
||||
function travel(item)
|
||||
{
|
||||
mData.push(item);
|
||||
if (item.children) {
|
||||
for (var g in item.children) {
|
||||
travel(item.children[g]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var h in tree) {
|
||||
travel(tree[h]);
|
||||
}
|
||||
|
||||
param.prevUrl = param.url;
|
||||
param.url = undefined;
|
||||
@ -194,10 +228,10 @@ layui.define(['layer', 'table'], function (exports) {
|
||||
},
|
||||
// 检查参数
|
||||
checkParam: function (param) {
|
||||
if (!param.treeSpid && param.treeSpid != 0) {
|
||||
/*if (!param.treeSpid && param.treeSpid != 0) {
|
||||
layer.msg('参数treeSpid不能为空', {icon: 5});
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
if (!param.treeIdName) {
|
||||
layer.msg('参数treeIdName不能为空', {icon: 5});
|
||||
|
@ -92,7 +92,6 @@
|
||||
|
||||
treetable.render({
|
||||
treeColIndex: 1,
|
||||
treeSpid: 0,
|
||||
treeIdName: 'powerId',
|
||||
treePidName: 'parentId',
|
||||
skin:'line',
|
||||
|
@ -104,7 +104,6 @@
|
||||
window.render = function(){
|
||||
treetable.render({
|
||||
treeColIndex: 1,
|
||||
treeSpid: 0,
|
||||
treeIdName: 'powerId',
|
||||
treePidName: 'parentId',
|
||||
skin:'line',
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user