Compare commits

..

10 Commits

Author SHA1 Message Date
xinadmin 93c65b56f6 登录注册 2026-07-15 12:07:32 +08:00
xinadmin 9eed7c87f6 前端打包 2026-06-17 13:08:53 +08:00
xinadmin 94dc78cd9c 修复别名错误 2026-06-17 13:01:48 +08:00
xinadmin a5eb91fadd 权限分配 2026-06-17 12:49:44 +08:00
xinadmin f63a7db58f 商户后台 2026-06-17 12:41:49 +08:00
xinadmin 845bea4b81 商户订单 2026-06-17 10:52:47 +08:00
xinadmin 8d52e863b9 接单员与财务管理 2026-06-17 10:35:13 +08:00
xinadmin 254823e308 校园商户 2026-06-17 09:13:49 +08:00
xinadmin 86be1c230e 校园论坛 2026-05-31 03:47:57 +08:00
xinadmin a1c6ecf2b9 小程序用户 2026-05-31 03:33:38 +08:00
415 changed files with 16822 additions and 1194 deletions
+6 -5
View File
@@ -1,11 +1,12 @@
{
"permissions": {
"allow": [
"mcp__laravel-boost__database-schema",
"Bash(php artisan *)"
]
},
"enableAllProjectMcpServers": true,
"enabledMcpjsonServers": [
"laravel-boost"
],
"permissions": {
"allow": [
"mcp__laravel-boost__database-schema"
]
}
}
+6
View File
@@ -38,6 +38,12 @@ QUEUE_CONNECTION=database
MEMCACHED_HOST=127.0.0.1
# 微信小程序配置
WECHAT_MINI_PROGRAM_APP_ID=
WECHAT_MINI_PROGRAM_SECRET=
WECHAT_MINI_PROGRAM_TOKEN=
WECHAT_MINI_PROGRAM_AES_KEY=
# 系统设置
SETTING_CACHE_KEY=settings
+69 -5
View File
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
use App\Http\Requests\UserRegisterRequest;
use App\Models\UserModel;
use App\Services\Wechat\MiniProgramService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@@ -16,11 +17,9 @@ use Modules\Common\Trait\RequestJson;
class IndexController
{
use RequestJson;
// 权限验证白名单
protected array $noPermission = ['index', 'login', 'register', 'mail'];
/** 获取首页信息 */
#[GetRoute('/index')]
#[GetRoute('/index', false)]
public function index(): JsonResponse
{
$web_setting = site_config('web');
@@ -29,7 +28,7 @@ class IndexController
}
/** 用户登录 */
#[PostRoute('/login')]
#[PostRoute('/login', false)]
public function login(Request $request): JsonResponse
{
$credentials = $request->validate([
@@ -46,7 +45,7 @@ class IndexController
}
/** 用户注册 */
#[PostRoute('/register')]
#[PostRoute('/register', false)]
public function register(UserRegisterRequest $request): JsonResponse
{
$data = $request->validated();
@@ -60,4 +59,69 @@ class IndexController
return $this->error('创建用户失败');
}
/**
* 小程序登录
*
* 仅需 code 完成 openid 换取,首次登录使用默认昵称和头像,
* 用户信息后续通过编辑接口完善。
*/
#[PostRoute('/wx/login', false)]
public function loginMiniProgram(Request $request, MiniProgramService $miniProgram): JsonResponse
{
$validated = $request->validate([
'code' => 'required|string',
'phoneCode' => 'nullable|string',
]);
// 1. 通过 code 换取 openid、session_key、unionid
$session = $miniProgram->codeToSession($validated['code']);
// 2. 构建用户数据,昵称/头像/性别使用默认值
$userData = [
'openid' => $session['openid'],
'unionid' => $session['unionid'] ?? '',
'username' => 'wx_'.uniqid(),
'nickname' => '微信用户',
'avatar' => '',
'gender' => 0,
'password' => '',
];
// 3. 解密手机号
if (! empty($validated['phoneCode'])) {
try {
$phoneInfo = $miniProgram->getPhoneNumber($validated['phoneCode']);
$userData['mobile'] = $phoneInfo['phone_info']['purePhoneNumber'] ?? '';
} catch (\Throwable) {
// 手机号解密失败不阻塞登录
}
}
// 4. 查找或创建用户
$user = UserModel::firstOrCreate(
['openid' => $userData['openid']],
$userData
);
// 5. 更新已有用户缺失的手机号和 unionid
$needUpdate = false;
foreach (['mobile', 'unionid'] as $field) {
if (! empty($userData[$field]) && empty($user->$field)) {
$user->$field = $userData[$field];
$needUpdate = true;
}
}
if ($needUpdate) {
$user->save();
}
// 6. 创建 Sanctum token
$token = $user->createToken($user->username)->toArray();
return $this->success([
'token' => $token['plainTextToken'],
'user' => $user->toArray(),
], __('user.login_success'));
}
}
@@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers;
use App\Models\PaymentTransactionModel;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
#[RequestAttribute('/finance/payment-transaction', 'finance.transaction')]
class PaymentTransactionController extends BaseController
{
protected array $searchField = [
'status' => '=',
'pay_type' => '=',
'business_type' => '=',
'user_id' => '=',
];
protected array $quickSearchField = ['transaction_no', 'out_trade_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = PaymentTransactionModel::query();
$data = $this->buildSearch($params, $query)->paginate($pageSize)->toArray();
return $this->success($data);
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = PaymentTransactionModel::find($id);
if (empty($model)) {
return $this->error('记录不存在');
}
$model->delete();
return $this->success();
}
}
+28 -33
View File
@@ -21,48 +21,43 @@ class UserController
#[GetRoute]
public function getUserInfo(): JsonResponse
{
$info = auth()->user();
return $this->success(compact('info'));
$user = UserModel::query()->find(auth()->id());
if (! $user) {
return $this->error('用户不存在');
}
#[PostRoute('/logout')]
public function logout(): JsonResponse
{
$user_id = auth('users')->id();
$model = new UserModel;
if ($model->logout($user_id)) {
return $this->success('退出登录成功');
} else {
return $this->error($model->getErrorMsg());
}
$data = $user->toArray();
// 手机号脱敏:13812345678 → 138****5678
if (! empty($data['mobile'])) {
$data['mobile'] = substr_replace($data['mobile'], '****', 3, 4);
}
#[PutRoute]
public function setUserInfo(UserUpdateInfoRequest $request): JsonResponse
{
UserModel::where('user_id', auth('user')->id())->update($request->validated());
return $this->error('更新成功');
// 邮箱脱敏:test@example.com → t***@example.com
if (! empty($data['email'])) {
$parts = explode('@', $data['email']);
$parts[0] = substr($parts[0], 0, 1).'***';
$data['email'] = implode('@', $parts);
}
#[PostRoute('/setPwd')]
public function setPassword(Request $request): JsonResponse
return $this->success($data);
}
/** 编辑用户信息(头像、昵称、性别) */
#[PutRoute('/profile')]
public function updateProfile(Request $request): JsonResponse
{
$data = $request->validate([
'oldPassword' => 'required|string|max:20',
'newPassword' => 'required|string|min:6|max:20',
'rePassword' => 'required|same:newPassword',
'avatar' => 'required|string|max:500',
'nickname' => 'required|string|max:32',
'gender' => 'required|integer|in:0,1,2',
]);
$user_id = auth('user')->id();
$user = UserModel::query()->find($user_id);
if (! password_verify($data['oldPassword'], $user['password'])) {
return $this->error('旧密码不正确!');
}
$user->password = password_hash($data['newPassword'], PASSWORD_DEFAULT);
if ($user->save()) {
return $this->success('更新成功');
}
return $this->error('更新失败');
$user = UserModel::query()->find(auth()->id());
$user->update($data);
return $this->success($user->toArray(), '更新成功');
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* 统一三方支付流水模型
*/
class PaymentTransactionModel extends Model
{
protected $table = 'payment_transactions';
protected $fillable = [
'transaction_no',
'out_trade_no',
'pay_type',
'amount',
'status',
'business_type',
'business_id',
'user_id',
'openid',
'raw_data',
'paid_at',
];
protected $casts = [
'amount' => 'decimal:2',
'status' => 'integer',
'business_id' => 'integer',
'user_id' => 'integer',
'raw_data' => 'array',
'paid_at' => 'datetime',
];
}
+4
View File
@@ -28,5 +28,9 @@ class UserModel extends Authenticatable
'email',
'password',
'nickname',
'openid',
'unionid',
'avatar',
'gender'
];
}
@@ -0,0 +1,72 @@
<?php
namespace App\Services\Wechat;
use EasyWeChat\Kernel\Exceptions\HttpException;
use EasyWeChat\MiniApp\Application;
use EasyWeChat\MiniApp\Utils;
/**
* 微信小程序服务基类
*
* 封装 EasyWeChat MiniApp Application,提供单例访问和小程序常用方法。
* 业务模块可继承此类或通过依赖注入使用。
*/
class MiniProgramService
{
protected ?Application $app = null;
/**
* 获取 EasyWeChat MiniApp Application 实例
*/
public function app(): Application
{
if (! $this->app) {
$this->app = new Application(config('wechat.mini_program'));
}
return $this->app;
}
/**
* 获取 Utils 实例(code2Session、解密等)
*/
public function utils(): Utils
{
return $this->app()->getUtils();
}
/**
* 通过 code 换取 session
*
* @return array{openid: string, session_key: string, unionid?: string}
*
* @throws HttpException
*/
public function codeToSession(string $code): array
{
return $this->utils()->codeToSession($code);
}
/**
* 解密加密数据(如用户信息、手机号)
*
* @return array<string, mixed>
*/
public function decryptData(string $sessionKey, string $iv, string $ciphertext): array
{
return $this->utils()->decryptSession($sessionKey, $iv, $ciphertext);
}
/**
* 获取用户手机号
*
* @return array<string, mixed>
*
* @throws HttpException
*/
public function getPhoneNumber(string $code): array
{
return $this->utils()->getPhoneNumber($code);
}
}
+10
View File
@@ -6,6 +6,11 @@ use Modules\Common\Providers\PaginationProvider;
use Modules\SystemAgent\Providers\SystemAgentServiceProvider;
use Modules\SystemTool\Providers\SystemToolServiceProvider;
use Modules\SystemUser\Providers\SystemUserServiceProvider;
use Modules\Member\Providers\MemberServiceProvider;
use Modules\Forum\Providers\ForumServiceProvider;
use Modules\Merchant\Providers\MerchantServiceProvider;
use Modules\Runner\Providers\RunnerServiceProvider;
use Modules\Task\Providers\TaskServiceProvider;
return [
AppServiceProvider::class,
@@ -14,4 +19,9 @@ return [
SystemAgentServiceProvider::class,
SystemUserServiceProvider::class,
SystemToolServiceProvider::class,
MemberServiceProvider::class,
ForumServiceProvider::class,
MerchantServiceProvider::class,
TaskServiceProvider::class,
RunnerServiceProvider::class,
];
+2 -1
View File
@@ -14,7 +14,8 @@
"laravel/framework": "^13.0",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^3.0",
"predis/predis": "2.0"
"predis/predis": "2.0",
"w7corp/easywechat": "^6.19"
},
"require-dev": {
"laravel/boost": "^2.0",
Generated
+1017 -4
View File
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| 微信小程序配置
|--------------------------------------------------------------------------
*/
'mini_program' => [
'app_id' => env('WECHAT_MINI_PROGRAM_APP_ID', ''),
'secret' => env('WECHAT_MINI_PROGRAM_SECRET', ''),
'token' => env('WECHAT_MINI_PROGRAM_TOKEN', ''),
'aes_key' => env('WECHAT_MINI_PROGRAM_AES_KEY', ''),
/**
* HTTP 客户端配置
* 参考:https://symfony.com/doc/current/http_client.html
*/
'http' => [
'throw' => false, // 是否直接抛出异常
'timeout' => 10.0,
'retry' => true, // 失败重试
'max_retries' => 2,
],
],
];
@@ -23,7 +23,7 @@ return new class extends Migration
$table->integer('sex')->default(0)->comment('性别(男、女)');
$table->string('bio', 255)->default('')->nullable()->comment('个人简介');
$table->string('mobile', 20)->default('')->comment('手机号');
$table->string('email', 50)->unique()->comment('邮箱');
$table->string('email', 50)->default('')->comment('邮箱');
$table->timestamp('email_verified_at')->nullable();
$table->integer('dept_id')->default(0)->comment('部门ID');
$table->string('login_ip', 60)->default('')->comment('最后登录IP');
@@ -8,20 +8,19 @@ return new class extends Migration
{
public function up(): void
{
// 话题分类
// 论坛板块
if (! Schema::hasTable('forum_categories')) {
Schema::create('forum_categories', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('parent_id')->default(0)->comment('父级ID');
$table->string('name', 50)->comment('分类名称');
$table->string('slug', 50)->comment('标识');
$table->string('description', 255)->default('')->comment('描述');
$table->string('name', 50)->comment('板块名称');
$table->string('description', 255)->default('')->comment('板块描述');
$table->string('icon', 255)->default('')->comment('图标');
$table->integer('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态:0=禁用,1=正常');
$table->tinyInteger('review')->default(1)->comment('帖子是否审核:0=无需审核,1=需要审核');
$table->tinyInteger('comment_review')->default(1)->comment('评论是否审核:0=无需审核,1=需要审核');
$table->timestamps();
$table->index('slug');
$table->comment('话题分类');
$table->comment('帖子板块');
});
}
@@ -30,7 +29,7 @@ return new class extends Migration
Schema::create('forum_posts', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('user_id')->comment('发布用户ID');
$table->unsignedBigInteger('category_id')->nullable()->comment('分类ID');
$table->unsignedBigInteger('category_id')->nullable()->comment('帖子板块ID');
$table->string('title', 100)->comment('帖子标题');
$table->text('content')->comment('帖子内容');
$table->json('images')->nullable()->comment('图片列表');
@@ -40,7 +39,7 @@ return new class extends Migration
$table->integer('favorite_count')->default(0)->comment('收藏数');
$table->tinyInteger('is_hot')->default(0)->comment('是否热门:0=否,1=是');
$table->tinyInteger('is_top')->default(0)->comment('是否置顶:0=否,1=是');
$table->tinyInteger('status')->default(1)->comment('状态:0=草稿,1=发布,2=隐藏');
$table->tinyInteger('status')->default(1)->comment('状态:1=发布,2=隐藏');
$table->timestamps();
$table->softDeletes();
$table->index('user_id');
@@ -8,14 +8,15 @@ return new class extends Migration
{
public function up(): void
{
// 任务分类
// 任务分类(跑腿/代取/租借等,后台可管理)
if (! Schema::hasTable('task_categories')) {
Schema::create('task_categories', function (Blueprint $table) {
$table->id();
$table->string('name', 50)->comment('分类名称');
$table->string('slug', 50)->comment('标识');
$table->string('slug', 50)->comment('标识:errand=跑腿,pickup=代取,rental=租借');
$table->string('description', 255)->default('')->comment('描述');
$table->string('icon', 255)->default('')->comment('图标');
$table->json('form_schema')->nullable()->comment('分类特有字段模板,前端据此动态渲染表单');
$table->integer('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态:0=禁用,1=正常');
$table->timestamps();
@@ -24,26 +25,37 @@ return new class extends Migration
});
}
// 任务订单(跑腿/代取/租借)
// 任务订单跑腿/代取/租借统一,分类特有字段存 extra
if (! Schema::hasTable('task_orders')) {
Schema::create('task_orders', function (Blueprint $table) {
$table->id();
$table->string('order_no', 32)->comment('订单编号');
$table->unsignedInteger('user_id')->comment('发布用户ID');
$table->unsignedInteger('runner_id')->nullable()->comment('接单用户ID');
$table->unsignedBigInteger('category_id')->comment('分类ID');
$table->unsignedBigInteger('category_id')->comment('任务分类ID');
$table->string('title', 100)->comment('任务标题');
$table->text('description')->comment('任务描述');
$table->text('description')->nullable()->comment('任务描述');
$table->json('images')->nullable()->comment('图片列表');
$table->decimal('price', 10, 2)->default(0)->comment('任务价格/报酬');
$table->json('extra')->nullable()->comment('分类特有字段:跑腿{取件地址,送达地址},代取{取件地点,取件码},租借{押金,租借天数}');
$table->decimal('price', 10, 2)->default(0)->comment('任务报酬');
$table->string('address', 255)->default('')->comment('任务地址');
$table->string('contact_name', 30)->default('')->comment('联系人');
$table->string('contact_mobile', 20)->default('')->comment('联系电话');
$table->timestamp('deadline')->nullable()->comment('截止时间');
// 支付信息(创建订单时支付)
$table->tinyInteger('pay_type')->default(0)->comment('支付方式:0=余额,1=微信支付');
$table->tinyInteger('pay_status')->default(0)->comment('支付状态:0=待支付,1=已支付,2=退款中,3=已退款');
$table->timestamp('paid_at')->nullable()->comment('支付时间');
// 订单状态流转
$table->tinyInteger('status')->default(0)->comment('状态:0=待接单,1=已接单,2=进行中,3=已完成,4=已取消');
$table->string('cancel_reason', 255)->default('')->comment('取消原因');
$table->string('remark', 500)->default('')->comment('订单备注');
$table->timestamp('accepted_at')->nullable()->comment('接单时间');
$table->timestamp('completed_at')->nullable()->comment('完成时间');
$table->timestamp('cancelled_at')->nullable()->comment('取消时间');
$table->timestamps();
$table->softDeletes();
$table->unique('order_no');
@@ -51,29 +63,56 @@ return new class extends Migration
$table->index('runner_id');
$table->index('category_id');
$table->index('status');
$table->index('pay_status');
$table->comment('校园任务订单');
});
}
// 任务竞价/接单报价
// 接单记录/竞价(用户对任务报价或申请接单)
if (! Schema::hasTable('task_bids')) {
Schema::create('task_bids', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('task_id')->comment('任务ID');
$table->unsignedBigInteger('task_id')->comment('任务订单ID');
$table->unsignedInteger('user_id')->comment('接单人ID');
$table->decimal('price', 10, 2)->default(0)->comment('报价');
$table->string('message', 500)->default('')->comment('留言');
$table->decimal('price', 10, 2)->default(0)->comment('报价(等于任务价即为直接接单)');
$table->string('message', 500)->default('')->comment('申请留言/自我介绍');
$table->tinyInteger('status')->default(0)->comment('状态:0=待确认,1=已接受,2=已拒绝');
$table->timestamp('accepted_at')->nullable()->comment('接受时间');
$table->timestamps();
$table->index('task_id');
$table->index('user_id');
$table->comment('任务竞价');
$table->unique(['task_id', 'user_id'], 'uk_task_user');
$table->comment('任务接单/竞价记录');
});
}
// 任务支付日志(支付成功后写入,关联三方支付流水)
if (! Schema::hasTable('task_payments')) {
Schema::create('task_payments', function (Blueprint $table) {
$table->id();
$table->string('payment_no', 32)->comment('支付日志编号');
$table->unsignedBigInteger('order_id')->comment('任务订单ID');
$table->unsignedInteger('user_id')->comment('支付用户ID');
$table->unsignedBigInteger('payment_transaction_id')->nullable()->comment('三方支付流水ID');
$table->decimal('amount', 10, 2)->comment('支付金额');
$table->tinyInteger('pay_type')->comment('支付方式:0=余额,1=微信支付');
$table->tinyInteger('status')->default(0)->comment('状态:0=待支付,1=已支付,2=已退款');
$table->timestamp('paid_at')->nullable()->comment('支付时间');
$table->timestamp('refund_at')->nullable()->comment('退款时间');
$table->timestamps();
$table->unique('payment_no');
$table->index('order_id');
$table->index('user_id');
$table->index('payment_transaction_id');
$table->index('status');
$table->comment('任务支付日志');
});
}
}
public function down(): void
{
Schema::dropIfExists('task_payments');
Schema::dropIfExists('task_bids');
Schema::dropIfExists('task_orders');
Schema::dropIfExists('task_categories');
@@ -8,79 +8,57 @@ return new class extends Migration
{
public function up(): void
{
// 兼职岗位
if (! Schema::hasTable('part_time_jobs')) {
Schema::create('part_time_jobs', function (Blueprint $table) {
// 接单员申请
if (! Schema::hasTable('runner_applications')) {
Schema::create('runner_applications', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('merchant_id')->nullable()->comment('发布商户ID');
$table->string('title', 100)->comment('岗位标题');
$table->text('description')->nullable()->comment('岗位描述');
$table->text('requirements')->nullable()->comment('任职要求');
$table->decimal('salary', 10, 2)->default(0)->comment('薪资');
$table->tinyInteger('salary_type')->default(1)->comment('薪资类型:1=时薪,2=日薪,3=月薪');
$table->string('location', 255)->default('')->comment('工作地点');
$table->string('contact_name', 30)->default('')->comment('联系人');
$table->string('contact_mobile', 20)->default('')->comment('联系电话');
$table->integer('quota')->default(1)->comment('招聘人数');
$table->integer('applied_count')->default(0)->comment('已申请人数');
$table->tinyInteger('status')->default(1)->comment('状态:0=草稿,1=发布,2=已关闭');
$table->date('start_date')->nullable()->comment('开始日期');
$table->date('end_date')->nullable()->comment('截止日期');
$table->timestamps();
$table->index('merchant_id');
$table->index('status');
$table->comment('兼职岗位');
});
}
// 兼职申请/报名
if (! Schema::hasTable('part_time_applications')) {
Schema::create('part_time_applications', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('job_id')->comment('岗位ID');
$table->unsignedInteger('user_id')->comment('申请用户ID');
$table->string('real_name', 30)->comment('真实姓名');
$table->string('mobile', 20)->comment('联系电话');
$table->string('resume', 500)->default('')->comment('个人简介/简历');
$table->string('resume', 500)->default('')->comment('个人简介/申请理由');
$table->string('id_card', 18)->comment('身份证号');
$table->string('id_card_front', 255)->default('')->comment('身份证正面照');
$table->string('id_card_back', 255)->default('')->comment('身份证背面照');
$table->tinyInteger('status')->default(0)->comment('状态:0=待审核,1=已通过,2=已拒绝');
$table->string('review_remark', 255)->default('')->comment('审核备注');
$table->timestamp('reviewed_at')->nullable()->comment('审核时间');
$table->timestamps();
$table->index('job_id');
$table->index('user_id');
$table->comment('兼职申请');
$table->index('mobile');
$table->comment('接单员申请');
});
}
// 兼职人员(已认证)
if (! Schema::hasTable('part_time_workers')) {
Schema::create('part_time_workers', function (Blueprint $table) {
// 接单员列表(审核通过后写入)
if (! Schema::hasTable('runner_workers')) {
Schema::create('runner_workers', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('user_id')->comment('用户ID');
$table->unsignedInteger('user_id')->unique()->comment('用户ID');
$table->string('real_name', 30)->comment('真实姓名');
$table->string('mobile', 20)->comment('联系电话');
$table->string('id_card', 18)->comment('身份证号');
$table->string('id_card_front', 255)->default('')->comment('身份证正面照');
$table->string('id_card_back', 255)->default('')->comment('身份证背面照');
$table->decimal('balance', 10, 2)->default(0)->comment('佣金余额');
$table->decimal('total_income', 10, 2)->default(0)->comment('累计收入');
$table->tinyInteger('status')->default(0)->comment('状态:0=待认证,1=已认证,2=已拒绝');
$table->timestamp('verified_at')->nullable()->comment('认证时间');
$table->integer('total_order')->default(0)->comment('累计完成订单');
$table->integer('cancel_order')->default(0)->comment('累计取消订单');
$table->decimal('credit_score', 10, 2)->default(100)->comment('信誉分(满分100)');
$table->timestamp('verified_at')->nullable()->comment('认证通过时间');
$table->tinyInteger('status')->default(1)->comment('状态:0=禁止接单,1=正常,2=休息中');
$table->timestamps();
$table->index('user_id');
$table->index('mobile');
$table->comment('兼职人员');
$table->index('credit_score');
$table->comment('接单员');
});
}
// 兼职提现
if (! Schema::hasTable('part_time_withdrawals')) {
Schema::create('part_time_withdrawals', function (Blueprint $table) {
// 接单员提现
if (! Schema::hasTable('runner_withdrawals')) {
Schema::create('runner_withdrawals', function (Blueprint $table) {
$table->id();
$table->string('withdraw_no', 32)->comment('提现编号');
$table->unsignedInteger('user_id')->comment('用户ID');
$table->unsignedBigInteger('worker_id')->comment('兼职人员ID');
$table->unsignedBigInteger('worker_id')->comment('接单员ID');
$table->decimal('amount', 10, 2)->comment('提现金额');
$table->decimal('fee', 10, 2)->default(0)->comment('手续费');
$table->string('channel', 20)->comment('提现渠道:wechat=微信,alipay=支付宝,bank=银行卡');
$table->json('account_info')->nullable()->comment('收款账户信息');
$table->tinyInteger('status')->default(0)->comment('状态:0=待审核,1=已通过,2=已完成,3=已拒绝');
@@ -91,16 +69,127 @@ return new class extends Migration
$table->index('user_id');
$table->index('worker_id');
$table->index('status');
$table->comment('兼职提现');
$table->comment('接单员提现');
});
}
// 信誉分变动记录
if (! Schema::hasTable('runner_credit_logs')) {
Schema::create('runner_credit_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('worker_id')->comment('接单员ID');
$table->decimal('score', 5, 2)->comment('变动分值(正=加分,负=扣分)');
$table->decimal('score_after', 5, 2)->comment('变动后分值');
$table->string('type', 30)->comment('变动类型:order_complete=完成订单,order_cancel=取消订单,order_timeout=超时,complaint=被投诉,appeal_success=申诉成功,manual=管理员调整');
$table->string('description', 255)->comment('变动说明');
$table->string('related_type', 30)->nullable()->comment('关联类型');
$table->unsignedBigInteger('related_id')->nullable()->comment('关联ID');
$table->timestamps();
$table->index('worker_id');
$table->index('type');
$table->index(['related_type', 'related_id']);
$table->comment('接单员信誉分记录');
});
}
// 投诉记录
if (! Schema::hasTable('runner_complaints')) {
Schema::create('runner_complaints', function (Blueprint $table) {
$table->id();
$table->string('complaint_no', 32)->comment('投诉编号');
$table->unsignedInteger('user_id')->comment('投诉用户ID');
$table->unsignedBigInteger('worker_id')->comment('被投诉接单员ID');
$table->unsignedBigInteger('order_id')->nullable()->comment('关联任务订单ID');
$table->string('type', 30)->comment('投诉类型:late=迟到/超时,attitude=服务态度,damage=物品损坏,lost=物品丢失,other=其他');
$table->text('content')->comment('投诉内容');
$table->json('images')->nullable()->comment('凭证图片');
$table->tinyInteger('status')->default(0)->comment('状态:0=待处理,1=已处理,2=已驳回');
$table->string('result', 255)->default('')->comment('处理结果');
$table->string('result_remark', 500)->default('')->comment('处理备注');
$table->timestamp('handled_at')->nullable()->comment('处理时间');
$table->timestamps();
$table->unique('complaint_no');
$table->index('user_id');
$table->index('worker_id');
$table->index('order_id');
$table->index('status');
$table->comment('接单员投诉记录');
});
}
// 投诉申诉记录
if (! Schema::hasTable('runner_complaint_appeals')) {
Schema::create('runner_complaint_appeals', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('complaint_id')->comment('投诉ID');
$table->unsignedBigInteger('worker_id')->comment('申诉接单员ID');
$table->text('content')->comment('申诉内容');
$table->json('images')->nullable()->comment('凭证图片');
$table->tinyInteger('status')->default(0)->comment('状态:0=待审核,1=已通过,2=已驳回');
$table->string('reply', 500)->default('')->comment('审核回复');
$table->timestamp('reviewed_at')->nullable()->comment('审核时间');
$table->timestamps();
$table->index('complaint_id');
$table->index('worker_id');
$table->comment('接单员投诉申诉');
});
}
// 接单员保证金
if (! Schema::hasTable('runner_deposits')) {
Schema::create('runner_deposits', function (Blueprint $table) {
$table->id();
$table->string('deposit_no', 32)->comment('保证金编号');
$table->unsignedBigInteger('worker_id')->comment('接单员ID');
$table->unsignedInteger('user_id')->comment('用户ID');
$table->decimal('amount', 10, 2)->comment('保证金金额');
$table->tinyInteger('status')->default(0)->comment('状态:0=未缴纳,1=已缴纳,2=已退还,3=已扣除');
$table->string('deduct_reason', 255)->default('')->comment('扣除原因');
$table->timestamp('paid_at')->nullable()->comment('缴纳时间');
$table->timestamp('refund_at')->nullable()->comment('退还时间');
$table->timestamp('deducted_at')->nullable()->comment('扣除时间');
$table->timestamps();
$table->unique('deposit_no');
$table->index('worker_id');
$table->index('user_id');
$table->index('status');
$table->comment('接单员保证金');
});
}
// 保证金支付日志(支付成功后写入,关联三方支付流水)
if (! Schema::hasTable('deposit_payments')) {
Schema::create('deposit_payments', function (Blueprint $table) {
$table->id();
$table->string('payment_no', 32)->comment('支付日志编号');
$table->unsignedBigInteger('deposit_id')->comment('保证金ID');
$table->unsignedInteger('user_id')->comment('支付用户ID');
$table->unsignedBigInteger('payment_transaction_id')->nullable()->comment('三方支付流水ID');
$table->decimal('amount', 10, 2)->comment('支付金额');
$table->tinyInteger('pay_type')->comment('支付方式:0=余额,1=微信支付');
$table->tinyInteger('status')->default(0)->comment('状态:0=待支付,1=已支付,2=已退款');
$table->timestamp('paid_at')->nullable()->comment('支付时间');
$table->timestamp('refund_at')->nullable()->comment('退款时间');
$table->timestamps();
$table->unique('payment_no');
$table->index('deposit_id');
$table->index('user_id');
$table->index('payment_transaction_id');
$table->index('status');
$table->comment('保证金支付日志');
});
}
}
public function down(): void
{
Schema::dropIfExists('part_time_withdrawals');
Schema::dropIfExists('part_time_workers');
Schema::dropIfExists('part_time_applications');
Schema::dropIfExists('part_time_jobs');
Schema::dropIfExists('deposit_payments');
Schema::dropIfExists('runner_deposits');
Schema::dropIfExists('runner_complaint_appeals');
Schema::dropIfExists('runner_complaints');
Schema::dropIfExists('runner_credit_logs');
Schema::dropIfExists('runner_withdrawals');
Schema::dropIfExists('runner_workers');
Schema::dropIfExists('runner_applications');
}
};
@@ -8,21 +8,6 @@ return new class extends Migration
{
public function up(): void
{
// 商户分类
if (! Schema::hasTable('merchant_categories')) {
Schema::create('merchant_categories', function (Blueprint $table) {
$table->id();
$table->string('name', 50)->comment('分类名称');
$table->string('slug', 50)->comment('标识');
$table->string('description', 255)->default('')->comment('描述');
$table->string('icon', 255)->default('')->comment('图标');
$table->integer('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态:0=禁用,1=正常');
$table->timestamps();
$table->unique('slug');
$table->comment('商户分类');
});
}
// 商户/店铺
if (! Schema::hasTable('merchants')) {
@@ -74,6 +59,22 @@ return new class extends Migration
});
}
// 商户商品分类
if (! Schema::hasTable('platform_categories')) {
Schema::create('platform_categories', function (Blueprint $table) {
$table->id();
$table->string('name', 50)->comment('分类名称');
$table->string('slug', 50)->comment('标识');
$table->string('description', 255)->default('')->comment('描述');
$table->string('icon', 255)->default('')->comment('图标');
$table->integer('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态:0=禁用,1=正常');
$table->timestamps();
$table->unique('slug');
$table->comment('商户分类');
});
}
// 商品
if (! Schema::hasTable('merchant_products')) {
Schema::create('merchant_products', function (Blueprint $table) {
@@ -79,6 +79,29 @@ return new class extends Migration
});
}
// 订单支付日志(支付成功后写入,关联三方支付流水)
if (! Schema::hasTable('order_payments')) {
Schema::create('order_payments', function (Blueprint $table) {
$table->id();
$table->string('payment_no', 32)->comment('支付日志编号');
$table->unsignedBigInteger('order_id')->comment('订单ID');
$table->unsignedInteger('user_id')->comment('支付用户ID');
$table->unsignedBigInteger('payment_transaction_id')->nullable()->comment('三方支付流水ID');
$table->decimal('amount', 10, 2)->comment('支付金额');
$table->tinyInteger('pay_type')->comment('支付方式:0=余额,1=微信支付');
$table->tinyInteger('status')->default(0)->comment('状态:0=待支付,1=已支付,2=已退款');
$table->timestamp('paid_at')->nullable()->comment('支付时间');
$table->timestamp('refund_at')->nullable()->comment('退款时间');
$table->timestamps();
$table->unique('payment_no');
$table->index('order_id');
$table->index('user_id');
$table->index('payment_transaction_id');
$table->index('status');
$table->comment('订单支付日志');
});
}
// 商户提现
if (! Schema::hasTable('merchant_withdrawals')) {
Schema::create('merchant_withdrawals', function (Blueprint $table) {
@@ -103,6 +126,7 @@ return new class extends Migration
public function down(): void
{
Schema::dropIfExists('merchant_withdrawals');
Schema::dropIfExists('order_payments');
Schema::dropIfExists('order_refunds');
Schema::dropIfExists('order_items');
Schema::dropIfExists('orders');
@@ -8,37 +8,28 @@ return new class extends Migration
{
public function up(): void
{
// 钱包
if (! Schema::hasTable('wallets')) {
Schema::create('wallets', function (Blueprint $table) {
// 统一三方支付流水
if (! Schema::hasTable('payment_transactions')) {
Schema::create('payment_transactions', function (Blueprint $table) {
$table->id();
$table->string('owner_type', 30)->comment('所属类型:user=用户,merchant=商户');
$table->unsignedBigInteger('owner_id')->comment('所属ID');
$table->decimal('balance', 10, 2)->default(0)->comment('可用余额');
$table->decimal('frozen_balance', 10, 2)->default(0)->comment('冻结余额');
$table->timestamps();
$table->unique(['owner_type', 'owner_id']);
$table->comment('钱包');
});
}
// 资金流水
if (! Schema::hasTable('transactions')) {
Schema::create('transactions', function (Blueprint $table) {
$table->id();
$table->string('transaction_no', 32)->comment('流水编号');
$table->unsignedBigInteger('wallet_id')->comment('钱包ID');
$table->tinyInteger('type')->comment('类型:1=收入,2=支出');
$table->decimal('amount', 10, 2)->comment('金额');
$table->decimal('balance_after', 10, 2)->comment('交易后余额');
$table->string('description', 255)->comment('描述');
$table->string('related_type', 30)->nullable()->comment('关联类型:order=订单,task=任务,withdrawal=提现,refund=退款');
$table->unsignedBigInteger('related_id')->nullable()->comment('关联ID');
$table->string('transaction_no', 64)->comment('第三方交易号(微信支付transaction_id)');
$table->string('out_trade_no', 32)->comment('商户订单号');
$table->string('pay_type', 20)->comment('支付方式:wechat=微信支付,alipay=支付宝');
$table->decimal('amount', 10, 2)->comment('支付金额');
$table->tinyInteger('status')->default(0)->comment('状态:0=待支付,1=成功,2=失败,3=已退款');
$table->string('business_type', 30)->comment('业务类型:task=任务订单,deposit=保证金,order=商城订单');
$table->unsignedBigInteger('business_id')->nullable()->comment('业务ID');
$table->unsignedInteger('user_id')->comment('支付用户ID');
$table->string('openid', 64)->default('')->comment('微信OpenID');
$table->json('raw_data')->nullable()->comment('支付/退款回调原始数据');
$table->timestamp('paid_at')->nullable()->comment('支付时间');
$table->timestamps();
$table->unique('transaction_no');
$table->index('wallet_id');
$table->index(['related_type', 'related_id']);
$table->comment('资金流水');
$table->unique('out_trade_no');
$table->index('user_id');
$table->index(['business_type', 'business_id']);
$table->index('status');
$table->comment('三方支付流水');
});
}
@@ -65,7 +56,6 @@ return new class extends Migration
public function down(): void
{
Schema::dropIfExists('messages');
Schema::dropIfExists('transactions');
Schema::dropIfExists('wallets');
Schema::dropIfExists('payment_transactions');
}
};
+1
View File
@@ -13,6 +13,7 @@ class DatabaseSeeder extends Seeder
{
$this->call([
SysUserSeeder::class,
SysRuleSeeder::class,
SysDataSeeder::class,
SysAgentSeeder::class,
]);
+839
View File
@@ -0,0 +1,839 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class SysRuleSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// 每次执行前清空权限菜单和角色权限关联
DB::table('sys_role_rule')->delete();
DB::table('sys_rule')->delete();
$rules = [
[
'type' => 'menu',
'name' => '仪表盘',
'key' => 'dashboard',
'icon' => 'PieChartOutlined',
'local' => 'menu.dashboard',
'children' => [
[
'type' => 'route',
'name' => '分析页',
'local' => "menu.analysis",
'key' => 'dashboard.analysis',
'path' => '/dashboard/analysis',
]
]
],
[
'type' => 'menu',
'name' => 'AI',
'local' => "menu.ai",
'icon' => "OpenAIOutlined",
'key' => "ai",
'children' => [
[
'type' => "route",
'key' => "ai.chat",
'name' => "AI对话",
"path" => "/ai/chat",
'local' => "menu.ai.chat",
'children' => [
['type' => 'rule', 'name' => '发送消息', 'key' => 'ai.chat.send'],
['type' => 'rule', 'name' => '会话列表', 'key' => 'ai.chat.conversations'],
['type' => 'rule', 'name' => '消息列表', 'key' => 'ai.chat.messages'],
['type' => 'rule', 'name' => '删除会话', 'key' => 'ai.chat.delete'],
]
],
[
'type' => "route",
'key' => "ai.conversation",
'name' => "会话管理",
"path" => "/ai/conversation",
'local' => "menu.ai.conversation",
'children' => [
['type' => 'rule', 'name' => '查询会话列表', 'key' => 'ai.conversation.query'],
['type' => 'rule', 'name' => '删除会话', 'key' => 'ai.conversation.delete'],
]
],
[
'type' => "route",
'key' => "ai.agent",
'name' => "Agent 管理",
"path" => "/ai/agent",
'local' => "menu.ai.agent",
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'ai.agent.query'],
['type' => 'rule', 'name' => '更新 Agent', 'key' => 'ai.agent.update'],
]
],
]
],
[
'type' => "menu",
'name' => "系统管理",
'local' => "menu.system",
'icon' => "SettingOutlined",
'key' => "system",
'children' => [
[
'type' => "route",
'key' => "system.user",
'name' => "用户管理",
'path' => "/system/user",
'local' => "menu.system.user",
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'system.user.query'],
['type' => 'rule', 'name' => '新增用户', 'key' => 'system.user.create'],
['type' => 'rule', 'name' => '修改用户', 'key' => 'system.user.update'],
['type' => 'rule', 'name' => '删除用户', 'key' => 'system.user.delete'],
['type' => 'rule', 'name' => '重置用户密码', 'key' => 'system.user.resetPassword'],
['type' => 'rule', 'name' => '获取角色选项', 'key' => 'system.user.role'],
['type' => 'rule', 'name' => '获取部门选项', 'key' => 'system.user.dept'],
]
],
[
'type' => "route",
'key' => "system.dept",
'name' => "部门管理",
'path' => "/system/dept",
'local' => "menu.system.dept",
'children' => [
['type' => 'rule', 'name' => '获取部门列表', 'key' => 'system.dept.query'],
['type' => 'rule', 'name' => '新建部门', 'key' => 'system.dept.create'],
['type' => 'rule', 'name' => '更新部门信息', 'key' => 'system.dept.update'],
['type' => 'rule', 'name' => '删除部门', 'key' => 'system.dept.delete'],
['type' => 'rule', 'name' => '获取部门用户', 'key' => 'system.dept.users'],
]
],
[
'type' => "route",
'key' => "system.role",
'name' => "角色管理",
'path' => "/system/role",
'local' => "menu.system.role",
'children' => [
['type' => 'rule', 'name' => '新增角色', 'key' => 'system.role.create'],
['type' => 'rule', 'name' => '查询角色列表', 'key' => 'system.role.query'],
['type' => 'rule', 'name' => '更新角色信息', 'key' => 'system.role.update'],
['type' => 'rule', 'name' => '删除角色', 'key' => 'system.role.delete'],
['type' => 'rule', 'name' => '设置启用状态', 'key' => 'system.role.status'],
['type' => 'rule', 'name' => '获取角色用户', 'key' => 'system.role.users'],
['type' => 'rule', 'name' => '设置角色权限', 'key' => 'system.role.setRule'],
['type' => 'rule', 'name' => '获取权限选项', 'key' => 'system.role.ruleList'],
]
],
[
'type' => "route",
'key' => "system.rule",
'name' => "菜单管理",
'path' => "/system/rule",
'local' => "menu.system.rule",
'children' => [
['type' => 'rule', 'name' => '获取权限列表', 'key' => 'system.rule.query'],
['type' => 'rule', 'name' => '创建权限规则', 'key' => 'system.rule.create'],
['type' => 'rule', 'name' => '更新权限规则', 'key' => 'system.rule.update'],
['type' => 'rule', 'name' => '删除权限规则', 'key' => 'system.rule.delete'],
['type' => 'rule', 'name' => '获取父级权限', 'key' => 'system.rule.parentQuery'],
['type' => 'rule', 'name' => '设置显示状态', 'key' => 'system.rule.show'],
['type' => 'rule', 'name' => '设置启用状态', 'key' => 'system.rule.status'],
]
],
[
'type' => "route",
'name' => "文件管理",
'local' => "menu.system.file",
'key' => "system.file",
'path' => "/system/file",
'children' => [
['type' => 'rule', 'name' => '获取文件夹', 'key' => 'system.file.group.query'],
['type' => 'rule', 'name' => '新增文件夹', 'key' => 'system.file.group.create'],
['type' => 'rule', 'name' => '编辑文件夹', 'key' => 'system.file.group.update'],
['type' => 'rule', 'name' => '删除文件夹', 'key' => 'system.file.group.delete'],
['type' => 'rule', 'name' => '查询文件列表', 'key' => 'system.file.list.query'],
['type' => 'rule', 'name' => '上传文件', 'key' => 'system.file.list.upload'],
['type' => 'rule', 'name' => '下载文件', 'key' => 'system.file.list.download'],
['type' => 'rule', 'name' => '删除文件', 'key' => 'system.file.list.delete'],
['type' => 'rule', 'name' => '永久删除文件', 'key' => 'system.file.list.force-delete'],
['type' => 'rule', 'name' => '恢复文件', 'key' => 'system.file.list.restore'],
['type' => 'rule', 'name' => '查看回收站', 'key' => 'system.file.list.trashed'],
['type' => 'rule', 'name' => '清空回收站', 'key' => 'system.file.list.clean-trashed'],
['type' => 'rule', 'name' => '复制文件', 'key' => 'system.file.list.copy'],
['type' => 'rule', 'name' => '移动文件', 'key' => 'system.file.list.move'],
['type' => 'rule', 'name' => '重命名文件', 'key' => 'system.file.list.rename']
],
],
[
'type' => "route",
'name' => "系统字典",
'local' => "menu.system.dict",
'key' => "system.dict",
'path' => "/system/dict",
'children' => [
['type' => 'rule', 'name' => '字典列表', 'key' => 'system.dict.list.query'],
['type' => 'rule', 'name' => '新增字典', 'key' => 'system.dict.list.create'],
['type' => 'rule', 'name' => '删除字典', 'key' => 'system.dict.list.delete'],
['type' => 'rule', 'name' => '更新字典', 'key' => 'system.dict.list.update'],
['type' => 'rule', 'name' => '字典项列表', 'key' => 'system.dict.item.query'],
['type' => 'rule', 'name' => '字典项新增', 'key' => 'system.dict.item.create'],
['type' => 'rule', 'name' => '字典项编辑', 'key' => 'system.dict.item.update'],
['type' => 'rule', 'name' => '字典项删除', 'key' => 'system.dict.item.delete'],
]
],
[
'type' => "route",
'name' => "系统配置",
'local' => "menu.system.config",
'key' => "system.config",
'path' => "/system/config",
'children' => [
['type' => 'rule', 'name' => '配置列表', 'key' => 'system.config.items.query'],
['type' => 'rule', 'name' => '新增配置', 'key' => 'system.config.items.create'],
['type' => 'rule', 'name' => '编辑配置', 'key' => 'system.config.items.update'],
['type' => 'rule', 'name' => '删除配置', 'key' => 'system.config.items.delete'],
['type' => 'rule', 'name' => '保存配置', 'key' => 'system.config.items.save'],
['type' => 'rule', 'name' => '刷新配置', 'key' => 'system.config.items.refresh'],
['type' => 'rule', 'name' => '配置组编辑', 'key' => 'system.config.group.update'],
['type' => 'rule', 'name' => '配置组删除', 'key' => 'system.config.items.item.delete'],
['type' => 'rule', 'name' => '配置组列表', 'key' => 'system.config.group.query'],
['type' => 'rule', 'name' => '配置组新增', 'key' => 'system.config.group.create'],
]
],
[
'type' => 'route',
'key' => 'system.mail',
'name' => '邮件配置',
'path' => '/system/mail',
'local' => 'menu.system.mail',
'children' => [
['type' => 'rule', 'name' => '获取配置', 'key' => 'system.mail.config'],
['type' => 'rule', 'name' => '保存配置', 'key' => 'system.mail.save'],
['type' => 'rule', 'name' => '发送测试', 'key' => 'system.mail.test'],
]
],
[
'type' => 'route',
'key' => 'system.storage',
'name' => '存储配置',
'path' => '/system/storage',
'local' => 'menu.system.storage',
'children' => [
['type' => 'rule', 'name' => '获取配置', 'key' => 'system.storage.config'],
['type' => 'rule', 'name' => '保存配置', 'key' => 'system.storage.save'],
['type' => 'rule', 'name' => '测试连接', 'key' => 'system.storage.test'],
]
],
[
'type' => 'route',
'key' => 'system.ai',
'name' => 'AI 配置',
'path' => '/system/ai',
'local' => 'menu.system.ai',
'children' => [
['type' => 'rule', 'name' => '获取可用AI列表', 'key' => 'system.ai.list'],
['type' => 'rule', 'name' => '获取AI配置', 'key' => 'system.ai.config'],
['type' => 'rule', 'name' => '保存AI配置', 'key' => 'system.ai.save'],
['type' => 'rule', 'name' => '测试连接', 'key' => 'system.ai.test'],
]
],
[
'type' => "route",
'name' => "系统信息",
'local' => "menu.system.info",
'key' => "system.info",
'path' => "/system/info",
]
]
],
[
'type' => 'menu',
'name' => '小程序用户',
'local' => 'menu.member',
'icon' => 'UserOutlined',
'key' => 'member',
'children' => [
[
'type' => 'route',
'name' => '用户列表',
'key' => 'member.user',
'path' => '/member/user',
'local' => 'menu.member.user',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'member.user.query'],
['type' => 'rule', 'name' => '新增用户', 'key' => 'member.user.create'],
['type' => 'rule', 'name' => '修改用户', 'key' => 'member.user.update'],
['type' => 'rule', 'name' => '删除用户', 'key' => 'member.user.delete'],
],
],
[
'type' => 'route',
'name' => '地址管理',
'key' => 'member.address',
'path' => '/member/address',
'local' => 'menu.member.address',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'member.address.query'],
['type' => 'rule', 'name' => '新增地址', 'key' => 'member.address.create'],
['type' => 'rule', 'name' => '修改地址', 'key' => 'member.address.update'],
['type' => 'rule', 'name' => '删除地址', 'key' => 'member.address.delete'],
],
],
],
],
[
'type' => 'menu',
'name' => '校园论坛',
'local' => 'menu.forum',
'icon' => 'MessageOutlined',
'key' => 'forum',
'children' => [
[
'type' => 'route',
'name' => '话题管理',
'key' => 'forum.category',
'path' => '/forum/category',
'local' => 'menu.forum.category',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'forum.category.query'],
['type' => 'rule', 'name' => '新增分类', 'key' => 'forum.category.create'],
['type' => 'rule', 'name' => '修改分类', 'key' => 'forum.category.update'],
['type' => 'rule', 'name' => '删除分类', 'key' => 'forum.category.delete'],
],
],
[
'type' => 'route',
'name' => '帖子管理',
'key' => 'forum.post',
'path' => '/forum/post',
'local' => 'menu.forum.post',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'forum.post.query'],
['type' => 'rule', 'name' => '新增帖子', 'key' => 'forum.post.create'],
['type' => 'rule', 'name' => '修改帖子', 'key' => 'forum.post.update'],
['type' => 'rule', 'name' => '删除帖子', 'key' => 'forum.post.delete'],
],
],
[
'type' => 'route',
'name' => '评论管理',
'key' => 'forum.comment',
'path' => '/forum/comment',
'local' => 'menu.forum.comment',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'forum.comment.query'],
['type' => 'rule', 'name' => '新增评论', 'key' => 'forum.comment.create'],
['type' => 'rule', 'name' => '修改评论', 'key' => 'forum.comment.update'],
['type' => 'rule', 'name' => '删除评论', 'key' => 'forum.comment.delete'],
],
],
[
'type' => 'route',
'name' => '敏感词管理',
'key' => 'forum.sensitive-word',
'path' => '/forum/sensitive-word',
'local' => 'menu.forum.sensitive-word',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'forum.sensitive-word.query'],
['type' => 'rule', 'name' => '新增敏感词', 'key' => 'forum.sensitive-word.create'],
['type' => 'rule', 'name' => '修改敏感词', 'key' => 'forum.sensitive-word.update'],
['type' => 'rule', 'name' => '删除敏感词', 'key' => 'forum.sensitive-word.delete'],
],
],
[
'type' => 'route',
'name' => '点赞记录',
'key' => 'forum.post-like',
'path' => '/forum/post-like',
'local' => 'menu.forum.post-like',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'forum.post-like.query'],
['type' => 'rule', 'name' => '删除记录', 'key' => 'forum.post-like.delete'],
],
],
[
'type' => 'route',
'name' => '收藏记录',
'key' => 'forum.post-favorite',
'path' => '/forum/post-favorite',
'local' => 'menu.forum.post-favorite',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'forum.post-favorite.query'],
['type' => 'rule', 'name' => '删除记录', 'key' => 'forum.post-favorite.delete'],
],
],
],
],
[
'type' => 'menu',
'name' => '校园商户',
'local' => 'menu.merchant',
'icon' => 'ShopOutlined',
'key' => 'merchant',
'children' => [
[
'type' => 'route',
'name' => '商户分类',
'key' => 'merchant.category',
'path' => '/merchant/category',
'local' => 'menu.merchant.category',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.category.query'],
['type' => 'rule', 'name' => '新增分类', 'key' => 'merchant.category.create'],
['type' => 'rule', 'name' => '修改分类', 'key' => 'merchant.category.update'],
['type' => 'rule', 'name' => '删除分类', 'key' => 'merchant.category.delete'],
],
],
[
'type' => 'route',
'name' => '商户管理',
'key' => 'merchant.store',
'path' => '/merchant/store',
'local' => 'menu.merchant.store',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.store.query'],
['type' => 'rule', 'name' => '新增商户', 'key' => 'merchant.store.create'],
['type' => 'rule', 'name' => '修改商户', 'key' => 'merchant.store.update'],
['type' => 'rule', 'name' => '删除商户', 'key' => 'merchant.store.delete'],
],
],
[
'type' => 'route',
'name' => '商品分类',
'key' => 'merchant.product-category',
'path' => '/merchant/product-category',
'local' => 'menu.merchant.product-category',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.product-category.query'],
['type' => 'rule', 'name' => '新增分类', 'key' => 'merchant.product-category.create'],
['type' => 'rule', 'name' => '修改分类', 'key' => 'merchant.product-category.update'],
['type' => 'rule', 'name' => '删除分类', 'key' => 'merchant.product-category.delete'],
],
],
[
'type' => 'route',
'name' => '商品管理',
'key' => 'merchant.product',
'path' => '/merchant/product',
'local' => 'menu.merchant.product',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.product.query'],
['type' => 'rule', 'name' => '新增商品', 'key' => 'merchant.product.create'],
['type' => 'rule', 'name' => '修改商品', 'key' => 'merchant.product.update'],
['type' => 'rule', 'name' => '删除商品', 'key' => 'merchant.product.delete'],
],
],
[
'type' => 'route',
'name' => '打印机管理',
'key' => 'merchant.printer',
'path' => '/merchant/printer',
'local' => 'menu.merchant.printer',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.printer.query'],
['type' => 'rule', 'name' => '新增打印机', 'key' => 'merchant.printer.create'],
['type' => 'rule', 'name' => '修改打印机', 'key' => 'merchant.printer.update'],
['type' => 'rule', 'name' => '删除打印机', 'key' => 'merchant.printer.delete'],
],
],
[
'type' => 'route',
'name' => '打印任务',
'key' => 'merchant.print-task',
'path' => '/merchant/print-task',
'local' => 'menu.merchant.print-task',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.print-task.query'],
['type' => 'rule', 'name' => '删除任务', 'key' => 'merchant.print-task.delete'],
],
],
[
'type' => 'route',
'name' => '订单管理',
'key' => 'merchant.order',
'path' => '/merchant/order',
'local' => 'menu.merchant.order',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.order.query'],
['type' => 'rule', 'name' => '新增订单', 'key' => 'merchant.order.create'],
['type' => 'rule', 'name' => '修改订单', 'key' => 'merchant.order.update'],
['type' => 'rule', 'name' => '删除订单', 'key' => 'merchant.order.delete'],
],
],
[
'type' => 'route',
'name' => '订单退款',
'key' => 'merchant.refund',
'path' => '/merchant/refund',
'local' => 'menu.merchant.refund',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.refund.query'],
['type' => 'rule', 'name' => '处理退款', 'key' => 'merchant.refund.update'],
['type' => 'rule', 'name' => '删除记录', 'key' => 'merchant.refund.delete'],
],
],
],
],
// 校园任务
[
'type' => 'menu',
'key' => 'task',
'name' => '校园任务',
'icon' => 'ThunderboltOutlined',
'local' => 'menu.task',
'children' => [
// 任务分类
[
'type' => 'route', 'key' => 'task.category', 'name' => '任务分类',
'path' => '/task/category', 'local' => 'menu.task.category',
'children' => [
['type' => 'rule', 'key' => 'task.category.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'task.category.create', 'name' => '创建'],
['type' => 'rule', 'key' => 'task.category.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'task.category.delete', 'name' => '删除'],
],
],
// 跑腿订单
[
'type' => 'route', 'key' => 'task.order_errand', 'name' => '跑腿订单',
'path' => '/task/order-errand', 'local' => 'menu.task.order_errand',
'children' => [
['type' => 'rule', 'key' => 'task.order.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'task.order.create', 'name' => '创建'],
['type' => 'rule', 'key' => 'task.order.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'task.order.delete', 'name' => '删除'],
],
],
// 代取订单
[
'type' => 'route', 'key' => 'task.order_pickup', 'name' => '代取订单',
'path' => '/task/order-pickup', 'local' => 'menu.task.order_pickup',
],
// 租借订单
[
'type' => 'route', 'key' => 'task.order_rental', 'name' => '租借订单',
'path' => '/task/order-rental', 'local' => 'menu.task.order_rental',
],
// 接单记录
[
'type' => 'route', 'key' => 'task.bid', 'name' => '接单记录',
'path' => '/task/bid', 'local' => 'menu.task.bid',
'children' => [
['type' => 'rule', 'key' => 'task.bid.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'task.bid.create', 'name' => '创建'],
['type' => 'rule', 'key' => 'task.bid.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'task.bid.delete', 'name' => '删除'],
],
],
],
],
// 接单员管理
[
'type' => 'menu',
'key' => 'runner',
'name' => '接单员管理',
'icon' => 'TeamOutlined',
'local' => 'menu.runner',
'children' => [
// 接单员申请
[
'type' => 'route', 'key' => 'runner.application', 'name' => '接单员申请',
'path' => '/runner/application', 'local' => 'menu.runner.application',
'children' => [
['type' => 'rule', 'key' => 'runner.application.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'runner.application.create', 'name' => '创建'],
['type' => 'rule', 'key' => 'runner.application.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'runner.application.delete', 'name' => '删除'],
],
],
// 接单员列表 (query/update/delete)
[
'type' => 'route', 'key' => 'runner.worker', 'name' => '接单员列表',
'path' => '/runner/worker', 'local' => 'menu.runner.worker',
'children' => [
['type' => 'rule', 'key' => 'runner.worker.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'runner.worker.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'runner.worker.delete', 'name' => '删除'],
],
],
// 信誉分记录 (query only)
[
'type' => 'route', 'key' => 'runner.credit_log', 'name' => '信誉分记录',
'path' => '/runner/credit-log', 'local' => 'menu.runner.credit_log',
'children' => [
['type' => 'rule', 'key' => 'runner.credit_log.query', 'name' => '查询'],
],
],
// 投诉记录
[
'type' => 'route', 'key' => 'runner.complaint', 'name' => '投诉记录',
'path' => '/runner/complaint', 'local' => 'menu.runner.complaint',
'children' => [
['type' => 'rule', 'key' => 'runner.complaint.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'runner.complaint.create', 'name' => '创建'],
['type' => 'rule', 'key' => 'runner.complaint.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'runner.complaint.delete', 'name' => '删除'],
],
],
// 投诉申诉
[
'type' => 'route', 'key' => 'runner.complaint_appeal', 'name' => '投诉申诉',
'path' => '/runner/complaint-appeal', 'local' => 'menu.runner.complaint_appeal',
'children' => [
['type' => 'rule', 'key' => 'runner.complaint_appeal.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'runner.complaint_appeal.create', 'name' => '创建'],
['type' => 'rule', 'key' => 'runner.complaint_appeal.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'runner.complaint_appeal.delete', 'name' => '删除'],
],
],
],
],
// 财务管理
[
'type' => 'menu',
'key' => 'finance',
'name' => '财务管理',
'icon' => 'AccountBookOutlined',
'local' => 'menu.finance',
'children' => [
// 任务支付日志 (query/delete)
[
'type' => 'route', 'key' => 'task.payment', 'name' => '任务支付日志',
'path' => '/finance/task-payment', 'local' => 'menu.finance.task_payment',
'children' => [
['type' => 'rule', 'key' => 'task.payment.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'task.payment.delete', 'name' => '删除'],
],
],
// 保证金管理 (query/update/delete)
[
'type' => 'route', 'key' => 'runner.deposit', 'name' => '保证金管理',
'path' => '/finance/deposit', 'local' => 'menu.finance.deposit',
'children' => [
['type' => 'rule', 'key' => 'runner.deposit.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'runner.deposit.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'runner.deposit.delete', 'name' => '删除'],
],
],
// 保证金支付日志 (query/delete)
[
'type' => 'route', 'key' => 'runner.deposit_payment', 'name' => '保证金支付日志',
'path' => '/finance/deposit-payment', 'local' => 'menu.finance.deposit_payment',
'children' => [
['type' => 'rule', 'key' => 'runner.deposit_payment.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'runner.deposit_payment.delete', 'name' => '删除'],
],
],
// 接单员提现 (query/update/delete)
[
'type' => 'route', 'key' => 'runner.withdrawal', 'name' => '接单员提现',
'path' => '/finance/withdrawal', 'local' => 'menu.finance.withdrawal',
'children' => [
['type' => 'rule', 'key' => 'runner.withdrawal.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'runner.withdrawal.update', 'name' => '编辑'],
['type' => 'rule', 'key' => 'runner.withdrawal.delete', 'name' => '删除'],
],
],
// 资金流水 (query only)
[
'type' => 'route', 'key' => 'finance.transaction', 'name' => '资金流水',
'path' => '/finance/transaction', 'local' => 'menu.finance.transaction',
'children' => [
['type' => 'rule', 'key' => 'finance.transaction.query', 'name' => '查询'],
['type' => 'rule', 'key' => 'finance.transaction.delete', 'name' => '删除'],
],
],
[
'type' => 'route',
'name' => '订单支付日志',
'key' => 'merchant.order_payment',
'path' => '/finance/order-payment',
'local' => 'menu.finance.order_payment',
'children' => [
['type' => 'rule', 'name' => '查询', 'key' => 'merchant.order_payment.query'],
['type' => 'rule', 'name' => '删除', 'key' => 'merchant.order_payment.delete'],
],
],
[
'type' => 'route',
'name' => '商户提现',
'key' => 'merchant.withdrawal',
'path' => '/finance/merchant-withdrawal',
'local' => 'menu.finance.merchant_withdrawal',
'children' => [
['type' => 'rule', 'name' => '查询', 'key' => 'merchant.withdrawal.query'],
['type' => 'rule', 'name' => '审核', 'key' => 'merchant.withdrawal.update'],
['type' => 'rule', 'name' => '删除', 'key' => 'merchant.withdrawal.delete'],
],
],
],
],
[
'type' => 'menu',
'name' => '商户管理',
'local' => 'menu.merchant_portal',
'icon' => 'ShopOutlined',
'key' => 'merchant.portal',
'children' => [
[
'type' => 'route',
'name' => '商品列表',
'key' => 'merchant.portal.product',
'path' => '/merchant-portal/product',
'local' => 'menu.merchant_portal.product',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.portal.product.query'],
['type' => 'rule', 'name' => '新增商品', 'key' => 'merchant.portal.product.create'],
['type' => 'rule', 'name' => '修改商品', 'key' => 'merchant.portal.product.update'],
['type' => 'rule', 'name' => '删除商品', 'key' => 'merchant.portal.product.delete'],
],
],
[
'type' => 'route',
'name' => '商品分类',
'key' => 'merchant.portal.product-category',
'path' => '/merchant-portal/product-category',
'local' => 'menu.merchant_portal.product-category',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.portal.product-category.query'],
['type' => 'rule', 'name' => '新增分类', 'key' => 'merchant.portal.product-category.create'],
['type' => 'rule', 'name' => '修改分类', 'key' => 'merchant.portal.product-category.update'],
['type' => 'rule', 'name' => '删除分类', 'key' => 'merchant.portal.product-category.delete'],
],
],
[
'type' => 'route',
'name' => '订单列表',
'key' => 'merchant.portal.order',
'path' => '/merchant-portal/order',
'local' => 'menu.merchant_portal.order',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.portal.order.query'],
],
],
[
'type' => 'route',
'name' => '交易流水',
'key' => 'merchant.portal.payment',
'path' => '/merchant-portal/payment',
'local' => 'menu.merchant_portal.payment',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.portal.payment.query'],
],
],
[
'type' => 'route',
'name' => '打印机管理',
'key' => 'merchant.portal.printer',
'path' => '/merchant-portal/printer',
'local' => 'menu.merchant_portal.printer',
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'merchant.portal.printer.query'],
['type' => 'rule', 'name' => '新增打印机', 'key' => 'merchant.portal.printer.create'],
['type' => 'rule', 'name' => '修改打印机', 'key' => 'merchant.portal.printer.update'],
['type' => 'rule', 'name' => '删除打印机', 'key' => 'merchant.portal.printer.delete'],
],
],
[
'type' => 'route',
'name' => '商户信息',
'key' => 'merchant.portal.store',
'path' => '/merchant-portal/store',
'local' => 'menu.merchant_portal.store',
'children' => [
['type' => 'rule', 'name' => '查看信息', 'key' => 'merchant.portal.store.query'],
['type' => 'rule', 'name' => '修改信息', 'key' => 'merchant.portal.store.update'],
],
],
],
],
[
'type' => 'route',
'name' => 'XinAdmin',
'local' => "menu.xin-admin",
'key' => "xin-admin",
'icon' => "LinkOutlined",
'link' => 1,
'path' => 'https://xinadmin.cn',
]
];
$this->insertRules($rules);
// 为超级管理员(role_id=1)授予全部启用权限
DB::table('sys_role_rule')->insertUsing(
['role_id', 'rule_id'],
DB::table('sys_rule')
->where('status', 1)
->select(DB::raw('1 as role_id'), 'id')
);
// 为商户角色分配 merchant.portal.* 及 dashboard 权限
$portalRuleIds = DB::table('sys_rule')
->where('status', 1)
->where(function ($query) {
$query->where('key', 'LIKE', 'merchant.portal%')
->orWhere('key', 'dashboard')
->orWhere('key', 'dashboard.analysis');
})
->pluck('id');
DB::table('sys_role_rule')->insert(
$portalRuleIds->map(fn ($ruleId) => [
'role_id' => 3,
'rule_id' => $ruleId,
])->toArray()
);
// 为管理员角色分配所有启用权限,排除 merchant.portal.*(商户门户权限)
$adminRuleIds = DB::table('sys_rule')
->where('status', 1)
->where('key', 'NOT LIKE', 'merchant.portal%')
->pluck('id');
DB::table('sys_role_rule')->insert(
$adminRuleIds->map(fn ($ruleId) => [
'role_id' => 2,
'rule_id' => $ruleId,
])->toArray()
);
}
/**
* 递归插入权限规则数据
*/
private function insertRules(array $rules, int $pid = 0): void
{
$order = 0;
foreach ($rules as $rule) {
$insertData = [
'parent_id' => $pid,
'type' => $rule['type'],
'key' => $rule['key'],
'name' => $rule['name'],
'path' => $rule['path'] ?? '',
'icon' => $rule['icon'] ?? '',
'order' => $order++,
'local' => $rule['local'] ?? '',
'status' => 1,
'hidden' => 1,
'link' => $rule['link'] ?? 0,
'created_at' => now(),
'updated_at' => now(),
];
$currentId = DB::table('sys_rule')->insertGetId($insertData);
if (! empty($rule['children']) && is_array($rule['children'])) {
$this->insertRules($rule['children'], $currentId);
}
}
}
}
+8 -361
View File
@@ -18,8 +18,8 @@ class SysUserSeeder extends Seeder
DB::table('sys_user')->insert([
[
'id' => 1,
'username' => 'admin',
'nickname' => '管理员',
'username' => 'super_admin',
'nickname' => '超级管理员',
'email' => Str::random(10).'@example.com',
'password' => Hash::make('123456'),
'dept_id' => 1,
@@ -31,11 +31,11 @@ class SysUserSeeder extends Seeder
],
[
'id' => 2,
'username' => 'user',
'nickname' => '财务',
'username' => 'admin',
'nickname' => '管理员',
'email' => Str::random(10).'@example.com',
'password' => Hash::make('123456'),
'dept_id' => 2,
'dept_id' => 1,
'avatar_id' => 1,
'email_verified_at' => now(),
'remember_token' => Str::random(10),
@@ -45,9 +45,8 @@ class SysUserSeeder extends Seeder
]);
DB::table('sys_role')->insert([
['id' => 1, 'name' => '超级管理员', 'created_at' => $date, 'updated_at' => $date],
['id' => 2, 'name' => '财务', 'created_at' => $date, 'updated_at' => $date],
['id' => 3, 'name' => '电商总监', 'created_at' => $date, 'updated_at' => $date],
['id' => 4, 'name' => '市场运营', 'created_at' => $date, 'updated_at' => $date],
['id' => 2, 'name' => '管理员', 'created_at' => $date, 'updated_at' => $date],
['id' => 3, 'name' => '商户', 'created_at' => $date, 'updated_at' => $date],
]);
DB::table('sys_dept')->insert([
[
@@ -63,322 +62,9 @@ class SysUserSeeder extends Seeder
'remark' => '总公司',
'created_at' => $date,
'updated_at' => $date
],
[
'id' => 2,
'name' => '新时代软件技术(洛阳)有限公司',
'code' => 'A01-B01',
'type' => 0,
'parent_id' => 1,
'sort' => 0,
'phone' => '19999999999',
'email' => Str::random(10).'@example.com',
'address' => '河南省洛阳市龙门区某某街道99号',
'remark' => '洛阳市分公司',
'created_at' => $date,
'updated_at' => $date
],
[
'id' => 3,
'name' => '新时代智能科技(郑州)有限公司',
'code' => 'A01-B02',
'type' => 0,
'parent_id' => 1,
'sort' => 0,
'phone' => '19999999999',
'email' => Str::random(10).'@example.com',
'address' => '河南省郑州市二七区某某街道69号',
'remark' => '郑州市分公司',
'created_at' => $date,
'updated_at' => $date
],
[
'id' => 4,
'name' => '新征程科技(南阳)有限公司',
'code' => 'A01-B03',
'type' => 0,
'parent_id' => 1,
'sort' => 2,
'phone' => '19999999999',
'email' => Str::random(10).'@example.com',
'address' => '河南省南阳市卧龙区某某街道77号',
'remark' => '南阳市分公司',
'created_at' => $date,
'updated_at' => $date
],
[
'id' => 5,
'name' => '新时代投资发展有限公司',
'code' => 'B01',
'type' => 0,
'parent_id' => 0,
'sort' => 2,
'phone' => '19999999999',
'email' => Str::random(10).'@example.com',
'address' => '北京市海淀区人民路666号',
'remark' => '我们坚信,卓越的投资在于发现价值,而卓越的投资管理在于创造价值。我们立志成为科技创业者身边最懂业务、最能赋能、最长情的资本伙伴,共同将创新的火种,转化为引领行业的参天大树。',
'created_at' => $date,
'updated_at' => $date
],
]
]);
$rules = [
[
'type' => 'menu',
'name' => '仪表盘',
'key' => 'dashboard',
'icon' => 'PieChartOutlined',
'local' => 'menu.dashboard',
'children' => [
[
'type' => 'route',
'name' => '分析页',
'local' => "menu.analysis",
'key' => 'dashboard.analysis',
'path' => '/dashboard/analysis',
]
]
],
[
'type' => 'menu',
'name' => 'AI',
'local' => "menu.ai",
'icon' => "OpenAIOutlined",
'key' => "ai",
'children' => [
[
'type' => "route",
'key' => "ai.chat",
'name' => "AI对话",
"path" => "/ai/chat",
'local' => "menu.ai.chat",
'children' => [
['type' => 'rule', 'name' => '发送消息', 'key' => 'ai.chat.send'],
['type' => 'rule', 'name' => '会话列表', 'key' => 'ai.chat.conversations'],
['type' => 'rule', 'name' => '消息列表', 'key' => 'ai.chat.messages'],
['type' => 'rule', 'name' => '删除会话', 'key' => 'ai.chat.delete'],
]
],
[
'type' => "route",
'key' => "ai.conversation",
'name' => "会话管理",
"path" => "/ai/conversation",
'local' => "menu.ai.conversation",
'children' => [
['type' => 'rule', 'name' => '查询会话列表', 'key' => 'ai.conversation.query'],
['type' => 'rule', 'name' => '删除会话', 'key' => 'ai.conversation.delete'],
]
],
[
'type' => "route",
'key' => "ai.agent",
'name' => "Agent 管理",
"path" => "/ai/agent",
'local' => "menu.ai.agent",
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'ai.agent.query'],
['type' => 'rule', 'name' => '更新 Agent', 'key' => 'ai.agent.update'],
]
],
]
],
[
'type' => "menu",
'name' => "系统管理",
'local' => "menu.system",
'icon' => "SettingOutlined",
'key' => "system",
'children' => [
[
'type' => "route",
'key' => "system.user",
'name' => "用户管理",
'path' => "/system/user",
'local' => "menu.system.user",
'children' => [
['type' => 'rule', 'name' => '查询列表', 'key' => 'system.user.query'],
['type' => 'rule', 'name' => '新增用户', 'key' => 'system.user.create'],
['type' => 'rule', 'name' => '修改用户', 'key' => 'system.user.update'],
['type' => 'rule', 'name' => '删除用户', 'key' => 'system.user.delete'],
['type' => 'rule', 'name' => '重置用户密码', 'key' => 'system.user.resetPassword'],
['type' => 'rule', 'name' => '获取角色选项', 'key' => 'system.user.role'],
['type' => 'rule', 'name' => '获取部门选项', 'key' => 'system.user.dept'],
]
],
[
'type' => "route",
'key' => "system.dept",
'name' => "部门管理",
'path' => "/system/dept",
'local' => "menu.system.dept",
'children' => [
['type' => 'rule', 'name' => '获取部门列表', 'key' => 'system.dept.query'],
['type' => 'rule', 'name' => '新建部门', 'key' => 'system.dept.create'],
['type' => 'rule', 'name' => '更新部门信息', 'key' => 'system.dept.update'],
['type' => 'rule', 'name' => '删除部门', 'key' => 'system.dept.delete'],
['type' => 'rule', 'name' => '获取部门用户', 'key' => 'system.dept.users'],
]
],
[
'type' => "route",
'key' => "system.role",
'name' => "角色管理",
'path' => "/system/role",
'local' => "menu.system.role",
'children' => [
['type' => 'rule', 'name' => '新增角色', 'key' => 'system.role.create'],
['type' => 'rule', 'name' => '查询角色列表', 'key' => 'system.role.query'],
['type' => 'rule', 'name' => '更新角色信息', 'key' => 'system.role.update'],
['type' => 'rule', 'name' => '删除角色', 'key' => 'system.role.delete'],
['type' => 'rule', 'name' => '设置启用状态', 'key' => 'system.role.status'],
['type' => 'rule', 'name' => '获取角色用户', 'key' => 'system.role.users'],
['type' => 'rule', 'name' => '设置角色权限', 'key' => 'system.role.setRule'],
['type' => 'rule', 'name' => '获取权限选项', 'key' => 'system.role.ruleList'],
]
],
[
'type' => "route",
'key' => "system.rule",
'name' => "菜单管理",
'path' => "/system/rule",
'local' => "menu.system.rule",
'children' => [
['type' => 'rule', 'name' => '获取权限列表', 'key' => 'system.rule.query'],
['type' => 'rule', 'name' => '创建权限规则', 'key' => 'system.rule.create'],
['type' => 'rule', 'name' => '更新权限规则', 'key' => 'system.rule.update'],
['type' => 'rule', 'name' => '删除权限规则', 'key' => 'system.rule.delete'],
['type' => 'rule', 'name' => '获取父级权限', 'key' => 'system.rule.parentQuery'],
['type' => 'rule', 'name' => '设置显示状态', 'key' => 'system.rule.show'],
['type' => 'rule', 'name' => '设置启用状态', 'key' => 'system.rule.status'],
]
],
[
'type' => "route",
'name' => "文件管理",
'local' => "menu.system.file",
'key' => "system.file",
'path' => "/system/file",
'children' => [
['type' => 'rule', 'name' => '获取文件夹', 'key' => 'system.file.group.query'],
['type' => 'rule', 'name' => '新增文件夹', 'key' => 'system.file.group.create'],
['type' => 'rule', 'name' => '编辑文件夹', 'key' => 'system.file.group.update'],
['type' => 'rule', 'name' => '删除文件夹', 'key' => 'system.file.group.delete'],
['type' => 'rule', 'name' => '查询文件列表', 'key' => 'system.file.list.query'],
['type' => 'rule', 'name' => '上传文件', 'key' => 'system.file.list.upload'],
['type' => 'rule', 'name' => '下载文件', 'key' => 'system.file.list.download'],
['type' => 'rule', 'name' => '删除文件', 'key' => 'system.file.list.delete'],
['type' => 'rule', 'name' => '永久删除文件', 'key' => 'system.file.list.force-delete'],
['type' => 'rule', 'name' => '恢复文件', 'key' => 'system.file.list.restore'],
['type' => 'rule', 'name' => '查看回收站', 'key' => 'system.file.list.trashed'],
['type' => 'rule', 'name' => '清空回收站', 'key' => 'system.file.list.clean-trashed'],
['type' => 'rule', 'name' => '复制文件', 'key' => 'system.file.list.copy'],
['type' => 'rule', 'name' => '移动文件', 'key' => 'system.file.list.move'],
['type' => 'rule', 'name' => '重命名文件', 'key' => 'system.file.list.rename']
],
],
[
'type' => "route",
'name' => "系统字典",
'local' => "menu.system.dict",
'key' => "system.dict",
'path' => "/system/dict",
'children' => [
['type' => 'rule', 'name' => '字典列表', 'key' => 'system.dict.list.query'],
['type' => 'rule', 'name' => '新增字典', 'key' => 'system.dict.list.create'],
['type' => 'rule', 'name' => '删除字典', 'key' => 'system.dict.list.delete'],
['type' => 'rule', 'name' => '更新字典', 'key' => 'system.dict.list.update'],
['type' => 'rule', 'name' => '字典项列表', 'key' => 'system.dict.item.query'],
['type' => 'rule', 'name' => '字典项新增', 'key' => 'system.dict.item.create'],
['type' => 'rule', 'name' => '字典项编辑', 'key' => 'system.dict.item.update'],
['type' => 'rule', 'name' => '字典项删除', 'key' => 'system.dict.item.delete'],
]
],
[
'type' => "route",
'name' => "系统配置",
'local' => "menu.system.config",
'key' => "system.config",
'path' => "/system/config",
'children' => [
['type' => 'rule', 'name' => '配置列表', 'key' => 'system.config.items.query'],
['type' => 'rule', 'name' => '新增配置', 'key' => 'system.config.items.create'],
['type' => 'rule', 'name' => '编辑配置', 'key' => 'system.config.items.update'],
['type' => 'rule', 'name' => '删除配置', 'key' => 'system.config.items.delete'],
['type' => 'rule', 'name' => '保存配置', 'key' => 'system.config.items.save'],
['type' => 'rule', 'name' => '刷新配置', 'key' => 'system.config.items.refresh'],
['type' => 'rule', 'name' => '配置组编辑', 'key' => 'system.config.group.update'],
['type' => 'rule', 'name' => '配置组删除', 'key' => 'system.config.items.item.delete'],
['type' => 'rule', 'name' => '配置组列表', 'key' => 'system.config.group.query'],
['type' => 'rule', 'name' => '配置组新增', 'key' => 'system.config.group.create'],
]
],
[
'type' => 'route',
'key' => 'system.mail',
'name' => '邮件配置',
'path' => '/system/mail',
'local' => 'menu.system.mail',
'children' => [
['type' => 'rule', 'name' => '获取配置', 'key' => 'system.mail.config'],
['type' => 'rule', 'name' => '保存配置', 'key' => 'system.mail.save'],
['type' => 'rule', 'name' => '发送测试', 'key' => 'system.mail.test'],
]
],
[
'type' => 'route',
'key' => 'system.storage',
'name' => '存储配置',
'path' => '/system/storage',
'local' => 'menu.system.storage',
'children' => [
['type' => 'rule', 'name' => '获取配置', 'key' => 'system.storage.config'],
['type' => 'rule', 'name' => '保存配置', 'key' => 'system.storage.save'],
['type' => 'rule', 'name' => '测试连接', 'key' => 'system.storage.test'],
]
],
[
'type' => 'route',
'key' => 'system.ai',
'name' => 'AI 配置',
'path' => '/system/ai',
'local' => 'menu.system.ai',
'children' => [
['type' => 'rule', 'name' => '获取可用AI列表', 'key' => 'system.ai.list'],
['type' => 'rule', 'name' => '获取AI配置', 'key' => 'system.ai.config'],
['type' => 'rule', 'name' => '保存AI配置', 'key' => 'system.ai.save'],
['type' => 'rule', 'name' => '测试连接', 'key' => 'system.ai.test'],
]
],
[
'type' => "route",
'name' => "系统信息",
'local' => "menu.system.info",
'key' => "system.info",
'path' => "/system/info",
]
]
],
[
'type' => 'route',
'name' => 'XinAdmin',
'local' => "menu.xin-admin",
'key' => "xin-admin",
'icon' => "LinkOutlined",
'link' => 1,
'path' => 'https://xinadmin.cn',
]
];
$this->insertRules($rules);
DB::table('sys_role_rule')->insertUsing(
['role_id', 'rule_id'],
DB::table('sys_rule')
->where('status', 1)
->select(DB::raw('1 as role_id'), 'id')
);
DB::table('sys_user_role')->insert([
[
'user_id' => 1,
@@ -390,43 +76,4 @@ class SysUserSeeder extends Seeder
]
]);
}
/**
* 递归插入权限规则数据
*
* @param array $rules 规则数据
* @param int $pid 父级ID,默认为0(顶级)
* @return void
*/
function insertRules(array $rules, int $pid = 0): void
{
$order = 0;
foreach ($rules as $rule) {
// 准备插入数据
$insertData = [
'parent_id' => $pid,
'type' => $rule['type'],
'key' => $rule['key'],
'name' => $rule['name'],
'path' => $rule['path'] ?? '',
'icon' => $rule['icon'] ?? '',
'order' => $order++,
'local' => $rule['local'] ?? '',
'status' => 1,
'hidden' => 1,
'link' => $rule['link'] ?? 0,
'created_at' => now(),
'updated_at' => now(),
];
// 插入数据并获取插入的ID
$currentId = DB::table('sys_rule')->insertGetId($insertData);
// 如果有子菜单,递归插入
if (!empty($rule['children']) && is_array($rule['children'])) {
$this->insertRules($rule['children'], $currentId);
}
}
}
}
+2 -1
View File
@@ -108,9 +108,10 @@ class RouteRegisterService
} else {
$authMiddleware[] = 'authGuard';
}
if (is_string($authorize) && !empty($abilitiesPrefix)) {
$authMiddleware[] = 'abilities:' . $abilitiesPrefix . '.' . $authorize;
} else {
} else if ($authorize !== true) {
$authMiddleware[] = 'abilities:' . $authorize;
}
}
@@ -167,8 +167,8 @@ class GenerateRouteHelperCommand extends Command
if (is_string($authorize) && !empty($abilitiesPrefix)) {
$authMiddleware[] = 'abilities:' . $abilitiesPrefix . '.' . $authorize;
} else {
$authMiddleware[] = 'abilities:' . (is_string($authorize) ? $authorize : '');
} else if($authorize !== true) {
$authMiddleware[] = 'abilities:' . $authorize;
}
return $authMiddleware;
@@ -0,0 +1,73 @@
<?php
namespace Modules\Forum\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Forum\Http\Requests\ForumCategoryFormRequest;
use Modules\Forum\Models\ForumCategoryModel;
#[RequestAttribute('/forum/category', 'forum.category')]
class ForumCategoryController extends BaseController
{
protected array $searchField = [
'status' => '=',
];
protected array $quickSearchField = ['name', 'slug'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ForumCategoryModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(ForumCategoryFormRequest $request): JsonResponse
{
ForumCategoryModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, ForumCategoryFormRequest $request): JsonResponse
{
$model = ForumCategoryModel::find($id);
if (empty($model)) {
return $this->error('分类不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ForumCategoryModel::find($id);
if (empty($model)) {
return $this->error('分类不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,74 @@
<?php
namespace Modules\Forum\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Forum\Http\Requests\ForumCommentFormRequest;
use Modules\Forum\Models\ForumCommentModel;
#[RequestAttribute('/forum/comment', 'forum.comment')]
class ForumCommentController extends BaseController
{
protected array $searchField = [
'status' => '=',
'post_id' => '=',
];
protected array $quickSearchField = ['content'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ForumCommentModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(ForumCommentFormRequest $request): JsonResponse
{
ForumCommentModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, ForumCommentFormRequest $request): JsonResponse
{
$model = ForumCommentModel::find($id);
if (empty($model)) {
return $this->error('评论不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ForumCommentModel::find($id);
if (empty($model)) {
return $this->error('评论不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,76 @@
<?php
namespace Modules\Forum\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Forum\Http\Requests\ForumPostFormRequest;
use Modules\Forum\Models\ForumPostModel;
#[RequestAttribute('/forum/post', 'forum.post')]
class ForumPostController extends BaseController
{
protected array $searchField = [
'status' => '=',
'is_hot' => '=',
'is_top' => '=',
'category_id' => '=',
];
protected array $quickSearchField = ['title'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ForumPostModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(ForumPostFormRequest $request): JsonResponse
{
ForumPostModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, ForumPostFormRequest $request): JsonResponse
{
$model = ForumPostModel::find($id);
if (empty($model)) {
return $this->error('帖子不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ForumPostModel::find($id);
if (empty($model)) {
return $this->error('帖子不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,46 @@
<?php
namespace Modules\Forum\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Forum\Models\ForumPostFavoriteModel;
#[RequestAttribute('/forum/post-favorite', 'forum.post-favorite')]
class ForumPostFavoriteController extends BaseController
{
protected array $searchField = [
'post_id' => '=',
];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ForumPostFavoriteModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ForumPostFavoriteModel::find($id);
if (empty($model)) {
return $this->error('收藏记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,46 @@
<?php
namespace Modules\Forum\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Forum\Models\ForumPostLikeModel;
#[RequestAttribute('/forum/post-like', 'forum.post-like')]
class ForumPostLikeController extends BaseController
{
protected array $searchField = [
'post_id' => '=',
];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ForumPostLikeModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ForumPostLikeModel::find($id);
if (empty($model)) {
return $this->error('点赞记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,74 @@
<?php
namespace Modules\Forum\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Forum\Http\Requests\ForumSensitiveWordFormRequest;
use Modules\Forum\Models\ForumSensitiveWordModel;
#[RequestAttribute('/forum/sensitive-word', 'forum.sensitive-word')]
class ForumSensitiveWordController extends BaseController
{
protected array $searchField = [
'status' => '=',
'type' => '=',
];
protected array $quickSearchField = ['word'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ForumSensitiveWordModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(ForumSensitiveWordFormRequest $request): JsonResponse
{
ForumSensitiveWordModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, ForumSensitiveWordFormRequest $request): JsonResponse
{
$model = ForumSensitiveWordModel::find($id);
if (empty($model)) {
return $this->error('敏感词不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ForumSensitiveWordModel::find($id);
if (empty($model)) {
return $this->error('敏感词不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,50 @@
<?php
namespace Modules\Forum\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class ForumCategoryFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'name' => 'required|max:50',
'slug' => 'required|max:50|unique:forum_categories,slug',
'parent_id' => 'nullable|integer',
'description' => 'nullable|max:255',
'icon' => 'nullable|max:255',
'sort' => 'nullable|integer',
'status' => 'nullable|integer|in:0,1',
];
}
$id = $this->route('id');
return [
'name' => 'required|max:50',
'slug' => [
'required',
'max:50',
Rule::unique('forum_categories', 'slug')->ignore($id),
],
'parent_id' => 'nullable|integer',
'description' => 'nullable|max:255',
'icon' => 'nullable|max:255',
'sort' => 'nullable|integer',
'status' => 'nullable|integer|in:0,1',
];
}
public function messages(): array
{
return [
'name.required' => '分类名称不能为空',
'slug.required' => '分类标识不能为空',
'slug.unique' => '分类标识已存在',
];
}
}
@@ -0,0 +1,31 @@
<?php
namespace Modules\Forum\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class ForumCommentFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'post_id' => 'required|integer',
'user_id' => 'required|integer',
'content' => 'required',
'parent_id' => 'nullable|integer',
'reply_to' => 'nullable|integer',
'status' => 'nullable|integer|in:0,1',
];
}
public function messages(): array
{
return [
'post_id.required' => '帖子ID不能为空',
'user_id.required' => '评论用户不能为空',
'content.required' => '评论内容不能为空',
];
}
}
@@ -0,0 +1,33 @@
<?php
namespace Modules\Forum\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class ForumPostFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'title' => 'required|max:100',
'content' => 'required',
'category_id' => 'nullable|integer',
'user_id' => 'required|integer',
'images' => 'nullable|array',
'is_hot' => 'nullable|integer|in:0,1',
'is_top' => 'nullable|integer|in:0,1',
'status' => 'nullable|integer|in:0,1,2',
];
}
public function messages(): array
{
return [
'title.required' => '帖子标题不能为空',
'content.required' => '帖子内容不能为空',
'user_id.required' => '发布用户不能为空',
];
}
}
@@ -0,0 +1,43 @@
<?php
namespace Modules\Forum\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class ForumSensitiveWordFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'word' => 'required|max:100|unique:forum_sensitive_words,word',
'replacement' => 'nullable|max:100',
'type' => 'nullable|integer|in:1,2',
'status' => 'nullable|integer|in:0,1',
];
}
$id = $this->route('id');
return [
'word' => [
'required',
'max:100',
Rule::unique('forum_sensitive_words', 'word')->ignore($id),
],
'replacement' => 'nullable|max:100',
'type' => 'nullable|integer|in:1,2',
'status' => 'nullable|integer|in:0,1',
];
}
public function messages(): array
{
return [
'word.required' => '敏感词不能为空',
'word.unique' => '敏感词已存在',
];
}
}
@@ -0,0 +1,26 @@
<?php
namespace Modules\Forum\Models;
use Illuminate\Database\Eloquent\Model;
class ForumCategoryModel extends Model
{
protected $table = 'forum_categories';
protected $fillable = [
'parent_id',
'name',
'slug',
'description',
'icon',
'sort',
'status',
];
protected $casts = [
'parent_id' => 'integer',
'sort' => 'integer',
'status' => 'integer',
];
}
@@ -0,0 +1,29 @@
<?php
namespace Modules\Forum\Models;
use Illuminate\Database\Eloquent\Model;
class ForumCommentModel extends Model
{
protected $table = 'forum_comments';
protected $fillable = [
'post_id',
'user_id',
'parent_id',
'reply_to',
'content',
'like_count',
'status',
];
protected $casts = [
'post_id' => 'integer',
'user_id' => 'integer',
'parent_id' => 'integer',
'reply_to' => 'integer',
'like_count' => 'integer',
'status' => 'integer',
];
}
@@ -0,0 +1,23 @@
<?php
namespace Modules\Forum\Models;
use Illuminate\Database\Eloquent\Model;
class ForumPostFavoriteModel extends Model
{
protected $table = 'forum_post_favorites';
public $timestamps = false;
protected $fillable = [
'post_id',
'user_id',
'created_at',
];
protected $casts = [
'post_id' => 'integer',
'user_id' => 'integer',
];
}
@@ -0,0 +1,23 @@
<?php
namespace Modules\Forum\Models;
use Illuminate\Database\Eloquent\Model;
class ForumPostLikeModel extends Model
{
protected $table = 'forum_post_likes';
public $timestamps = false;
protected $fillable = [
'post_id',
'user_id',
'created_at',
];
protected $casts = [
'post_id' => 'integer',
'user_id' => 'integer',
];
}
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace Modules\Forum\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ForumPostModel extends Model
{
use SoftDeletes;
protected $table = 'forum_posts';
protected $fillable = [
'user_id',
'category_id',
'title',
'content',
'images',
'view_count',
'comment_count',
'like_count',
'favorite_count',
'is_hot',
'is_top',
'status',
];
protected $casts = [
'user_id' => 'integer',
'category_id' => 'integer',
'images' => 'array',
'view_count' => 'integer',
'comment_count' => 'integer',
'like_count' => 'integer',
'favorite_count' => 'integer',
'is_hot' => 'integer',
'is_top' => 'integer',
'status' => 'integer',
];
}
@@ -0,0 +1,22 @@
<?php
namespace Modules\Forum\Models;
use Illuminate\Database\Eloquent\Model;
class ForumSensitiveWordModel extends Model
{
protected $table = 'forum_sensitive_words';
protected $fillable = [
'word',
'replacement',
'type',
'status',
];
protected $casts = [
'type' => 'integer',
'status' => 'integer',
];
}
@@ -0,0 +1,14 @@
<?php
namespace Modules\Forum\Providers;
use Illuminate\Support\ServiceProvider;
use Modules\AnnoRoute\AnnoRoute;
class ForumServiceProvider extends ServiceProvider
{
public function boot(AnnoRoute $annoRoute): void
{
$annoRoute->register(base_path('modules/Forum/Http/Controllers'));
}
}
@@ -0,0 +1,75 @@
<?php
namespace Modules\Member\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Member\Http\Requests\MemberAddressFormRequest;
use Modules\Member\Models\UserAddressModel;
#[RequestAttribute('/member/address', 'member.address')]
class MemberAddressController extends BaseController
{
protected array $searchField = [
'is_default' => '=',
];
protected array $quickSearchField = ['name', 'mobile', 'detail'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = UserAddressModel::with('user:id,username,nickname,mobile');
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(MemberAddressFormRequest $request): JsonResponse
{
$validated = $request->validated();
UserAddressModel::create($validated);
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, MemberAddressFormRequest $request): JsonResponse
{
$validated = $request->validated();
$model = UserAddressModel::find($id);
if (empty($model)) {
return $this->error();
}
$model->update($validated);
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = UserAddressModel::find($id);
if (empty($model)) {
return $this->error('地址不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,83 @@
<?php
namespace Modules\Member\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Member\Http\Requests\MemberUserFormRequest;
use Modules\Member\Models\MemberUserModel;
#[RequestAttribute('/member/user', 'member.user')]
class MemberUserController extends BaseController
{
protected array $searchField = [
'status' => '=',
'gender' => '=',
];
protected array $quickSearchField = ['username', 'nickname', 'mobile'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = MemberUserModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(MemberUserFormRequest $request): JsonResponse
{
$validated = $request->validated();
$validated['password'] = Hash::make($validated['password']);
MemberUserModel::create($validated);
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, MemberUserFormRequest $request): JsonResponse
{
$validated = $request->validated();
$model = MemberUserModel::find($id);
if (empty($model)) {
return $this->error();
}
if (!empty($validated['password'])) {
$validated['password'] = Hash::make($validated['password']);
} else {
unset($validated['password']);
}
$model->update($validated);
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$user = MemberUserModel::find($id);
if (empty($user)) {
return $this->error('用户不存在');
}
$user->delete();
return $this->success();
}
}
@@ -0,0 +1,41 @@
<?php
namespace Modules\Member\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class MemberAddressFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'user_id' => 'required|integer|exists:user,id',
'name' => 'required|max:30',
'mobile' => 'required|max:20',
'province' => 'required|max:30',
'city' => 'required|max:30',
'district' => 'required|max:30',
'detail' => 'required|max:255',
'is_default' => 'nullable|integer|in:0,1',
];
}
public function messages(): array
{
return [
'user_id.required' => '用户ID不能为空',
'user_id.exists' => '用户不存在',
'name.required' => '收货人不能为空',
'name.max' => '收货人名称不能超过30个字符',
'mobile.required' => '联系电话不能为空',
'mobile.max' => '联系电话不能超过20个字符',
'province.required' => '省份不能为空',
'city.required' => '城市不能为空',
'district.required' => '区县不能为空',
'detail.required' => '详细地址不能为空',
'is_default.in' => '默认地址格式错误',
];
}
}
@@ -0,0 +1,61 @@
<?php
namespace Modules\Member\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class MemberUserFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'username' => 'required|unique:user,username',
'password' => 'required|min:6',
'nickname' => 'nullable',
'email' => 'nullable|email',
'mobile' => 'nullable',
'gender' => 'nullable|integer|in:0,1,2',
'status' => 'nullable|integer|in:0,1',
'avatar' => 'nullable',
'birthday' => 'nullable|date',
];
}
$id = $this->route('id');
return [
'username' => [
'required',
Rule::unique('user', 'username')->ignore($id),
],
'password' => 'nullable|min:6',
'nickname' => 'nullable',
'email' => [
'nullable',
'email',
],
'mobile' => 'nullable',
'gender' => 'nullable|integer|in:0,1,2',
'status' => 'nullable|integer|in:0,1',
'avatar' => 'nullable',
'birthday' => 'nullable|date',
];
}
public function messages(): array
{
return [
'username.required' => '用户名不能为空',
'username.unique' => '用户名已存在',
'password.required' => '密码不能为空',
'password.min' => '密码至少6位',
'email.email' => '邮箱格式错误',
'gender.in' => '性别格式错误',
'status.in' => '状态格式错误',
'birthday.date' => '生日格式错误',
];
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace Modules\Member\Models;
use Illuminate\Database\Eloquent\Model;
class MemberUserModel extends Model
{
protected $table = 'user';
protected $primaryKey = 'id';
protected $fillable = [
'username',
'password',
'nickname',
'email',
'avatar',
'mobile',
'gender',
'birthday',
'balance',
'status',
'last_login_at',
'openid',
'unionid',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'last_login_at' => 'datetime',
'birthday' => 'date',
'gender' => 'integer',
'status' => 'integer',
'balance' => 'decimal:2',
];
}
@@ -0,0 +1,31 @@
<?php
namespace Modules\Member\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class UserAddressModel extends Model
{
protected $table = 'user_addresses';
protected $fillable = [
'user_id',
'name',
'mobile',
'province',
'city',
'district',
'detail',
'is_default',
];
protected $casts = [
'is_default' => 'integer',
];
public function user(): BelongsTo
{
return $this->belongsTo(MemberUserModel::class, 'user_id', 'id');
}
}
@@ -0,0 +1,14 @@
<?php
namespace Modules\Member\Providers;
use Illuminate\Support\ServiceProvider;
use Modules\AnnoRoute\AnnoRoute;
class MemberServiceProvider extends ServiceProvider
{
public function boot(AnnoRoute $annoRoute): void
{
$annoRoute->register(base_path('modules/Member/Http/Controllers'));
}
}
@@ -0,0 +1,73 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\MerchantCategoryFormRequest;
use Modules\Merchant\Models\MerchantCategoryModel;
#[RequestAttribute('/merchant/category', 'merchant.category')]
class MerchantCategoryController extends BaseController
{
protected array $searchField = [
'status' => '=',
];
protected array $quickSearchField = ['name', 'slug'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = MerchantCategoryModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(MerchantCategoryFormRequest $request): JsonResponse
{
MerchantCategoryModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, MerchantCategoryFormRequest $request): JsonResponse
{
$model = MerchantCategoryModel::find($id);
if (empty($model)) {
return $this->error('分类不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = MerchantCategoryModel::find($id);
if (empty($model)) {
return $this->error('分类不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,76 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\MerchantProductFormRequest;
use Modules\Merchant\Models\MerchantProductModel;
#[RequestAttribute('/merchant/product', 'merchant.product')]
class MerchantProductController extends BaseController
{
protected array $searchField = [
'status' => '=',
'is_recommend' => '=',
'merchant_id' => '=',
'category_id' => '=',
];
protected array $quickSearchField = ['name'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = MerchantProductModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(MerchantProductFormRequest $request): JsonResponse
{
MerchantProductModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, MerchantProductFormRequest $request): JsonResponse
{
$model = MerchantProductModel::find($id);
if (empty($model)) {
return $this->error('商品不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = MerchantProductModel::find($id);
if (empty($model)) {
return $this->error('商品不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,117 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\MerchantStoreFormRequest;
use Modules\Merchant\Models\MerchantStoreModel;
use Modules\SystemUser\Models\SysUserModel;
#[RequestAttribute('/merchant/store', 'merchant.store')]
class MerchantStoreController extends BaseController
{
protected array $searchField = [
'status' => '=',
'category_id' => '=',
];
protected array $quickSearchField = ['name', 'contact_name', 'contact_mobile'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = MerchantStoreModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(MerchantStoreFormRequest $request): JsonResponse
{
$data = $request->validated();
// 检查用户名是否已存在
$username = $data['username'];
if (SysUserModel::where('username', $username)->exists()) {
return $this->error('用户名已存在');
}
DB::beginTransaction();
try {
// 创建管理员用户
$user = SysUserModel::create([
'username' => $username,
'password' => Hash::make($data['password']),
'nickname' => $data['name'] ?? $username,
'status' => 1,
]);
// 分配"商户"角色
$merchantRole = DB::table('sys_role')->where('name', '商户')->first();
if ($merchantRole) {
DB::table('sys_user_role')->insert([
'user_id' => $user->id,
'role_id' => $merchantRole->id,
]);
}
// 创建商户,关联用户
$data['user_id'] = $user->id;
unset($data['username'], $data['password']);
MerchantStoreModel::create($data);
DB::commit();
return $this->success();
} catch (\Exception $e) {
DB::rollBack();
return $this->error('创建商户失败:' . $e->getMessage());
}
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, MerchantStoreFormRequest $request): JsonResponse
{
$model = MerchantStoreModel::find($id);
if (empty($model)) {
return $this->error('商户不存在');
}
$data = $request->validated();
// 更新时不允许通过此接口修改 username/password/user_id
unset($data['username'], $data['password'], $data['user_id']);
$model->update($data);
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = MerchantStoreModel::find($id);
if (empty($model)) {
return $this->error('商户不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,67 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\MerchantWithdrawalFormRequest;
use Modules\Merchant\Models\MerchantWithdrawalModel;
#[RequestAttribute('/merchant/withdrawal', 'merchant.withdrawal')]
class MerchantWithdrawalController extends BaseController
{
protected array $searchField = [
'status' => '=',
'channel' => '=',
'merchant_id' => '=',
];
protected array $quickSearchField = ['withdraw_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = MerchantWithdrawalModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, MerchantWithdrawalFormRequest $request): JsonResponse
{
$model = MerchantWithdrawalModel::find($id);
if (empty($model)) {
return $this->error('提现记录不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = MerchantWithdrawalModel::find($id);
if (empty($model)) {
return $this->error('提现记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,76 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\OrderFormRequest;
use Modules\Merchant\Models\OrderModel;
#[RequestAttribute('/merchant/order', 'merchant.order')]
class OrderController extends BaseController
{
protected array $searchField = [
'status' => '=',
'pay_status' => '=',
'user_id' => '=',
'merchant_id' => '=',
];
protected array $quickSearchField = ['order_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = OrderModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(OrderFormRequest $request): JsonResponse
{
OrderModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, OrderFormRequest $request): JsonResponse
{
$model = OrderModel::find($id);
if (empty($model)) {
return $this->error('订单不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = OrderModel::find($id);
if (empty($model)) {
return $this->error('订单不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,51 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Models\OrderPaymentModel;
#[RequestAttribute('/merchant/order-payment', 'merchant.order_payment')]
class OrderPaymentController extends BaseController
{
protected array $searchField = [
'status' => '=',
'pay_type' => '=',
'order_id' => '=',
'user_id' => '=',
];
protected array $quickSearchField = ['payment_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = OrderPaymentModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = OrderPaymentModel::find($id);
if (empty($model)) {
return $this->error('支付记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,68 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\OrderRefundFormRequest;
use Modules\Merchant\Models\OrderRefundModel;
#[RequestAttribute('/merchant/refund', 'merchant.refund')]
class OrderRefundController extends BaseController
{
protected array $searchField = [
'status' => '=',
'order_id' => '=',
'user_id' => '=',
'merchant_id' => '=',
];
protected array $quickSearchField = ['refund_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = OrderRefundModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, OrderRefundFormRequest $request): JsonResponse
{
$model = OrderRefundModel::find($id);
if (empty($model)) {
return $this->error('退款记录不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = OrderRefundModel::find($id);
if (empty($model)) {
return $this->error('退款记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,46 @@
<?php
namespace Modules\Merchant\Http\Controllers\Portal;
use Illuminate\Support\Facades\Auth;
use Modules\Merchant\Models\MerchantStoreModel;
trait MerchantAuthTrait
{
protected ?int $_merchantId = null;
/**
* 获取当前登录商户的 ID
* 通过 sys_user.id -> merchants.user_id 关联获取
*/
public function getMerchantId(): int
{
if ($this->_merchantId === null) {
$userId = Auth::id();
$merchant = MerchantStoreModel::where('user_id', $userId)->first(['id']);
if (!$merchant) {
$this->throwError('商户信息不存在,请联系管理员');
}
$this->_merchantId = $merchant->id;
}
return $this->_merchantId;
}
/**
* 获取当前登录商户的完整模型
*/
public function getMerchant(): MerchantStoreModel
{
$userId = Auth::id();
$merchant = MerchantStoreModel::where('user_id', $userId)->first();
if (!$merchant) {
$this->throwError('商户信息不存在,请联系管理员');
}
return $merchant;
}
}
@@ -0,0 +1,36 @@
<?php
namespace Modules\Merchant\Http\Controllers\Portal;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Models\OrderModel;
#[RequestAttribute('/merchant-portal/order', 'merchant.portal.order')]
class OrderController extends BaseController
{
use MerchantAuthTrait;
protected array $searchField = [
'status' => '=',
'pay_status' => '=',
'pay_type' => '=',
];
protected array $quickSearchField = ['order_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = OrderModel::where('merchant_id', $this->getMerchantId());
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
}
@@ -0,0 +1,40 @@
<?php
namespace Modules\Merchant\Http\Controllers\Portal;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Models\OrderPaymentModel;
#[RequestAttribute('/merchant-portal/payment', 'merchant.portal.payment')]
class PaymentController extends BaseController
{
use MerchantAuthTrait;
protected array $searchField = [
'pay_type' => '=',
'status' => '=',
];
protected array $quickSearchField = ['payment_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$merchantId = $this->getMerchantId();
$query = OrderPaymentModel::whereHas('order', function ($q) use ($merchantId) {
$q->where('merchant_id', $merchantId);
});
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
}
@@ -0,0 +1,82 @@
<?php
namespace Modules\Merchant\Http\Controllers\Portal;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\Portal\PrinterFormRequest;
use Modules\Merchant\Models\PrinterModel;
#[RequestAttribute('/merchant-portal/printer', 'merchant.portal.printer')]
class PrinterController extends BaseController
{
use MerchantAuthTrait;
protected array $searchField = [
'status' => '=',
'brand' => '=',
];
protected array $quickSearchField = ['name'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = PrinterModel::where('merchant_id', $this->getMerchantId());
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(PrinterFormRequest $request): JsonResponse
{
$data = $request->validated();
$data['merchant_id'] = $this->getMerchantId();
PrinterModel::create($data);
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, PrinterFormRequest $request): JsonResponse
{
$model = PrinterModel::where('id', $id)
->where('merchant_id', $this->getMerchantId())
->first();
if (empty($model)) {
return $this->error('打印机不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = PrinterModel::where('id', $id)
->where('merchant_id', $this->getMerchantId())
->first();
if (empty($model)) {
return $this->error('打印机不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,82 @@
<?php
namespace Modules\Merchant\Http\Controllers\Portal;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\Portal\ProductCategoryFormRequest;
use Modules\Merchant\Models\ProductCategoryModel;
#[RequestAttribute('/merchant-portal/product-category', 'merchant.portal.product-category')]
class ProductCategoryController extends BaseController
{
use MerchantAuthTrait;
protected array $searchField = [
'status' => '=',
'parent_id' => '=',
];
protected array $quickSearchField = ['name'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ProductCategoryModel::where('merchant_id', $this->getMerchantId());
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(ProductCategoryFormRequest $request): JsonResponse
{
$data = $request->validated();
$data['merchant_id'] = $this->getMerchantId();
ProductCategoryModel::create($data);
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, ProductCategoryFormRequest $request): JsonResponse
{
$model = ProductCategoryModel::where('id', $id)
->where('merchant_id', $this->getMerchantId())
->first();
if (empty($model)) {
return $this->error('分类不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ProductCategoryModel::where('id', $id)
->where('merchant_id', $this->getMerchantId())
->first();
if (empty($model)) {
return $this->error('分类不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,83 @@
<?php
namespace Modules\Merchant\Http\Controllers\Portal;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\Portal\ProductFormRequest;
use Modules\Merchant\Models\MerchantProductModel;
#[RequestAttribute('/merchant-portal/product', 'merchant.portal.product')]
class ProductController extends BaseController
{
use MerchantAuthTrait;
protected array $searchField = [
'status' => '=',
'is_recommend' => '=',
'category_id' => '=',
];
protected array $quickSearchField = ['name'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = MerchantProductModel::where('merchant_id', $this->getMerchantId());
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(ProductFormRequest $request): JsonResponse
{
$data = $request->validated();
$data['merchant_id'] = $this->getMerchantId();
MerchantProductModel::create($data);
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, ProductFormRequest $request): JsonResponse
{
$model = MerchantProductModel::where('id', $id)
->where('merchant_id', $this->getMerchantId())
->first();
if (empty($model)) {
return $this->error('商品不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = MerchantProductModel::where('id', $id)
->where('merchant_id', $this->getMerchantId())
->first();
if (empty($model)) {
return $this->error('商品不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,31 @@
<?php
namespace Modules\Merchant\Http\Controllers\Portal;
use Illuminate\Http\JsonResponse;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\Portal\StoreFormRequest;
#[RequestAttribute('/merchant-portal/store', 'merchant.portal.store')]
class StoreController extends BaseController
{
use MerchantAuthTrait;
#[GetRoute(authorize: 'query')]
public function query(): JsonResponse
{
$merchant = $this->getMerchant();
return $this->success($merchant->toArray());
}
#[PutRoute(authorize: 'update')]
public function update(StoreFormRequest $request): JsonResponse
{
$merchant = $this->getMerchant();
$merchant->update($request->validated());
return $this->success();
}
}
@@ -0,0 +1,47 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Models\PrintTaskModel;
#[RequestAttribute('/merchant/print-task', 'merchant.print-task')]
class PrintTaskController extends BaseController
{
protected array $searchField = [
'status' => '=',
'printer_id' => '=',
];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = PrintTaskModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = PrintTaskModel::find($id);
if (empty($model)) {
return $this->error('打印任务不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,74 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\PrinterFormRequest;
use Modules\Merchant\Models\PrinterModel;
#[RequestAttribute('/merchant/printer', 'merchant.printer')]
class PrinterController extends BaseController
{
protected array $searchField = [
'status' => '=',
'merchant_id' => '=',
];
protected array $quickSearchField = ['name', 'brand', 'model'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = PrinterModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(PrinterFormRequest $request): JsonResponse
{
PrinterModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, PrinterFormRequest $request): JsonResponse
{
$model = PrinterModel::find($id);
if (empty($model)) {
return $this->error('打印机不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = PrinterModel::find($id);
if (empty($model)) {
return $this->error('打印机不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,74 @@
<?php
namespace Modules\Merchant\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Merchant\Http\Requests\ProductCategoryFormRequest;
use Modules\Merchant\Models\ProductCategoryModel;
#[RequestAttribute('/merchant/product-category', 'merchant.product-category')]
class ProductCategoryController extends BaseController
{
protected array $searchField = [
'status' => '=',
'merchant_id' => '=',
];
protected array $quickSearchField = ['name', 'slug'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = ProductCategoryModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(ProductCategoryFormRequest $request): JsonResponse
{
ProductCategoryModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, ProductCategoryFormRequest $request): JsonResponse
{
$model = ProductCategoryModel::find($id);
if (empty($model)) {
return $this->error('分类不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = ProductCategoryModel::find($id);
if (empty($model)) {
return $this->error('分类不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,48 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class MerchantCategoryFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'name' => 'required|max:50',
'slug' => 'required|max:50|unique:merchant_categories,slug',
'description' => 'nullable|max:255',
'icon' => 'nullable|max:255',
'sort' => 'nullable|integer',
'status' => 'nullable|integer|in:0,1',
];
}
$id = $this->route('id');
return [
'name' => 'required|max:50',
'slug' => [
'required',
'max:50',
Rule::unique('merchant_categories', 'slug')->ignore($id),
],
'description' => 'nullable|max:255',
'icon' => 'nullable|max:255',
'sort' => 'nullable|integer',
'status' => 'nullable|integer|in:0,1',
];
}
public function messages(): array
{
return [
'name.required' => '分类名称不能为空',
'slug.required' => '分类标识不能为空',
'slug.unique' => '分类标识已存在',
];
}
}
@@ -0,0 +1,37 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class MerchantProductFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'merchant_id' => 'required|integer',
'category_id' => 'nullable|integer',
'name' => 'required|max:100',
'description' => 'nullable',
'images' => 'nullable|array',
'price' => 'required|numeric',
'original_price' => 'nullable|numeric',
'stock' => 'nullable|integer',
'unit' => 'nullable|max:20',
'status' => 'nullable|integer|in:0,1',
'is_recommend' => 'nullable|integer|in:0,1',
'sort' => 'nullable|integer',
];
}
public function messages(): array
{
return [
'merchant_id.required' => '所属商户不能为空',
'name.required' => '商品名称不能为空',
'price.required' => '售价不能为空',
];
}
}
@@ -0,0 +1,54 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class MerchantStoreFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
$rules = [
'user_id' => 'nullable|integer',
'username' => 'nullable|max:50',
'password' => 'nullable|min:6|max:50',
'category_id' => 'nullable|integer',
'name' => 'required|max:50',
'logo' => 'nullable|max:255',
'banner' => 'nullable|max:255',
'description' => 'nullable',
'contact_name' => 'nullable|max:30',
'contact_mobile' => 'nullable|max:20',
'province' => 'nullable|max:30',
'city' => 'nullable|max:30',
'district' => 'nullable|max:30',
'address' => 'nullable|max:255',
'latitude' => 'nullable|max:20',
'longitude' => 'nullable|max:20',
'business_hours' => 'nullable|max:100',
'min_price' => 'nullable|numeric',
'status' => 'nullable|integer|in:0,1,2,3',
'reject_reason' => 'nullable|max:255',
];
// 新建时用户名和密码必填
if (! $this->isUpdate()) {
$rules['username'] = 'required|max:50';
$rules['password'] = 'required|min:6|max:50';
}
return $rules;
}
public function messages(): array
{
return [
'name.required' => '店铺名称不能为空',
'username.required' => '登录用户名不能为空',
'password.required' => '登录密码不能为空',
'password.min' => '登录密码不能少于6位',
];
}
}
@@ -0,0 +1,52 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class MerchantWithdrawalFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'withdraw_no' => 'required|string|max:32|unique:merchant_withdrawals,withdraw_no',
'merchant_id' => 'required|integer',
'amount' => 'required|numeric',
'channel' => 'required|string|max:50',
'account_info' => 'required|array',
'status' => 'required|integer|in:0,1,2',
'remark' => 'nullable|string',
'processed_at' => 'nullable|date',
];
}
$id = $this->route('id');
return [
'withdraw_no' => ['required', 'string', 'max:32', Rule::unique('merchant_withdrawals', 'withdraw_no')->ignore($id)],
'merchant_id' => 'required|integer',
'amount' => 'required|numeric',
'channel' => 'required|string|max:50',
'account_info' => 'required|array',
'status' => 'required|integer|in:0,1,2',
'remark' => 'nullable|string',
'processed_at' => 'nullable|date',
];
}
public function messages(): array
{
return [
'withdraw_no.required' => '提现单号不能为空',
'withdraw_no.unique' => '提现单号已存在',
'merchant_id.required' => '商户ID不能为空',
'amount.required' => '提现金额不能为空',
'channel.required' => '提现渠道不能为空',
'account_info.required' => '账户信息不能为空',
'status.required' => '提现状态不能为空',
];
}
}
@@ -0,0 +1,69 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class OrderFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'order_no' => 'required|string|max:32|unique:orders,order_no',
'user_id' => 'required|integer',
'merchant_id' => 'required|integer',
'address_id' => 'required|integer',
'total_amount' => 'required|numeric',
'discount_amount' => 'nullable|numeric',
'delivery_fee' => 'nullable|numeric',
'payment_amount' => 'required|numeric',
'pay_type' => 'required|integer|in:0,1,2',
'pay_status' => 'required|integer|in:0,1',
'paid_at' => 'nullable|date',
'status' => 'required|integer|in:0,1,2,3,4,5',
'cancel_reason' => 'nullable|string',
'remark' => 'nullable|string',
'completed_at' => 'nullable|date',
];
}
$id = $this->route('id');
return [
'order_no' => ['required', 'string', 'max:32', Rule::unique('orders', 'order_no')->ignore($id)],
'user_id' => 'required|integer',
'merchant_id' => 'required|integer',
'address_id' => 'required|integer',
'total_amount' => 'required|numeric',
'discount_amount' => 'nullable|numeric',
'delivery_fee' => 'nullable|numeric',
'payment_amount' => 'required|numeric',
'pay_type' => 'required|integer|in:0,1,2',
'pay_status' => 'required|integer|in:0,1',
'paid_at' => 'nullable|date',
'status' => 'required|integer|in:0,1,2,3,4,5',
'cancel_reason' => 'nullable|string',
'remark' => 'nullable|string',
'completed_at' => 'nullable|date',
];
}
public function messages(): array
{
return [
'order_no.required' => '订单号不能为空',
'order_no.unique' => '订单号已存在',
'user_id.required' => '用户ID不能为空',
'merchant_id.required' => '商户ID不能为空',
'address_id.required' => '地址ID不能为空',
'total_amount.required' => '订单总金额不能为空',
'payment_amount.required' => '支付金额不能为空',
'pay_type.required' => '支付类型不能为空',
'pay_status.required' => '支付状态不能为空',
'status.required' => '订单状态不能为空',
];
}
}
@@ -0,0 +1,54 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class OrderPaymentFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'payment_no' => 'required|string|max:32|unique:order_payments,payment_no',
'order_id' => 'required|integer',
'user_id' => 'required|integer',
'payment_transaction_id' => 'nullable|integer',
'amount' => 'required|numeric',
'pay_type' => 'required|integer|in:0,1,2',
'status' => 'required|integer|in:0,1,2',
'paid_at' => 'nullable|date',
'refund_at' => 'nullable|date',
];
}
$id = $this->route('id');
return [
'payment_no' => ['required', 'string', 'max:32', Rule::unique('order_payments', 'payment_no')->ignore($id)],
'order_id' => 'required|integer',
'user_id' => 'required|integer',
'payment_transaction_id' => 'nullable|integer',
'amount' => 'required|numeric',
'pay_type' => 'required|integer|in:0,1,2',
'status' => 'required|integer|in:0,1,2',
'paid_at' => 'nullable|date',
'refund_at' => 'nullable|date',
];
}
public function messages(): array
{
return [
'payment_no.required' => '支付单号不能为空',
'payment_no.unique' => '支付单号已存在',
'order_id.required' => '订单ID不能为空',
'user_id.required' => '用户ID不能为空',
'amount.required' => '支付金额不能为空',
'pay_type.required' => '支付类型不能为空',
'status.required' => '支付状态不能为空',
];
}
}
@@ -0,0 +1,59 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class OrderRefundFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'refund_no' => 'required|string|max:32|unique:order_refunds,refund_no',
'order_id' => 'required|integer',
'order_item_id' => 'nullable|integer',
'user_id' => 'required|integer',
'merchant_id' => 'required|integer',
'amount' => 'required|numeric',
'reason' => 'required|string',
'images' => 'nullable|array',
'status' => 'required|integer|in:0,1,2,3',
'reply' => 'nullable|string',
'processed_at' => 'nullable|date',
];
}
$id = $this->route('id');
return [
'refund_no' => ['required', 'string', 'max:32', Rule::unique('order_refunds', 'refund_no')->ignore($id)],
'order_id' => 'required|integer',
'order_item_id' => 'nullable|integer',
'user_id' => 'required|integer',
'merchant_id' => 'required|integer',
'amount' => 'required|numeric',
'reason' => 'required|string',
'images' => 'nullable|array',
'status' => 'required|integer|in:0,1,2,3',
'reply' => 'nullable|string',
'processed_at' => 'nullable|date',
];
}
public function messages(): array
{
return [
'refund_no.required' => '退款单号不能为空',
'refund_no.unique' => '退款单号已存在',
'order_id.required' => '订单ID不能为空',
'user_id.required' => '用户ID不能为空',
'merchant_id.required' => '商户ID不能为空',
'amount.required' => '退款金额不能为空',
'reason.required' => '退款原因不能为空',
'status.required' => '退款状态不能为空',
];
}
}
@@ -0,0 +1,30 @@
<?php
namespace Modules\Merchant\Http\Requests\Portal;
use Modules\Common\Http\Requests\BaseFormRequest;
class PrinterFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'name' => 'required|max:50',
'brand' => 'nullable|max:30',
'model' => 'nullable|max:50',
'device_no' => 'nullable|max:100',
'secret_key' => 'nullable|max:100',
'status' => 'nullable|integer|in:0,1',
'config' => 'nullable',
];
}
public function messages(): array
{
return [
'name.required' => '打印机名称不能为空',
];
}
}
@@ -0,0 +1,30 @@
<?php
namespace Modules\Merchant\Http\Requests\Portal;
use Modules\Common\Http\Requests\BaseFormRequest;
class ProductCategoryFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'parent_id' => 'nullable|integer',
'name' => 'required|max:100',
'slug' => 'nullable|max:100',
'description' => 'nullable',
'icon' => 'nullable|max:255',
'sort' => 'nullable|integer',
'status' => 'nullable|integer|in:0,1',
];
}
public function messages(): array
{
return [
'name.required' => '分类名称不能为空',
];
}
}
@@ -0,0 +1,35 @@
<?php
namespace Modules\Merchant\Http\Requests\Portal;
use Modules\Common\Http\Requests\BaseFormRequest;
class ProductFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'category_id' => 'nullable|integer',
'name' => 'required|max:100',
'description' => 'nullable',
'images' => 'nullable|array',
'price' => 'required|numeric',
'original_price' => 'nullable|numeric',
'stock' => 'nullable|integer',
'unit' => 'nullable|max:20',
'status' => 'nullable|integer|in:0,1',
'is_recommend' => 'nullable|integer|in:0,1',
'sort' => 'nullable|integer',
];
}
public function messages(): array
{
return [
'name.required' => '商品名称不能为空',
'price.required' => '售价不能为空',
];
}
}
@@ -0,0 +1,37 @@
<?php
namespace Modules\Merchant\Http\Requests\Portal;
use Modules\Common\Http\Requests\BaseFormRequest;
class StoreFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'name' => 'required|max:50',
'logo' => 'nullable|max:255',
'banner' => 'nullable|max:255',
'description' => 'nullable',
'contact_name' => 'nullable|max:30',
'contact_mobile' => 'nullable|max:20',
'province' => 'nullable|max:30',
'city' => 'nullable|max:30',
'district' => 'nullable|max:30',
'address' => 'nullable|max:255',
'latitude' => 'nullable|max:20',
'longitude' => 'nullable|max:20',
'business_hours' => 'nullable|max:100',
'min_price' => 'nullable|numeric',
];
}
public function messages(): array
{
return [
'name.required' => '店铺名称不能为空',
];
}
}
@@ -0,0 +1,32 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class PrinterFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'merchant_id' => 'required|integer',
'name' => 'required|max:50',
'brand' => 'nullable|max:50',
'model' => 'nullable|max:50',
'device_no' => 'nullable|max:100',
'secret_key' => 'nullable|max:255',
'status' => 'nullable|integer|in:0,1,2',
'config' => 'nullable|array',
];
}
public function messages(): array
{
return [
'merchant_id.required' => '所属商户不能为空',
'name.required' => '打印机名称不能为空',
];
}
}
@@ -0,0 +1,33 @@
<?php
namespace Modules\Merchant\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class ProductCategoryFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'merchant_id' => 'required|integer',
'parent_id' => 'nullable|integer',
'name' => 'required|max:50',
'slug' => 'required|max:50',
'description' => 'nullable|max:255',
'icon' => 'nullable|max:255',
'sort' => 'nullable|integer',
'status' => 'nullable|integer|in:0,1',
];
}
public function messages(): array
{
return [
'merchant_id.required' => '所属商户不能为空',
'name.required' => '分类名称不能为空',
'slug.required' => '分类标识不能为空',
];
}
}
@@ -0,0 +1,24 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class MerchantCategoryModel extends Model
{
protected $table = 'platform_categories';
protected $fillable = [
'name',
'slug',
'description',
'icon',
'sort',
'status',
];
protected $casts = [
'sort' => 'integer',
'status' => 'integer',
];
}
@@ -0,0 +1,42 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class MerchantProductModel extends Model
{
use SoftDeletes;
protected $table = 'merchant_products';
protected $fillable = [
'merchant_id',
'category_id',
'name',
'description',
'images',
'price',
'original_price',
'stock',
'unit',
'sales',
'status',
'is_recommend',
'sort',
];
protected $casts = [
'merchant_id' => 'integer',
'category_id' => 'integer',
'images' => 'array',
'price' => 'decimal:2',
'original_price' => 'decimal:2',
'stock' => 'integer',
'sales' => 'integer',
'status' => 'integer',
'is_recommend' => 'integer',
'sort' => 'integer',
];
}
@@ -0,0 +1,42 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class MerchantStoreModel extends Model
{
protected $table = 'merchants';
protected $fillable = [
'user_id',
'category_id',
'name',
'logo',
'banner',
'description',
'contact_name',
'contact_mobile',
'province',
'city',
'district',
'address',
'latitude',
'longitude',
'business_hours',
'balance',
'total_income',
'min_price',
'status',
'reject_reason',
];
protected $casts = [
'user_id' => 'integer',
'category_id' => 'integer',
'balance' => 'decimal:2',
'total_income' => 'decimal:2',
'min_price' => 'decimal:2',
'status' => 'integer',
];
}
@@ -0,0 +1,29 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class MerchantWithdrawalModel extends Model
{
protected $table = 'merchant_withdrawals';
protected $fillable = [
'withdraw_no',
'merchant_id',
'amount',
'channel',
'account_info',
'status',
'remark',
'processed_at',
];
protected $casts = [
'merchant_id' => 'integer',
'amount' => 'decimal:2',
'account_info' => 'array',
'status' => 'integer',
'processed_at' => 'datetime',
];
}
@@ -0,0 +1,28 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class OrderItemModel extends Model
{
protected $table = 'order_items';
protected $fillable = [
'order_id',
'product_id',
'product_name',
'product_image',
'price',
'quantity',
'subtotal',
];
protected $casts = [
'order_id' => 'integer',
'product_id' => 'integer',
'price' => 'decimal:2',
'quantity' => 'integer',
'subtotal' => 'decimal:2',
];
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class OrderModel extends Model
{
protected $table = 'orders';
protected $fillable = [
'order_no',
'user_id',
'merchant_id',
'address_id',
'total_amount',
'discount_amount',
'delivery_fee',
'payment_amount',
'pay_type',
'pay_status',
'paid_at',
'status',
'cancel_reason',
'remark',
'completed_at',
];
protected $casts = [
'total_amount' => 'decimal:2',
'discount_amount' => 'decimal:2',
'delivery_fee' => 'decimal:2',
'payment_amount' => 'decimal:2',
'pay_type' => 'integer',
'pay_status' => 'integer',
'status' => 'integer',
'user_id' => 'integer',
'merchant_id' => 'integer',
'address_id' => 'integer',
'paid_at' => 'datetime',
'completed_at' => 'datetime',
];
}
@@ -0,0 +1,39 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class OrderPaymentModel extends Model
{
protected $table = 'order_payments';
protected $fillable = [
'payment_no',
'order_id',
'user_id',
'payment_transaction_id',
'amount',
'pay_type',
'status',
'paid_at',
'refund_at',
];
protected $casts = [
'order_id' => 'integer',
'user_id' => 'integer',
'payment_transaction_id' => 'integer',
'amount' => 'decimal:2',
'pay_type' => 'integer',
'status' => 'integer',
'paid_at' => 'datetime',
'refund_at' => 'datetime',
];
public function order(): BelongsTo
{
return $this->belongsTo(OrderModel::class, 'order_id', 'id');
}
}
@@ -0,0 +1,35 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class OrderRefundModel extends Model
{
protected $table = 'order_refunds';
protected $fillable = [
'refund_no',
'order_id',
'order_item_id',
'user_id',
'merchant_id',
'amount',
'reason',
'images',
'status',
'reply',
'processed_at',
];
protected $casts = [
'order_id' => 'integer',
'order_item_id' => 'integer',
'user_id' => 'integer',
'merchant_id' => 'integer',
'amount' => 'decimal:2',
'images' => 'array',
'status' => 'integer',
'processed_at' => 'datetime',
];
}
@@ -0,0 +1,28 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class PrintTaskModel extends Model
{
protected $table = 'print_tasks';
protected $fillable = [
'printer_id',
'order_id',
'content',
'copies',
'status',
'error_msg',
'printed_at',
];
protected $casts = [
'printer_id' => 'integer',
'order_id' => 'integer',
'copies' => 'integer',
'status' => 'integer',
'printed_at' => 'datetime',
];
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class PrinterModel extends Model
{
protected $table = 'printers';
protected $fillable = [
'merchant_id',
'name',
'brand',
'model',
'device_no',
'secret_key',
'status',
'config',
];
protected $casts = [
'merchant_id' => 'integer',
'status' => 'integer',
'config' => 'array',
];
}
@@ -0,0 +1,28 @@
<?php
namespace Modules\Merchant\Models;
use Illuminate\Database\Eloquent\Model;
class ProductCategoryModel extends Model
{
protected $table = 'product_categories';
protected $fillable = [
'merchant_id',
'parent_id',
'name',
'slug',
'description',
'icon',
'sort',
'status',
];
protected $casts = [
'merchant_id' => 'integer',
'parent_id' => 'integer',
'sort' => 'integer',
'status' => 'integer',
];
}
@@ -0,0 +1,14 @@
<?php
namespace Modules\Merchant\Providers;
use Illuminate\Support\ServiceProvider;
use Modules\AnnoRoute\AnnoRoute;
class MerchantServiceProvider extends ServiceProvider
{
public function boot(AnnoRoute $annoRoute): void
{
$annoRoute->register(base_path('modules/Merchant/Http/Controllers'));
}
}
@@ -0,0 +1,51 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Models\DepositPaymentModel;
#[RequestAttribute('/runner/deposit-payment', 'runner.deposit_payment')]
class DepositPaymentController extends BaseController
{
protected array $searchField = [
'status' => '=',
'pay_type' => '=',
'deposit_id' => '=',
'user_id' => '=',
];
protected array $quickSearchField = ['payment_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = DepositPaymentModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = DepositPaymentModel::find($id);
if (empty($model)) {
return $this->error('支付记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,73 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Http\Requests\RunnerApplicationFormRequest;
use Modules\Runner\Models\RunnerApplicationModel;
#[RequestAttribute('/runner/application', 'runner.application')]
class RunnerApplicationController extends BaseController
{
protected array $searchField = [
'status' => '=',
];
protected array $quickSearchField = ['real_name', 'mobile', 'id_card'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = RunnerApplicationModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(RunnerApplicationFormRequest $request): JsonResponse
{
RunnerApplicationModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, RunnerApplicationFormRequest $request): JsonResponse
{
$model = RunnerApplicationModel::find($id);
if (empty($model)) {
return $this->error('申请记录不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = RunnerApplicationModel::find($id);
if (empty($model)) {
return $this->error('申请记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,75 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Http\Requests\RunnerComplaintAppealFormRequest;
use Modules\Runner\Models\RunnerComplaintAppealModel;
#[RequestAttribute('/runner/complaint-appeal', 'runner.complaint_appeal')]
class RunnerComplaintAppealController extends BaseController
{
protected array $searchField = [
'status' => '=',
'complaint_id' => '=',
'worker_id' => '=',
];
protected array $quickSearchField = ['content'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = RunnerComplaintAppealModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(RunnerComplaintAppealFormRequest $request): JsonResponse
{
RunnerComplaintAppealModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, RunnerComplaintAppealFormRequest $request): JsonResponse
{
$model = RunnerComplaintAppealModel::find($id);
if (empty($model)) {
return $this->error('申诉记录不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = RunnerComplaintAppealModel::find($id);
if (empty($model)) {
return $this->error('申诉记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,77 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Http\Requests\RunnerComplaintFormRequest;
use Modules\Runner\Models\RunnerComplaintModel;
#[RequestAttribute('/runner/complaint', 'runner.complaint')]
class RunnerComplaintController extends BaseController
{
protected array $searchField = [
'status' => '=',
'type' => '=',
'user_id' => '=',
'worker_id' => '=',
'order_id' => '=',
];
protected array $quickSearchField = ['complaint_no', 'content'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = RunnerComplaintModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PostRoute(authorize: 'create')]
public function create(RunnerComplaintFormRequest $request): JsonResponse
{
RunnerComplaintModel::create($request->validated());
return $this->success();
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, RunnerComplaintFormRequest $request): JsonResponse
{
$model = RunnerComplaintModel::find($id);
if (empty($model)) {
return $this->error('投诉记录不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = RunnerComplaintModel::find($id);
if (empty($model)) {
return $this->error('投诉记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,33 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Models\RunnerCreditLogModel;
#[RequestAttribute('/runner/credit-log', 'runner.credit_log')]
class RunnerCreditLogController extends BaseController
{
protected array $searchField = [
'type' => '=',
'worker_id' => '=',
];
protected array $quickSearchField = ['description'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = RunnerCreditLogModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
}
@@ -0,0 +1,67 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Http\Requests\RunnerDepositFormRequest;
use Modules\Runner\Models\RunnerDepositModel;
#[RequestAttribute('/runner/deposit', 'runner.deposit')]
class RunnerDepositController extends BaseController
{
protected array $searchField = [
'status' => '=',
'worker_id' => '=',
'user_id' => '=',
];
protected array $quickSearchField = ['deposit_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = RunnerDepositModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, RunnerDepositFormRequest $request): JsonResponse
{
$model = RunnerDepositModel::find($id);
if (empty($model)) {
return $this->error('保证金记录不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = RunnerDepositModel::find($id);
if (empty($model)) {
return $this->error('保证金记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,68 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Http\Requests\RunnerWithdrawalFormRequest;
use Modules\Runner\Models\RunnerWithdrawalModel;
#[RequestAttribute('/runner/withdrawal', 'runner.withdrawal')]
class RunnerWithdrawalController extends BaseController
{
protected array $searchField = [
'status' => '=',
'channel' => '=',
'user_id' => '=',
'worker_id' => '=',
];
protected array $quickSearchField = ['withdraw_no'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = RunnerWithdrawalModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, RunnerWithdrawalFormRequest $request): JsonResponse
{
$model = RunnerWithdrawalModel::find($id);
if (empty($model)) {
return $this->error('提现记录不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = RunnerWithdrawalModel::find($id);
if (empty($model)) {
return $this->error('提现记录不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,65 @@
<?php
namespace Modules\Runner\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\AnnoRoute\Attribute\DeleteRoute;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
use Modules\Common\Http\Controllers\BaseController;
use Modules\Runner\Http\Requests\RunnerWorkerFormRequest;
use Modules\Runner\Models\RunnerWorkerModel;
#[RequestAttribute('/runner/worker', 'runner.worker')]
class RunnerWorkerController extends BaseController
{
protected array $searchField = [
'status' => '=',
];
protected array $quickSearchField = ['real_name', 'mobile'];
#[GetRoute(authorize: 'query')]
public function query(Request $request): JsonResponse
{
$params = $request->all();
$pageSize = $params['pageSize'] ?? 10;
$query = RunnerWorkerModel::query();
$data = $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
return $this->success($data);
}
#[PutRoute(
route: '/{id}',
authorize: 'update',
where: ['id' => '[0-9]+']
)]
public function update(int $id, RunnerWorkerFormRequest $request): JsonResponse
{
$model = RunnerWorkerModel::find($id);
if (empty($model)) {
return $this->error('跑腿员不存在');
}
$model->update($request->validated());
return $this->success();
}
#[DeleteRoute(
route: '/{id}',
authorize: 'delete',
where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
$model = RunnerWorkerModel::find($id);
if (empty($model)) {
return $this->error('跑腿员不存在');
}
$model->delete();
return $this->success();
}
}
@@ -0,0 +1,35 @@
<?php
namespace Modules\Runner\Http\Requests;
use Modules\Common\Http\Requests\BaseFormRequest;
class DepositPaymentFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
return [
'payment_no' => 'required|string|max:50',
'deposit_id' => 'required|integer|exists:runner_deposits,id',
'user_id' => 'required|integer|exists:user,id',
'payment_transaction_id' => 'nullable|integer',
'amount' => 'required|numeric|min:0',
'pay_type' => 'nullable|integer|in:0,1,2',
'status' => 'nullable|integer|in:0,1,2',
'paid_at' => 'nullable|date',
'refund_at' => 'nullable|date',
];
}
public function messages(): array
{
return [
'payment_no.required' => '支付单号不能为空',
'deposit_id.required' => '保证金记录不能为空',
'user_id.required' => '用户不能为空',
'amount.required' => '金额不能为空',
];
}
}
@@ -0,0 +1,50 @@
<?php
namespace Modules\Runner\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Common\Http\Requests\BaseFormRequest;
class RunnerApplicationFormRequest extends BaseFormRequest
{
protected $stopOnFirstFailure = true;
public function rules(): array
{
if (!$this->isUpdate()) {
return [
'user_id' => 'required|integer|exists:user,id',
'real_name' => 'required|string|max:30',
'mobile' => 'required|string|max:20',
'resume' => 'nullable|string|max:500',
'id_card' => 'required|string|size:18',
'id_card_front' => 'nullable|string|max:255',
'id_card_back' => 'nullable|string|max:255',
'status' => 'nullable|integer|in:0,1,2',
'review_remark' => 'nullable|string|max:255',
];
}
$id = $this->route('id');
return [
'user_id' => 'required|integer|exists:user,id',
'real_name' => 'required|string|max:30',
'mobile' => 'required|string|max:20',
'resume' => 'nullable|string|max:500',
'id_card' => ['required', 'string', 'size:18', Rule::unique('runner_applications', 'id_card')->ignore($id)],
'id_card_front' => 'nullable|string|max:255',
'id_card_back' => 'nullable|string|max:255',
'status' => 'nullable|integer|in:0,1,2',
'review_remark' => 'nullable|string|max:255',
];
}
public function messages(): array
{
return [
'real_name.required' => '真实姓名不能为空',
'mobile.required' => '联系电话不能为空',
'id_card.required' => '身份证号不能为空',
];
}
}

Some files were not shown because too many files have changed in this diff Show More