+ */
+ protected $exceptRoutes = [
+ //
+ ];
+
+ /**
+ * Handle an incoming request.
+ *
+ * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
+ */
+ public function handle(Request $request, Closure $next): Response
+ {
+ if ($this->inExceptArray($request) || $this->checkRoutePermission($request)) {
+ return $next($request);
+ }
+
+ return Admin::response()->fail(__('admin.unauthorized'), ['route' => $request->route()->getName()]);
+ }
+
+ protected function checkRoutePermission(Request $request): bool
+ {
+ if (is_null($user = Admin::user())) {
+ return false;
+ }
+
+ $ability = $this->normalizeRouteAbility(
+ $original = $request->route()->getName()
+ );
+
+ return collect($ability)
+ ->when($ability !== $original, fn (Collection $collection) => $collection->push($original))
+ ->contains(fn ($ability) => $user->can($ability));
+ }
+
+ protected function normalizeRouteAbility(string $ability)
+ {
+ foreach ($this->resourceAbilityMap() as $method => $map) {
+ if (str_ends_with($ability, ".{$method}")) {
+ return preg_replace("/(.*)\.{$method}$/", '${1}.'.$map, $ability);
+ }
+ }
+
+ return $ability;
+ }
+
+ protected function resourceAbilityMap(): array
+ {
+ return [
+ 'index' => 'list',
+ 'show' => 'view',
+ 'store' => 'create',
+ 'edit' => 'update',
+ 'destroy' => 'delete',
+ ];
+ }
+
+ protected function inExceptArray(Request $request): bool
+ {
+ if (in_array($request->route()->getName(), $this->exceptRoutes)) {
+ return true;
+ }
+
+ $permission = Admin::permission();
+
+ return $request->is(
+ collect($this->exceptPaths)
+ ->when(Admin::permission(), fn (Collection $collection, Permission $permission) => $collection->merge($permission->authExcept)->merge($permission->permissionExcept))
+ ->map(function ($path) {
+ $path = trim((string) config('admin.route.prefix'), '/').'/'.trim((string) $path, '/');
+
+ return ltrim($path, '/');
+ })
+ );
+ }
+}
diff --git a/app/Services/Admin/AdService.php b/app/Admin/Services/AdService.php
similarity index 98%
rename from app/Services/Admin/AdService.php
rename to app/Admin/Services/AdService.php
index 84fa949..4829c46 100644
--- a/app/Services/Admin/AdService.php
+++ b/app/Admin/Services/AdService.php
@@ -1,9 +1,9 @@
currentModel;
+ }
+
+ public function sortColumn()
+ {
+ return 'id';
+ }
+
+ public function getTree()
+ {
+ $list = $this->query()->orderByDesc('sort')->get();
+ $minNum = $list->min('parent_id');
+
+ return array2tree($list->toArray(), $minNum);
+ }
+
+ public function list()
+ {
+ $query = $this->listQuery();
+ if (request()->input('_all')) {
+ $list = (clone $query)->get();
+ $items = $list->all();
+ $total = $list->count();
+ } else {
+ $list = (clone $query)->paginate(request()->input('perPage', 20));
+ $items = $list->items();
+ $total = $list->total();
+ }
+
+ return compact('items', 'total');
+ }
+
+ public function getModelFilter()
+ {
+ return $this->modelFilterName;
+ }
+
+ public function listQuery()
+ {
+ $query = $this->query();
+
+ $this->addRelations($query);
+
+ if ($filter = $this->getModelFilter()) {
+ $query->filter(request()->input(), $filter);
+ }
+
+ if ($this->modelSortAble) {
+ $query->sort();
+ }
+
+ $this->sortable($query);
+
+ return $query;
+ }
+
+ public function store($data): bool
+ {
+ $data = $this->resloveData($data);
+
+ $validate = $this->validate($data);
+ if ($validate !== true) {
+ $this->setError($validate);
+
+ return false;
+ }
+
+ $model = $this->modelName::create($data);
+ $this->currentModel = $model;
+
+ return true;
+ }
+
+ public function update($primaryKey, $data): bool
+ {
+ $model = $this->query()->whereKey($primaryKey)->firstOrFail();
+ $data = $this->resloveData($data, $model);
+ $validate = $this->validate($data, $model);
+ if ($validate !== true) {
+ $this->setError($validate);
+
+ return false;
+ }
+ $model->update($data);
+ $this->currentModel = $model;
+ return true;
+ }
+
+ public function delete(string $ids): mixed
+ {
+ $this->preDelete(explode(',', $ids));
+
+ return parent::delete($ids);
+ }
+
+ /**
+ * 处理表单数据
+ *
+ * @param array $data
+ * @param Model $model 空 : 添加, 非空: 修改
+ * @return array
+ */
+ public function resloveData($data, $model = null)
+ {
+ return $data;
+ }
+
+ /**
+ * 表单验证
+ *
+ * @param array $data
+ * @param Model $model 空: 添加, 非空: 修改
+ * @return mixed true: 验证通过, string: 错误提示
+ */
+ public function validate($data, $model = null)
+ {
+ // $createRules = [
+ // 'key' => ['required', Rule::unique('keywords', 'key')],
+ // 'name' => ['required'],
+ // ];
+ // $updateRules = [
+ // 'key' => [Rule::unique('keywords', 'key')->ignore($model->id)]
+ // ];
+ // $validator = Validator::make($data, $model ? $updateRules : $createRules, [
+ // 'key.unique' => ':input 已经存在'
+ // ]);
+ // if ($validator->fails()) {
+ // return $validator->errors()->first();
+ // }
+ return true;
+ }
+
+ /**
+ * 删除的前置方法
+ *
+ * @param array $ids 主键id
+ */
+ public function preDelete(array $ids): void
+ {
+ }
+}
diff --git a/app/Admin/Services/System/AdminMenuService.php b/app/Admin/Services/System/AdminMenuService.php
new file mode 100644
index 0000000..e85486d
--- /dev/null
+++ b/app/Admin/Services/System/AdminMenuService.php
@@ -0,0 +1,95 @@
+modelName = Admin::adminMenuModel();
+ }
+
+ public function getTree(): array
+ {
+ $list = $this->query()->orderBy('order')->get()->toArray();
+
+ return array2tree($list);
+ }
+
+ public function parentIsChild($id, $parent_id): bool
+ {
+ $parent = $this->query()->find($parent_id);
+
+ do {
+ if ($parent->parent_id == $id) {
+ return true;
+ }
+ // 如果没有parent 则为顶级菜单 退出循环
+ $parent = $parent->parent;
+ } while ($parent);
+
+ return false;
+ }
+
+ public function update($primaryKey, $data): bool
+ {
+ $columns = $this->getTableColumns();
+
+ $parent_id = Arr::get($data, 'parent_id');
+ if ($parent_id != 0) {
+ amis_abort_if($this->parentIsChild($primaryKey, $parent_id), __('admin.admin_menu.parent_id_not_allow'));
+ }
+
+ $model = $this->query()->whereKey($primaryKey)->first();
+
+ return $this->saveData($data, $columns, $model);
+ }
+
+ public function store($data): bool
+ {
+ $columns = $this->getTableColumns();
+
+ $model = $this->getModel();
+
+ return $this->saveData($data, $columns, $model);
+ }
+
+ public function changeHomePage($excludeId = 0)
+ {
+ $this->query()->when($excludeId, fn ($query) => $query->where('id', '<>', $excludeId))->update(['is_home' => 0]);
+ }
+
+ public function list()
+ {
+ return ['items' => $this->getTree()];
+ }
+
+ protected function saveData($data, array $columns, AdminMenu $model): bool
+ {
+ foreach ($data as $k => $v) {
+ if (! in_array($k, $columns)) {
+ continue;
+ }
+
+ $v = $k == 'parent_id' ? intval($v) : $v;
+
+ $model->setAttribute($k, $v);
+
+ if ($k == 'is_home' && $v == 1) {
+ $this->changeHomePage($model->getKey());
+ }
+ }
+
+ return $model->save();
+ }
+}
diff --git a/app/Admin/Services/System/AdminPermissionService.php b/app/Admin/Services/System/AdminPermissionService.php
new file mode 100644
index 0000000..1d16223
--- /dev/null
+++ b/app/Admin/Services/System/AdminPermissionService.php
@@ -0,0 +1,117 @@
+modelName = Admin::adminPermissionModel();
+ }
+
+ public function getTree(): array
+ {
+ $list = $this->query()->orderBy('order')->get()->toArray();
+
+ return array2tree($list);
+ }
+
+ public function parentIsChild($id, $parent_id): bool
+ {
+ $parent = $this->query()->find($parent_id);
+
+ do {
+ if ($parent->parent_id == $id) {
+ return true;
+ }
+ // 如果没有parent 则为顶级 退出循环
+ $parent = $parent->parent;
+ } while ($parent);
+
+ return false;
+ }
+
+ public function getEditData($id): Model|\Illuminate\Database\Eloquent\Collection|Builder|array|null
+ {
+ $permission = parent::getEditData($id);
+
+ $permission->load(['menus']);
+
+ return $permission;
+ }
+
+ public function store($data): bool
+ {
+ $this->checkRepeated($data);
+
+ $columns = $this->getTableColumns();
+
+ $model = $this->getModel();
+
+ return $this->saveData($data, $columns, $model);
+ }
+
+ public function update($primaryKey, $data): bool
+ {
+ $this->checkRepeated($data, $primaryKey);
+
+ $columns = $this->getTableColumns();
+
+ $parent_id = Arr::get($data, 'parent_id');
+ if ($parent_id != 0) {
+ amis_abort_if($this->parentIsChild($primaryKey, $parent_id), __('admin.admin_permission.parent_id_not_allow'));
+ }
+
+ $model = $this->query()->whereKey($primaryKey)->first();
+
+ return $this->saveData($data, $columns, $model);
+ }
+
+ public function checkRepeated($data, $id = 0)
+ {
+ $query = $this->query()->when($id, fn ($query) => $query->where('id', '<>', $id));
+
+ amis_abort_if($query->clone()->where('name', $data['name'])
+ ->exists(), __('admin.admin_permission.name_already_exists'));
+
+ amis_abort_if($query->clone()->where('slug', $data['slug'])
+ ->exists(), __('admin.admin_permission.slug_already_exists'));
+ }
+
+ public function list()
+ {
+ return ['items' => $this->getTree()];
+ }
+
+ protected function saveData($data, array $columns, AdminPermission $model): bool
+ {
+ $menus = Arr::pull($data, 'menus');
+
+ foreach ($data as $k => $v) {
+ if (! in_array($k, $columns)) {
+ continue;
+ }
+
+ $model->setAttribute($k, $v);
+ }
+
+ if ($model->save()) {
+ $model->menus()->sync(Arr::has($menus, '0.id') ? Arr::pluck($menus, 'id') : $menus);
+
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/app/Admin/Services/System/AdminRoleService.php b/app/Admin/Services/System/AdminRoleService.php
new file mode 100644
index 0000000..5c0e7e4
--- /dev/null
+++ b/app/Admin/Services/System/AdminRoleService.php
@@ -0,0 +1,100 @@
+modelName = Admin::adminRoleModel();
+ }
+
+ public function list()
+ {
+ $query = $this->listQuery();
+
+ /** @var \Illuminate\Pagination\LengthAwarePaginator */
+ $list = $query->with(['menus', 'permissions'])->paginate(request()->input('perPage', 20));
+ $list->through(function ($item) {
+ $instance = $item->withoutRelations();
+ $instance->setAttribute('menu_ids', $item->menus->pluck('id'));
+ $instance->setAttribute('permission_ids', $item->permissions->pluck('id'));
+
+ return $instance;
+ });
+ $items = $list->items();
+ $total = $list->total();
+
+ return compact('items', 'total');
+ }
+
+ public function store($data): bool
+ {
+ $this->checkRepeated($data);
+
+ $columns = $this->getTableColumns();
+
+ $model = $this->getModel();
+
+ foreach ($data as $k => $v) {
+ if (! in_array($k, $columns)) {
+ continue;
+ }
+
+ $model->setAttribute($k, $v);
+ }
+
+ return $model->save();
+ }
+
+ public function update($primaryKey, $data): bool
+ {
+ $this->checkRepeated($data, $primaryKey);
+
+ $columns = $this->getTableColumns();
+
+ $model = $this->query()->whereKey($primaryKey)->first();
+
+ foreach ($data as $k => $v) {
+ if (! in_array($k, $columns)) {
+ continue;
+ }
+
+ $model->setAttribute($k, $v);
+ }
+
+ return $model->save();
+ }
+
+ public function checkRepeated($data, $id = 0)
+ {
+ $query = $this->query()->when($id, fn ($query) => $query->where('id', '<>', $id));
+
+ amis_abort_if($query->clone()
+ ->where('name', $data['name'])
+ ->exists(), __('admin.admin_role.name_already_exists'));
+
+ amis_abort_if($query->clone()
+ ->where('slug', $data['slug'])
+ ->exists(), __('admin.admin_role.slug_already_exists'));
+ }
+
+ public function savePermissions($primaryKey, $permissions): void
+ {
+ $model = $this->query()->whereKey($primaryKey)->first();
+
+ $model->permissions()->detach();
+ $model->permissions()->attach($permissions);
+ }
+
+ public function saveMenus($primaryKey, $menus): void
+ {
+ $model = $this->query()->whereKey($primaryKey)->first();
+
+ $model->menus()->detach();
+ $model->menus()->attach($menus);
+ }
+}
diff --git a/app/Admin/Services/System/AdminUserService.php b/app/Admin/Services/System/AdminUserService.php
new file mode 100644
index 0000000..115bf13
--- /dev/null
+++ b/app/Admin/Services/System/AdminUserService.php
@@ -0,0 +1,161 @@
+modelName = Admin::adminUserModel();
+ }
+
+ public function getEditData($id): Model|\Illuminate\Database\Eloquent\Collection|Builder|array|null
+ {
+ $adminUser = parent::getEditData($id)->makeHidden('password');
+
+ $adminUser->load('roles');
+
+ return $adminUser;
+ }
+
+ public function store($data): bool
+ {
+ if ($this->checkUsernameUnique($data['username'])) {
+ admin_abort(__('admin.admin_user.username_already_exists'));
+ }
+
+ if (! data_get($data, 'password')) {
+ admin_abort(__('admin.required', ['attribute' => __('admin.password')]));
+ }
+
+ if (array_key_exists('confirm_password', $data)) {
+ if ($data['password'] !== $data['confirm_password']) {
+ admin_abort(__('admin.admin_user.password_confirmation'));
+ }
+ unset($data['confirm_password']);
+ }
+
+ if (Hash::needsRehash($data['password'])) {
+ $data['password'] = Hash::make($data['password']);
+ }
+
+ $model = $this->getModel();
+ $user = $model::create(Arr::except($data, ['roles']));
+
+ if (isset($data['roles'])) {
+ $user->roles()->attach($data['roles']);
+ }
+
+ return true;
+ }
+
+ public function update($primaryKey, $data): bool
+ {
+ if (isset($data['username']) && $this->checkUsernameUnique($data['username'], $primaryKey)) {
+ admin_abort(__('admin.admin_user.username_already_exists'));
+ }
+
+ if (isset($data['password']) && Hash::needsRehash($data['password'])) {
+ $data['password'] = Hash::make($data['password']);
+ }
+
+ $user = $this->query()->whereKey($primaryKey)->firstOrFail();
+
+ foreach (['username', 'password', 'name', 'avatar', 'lock'] as $attribute) {
+ if (array_key_exists($attribute, $data)) {
+ $user->{$attribute} = $data[$attribute];
+ }
+ }
+
+ if ($user->isDirty('lock') && $user->lock != 1) {
+ $user->error_num = 0;
+ $user->last_error_at = null;
+ }
+
+ $user->save();
+
+ if (isset($data['roles'])) {
+ $roles = Arr::pull($data, 'roles');
+ $user->roles()->detach();
+ $user->roles()->attach(Arr::has($roles, '0.id') ? Arr::pluck($roles, 'id') : $roles);
+ }
+
+ return true;
+ }
+
+ public function checkUsernameUnique($username, $id = 0): bool
+ {
+ return $this->query()
+ ->where('username', $username)
+ ->when($id, fn ($query) => $query->where('id', '<>', $id))
+ ->exists();
+ }
+
+ public function updateUserSetting($primaryKey, $data): bool
+ {
+ $this->passwordHandler($data, $primaryKey);
+
+ return parent::update($primaryKey, $data);
+ }
+
+ public function passwordHandler(&$data, $id = null)
+ {
+ $password = Arr::get($data, 'password');
+
+ if ($password) {
+ if ($password !== Arr::get($data, 'confirm_password')) {
+ admin_abort(__('admin.admin_user.password_confirmation'));
+ }
+
+ if (strlen($password) < 6) {
+ admin_abort('密码长度至少6个字符');
+ }
+
+ if ($id) {
+ if (! Arr::get($data, 'old_password')) {
+ admin_abort(__('admin.admin_user.old_password_required'));
+ }
+
+ $oldPassword = $this->query()->where('id', $id)->value('password');
+
+ if (! Hash::check($data['old_password'], $oldPassword)) {
+ admin_abort(__('admin.admin_user.old_password_error'));
+ }
+ }
+
+ $data['password'] = bcrypt($password);
+
+ unset($data['confirm_password']);
+ unset($data['old_password']);
+ }
+ }
+
+ public function list()
+ {
+ $keyword = request()->keyword;
+
+ $query = $this
+ ->query()
+ ->with('roles')
+ ->select(['id', 'name', 'username', 'avatar', 'created_at', 'lock'])
+ ->when($keyword, function ($query) use ($keyword) {
+ $query->where('username', 'like', "%{$keyword}%")->orWhere('name', 'like', "%{$keyword}%");
+ });
+
+ $this->sortable($query);
+
+ $items = (clone $query)->paginate(request()->input('perPage', 20))->items();
+ $total = (clone $query)->count();
+
+ return compact('items', 'total');
+ }
+}
diff --git a/app/Services/Admin/KeywordService.php b/app/Admin/Services/System/KeywordService.php
similarity index 82%
rename from app/Services/Admin/KeywordService.php
rename to app/Admin/Services/System/KeywordService.php
index 7e28bc1..e9c9a83 100644
--- a/app/Services/Admin/KeywordService.php
+++ b/app/Admin/Services/System/KeywordService.php
@@ -1,10 +1,11 @@
query()->filter(request()->all(), $this->modelFilterName)->orderByDesc('sort')->get();
+ $list = $this->query()->sort()->filter(request()->all(), $this->modelFilterName)->get();
$minNum = $list->min('parent_id');
- return !$list->isEmpty() ? array2tree($list->toArray(), $minNum) :[];
+
+ return ! $list->isEmpty() ? array2tree($list->toArray(), $minNum) : [];
}
public function parentIsChild($id, $pid): bool
@@ -53,7 +56,7 @@ class KeywordService extends BaseService
$model = $this->getModel();
foreach ($data as $k => $v) {
- if (!in_array($k, $columns)) {
+ if (! in_array($k, $columns)) {
continue;
}
@@ -75,6 +78,7 @@ class KeywordService extends BaseService
if ($pid != 0) {
if ($this->parentIsChild($primaryKey, $pid)) {
$this->setError('父级不允许设置为当前子权限');
+
return false;
}
}
@@ -82,7 +86,7 @@ class KeywordService extends BaseService
$model = $this->query()->whereKey($primaryKey)->first();
foreach ($data as $k => $v) {
- if (!in_array($k, $columns)) {
+ if (! in_array($k, $columns)) {
continue;
}
@@ -94,10 +98,11 @@ class KeywordService extends BaseService
public function hasRepeated($data, $id = 0): bool
{
- $query = $this->query()->when($id, fn($query) => $query->where('id', '<>', $id));
+ $query = $this->query()->when($id, fn ($query) => $query->where('id', '<>', $id));
if ((clone $query)->where('key', $data['key'])->exists()) {
$this->setError('KEY重复');
+
return true;
}
@@ -107,7 +112,7 @@ class KeywordService extends BaseService
public function delete(string $ids): mixed
{
$ids = explode(',', $ids);
- if(count($ids) == 1){
+ if (count($ids) == 1) {
$this->query()->where('path', 'like', '%-'.$ids[0].'-%')->delete();
}
diff --git a/app/Admin/routes.php b/app/Admin/routes.php
index b080bf1..39d69ee 100644
--- a/app/Admin/routes.php
+++ b/app/Admin/routes.php
@@ -19,15 +19,8 @@ Route::group([
$router->post('login', [App\Admin\Controllers\AuthController::class, 'login']);
- $router->resource('system/admin_users', App\Admin\Controllers\AdminUserController::class);
- $router->post('quick-edit/admin_users/{admin_user}',[\App\Admin\Controllers\AdminUserController::class, 'update']);
-
$router->get('system/admin_roles', [App\Admin\Controllers\AdminRoleController::class, 'index']);
- $router->resource('system/settings', \App\Admin\Controllers\SettingController::class);
-
- $router->resource('system/keywords', \App\Admin\Controllers\KeywordController::class);
-
$router->resource('articles', \App\Admin\Controllers\ArticleController::class);
$router->resource('ads', \App\Admin\Controllers\AdController::class);
@@ -40,4 +33,26 @@ Route::group([
$router->post('start_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'startChunk']);
$router->post('save_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'saveChunk']);
$router->post('finish_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'finishChunk']);
+
+
+ $router->group([
+ 'prefix' => 'system',
+ 'as' => 'system.',
+ ], function (Router $router) {
+ // 账号管理
+ $router->resource('admin_users', App\Admin\Controllers\System\AdminUserController::class);
+ $router->post('/admin_users/{admin_user}/change-password', [App\Admin\Controllers\System\AdminUserController::class, 'changePassword'])->name('admin_users.change_password');
+ // 角色管理
+ $router->resource('admin_roles', App\Admin\Controllers\System\AdminRoleController::class);
+ $router->post('admin_roles/{admin_role}/menus', [App\Admin\Controllers\System\AdminRoleController::class, 'saveMenus'])->name('admin_roles.set_menus');
+ $router->post('admin_roles/{admin_role}/permissions', [App\Admin\Controllers\System\AdminRoleController::class, 'savePermissions'])->name('admin_roles.set_permissions');
+ // 权限管理
+ $router->resource('admin_permissions', App\Admin\Controllers\System\AdminPermissionController::class);
+ // 菜单管理
+ $router->resource('admin_menus', App\Admin\Controllers\System\AdminMenuController::class);
+ // 系统设置
+ $router->resource('settings', \App\Admin\Controllers\SettingController::class);
+ // 数据字典
+ $router->resource('keywords', App\Admin\Controllers\System\KeywordController::class);
+ });
});
diff --git a/app/Models/Filters/AdFilter.php b/app/ModelFilters/AdFilter.php
similarity index 98%
rename from app/Models/Filters/AdFilter.php
rename to app/ModelFilters/AdFilter.php
index 5b1e5f6..8a5d398 100644
--- a/app/Models/Filters/AdFilter.php
+++ b/app/ModelFilters/AdFilter.php
@@ -1,6 +1,6 @@
where('name', 'like', '%'.$name.'%')->orWhere('key', 'like', '%'.$name.'%');
+ }
+
+ public function parentKey($key)
+ {
+ return $this->where('parent_key', $key);
+ }
+}
diff --git a/app/Models/AdminRole.php b/app/Models/AdminRole.php
new file mode 100644
index 0000000..0a1ffcb
--- /dev/null
+++ b/app/Models/AdminRole.php
@@ -0,0 +1,25 @@
+menus()->detach();
+ $model->permissions()->detach();
+ });
+ }
+
+ public function menus(): BelongsToMany
+ {
+ return $this->belongsToMany(Admin::adminMenuModel(), 'admin_role_menus', 'role_id', 'menu_id');
+ }
+}
diff --git a/app/Models/AdminUser.php b/app/Models/AdminUser.php
new file mode 100644
index 0000000..c5d8ed0
--- /dev/null
+++ b/app/Models/AdminUser.php
@@ -0,0 +1,121 @@
+belongsToMany(Admin::adminRoleModel(), 'admin_role_users', 'user_id', 'role_id')->withTimestamps();
+ }
+
+ /**
+ * 获取此用户的全部能力
+ */
+ public function allAbilities(): Collection
+ {
+ if ($this->allAbilities) {
+ return $this->allAbilities;
+ }
+
+ $model = Admin::adminPermissionModel();
+ $allPermissions = $model::all(['id', 'parent_id', 'slug'])->keyBy('id');
+
+ /** @var \Illuminate\Database\Eloquent\Collection 此用户的所有角色的权限集合 */
+ $rolePermissions = $this->roles
+ ->pluck('permissions')
+ ->flatten()
+ ->keyBy('id');
+
+ $abilities = $rolePermissions->map(fn ($permission) => $permission->slug);
+
+ foreach ($rolePermissions as $rolePermission) {
+ if (is_null($rolePermission->parent_id) || $abilities->has($rolePermission->parent_id)) {
+ continue;
+ }
+
+ $parent = $allPermissions->get($rolePermission->parent_id);
+
+ while ($parent) {
+ $abilities->put($parent->id, $parent->slug);
+
+ if (is_null($parent->parent_id)) {
+ break;
+ }
+
+ $parent = $allPermissions->get($parent->parent_id);
+ }
+ }
+
+ unset($allPermissions, $rolePermissions);
+
+ return $this->allAbilities = $abilities;
+ }
+
+ public function can($abilities, $arguments = []): bool
+ {
+ if (empty($abilities)) {
+ return true;
+ }
+
+ if ($this->isAdministrator()) {
+ return true;
+ }
+
+ return collect($abilities)->every(
+ fn ($ability) => $this->allAbilities()->contains($ability)
+ );
+ }
+
+ public function allMenus(): Collection
+ {
+ $model = Admin::adminMenuModel();
+ $allMenus = $model::all()->keyBy($this->getKeyName());
+
+ if ($this->isAdministrator()) {
+ return $allMenus;
+ }
+
+ /** @var \Illuminate\Database\Eloquent\Collection */
+ $roleMenus = $this->roles
+ ->pluck('menus')
+ ->flatten()
+ ->keyBy($this->getKeyName());
+
+ $allRoleMenus = $roleMenus->collect();
+
+ foreach ($roleMenus as $roleMenu) {
+ if (is_null($roleMenu->parent_id) || $allRoleMenus->has($roleMenu->parent_id)) {
+ continue;
+ }
+
+ $parent = $allMenus->get($roleMenu->parent_id);
+
+ while ($parent) {
+ $allRoleMenus->put($parent->id, $parent);
+
+ if (is_null($parent->parent_id)) {
+ break;
+ }
+
+ $parent = $allMenus->get($parent->parent_id);
+ }
+ }
+
+ unset($allMenus, $roleMenus);
+
+ return $allRoleMenus;
+ }
+}
diff --git a/app/Models/Filters/KeywordFilter.php b/app/Models/Filters/KeywordFilter.php
deleted file mode 100644
index caf1040..0000000
--- a/app/Models/Filters/KeywordFilter.php
+++ /dev/null
@@ -1,31 +0,0 @@
-where('name','like', '%'.$name.'%')
- ->orWhere('key','like', '%'.$name.'%');
- }
-
- public function parentName($parent_name)
- {
- if(request('has_owner', 1)){
- $this->where(function($q) use ($parent_name){
- $q->where('name','like', '%'.$parent_name.'%')
- ->orWhere('key','like', '%'.$parent_name.'%');
- });
- }
- return $this->orWhere('path','like', '%-'.
- Keyword::where('name','like', '%'.$parent_name.'%')->orWhere('key','like', '%'.$parent_name.'%')->value('id')
- . '-%' ?? '');
- }
-}
diff --git a/app/Models/Keyword.php b/app/Models/Keyword.php
index d065b36..7bb1025 100644
--- a/app/Models/Keyword.php
+++ b/app/Models/Keyword.php
@@ -2,19 +2,21 @@
namespace App\Models;
+use App\Admin\Components;
+use App\ModelFilters\KeywordFilter;
+use EloquentFilter\Filterable;
+use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
-use EloquentFilter\Filterable;
-use App\Admin\Components;
use Illuminate\Support\Str;
class Keyword extends Model
{
- use HasFactory;
use Filterable;
+ use HasFactory;
protected $fillable = ['name', 'key', 'value', 'parent_id', 'parent_key', 'path', 'sort', 'lv'];
-
+
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
@@ -23,26 +25,27 @@ class Keyword extends Model
protected static function boot()
{
parent::boot();
+
// 监听 Keyword 的创建事件,用于初始化 path 和 lv 字段值
- static::saving(function ($keyword) {
- // 如果创建的是一个根类目
- if (! $keyword->parent_id) {
- // 将层级设为 1
- $keyword->lv = 1;
- // 将 path 设为 -
- $keyword->path = '-';
- if(empty($keyword->key)){
- $keyword->key = Str::quickRandom($length = 16);
+ static::saving(function (Keyword $keyword) {
+ if (is_null($parent = $keyword->parent)) {
+ $keyword->forceFill([
+ 'path' => '-',
+ 'lv' => 1,
+ ]);
+
+ if ((string) $keyword->key === '') {
+ $keyword->key = Str::random(16);
}
} else {
- // 将层级设为父类目的层级 + 1
- $keyword->lv = $keyword->parent->lv + 1;
- $keyword->parent_key = $keyword->parent->key;
- // 将 path 值设为父类目的 path 追加父类目 ID 以及最后跟上一个 - 分隔符
- $keyword->path = $keyword->parent->path.$keyword->parent_id.'-';
- //当前key是否为空
- if(empty($keyword->key)){
- $keyword->key = $keyword->parent_key . '_' . (self::where('parent_key', $keyword->parent_key)->count() + 1);
+ $keyword->forceFill([
+ 'parent_key' => $parent->lv > 1 ? $parent->parent_key : $parent->key,
+ 'path' => $parent->full_path,
+ 'lv' => $parent->lv + 1,
+ ]);
+
+ if ((string) $keyword->key === '') {
+ $keyword->key = $parent->key.'_'.($parent->children()->count() + 1);
}
}
});
@@ -58,19 +61,32 @@ class Keyword extends Model
return $this->hasMany(static::class, 'parent_id');
}
- public function scopeAllChildrenOfKey($q, $parentKey)
+ public function scopeSort($q)
{
- $q->where('path','like', '%-'.
- static::where('key', $parentKey)->value('id')
- . '-%' ?? '');
+ return $q->orderBy('sort', 'asc');
}
- public static function tagsMap(String $key)
+ public function scopeAllChildrenOfKey($q, $parentKey)
+ {
+ $q->where('path', 'like', '%-'.
+ static::where('key', $parentKey)->value('id')
+ .'-%' ?? '');
+ }
+
+ public static function tagsMap(string $key)
{
$mapArr = [];
- self::query()->where('parent_key', $key)->get()->map(function($item) use (&$mapArr){
+ self::query()->where('parent_key', $key)->get()->map(function ($item) use (&$mapArr) {
$mapArr[$item->id] = Components::make()->keywordsTag($item->name, $item->value);
});
+
return $mapArr;
}
+
+ protected function fullPath(): Attribute
+ {
+ return Attribute::make(
+ get: fn (mixed $value, array $attributes) => $attributes['path'].$attributes['id'].'-',
+ );
+ }
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index f782b96..4d70882 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -2,7 +2,10 @@
namespace App\Providers;
+use Illuminate\Database\Eloquent\Relations\Relation;
+use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\ServiceProvider;
+use Illuminate\Support\Facades\Validator;
class AppServiceProvider extends ServiceProvider
{
@@ -11,8 +14,7 @@ class AppServiceProvider extends ServiceProvider
*/
public function register(): void
{
- //
-
+ $this->app->singleton('admin.menu', \App\Admin\Menu::class);
}
/**
@@ -20,6 +22,24 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
- \Schema::defaultStringLength(191);
+ JsonResource::withoutWrapping();
+
+ $this->definePolymorphicTypes();
+
+ Validator::extend('phone', function ($attribute, $value, $parameters, $validator) {
+ return preg_match('/^1[\d]{10}$/', $value);
+ });
+ }
+
+ /**
+ * 自定义多态类型
+ */
+ protected function definePolymorphicTypes(): void
+ {
+ Relation::enforceMorphMap(
+ collect([
+ \App\Models\AdminUser::class,
+ ])->mapWithKeys(fn ($model) => [(new $model)->getTable() => $model])->all()
+ );
}
}
diff --git a/app/Services/Admin/BaseService.php b/app/Services/Admin/BaseService.php
deleted file mode 100644
index 4fa0ecd..0000000
--- a/app/Services/Admin/BaseService.php
+++ /dev/null
@@ -1,58 +0,0 @@
-query()->orderByDesc('sort')->get();
- $minNum = $list->min('parent_id');
- return array2tree($list->toArray(), $minNum);
- }
-
- public function getModelFilter()
- {
- return $this->modelFilterName;
- }
-
- public function listQuery()
- {
- $model = $this->getModel();
- $filter = $this->getModelFilter();
-
- $query = $this->query();
- if($this->withRelationships){
- $query->with($this->withRelationships);
- }
-
- if ($filter) {
- $query->filter(request()->input(), $filter);
- }
-
- if($this->modelSortAble){
- $query->sort();
- }
-
- $this->sortable($query);
-
- return $query;
- }
-
- public function getDetail($id)
- {
- return $this->query()->with($this->withRelationships)->find($id);
- }
-}
diff --git a/config/admin.php b/config/admin.php
index 12b20d7..e26b0b1 100644
--- a/config/admin.php
+++ b/config/admin.php
@@ -2,26 +2,32 @@
return [
// 应用名称
- 'name' => 'Owl Admin',
+ 'name' => 'Owl Admin',
// 应用 logo
- 'logo' => '/admin-assets/logo.png',
+ 'logo' => '/admin-assets/logo.png',
// 默认头像
'default_avatar' => '/admin-assets/default-avatar.png',
// 应用安装目录
- 'directory' => app_path('Admin'),
+ 'directory' => app_path('Admin'),
// 引导文件
- 'bootstrap' => app_path('Admin/bootstrap.php'),
+ 'bootstrap' => app_path('Admin/bootstrap.php'),
// 应用路由
- 'route' => [
- 'prefix' => 'admin-api',
- 'domain' => null,
- 'namespace' => 'App\\Admin\\Controllers',
- 'middleware' => ['admin'],
+ 'route' => [
+ 'prefix' => 'admin-api',
+ 'domain' => null,
+ 'namespace' => 'App\\Admin\\Controllers',
+ 'middleware' => [
+ \App\Admin\Middleware\Authenticate::class,
+ 'admin.bootstrap',
+ \App\Admin\Middleware\CheckPermission::class,
+ 'sanctum',
+ 'substitute',
+ ],
// 不包含额外路由, 配置后, 不会追加新增/详情/编辑页面路由
'without_extra_routes' => [
'/dashboard',
@@ -30,70 +36,69 @@ return [
'auth' => [
// 是否开启验证码
- 'login_captcha' => env('ADMIN_LOGIN_CAPTCHA', true),
+ 'login_captcha' => env('ADMIN_LOGIN_CAPTCHA', true),
// 是否开启认证
- 'enable' => true,
+ 'enable' => true,
// 是否开启鉴权
- 'permission' => true,
+ 'permission' => true,
// token 有效期 (分钟), 为空则不会过期
'token_expiration' => null,
- 'guard' => 'admin',
- 'guards' => [
+ 'guard' => 'admin',
+ 'guards' => [
'admin' => [
- 'driver' => 'sanctum',
+ 'driver' => 'sanctum',
'provider' => 'admin',
],
],
- 'providers' => [
+ 'providers' => [
'admin' => [
'driver' => 'eloquent',
- 'model' => \Slowlyo\OwlAdmin\Models\AdminUser::class,
+ 'model' => \App\Models\AdminUser::class,
],
],
- 'except' => [
-
+ 'except' => [
],
],
'upload' => [
- 'disk' => env("FILESYSTEM_DISK", 'public'),
+ 'disk' => env('FILESYSTEM_DISK', 'public'),
// 文件上传目录
'directory' => [
'image' => 'images',
- 'file' => 'files',
- 'rich' => 'rich',
+ 'file' => 'files',
+ 'rich' => 'rich',
],
// 临时目录
'tem_directory' => [
'image' => 'temporary/images',
- 'file' => 'temporary/file',
- 'rich' => 'temporary/rich',
- ]
+ 'file' => 'temporary/file',
+ 'rich' => 'temporary/rich',
+ ],
],
- 'https' => env('ADMIN_HTTPS', false),
+ 'https' => env('ADMIN_HTTPS', false),
// 是否显示 [开发者工具]
- 'show_development_tools' => env('ADMIN_SHOW_DEVELOPMENT_TOOLS', true),
+ 'show_development_tools' => env('ADMIN_SHOW_DEVELOPMENT_TOOLS', false),
// 是否显示 [权限] 功能中的自动生成按钮
'show_auto_generate_permission_button' => env('ADMIN_SHOW_AUTO_GENERATE_PERMISSION_BUTTON', true),
// 扩展
- 'extension' => [
+ 'extension' => [
'dir' => base_path('extensions'),
],
'layout' => [
// 浏览器标题, 功能名称使用 %title% 代替
- 'title' => '%title% | OwlAdmin',
- 'header' => [
+ 'title' => '%title% | 门店助手-管理后台',
+ 'header' => [
// 是否显示 [刷新] 按钮
- 'refresh' => true,
+ 'refresh' => true,
// 是否显示 [暗色模式] 按钮
- 'dark' => true,
+ 'dark' => true,
// 是否显示 [全屏] 按钮
- 'full_screen' => true,
+ 'full_screen' => true,
// 是否显示 [主题配置] 按钮
'theme_config' => true,
],
@@ -108,17 +113,17 @@ return [
*/
'keep_alive_exclude' => [],
// 底部信息
- 'footer' => 'Owl Admin',
+ 'footer' => '',
],
'database' => [
- 'connection' => env('ADMIN_DB_CONNECTION') ?? env('DB_CONNECTION', 'mysql'),
+ 'connection' => env('DB_CONNECTION', 'mysql'),
],
'models' => [
- 'admin_user' => \Slowlyo\OwlAdmin\Models\AdminUser::class,
- 'admin_role' => \Slowlyo\OwlAdmin\Models\AdminRole::class,
- 'admin_menu' => \Slowlyo\OwlAdmin\Models\AdminMenu::class,
+ 'admin_user' => \App\Models\AdminUser::class,
+ 'admin_role' => \App\Models\AdminRole::class,
+ 'admin_menu' => \Slowlyo\OwlAdmin\Models\AdminMenu::class,
'admin_permission' => \Slowlyo\OwlAdmin\Models\AdminPermission::class,
],
diff --git a/lang/zh_CN/admin.php b/lang/zh_CN/admin.php
index a888d66..c34c2f9 100644
--- a/lang/zh_CN/admin.php
+++ b/lang/zh_CN/admin.php
@@ -1,231 +1,228 @@
'记住我',
- 'login' => '登 录',
- 'logout' => '退出登录',
- 'username' => '用户名',
- 'password' => '密码',
- 'old_password' => '旧密码',
+ 'remember_me' => '记住我',
+ 'login' => '登 录',
+ 'logout' => '退出登录',
+ 'username' => '用户名',
+ 'password' => '密码',
+ 'old_password' => '旧密码',
'confirm_password' => '确认密码',
- 'captcha' => '验证码',
- 'captcha_error' => '验证码有误',
- 'required' => '请填写:attribute',
+ 'captcha' => '验证码',
+ 'captcha_error' => '验证码有误',
+ 'required' => '请填写:attribute',
'login_successful' => '登录成功',
- 'login_failed' => '用户名或密码错误',
- 'user_setting' => '个人设置',
- 'created_at' => '创建时间',
- 'updated_at' => '更新时间',
- 'deleted_at' => '删除时间',
- 'actions' => '操作',
- 'create' => '新增',
- 'edit' => '编辑',
- 'show' => '查看',
- 'delete' => '删除',
- 'copy' => '复制',
- 'confirm_delete' => '确认删除选中项?',
- 'back' => '返回',
- 'reset' => '重置',
- 'search' => '搜索',
- 'list' => '列表',
- 'add' => '新增',
- 'save' => '保存',
- 'detail' => '详情',
+ 'login_failed' => '用户名或密码错误',
+ 'user_setting' => '个人设置',
+ 'created_at' => '创建时间',
+ 'updated_at' => '更新时间',
+ 'deleted_at' => '删除时间',
+ 'actions' => '操作',
+ 'create' => '新增',
+ 'edit' => '编辑',
+ 'show' => '查看',
+ 'delete' => '删除',
+ 'copy' => '复制',
+ 'confirm_delete' => '确认删除选中项?',
+ 'confirm' => '是否确定?',
+ 'back' => '返回',
+ 'reset' => '重置',
+ 'search' => '搜索',
+ 'list' => '列表',
+ 'add' => '新增',
+ 'save' => '保存',
+ 'detail' => '详情',
- 'developer' => '开发',
- 'code_generator' => '代码生成器',
- 'visual_editor' => '可视化编辑器',
- 'terminal' => '终端',
- 'administrator' => '管理员',
- 'soft_delete' => '软删除',
- 'keyword' => '关键字',
- 'unknown_error' => '未知错误',
- 'upload_file_error' => '上传文件错误',
- 'parent' => '父级',
- 'order' => '排序',
- 'order_desc' => '降序排序',
- 'order_asc' => '升序排序',
- 'menus' => '菜单',
- 'successfully' => '成功',
- 'failed' => '失败',
- 'successfully_message' => ':attribute成功',
- 'failed_message' => ':attribute失败',
- 'action_success' => '操作成功',
- 'action_failed' => '操作失败',
- 'save_success' => '保存成功',
- 'save_failed' => '保存失败',
- 'yes' => '是',
- 'no' => '否',
+ 'developer' => '开发',
+ 'code_generator' => '代码生成器',
+ 'visual_editor' => '可视化编辑器',
+ 'terminal' => '终端',
+ 'administrator' => '管理员',
+ 'soft_delete' => '软删除',
+ 'keyword' => '关键字',
+ 'unknown_error' => '未知错误',
+ 'upload_file_error' => '上传文件错误',
+ 'parent' => '父级',
+ 'order' => '排序',
+ 'order_desc' => '降序排序',
+ 'order_asc' => '升序排序',
+ 'menus' => '菜单',
+ 'successfully' => '成功',
+ 'failed' => '失败',
+ 'successfully_message' => ':attribute成功',
+ 'failed_message' => ':attribute失败',
+ 'action_success' => '操作成功',
+ 'action_failed' => '操作失败',
+ 'save_success' => '保存成功',
+ 'save_failed' => '保存失败',
+ 'yes' => '是',
+ 'no' => '否',
'need_start_with_slash' => '需要以 / 开头',
- 'cancel' => '取消',
- 'please_login' => '请先登录',
- 'unauthorized' => '无权访问',
- 'user_disabled' => '用户已被禁用',
+ 'cancel' => '取消',
+ 'please_login' => '请先登录',
+ 'unauthorized' => '无权访问',
'code_generators' => [
- 'remark1' => '额外参数请参考',
- 'remark2' => '数据库迁移',
- 'remark3' => '多个参数使用英文逗号分割',
- 'table_name' => '表名',
- 'model_name' => '模型',
- 'controller_name' => '控制器',
- 'service_name' => 'Service',
- 'primary_key' => '主键名称',
- 'primary_key_description' => '使用 increments 方法',
- 'options' => '可选项',
+ 'remark1' => '额外参数请参考',
+ 'remark2' => '数据库迁移',
+ 'remark3' => '多个参数使用英文逗号分割',
+ 'table_name' => '表名',
+ 'model_name' => '模型',
+ 'controller_name' => '控制器',
+ 'service_name' => 'Service',
+ 'primary_key' => '主键名称',
+ 'primary_key_description' => '使用 increments 方法',
+ 'options' => '可选项',
'create_database_migration' => '创建数据库迁移文件',
- 'create_table' => '创建数据表',
- 'create_model' => '创建模型',
- 'create_controller' => '创建控制器',
- 'create_service' => '创建Service',
- 'app_title' => '功能名称',
- 'column_name' => '字段名',
- 'type' => '类型',
- 'extra_params' => '额外参数',
- 'nullable' => '允许空值',
- 'index' => '索引',
- 'default_value' => '默认值',
- 'comment' => '注释',
- 'exists_table' => '已有数据表',
- 'generate_code' => '生成代码',
- 'expand_more_settings' => '更多设置',
- 'collapse_settings' => '收起设置',
- 'confirm_generate_code' => '确认生成代码?',
- 'preview' => '预览',
- 'base_info' => '基本信息',
- 'column_info' => '字段信息',
- 'route_config' => '路由配置',
- 'page_config' => '页面配置',
- 'gen_route_menu' => '生成路由&菜单',
- 'route' => '路由',
- 'menu_name' => '菜单名称',
- 'parent_menu' => '父级菜单',
- 'menu_icon' => '菜单图标',
- 'name_label_desc' => 'name和label属性取字段名和注释',
- 'column_warning' => '如果字段名存在 no、status 会导致 form 回显失败!',
- 'add_column' => '添加字段',
- 'scope' => '作用域',
- 'list_component' => '列表组件',
- 'list_component_desc' => '列表组件, 默认为 TableColumn',
- 'form_component' => '表单组件',
- 'form_component_desc' => '表单组件, 默认为 TextControl',
- 'detail_component' => '详情组件',
- 'detail_component_desc' => '详情组件, 默认为 TextControl',
- 'model_config' => '模型配置',
- 'file_column' => '文件字段',
- 'file_column_desc' => '文件字段会自动在模型中添加 获取/修改器 方法',
- 'preview_code' => '预览代码',
- 'property' => '属性',
- 'property_name' => '属性名称',
- 'value' => '值',
- 'dialog_form' => '弹窗表单',
- 'dialog_size' => '弹窗大小',
- 'copy_record' => '复制记录',
- 'copy_record_description' => '你可以复制后分享到 Github',
- 'import_record' => '导入记录',
+ 'create_table' => '创建数据表',
+ 'create_model' => '创建模型',
+ 'create_controller' => '创建控制器',
+ 'create_service' => '创建Service',
+ 'app_title' => '功能名称',
+ 'column_name' => '字段名',
+ 'type' => '类型',
+ 'extra_params' => '额外参数',
+ 'nullable' => '允许空值',
+ 'index' => '索引',
+ 'default_value' => '默认值',
+ 'comment' => '注释',
+ 'exists_table' => '已有数据表',
+ 'generate_code' => '生成代码',
+ 'expand_more_settings' => '更多设置',
+ 'collapse_settings' => '收起设置',
+ 'confirm_generate_code' => '确认生成代码?',
+ 'preview' => '预览',
+ 'base_info' => '基本信息',
+ 'column_info' => '字段信息',
+ 'route_config' => '路由配置',
+ 'page_config' => '页面配置',
+ 'gen_route_menu' => '生成路由&菜单',
+ 'route' => '路由',
+ 'menu_name' => '菜单名称',
+ 'parent_menu' => '父级菜单',
+ 'menu_icon' => '菜单图标',
+ 'name_label_desc' => 'name和label属性取字段名和注释',
+ 'column_warning' => '如果字段名存在 no、status 会导致 form 回显失败!',
+ 'add_column' => '添加字段',
+ 'scope' => '作用域',
+ 'list_component' => '列表组件',
+ 'list_component_desc' => '列表组件, 默认为 TableColumn',
+ 'form_component' => '表单组件',
+ 'form_component_desc' => '表单组件, 默认为 TextControl',
+ 'detail_component' => '详情组件',
+ 'detail_component_desc' => '详情组件, 默认为 TextControl',
+ 'model_config' => '模型配置',
+ 'file_column' => '文件字段',
+ 'file_column_desc' => '文件字段会自动在模型中添加 获取/修改器 方法',
+ 'preview_code' => '预览代码',
+ 'property' => '属性',
+ 'property_name' => '属性名称',
+ 'value' => '值',
+ 'dialog_form' => '弹窗表单',
+ 'dialog_size' => '弹窗大小',
+ 'copy_record' => '复制记录',
+ 'copy_record_description' => '你可以复制后分享到 Github',
+ 'import_record' => '导入记录',
'import_record_placeholder' => '请输入导入的json记录',
- 'import_record_desc' => '你可以在 Github 找到一些其他人分享的记录',
- 'load_config' => '加载配置',
- 'load_component_config' => '加载 :c 配置',
- 'fill' => '填充',
- 'save_current_config' => '保存当前配置',
- 'input_config_name' => '请填写配置名称',
- 'same_name_tips' => '相同名称的配置将会被覆盖',
- 'save_path_dir' => '主应用',
- 'save_path_select' => '选择目录',
- 'save_path_select_tips' => '可选择项目根目录或插件根目录',
- 'save_path_label_prefix' => '插件 -> ',
+ 'import_record_desc' => '你可以在 Github 找到一些其他人分享的记录',
+ 'load_config' => '加载配置',
+ 'load_component_config' => '加载 :c 配置',
+ 'fill' => '填充',
+ 'save_current_config' => '保存当前配置',
+ 'input_config_name' => '请填写配置名称',
+ 'same_name_tips' => '相同名称的配置将会被覆盖',
],
'admin_users' => '管理员',
- 'admin_user' => [
- 'avatar' => '头像',
- 'name' => '姓名',
- 'roles' => '角色',
- 'search_username' => '搜索用户名/名称',
- 'password_confirmation' => '两次输入密码不一致',
- 'old_password_required' => '请输入原密码',
- 'old_password_error' => '原密码错误',
+ 'admin_user' => [
+ 'avatar' => '头像',
+ 'name' => '姓名',
+ 'roles' => '角色',
+ 'lock' => '锁定',
+ 'edit_password' => '修改密码',
+ 'search_username' => '搜索用户名/姓名',
+ 'password_confirmation' => '两次输入密码不一致',
+ 'old_password_required' => '请输入原密码',
+ 'old_password_error' => '原密码错误',
'username_already_exists' => '用户名已存在',
- 'cannot_delete' => '不可删除超级管理员',
],
'admin_roles' => '角色',
- 'admin_role' => [
- 'name' => '名称',
- 'slug' => '标识',
- 'permissions' => '权限',
- 'slug_description' => '角色的唯一标识, 不可重复',
+ 'admin_role' => [
+ 'name' => '名称',
+ 'slug' => '标识',
+ 'permissions' => '权限',
+ 'slug_description' => '角色的唯一标识, 不可重复',
'name_already_exists' => '角色名称已存在',
'slug_already_exists' => '角色标识已存在',
- 'set_permissions' => '设置权限',
- 'cannot_delete' => '不可删除超级管理员',
- 'used' => '不可删除正在使用的角色',
+ 'set_permissions' => '设置权限',
+ 'set_menus' => '设置菜单',
],
'admin_permissions' => '权限',
- 'admin_permission' => [
- 'name' => '名称',
- 'slug' => '标识',
- 'http_method' => '请求方式',
+ 'admin_permission' => [
+ 'name' => '名称',
+ 'slug' => '标识',
+ 'http_method' => '请求方式',
'http_method_description' => '不选则为ANY',
- 'http_path' => '路由',
- 'auto_generate' => '自动生成',
- 'auto_generate_confirm' => '权限信息会在 截断权限表&权限菜单关联表 后重新生成, 是否继续操作 ?',
- 'parent_id_not_allow' => '父级不允许设置为当前子权限',
- 'name_already_exists' => '权限名称已存在',
- 'slug_already_exists' => '权限标识已存在',
+ 'http_path' => '路由',
+ 'auto_generate' => '自动生成',
+ 'auto_generate_confirm' => '权限信息会在 截断权限表&权限菜单关联表 后重新生成, 是否继续操作 ?',
+ 'parent_id_not_allow' => '父级不允许设置为当前子权限',
+ 'name_already_exists' => '权限名称已存在',
+ 'slug_already_exists' => '权限标识已存在',
],
'admin_menus' => '菜单',
- 'admin_menu' => [
- 'parent_id' => '父级',
- 'order' => '排序',
- 'title' => '名称',
- 'icon' => '图标',
- 'icon_description' => '请参考',
- 'url' => '链接',
- 'visible' => '可见',
- 'type' => '类型',
- 'iframe' => 'Iframe',
- 'iframe_description' => '开启后页面将缓存,重新打开时不会重新加载',
- 'api' => '页面Api',
- 'api_description' => 'schemaApi, 页面初始化请求的api, 需要与Controller中的queryPath一致',
- 'route' => '路由',
- 'keep_alive' => '缓存页面',
- 'link' => '外链',
- 'class_name' => '类名',
+ 'admin_menu' => [
+ 'parent_id' => '父级',
+ 'order' => '排序',
+ 'title' => '名称',
+ 'icon' => '图标',
+ 'icon_description' => '请参考',
+ 'url' => '链接',
+ 'visible' => '可见',
+ 'type' => '类型',
+ 'api' => '页面Api',
+ 'api_description' => 'schemaApi, 页面初始化请求的api, 需要与Controller中的queryPath一致',
+ 'route' => '路由',
+ 'link' => '外链',
+ 'class_name' => '类名',
'class_name_description' => '菜单的CSS类名, 一般用于自定义样式',
- 'show' => '可见',
- 'hide' => '隐藏',
- 'is_home' => '首页',
- 'is_home_description' => '在多页签卡模式下,页面标签将固定在左侧',
- 'is_full' => '全屏',
- 'is_full_description' => '开启后将隐藏该页面的菜单栏部分',
- 'parent_id_not_allow' => '父级菜单不允许设置为当前子菜单',
- 'component' => '组件',
- 'component_desc' => '默认为 amis , 非自定义前端页面请勿修改',
- 'url_exists' => '菜单路径重复',
+ 'show' => '可见',
+ 'hide' => '隐藏',
+ 'is_home' => '首页',
+ 'is_home_description' => '在多页签卡模式下,页面标签将固定在左侧',
+ 'is_full' => '全屏',
+ 'is_full_description' => '开启后将隐藏该页面的菜单栏部分',
+ 'parent_id_not_allow' => '父级菜单不允许设置为当前子菜单',
+ 'component' => '组件',
+ 'component_desc' => '默认为 amis , 非自定义前端页面请勿修改',
+ ],
+
+ 'keywords' => [
+ 'search_name' => '名称/KEY',
+ 'parent_keyword' => '父级关键字',
],
'extensions' => [
- 'name_invalid' => '无效的扩展名称',
- 'exists' => '该扩展已存在:',
- 'menu' => '扩展',
- 'page_title' => '扩展',
- 'create' => '创建',
- 'install' => '安装',
- 'create_extension' => '创建扩展',
- 'create_tips' => '创建成功后会在
:dir
目录下创建基础的扩展目录结构',
- 'local_install' => '本地安装',
- 'more_extensions' => '更多扩展',
- 'setting' => '设置',
- 'enable' => '启用',
- 'enable_confirm' => '确定要启用该扩展吗?',
- 'disable' => '禁用',
- 'disable_confirm' => '确定要禁用该扩展吗?',
- 'uninstall' => '卸载',
- 'uninstall_confirm' => '
+ 'name_invalid' => '无效的扩展名称',
+ 'exists' => '该扩展已存在:',
+ 'menu' => '扩展',
+ 'page_title' => '扩展',
+ 'create' => '创建',
+ 'install' => '安装',
+ 'create_extension' => '创建扩展',
+ 'create_tips' => '创建成功后会在
:dir
目录下创建基础的扩展目录结构',
+ 'local_install' => '本地安装',
+ 'more_extensions' => '更多扩展',
+ 'setting' => '设置',
+ 'enable' => '启用',
+ 'enable_confirm' => '确定要启用该扩展吗?',
+ 'disable' => '禁用',
+ 'disable_confirm' => '确定要禁用该扩展吗?',
+ 'uninstall' => '卸载',
+ 'uninstall_confirm' => '
确认卸载该扩展?
卸载将会删除启用扩展后发布的所有文件及数据库, 且不可找回!!!
@@ -234,73 +231,34 @@ return [
',
'filter_placeholder' => '输入扩展名称',
- 'form' => [
- 'create_extension' => '创建扩展',
- 'name' => '名称',
- 'namespace' => '命名空间',
+ 'form' => [
+ 'create_extension' => '创建扩展',
+ 'name' => '名称',
+ 'namespace' => '命名空间',
'create_description' => '创建成功后会在 :dir 目录下创建基础的扩展目录结构',
],
- 'card' => [
- 'author' => '作者',
- 'version' => '版本',
+ 'card' => [
+ 'author' => '作者',
+ 'version' => '版本',
'homepage' => '主页',
- 'status' => '状态',
+ 'status' => '状态',
],
- 'status_map' => [
- 'enabled' => '已启用',
+ 'status_map' => [
+ 'enabled' => '已启用',
'disabled' => '已禁用',
],
- 'validation' => [
- 'file' => '请选择文件',
+ 'validation' => [
+ 'file' => '请选择文件',
'invalid_package' => '无效的扩展包',
],
],
- 'export' => [
- 'title' => '导出',
- 'all' => '全部',
- 'page' => '本页',
- 'selected_rows' => '选中行',
- 'page_no_data' => '本页无数据',
- 'selected_rows_no_data' => '请选择要导出的数据',
+ 'export' => [
+ 'title' => '导出',
+ 'all' => '全部',
+ 'page' => '本页',
+ 'selected_rows' => '选中行',
+ 'page_no_data' => '本页无数据',
+ 'selected_rows_no_data' => '请选择要导出的数据',
'please_install_laravel_excel' => '请先安装 laravel-excel 扩展',
],
- 'keywords' => [
- 'search_name' => '名称/KEY',
- 'parent_keyword' => '父级关键字',
- ],
- 'articles' => [
- 'id' => '主键ID',
- 'title' => '标题',
- 'content' => '内容',
- 'cover' =>'封面',
- 'category' => '分类',
- 'tags' => '标签',
- 't_ids' => '标签',
- 'published_at' => '定时发布',
- 'published_at_g' => '发布时间',
- 'is_enable' => '显示',
- 'is_recommend' => '推荐',
- 'sort' => '排序',
- 'appendixes' => '附件',
- 'published_at_remark' => '*若未设置发布时间且操作设置为显示,则默认生成发布时间',
- ],
- 'ads' => [
- 'id' => 'ID',
- 'address' => '位置',
- 'resource' =>'内容',
- 'published_at' => '定时发布',
- 'published_at_g' => '发布时间',
- 'is_enable' => '显示',
- 'remark' => '备注',
- 'sort' => '排序',
- 'published_at_remark' => '*若未设置发布时间且操作设置为显示,则默认生成发布时间',
- 'jump_type' => '跳转类型',
- 'jump_config'=>'跳转配置',
- 'jump_config_arr'=>[
- 'web_link' => '网页地址',
- 'app_link' => '应用路径',
- 'mini_id' => '小程序ID',
- 'mini_link'=> '小程序路径'
- ],
- ]
];