diff --git a/app/Admin/Controllers/Store/DeviceController.php b/app/Admin/Controllers/Store/DeviceController.php index df86abd..3653814 100644 --- a/app/Admin/Controllers/Store/DeviceController.php +++ b/app/Admin/Controllers/Store/DeviceController.php @@ -26,6 +26,12 @@ class DeviceController extends AdminController ->bulkActions([]) ->filter($this->baseFilter()->body([ amis()->GroupControl()->mode('horizontal')->body([ + amisMake()->SelectControl()->name('store_id')->label(__('store_device.store_id')) + ->source(admin_url('store/stores?_action=getData&_all=1')) + ->labelField('title') + ->valueField('id') + ->columnRatio(3) + ->clearable(), amisMake()->TextControl()->name('name')->label(__('store_device.name'))->columnRatio(3)->clearable(), ]), ])) @@ -49,7 +55,7 @@ class DeviceController extends AdminController { return $this->baseForm()->title('')->body([ amisMake()->SelectControl()->name('store_id')->label(__('store_device.store_id')) - ->source(admin_url('store/stores?_action=getData')) + ->source(admin_url('store/stores?_action=getData&_all=1')) ->labelField('title') ->valueField('id') ->required(), diff --git a/app/Admin/Controllers/Store/EmployeeController.php b/app/Admin/Controllers/Store/EmployeeController.php new file mode 100644 index 0000000..db7b5c4 --- /dev/null +++ b/app/Admin/Controllers/Store/EmployeeController.php @@ -0,0 +1,67 @@ +baseCRUD() + ->tableLayout('fixed') + ->headerToolbar([ + $this->createButton(true)->visible(Admin::user()->can('admin.store.employees.create')), + ...$this->baseHeaderToolBar(), + ]) + ->bulkActions([]) + ->filter($this->baseFilter()->body([ + amis()->GroupControl()->mode('horizontal')->body([ + amisMake()->SelectControl()->name('store_id')->label(__('employee.store_id')) + ->source(admin_url('store/stores?_action=getData&_all=1')) + ->labelField('title') + ->valueField('id') + ->columnRatio(3) + ->clearable(), + amisMake()->TextControl()->name('employee_search')->label(__('store.employees'))->placeholder('姓名/电话')->columnRatio(3)->clearable(), + ]), + ])) + ->columns([ + amisMake()->TableColumn()->name('id')->label(__('employee.id')), + amisMake()->TableColumn()->name('store.title')->label(__('employee.store_id')), + amisMake()->TableColumn()->name('employee.name')->label(__('store.employees')), + amisMake()->TableColumn()->name('employee.phone')->label(__('employee.phone')), + $this->rowActions([ + // $this->rowEditButton(true)->visible(Admin::user()->can('admin.store.employees.update')), + $this->rowDeleteButton()->visible(Admin::user()->can('admin.store.employees.delete')), + ]), + ]); + + return $this->baseList($crud); + } + + public function form($edit): Form + { + return $this->baseForm()->title('')->body([ + amisMake()->SelectControl()->name('store_id')->label(__('employee.store_id')) + ->source(admin_url('store/stores?_action=getData&_all=1')) + ->labelField('title') + ->valueField('id') + ->required(), + amisMake()->SelectControl()->name('employee_id')->label(__('store.employees')) + ->source(admin_url('hr/employees?_action=getData&_all=1')) + ->labelField('name') + ->valueField('id') + ->required(), + ]); + } +} diff --git a/app/Admin/Controllers/Store/StoreController.php b/app/Admin/Controllers/Store/StoreController.php index d8f492e..1baa6bb 100644 --- a/app/Admin/Controllers/Store/StoreController.php +++ b/app/Admin/Controllers/Store/StoreController.php @@ -59,6 +59,7 @@ class StoreController extends AdminController ->columns([ amisMake()->TableColumn()->name('id')->label(__('store.id')), amisMake()->TableColumn()->name('title')->label(__('store.title')), + amisMake()->TableColumn()->name('master.name')->label(__('store.master_id')), amisMake()->TableColumn()->name('category.name')->label(__('store.category_id')), amisMake()->TableColumn()->name('business.name')->label(__('store.business_id')), amisMake()->TableColumn()->name('level.name')->label(__('store.level_id')), @@ -115,68 +116,10 @@ class StoreController extends AdminController ['label' => __('store.business_id'), 'content' => '${business.name}'], ['label' => __('store.level_id'), 'content' => '${level.name}'], ['label' => __('store.region'), 'content' => '${region.province}-${region.city}'], - ['label' => __('store.address'), 'content' => '${region.address}', 'span' => 2], + ['label' => __('store.address'), 'content' => '${address}', 'span' => 2], ['label' => __('store.profit_ratio'), 'content' => '${profit_ratio}%', 'span' => 3], ]); - - // 员工列表 - $sales = amisMake()->Service()->id('store-employees-table')->api(admin_url('store/stores/${id}/employees'))->initFetch(false)->body(amisMake()->Table()->columns([ - amisMake()->TableColumn()->name('name')->label(__('employee.name')), - amisMake()->TableColumn()->name('phone')->label(__('employee.phone')), - ])->itemActions([ - amisMake()->AjaxAction() - ->label(__('admin.delete')) - ->level('link') - ->confirmText(__('admin.confirm_delete')) - ->api('delete:'.admin_url('store/stores/${id}/employees').'?employees=${id}') - ->reload('store-employees-table') - ])); - return $this->baseDetail()->title('')->body([$detail, amisMake()->Divider()->title(__('store.employees')), $sales]); - } - - public function show($id) - { - if ($this->actionOfGetData()) { - return $this->response()->success($this->service->getDetail($id)); - } - - $form = amisMake()->Form() - ->labelWidth(0) - ->api('post:' . admin_url('store/stores/'.$id.'/employees')) - ->redirect('') - ->onEvent([ - 'submitSucc' => [ - 'actions' => [ - ['actionType' => 'reload','componentId' => 'store-employees-table'] - ] - ] - ]) - ->body([ - amisMake()->TransferControl()->name('employees') - ->source(admin_url('store/stores/employee_options') . '?store_id='.$id) - ->selectMode('table') - ->resultListModeFollowSelect() - ->joinValues(false) - ->extractValue(true) - ->columns([ - amisMake()->Column()->name('label')->label(__('employee.name')), - amisMake()->Column()->name('phone')->label(__('employee.phone')), - ]), - ]); - $dialog = amisMake()->Dialog()->size('lg')->title('添加'.__('store.employees'))->body($form); - $detail = amis() - ->Card() - ->className('base-form') - ->header(['title' => __('admin.detail')]) - ->body($this->detail()) - ->toolbar([ - amisMake()->DialogAction()->label('添加'. __('store.employees'))->level('primary')->className('mr-1')->dialog($dialog), - $this->backButton(), - ]); - - $page = $this->basePage()->body($detail); - - return $this->response()->success($page); + return $this->baseDetail()->title('')->body([$detail]); } public function employees($id) diff --git a/app/Admin/Filters/StoreEmployeeFilter.php b/app/Admin/Filters/StoreEmployeeFilter.php new file mode 100644 index 0000000..95296b7 --- /dev/null +++ b/app/Admin/Filters/StoreEmployeeFilter.php @@ -0,0 +1,30 @@ + [ + 'store_title' => 'title' + ], + 'employee' => [ + 'employee_name' => 'name', + 'employee_search' => 'search', + ] + ]; + + public function employeeId($key) + { + $this->where('employee_id', $key); + } + + public function storeId($key) + { + $this->where('store_id', $key); + } +} diff --git a/app/Admin/Services/BaseService.php b/app/Admin/Services/BaseService.php index b992578..912b586 100644 --- a/app/Admin/Services/BaseService.php +++ b/app/Admin/Services/BaseService.php @@ -24,6 +24,22 @@ class BaseService extends AdminService return array2tree($list->toArray(), $minNum); } + public function list() + { + $query = $this->listQuery(); + if (request()->input('_all')) { + $list = (clone $query)->get(); + $items = $list->all(); + $total = $list->count(); + } else { + $list = (clone $query)->paginate(request()->input('perPage', 20)); + $items = $list->items(); + $total = $list->total(); + } + + return compact('items', 'total'); + } + public function getModelFilter() { return $this->modelFilterName; diff --git a/app/Admin/Services/EmployeeService.php b/app/Admin/Services/EmployeeService.php index 4a64987..109abf3 100644 --- a/app/Admin/Services/EmployeeService.php +++ b/app/Admin/Services/EmployeeService.php @@ -108,7 +108,7 @@ class EmployeeService extends BaseService public function preDelete(array $ids) { - // 店长关联 + // 店员关联 if (DB::table('store_employees')->whereIn('employee_id', $ids)->exists()) { return '员工已关联门店, 请先从门店中删除'; } diff --git a/app/Admin/Services/StoreEmployeeService.php b/app/Admin/Services/StoreEmployeeService.php new file mode 100644 index 0000000..4cc4eb4 --- /dev/null +++ b/app/Admin/Services/StoreEmployeeService.php @@ -0,0 +1,37 @@ + ['required'], + 'employee_id' => ['required', Rule::unique('store_employees', 'employee_id')], + ]; + $updateRules = [ + 'employee_id' => [Rule::unique('store_employees', 'employee_id')->ignore($model, 'employee_id')], + ]; + $validator = Validator::make($data, $model ? $updateRules : $createRules, [ + 'employee_id.unique' => '已经是店员了', + ]); + if ($validator->fails()) { + return $validator->errors()->first(); + } + + return true; + } +} diff --git a/app/Admin/Services/StoreService.php b/app/Admin/Services/StoreService.php index 04216e2..53b5451 100644 --- a/app/Admin/Services/StoreService.php +++ b/app/Admin/Services/StoreService.php @@ -116,4 +116,11 @@ class StoreService extends BaseService return true; } + + public function preDelete(array $ids) + { + // 删除店员 + DB::table('store_employees')->whereIn('store_id', $ids)->delete(); + return true; + } } diff --git a/app/Admin/routes.php b/app/Admin/routes.php index ebd9e41..75316e4 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -2,6 +2,7 @@ use App\Admin\Controllers\Hr\EmployeeController; use App\Admin\Controllers\Store\StoreController; +use App\Admin\Controllers\Store\EmployeeController as StoreEmployeeController; use App\Admin\Controllers\Store\DeviceController; use App\Admin\Controllers\System\AdminMenuController; use App\Admin\Controllers\System\AdminPermissionController; @@ -30,16 +31,10 @@ Route::group([ 'prefix' => 'store', 'as' => 'store.', ], function (Router $router) { - // 店员列表 - $router->get('stores/{id}/employees', [StoreController::class, 'employees']); - // 添加店员时, 可选的员工列表 - $router->get('stores/employee_options', [StoreController::class, 'employeeOptions']); - // 添加店员 - $router->post('stores/{id}/employees', [StoreController::class, 'employeeAdd']); - // 删除店员 - $router->delete('stores/{id}/employees', [StoreController::class, 'employeeDestroy']); // 门店管理 $router->resource('stores', StoreController::class); + // 店员管理 + $router->resource('employees', StoreEmployeeController::class); // 彩票机管理 $router->resource('devices', DeviceController::class); }); diff --git a/app/Models/Employee.php b/app/Models/Employee.php index c35cebb..fcab8f5 100644 --- a/app/Models/Employee.php +++ b/app/Models/Employee.php @@ -9,6 +9,7 @@ use EloquentFilter\Filterable; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; use Slowlyo\OwlAdmin\Models\AdminUser; +use App\Admin\Filters\EmployeeFilter; /** * 员工 @@ -35,6 +36,11 @@ class Employee extends Model protected $appends = ['employee_status_text', 'employee_status_color']; + public function modelFilter() + { + return EmployeeFilter::class; + } + // 拥有的职位 public function jobs() { diff --git a/app/Models/Store.php b/app/Models/Store.php index 512e503..0ba47f4 100644 --- a/app/Models/Store.php +++ b/app/Models/Store.php @@ -53,7 +53,7 @@ class Store extends Model public function employees() { // role(1: 店长, 2: 店员) - return $this->belongsToMany(Employee::class, 'store_employees', 'store_id', 'employee_id')->withPivot(['role']); + return $this->belongsToMany(Employee::class, 'store_employees', 'store_id', 'employee_id')->using(StoreEmployee::class); } protected function businessStatusText(): Attribute diff --git a/app/Models/StoreEmployee.php b/app/Models/StoreEmployee.php new file mode 100644 index 0000000..538f85d --- /dev/null +++ b/app/Models/StoreEmployee.php @@ -0,0 +1,28 @@ +belongsTo(Store::class, 'store_id'); + } + + public function employee() + { + return $this->belongsTo(Employee::class, 'employee_id'); + } +} diff --git a/config/app.php b/config/app.php index c832441..76b1f2c 100644 --- a/config/app.php +++ b/config/app.php @@ -109,7 +109,7 @@ return [ | */ - 'faker_locale' => 'en_US', + 'faker_locale' => 'zh_CN', /* |-------------------------------------------------------------------------- diff --git a/database/factories/EmployeeFactory.php b/database/factories/EmployeeFactory.php new file mode 100644 index 0000000..2fb9b8b --- /dev/null +++ b/database/factories/EmployeeFactory.php @@ -0,0 +1,40 @@ + + */ +class EmployeeFactory extends Factory +{ + protected $model = Employee::class; + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + $faker = $this->faker; + $name = $faker->name; + $phone = $faker->phoneNumber(); + // $adminUser = AdminUser::create([ + // 'username' => $phone, + // 'password' => bcrypt($phone), + // 'name' => $name, + // ]); + // $adminUser = AdminUser::first(); + return [ + 'name' => $name, + 'phone' => $phone, + 'prize_images' => ['https://via.placeholder.com/100x100.png'], + 'skill_images' => ['https://via.placeholder.com/100x100.png'], + // 'admin_user_id' => $adminUser->id, + 'join_at' => now() + ]; + } +} diff --git a/database/factories/StoreFactory.php b/database/factories/StoreFactory.php new file mode 100644 index 0000000..89e99c5 --- /dev/null +++ b/database/factories/StoreFactory.php @@ -0,0 +1,36 @@ + + */ +class StoreFactory extends Factory +{ + protected $model = Store::class; + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + do { + $master = Employee::inRandomOrder()->first(); + } while(StoreEmployee::where('employee_id', $master->id)->exists()); + return [ + 'title' => $this->faker->word(), + 'master_id' => $master->id, + 'category_id' => Keyword::where('lv', 3)->where('parent_key', 'store_category')->inRandomOrder()->value('key'), + 'business_id' => Keyword::where('lv', 2)->where('parent_key', 'store_business')->inRandomOrder()->value('key'), + 'level_id' => Keyword::where('lv', 2)->where('parent_key', 'store_level')->inRandomOrder()->value('key'), + 'region' => ["city" => "通辽市", "code" => 150500, "street" => null, "cityCode" => 150500, "district" => null, "province" => "内蒙古自治区", "districtCode" => 0, "provinceCode" => 150000], + 'lon' => '107.11352677389', + 'lat' => '29.167519061656', + 'address' => '重庆市南川区东城街道办事处东环路三号', + ]; + } +} diff --git a/database/migrations/2024_03_23_095309_create_stores_table.php b/database/migrations/2024_03_23_095309_create_stores_table.php index ce90dfb..8615fdf 100644 --- a/database/migrations/2024_03_23_095309_create_stores_table.php +++ b/database/migrations/2024_03_23_095309_create_stores_table.php @@ -30,6 +30,7 @@ return new class extends Migration }); Schema::create('store_employees', function (Blueprint $table) { + $table->id(); $table->foreignId('store_id'); $table->foreignId('employee_id'); $table->unsignedInteger('role')->default(2)->comment('身份(1: 店长, 2: 店员)'); diff --git a/database/seeders/AdminPermissionSeeder.php b/database/seeders/AdminPermissionSeeder.php index d59fcbd..6e79180 100644 --- a/database/seeders/AdminPermissionSeeder.php +++ b/database/seeders/AdminPermissionSeeder.php @@ -40,13 +40,19 @@ class AdminPermissionSeeder extends Seeder 'children' => [ 'stores' => [ 'name' => '门店管理', - 'icon' => 'material-symbols:store-rounded', + 'icon' => '', 'uri' => '/store/stores', 'resource' => true, ], + 'employees' => [ + 'name' => '店员管理', + 'icon' => '', + 'uri' => '/store/employees', + 'resource' => true, + ], 'devices' => [ 'name' => '彩票机管理', - 'icon' => 'material-symbols:store-rounded', + 'icon' => '', 'uri' => '/store/devices', 'resource' => true, ] diff --git a/database/seeders/AdminSeeder.php b/database/seeders/AdminSeeder.php index 5aa9475..31cd640 100644 --- a/database/seeders/AdminSeeder.php +++ b/database/seeders/AdminSeeder.php @@ -3,6 +3,7 @@ namespace Database\Seeders; use Illuminate\Database\Seeder; +use Illuminate\Support\Facades\DB; class AdminSeeder extends Seeder { @@ -13,9 +14,29 @@ class AdminSeeder extends Seeder */ public function run() { - $this->call([ - KeywordSeeder::class, - AdminPermissionSeeder::class, + $adminUser = DB::table('admin_users'); + $adminPermission = DB::table('admin_permissions'); + $adminRole = DB::table('admin_roles'); + // 创建初始用户 + $adminUser->truncate(); + $adminUser->insert([ + 'username' => 'admin', + 'password' => bcrypt('admin'), + 'name' => 'Administrator', + ]); + + // 创建初始角色 + $adminRole->truncate(); + $adminRole->insert([ + 'name' => 'Administrator', + 'slug' => 'administrator', + ]); + + // 用户 - 角色绑定 + DB::table('admin_role_users')->truncate(); + DB::table('admin_role_users')->insert([ + 'role_id' => 1, + 'user_id' => 1, ]); } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 0493ef7..fdb4240 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -12,6 +12,10 @@ class DatabaseSeeder extends Seeder */ public function run(): void { - // + $this->call([ + AdminSeeder::class, + KeywordSeeder::class, + AdminPermissionSeeder::class, + ]); } } diff --git a/database/seeders/EmployeeSeeder.php b/database/seeders/EmployeeSeeder.php new file mode 100644 index 0000000..a9448de --- /dev/null +++ b/database/seeders/EmployeeSeeder.php @@ -0,0 +1,26 @@ +truncate(); + Employee::truncate(); + (new EmployeeFactory)->count(100)->create(['admin_user_id' => 1]); + + DB::table('store_employees')->truncate(); + Store::truncate(); + (new StoreFactory)->count(10)->create(); + } +} diff --git a/lang/zh_CN/employee.php b/lang/zh_CN/employee.php index d2179f3..c2af87d 100644 --- a/lang/zh_CN/employee.php +++ b/lang/zh_CN/employee.php @@ -18,4 +18,5 @@ return [ 'join_at' => '入职时间', 'leave_confirm' => '是否确定?', 'remarks' => '备注', + 'store_id' => '门店', ];