Template
调整数据库表的单复数
This commit is contained in:
1 parent
736a41a718
commit
d310a29c03
56 files changed
+45577
-506
No files matched your search
+1
-1
@@ -628,7 +628,7 @@ $timerId = \Swoole\Timer::tick(1000, function() {
|
||||
|
||||
**表命名示例:**
|
||||
- Auth 模块: `auth_users`, `auth_roles`, `auth_permissions`, `auth_role_permission`
|
||||
- System 模块: `system_configs`, `system_logs`, `system_dictionaries`
|
||||
- System 模块: `system_setting`, `system_logs`, `system_dictionaries`
|
||||
|
||||
**迁移文件示例:**
|
||||
```php
|
||||
|
||||
@@ -130,9 +130,9 @@ class City extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function children(int $parentId)
|
||||
public function children(string $parentCode)
|
||||
{
|
||||
$children = $this->cityService->getChildren($parentId);
|
||||
$children = $this->cityService->getChildren($parentCode);
|
||||
return response()->json([
|
||||
'code' => 200,
|
||||
'message' => 'success',
|
||||
|
||||
@@ -11,7 +11,7 @@ class Department extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'auth_departments';
|
||||
protected $table = 'auth_department';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
|
||||
@@ -11,7 +11,7 @@ class Permission extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'auth_permissions';
|
||||
protected $table = 'auth_permission';
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
|
||||
@@ -11,7 +11,7 @@ class Role extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'auth_roles';
|
||||
protected $table = 'auth_role';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
|
||||
@@ -14,7 +14,7 @@ class User extends Authenticatable implements JWTSubject
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'auth_users';
|
||||
protected $table = 'auth_user';
|
||||
|
||||
protected $fillable = [
|
||||
'username',
|
||||
|
||||
+19
-24
@@ -9,40 +9,35 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
class City extends Model
|
||||
{
|
||||
use ModelTrait;
|
||||
protected $table = 'system_cities';
|
||||
protected $table = 'system_city';
|
||||
|
||||
protected $fillable = [
|
||||
'parent_id',
|
||||
'name',
|
||||
'title',
|
||||
'code',
|
||||
'pinyin',
|
||||
'pinyin_short',
|
||||
'level',
|
||||
'sort',
|
||||
'status',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'parent_id' => 'integer',
|
||||
'level' => 'integer',
|
||||
'sort' => 'integer',
|
||||
'status' => 'boolean',
|
||||
'parent_code',
|
||||
];
|
||||
|
||||
/**
|
||||
* 子级城市
|
||||
*/
|
||||
public function children(): HasMany
|
||||
{
|
||||
return $this->hasMany(City::class, 'parent_id')->orderBy('sort');
|
||||
}
|
||||
|
||||
public function activeChildren(): HasMany
|
||||
{
|
||||
return $this->hasMany(City::class, 'parent_id')
|
||||
->where('status', true)
|
||||
->orderBy('sort');
|
||||
return $this->hasMany(City::class, 'parent_code', 'code');
|
||||
}
|
||||
|
||||
/**
|
||||
* 父级城市
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(City::class, 'parent_id');
|
||||
return $this->belongsTo(City::class, 'parent_code', 'code');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是顶级城市(省/直辖市/自治区)
|
||||
*/
|
||||
public function isTopLevel(): bool
|
||||
{
|
||||
return empty($this->parent_code);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ class Config extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'system_configs';
|
||||
protected $table = 'system_setting';
|
||||
|
||||
protected $fillable = [
|
||||
'group',
|
||||
|
||||
@@ -11,7 +11,7 @@ class Dictionary extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'system_dictionaries';
|
||||
protected $table = 'system_dictionary';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
|
||||
@@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
class DictionaryItem extends Model
|
||||
{
|
||||
use ModelTrait;
|
||||
protected $table = 'system_dictionary_items';
|
||||
protected $table = 'system_dictionary_item';
|
||||
|
||||
protected $fillable = [
|
||||
'dictionary_id',
|
||||
|
||||
@@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
class Log extends Model
|
||||
{
|
||||
use ModelTrait;
|
||||
protected $table = 'system_logs';
|
||||
protected $table = 'system_log';
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
|
||||
@@ -11,7 +11,7 @@ class Notification extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'system_notifications';
|
||||
protected $table = 'system_notification';
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
|
||||
@@ -10,7 +10,7 @@ class Task extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'system_tasks';
|
||||
protected $table = 'system_task';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
|
||||
@@ -12,27 +12,18 @@ class CityService
|
||||
{
|
||||
$query = City::query();
|
||||
|
||||
if (!empty($params['parent_id'])) {
|
||||
$query->where('parent_id', $params['parent_id']);
|
||||
}
|
||||
|
||||
if (!empty($params['level'])) {
|
||||
$query->where('level', $params['level']);
|
||||
if (!empty($params['parent_code'])) {
|
||||
$query->where('parent_code', $params['parent_code']);
|
||||
}
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('code', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('pinyin', 'like', '%' . $params['keyword'] . '%');
|
||||
$q->where('title', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('code', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
$query->orderBy('sort')->orderBy('id');
|
||||
$query->orderBy('id');
|
||||
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize);
|
||||
@@ -47,14 +38,13 @@ class CityService
|
||||
|
||||
public function getTree(): array
|
||||
{
|
||||
return $this->buildTree(City::where('status', true)->orderBy('sort')->get());
|
||||
return $this->buildTree(City::orderBy('id')->get());
|
||||
}
|
||||
|
||||
public function getChildren(int $parentId): array
|
||||
public function getChildren(string $parentCode): array
|
||||
{
|
||||
return City::where('parent_id', $parentId)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
return City::where('parent_code', $parentCode)
|
||||
->orderBy('id')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
@@ -69,21 +59,12 @@ class CityService
|
||||
return City::find($id);
|
||||
}
|
||||
|
||||
public function getByPinyin(string $pinyin): array
|
||||
{
|
||||
return City::where('pinyin', 'like', '%' . $pinyin . '%')
|
||||
->where('status', true)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function create(array $data): City
|
||||
{
|
||||
Validator::make($data, [
|
||||
'name' => 'required|string|max:100',
|
||||
'code' => 'required|string|max:50|unique:system_cities,code',
|
||||
'level' => 'required|integer|in:1,2,3',
|
||||
'parent_id' => 'sometimes|exists:system_cities,id',
|
||||
'title' => 'required|string|max:100',
|
||||
'code' => 'required|string|max:50|unique:system_city,code',
|
||||
'parent_code' => 'sometimes|nullable|exists:system_city,code',
|
||||
])->validate();
|
||||
|
||||
$city = City::create($data);
|
||||
@@ -96,12 +77,16 @@ class CityService
|
||||
$city = City::findOrFail($id);
|
||||
|
||||
Validator::make($data, [
|
||||
'name' => 'sometimes|required|string|max:100',
|
||||
'code' => 'sometimes|required|string|max:50|unique:system_cities,code,' . $id,
|
||||
'level' => 'sometimes|required|integer|in:1,2,3',
|
||||
'parent_id' => 'sometimes|exists:system_cities,id',
|
||||
'title' => 'sometimes|required|string|max:100',
|
||||
'code' => 'sometimes|required|string|max:50|unique:system_city,code,' . $id,
|
||||
'parent_code' => 'sometimes|nullable|exists:system_city,code',
|
||||
])->validate();
|
||||
|
||||
// 防止循环引用
|
||||
if (isset($data['parent_code']) && $data['parent_code'] === $city->code) {
|
||||
throw new \Exception('不能将城市设置为自己的子级');
|
||||
}
|
||||
|
||||
$city->update($data);
|
||||
$this->clearCache();
|
||||
return $city;
|
||||
@@ -127,19 +112,69 @@ class CityService
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchUpdateStatus(array $ids, bool $status): bool
|
||||
/**
|
||||
* 获取所有顶级城市(省/直辖市/自治区)
|
||||
*/
|
||||
public function getTopLevel(): array
|
||||
{
|
||||
City::whereIn('id', $ids)->update(['status' => $status]);
|
||||
$this->clearCache();
|
||||
return true;
|
||||
return City::whereNull('parent_code')
|
||||
->orderBy('id')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private function buildTree(array $cities, int $parentId = 0): array
|
||||
/**
|
||||
* 根据父级编码获取城市
|
||||
*/
|
||||
public function getByParentCode(string $parentCode): array
|
||||
{
|
||||
return City::where('parent_code', $parentCode)
|
||||
->orderBy('id')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取城市的完整路径(从顶级到当前)
|
||||
*/
|
||||
public function getPath(string $code): array
|
||||
{
|
||||
$path = [];
|
||||
$city = $this->getByCode($code);
|
||||
|
||||
while ($city) {
|
||||
array_unshift($path, $city);
|
||||
$city = $city->parent;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取城市的所有子孙
|
||||
*/
|
||||
public function getDescendants(string $code): array
|
||||
{
|
||||
$descendants = [];
|
||||
$this->collectDescendants($code, $descendants);
|
||||
return $descendants;
|
||||
}
|
||||
|
||||
private function collectDescendants(string $parentCode, array &$result): void
|
||||
{
|
||||
$children = City::where('parent_code', $parentCode)->get();
|
||||
foreach ($children as $child) {
|
||||
$result[] = $child;
|
||||
$this->collectDescendants($child->code, $result);
|
||||
}
|
||||
}
|
||||
|
||||
private function buildTree($cities, string $parentCode = ''): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($cities as $city) {
|
||||
if ($city['parent_id'] == $parentId) {
|
||||
$children = $this->buildTree($cities, $city['id']);
|
||||
if ($city->parent_code == $parentCode) {
|
||||
$children = $this->buildTree($cities, $city->code);
|
||||
if (!empty($children)) {
|
||||
$city['children'] = $children;
|
||||
}
|
||||
@@ -167,32 +202,36 @@ class CityService
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取省份(兼容旧接口)
|
||||
*/
|
||||
public function getProvinces(): array
|
||||
{
|
||||
return City::where('level', 1)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
return $this->getTopLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取城市(兼容旧接口)
|
||||
*/
|
||||
public function getCities(int $provinceId): array
|
||||
{
|
||||
return City::where('parent_id', $provinceId)
|
||||
->where('level', 2)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
// 由于新结构使用code关联,这里需要根据id找到对应的code
|
||||
$province = City::find($provinceId);
|
||||
if (!$province) {
|
||||
return [];
|
||||
}
|
||||
return $this->getByParentCode($province->code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区县(兼容旧接口)
|
||||
*/
|
||||
public function getDistricts(int $cityId): array
|
||||
{
|
||||
return City::where('parent_id', $cityId)
|
||||
->where('level', 3)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
$city = City::find($cityId);
|
||||
if (!$city) {
|
||||
return [];
|
||||
}
|
||||
return $this->getByParentCode($city->code);
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,7 @@ class ConfigService
|
||||
{
|
||||
Validator::make($data, [
|
||||
'group' => 'required|string|max:50',
|
||||
'key' => 'required|string|max:100|unique:system_configs,key',
|
||||
'key' => 'required|string|max:100|unique:system_setting,key',
|
||||
'name' => 'required|string|max:100',
|
||||
'type' => 'required|string|in:string,text,number,boolean,select,radio,checkbox,file,json',
|
||||
])->validate();
|
||||
@@ -104,7 +104,7 @@ class ConfigService
|
||||
|
||||
Validator::make($data, [
|
||||
'group' => 'sometimes|required|string|max:50',
|
||||
'key' => 'sometimes|required|string|max:100|unique:system_configs,key,' . $id,
|
||||
'key' => 'sometimes|required|string|max:100|unique:system_setting,key,' . $id,
|
||||
'name' => 'sometimes|required|string|max:100',
|
||||
'type' => 'sometimes|required|string|in:string,text,number,boolean,select,radio,checkbox,file,json',
|
||||
])->validate();
|
||||
|
||||
@@ -12,7 +12,7 @@ return new class extends Migration
|
||||
public function up(): void
|
||||
{
|
||||
// 管理员表
|
||||
Schema::create('auth_users', function (Blueprint $table) {
|
||||
Schema::create('auth_user', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('username', 50)->unique()->comment('用户名');
|
||||
$table->string('password')->comment('密码');
|
||||
@@ -32,7 +32,7 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// 部门表
|
||||
Schema::create('auth_departments', function (Blueprint $table) {
|
||||
Schema::create('auth_department', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 100)->comment('部门名称');
|
||||
$table->unsignedBigInteger('parent_id')->default(0)->comment('父部门ID');
|
||||
@@ -48,7 +48,7 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// 角色表
|
||||
Schema::create('auth_roles', function (Blueprint $table) {
|
||||
Schema::create('auth_role', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 50)->unique()->comment('角色名称');
|
||||
$table->string('code', 50)->unique()->comment('角色编码');
|
||||
@@ -62,7 +62,7 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// 权限表
|
||||
Schema::create('auth_permissions', function (Blueprint $table) {
|
||||
Schema::create('auth_permission', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title', 100)->comment('权限标题');
|
||||
$table->string('name', 100)->unique()->comment('权限编码');
|
||||
@@ -114,9 +114,9 @@ return new class extends Migration
|
||||
{
|
||||
Schema::dropIfExists('auth_role_permission');
|
||||
Schema::dropIfExists('auth_user_role');
|
||||
Schema::dropIfExists('auth_permissions');
|
||||
Schema::dropIfExists('auth_roles');
|
||||
Schema::dropIfExists('auth_departments');
|
||||
Schema::dropIfExists('auth_users');
|
||||
Schema::dropIfExists('auth_permission');
|
||||
Schema::dropIfExists('auth_role');
|
||||
Schema::dropIfExists('auth_department');
|
||||
Schema::dropIfExists('auth_user');
|
||||
}
|
||||
};
|
||||
@@ -9,7 +9,7 @@ return new class extends Migration
|
||||
public function up()
|
||||
{
|
||||
// 系统配置表
|
||||
Schema::create('system_configs', function (Blueprint $table) {
|
||||
Schema::create('system_setting', function (Blueprint $table) {
|
||||
$table->comment('系统配置表');
|
||||
$table->id();
|
||||
$table->string('group')->comment('配置分组');
|
||||
@@ -32,7 +32,7 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// 系统日志表
|
||||
Schema::create('system_logs', function (Blueprint $table) {
|
||||
Schema::create('system_log', function (Blueprint $table) {
|
||||
$table->comment('系统日志表');
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id')->nullable()->comment('用户ID');
|
||||
@@ -58,7 +58,7 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// 系统字典表
|
||||
Schema::create('system_dictionaries', function (Blueprint $table) {
|
||||
Schema::create('system_dictionary', function (Blueprint $table) {
|
||||
$table->comment('系统字典表');
|
||||
$table->id();
|
||||
$table->string('name')->comment('字典名称');
|
||||
@@ -72,7 +72,7 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// 系统字典项表
|
||||
Schema::create('system_dictionary_items', function (Blueprint $table) {
|
||||
Schema::create('system_dictionary_item', function (Blueprint $table) {
|
||||
$table->comment('系统字典项表');
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('dictionary_id')->comment('字典ID');
|
||||
@@ -85,12 +85,12 @@ return new class extends Migration
|
||||
$table->integer('sort')->default(0)->comment('排序');
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('dictionary_id')->references('id')->on('system_dictionaries')->onDelete('cascade');
|
||||
$table->foreign('dictionary_id')->references('id')->on('system_dictionary')->onDelete('cascade');
|
||||
$table->index('dictionary_id');
|
||||
});
|
||||
|
||||
// 系统任务表
|
||||
Schema::create('system_tasks', function (Blueprint $table) {
|
||||
Schema::create('system_task', function (Blueprint $table) {
|
||||
$table->comment('系统任务表');
|
||||
$table->id();
|
||||
$table->string('name')->comment('任务名称');
|
||||
@@ -115,32 +115,54 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// 系统城市表
|
||||
Schema::create('system_cities', function (Blueprint $table) {
|
||||
Schema::create('system_city', function (Blueprint $table) {
|
||||
$table->comment('系统城市表');
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('parent_id')->default(0)->comment('父级ID');
|
||||
$table->string('name')->comment('城市名称');
|
||||
$table->string('title')->comment('城市名称');
|
||||
$table->string('code')->unique()->comment('城市编码');
|
||||
$table->string('pinyin')->nullable()->comment('拼音');
|
||||
$table->string('pinyin_short')->nullable()->comment('拼音首字母');
|
||||
$table->integer('level')->default(1)->comment('级别:1=省,2=市,3=区/县');
|
||||
$table->integer('sort')->default(0)->comment('排序');
|
||||
$table->boolean('status')->default(true)->comment('状态');
|
||||
$table->string('parent_code')->nullable()->comment('父级编码');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('parent_id');
|
||||
$table->index('code');
|
||||
$table->index('level');
|
||||
$table->index('parent_code');
|
||||
});
|
||||
|
||||
// 系统通知表
|
||||
Schema::create('system_notification', function (Blueprint $table) {
|
||||
$table->comment('系统通知表');
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id')->comment('用户ID');
|
||||
$table->string('title')->comment('通知标题');
|
||||
$table->text('content')->comment('通知内容');
|
||||
$table->string('type')->default('info')->comment('通知类型:info, success, warning, error, task, system');
|
||||
$table->string('category')->nullable()->comment('通知分类:system, task, message, reminder, announcement');
|
||||
$table->json('data')->nullable()->comment('附加数据(JSON格式)');
|
||||
$table->string('action_type')->nullable()->comment('操作类型:link, modal, none');
|
||||
$table->text('action_data')->nullable()->comment('操作数据');
|
||||
$table->boolean('is_read')->default(false)->comment('是否已读');
|
||||
$table->timestamp('read_at')->nullable()->comment('阅读时间');
|
||||
$table->boolean('sent_via_websocket')->default(false)->comment('是否已通过WebSocket发送');
|
||||
$table->timestamp('sent_at')->nullable()->comment('发送时间');
|
||||
$table->integer('retry_count')->default(0)->comment('重试次数');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index('user_id');
|
||||
$table->index('is_read');
|
||||
$table->index('type');
|
||||
$table->index('category');
|
||||
$table->index('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('system_dictionary_items');
|
||||
Schema::dropIfExists('system_dictionaries');
|
||||
Schema::dropIfExists('system_configs');
|
||||
Schema::dropIfExists('system_logs');
|
||||
Schema::dropIfExists('system_tasks');
|
||||
Schema::dropIfExists('system_cities');
|
||||
Schema::dropIfExists('system_notification');
|
||||
Schema::dropIfExists('system_dictionary_item');
|
||||
Schema::dropIfExists('system_dictionary');
|
||||
Schema::dropIfExists('system_setting');
|
||||
Schema::dropIfExists('system_log');
|
||||
Schema::dropIfExists('system_task');
|
||||
Schema::dropIfExists('system_city');
|
||||
}
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// 系统通知表
|
||||
Schema::create('system_notifications', function (Blueprint $table) {
|
||||
$table->comment('系统通知表');
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id')->comment('用户ID');
|
||||
$table->string('title')->comment('通知标题');
|
||||
$table->text('content')->comment('通知内容');
|
||||
$table->string('type')->default('info')->comment('通知类型:info, success, warning, error, task, system');
|
||||
$table->string('category')->nullable()->comment('通知分类:system, task, message, reminder, announcement');
|
||||
$table->json('data')->nullable()->comment('附加数据(JSON格式)');
|
||||
$table->string('action_type')->nullable()->comment('操作类型:link, modal, none');
|
||||
$table->text('action_data')->nullable()->comment('操作数据');
|
||||
$table->boolean('is_read')->default(false)->comment('是否已读');
|
||||
$table->timestamp('read_at')->nullable()->comment('阅读时间');
|
||||
$table->boolean('sent_via_websocket')->default(false)->comment('是否已通过WebSocket发送');
|
||||
$table->timestamp('sent_at')->nullable()->comment('发送时间');
|
||||
$table->integer('retry_count')->default(0)->comment('重试次数');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index('user_id');
|
||||
$table->index('is_read');
|
||||
$table->index('type');
|
||||
$table->index('category');
|
||||
$table->index('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('system_notifications');
|
||||
}
|
||||
};
|
||||
@@ -161,8 +161,8 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为权限菜单的ID
|
||||
'path' => '/auth/users',
|
||||
'component' => 'auth/users/index',
|
||||
'path' => '/auth/user',
|
||||
'component' => 'auth/user/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'UserOutlined',
|
||||
'hidden' => false,
|
||||
@@ -176,7 +176,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为用户管理菜单的ID
|
||||
'path' => 'admin.users.index',
|
||||
'path' => 'admin.user.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -187,7 +187,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为用户管理菜单的ID
|
||||
'path' => 'admin.users.store',
|
||||
'path' => 'admin.user.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -198,7 +198,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为用户管理菜单的ID
|
||||
'path' => 'admin.users.update',
|
||||
'path' => 'admin.user.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -209,7 +209,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为用户管理菜单的ID
|
||||
'path' => 'admin.users.destroy',
|
||||
'path' => 'admin.user.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -220,7 +220,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为用户管理菜单的ID
|
||||
'path' => 'admin.users.batch-delete',
|
||||
'path' => 'admin.user.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
@@ -231,7 +231,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users.export',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为用户管理菜单的ID
|
||||
'path' => 'admin.users.export',
|
||||
'path' => 'admin.user.export',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 6,
|
||||
@@ -242,7 +242,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.users.import',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为用户管理菜单的ID
|
||||
'path' => 'admin.users.import',
|
||||
'path' => 'admin.user.import',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 7,
|
||||
@@ -254,8 +254,8 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.roles',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为权限菜单的ID
|
||||
'path' => '/auth/roles',
|
||||
'component' => 'auth/roles/index',
|
||||
'path' => '/auth/role',
|
||||
'component' => 'auth/role/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'UserFilled',
|
||||
'hidden' => false,
|
||||
@@ -269,7 +269,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.roles.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为角色管理菜单的ID
|
||||
'path' => 'admin.roles.index',
|
||||
'path' => 'admin.role.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -280,7 +280,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.roles.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为角色管理菜单的ID
|
||||
'path' => 'admin.roles.store',
|
||||
'path' => 'admin.role.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -291,7 +291,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.roles.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为角色管理菜单的ID
|
||||
'path' => 'admin.roles.update',
|
||||
'path' => 'admin.role.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -302,7 +302,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.roles.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为角色管理菜单的ID
|
||||
'path' => 'admin.roles.destroy',
|
||||
'path' => 'admin.role.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -313,7 +313,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.roles.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为角色管理菜单的ID
|
||||
'path' => 'admin.roles.batch-delete',
|
||||
'path' => 'admin.role.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
@@ -324,7 +324,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.roles.assign-permissions',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为角色管理菜单的ID
|
||||
'path' => 'admin.roles.assign-permissions',
|
||||
'path' => 'admin.role.assign-permissions',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 6,
|
||||
@@ -336,8 +336,8 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.permissions',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为权限菜单的ID
|
||||
'path' => '/auth/permissions',
|
||||
'component' => 'auth/permissions/index',
|
||||
'path' => '/auth/permission',
|
||||
'component' => 'auth/permission/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'Lock',
|
||||
'hidden' => false,
|
||||
@@ -351,7 +351,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.permissions.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为权限管理菜单的ID
|
||||
'path' => 'admin.permissions.index',
|
||||
'path' => 'admin.permission.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -362,7 +362,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.permissions.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为权限管理菜单的ID
|
||||
'path' => 'admin.permissions.store',
|
||||
'path' => 'admin.permission.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -373,7 +373,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.permissions.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为权限管理菜单的ID
|
||||
'path' => 'admin.permissions.update',
|
||||
'path' => 'admin.permission.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -384,7 +384,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.permissions.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为权限管理菜单的ID
|
||||
'path' => 'admin.permissions.destroy',
|
||||
'path' => 'admin.permission.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -395,7 +395,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.permissions.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为权限管理菜单的ID
|
||||
'path' => 'admin.permissions.batch-delete',
|
||||
'path' => 'admin.permission.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
@@ -407,8 +407,8 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.departments',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为权限菜单的ID
|
||||
'path' => '/auth/departments',
|
||||
'component' => 'auth/departments/index',
|
||||
'path' => '/auth/department',
|
||||
'component' => 'auth/department/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'OfficeBuilding',
|
||||
'hidden' => false,
|
||||
@@ -422,7 +422,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.departments.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为部门管理菜单的ID
|
||||
'path' => 'admin.departments.index',
|
||||
'path' => 'admin.department.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -433,7 +433,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.departments.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为部门管理菜单的ID
|
||||
'path' => 'admin.departments.store',
|
||||
'path' => 'admin.department.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -444,7 +444,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.departments.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为部门管理菜单的ID
|
||||
'path' => 'admin.departments.update',
|
||||
'path' => 'admin.department.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -455,7 +455,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.departments.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为部门管理菜单的ID
|
||||
'path' => 'admin.departments.destroy',
|
||||
'path' => 'admin.department.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -466,7 +466,7 @@ class AuthSeeder extends Seeder
|
||||
'name' => 'auth.departments.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为部门管理菜单的ID
|
||||
'path' => 'admin.departments.batch-delete',
|
||||
'path' => 'admin.department.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
|
||||
+227
-127
@@ -67,11 +67,11 @@ class SystemSeeder extends Seeder
|
||||
// 系统配置
|
||||
[
|
||||
'title' => '系统配置',
|
||||
'name' => 'system.config',
|
||||
'name' => 'system.setting',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为系统菜单的ID
|
||||
'path' => '/system/config',
|
||||
'component' => 'system/config/index',
|
||||
'path' => '/system/setting',
|
||||
'component' => 'system/setting/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'SettingFilled',
|
||||
'hidden' => false,
|
||||
@@ -82,10 +82,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '查看配置',
|
||||
'name' => 'system.config.view',
|
||||
'name' => 'system.setting.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统配置菜单的ID
|
||||
'path' => 'admin.config.index',
|
||||
'path' => 'admin.setting.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -93,10 +93,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '创建配置',
|
||||
'name' => 'system.config.create',
|
||||
'name' => 'system.setting.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统配置菜单的ID
|
||||
'path' => 'admin.config.store',
|
||||
'path' => 'admin.setting.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -104,10 +104,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '编辑配置',
|
||||
'name' => 'system.config.update',
|
||||
'name' => 'system.setting.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统配置菜单的ID
|
||||
'path' => 'admin.config.update',
|
||||
'path' => 'admin.setting.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -115,10 +115,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '删除配置',
|
||||
'name' => 'system.config.delete',
|
||||
'name' => 'system.setting.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统配置菜单的ID
|
||||
'path' => 'admin.config.destroy',
|
||||
'path' => 'admin.setting.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -126,10 +126,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '批量删除配置',
|
||||
'name' => 'system.config.batch-delete',
|
||||
'name' => 'system.setting.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统配置菜单的ID
|
||||
'path' => 'admin.config.batch-delete',
|
||||
'path' => 'admin.setting.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
@@ -139,11 +139,11 @@ class SystemSeeder extends Seeder
|
||||
// 系统日志
|
||||
[
|
||||
'title' => '系统日志',
|
||||
'name' => 'system.logs',
|
||||
'name' => 'system.log',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为系统菜单的ID
|
||||
'path' => '/system/logs',
|
||||
'component' => 'system/logs/index',
|
||||
'path' => '/system/log',
|
||||
'component' => 'system/log/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'DocumentCopy',
|
||||
'hidden' => false,
|
||||
@@ -154,10 +154,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '查看日志',
|
||||
'name' => 'system.logs.view',
|
||||
'name' => 'system.log.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统日志菜单的ID
|
||||
'path' => 'admin.logs.index',
|
||||
'path' => 'admin.log.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -165,10 +165,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '删除日志',
|
||||
'name' => 'system.logs.delete',
|
||||
'name' => 'system.log.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统日志菜单的ID
|
||||
'path' => 'admin.logs.destroy',
|
||||
'path' => 'admin.log.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -176,10 +176,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '批量删除日志',
|
||||
'name' => 'system.logs.batch-delete',
|
||||
'name' => 'system.log.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统日志菜单的ID
|
||||
'path' => 'admin.logs.batch-delete',
|
||||
'path' => 'admin.log.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -187,10 +187,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '导出日志',
|
||||
'name' => 'system.logs.export',
|
||||
'name' => 'system.log.export',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为系统日志菜单的ID
|
||||
'path' => 'admin.logs.export',
|
||||
'path' => 'admin.log.export',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -200,11 +200,11 @@ class SystemSeeder extends Seeder
|
||||
// 数据字典
|
||||
[
|
||||
'title' => '数据字典',
|
||||
'name' => 'system.dictionaries',
|
||||
'name' => 'system.dictionary',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为系统菜单的ID
|
||||
'path' => '/system/dictionaries',
|
||||
'component' => 'system/dictionaries/index',
|
||||
'path' => '/system/dictionary',
|
||||
'component' => 'system/dictionary/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'Notebook',
|
||||
'hidden' => false,
|
||||
@@ -215,10 +215,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '查看字典',
|
||||
'name' => 'system.dictionaries.view',
|
||||
'name' => 'system.dictionary.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为数据字典菜单的ID
|
||||
'path' => 'admin.dictionaries.index',
|
||||
'path' => 'admin.dictionary.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -226,10 +226,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '创建字典',
|
||||
'name' => 'system.dictionaries.create',
|
||||
'name' => 'system.dictionary.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为数据字典菜单的ID
|
||||
'path' => 'admin.dictionaries.store',
|
||||
'path' => 'admin.dictionary.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -237,10 +237,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '编辑字典',
|
||||
'name' => 'system.dictionaries.update',
|
||||
'name' => 'system.dictionary.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为数据字典菜单的ID
|
||||
'path' => 'admin.dictionaries.update',
|
||||
'path' => 'admin.dictionary.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -248,10 +248,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '删除字典',
|
||||
'name' => 'system.dictionaries.delete',
|
||||
'name' => 'system.dictionary.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为数据字典菜单的ID
|
||||
'path' => 'admin.dictionaries.destroy',
|
||||
'path' => 'admin.dictionary.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -259,10 +259,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '批量删除字典',
|
||||
'name' => 'system.dictionaries.batch-delete',
|
||||
'name' => 'system.dictionary.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为数据字典菜单的ID
|
||||
'path' => 'admin.dictionaries.batch-delete',
|
||||
'path' => 'admin.dictionary.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
@@ -272,11 +272,11 @@ class SystemSeeder extends Seeder
|
||||
// 定时任务
|
||||
[
|
||||
'title' => '定时任务',
|
||||
'name' => 'system.tasks',
|
||||
'name' => 'system.task',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为系统菜单的ID
|
||||
'path' => '/system/tasks',
|
||||
'component' => 'system/tasks/index',
|
||||
'path' => '/system/task',
|
||||
'component' => 'system/task/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'Timer',
|
||||
'hidden' => false,
|
||||
@@ -287,10 +287,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '查看任务',
|
||||
'name' => 'system.tasks.view',
|
||||
'name' => 'system.task.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.index',
|
||||
'path' => 'admin.task.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
@@ -298,10 +298,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '创建任务',
|
||||
'name' => 'system.tasks.create',
|
||||
'name' => 'system.task.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.store',
|
||||
'path' => 'admin.task.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
@@ -309,10 +309,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '编辑任务',
|
||||
'name' => 'system.tasks.update',
|
||||
'name' => 'system.task.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.update',
|
||||
'path' => 'admin.task.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
@@ -320,10 +320,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '删除任务',
|
||||
'name' => 'system.tasks.delete',
|
||||
'name' => 'system.task.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.destroy',
|
||||
'path' => 'admin.task.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
@@ -331,10 +331,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '批量删除任务',
|
||||
'name' => 'system.tasks.batch-delete',
|
||||
'name' => 'system.task.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.batch-delete',
|
||||
'path' => 'admin.task.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
@@ -342,10 +342,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '执行任务',
|
||||
'name' => 'system.tasks.execute',
|
||||
'name' => 'system.task.execute',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.execute',
|
||||
'path' => 'admin.task.execute',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 6,
|
||||
@@ -353,10 +353,10 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '启用任务',
|
||||
'name' => 'system.tasks.enable',
|
||||
'name' => 'system.task.enable',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.enable',
|
||||
'path' => 'admin.task.enable',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 7,
|
||||
@@ -364,15 +364,87 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'title' => '禁用任务',
|
||||
'name' => 'system.tasks.disable',
|
||||
'name' => 'system.task.disable',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为定时任务菜单的ID
|
||||
'path' => 'admin.tasks.disable',
|
||||
'path' => 'admin.task.disable',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 8,
|
||||
'status' => 1,
|
||||
],
|
||||
|
||||
// 城市管理
|
||||
[
|
||||
'title' => '城市管理',
|
||||
'name' => 'system.city',
|
||||
'type' => 'menu',
|
||||
'parent_id' => 0, // 稍后更新为系统菜单的ID
|
||||
'path' => '/system/city',
|
||||
'component' => 'system/city/index',
|
||||
'meta' => json_encode([
|
||||
'icon' => 'EnvironmentOutlined',
|
||||
'hidden' => false,
|
||||
'hiddenBreadcrumb' => false,
|
||||
]),
|
||||
'sort' => 5,
|
||||
'status' => 1,
|
||||
],
|
||||
[
|
||||
'title' => '查看城市',
|
||||
'name' => 'system.city.view',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为城市管理菜单的ID
|
||||
'path' => 'admin.city.index',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
],
|
||||
[
|
||||
'title' => '创建城市',
|
||||
'name' => 'system.city.create',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为城市管理菜单的ID
|
||||
'path' => 'admin.city.store',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 2,
|
||||
'status' => 1,
|
||||
],
|
||||
[
|
||||
'title' => '编辑城市',
|
||||
'name' => 'system.city.update',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为城市管理菜单的ID
|
||||
'path' => 'admin.city.update',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 3,
|
||||
'status' => 1,
|
||||
],
|
||||
[
|
||||
'title' => '删除城市',
|
||||
'name' => 'system.city.delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为城市管理菜单的ID
|
||||
'path' => 'admin.city.destroy',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 4,
|
||||
'status' => 1,
|
||||
],
|
||||
[
|
||||
'title' => '批量删除城市',
|
||||
'name' => 'system.city.batch-delete',
|
||||
'type' => 'button',
|
||||
'parent_id' => 0, // 稍后更新为城市管理菜单的ID
|
||||
'path' => 'admin.city.batch-delete',
|
||||
'component' => null,
|
||||
'meta' => null,
|
||||
'sort' => 5,
|
||||
'status' => 1,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
@@ -394,128 +466,156 @@ class SystemSeeder extends Seeder
|
||||
$systemMenu = $permissions->where('name', 'system')->first();
|
||||
|
||||
// 获取系统子菜单ID
|
||||
$configMenu = $permissions->where('name', 'system.config')->first();
|
||||
$logsMenu = $permissions->where('name', 'system.logs')->first();
|
||||
$dictionariesMenu = $permissions->where('name', 'system.dictionaries')->first();
|
||||
$tasksMenu = $permissions->where('name', 'system.tasks')->first();
|
||||
$settingMenu = $permissions->where('name', 'system.setting')->first();
|
||||
$logMenu = $permissions->where('name', 'system.log')->first();
|
||||
$dictionaryMenu = $permissions->where('name', 'system.dictionary')->first();
|
||||
$taskMenu = $permissions->where('name', 'system.task')->first();
|
||||
$cityMenu = $permissions->where('name', 'system.city')->first();
|
||||
|
||||
// 更新系统子菜单的parent_id
|
||||
if ($systemMenu) {
|
||||
if ($configMenu) {
|
||||
$configMenu->update(['parent_id' => $systemMenu->id]);
|
||||
if ($settingMenu) {
|
||||
$settingMenu->update(['parent_id' => $systemMenu->id]);
|
||||
}
|
||||
if ($logsMenu) {
|
||||
$logsMenu->update(['parent_id' => $systemMenu->id]);
|
||||
if ($logMenu) {
|
||||
$logMenu->update(['parent_id' => $systemMenu->id]);
|
||||
}
|
||||
if ($dictionariesMenu) {
|
||||
$dictionariesMenu->update(['parent_id' => $systemMenu->id]);
|
||||
if ($dictionaryMenu) {
|
||||
$dictionaryMenu->update(['parent_id' => $systemMenu->id]);
|
||||
}
|
||||
if ($tasksMenu) {
|
||||
$tasksMenu->update(['parent_id' => $systemMenu->id]);
|
||||
if ($taskMenu) {
|
||||
$taskMenu->update(['parent_id' => $systemMenu->id]);
|
||||
}
|
||||
if ($cityMenu) {
|
||||
$cityMenu->update(['parent_id' => $systemMenu->id]);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新按钮权限的parent_id - 系统配置
|
||||
$configViewBtn = $permissions->where('name', 'system.config.view')->first();
|
||||
$configCreateBtn = $permissions->where('name', 'system.config.create')->first();
|
||||
$configUpdateBtn = $permissions->where('name', 'system.config.update')->first();
|
||||
$configDeleteBtn = $permissions->where('name', 'system.config.delete')->first();
|
||||
$configBatchDeleteBtn = $permissions->where('name', 'system.config.batch-delete')->first();
|
||||
if ($configMenu) {
|
||||
if ($configViewBtn) {
|
||||
$configViewBtn->update(['parent_id' => $configMenu->id]);
|
||||
$settingViewBtn = $permissions->where('name', 'system.setting.view')->first();
|
||||
$settingCreateBtn = $permissions->where('name', 'system.setting.create')->first();
|
||||
$settingUpdateBtn = $permissions->where('name', 'system.setting.update')->first();
|
||||
$settingDeleteBtn = $permissions->where('name', 'system.setting.delete')->first();
|
||||
$settingBatchDeleteBtn = $permissions->where('name', 'system.setting.batch-delete')->first();
|
||||
if ($settingMenu) {
|
||||
if ($settingViewBtn) {
|
||||
$settingViewBtn->update(['parent_id' => $settingMenu->id]);
|
||||
}
|
||||
if ($configCreateBtn) {
|
||||
$configCreateBtn->update(['parent_id' => $configMenu->id]);
|
||||
if ($settingCreateBtn) {
|
||||
$settingCreateBtn->update(['parent_id' => $settingMenu->id]);
|
||||
}
|
||||
if ($configUpdateBtn) {
|
||||
$configUpdateBtn->update(['parent_id' => $configMenu->id]);
|
||||
if ($settingUpdateBtn) {
|
||||
$settingUpdateBtn->update(['parent_id' => $settingMenu->id]);
|
||||
}
|
||||
if ($configDeleteBtn) {
|
||||
$configDeleteBtn->update(['parent_id' => $configMenu->id]);
|
||||
if ($settingDeleteBtn) {
|
||||
$settingDeleteBtn->update(['parent_id' => $settingMenu->id]);
|
||||
}
|
||||
if ($configBatchDeleteBtn) {
|
||||
$configBatchDeleteBtn->update(['parent_id' => $configMenu->id]);
|
||||
if ($settingBatchDeleteBtn) {
|
||||
$settingBatchDeleteBtn->update(['parent_id' => $settingMenu->id]);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新按钮权限的parent_id - 系统日志
|
||||
$logsViewBtn = $permissions->where('name', 'system.logs.view')->first();
|
||||
$logsDeleteBtn = $permissions->where('name', 'system.logs.delete')->first();
|
||||
$logsBatchDeleteBtn = $permissions->where('name', 'system.logs.batch-delete')->first();
|
||||
$logsExportBtn = $permissions->where('name', 'system.logs.export')->first();
|
||||
if ($logsMenu) {
|
||||
if ($logsViewBtn) {
|
||||
$logsViewBtn->update(['parent_id' => $logsMenu->id]);
|
||||
$logViewBtn = $permissions->where('name', 'system.log.view')->first();
|
||||
$logDeleteBtn = $permissions->where('name', 'system.log.delete')->first();
|
||||
$logBatchDeleteBtn = $permissions->where('name', 'system.log.batch-delete')->first();
|
||||
$logExportBtn = $permissions->where('name', 'system.log.export')->first();
|
||||
if ($logMenu) {
|
||||
if ($logViewBtn) {
|
||||
$logViewBtn->update(['parent_id' => $logMenu->id]);
|
||||
}
|
||||
if ($logsDeleteBtn) {
|
||||
$logsDeleteBtn->update(['parent_id' => $logsMenu->id]);
|
||||
if ($logDeleteBtn) {
|
||||
$logDeleteBtn->update(['parent_id' => $logMenu->id]);
|
||||
}
|
||||
if ($logsBatchDeleteBtn) {
|
||||
$logsBatchDeleteBtn->update(['parent_id' => $logsMenu->id]);
|
||||
if ($logBatchDeleteBtn) {
|
||||
$logBatchDeleteBtn->update(['parent_id' => $logMenu->id]);
|
||||
}
|
||||
if ($logsExportBtn) {
|
||||
$logsExportBtn->update(['parent_id' => $logsMenu->id]);
|
||||
if ($logExportBtn) {
|
||||
$logExportBtn->update(['parent_id' => $logMenu->id]);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新按钮权限的parent_id - 数据字典
|
||||
$dictViewBtn = $permissions->where('name', 'system.dictionaries.view')->first();
|
||||
$dictCreateBtn = $permissions->where('name', 'system.dictionaries.create')->first();
|
||||
$dictUpdateBtn = $permissions->where('name', 'system.dictionaries.update')->first();
|
||||
$dictDeleteBtn = $permissions->where('name', 'system.dictionaries.delete')->first();
|
||||
$dictBatchDeleteBtn = $permissions->where('name', 'system.dictionaries.batch-delete')->first();
|
||||
if ($dictionariesMenu) {
|
||||
$dictViewBtn = $permissions->where('name', 'system.dictionary.view')->first();
|
||||
$dictCreateBtn = $permissions->where('name', 'system.dictionary.create')->first();
|
||||
$dictUpdateBtn = $permissions->where('name', 'system.dictionary.update')->first();
|
||||
$dictDeleteBtn = $permissions->where('name', 'system.dictionary.delete')->first();
|
||||
$dictBatchDeleteBtn = $permissions->where('name', 'system.dictionary.batch-delete')->first();
|
||||
if ($dictionaryMenu) {
|
||||
if ($dictViewBtn) {
|
||||
$dictViewBtn->update(['parent_id' => $dictionariesMenu->id]);
|
||||
$dictViewBtn->update(['parent_id' => $dictionaryMenu->id]);
|
||||
}
|
||||
if ($dictCreateBtn) {
|
||||
$dictCreateBtn->update(['parent_id' => $dictionariesMenu->id]);
|
||||
$dictCreateBtn->update(['parent_id' => $dictionaryMenu->id]);
|
||||
}
|
||||
if ($dictUpdateBtn) {
|
||||
$dictUpdateBtn->update(['parent_id' => $dictionariesMenu->id]);
|
||||
$dictUpdateBtn->update(['parent_id' => $dictionaryMenu->id]);
|
||||
}
|
||||
if ($dictDeleteBtn) {
|
||||
$dictDeleteBtn->update(['parent_id' => $dictionariesMenu->id]);
|
||||
$dictDeleteBtn->update(['parent_id' => $dictionaryMenu->id]);
|
||||
}
|
||||
if ($dictBatchDeleteBtn) {
|
||||
$dictBatchDeleteBtn->update(['parent_id' => $dictionariesMenu->id]);
|
||||
$dictBatchDeleteBtn->update(['parent_id' => $dictionaryMenu->id]);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新按钮权限的parent_id - 定时任务
|
||||
$taskViewBtn = $permissions->where('name', 'system.tasks.view')->first();
|
||||
$taskCreateBtn = $permissions->where('name', 'system.tasks.create')->first();
|
||||
$taskUpdateBtn = $permissions->where('name', 'system.tasks.update')->first();
|
||||
$taskDeleteBtn = $permissions->where('name', 'system.tasks.delete')->first();
|
||||
$taskBatchDeleteBtn = $permissions->where('name', 'system.tasks.batch-delete')->first();
|
||||
$taskExecuteBtn = $permissions->where('name', 'system.tasks.execute')->first();
|
||||
$taskEnableBtn = $permissions->where('name', 'system.tasks.enable')->first();
|
||||
$taskDisableBtn = $permissions->where('name', 'system.tasks.disable')->first();
|
||||
if ($tasksMenu) {
|
||||
$taskViewBtn = $permissions->where('name', 'system.task.view')->first();
|
||||
$taskCreateBtn = $permissions->where('name', 'system.task.create')->first();
|
||||
$taskUpdateBtn = $permissions->where('name', 'system.task.update')->first();
|
||||
$taskDeleteBtn = $permissions->where('name', 'system.task.delete')->first();
|
||||
$taskBatchDeleteBtn = $permissions->where('name', 'system.task.batch-delete')->first();
|
||||
$taskExecuteBtn = $permissions->where('name', 'system.task.execute')->first();
|
||||
$taskEnableBtn = $permissions->where('name', 'system.task.enable')->first();
|
||||
$taskDisableBtn = $permissions->where('name', 'system.task.disable')->first();
|
||||
if ($taskMenu) {
|
||||
if ($taskViewBtn) {
|
||||
$taskViewBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskViewBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
if ($taskCreateBtn) {
|
||||
$taskCreateBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskCreateBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
if ($taskUpdateBtn) {
|
||||
$taskUpdateBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskUpdateBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
if ($taskDeleteBtn) {
|
||||
$taskDeleteBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskDeleteBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
if ($taskBatchDeleteBtn) {
|
||||
$taskBatchDeleteBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskBatchDeleteBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
if ($taskExecuteBtn) {
|
||||
$taskExecuteBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskExecuteBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
if ($taskEnableBtn) {
|
||||
$taskEnableBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskEnableBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
if ($taskDisableBtn) {
|
||||
$taskDisableBtn->update(['parent_id' => $tasksMenu->id]);
|
||||
$taskDisableBtn->update(['parent_id' => $taskMenu->id]);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新按钮权限的parent_id - 城市管理
|
||||
$cityViewBtn = $permissions->where('name', 'system.city.view')->first();
|
||||
$cityCreateBtn = $permissions->where('name', 'system.city.create')->first();
|
||||
$cityUpdateBtn = $permissions->where('name', 'system.city.update')->first();
|
||||
$cityDeleteBtn = $permissions->where('name', 'system.city.delete')->first();
|
||||
$cityBatchDeleteBtn = $permissions->where('name', 'system.city.batch-delete')->first();
|
||||
if ($cityMenu) {
|
||||
if ($cityViewBtn) {
|
||||
$cityViewBtn->update(['parent_id' => $cityMenu->id]);
|
||||
}
|
||||
if ($cityCreateBtn) {
|
||||
$cityCreateBtn->update(['parent_id' => $cityMenu->id]);
|
||||
}
|
||||
if ($cityUpdateBtn) {
|
||||
$cityUpdateBtn->update(['parent_id' => $cityMenu->id]);
|
||||
}
|
||||
if ($cityDeleteBtn) {
|
||||
$cityDeleteBtn->update(['parent_id' => $cityMenu->id]);
|
||||
}
|
||||
if ($cityBatchDeleteBtn) {
|
||||
$cityBatchDeleteBtn->update(['parent_id' => $cityMenu->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -526,7 +626,7 @@ class SystemSeeder extends Seeder
|
||||
private function createSystemDictionaries(): void
|
||||
{
|
||||
// 创建字典类型
|
||||
$dictionaries = [
|
||||
$dictionary = [
|
||||
[
|
||||
'name' => '用户状态',
|
||||
'code' => 'user_status',
|
||||
@@ -593,7 +693,7 @@ class SystemSeeder extends Seeder
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($dictionaries as $dictionary) {
|
||||
foreach ($dictionary as $dictionary) {
|
||||
$dict = Dictionary::create($dictionary);
|
||||
$this->createDictionaryItems($dict);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -49,7 +49,7 @@ app/Http/Controllers/System/
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### system_configs (系统配置表)
|
||||
### system_setting (系统配置表)
|
||||
- `id`: 主键
|
||||
- `group`: 配置分组(如:system, site, upload)
|
||||
- `key`: 配置键(唯一)
|
||||
@@ -1270,7 +1270,7 @@ protected function schedule(Schedule $schedule)
|
||||
- `system_logs`: `user_id`, `username`, `module`, `status`, `created_at`
|
||||
- `system_dictionaries`: `code`, `status`
|
||||
- `system_dictionary_items`: `dictionary_id`, `status`
|
||||
- `system_configs`: `group`, `key`, `status`
|
||||
- `system_setting`: `group`, `key`, `status`
|
||||
|
||||
### 3. 分页查询
|
||||
|
||||
|
||||
@@ -35,72 +35,72 @@ export default {
|
||||
},
|
||||
|
||||
// 用户管理
|
||||
users: {
|
||||
user: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/users", { params });
|
||||
return await request.get("auth/user", { params });
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/users/${id}`);
|
||||
return await request.get(`auth/user/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users", params);
|
||||
return await request.post("auth/user", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/users/${id}`, params);
|
||||
return await request.put(`auth/user/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/users/${id}`);
|
||||
return await request.delete(`auth/user/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/batch-delete", params);
|
||||
return await request.post("auth/user/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/batch-status", params);
|
||||
return await request.post("auth/user/batch-status", params);
|
||||
},
|
||||
},
|
||||
batchDepartment: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/users/batch-department",
|
||||
"auth/user/batch-department",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
batchRoles: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/batch-roles", params);
|
||||
return await request.post("auth/user/batch-roles", params);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/export", params, {
|
||||
return await request.post("auth/user/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/users/import", formData, {
|
||||
return await request.post("auth/user/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/users/download-template", {
|
||||
return await request.get("auth/user/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
@@ -108,28 +108,28 @@ export default {
|
||||
},
|
||||
|
||||
// 在线用户管理
|
||||
onlineUsers: {
|
||||
onlineUser: {
|
||||
count: {
|
||||
get: async function () {
|
||||
return await request.get("auth/online-users/count");
|
||||
return await request.get("auth/online-user/count");
|
||||
},
|
||||
},
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/online-users", { params });
|
||||
return await request.get("auth/online-user", { params });
|
||||
},
|
||||
},
|
||||
sessions: {
|
||||
get: async function (userId) {
|
||||
return await request.get(
|
||||
`auth/online-users/${userId}/sessions`,
|
||||
`auth/online-user/${userId}/sessions`,
|
||||
);
|
||||
},
|
||||
},
|
||||
offline: {
|
||||
post: async function (userId, params) {
|
||||
return await request.post(
|
||||
`auth/online-users/${userId}/offline`,
|
||||
`auth/online-user/${userId}/offline`,
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -137,92 +137,92 @@ export default {
|
||||
offlineAll: {
|
||||
post: async function (userId) {
|
||||
return await request.post(
|
||||
`auth/online-users/${userId}/offline-all`,
|
||||
`auth/online-user/${userId}/offline-all`,
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// 角色管理
|
||||
roles: {
|
||||
role: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/roles", { params });
|
||||
return await request.get("auth/role", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("auth/roles/all");
|
||||
return await request.get("auth/role/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/roles/${id}`);
|
||||
return await request.get(`auth/role/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles", params);
|
||||
return await request.post("auth/role", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/roles/${id}`, params);
|
||||
return await request.put(`auth/role/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/roles/${id}`);
|
||||
return await request.delete(`auth/role/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/batch-delete", params);
|
||||
return await request.post("auth/role/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/batch-status", params);
|
||||
return await request.post("auth/role/batch-status", params);
|
||||
},
|
||||
},
|
||||
permissions: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/roles/${id}/permissions`);
|
||||
return await request.get(`auth/role/${id}/permissions`);
|
||||
},
|
||||
post: async function (id, params) {
|
||||
return await request.post(
|
||||
`auth/roles/${id}/permissions`,
|
||||
`auth/role/${id}/permissions`,
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
copy: {
|
||||
post: async function (id, params) {
|
||||
return await request.post(`auth/roles/${id}/copy`, params);
|
||||
return await request.post(`auth/role/${id}/copy`, params);
|
||||
},
|
||||
},
|
||||
batchCopy: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/batch-copy", params);
|
||||
return await request.post("auth/role/batch-copy", params);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/export", params, {
|
||||
return await request.post("auth/role/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/roles/import", formData, {
|
||||
return await request.post("auth/role/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/roles/download-template", {
|
||||
return await request.get("auth/role/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
@@ -230,46 +230,46 @@ export default {
|
||||
},
|
||||
|
||||
// 权限管理
|
||||
permissions: {
|
||||
permission: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/permissions", { params });
|
||||
return await request.get("auth/permission", { params });
|
||||
},
|
||||
},
|
||||
tree: {
|
||||
get: async function () {
|
||||
return await request.get("auth/permissions/tree");
|
||||
return await request.get("auth/permission/tree");
|
||||
},
|
||||
},
|
||||
menu: {
|
||||
get: async function () {
|
||||
return await request.get("auth/permissions/menu");
|
||||
return await request.get("auth/permission/menu");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/permissions/${id}`);
|
||||
return await request.get(`auth/permission/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/permissions", params);
|
||||
return await request.post("auth/permission", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/permissions/${id}`, params);
|
||||
return await request.put(`auth/permission/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/permissions/${id}`);
|
||||
return await request.delete(`auth/permission/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/permissions/batch-delete",
|
||||
"auth/permission/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -277,28 +277,28 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/permissions/batch-status",
|
||||
"auth/permission/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/permissions/export", params, {
|
||||
return await request.post("auth/permission/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/permissions/import", formData, {
|
||||
return await request.post("auth/permission/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/permissions/download-template", {
|
||||
return await request.get("auth/permission/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
@@ -306,46 +306,46 @@ export default {
|
||||
},
|
||||
|
||||
// 部门管理
|
||||
departments: {
|
||||
department: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/departments", { params });
|
||||
return await request.get("auth/department", { params });
|
||||
},
|
||||
},
|
||||
tree: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/departments/tree", { params });
|
||||
return await request.get("auth/department/tree", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("auth/departments/all");
|
||||
return await request.get("auth/department/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/departments/${id}`);
|
||||
return await request.get(`auth/department/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/departments", params);
|
||||
return await request.post("auth/department", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/departments/${id}`, params);
|
||||
return await request.put(`auth/department/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/departments/${id}`);
|
||||
return await request.delete(`auth/department/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/departments/batch-delete",
|
||||
"auth/department/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -353,28 +353,28 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/departments/batch-status",
|
||||
"auth/department/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/departments/export", params, {
|
||||
return await request.post("auth/department/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/departments/import", formData, {
|
||||
return await request.post("auth/department/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/departments/download-template", {
|
||||
return await request.get("auth/department/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2,46 +2,46 @@ import request from "@/utils/request";
|
||||
|
||||
export default {
|
||||
// 系统配置管理
|
||||
configs: {
|
||||
config: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs", { params });
|
||||
return await request.get("system/setting", { params });
|
||||
},
|
||||
},
|
||||
groups: {
|
||||
get: async function () {
|
||||
return await request.get("system/configs/groups");
|
||||
return await request.get("system/setting/groups");
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs/all", { params });
|
||||
return await request.get("system/setting/all", { params });
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/configs/${id}`);
|
||||
return await request.get(`system/setting/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/configs", params);
|
||||
return await request.post("system/setting", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/configs/${id}`, params);
|
||||
return await request.put(`system/setting/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/configs/${id}`);
|
||||
return await request.delete(`system/setting/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/configs/batch-delete",
|
||||
"system/setting/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -49,7 +49,7 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/configs/batch-status",
|
||||
"system/setting/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -57,35 +57,35 @@ export default {
|
||||
},
|
||||
|
||||
// 操作日志管理
|
||||
logs: {
|
||||
log: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/logs", { params });
|
||||
return await request.get("system/log", { params });
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/logs/${id}`);
|
||||
return await request.get(`system/log/${id}`);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/logs/${id}`);
|
||||
return await request.delete(`system/log/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/logs/batch-delete", params);
|
||||
return await request.post("system/log/batch-delete", params);
|
||||
},
|
||||
},
|
||||
clear: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/logs/clear", params);
|
||||
return await request.post("system/log/clear", params);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/logs/export", {
|
||||
return await request.get("system/log/export", {
|
||||
params,
|
||||
responseType: "blob",
|
||||
});
|
||||
@@ -93,47 +93,47 @@ export default {
|
||||
},
|
||||
statistics: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/logs/statistics", { params });
|
||||
return await request.get("system/log/statistics", { params });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// 数据字典管理
|
||||
dictionaries: {
|
||||
dictionary: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/dictionaries", { params });
|
||||
return await request.get("system/dictionary", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/dictionaries/all");
|
||||
return await request.get("system/dictionary/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/dictionaries/${id}`);
|
||||
return await request.get(`system/dictionary/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/dictionaries", params);
|
||||
return await request.post("system/dictionary", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/dictionaries/${id}`, params);
|
||||
return await request.put(`system/dictionary/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/dictionaries/${id}`);
|
||||
return await request.delete(`system/dictionary/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionaries/batch-delete",
|
||||
"system/dictionary/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -141,7 +141,7 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionaries/batch-status",
|
||||
"system/dictionary/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -149,7 +149,7 @@ export default {
|
||||
items: {
|
||||
all: {
|
||||
get: async function (code) {
|
||||
return await request.get(`system/dictionaries/code`, {
|
||||
return await request.get(`system/dictionary/code`, {
|
||||
params: { code },
|
||||
});
|
||||
},
|
||||
@@ -158,44 +158,44 @@ export default {
|
||||
},
|
||||
|
||||
// 数据字典项管理
|
||||
dictionaryItems: {
|
||||
dictionaryItem: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/dictionary-items", { params });
|
||||
return await request.get("system/dictionary-item", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/dictionary-items/all");
|
||||
return await request.get("system/dictionary-item/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/dictionary-items/${id}`);
|
||||
return await request.get(`system/dictionary-item/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/dictionary-items", params);
|
||||
return await request.post("system/dictionary-item", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(
|
||||
`system/dictionary-items/${id}`,
|
||||
`system/dictionary-item/${id}`,
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/dictionary-items/${id}`);
|
||||
return await request.delete(`system/dictionary-item/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionary-items/batch-delete",
|
||||
"system/dictionary-item/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -203,7 +203,7 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionary-items/batch-status",
|
||||
"system/dictionary-item/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -211,119 +211,119 @@ export default {
|
||||
},
|
||||
|
||||
// 任务管理
|
||||
tasks: {
|
||||
task: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/tasks", { params });
|
||||
return await request.get("system/task", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/tasks/all");
|
||||
return await request.get("system/task/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/tasks/${id}`);
|
||||
return await request.get(`system/task/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/tasks", params);
|
||||
return await request.post("system/task", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/tasks/${id}`, params);
|
||||
return await request.put(`system/task/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/tasks/${id}`);
|
||||
return await request.delete(`system/task/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/tasks/batch-delete", params);
|
||||
return await request.post("system/task/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/tasks/batch-status", params);
|
||||
return await request.post("system/task/batch-status", params);
|
||||
},
|
||||
},
|
||||
run: {
|
||||
post: async function (id) {
|
||||
return await request.post(`system/tasks/${id}/run`);
|
||||
return await request.post(`system/task/${id}/run`);
|
||||
},
|
||||
},
|
||||
statistics: {
|
||||
get: async function () {
|
||||
return await request.get("system/tasks/statistics");
|
||||
return await request.get("system/task/statistics");
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// 城市数据管理
|
||||
cities: {
|
||||
city: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/cities", { params });
|
||||
return await request.get("system/city", { params });
|
||||
},
|
||||
},
|
||||
tree: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/tree");
|
||||
return await request.get("system/city/tree");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/cities/${id}`);
|
||||
return await request.get(`system/city/${id}`);
|
||||
},
|
||||
},
|
||||
children: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/cities/${id}/children`);
|
||||
get: async function (code) {
|
||||
return await request.get(`system/city/code/${code}/children`);
|
||||
},
|
||||
},
|
||||
provinces: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/provinces");
|
||||
return await request.get("system/city/provinces");
|
||||
},
|
||||
},
|
||||
cities: {
|
||||
get: async function (provinceId) {
|
||||
return await request.get(`system/cities/${provinceId}/cities`);
|
||||
return await request.get(`system/city/${provinceId}/cities`);
|
||||
},
|
||||
},
|
||||
districts: {
|
||||
get: async function (cityId) {
|
||||
return await request.get(`system/cities/${cityId}/districts`);
|
||||
return await request.get(`system/city/${cityId}/districts`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/cities", params);
|
||||
return await request.post("system/city", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/cities/${id}`, params);
|
||||
return await request.put(`system/city/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/cities/${id}`);
|
||||
return await request.delete(`system/city/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/cities/batch-delete", params);
|
||||
return await request.post("system/city/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/cities/batch-status", params);
|
||||
return await request.post("system/city/batch-status", params);
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -362,79 +362,79 @@ export default {
|
||||
},
|
||||
|
||||
// 通知管理
|
||||
notifications: {
|
||||
notification: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/notifications", { params });
|
||||
return await request.get("system/notification", { params });
|
||||
},
|
||||
},
|
||||
unread: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/notifications/unread", {
|
||||
return await request.get("system/notification/unread", {
|
||||
params,
|
||||
});
|
||||
},
|
||||
},
|
||||
unreadCount: {
|
||||
get: async function () {
|
||||
return await request.get("system/notifications/unread-count");
|
||||
return await request.get("system/notification/unread-count");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/notifications/${id}`);
|
||||
return await request.get(`system/notification/${id}`);
|
||||
},
|
||||
},
|
||||
markAsRead: {
|
||||
post: async function (id) {
|
||||
return await request.post(`system/notifications/${id}/read`);
|
||||
return await request.post(`system/notification/${id}/read`);
|
||||
},
|
||||
},
|
||||
batchMarkAsRead: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/notifications/batch-read",
|
||||
"system/notification/batch-read",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
markAllAsRead: {
|
||||
post: async function () {
|
||||
return await request.post("system/notifications/read-all");
|
||||
return await request.post("system/notification/read-all");
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/notifications/${id}`);
|
||||
return await request.delete(`system/notification/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/notifications/batch-delete",
|
||||
"system/notification/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
clearRead: {
|
||||
post: async function () {
|
||||
return await request.post("system/notifications/clear-read");
|
||||
return await request.post("system/notification/clear-read");
|
||||
},
|
||||
},
|
||||
statistics: {
|
||||
get: async function () {
|
||||
return await request.get("system/notifications/statistics");
|
||||
return await request.get("system/notification/statistics");
|
||||
},
|
||||
},
|
||||
send: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/notifications/send", params);
|
||||
return await request.post("system/notification/send", params);
|
||||
},
|
||||
},
|
||||
retryUnsent: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/notifications/retry-unsent",
|
||||
"system/notification/retry-unsent",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -443,72 +443,72 @@ export default {
|
||||
|
||||
// 公共接口 (无需认证)
|
||||
public: {
|
||||
configs: {
|
||||
config: {
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/configs");
|
||||
return await request.get("system/config");
|
||||
},
|
||||
},
|
||||
group: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs/group", {
|
||||
return await request.get("system/config/group", {
|
||||
params,
|
||||
});
|
||||
},
|
||||
},
|
||||
key: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs/key", { params });
|
||||
return await request.get("system/config/key", { params });
|
||||
},
|
||||
},
|
||||
},
|
||||
dictionaries: {
|
||||
dictionary: {
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/dictionaries");
|
||||
return await request.get("system/dictionary");
|
||||
},
|
||||
},
|
||||
code: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/dictionaries/code", {
|
||||
return await request.get("system/dictionary/code", {
|
||||
params,
|
||||
});
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/dictionaries/${id}`);
|
||||
return await request.get(`system/dictionary/${id}`);
|
||||
},
|
||||
},
|
||||
},
|
||||
cities: {
|
||||
city: {
|
||||
tree: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/tree");
|
||||
return await request.get("system/city/tree");
|
||||
},
|
||||
},
|
||||
provinces: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/provinces");
|
||||
return await request.get("system/city/provinces");
|
||||
},
|
||||
},
|
||||
cities: {
|
||||
get: async function (provinceId) {
|
||||
return await request.get(
|
||||
`system/cities/${provinceId}/cities`,
|
||||
`system/city/${provinceId}/cities`,
|
||||
);
|
||||
},
|
||||
},
|
||||
districts: {
|
||||
get: async function (cityId) {
|
||||
return await request.get(
|
||||
`system/cities/${cityId}/districts`,
|
||||
`system/city/${cityId}/districts`,
|
||||
);
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/cities/${id}`);
|
||||
return await request.get(`system/city/${id}`);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:open="visible"
|
||||
:title="title"
|
||||
:width="500"
|
||||
:confirm-loading="loading"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
>
|
||||
<a-form-item label="城市名称" name="title">
|
||||
<a-input
|
||||
v-model:value="formData.title"
|
||||
placeholder="请输入城市名称"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="城市编码" name="code">
|
||||
<a-input
|
||||
v-model:value="formData.code"
|
||||
placeholder="请输入城市编码"
|
||||
allow-clear
|
||||
:disabled="mode === 'edit'"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-if="mode === 'add'"
|
||||
label="父级城市"
|
||||
name="parent_code"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="formData.parent_code"
|
||||
placeholder="请选择父级城市"
|
||||
allow-clear
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select-option :value="null"
|
||||
>无(顶级城市)</a-select-option
|
||||
>
|
||||
<a-select-option
|
||||
v-for="city in flatCities"
|
||||
:key="city.code"
|
||||
:value="city.code"
|
||||
>
|
||||
{{ city.title }} ({{ city.code }})
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-if="mode === 'addChild'"
|
||||
label="父级城市"
|
||||
name="parent_code"
|
||||
>
|
||||
<a-input v-model:value="parentCityTitle" disabled />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import api from "@/api/system";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
cityData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: "add",
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "success"]);
|
||||
|
||||
const formRef = ref(null);
|
||||
const loading = ref(false);
|
||||
const flatCities = ref([]);
|
||||
const parentCityTitle = ref("");
|
||||
|
||||
const formData = reactive({
|
||||
title: "",
|
||||
code: "",
|
||||
parent_code: null,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
title: [
|
||||
{ required: true, message: "请输入城市名称", trigger: "blur" },
|
||||
{ max: 100, message: "城市名称不能超过100个字符", trigger: "blur" },
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: "请输入城市编码", trigger: "blur" },
|
||||
{ max: 50, message: "城市编码不能超过50个字符", trigger: "blur" },
|
||||
{
|
||||
pattern: /^[A-Za-z0-9_-]+$/,
|
||||
message: "城市编码只能包含字母、数字、下划线和横线",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const title = computed(() => {
|
||||
const titles = {
|
||||
add: "新增城市",
|
||||
addChild: "新增子城市",
|
||||
edit: "编辑城市",
|
||||
};
|
||||
return titles[props.mode] || "城市";
|
||||
});
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.visible,
|
||||
set: (val) => emit("update:visible", val),
|
||||
});
|
||||
|
||||
// 加载所有城市(用于父级选择)
|
||||
const loadAllCities = async () => {
|
||||
try {
|
||||
const res = await api.cities.list.get({ page_size: 1000 });
|
||||
if (res.code === 200) {
|
||||
flatCities.value = res.data.list || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载城市列表失败", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索过滤
|
||||
const filterOption = (input, option) => {
|
||||
return option.children[0].children
|
||||
.toLowerCase()
|
||||
.includes(input.toLowerCase());
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
formData.title = "";
|
||||
formData.code = "";
|
||||
formData.parent_code = null;
|
||||
parentCityTitle.value = "";
|
||||
formRef.value?.clearValidate();
|
||||
};
|
||||
|
||||
// 监听 cityData 变化
|
||||
watch(
|
||||
() => props.cityData,
|
||||
(val) => {
|
||||
if (val && props.visible) {
|
||||
formData.title = val.title || "";
|
||||
formData.code = val.code || "";
|
||||
formData.parent_code = val.parent_code || null;
|
||||
|
||||
if (props.mode === "addChild" && val.parent_code) {
|
||||
// 查找父级城市名称
|
||||
const parentCity = flatCities.value.find(
|
||||
(city) => city.code === val.parent_code,
|
||||
);
|
||||
parentCityTitle.value = parentCity
|
||||
? `${parentCity.title} (${parentCity.code})`
|
||||
: val.parent_code;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
// 监听弹窗打开
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (val) {
|
||||
loadAllCities();
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// 确定
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
loading.value = true;
|
||||
|
||||
const data = {
|
||||
title: formData.title,
|
||||
code: formData.code,
|
||||
};
|
||||
|
||||
if (props.mode === "add" && formData.parent_code) {
|
||||
data.parent_code = formData.parent_code;
|
||||
}
|
||||
|
||||
let res;
|
||||
if (props.mode === "add" || props.mode === "addChild") {
|
||||
res = await api.cities.add.post(data);
|
||||
} else if (props.mode === "edit") {
|
||||
res = await api.cities.edit.put(props.cityData.id, data);
|
||||
}
|
||||
|
||||
if (res.code === 200) {
|
||||
message.success(props.mode === "edit" ? "更新成功" : "创建成功");
|
||||
emit("success");
|
||||
handleCancel();
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.errorFields) {
|
||||
// 表单验证错误,不提示
|
||||
} else {
|
||||
message.error(error.message || "操作失败");
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
resetForm();
|
||||
emit("update:visible", false);
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<div class="pages-base-layout city-page">
|
||||
<div class="tool-bar">
|
||||
<div class="left-panel">
|
||||
<a-space>
|
||||
<a-input
|
||||
v-model:value="searchForm.keyword"
|
||||
placeholder="城市名称/编码"
|
||||
allow-clear
|
||||
style="width: 180px"
|
||||
/>
|
||||
<a-button type="primary" @click="handleSearch">
|
||||
<template #icon><search-outlined /></template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="handleReset">
|
||||
<template #icon><redo-outlined /></template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<a-button type="primary" @click="handleAdd">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<a-dropdown>
|
||||
<a-button>
|
||||
更多
|
||||
<down-outlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item @click="handleRefresh">
|
||||
<reload-outlined />
|
||||
刷新
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="handleExpandAll">
|
||||
<expand-outlined />
|
||||
展开全部
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="handleCollapseAll">
|
||||
<compress-outlined />
|
||||
折叠全部
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-content">
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:row-key="rowKey"
|
||||
:expand-row-by-click="true"
|
||||
:default-expand-all-rows="false"
|
||||
:expand-icon-column-index="1"
|
||||
:indent-size="20"
|
||||
@expand="handleExpand"
|
||||
>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<a-table
|
||||
:columns="childColumns"
|
||||
:data-source="record.children"
|
||||
:pagination="false"
|
||||
:row-key="rowKey"
|
||||
size="small"
|
||||
:show-header="false"
|
||||
>
|
||||
<template #bodyCell="{ column, record: child }">
|
||||
<template v-if="column.key === 'title'">
|
||||
<a-tag color="blue">{{ child.title }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'code'">
|
||||
{{ child.code }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleAddChild(child)"
|
||||
>
|
||||
新增子级
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(child)"
|
||||
>
|
||||
编辑
|
||||
</a-button>
|
||||
<a-popconfirm
|
||||
title="确定要删除该城市吗?"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@confirm="handleDelete(child.id)"
|
||||
>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
>删除</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'title'">
|
||||
<a-tag color="green">{{ record.title }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'code'">
|
||||
{{ record.code }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'parent_code'">
|
||||
<a-tag v-if="record.parent_code" color="purple">{{
|
||||
record.parent_code
|
||||
}}</a-tag>
|
||||
<span v-else class="text-gray-400">-</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'has_children'">
|
||||
<a-tag v-if="hasChildren(record)" color="orange"
|
||||
>有</a-tag
|
||||
>
|
||||
<span v-else class="text-gray-400">无</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleAddChild(record)"
|
||||
>
|
||||
新增子级
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>
|
||||
编辑
|
||||
</a-button>
|
||||
<a-popconfirm
|
||||
title="确定要删除该城市吗?"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@confirm="handleDelete(record.id)"
|
||||
>
|
||||
<a-button type="link" size="small" danger
|
||||
>删除</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<SaveDialog
|
||||
v-model:visible="saveDialogVisible"
|
||||
:city-data="currentCity"
|
||||
:mode="saveMode"
|
||||
@success="handleSaveSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import api from "@/api/system";
|
||||
import SaveDialog from "./components/SaveDialog.vue";
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
keyword: "",
|
||||
});
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
const loading = ref(false);
|
||||
const expandedKeys = ref([]);
|
||||
|
||||
// 新增/编辑弹窗
|
||||
const saveDialogVisible = ref(false);
|
||||
const saveMode = ref("add");
|
||||
const currentCity = ref(null);
|
||||
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: "城市名称",
|
||||
key: "title",
|
||||
width: 250,
|
||||
},
|
||||
{
|
||||
title: "城市编码",
|
||||
key: "code",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "父级编码",
|
||||
key: "parent_code",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "子级数量",
|
||||
key: "has_children",
|
||||
width: 120,
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 200,
|
||||
fixed: "right",
|
||||
},
|
||||
];
|
||||
|
||||
// 子表格列配置
|
||||
const childColumns = [
|
||||
{
|
||||
title: "城市名称",
|
||||
key: "title",
|
||||
width: 250,
|
||||
},
|
||||
{
|
||||
title: "城市编码",
|
||||
key: "code",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 250,
|
||||
},
|
||||
];
|
||||
|
||||
const rowKey = (record) => record.id;
|
||||
|
||||
// 判断是否有子级
|
||||
const hasChildren = (record) => {
|
||||
return record.children && record.children.length > 0;
|
||||
};
|
||||
|
||||
// 加载城市树形数据
|
||||
const loadCityTree = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await api.cities.tree.get();
|
||||
if (res.code === 200) {
|
||||
tableData.value = res.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
message.error("加载城市数据失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchForm.keyword = "";
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
// 刷新
|
||||
const handleRefresh = () => {
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
// 展开全部
|
||||
const handleExpandAll = () => {
|
||||
const allKeys = [];
|
||||
const collectKeys = (list) => {
|
||||
list.forEach((item) => {
|
||||
if (item.children && item.children.length > 0) {
|
||||
allKeys.push(item.id);
|
||||
collectKeys(item.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
collectKeys(tableData.value);
|
||||
expandedKeys.value = allKeys;
|
||||
};
|
||||
|
||||
// 折叠全部
|
||||
const handleCollapseAll = () => {
|
||||
expandedKeys.value = [];
|
||||
};
|
||||
|
||||
// 展开/折叠事件
|
||||
const handleExpand = (expanded, record) => {
|
||||
if (expanded) {
|
||||
if (!expandedKeys.value.includes(record.id)) {
|
||||
expandedKeys.value.push(record.id);
|
||||
}
|
||||
} else {
|
||||
expandedKeys.value = expandedKeys.value.filter(
|
||||
(key) => key !== record.id,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// 新增
|
||||
const handleAdd = () => {
|
||||
saveMode.value = "add";
|
||||
currentCity.value = {
|
||||
title: "",
|
||||
code: "",
|
||||
parent_code: null,
|
||||
};
|
||||
saveDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 新增子级
|
||||
const handleAddChild = (record) => {
|
||||
saveMode.value = "addChild";
|
||||
currentCity.value = {
|
||||
title: "",
|
||||
code: "",
|
||||
parent_code: record.code,
|
||||
};
|
||||
saveDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (record) => {
|
||||
saveMode.value = "edit";
|
||||
currentCity.value = {
|
||||
id: record.id,
|
||||
title: record.title,
|
||||
code: record.code,
|
||||
parent_code: record.parent_code,
|
||||
};
|
||||
saveDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = async (id) => {
|
||||
try {
|
||||
const res = await api.cities.delete.delete(id);
|
||||
if (res.code === 200) {
|
||||
message.success("删除成功");
|
||||
loadCityTree();
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(error.message || "删除失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 保存成功
|
||||
const handleSaveSuccess = () => {
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadCityTree();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.city-page {
|
||||
@extend .pages-base-layout;
|
||||
|
||||
.text-gray-400 {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:open="visible"
|
||||
title="日志详情"
|
||||
width="800px"
|
||||
:footer="null"
|
||||
>
|
||||
<a-descriptions v-if="logData" bordered :column="2" size="small">
|
||||
<a-descriptions-item label="日志ID" :span="1">
|
||||
{{ logData.id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="用户名" :span="1">
|
||||
{{ logData.username || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="模块" :span="1">
|
||||
{{ logData.module || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="操作" :span="1">
|
||||
{{ logData.action || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="请求方式" :span="1">
|
||||
<a-tag :color="getMethodColor(logData.method)">
|
||||
{{ logData.method }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="URL" :span="1">
|
||||
{{ logData.url || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="IP地址" :span="1">
|
||||
{{ logData.ip || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态码" :span="1">
|
||||
{{ logData.status_code || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态" :span="1">
|
||||
<a-tag
|
||||
:color="logData.status === 'success' ? 'success' : 'error'"
|
||||
>
|
||||
{{ logData.status === "success" ? "成功" : "失败" }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="执行时间" :span="1">
|
||||
<span
|
||||
:style="{
|
||||
color: getExecutionTimeColor(logData.execution_time),
|
||||
}"
|
||||
>
|
||||
{{ logData.execution_time }}ms
|
||||
</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间" :span="2">
|
||||
{{ logData.created_at || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="User Agent" :span="2">
|
||||
<div style="max-height: 60px; overflow-y: auto">
|
||||
{{ logData.user_agent || "-" }}
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="logData.error_message"
|
||||
label="错误信息"
|
||||
:span="2"
|
||||
>
|
||||
<a-alert
|
||||
:message="logData.error_message"
|
||||
type="error"
|
||||
show-icon
|
||||
/>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="logData.params && Object.keys(logData.params).length > 0"
|
||||
label="请求参数"
|
||||
:span="2"
|
||||
>
|
||||
<a-collapse>
|
||||
<a-collapse-panel key="params" header="查看请求参数">
|
||||
<pre
|
||||
style="
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
"
|
||||
>{{ formatJson(logData.params) }}</pre
|
||||
>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="logData.result"
|
||||
label="返回结果"
|
||||
:span="2"
|
||||
>
|
||||
<a-collapse>
|
||||
<a-collapse-panel key="result" header="查看返回结果">
|
||||
<pre
|
||||
style="
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
"
|
||||
>{{ formatJson(logData.result) }}</pre
|
||||
>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<template #footer>
|
||||
<a-button @click="handleClose">关闭</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import systemApi from "@/api/system";
|
||||
|
||||
defineOptions({
|
||||
name: "LogDetailDialog",
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
const logData = ref(null);
|
||||
|
||||
// 获取请求方式颜色
|
||||
const getMethodColor = (method) => {
|
||||
const colors = {
|
||||
GET: "blue",
|
||||
POST: "green",
|
||||
PUT: "orange",
|
||||
DELETE: "red",
|
||||
PATCH: "purple",
|
||||
};
|
||||
return colors[method] || "default";
|
||||
};
|
||||
|
||||
// 获取执行时间颜色
|
||||
const getExecutionTimeColor = (time) => {
|
||||
if (time > 1000) return "#ff4d4f";
|
||||
if (time > 500) return "#faad14";
|
||||
return "#52c41a";
|
||||
};
|
||||
|
||||
// 格式化JSON
|
||||
const formatJson = (data) => {
|
||||
if (typeof data === "string") {
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(data), null, 2);
|
||||
} catch (e) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(data, null, 2);
|
||||
};
|
||||
|
||||
// 打开弹窗
|
||||
const open = async () => {
|
||||
visible.value = true;
|
||||
return {
|
||||
setData,
|
||||
};
|
||||
};
|
||||
|
||||
// 设置数据
|
||||
const setData = async (data) => {
|
||||
if (data && data.id) {
|
||||
// 如果传入了完整数据,直接使用
|
||||
if (data.params || data.result) {
|
||||
logData.value = data;
|
||||
} else {
|
||||
// 否则从服务器获取完整数据
|
||||
try {
|
||||
const res = await systemApi.logs.detail.get(data.id);
|
||||
if (res.code === 200) {
|
||||
logData.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取日志详情失败:", error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logData.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const handleClose = () => {
|
||||
visible.value = false;
|
||||
logData.value = null;
|
||||
};
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.ant-descriptions-item-label) {
|
||||
width: 120px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,604 @@
|
||||
<template>
|
||||
<div class="pages-sidebar-layout log-page">
|
||||
<div class="left-box">
|
||||
<div class="header">日志筛选</div>
|
||||
<div class="body">
|
||||
<a-tree
|
||||
v-model:selectedKeys="selectedTreeKeys"
|
||||
:tree-data="filterTreeData"
|
||||
show-line
|
||||
:field-names="{
|
||||
title: 'title',
|
||||
key: 'key',
|
||||
children: 'children',
|
||||
}"
|
||||
@select="onTreeSelect"
|
||||
>
|
||||
<template #icon="{ dataRef }">
|
||||
<ApiOutlined v-if="dataRef.type === 'method'" />
|
||||
<CheckCircleOutlined
|
||||
v-else-if="
|
||||
dataRef.type === 'status' &&
|
||||
dataRef.key === 'success'
|
||||
"
|
||||
/>
|
||||
<CloseCircleOutlined
|
||||
v-else-if="
|
||||
dataRef.type === 'status' &&
|
||||
dataRef.key === 'error'
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-box">
|
||||
<!-- 统计卡片 -->
|
||||
<div class="statistics-cards">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="总日志数"
|
||||
:value="statistics.total || 0"
|
||||
>
|
||||
<template #prefix>
|
||||
<FileTextOutlined style="color: #1890ff" />
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="成功数"
|
||||
:value="statistics.success || 0"
|
||||
>
|
||||
<template #prefix>
|
||||
<CheckCircleOutlined
|
||||
style="color: #52c41a"
|
||||
/>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="失败数"
|
||||
:value="statistics.error || 0"
|
||||
>
|
||||
<template #prefix>
|
||||
<CloseCircleOutlined
|
||||
style="color: #ff4d4f"
|
||||
/>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="平均响应时间"
|
||||
:value="statistics.avg_time || 0"
|
||||
suffix="ms"
|
||||
>
|
||||
<template #prefix>
|
||||
<ClockCircleOutlined
|
||||
style="color: #faad14"
|
||||
/>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="tool-bar">
|
||||
<div class="left-panel">
|
||||
<a-space>
|
||||
<a-range-picker
|
||||
v-model:value="dateRange"
|
||||
:placeholder="['开始时间', '结束时间']"
|
||||
style="width: 260px"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
<a-button type="primary" @click="handleSearch">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="handleLogReset">
|
||||
<template #icon><RedoOutlined /></template>
|
||||
清除
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<a-space>
|
||||
<a-button
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
>
|
||||
<template #icon><DownloadOutlined /></template>
|
||||
导出
|
||||
</a-button>
|
||||
<a-dropdown>
|
||||
<a-button>
|
||||
更多
|
||||
<DownOutlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item @click="handleClearLogs">
|
||||
<DeleteOutlined />清理日志
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="handleRefreshStats">
|
||||
<ReloadOutlined />刷新统计
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-content">
|
||||
<sc-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:row-key="rowKey"
|
||||
@refresh="refreshTable"
|
||||
@paginationChange="handlePaginationChange"
|
||||
>
|
||||
<template #status="{ record }">
|
||||
<a-tag
|
||||
:color="
|
||||
record.status === 'success'
|
||||
? 'success'
|
||||
: 'error'
|
||||
"
|
||||
>
|
||||
{{ record.status === "success" ? "成功" : "失败" }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template #method="{ record }">
|
||||
<a-tag :color="getMethodColor(record.method)">
|
||||
{{ record.method }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template #execution_time="{ record }">
|
||||
<span
|
||||
:style="{
|
||||
color:
|
||||
record.execution_time > 1000
|
||||
? '#ff4d4f'
|
||||
: record.execution_time > 500
|
||||
? '#faad14'
|
||||
: '#52c41a',
|
||||
}"
|
||||
>
|
||||
{{ record.execution_time }}ms
|
||||
</span>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<a-space>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleView(record)"
|
||||
>查看详情</a-button
|
||||
>
|
||||
<a-popconfirm
|
||||
title="确定删除该日志吗?"
|
||||
@confirm="handleDelete(record)"
|
||||
>
|
||||
<a-button type="link" size="small" danger
|
||||
>删除</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</sc-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 日志详情弹窗 -->
|
||||
<detail-dialog ref="detailDialogRef" />
|
||||
|
||||
<!-- 清理日志确认弹窗 -->
|
||||
<a-modal
|
||||
v-model:open="dialog.clear"
|
||||
title="清理日志"
|
||||
:confirm-loading="clearLoading"
|
||||
@ok="handleConfirmClear"
|
||||
>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="清理天数">
|
||||
<a-input-number
|
||||
v-model:value="clearDays"
|
||||
:min="1"
|
||||
:max="365"
|
||||
style="width: 100%"
|
||||
placeholder="请输入天数"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-alert
|
||||
message="删除指定天数之前的日志记录,此操作不可恢复"
|
||||
type="warning"
|
||||
show-icon
|
||||
/>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import {
|
||||
SearchOutlined,
|
||||
RedoOutlined,
|
||||
DeleteOutlined,
|
||||
DownOutlined,
|
||||
ApiOutlined,
|
||||
CheckCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
FileTextOutlined,
|
||||
ClockCircleOutlined,
|
||||
DownloadOutlined,
|
||||
ReloadOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import scTable from "@/components/scTable/index.vue";
|
||||
import detailDialog from "./components/DetailDialog.vue";
|
||||
import systemApi from "@/api/system";
|
||||
import { useTable } from "@/hooks/useTable";
|
||||
|
||||
defineOptions({
|
||||
name: "systemLog",
|
||||
});
|
||||
|
||||
// 统计数据
|
||||
const statistics = ref({
|
||||
total: 0,
|
||||
success: 0,
|
||||
error: 0,
|
||||
avg_time: 0,
|
||||
});
|
||||
|
||||
// 使用useTable hooks
|
||||
const {
|
||||
tableRef,
|
||||
searchForm,
|
||||
tableData,
|
||||
loading,
|
||||
pagination,
|
||||
handleSearch,
|
||||
handlePaginationChange,
|
||||
refreshTable,
|
||||
} = useTable({
|
||||
api: systemApi.logs.list.get,
|
||||
searchForm: {
|
||||
method: "",
|
||||
status: "",
|
||||
start_date: "",
|
||||
end_date: "",
|
||||
},
|
||||
columns: [],
|
||||
needPagination: true,
|
||||
});
|
||||
|
||||
// 对话框状态
|
||||
const dialog = reactive({
|
||||
detail: false,
|
||||
clear: false,
|
||||
});
|
||||
|
||||
// 弹窗引用
|
||||
const detailDialogRef = ref(null);
|
||||
|
||||
// 清理日志相关
|
||||
const clearDays = ref(30);
|
||||
const clearLoading = ref(false);
|
||||
|
||||
// 导出相关
|
||||
const exportLoading = ref(false);
|
||||
|
||||
// 日期范围
|
||||
const dateRange = ref([]);
|
||||
|
||||
// 树形筛选数据
|
||||
const treeData = ref([
|
||||
{
|
||||
title: "请求方式",
|
||||
key: "method-root",
|
||||
type: "root",
|
||||
children: [
|
||||
{ title: "GET", key: "GET", type: "method" },
|
||||
{ title: "POST", key: "POST", type: "method" },
|
||||
{ title: "PUT", key: "PUT", type: "method" },
|
||||
{ title: "DELETE", key: "DELETE", type: "method" },
|
||||
{ title: "PATCH", key: "PATCH", type: "method" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "返回状态",
|
||||
key: "status-root",
|
||||
type: "root",
|
||||
children: [
|
||||
{ title: "成功", key: "success", type: "status" },
|
||||
{ title: "失败", key: "error", type: "status" },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
// 选中的树节点
|
||||
const selectedTreeKeys = ref([]);
|
||||
|
||||
// 行key
|
||||
const rowKey = "id";
|
||||
|
||||
// 过滤后的树数据
|
||||
const filterTreeData = computed(() => {
|
||||
return treeData.value;
|
||||
});
|
||||
|
||||
// 获取请求方式颜色
|
||||
const getMethodColor = (method) => {
|
||||
const colors = {
|
||||
GET: "blue",
|
||||
POST: "green",
|
||||
PUT: "orange",
|
||||
DELETE: "red",
|
||||
PATCH: "purple",
|
||||
};
|
||||
return colors[method] || "default";
|
||||
};
|
||||
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{ title: "ID", dataIndex: "id", key: "id", width: 80 },
|
||||
{ title: "用户名", dataIndex: "username", key: "username", width: 120 },
|
||||
{ title: "模块", dataIndex: "module", key: "module", width: 120 },
|
||||
{ title: "操作", dataIndex: "action", key: "action", width: 150 },
|
||||
{
|
||||
title: "请求方式",
|
||||
dataIndex: "method",
|
||||
key: "method",
|
||||
width: 100,
|
||||
align: "center",
|
||||
slot: "method",
|
||||
},
|
||||
{ title: "URL", dataIndex: "url", key: "url", ellipsis: true },
|
||||
{ title: "IP地址", dataIndex: "ip", key: "ip", width: 140 },
|
||||
{
|
||||
title: "状态码",
|
||||
dataIndex: "status_code",
|
||||
key: "status_code",
|
||||
width: 100,
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
width: 100,
|
||||
align: "center",
|
||||
slot: "status",
|
||||
},
|
||||
{
|
||||
title: "执行时间",
|
||||
dataIndex: "execution_time",
|
||||
key: "execution_time",
|
||||
width: 120,
|
||||
align: "center",
|
||||
slot: "execution_time",
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "created_at",
|
||||
key: "created_at",
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "table_action",
|
||||
key: "table_action",
|
||||
width: 150,
|
||||
align: "center",
|
||||
slot: "action",
|
||||
fixed: "right",
|
||||
},
|
||||
];
|
||||
|
||||
// 加载统计数据
|
||||
const loadStatistics = async () => {
|
||||
try {
|
||||
const res = await systemApi.logs.statistics.get(searchForm);
|
||||
if (res.code === 200) {
|
||||
statistics.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载统计数据失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 树形选择事件
|
||||
const onTreeSelect = (selectedKeys, { selectedNodes }) => {
|
||||
if (selectedKeys.length > 0) {
|
||||
const key = selectedKeys[0];
|
||||
const node = selectedNodes[0];
|
||||
|
||||
// 重置搜索表单
|
||||
searchForm.method = "";
|
||||
searchForm.status = "";
|
||||
|
||||
// 根据节点类型设置对应的筛选条件
|
||||
if (node.type === "method") {
|
||||
searchForm.method = key;
|
||||
} else if (node.type === "status") {
|
||||
searchForm.status = key;
|
||||
}
|
||||
|
||||
// 触发搜索
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
} else {
|
||||
// 取消选择时清空筛选条件
|
||||
searchForm.method = "";
|
||||
searchForm.status = "";
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
}
|
||||
};
|
||||
|
||||
// 日期变化
|
||||
const handleDateChange = (dates) => {
|
||||
if (dates && dates.length === 2) {
|
||||
searchForm.start_date = dates[0].format("YYYY-MM-DD HH:mm:ss");
|
||||
searchForm.end_date = dates[1].format("YYYY-MM-DD HH:mm:ss");
|
||||
} else {
|
||||
searchForm.start_date = "";
|
||||
searchForm.end_date = "";
|
||||
}
|
||||
// 自动触发搜索
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleLogReset = () => {
|
||||
// 重置日期范围
|
||||
dateRange.value = [];
|
||||
searchForm.start_date = "";
|
||||
searchForm.end_date = "";
|
||||
|
||||
// 重置树形选择
|
||||
selectedTreeKeys.value = [];
|
||||
searchForm.method = "";
|
||||
searchForm.status = "";
|
||||
|
||||
// 重置分页到第一页
|
||||
pagination.current = 1;
|
||||
|
||||
// 触发搜索
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleView = async (record) => {
|
||||
const dialog = await detailDialogRef.value?.open();
|
||||
dialog?.setData(record);
|
||||
};
|
||||
|
||||
// 删除日志
|
||||
const handleDelete = async (record) => {
|
||||
try {
|
||||
const res = await systemApi.logs.delete.delete(record.id);
|
||||
if (res.code === 200) {
|
||||
message.success("删除成功");
|
||||
refreshTable();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
} else {
|
||||
message.error(res.message || "删除失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("删除日志失败:", error);
|
||||
message.error("删除失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 清理日志
|
||||
const handleClearLogs = () => {
|
||||
dialog.clear = true;
|
||||
};
|
||||
|
||||
// 确认清理日志
|
||||
const handleConfirmClear = async () => {
|
||||
if (!clearDays.value || clearDays.value < 1) {
|
||||
message.warning("请输入有效的天数");
|
||||
return;
|
||||
}
|
||||
|
||||
clearLoading.value = true;
|
||||
try {
|
||||
const res = await systemApi.logs.clear.post({ days: clearDays.value });
|
||||
if (res.code === 200) {
|
||||
message.success("清理成功");
|
||||
dialog.clear = false;
|
||||
clearDays.value = 30;
|
||||
refreshTable();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
} else {
|
||||
message.error(res.message || "清理失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("清理日志失败:", error);
|
||||
message.error("清理失败");
|
||||
} finally {
|
||||
clearLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 刷新统计
|
||||
const handleRefreshStats = () => {
|
||||
loadStatistics();
|
||||
};
|
||||
|
||||
// 导出日志
|
||||
const handleExport = async () => {
|
||||
exportLoading.value = true;
|
||||
try {
|
||||
const blob = await systemApi.logs.export.get(searchForm);
|
||||
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = `系统日志_${new Date().getTime()}.xlsx`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
message.success("导出成功");
|
||||
} catch (error) {
|
||||
console.error("导出失败:", error);
|
||||
message.error("导出失败");
|
||||
} finally {
|
||||
exportLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
// 页面加载时自动搜索一次
|
||||
handleSearch();
|
||||
// 加载统计数据
|
||||
loadStatistics();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.log-page {
|
||||
.statistics-cards {
|
||||
margin-bottom: 16px;
|
||||
background: #fff;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.stat-card {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+13
-13
@@ -16,7 +16,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
Route::post('/change-password', [\App\Http\Controllers\Auth\Admin\Auth::class, 'changePassword']);
|
||||
|
||||
// 用户管理
|
||||
Route::prefix('users')->group(function () {
|
||||
Route::prefix('user')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Auth\Admin\User::class, 'index']);
|
||||
Route::get('/{id}', [\App\Http\Controllers\Auth\Admin\User::class, 'show']);
|
||||
Route::post('/', [\App\Http\Controllers\Auth\Admin\User::class, 'store']);
|
||||
@@ -32,7 +32,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 角色管理
|
||||
Route::prefix('roles')->group(function () {
|
||||
Route::prefix('role')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Auth\Admin\Role::class, 'index']);
|
||||
Route::get('/all', [\App\Http\Controllers\Auth\Admin\Role::class, 'getAll']);
|
||||
Route::get('/{id}', [\App\Http\Controllers\Auth\Admin\Role::class, 'show']);
|
||||
@@ -48,7 +48,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 权限管理
|
||||
Route::prefix('permissions')->group(function () {
|
||||
Route::prefix('permission')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Auth\Admin\Permission::class, 'index']);
|
||||
Route::get('/tree', [\App\Http\Controllers\Auth\Admin\Permission::class, 'tree']);
|
||||
Route::get('/menu', [\App\Http\Controllers\Auth\Admin\Permission::class, 'menu']);
|
||||
@@ -61,7 +61,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 部门管理
|
||||
Route::prefix('departments')->group(function () {
|
||||
Route::prefix('department')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Auth\Admin\Department::class, 'index']);
|
||||
Route::get('/tree', [\App\Http\Controllers\Auth\Admin\Department::class, 'tree']);
|
||||
Route::get('/all', [\App\Http\Controllers\Auth\Admin\Department::class, 'getAll']);
|
||||
@@ -77,7 +77,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 在线用户管理
|
||||
Route::prefix('online-users')->group(function () {
|
||||
Route::prefix('online-user')->group(function () {
|
||||
Route::get('/count', [\App\Http\Controllers\Auth\Admin\User::class, 'getOnlineCount']);
|
||||
Route::get('/', [\App\Http\Controllers\Auth\Admin\User::class, 'getOnlineUsers']);
|
||||
Route::get('/{userId}/sessions', [\App\Http\Controllers\Auth\Admin\User::class, 'getUserSessions']);
|
||||
@@ -89,7 +89,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
// 系统管理模块
|
||||
Route::prefix('system')->group(function () {
|
||||
// 系统配置管理
|
||||
Route::prefix('configs')->group(function () {
|
||||
Route::prefix('setting')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\System\Admin\Config::class, 'index']);
|
||||
Route::get('/all', [\App\Http\Controllers\System\Admin\Config::class, 'getByGroup']);
|
||||
Route::get('/groups', [\App\Http\Controllers\System\Admin\Config::class, 'getGroups']);
|
||||
@@ -102,7 +102,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 系统操作日志
|
||||
Route::prefix('logs')->group(function () {
|
||||
Route::prefix('log')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\System\Admin\Log::class, 'index']);
|
||||
Route::get('/export', [\App\Http\Controllers\System\Admin\Log::class, 'export']);
|
||||
Route::get('/statistics', [\App\Http\Controllers\System\Admin\Log::class, 'getStatistics']);
|
||||
@@ -113,7 +113,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 数据字典管理
|
||||
Route::prefix('dictionaries')->group(function () {
|
||||
Route::prefix('dictionary')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\System\Admin\Dictionary::class, 'index']);
|
||||
Route::get('/all', [\App\Http\Controllers\System\Admin\Dictionary::class, 'all']);
|
||||
Route::get('/{id}', [\App\Http\Controllers\System\Admin\Dictionary::class, 'show']);
|
||||
@@ -125,7 +125,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 数据字典项管理
|
||||
Route::prefix('dictionary-items')->group(function () {
|
||||
Route::prefix('dictionary-item')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\System\Admin\Dictionary::class, 'getItemsList']);
|
||||
Route::get('/all', [\App\Http\Controllers\System\Admin\Dictionary::class, 'getAllItems']);
|
||||
Route::post('/', [\App\Http\Controllers\System\Admin\Dictionary::class, 'storeItem']);
|
||||
@@ -136,7 +136,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 任务管理
|
||||
Route::prefix('tasks')->group(function () {
|
||||
Route::prefix('task')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\System\Admin\Task::class, 'index']);
|
||||
Route::get('/all', [\App\Http\Controllers\System\Admin\Task::class, 'all']);
|
||||
Route::get('/statistics', [\App\Http\Controllers\System\Admin\Task::class, 'getStatistics']);
|
||||
@@ -150,11 +150,11 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 城市数据管理
|
||||
Route::prefix('cities')->group(function () {
|
||||
Route::prefix('city')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\System\Admin\City::class, 'index']);
|
||||
Route::get('/tree', [\App\Http\Controllers\System\Admin\City::class, 'tree']);
|
||||
Route::get('/{id}', [\App\Http\Controllers\System\Admin\City::class, 'show']);
|
||||
Route::get('/{id}/children', [\App\Http\Controllers\System\Admin\City::class, 'children']);
|
||||
Route::get('/code/{code}/children', [\App\Http\Controllers\System\Admin\City::class, 'children']);
|
||||
Route::get('/provinces', [\App\Http\Controllers\System\Admin\City::class, 'provinces']);
|
||||
Route::get('/{provinceId}/cities', [\App\Http\Controllers\System\Admin\City::class, 'cities']);
|
||||
Route::get('/{cityId}/districts', [\App\Http\Controllers\System\Admin\City::class, 'districts']);
|
||||
@@ -175,7 +175,7 @@ Route::middleware(['auth.check:admin', 'log.request'])->group(function () {
|
||||
});
|
||||
|
||||
// 通知管理
|
||||
Route::prefix('notifications')->group(function () {
|
||||
Route::prefix('notification')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\System\Admin\Notification::class, 'index']);
|
||||
Route::get('/unread', [\App\Http\Controllers\System\Admin\Notification::class, 'unread']);
|
||||
Route::get('/unread-count', [\App\Http\Controllers\System\Admin\Notification::class, 'unreadCount']);
|
||||
|
||||
+11
-11
@@ -6,21 +6,21 @@ use App\Http\Controllers\System\Api\Dictionary;
|
||||
// 公开路由(不需要认证)
|
||||
Route::prefix('system')->group(function () {
|
||||
// 获取所有系统配置
|
||||
Route::get('/configs', [\App\Http\Controllers\System\Api\Config::class, 'all']);
|
||||
Route::get('/configs/group', [\App\Http\Controllers\System\Api\Config::class, 'getByGroup']);
|
||||
Route::get('/configs/key', [\App\Http\Controllers\System\Api\Config::class, 'getByKey']);
|
||||
Route::get('/config', [\App\Http\Controllers\System\Api\Config::class, 'all']);
|
||||
Route::get('/config/group', [\App\Http\Controllers\System\Api\Config::class, 'getByGroup']);
|
||||
Route::get('/config/key', [\App\Http\Controllers\System\Api\Config::class, 'getByKey']);
|
||||
|
||||
// 获取所有字典数据(用于前端缓存)
|
||||
Route::get('/dictionaries', [Dictionary::class, 'all']);
|
||||
Route::get('/dictionaries/code', [Dictionary::class, 'getByCode']);
|
||||
Route::get('/dictionaries/{id}', [Dictionary::class, 'show']);
|
||||
Route::get('/dictionary', [Dictionary::class, 'all']);
|
||||
Route::get('/dictionary/code', [Dictionary::class, 'getByCode']);
|
||||
Route::get('/dictionary/{id}', [Dictionary::class, 'show']);
|
||||
|
||||
// 获取城市数据
|
||||
Route::get('/cities/tree', [\App\Http\Controllers\System\Api\City::class, 'tree']);
|
||||
Route::get('/cities/provinces', [\App\Http\Controllers\System\Api\City::class, 'provinces']);
|
||||
Route::get('/cities/{provinceId}/cities', [\App\Http\Controllers\System\Api\City::class, 'cities']);
|
||||
Route::get('/cities/{cityId}/districts', [\App\Http\Controllers\System\Api\City::class, 'districts']);
|
||||
Route::get('/cities/{id}', [\App\Http\Controllers\System\Api\City::class, 'show']);
|
||||
Route::get('/city/tree', [\App\Http\Controllers\System\Api\City::class, 'tree']);
|
||||
Route::get('/city/provinces', [\App\Http\Controllers\System\Api\City::class, 'provinces']);
|
||||
Route::get('/city/{provinceId}/cities', [\App\Http\Controllers\System\Api\City::class, 'cities']);
|
||||
Route::get('/city/{cityId}/districts', [\App\Http\Controllers\System\Api\City::class, 'districts']);
|
||||
Route::get('/city/{id}', [\App\Http\Controllers\System\Api\City::class, 'show']);
|
||||
|
||||
// 文件上传
|
||||
Route::post('/upload', [\App\Http\Controllers\System\Api\Upload::class, 'upload']);
|
||||
|
||||
Reference in new issue
Block a user