feat: 第一阶段基础框架搭建
后端 (Laravel 10 + Sanctum): - RBAC 四层权限系统 (users→roles→permissions→menus) - 门店隔离中间件 (BelongsToStore Trait + StoreIsolation Middleware) - 操作日志中间件 (自动记录写操作) - 权限检查中间件 (CheckPermission) - 16张数据库表迁移 (系统基础+RBAC+字典+配置) - 11个 Eloquent Model - Auth API (登录/登出/用户信息) - 系统设置模块 CRUD (门店/部门/职务/用户/角色/菜单/权限/字典/日志) - 45条 RESTful API 路由 - InitSeeder 初始数据 (超管/角色/76权限/31菜单) 前端 (Vue 3 + Element Plus + Vite): - Axios 请求封装 + Token 注入 - Pinia 状态管理 (user + permission store) - 动态路由 (服务端菜单→前端路由自动生成) - 后台布局 (侧边栏+顶栏+主内容区) - 登录页 + 仪表盘首页 - 系统设置 7 个 CRUD 页面 技术方案文档 (7卷): - 技术总览/数据库设计/API规范/RBAC设计/模块详设/小程序设计/部署方案
This commit is contained in:
@@ -0,0 +1 @@
|
||||
*.sqlite*
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration')->index();
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('queue');
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
|
||||
$table->index(['queue', 'reserved_at', 'available_at']);
|
||||
});
|
||||
|
||||
Schema::create('job_batches', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->string('name');
|
||||
$table->integer('total_jobs');
|
||||
$table->integer('pending_jobs');
|
||||
$table->integer('failed_jobs');
|
||||
$table->longText('failed_job_ids');
|
||||
$table->mediumText('options')->nullable();
|
||||
$table->integer('cancelled_at')->nullable();
|
||||
$table->integer('created_at');
|
||||
$table->integer('finished_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('regions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 50)->comment('区域名称');
|
||||
$table->integer('sort')->default(0);
|
||||
$table->tinyInteger('status')->default(1)->comment('1启用 0停用');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('regions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('stores', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('region_id')->constrained()->comment('所属区域');
|
||||
$table->string('name', 100)->comment('门店名称');
|
||||
$table->string('code', 20)->unique()->nullable()->comment('门店编码');
|
||||
$table->string('address', 255)->nullable();
|
||||
$table->string('phone', 20)->nullable();
|
||||
$table->string('logo', 255)->nullable();
|
||||
$table->tinyInteger('status')->default(1)->comment('1启用 0停用');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('stores');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('departments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('store_id')->constrained()->comment('所属门店');
|
||||
$table->unsignedBigInteger('parent_id')->default(0)->comment('上级部门');
|
||||
$table->string('name', 50)->comment('部门名称');
|
||||
$table->integer('sort')->default(0);
|
||||
$table->tinyInteger('status')->default(1)->comment('1启用 0停用');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('store_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('departments');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('positions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('store_id')->constrained()->comment('所属门店');
|
||||
$table->string('name', 50)->comment('职务名称');
|
||||
$table->integer('sort')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('positions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('store_id')->constrained()->comment('所属门店');
|
||||
$table->unsignedBigInteger('department_id')->nullable();
|
||||
$table->unsignedBigInteger('position_id')->nullable();
|
||||
$table->string('username', 50)->unique()->comment('登录名');
|
||||
$table->string('password', 255);
|
||||
$table->string('name', 50)->comment('真实姓名');
|
||||
$table->string('phone', 20)->nullable();
|
||||
$table->string('email', 100)->nullable();
|
||||
$table->string('avatar', 255)->nullable();
|
||||
$table->tinyInteger('status')->default(1)->comment('0待审核 1正常 2禁用');
|
||||
$table->tinyInteger('is_super')->default(0)->comment('1超级管理员');
|
||||
$table->timestamp('last_login_at')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index('store_id');
|
||||
$table->index('phone');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('roles', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('store_id')->nullable()->comment('NULL=全局角色');
|
||||
$table->string('name', 50)->comment('角色名称');
|
||||
$table->string('code', 50)->unique()->comment('角色编码');
|
||||
$table->string('description', 255)->nullable();
|
||||
$table->tinyInteger('is_system')->default(0)->comment('1系统内置不可删');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('roles');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('permissions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('parent_id')->default(0)->comment('上级权限');
|
||||
$table->string('name', 50)->comment('权限名称');
|
||||
$table->string('code', 100)->unique()->comment('权限标识 如 crm.lead.create');
|
||||
$table->string('module', 50)->nullable()->comment('所属模块');
|
||||
$table->tinyInteger('type')->default(1)->comment('1菜单 2按钮 3接口');
|
||||
$table->string('description', 255)->nullable();
|
||||
$table->integer('sort')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('permissions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('menus', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('parent_id')->default(0)->comment('上级菜单');
|
||||
$table->string('name', 50)->comment('菜单名称');
|
||||
$table->string('path', 255)->nullable()->comment('路由路径');
|
||||
$table->string('component', 255)->nullable()->comment('组件路径');
|
||||
$table->string('icon', 50)->nullable()->comment('图标');
|
||||
$table->string('permission_code', 100)->nullable()->comment('关联权限标识');
|
||||
$table->tinyInteger('type')->default(1)->comment('1目录 2菜单 3按钮');
|
||||
$table->tinyInteger('visible')->default(1)->comment('1显示 0隐藏');
|
||||
$table->integer('sort')->default(0);
|
||||
$table->tinyInteger('status')->default(1)->comment('1启用 0停用');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('menus');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('role_user', function (Blueprint $table) {
|
||||
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('role_id')->constrained()->onDelete('cascade');
|
||||
$table->primary(['user_id', 'role_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('role_user');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('role_permission', function (Blueprint $table) {
|
||||
$table->foreignId('role_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('permission_id')->constrained()->onDelete('cascade');
|
||||
$table->primary(['role_id', 'permission_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('role_permission');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('operation_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('store_id')->constrained();
|
||||
$table->unsignedBigInteger('user_id');
|
||||
$table->string('user_name', 50);
|
||||
$table->string('module', 50)->comment('操作模块');
|
||||
$table->string('action', 50)->comment('操作类型 create/update/delete');
|
||||
$table->string('target', 100)->nullable()->comment('操作对象');
|
||||
$table->unsignedBigInteger('target_id')->nullable();
|
||||
$table->string('ip', 45)->nullable();
|
||||
$table->string('method', 10)->nullable()->comment('HTTP方法');
|
||||
$table->string('url', 500)->nullable()->comment('请求URL');
|
||||
$table->json('before')->nullable()->comment('变更前数据');
|
||||
$table->json('after')->nullable()->comment('变更后数据');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
|
||||
$table->index(['store_id', 'created_at']);
|
||||
$table->index('user_id');
|
||||
$table->index('module');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('operation_logs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('dictionaries', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 50)->comment('字典名称');
|
||||
$table->string('code', 50)->unique()->comment('字典编码');
|
||||
$table->string('description', 255)->nullable();
|
||||
$table->tinyInteger('is_system')->default(0)->comment('系统内置不可删');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('dictionary_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('dictionary_id')->constrained()->onDelete('cascade');
|
||||
$table->string('label', 100)->comment('显示文本');
|
||||
$table->string('value', 100)->comment('值');
|
||||
$table->integer('sort')->default(0);
|
||||
$table->tinyInteger('status')->default(1)->comment('1启用 0停用');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('dictionary_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('dictionary_items');
|
||||
Schema::dropIfExists('dictionaries');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('system_configs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('store_id')->nullable()->comment('NULL=全局配置');
|
||||
$table->string('group', 50)->default('general')->comment('配置分组');
|
||||
$table->string('key', 100)->comment('配置键');
|
||||
$table->text('value')->nullable()->comment('配置值');
|
||||
$table->string('description', 255)->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['store_id', 'key']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('system_configs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('tokenable');
|
||||
$table->text('name');
|
||||
$table->string('token', 64)->unique();
|
||||
$table->text('abilities')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable()->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('personal_access_tokens');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
use WithoutModelEvents;
|
||||
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// User::factory(10)->create();
|
||||
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Department;
|
||||
use App\Models\Menu;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Region;
|
||||
use App\Models\Role;
|
||||
use App\Models\Store;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class InitSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
// 1. 创建默认区域
|
||||
$region = Region::create(['name' => '默认区域', 'sort' => 0, 'status' => 1]);
|
||||
|
||||
// 2. 创建默认门店
|
||||
$store = Store::create([
|
||||
'region_id' => $region->id,
|
||||
'name' => '宫中有喜总店',
|
||||
'code' => 'HQ001',
|
||||
'status' => 1,
|
||||
]);
|
||||
|
||||
// 3. 创建默认部门
|
||||
Department::create(['store_id' => $store->id, 'name' => '管理层', 'sort' => 0]);
|
||||
|
||||
// 4. 创建超级管理员
|
||||
$admin = User::create([
|
||||
'store_id' => $store->id,
|
||||
'username' => 'admin',
|
||||
'password' => 'admin123',
|
||||
'name' => '超级管理员',
|
||||
'status' => 1,
|
||||
'is_super' => 1,
|
||||
]);
|
||||
|
||||
// 5. 创建默认角色
|
||||
$superRole = Role::create([
|
||||
'name' => '超级管理员',
|
||||
'code' => 'super_admin',
|
||||
'description' => '系统最高权限',
|
||||
'is_system' => 1,
|
||||
]);
|
||||
|
||||
$storeAdmin = Role::create([
|
||||
'store_id' => $store->id,
|
||||
'name' => '门店管理员',
|
||||
'code' => 'store_admin',
|
||||
'description' => '门店最高权限',
|
||||
'is_system' => 1,
|
||||
]);
|
||||
|
||||
$admin->roles()->attach($superRole->id);
|
||||
|
||||
// 6. 创建权限
|
||||
$this->createPermissions();
|
||||
|
||||
// 7. 创建菜单
|
||||
$this->createMenus();
|
||||
|
||||
// 8. 门店管理员分配所有权限
|
||||
$allPermissions = Permission::pluck('id')->toArray();
|
||||
$storeAdmin->permissions()->sync($allPermissions);
|
||||
}
|
||||
|
||||
private function createPermissions(): void
|
||||
{
|
||||
$modules = [
|
||||
['name' => 'CRM管理', 'code' => 'crm', 'children' => [
|
||||
['name' => '线索管理', 'code' => 'crm.lead', 'children' => [
|
||||
['name' => '查看', 'code' => 'crm.lead.view', 'type' => 2],
|
||||
['name' => '新建', 'code' => 'crm.lead.create', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'crm.lead.update', 'type' => 2],
|
||||
['name' => '删除', 'code' => 'crm.lead.delete', 'type' => 2],
|
||||
]],
|
||||
['name' => '客户管理', 'code' => 'crm.customer', 'children' => [
|
||||
['name' => '查看', 'code' => 'crm.customer.view', 'type' => 2],
|
||||
['name' => '新建', 'code' => 'crm.customer.create', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'crm.customer.update', 'type' => 2],
|
||||
['name' => '删除', 'code' => 'crm.customer.delete', 'type' => 2],
|
||||
]],
|
||||
['name' => '合同管理', 'code' => 'crm.contract', 'children' => [
|
||||
['name' => '查看', 'code' => 'crm.contract.view', 'type' => 2],
|
||||
['name' => '新建', 'code' => 'crm.contract.create', 'type' => 2],
|
||||
['name' => '审批', 'code' => 'crm.contract.approve', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '房务管理', 'code' => 'room', 'children' => [
|
||||
['name' => '房间管理', 'code' => 'room.room', 'children' => [
|
||||
['name' => '查看', 'code' => 'room.room.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'room.room.update', 'type' => 2],
|
||||
]],
|
||||
['name' => '预定管理', 'code' => 'room.reservation', 'children' => [
|
||||
['name' => '查看', 'code' => 'room.reservation.view', 'type' => 2],
|
||||
['name' => '新建', 'code' => 'room.reservation.create', 'type' => 2],
|
||||
['name' => '操作', 'code' => 'room.reservation.operate', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '护理管理', 'code' => 'care', 'children' => [
|
||||
['name' => '护理档案', 'code' => 'care.profile', 'children' => [
|
||||
['name' => '查看', 'code' => 'care.profile.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'care.profile.update', 'type' => 2],
|
||||
]],
|
||||
['name' => '护理记录', 'code' => 'care.record', 'children' => [
|
||||
['name' => '查看', 'code' => 'care.record.view', 'type' => 2],
|
||||
['name' => '新建', 'code' => 'care.record.create', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '月子餐管理', 'code' => 'meal', 'children' => [
|
||||
['name' => '菜品管理', 'code' => 'meal.dish', 'children' => [
|
||||
['name' => '查看', 'code' => 'meal.dish.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'meal.dish.update', 'type' => 2],
|
||||
]],
|
||||
['name' => '排餐管理', 'code' => 'meal.plan', 'children' => [
|
||||
['name' => '查看', 'code' => 'meal.plan.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'meal.plan.update', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '服务产康', 'code' => 'service', 'children' => [
|
||||
['name' => '服务项目', 'code' => 'service.item', 'children' => [
|
||||
['name' => '查看', 'code' => 'service.item.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'service.item.update', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '月嫂管理', 'code' => 'nanny', 'children' => [
|
||||
['name' => '月嫂档案', 'code' => 'nanny.profile', 'children' => [
|
||||
['name' => '查看', 'code' => 'nanny.profile.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'nanny.profile.update', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '进销存', 'code' => 'stock', 'children' => [
|
||||
['name' => '库存管理', 'code' => 'stock.inventory', 'children' => [
|
||||
['name' => '查看', 'code' => 'stock.inventory.view', 'type' => 2],
|
||||
['name' => '操作', 'code' => 'stock.inventory.operate', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '财务管理', 'code' => 'finance', 'children' => [
|
||||
['name' => '收支管理', 'code' => 'finance.record', 'children' => [
|
||||
['name' => '查看', 'code' => 'finance.record.view', 'type' => 2],
|
||||
['name' => '新建', 'code' => 'finance.record.create', 'type' => 2],
|
||||
['name' => '审核', 'code' => 'finance.record.approve', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '人事薪资', 'code' => 'hr', 'children' => [
|
||||
['name' => '员工管理', 'code' => 'hr.employee', 'children' => [
|
||||
['name' => '查看', 'code' => 'hr.employee.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'hr.employee.update', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '办公协同', 'code' => 'office', 'children' => [
|
||||
['name' => '审批管理', 'code' => 'office.approval', 'children' => [
|
||||
['name' => '查看', 'code' => 'office.approval.view', 'type' => 2],
|
||||
['name' => '审批', 'code' => 'office.approval.operate', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '统计报表', 'code' => 'report', 'children' => [
|
||||
['name' => '查看报表', 'code' => 'report.view', 'type' => 2],
|
||||
['name' => '导出报表', 'code' => 'report.export', 'type' => 2],
|
||||
]],
|
||||
['name' => '知识库', 'code' => 'kb', 'children' => [
|
||||
['name' => '文章管理', 'code' => 'kb.article', 'children' => [
|
||||
['name' => '查看', 'code' => 'kb.article.view', 'type' => 2],
|
||||
['name' => '编辑', 'code' => 'kb.article.update', 'type' => 2],
|
||||
]],
|
||||
]],
|
||||
['name' => '系统设置', 'code' => 'system', 'children' => [
|
||||
['name' => '门店管理', 'code' => 'system.store', 'type' => 2],
|
||||
['name' => '用户管理', 'code' => 'system.user', 'type' => 2],
|
||||
['name' => '角色管理', 'code' => 'system.role', 'type' => 2],
|
||||
['name' => '菜单管理', 'code' => 'system.menu', 'type' => 2],
|
||||
['name' => '字典管理', 'code' => 'system.dict', 'type' => 2],
|
||||
['name' => '操作日志', 'code' => 'system.log', 'type' => 2],
|
||||
]],
|
||||
];
|
||||
|
||||
$this->insertPermissions($modules);
|
||||
}
|
||||
|
||||
private function insertPermissions(array $items, int $parentId = 0, int &$sort = 0): void
|
||||
{
|
||||
foreach ($items as $item) {
|
||||
$children = $item['children'] ?? [];
|
||||
unset($item['children']);
|
||||
|
||||
$item['parent_id'] = $parentId;
|
||||
$item['type'] = $item['type'] ?? 1;
|
||||
$item['module'] = explode('.', $item['code'])[0];
|
||||
$item['sort'] = $sort++;
|
||||
|
||||
$permission = Permission::create($item);
|
||||
|
||||
if ($children) {
|
||||
$this->insertPermissions($children, $permission->id, $sort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function createMenus(): void
|
||||
{
|
||||
$menus = [
|
||||
['name' => '首页', 'path' => '/dashboard', 'component' => 'dashboard/index', 'icon' => 'HomeFilled', 'sort' => 0],
|
||||
['name' => 'CRM管理', 'icon' => 'User', 'sort' => 1, 'permission_code' => 'crm', 'children' => [
|
||||
['name' => '线索管理', 'path' => '/crm/leads', 'component' => 'crm/leads/index', 'permission_code' => 'crm.lead'],
|
||||
['name' => '客户管理', 'path' => '/crm/customers', 'component' => 'crm/customers/index', 'permission_code' => 'crm.customer'],
|
||||
['name' => '合同管理', 'path' => '/crm/contracts', 'component' => 'crm/contracts/index', 'permission_code' => 'crm.contract'],
|
||||
]],
|
||||
['name' => '房务管理', 'icon' => 'House', 'sort' => 2, 'permission_code' => 'room', 'children' => [
|
||||
['name' => '房态看板', 'path' => '/room/board', 'component' => 'room/board/index', 'permission_code' => 'room.room'],
|
||||
['name' => '预定管理', 'path' => '/room/reservations', 'component' => 'room/reservations/index', 'permission_code' => 'room.reservation'],
|
||||
]],
|
||||
['name' => '护理管理', 'icon' => 'FirstAidKit', 'sort' => 3, 'permission_code' => 'care', 'children' => [
|
||||
['name' => '护理档案', 'path' => '/care/profiles', 'component' => 'care/profiles/index', 'permission_code' => 'care.profile'],
|
||||
['name' => '护理记录', 'path' => '/care/records', 'component' => 'care/records/index', 'permission_code' => 'care.record'],
|
||||
]],
|
||||
['name' => '月子餐', 'icon' => 'Bowl', 'sort' => 4, 'permission_code' => 'meal', 'children' => [
|
||||
['name' => '菜品管理', 'path' => '/meal/dishes', 'component' => 'meal/dishes/index', 'permission_code' => 'meal.dish'],
|
||||
['name' => '排餐管理', 'path' => '/meal/plans', 'component' => 'meal/plans/index', 'permission_code' => 'meal.plan'],
|
||||
]],
|
||||
['name' => '服务产康', 'icon' => 'Promotion', 'sort' => 5, 'permission_code' => 'service'],
|
||||
['name' => '月嫂管理', 'icon' => 'Avatar', 'sort' => 6, 'permission_code' => 'nanny'],
|
||||
['name' => '进销存', 'icon' => 'Box', 'sort' => 7, 'permission_code' => 'stock'],
|
||||
['name' => '财务管理', 'icon' => 'Money', 'sort' => 8, 'permission_code' => 'finance'],
|
||||
['name' => '人事薪资', 'icon' => 'Stamp', 'sort' => 9, 'permission_code' => 'hr'],
|
||||
['name' => '办公协同', 'icon' => 'ChatDotRound', 'sort' => 10, 'permission_code' => 'office'],
|
||||
['name' => '统计报表', 'icon' => 'DataAnalysis', 'sort' => 11, 'permission_code' => 'report'],
|
||||
['name' => '知识库', 'icon' => 'Reading', 'sort' => 12, 'permission_code' => 'kb'],
|
||||
['name' => '系统设置', 'icon' => 'Setting', 'sort' => 99, 'permission_code' => 'system', 'children' => [
|
||||
['name' => '门店管理', 'path' => '/system/stores', 'component' => 'system/stores/index', 'permission_code' => 'system.store'],
|
||||
['name' => '部门管理', 'path' => '/system/departments', 'component' => 'system/departments/index', 'permission_code' => 'system.store'],
|
||||
['name' => '职务管理', 'path' => '/system/positions', 'component' => 'system/positions/index', 'permission_code' => 'system.store'],
|
||||
['name' => '用户管理', 'path' => '/system/users', 'component' => 'system/users/index', 'permission_code' => 'system.user'],
|
||||
['name' => '角色管理', 'path' => '/system/roles', 'component' => 'system/roles/index', 'permission_code' => 'system.role'],
|
||||
['name' => '菜单管理', 'path' => '/system/menus', 'component' => 'system/menus/index', 'permission_code' => 'system.menu'],
|
||||
['name' => '字典管理', 'path' => '/system/dictionaries', 'component' => 'system/dictionaries/index', 'permission_code' => 'system.dict'],
|
||||
['name' => '操作日志', 'path' => '/system/logs', 'component' => 'system/logs/index', 'permission_code' => 'system.log'],
|
||||
]],
|
||||
];
|
||||
|
||||
$this->insertMenus($menus);
|
||||
}
|
||||
|
||||
private function insertMenus(array $items, int $parentId = 0): void
|
||||
{
|
||||
foreach ($items as $index => $item) {
|
||||
$children = $item['children'] ?? [];
|
||||
unset($item['children']);
|
||||
|
||||
$item['parent_id'] = $parentId;
|
||||
$item['type'] = isset($item['component']) ? 2 : 1; // 有 component = 菜单,否则目录
|
||||
$item['sort'] = $item['sort'] ?? $index;
|
||||
$item['visible'] = 1;
|
||||
$item['status'] = 1;
|
||||
|
||||
$menu = Menu::create($item);
|
||||
|
||||
if ($children) {
|
||||
$this->insertMenus($children, $menu->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user