diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 35d6827..ee58690 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -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" - ] - } + ] } diff --git a/app/Http/Controllers/PaymentTransactionController.php b/app/Http/Controllers/PaymentTransactionController.php new file mode 100644 index 0000000..7c06760 --- /dev/null +++ b/app/Http/Controllers/PaymentTransactionController.php @@ -0,0 +1,49 @@ + '=', + '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(); + } +} diff --git a/app/Models/PaymentTransactionModel.php b/app/Models/PaymentTransactionModel.php new file mode 100644 index 0000000..1287371 --- /dev/null +++ b/app/Models/PaymentTransactionModel.php @@ -0,0 +1,36 @@ + 'decimal:2', + 'status' => 'integer', + 'business_id' => 'integer', + 'user_id' => 'integer', + 'raw_data' => 'array', + 'paid_at' => 'datetime', + ]; +} diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 8d06191..4385b16 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -9,6 +9,8 @@ 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, @@ -20,4 +22,6 @@ return [ MemberServiceProvider::class, ForumServiceProvider::class, MerchantServiceProvider::class, + TaskServiceProvider::class, + RunnerServiceProvider::class, ]; diff --git a/database/migrations/2026_05_30_000003_create_task_tables.php b/database/migrations/2026_05_30_000003_create_task_tables.php index 2f93060..738083f 100644 --- a/database/migrations/2026_05_30_000003_create_task_tables.php +++ b/database/migrations/2026_05_30_000003_create_task_tables.php @@ -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'); diff --git a/database/migrations/2026_05_30_000004_create_part_time_tables.php b/database/migrations/2026_05_30_000004_create_part_time_tables.php index 74eb428..bddd6a2 100644 --- a/database/migrations/2026_05_30_000004_create_part_time_tables.php +++ b/database/migrations/2026_05_30_000004_create_part_time_tables.php @@ -8,14 +8,14 @@ return new class extends Migration { public function up(): void { - // 兼职申请/报名 - if (! Schema::hasTable('part_time_applications')) { - Schema::create('part_time_applications', function (Blueprint $table) { + // 接单员申请 + if (! Schema::hasTable('runner_applications')) { + Schema::create('runner_applications', function (Blueprint $table) { $table->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('身份证背面照'); @@ -24,38 +24,41 @@ return new class extends Migration $table->timestamp('reviewed_at')->nullable()->comment('审核时间'); $table->timestamps(); $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->decimal('total_income', 10, 2)->default(0)->comment('累计收入'); - $table->integer('total_order')->default(0)->comment('累计订单'); - $table->decimal('credit_score', 10, 2)->default(100)->comment('信誉分'); - $table->timestamp('verified_at')->nullable()->comment('认证时间'); - $table->tinyInteger('status')->default(1)->comment('状态:0=禁止接单,1=正常'); + $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=已拒绝'); @@ -66,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'); } }; diff --git a/database/migrations/2026_05_30_000008_create_wallet_and_message_tables.php b/database/migrations/2026_05_30_000008_create_wallet_and_message_tables.php index 123c0c1..1f84cd6 100644 --- a/database/migrations/2026_05_30_000008_create_wallet_and_message_tables.php +++ b/database/migrations/2026_05_30_000008_create_wallet_and_message_tables.php @@ -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'); } }; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 80bc06d..98f14c6 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -13,6 +13,7 @@ class DatabaseSeeder extends Seeder { $this->call([ SysUserSeeder::class, + SysRuleSeeder::class, SysDataSeeder::class, SysAgentSeeder::class, ]); diff --git a/database/seeders/SysRuleSeeder.php b/database/seeders/SysRuleSeeder.php new file mode 100644 index 0000000..7fb2625 --- /dev/null +++ b/database/seeders/SysRuleSeeder.php @@ -0,0 +1,682 @@ +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' => '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' => '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') + ); + } + + /** + * 递归插入权限规则数据 + */ + 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); + } + } + } +} diff --git a/database/seeders/SysUserSeeder.php b/database/seeders/SysUserSeeder.php index ece49d5..5ff14b5 100644 --- a/database/seeders/SysUserSeeder.php +++ b/database/seeders/SysUserSeeder.php @@ -122,466 +122,6 @@ class SysUserSeeder extends Seeder ], ]); - $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' => '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, @@ -593,43 +133,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); - } - } - } } diff --git a/modules/Runner/Http/Controllers/DepositPaymentController.php b/modules/Runner/Http/Controllers/DepositPaymentController.php new file mode 100644 index 0000000..66fc87f --- /dev/null +++ b/modules/Runner/Http/Controllers/DepositPaymentController.php @@ -0,0 +1,51 @@ + '=', + '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(); + } +} diff --git a/modules/Runner/Http/Controllers/RunnerApplicationController.php b/modules/Runner/Http/Controllers/RunnerApplicationController.php new file mode 100644 index 0000000..3d3da60 --- /dev/null +++ b/modules/Runner/Http/Controllers/RunnerApplicationController.php @@ -0,0 +1,73 @@ + '=', + ]; + + 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(); + } +} diff --git a/modules/Runner/Http/Controllers/RunnerComplaintAppealController.php b/modules/Runner/Http/Controllers/RunnerComplaintAppealController.php new file mode 100644 index 0000000..b125227 --- /dev/null +++ b/modules/Runner/Http/Controllers/RunnerComplaintAppealController.php @@ -0,0 +1,75 @@ + '=', + '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(); + } +} diff --git a/modules/Runner/Http/Controllers/RunnerComplaintController.php b/modules/Runner/Http/Controllers/RunnerComplaintController.php new file mode 100644 index 0000000..3d75687 --- /dev/null +++ b/modules/Runner/Http/Controllers/RunnerComplaintController.php @@ -0,0 +1,77 @@ + '=', + '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(); + } +} diff --git a/modules/Runner/Http/Controllers/RunnerCreditLogController.php b/modules/Runner/Http/Controllers/RunnerCreditLogController.php new file mode 100644 index 0000000..55cb251 --- /dev/null +++ b/modules/Runner/Http/Controllers/RunnerCreditLogController.php @@ -0,0 +1,33 @@ + '=', + '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); + } +} diff --git a/modules/Runner/Http/Controllers/RunnerDepositController.php b/modules/Runner/Http/Controllers/RunnerDepositController.php new file mode 100644 index 0000000..f8083ae --- /dev/null +++ b/modules/Runner/Http/Controllers/RunnerDepositController.php @@ -0,0 +1,67 @@ + '=', + '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(); + } +} diff --git a/modules/Runner/Http/Controllers/RunnerWithdrawalController.php b/modules/Runner/Http/Controllers/RunnerWithdrawalController.php new file mode 100644 index 0000000..6db800d --- /dev/null +++ b/modules/Runner/Http/Controllers/RunnerWithdrawalController.php @@ -0,0 +1,68 @@ + '=', + '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(); + } +} diff --git a/modules/Runner/Http/Controllers/RunnerWorkerController.php b/modules/Runner/Http/Controllers/RunnerWorkerController.php new file mode 100644 index 0000000..2afe8d6 --- /dev/null +++ b/modules/Runner/Http/Controllers/RunnerWorkerController.php @@ -0,0 +1,65 @@ + '=', + ]; + + 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(); + } +} diff --git a/modules/Runner/Http/Requests/DepositPaymentFormRequest.php b/modules/Runner/Http/Requests/DepositPaymentFormRequest.php new file mode 100644 index 0000000..3126e06 --- /dev/null +++ b/modules/Runner/Http/Requests/DepositPaymentFormRequest.php @@ -0,0 +1,35 @@ + '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' => '金额不能为空', + ]; + } +} diff --git a/modules/Runner/Http/Requests/RunnerApplicationFormRequest.php b/modules/Runner/Http/Requests/RunnerApplicationFormRequest.php new file mode 100644 index 0000000..701dbf8 --- /dev/null +++ b/modules/Runner/Http/Requests/RunnerApplicationFormRequest.php @@ -0,0 +1,50 @@ +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' => '身份证号不能为空', + ]; + } +} diff --git a/modules/Runner/Http/Requests/RunnerComplaintAppealFormRequest.php b/modules/Runner/Http/Requests/RunnerComplaintAppealFormRequest.php new file mode 100644 index 0000000..a6ccfdf --- /dev/null +++ b/modules/Runner/Http/Requests/RunnerComplaintAppealFormRequest.php @@ -0,0 +1,44 @@ +isUpdate()) { + return [ + 'complaint_id' => 'required|integer|exists:runner_complaints,id', + 'worker_id' => 'required|integer|exists:runner_workers,id', + 'content' => 'required|string|max:1000', + 'images' => 'nullable|json', + 'status' => 'nullable|integer|in:0,1,2', + 'reply' => 'nullable|string|max:1000', + 'reviewed_at' => 'nullable|date', + ]; + } + + return [ + 'complaint_id' => 'required|integer|exists:runner_complaints,id', + 'worker_id' => 'required|integer|exists:runner_workers,id', + 'content' => 'required|string|max:1000', + 'images' => 'nullable|json', + 'status' => 'nullable|integer|in:0,1,2', + 'reply' => 'nullable|string|max:1000', + 'reviewed_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'complaint_id.required' => '投诉不能为空', + 'worker_id.required' => '跑腿员不能为空', + 'content.required' => '申诉内容不能为空', + ]; + } +} diff --git a/modules/Runner/Http/Requests/RunnerComplaintFormRequest.php b/modules/Runner/Http/Requests/RunnerComplaintFormRequest.php new file mode 100644 index 0000000..3d418ff --- /dev/null +++ b/modules/Runner/Http/Requests/RunnerComplaintFormRequest.php @@ -0,0 +1,59 @@ +isUpdate()) { + return [ + 'complaint_no' => 'required|string|max:50|unique:runner_complaints,complaint_no', + 'user_id' => 'required|integer|exists:user,id', + 'worker_id' => 'nullable|integer|exists:runner_workers,id', + 'order_id' => 'nullable|integer', + 'type' => 'nullable|string|max:50', + 'content' => 'required|string|max:1000', + 'images' => 'nullable|json', + 'status' => 'nullable|integer|in:0,1,2', + 'result' => 'nullable|string|max:255', + 'result_remark' => 'nullable|string|max:500', + 'handled_at' => 'nullable|date', + ]; + } + + $id = $this->route('id'); + return [ + 'complaint_no' => [ + 'required', + 'string', + 'max:50', + Rule::unique('runner_complaints', 'complaint_no')->ignore($id), + ], + 'user_id' => 'required|integer|exists:user,id', + 'worker_id' => 'nullable|integer|exists:runner_workers,id', + 'order_id' => 'nullable|integer', + 'type' => 'nullable|string|max:50', + 'content' => 'required|string|max:1000', + 'images' => 'nullable|json', + 'status' => 'nullable|integer|in:0,1,2', + 'result' => 'nullable|string|max:255', + 'result_remark' => 'nullable|string|max:500', + 'handled_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'complaint_no.required' => '投诉单号不能为空', + 'user_id.required' => '用户不能为空', + 'content.required' => '投诉内容不能为空', + ]; + } +} diff --git a/modules/Runner/Http/Requests/RunnerCreditLogFormRequest.php b/modules/Runner/Http/Requests/RunnerCreditLogFormRequest.php new file mode 100644 index 0000000..e456093 --- /dev/null +++ b/modules/Runner/Http/Requests/RunnerCreditLogFormRequest.php @@ -0,0 +1,31 @@ + 'required|integer|exists:runner_workers,id', + 'score' => 'required|numeric', + 'score_after' => 'nullable|numeric', + 'type' => 'nullable|string|max:50', + 'description' => 'nullable|string|max:500', + 'related_type' => 'nullable|string|max:50', + 'related_id' => 'nullable|integer', + ]; + } + + public function messages(): array + { + return [ + 'worker_id.required' => '跑腿员不能为空', + 'score.required' => '分值不能为空', + ]; + } +} diff --git a/modules/Runner/Http/Requests/RunnerDepositFormRequest.php b/modules/Runner/Http/Requests/RunnerDepositFormRequest.php new file mode 100644 index 0000000..49bf693 --- /dev/null +++ b/modules/Runner/Http/Requests/RunnerDepositFormRequest.php @@ -0,0 +1,35 @@ + 'required|string|max:50', + 'worker_id' => 'required|integer|exists:runner_workers,id', + 'user_id' => 'required|integer|exists:user,id', + 'amount' => 'required|numeric|min:0', + 'status' => 'nullable|integer|in:0,1,2,3', + 'deduct_reason' => 'nullable|string|max:255', + 'paid_at' => 'nullable|date', + 'refund_at' => 'nullable|date', + 'deducted_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'deposit_no.required' => '保证金单号不能为空', + 'worker_id.required' => '跑腿员不能为空', + 'user_id.required' => '用户不能为空', + 'amount.required' => '金额不能为空', + ]; + } +} diff --git a/modules/Runner/Http/Requests/RunnerWithdrawalFormRequest.php b/modules/Runner/Http/Requests/RunnerWithdrawalFormRequest.php new file mode 100644 index 0000000..f8e966c --- /dev/null +++ b/modules/Runner/Http/Requests/RunnerWithdrawalFormRequest.php @@ -0,0 +1,36 @@ + 'required|string|max:50', + 'user_id' => 'required|integer|exists:user,id', + 'worker_id' => 'required|integer|exists:runner_workers,id', + 'amount' => 'required|numeric|min:0', + 'fee' => 'nullable|numeric|min:0', + 'channel' => 'nullable|string|max:50', + 'account_info' => 'nullable|json', + 'status' => 'nullable|integer|in:0,1,2', + 'remark' => 'nullable|string|max:255', + 'processed_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'withdraw_no.required' => '提现单号不能为空', + 'user_id.required' => '用户不能为空', + 'worker_id.required' => '跑腿员不能为空', + 'amount.required' => '提现金额不能为空', + ]; + } +} diff --git a/modules/Runner/Http/Requests/RunnerWorkerFormRequest.php b/modules/Runner/Http/Requests/RunnerWorkerFormRequest.php new file mode 100644 index 0000000..74d11a8 --- /dev/null +++ b/modules/Runner/Http/Requests/RunnerWorkerFormRequest.php @@ -0,0 +1,48 @@ +isUpdate()) { + return [ + 'user_id' => 'required|integer|exists:user,id', + 'real_name' => 'required|string|max:30', + 'mobile' => 'required|string|max:20', + 'id_card' => 'required|string|size:18', + 'total_income' => 'nullable|numeric|min:0', + 'total_order' => 'nullable|integer|min:0', + 'cancel_order' => 'nullable|integer|min:0', + 'credit_score' => 'nullable|numeric|min:0|max:100', + 'status' => 'nullable|integer|in:0,1', + ]; + } + + return [ + 'user_id' => 'required|integer|exists:user,id', + 'real_name' => 'required|string|max:30', + 'mobile' => 'required|string|max:20', + 'id_card' => 'required|string|size:18', + 'total_income' => 'nullable|numeric|min:0', + 'total_order' => 'nullable|integer|min:0', + 'cancel_order' => 'nullable|integer|min:0', + 'credit_score' => 'nullable|numeric|min:0|max:100', + 'status' => 'nullable|integer|in:0,1', + ]; + } + + public function messages(): array + { + return [ + 'real_name.required' => '真实姓名不能为空', + 'mobile.required' => '联系电话不能为空', + 'id_card.required' => '身份证号不能为空', + ]; + } +} diff --git a/modules/Runner/Models/DepositPaymentModel.php b/modules/Runner/Models/DepositPaymentModel.php new file mode 100644 index 0000000..6172d1a --- /dev/null +++ b/modules/Runner/Models/DepositPaymentModel.php @@ -0,0 +1,33 @@ + 'integer', + 'user_id' => 'integer', + 'payment_transaction_id' => 'integer', + 'amount' => 'decimal:2', + 'pay_type' => 'integer', + 'status' => 'integer', + 'paid_at' => 'datetime', + 'refund_at' => 'datetime', + ]; +} diff --git a/modules/Runner/Models/RunnerApplicationModel.php b/modules/Runner/Models/RunnerApplicationModel.php new file mode 100644 index 0000000..ab3733e --- /dev/null +++ b/modules/Runner/Models/RunnerApplicationModel.php @@ -0,0 +1,29 @@ + 'integer', + 'status' => 'integer', + 'reviewed_at' => 'datetime', + ]; +} diff --git a/modules/Runner/Models/RunnerComplaintAppealModel.php b/modules/Runner/Models/RunnerComplaintAppealModel.php new file mode 100644 index 0000000..8105dc1 --- /dev/null +++ b/modules/Runner/Models/RunnerComplaintAppealModel.php @@ -0,0 +1,28 @@ + 'integer', + 'worker_id' => 'integer', + 'images' => 'array', + 'status' => 'integer', + 'reviewed_at' => 'datetime', + ]; +} diff --git a/modules/Runner/Models/RunnerComplaintModel.php b/modules/Runner/Models/RunnerComplaintModel.php new file mode 100644 index 0000000..6b9fa64 --- /dev/null +++ b/modules/Runner/Models/RunnerComplaintModel.php @@ -0,0 +1,33 @@ + 'integer', + 'worker_id' => 'integer', + 'order_id' => 'integer', + 'images' => 'array', + 'status' => 'integer', + 'handled_at' => 'datetime', + ]; +} diff --git a/modules/Runner/Models/RunnerCreditLogModel.php b/modules/Runner/Models/RunnerCreditLogModel.php new file mode 100644 index 0000000..ba9cb95 --- /dev/null +++ b/modules/Runner/Models/RunnerCreditLogModel.php @@ -0,0 +1,27 @@ + 'integer', + 'score' => 'decimal:2', + 'score_after' => 'decimal:2', + 'related_id' => 'integer', + ]; +} diff --git a/modules/Runner/Models/RunnerDepositModel.php b/modules/Runner/Models/RunnerDepositModel.php new file mode 100644 index 0000000..83ab1a4 --- /dev/null +++ b/modules/Runner/Models/RunnerDepositModel.php @@ -0,0 +1,32 @@ + 'integer', + 'user_id' => 'integer', + 'amount' => 'decimal:2', + 'status' => 'integer', + 'paid_at' => 'datetime', + 'refund_at' => 'datetime', + 'deducted_at' => 'datetime', + ]; +} diff --git a/modules/Runner/Models/RunnerWithdrawalModel.php b/modules/Runner/Models/RunnerWithdrawalModel.php new file mode 100644 index 0000000..6baa413 --- /dev/null +++ b/modules/Runner/Models/RunnerWithdrawalModel.php @@ -0,0 +1,33 @@ + 'integer', + 'worker_id' => 'integer', + 'amount' => 'decimal:2', + 'fee' => 'decimal:2', + 'account_info' => 'array', + 'status' => 'integer', + 'processed_at' => 'datetime', + ]; +} diff --git a/modules/Runner/Models/RunnerWorkerModel.php b/modules/Runner/Models/RunnerWorkerModel.php new file mode 100644 index 0000000..810d840 --- /dev/null +++ b/modules/Runner/Models/RunnerWorkerModel.php @@ -0,0 +1,33 @@ + 'integer', + 'total_income' => 'decimal:2', + 'total_order' => 'integer', + 'cancel_order' => 'integer', + 'credit_score' => 'decimal:2', + 'verified_at' => 'datetime', + 'status' => 'integer', + ]; +} diff --git a/modules/Runner/Providers/RunnerServiceProvider.php b/modules/Runner/Providers/RunnerServiceProvider.php new file mode 100644 index 0000000..f713dda --- /dev/null +++ b/modules/Runner/Providers/RunnerServiceProvider.php @@ -0,0 +1,14 @@ +register(base_path('modules/Runner/Http/Controllers')); + } +} diff --git a/modules/Task/Http/Controllers/TaskBidController.php b/modules/Task/Http/Controllers/TaskBidController.php new file mode 100644 index 0000000..ebed96d --- /dev/null +++ b/modules/Task/Http/Controllers/TaskBidController.php @@ -0,0 +1,75 @@ + '=', + 'task_id' => '=', + 'user_id' => '=', + ]; + + protected array $quickSearchField = ['message']; + + #[GetRoute(authorize: 'query')] + public function query(Request $request): JsonResponse + { + $params = $request->all(); + $pageSize = $params['pageSize'] ?? 10; + $query = TaskBidModel::query(); + $data = $this->buildSearch($params, $query) + ->paginate($pageSize) + ->toArray(); + return $this->success($data); + } + + #[PostRoute(authorize: 'create')] + public function create(TaskBidFormRequest $request): JsonResponse + { + TaskBidModel::create($request->validated()); + return $this->success(); + } + + #[PutRoute( + route: '/{id}', + authorize: 'update', + where: ['id' => '[0-9]+'] + )] + public function update(int $id, TaskBidFormRequest $request): JsonResponse + { + $model = TaskBidModel::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 = TaskBidModel::find($id); + if (empty($model)) { + return $this->error('投标不存在'); + } + $model->delete(); + return $this->success(); + } +} diff --git a/modules/Task/Http/Controllers/TaskCategoryController.php b/modules/Task/Http/Controllers/TaskCategoryController.php new file mode 100644 index 0000000..d9dd73c --- /dev/null +++ b/modules/Task/Http/Controllers/TaskCategoryController.php @@ -0,0 +1,73 @@ + '=', + ]; + + protected array $quickSearchField = ['name', 'slug']; + + #[GetRoute(authorize: 'query')] + public function query(Request $request): JsonResponse + { + $params = $request->all(); + $pageSize = $params['pageSize'] ?? 10; + $query = TaskCategoryModel::query(); + $data = $this->buildSearch($params, $query) + ->paginate($pageSize) + ->toArray(); + return $this->success($data); + } + + #[PostRoute(authorize: 'create')] + public function create(TaskCategoryFormRequest $request): JsonResponse + { + TaskCategoryModel::create($request->validated()); + return $this->success(); + } + + #[PutRoute( + route: '/{id}', + authorize: 'update', + where: ['id' => '[0-9]+'] + )] + public function update(int $id, TaskCategoryFormRequest $request): JsonResponse + { + $model = TaskCategoryModel::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 = TaskCategoryModel::find($id); + if (empty($model)) { + return $this->error('分类不存在'); + } + $model->delete(); + return $this->success(); + } +} diff --git a/modules/Task/Http/Controllers/TaskOrderController.php b/modules/Task/Http/Controllers/TaskOrderController.php new file mode 100644 index 0000000..e3aeb28 --- /dev/null +++ b/modules/Task/Http/Controllers/TaskOrderController.php @@ -0,0 +1,84 @@ + '=', + 'pay_status' => '=', + 'category_id' => '=', + 'user_id' => '=', + 'runner_id' => '=', + ]; + + protected array $quickSearchField = ['title', 'order_no', 'contact_name', 'contact_mobile']; + + #[GetRoute(authorize: 'query')] + public function query(Request $request): JsonResponse + { + $params = $request->all(); + $pageSize = $params['pageSize'] ?? 10; + $query = TaskOrderModel::query(); + + if (!empty($params['category_slug'])) { + $query->whereHas('category', function ($q) use ($params) { + $q->where('slug', $params['category_slug']); + }); + } + + $data = $this->buildSearch($params, $query) + ->paginate($pageSize) + ->toArray(); + return $this->success($data); + } + + #[PostRoute(authorize: 'create')] + public function create(TaskOrderFormRequest $request): JsonResponse + { + TaskOrderModel::create($request->validated()); + return $this->success(); + } + + #[PutRoute( + route: '/{id}', + authorize: 'update', + where: ['id' => '[0-9]+'] + )] + public function update(int $id, TaskOrderFormRequest $request): JsonResponse + { + $model = TaskOrderModel::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 = TaskOrderModel::find($id); + if (empty($model)) { + return $this->error('订单不存在'); + } + $model->delete(); + return $this->success(); + } +} diff --git a/modules/Task/Http/Controllers/TaskPaymentController.php b/modules/Task/Http/Controllers/TaskPaymentController.php new file mode 100644 index 0000000..9953c04 --- /dev/null +++ b/modules/Task/Http/Controllers/TaskPaymentController.php @@ -0,0 +1,62 @@ + '=', + '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 = TaskPaymentModel::query(); + $data = $this->buildSearch($params, $query) + ->paginate($pageSize) + ->toArray(); + return $this->success($data); + } + + #[GetRoute( + route: '/order/{orderId}', + authorize: 'query', + where: ['orderId' => '[0-9]+'] + )] + public function getByOrderId(int $orderId): JsonResponse + { + $payments = TaskPaymentModel::where('order_id', $orderId)->get(); + return $this->success($payments); + } + + #[DeleteRoute( + route: '/{id}', + authorize: 'delete', + where: ['id' => '[0-9]+'] + )] + public function delete(int $id): JsonResponse + { + $model = TaskPaymentModel::find($id); + if (empty($model)) { + return $this->error('支付记录不存在'); + } + $model->delete(); + return $this->success(); + } +} diff --git a/modules/Task/Http/Requests/TaskBidFormRequest.php b/modules/Task/Http/Requests/TaskBidFormRequest.php new file mode 100644 index 0000000..e4b2dee --- /dev/null +++ b/modules/Task/Http/Requests/TaskBidFormRequest.php @@ -0,0 +1,41 @@ +isUpdate()) { + return [ + 'task_id' => 'required|integer', + 'user_id' => 'required|integer', + 'price' => 'nullable|numeric|min:0', + 'message' => 'nullable|string|max:500', + 'status' => 'nullable|integer|in:0,1,2', + 'accepted_at' => 'nullable|date', + ]; + } + + return [ + 'task_id' => 'required|integer', + 'user_id' => 'required|integer', + 'price' => 'nullable|numeric|min:0', + 'message' => 'nullable|string|max:500', + 'status' => 'nullable|integer|in:0,1,2', + 'accepted_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'task_id.required' => '任务不能为空', + 'user_id.required' => '用户不能为空', + ]; + } +} diff --git a/modules/Task/Http/Requests/TaskCategoryFormRequest.php b/modules/Task/Http/Requests/TaskCategoryFormRequest.php new file mode 100644 index 0000000..1e1235b --- /dev/null +++ b/modules/Task/Http/Requests/TaskCategoryFormRequest.php @@ -0,0 +1,51 @@ +isUpdate()) { + return [ + 'name' => 'required|string|max:50', + 'slug' => 'required|string|max:50|unique:task_categories,slug', + 'description' => 'nullable|string|max:255', + 'icon' => 'nullable|string|max:255', + 'form_schema' => 'nullable|json', + 'sort' => 'nullable|integer|min:0', + 'status' => 'nullable|integer|in:0,1', + ]; + } + + $id = $this->route('id'); + return [ + 'name' => 'required|string|max:50', + 'slug' => [ + 'required', + 'string', + 'max:50', + Rule::unique('task_categories', 'slug')->ignore($id), + ], + 'description' => 'nullable|string|max:255', + 'icon' => 'nullable|string|max:255', + 'form_schema' => 'nullable|json', + 'sort' => 'nullable|integer|min:0', + 'status' => 'nullable|integer|in:0,1', + ]; + } + + public function messages(): array + { + return [ + 'name.required' => '分类名称不能为空', + 'slug.required' => '分类标识不能为空', + 'slug.unique' => '分类标识已存在', + ]; + } +} diff --git a/modules/Task/Http/Requests/TaskOrderFormRequest.php b/modules/Task/Http/Requests/TaskOrderFormRequest.php new file mode 100644 index 0000000..5d51356 --- /dev/null +++ b/modules/Task/Http/Requests/TaskOrderFormRequest.php @@ -0,0 +1,85 @@ +isUpdate()) { + return [ + 'order_no' => 'required|string|max:50|unique:task_orders,order_no', + 'user_id' => 'required|integer', + 'runner_id' => 'nullable|integer', + 'category_id' => 'required|integer', + 'title' => 'required|string|max:255', + 'description' => 'nullable|string', + 'images' => 'nullable|json', + 'extra' => 'nullable|json', + 'price' => 'nullable|numeric|min:0', + 'address' => 'nullable|string|max:255', + 'contact_name' => 'required|string|max:50', + 'contact_mobile' => 'required|string|max:20', + 'deadline' => 'nullable|date', + 'pay_type' => 'nullable|integer|in:0,1,2', + 'pay_status' => 'nullable|integer|in:0,1,2', + 'paid_at' => 'nullable|date', + 'status' => 'nullable|integer|in:0,1,2,3,4,5', + 'cancel_reason' => 'nullable|string|max:255', + 'remark' => 'nullable|string|max:255', + 'accepted_at' => 'nullable|date', + 'completed_at' => 'nullable|date', + 'cancelled_at' => 'nullable|date', + ]; + } + + $id = $this->route('id'); + return [ + 'order_no' => [ + 'required', + 'string', + 'max:50', + Rule::unique('task_orders', 'order_no')->ignore($id), + ], + 'user_id' => 'required|integer', + 'runner_id' => 'nullable|integer', + 'category_id' => 'required|integer', + 'title' => 'required|string|max:255', + 'description' => 'nullable|string', + 'images' => 'nullable|json', + 'extra' => 'nullable|json', + 'price' => 'nullable|numeric|min:0', + 'address' => 'nullable|string|max:255', + 'contact_name' => 'required|string|max:50', + 'contact_mobile' => 'required|string|max:20', + 'deadline' => 'nullable|date', + 'pay_type' => 'nullable|integer|in:0,1,2', + 'pay_status' => 'nullable|integer|in:0,1,2', + 'paid_at' => 'nullable|date', + 'status' => 'nullable|integer|in:0,1,2,3,4,5', + 'cancel_reason' => 'nullable|string|max:255', + 'remark' => 'nullable|string|max:255', + 'accepted_at' => 'nullable|date', + 'completed_at' => 'nullable|date', + 'cancelled_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'order_no.required' => '订单号不能为空', + 'order_no.unique' => '订单号已存在', + 'user_id.required' => '用户不能为空', + 'category_id.required' => '分类不能为空', + 'title.required' => '标题不能为空', + 'contact_name.required' => '联系人不能为空', + 'contact_mobile.required' => '联系电话不能为空', + ]; + } +} diff --git a/modules/Task/Http/Requests/TaskPaymentFormRequest.php b/modules/Task/Http/Requests/TaskPaymentFormRequest.php new file mode 100644 index 0000000..2ba11f1 --- /dev/null +++ b/modules/Task/Http/Requests/TaskPaymentFormRequest.php @@ -0,0 +1,38 @@ + 'required|string|max:50|unique:task_payments,payment_no', + 'order_id' => 'required|integer', + 'user_id' => 'required|integer', + 'payment_transaction_id' => 'nullable|integer', + 'amount' => 'required|numeric|min:0', + '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' => '订单不能为空', + 'user_id.required' => '用户不能为空', + 'amount.required' => '金额不能为空', + 'pay_type.required' => '支付方式不能为空', + 'status.required' => '状态不能为空', + ]; + } +} diff --git a/modules/Task/Models/TaskBidModel.php b/modules/Task/Models/TaskBidModel.php new file mode 100644 index 0000000..e6ea7a6 --- /dev/null +++ b/modules/Task/Models/TaskBidModel.php @@ -0,0 +1,27 @@ + 'decimal:2', + 'status' => 'integer', + 'task_id' => 'integer', + 'user_id' => 'integer', + 'accepted_at' => 'datetime', + ]; +} diff --git a/modules/Task/Models/TaskCategoryModel.php b/modules/Task/Models/TaskCategoryModel.php new file mode 100644 index 0000000..d9f8b19 --- /dev/null +++ b/modules/Task/Models/TaskCategoryModel.php @@ -0,0 +1,26 @@ + 'integer', + 'status' => 'integer', + 'form_schema' => 'array', + ]; +} diff --git a/modules/Task/Models/TaskOrderModel.php b/modules/Task/Models/TaskOrderModel.php new file mode 100644 index 0000000..42ca10f --- /dev/null +++ b/modules/Task/Models/TaskOrderModel.php @@ -0,0 +1,67 @@ + 'array', + 'extra' => 'array', + 'price' => 'decimal:2', + 'pay_type' => 'integer', + 'pay_status' => 'integer', + 'status' => 'integer', + 'user_id' => 'integer', + 'runner_id' => 'integer', + 'category_id' => 'integer', + 'deadline' => 'datetime', + 'paid_at' => 'datetime', + 'accepted_at' => 'datetime', + 'completed_at' => 'datetime', + 'cancelled_at' => 'datetime', + ]; + + protected $with = ['category']; + + protected $appends = ['category_slug']; + + public function category(): BelongsTo + { + return $this->belongsTo(TaskCategoryModel::class, 'category_id'); + } + + public function getCategorySlugAttribute(): ?string + { + return $this->category?->slug; + } +} diff --git a/modules/Task/Models/TaskPaymentModel.php b/modules/Task/Models/TaskPaymentModel.php new file mode 100644 index 0000000..0d29213 --- /dev/null +++ b/modules/Task/Models/TaskPaymentModel.php @@ -0,0 +1,33 @@ + 'decimal:2', + 'pay_type' => 'integer', + 'status' => 'integer', + 'order_id' => 'integer', + 'user_id' => 'integer', + 'payment_transaction_id' => 'integer', + 'paid_at' => 'datetime', + 'refund_at' => 'datetime', + ]; +} diff --git a/modules/Task/Providers/TaskServiceProvider.php b/modules/Task/Providers/TaskServiceProvider.php new file mode 100644 index 0000000..50e113c --- /dev/null +++ b/modules/Task/Providers/TaskServiceProvider.php @@ -0,0 +1,14 @@ +register(base_path('modules/Task/Http/Controllers')); + } +} diff --git a/web/domain/iDepositPayment.ts b/web/domain/iDepositPayment.ts new file mode 100644 index 0000000..0e9fe27 --- /dev/null +++ b/web/domain/iDepositPayment.ts @@ -0,0 +1,14 @@ +export default interface IDepositPayment { + id?: number; + payment_no?: string; + deposit_id?: number; + user_id?: number; + payment_transaction_id?: number; + amount?: number; + pay_type?: string; + status?: number; + paid_at?: string; + refund_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iPaymentTransaction.ts b/web/domain/iPaymentTransaction.ts new file mode 100644 index 0000000..d25272c --- /dev/null +++ b/web/domain/iPaymentTransaction.ts @@ -0,0 +1,16 @@ +export default interface IPaymentTransaction { + id?: number; + transaction_no?: string; + out_trade_no?: string; + pay_type?: string; + amount?: number; + status?: number; + business_type?: string; + business_id?: number; + user_id?: number; + openid?: string; + raw_data?: Record; + paid_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iRunnerApplication.ts b/web/domain/iRunnerApplication.ts new file mode 100644 index 0000000..3539d48 --- /dev/null +++ b/web/domain/iRunnerApplication.ts @@ -0,0 +1,15 @@ +export default interface IRunnerApplication { + id?: number; + user_id?: number; + real_name?: string; + mobile?: string; + resume?: string; + id_card?: string; + id_card_front?: string; + id_card_back?: string; + status?: number; + review_remark?: string; + reviewed_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iRunnerComplaint.ts b/web/domain/iRunnerComplaint.ts new file mode 100644 index 0000000..556fd87 --- /dev/null +++ b/web/domain/iRunnerComplaint.ts @@ -0,0 +1,16 @@ +export default interface IRunnerComplaint { + id?: number; + complaint_no?: string; + user_id?: number; + worker_id?: number; + order_id?: number; + type?: string; + content?: string; + images?: string; + status?: number; + result?: string; + result_remark?: string; + handled_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iRunnerComplaintAppeal.ts b/web/domain/iRunnerComplaintAppeal.ts new file mode 100644 index 0000000..12edf30 --- /dev/null +++ b/web/domain/iRunnerComplaintAppeal.ts @@ -0,0 +1,12 @@ +export default interface IRunnerComplaintAppeal { + id?: number; + complaint_id?: number; + worker_id?: number; + content?: string; + images?: string; + status?: number; + reply?: string; + reviewed_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iRunnerCreditLog.ts b/web/domain/iRunnerCreditLog.ts new file mode 100644 index 0000000..ab083e5 --- /dev/null +++ b/web/domain/iRunnerCreditLog.ts @@ -0,0 +1,12 @@ +export default interface IRunnerCreditLog { + id?: number; + worker_id?: number; + score?: number; + score_after?: number; + type?: string; + description?: string; + related_type?: string; + related_id?: number; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iRunnerDeposit.ts b/web/domain/iRunnerDeposit.ts new file mode 100644 index 0000000..c7281e1 --- /dev/null +++ b/web/domain/iRunnerDeposit.ts @@ -0,0 +1,14 @@ +export default interface IRunnerDeposit { + id?: number; + deposit_no?: string; + worker_id?: number; + user_id?: number; + amount?: number; + status?: number; + deduct_reason?: string; + paid_at?: string; + refund_at?: string; + deducted_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iRunnerWithdrawal.ts b/web/domain/iRunnerWithdrawal.ts new file mode 100644 index 0000000..63f0398 --- /dev/null +++ b/web/domain/iRunnerWithdrawal.ts @@ -0,0 +1,15 @@ +export default interface IRunnerWithdrawal { + id?: number; + withdraw_no?: string; + user_id?: number; + worker_id?: number; + amount?: number; + fee?: number; + channel?: string; + account_info?: string; + status?: number; + remark?: string; + processed_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iRunnerWorker.ts b/web/domain/iRunnerWorker.ts new file mode 100644 index 0000000..060fbc2 --- /dev/null +++ b/web/domain/iRunnerWorker.ts @@ -0,0 +1,15 @@ +export default interface IRunnerWorker { + id?: number; + user_id?: number; + real_name?: string; + mobile?: string; + id_card?: string; + total_income?: number; + total_order?: number; + cancel_order?: number; + credit_score?: number; + verified_at?: string; + status?: number; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iTaskBid.ts b/web/domain/iTaskBid.ts new file mode 100644 index 0000000..355638c --- /dev/null +++ b/web/domain/iTaskBid.ts @@ -0,0 +1,11 @@ +export default interface ITaskBid { + id?: number; + task_id?: number; + user_id?: number; + price?: number; + message?: string; + status?: number; + accepted_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iTaskCategory.ts b/web/domain/iTaskCategory.ts new file mode 100644 index 0000000..a340b3c --- /dev/null +++ b/web/domain/iTaskCategory.ts @@ -0,0 +1,12 @@ +export default interface ITaskCategory { + id?: number; + name?: string; + slug?: string; + description?: string; + icon?: string; + form_schema?: string; + sort?: number; + status?: number; + created_at?: string; + updated_at?: string; +} diff --git a/web/domain/iTaskOrder.ts b/web/domain/iTaskOrder.ts new file mode 100644 index 0000000..7d5a913 --- /dev/null +++ b/web/domain/iTaskOrder.ts @@ -0,0 +1,29 @@ +export default interface ITaskOrder { + id?: number; + order_no?: string; + user_id?: number; + runner_id?: number; + category_id?: number; + title?: string; + description?: string; + images?: string; + extra?: string; + price?: number; + address?: string; + contact_name?: string; + contact_mobile?: string; + deadline?: string; + pay_type?: string; + pay_status?: number; + paid_at?: string; + status?: number; + cancel_reason?: string; + remark?: string; + accepted_at?: string; + completed_at?: string; + cancelled_at?: string; + created_at?: string; + updated_at?: string; + deleted_at?: string; + category_slug?: string; +} diff --git a/web/domain/iTaskPayment.ts b/web/domain/iTaskPayment.ts new file mode 100644 index 0000000..af63094 --- /dev/null +++ b/web/domain/iTaskPayment.ts @@ -0,0 +1,14 @@ +export default interface ITaskPayment { + id?: number; + payment_no?: string; + order_id?: number; + user_id?: number; + payment_transaction_id?: number; + amount?: number; + pay_type?: string; + status?: number; + paid_at?: string; + refund_at?: string; + created_at?: string; + updated_at?: string; +} diff --git a/web/locales/en_US/finance/deposit-payment.ts b/web/locales/en_US/finance/deposit-payment.ts new file mode 100644 index 0000000..9fcaff7 --- /dev/null +++ b/web/locales/en_US/finance/deposit-payment.ts @@ -0,0 +1,21 @@ +export default { + "finance.deposit_payment.page.title": "Deposit Payment Logs", + "finance.deposit_payment.page.description": "View deposit payment records", + "finance.deposit_payment.id": "ID", + "finance.deposit_payment.payment_no": "Payment No", + "finance.deposit_payment.deposit_id": "Deposit ID", + "finance.deposit_payment.user_id": "User ID", + "finance.deposit_payment.payment_transaction_id": "Transaction ID", + "finance.deposit_payment.amount": "Amount", + "finance.deposit_payment.pay_type": "Pay Method", + "finance.deposit_payment.pay_type.0": "Balance", + "finance.deposit_payment.pay_type.1": "WeChat Pay", + "finance.deposit_payment.status": "Status", + "finance.deposit_payment.status.0": "Unpaid", + "finance.deposit_payment.status.1": "Paid", + "finance.deposit_payment.status.2": "Refunded", + "finance.deposit_payment.paid_at": "Paid At", + "finance.deposit_payment.refund_at": "Refund At", + "finance.deposit_payment.created_at": "Created At", + "finance.deposit_payment.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/finance/deposit.ts b/web/locales/en_US/finance/deposit.ts new file mode 100644 index 0000000..59b84ba --- /dev/null +++ b/web/locales/en_US/finance/deposit.ts @@ -0,0 +1,20 @@ +export default { + "finance.deposit.page.title": "Deposit Management", + "finance.deposit.page.description": "Manage runner security deposits", + "finance.deposit.id": "ID", + "finance.deposit.deposit_no": "Deposit No", + "finance.deposit.worker_id": "Runner ID", + "finance.deposit.user_id": "User ID", + "finance.deposit.amount": "Amount", + "finance.deposit.status": "Status", + "finance.deposit.status.0": "Unpaid", + "finance.deposit.status.1": "Paid", + "finance.deposit.status.2": "Refunded", + "finance.deposit.status.3": "Deducted", + "finance.deposit.deduct_reason": "Deduction Reason", + "finance.deposit.paid_at": "Paid At", + "finance.deposit.refund_at": "Refund At", + "finance.deposit.deducted_at": "Deducted At", + "finance.deposit.created_at": "Created At", + "finance.deposit.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/finance/task-payment.ts b/web/locales/en_US/finance/task-payment.ts new file mode 100644 index 0000000..c87dafa --- /dev/null +++ b/web/locales/en_US/finance/task-payment.ts @@ -0,0 +1,21 @@ +export default { + "finance.task_payment.page.title": "Task Payment Logs", + "finance.task_payment.page.description": "View task order payment records", + "finance.task_payment.id": "ID", + "finance.task_payment.payment_no": "Payment No", + "finance.task_payment.order_id": "Order ID", + "finance.task_payment.user_id": "User ID", + "finance.task_payment.payment_transaction_id": "Transaction ID", + "finance.task_payment.amount": "Amount", + "finance.task_payment.pay_type": "Pay Method", + "finance.task_payment.pay_type.0": "Balance", + "finance.task_payment.pay_type.1": "WeChat Pay", + "finance.task_payment.status": "Status", + "finance.task_payment.status.0": "Unpaid", + "finance.task_payment.status.1": "Paid", + "finance.task_payment.status.2": "Refunded", + "finance.task_payment.paid_at": "Paid At", + "finance.task_payment.refund_at": "Refund At", + "finance.task_payment.created_at": "Created At", + "finance.task_payment.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/finance/transaction.ts b/web/locales/en_US/finance/transaction.ts new file mode 100644 index 0000000..5fa66df --- /dev/null +++ b/web/locales/en_US/finance/transaction.ts @@ -0,0 +1,26 @@ +export default { + "finance.transaction.page.title": "Payment Transactions", + "finance.transaction.page.description": "Unified WeChat/Alipay payment transaction records across all business modules", + "finance.transaction.id": "ID", + "finance.transaction.transaction_no": "Transaction No", + "finance.transaction.out_trade_no": "Out Trade No", + "finance.transaction.pay_type": "Pay Method", + "finance.transaction.pay_type.wechat": "WeChat Pay", + "finance.transaction.pay_type.alipay": "Alipay", + "finance.transaction.amount": "Amount", + "finance.transaction.status": "Status", + "finance.transaction.status.0": "Pending", + "finance.transaction.status.1": "Success", + "finance.transaction.status.2": "Failed", + "finance.transaction.status.3": "Refunded", + "finance.transaction.business_type": "Business Type", + "finance.transaction.business_type.task": "Task Order", + "finance.transaction.business_type.deposit": "Deposit", + "finance.transaction.business_type.order": "Store Order", + "finance.transaction.business_id": "Business ID", + "finance.transaction.user_id": "User ID", + "finance.transaction.openid": "WeChat OpenID", + "finance.transaction.paid_at": "Paid At", + "finance.transaction.created_at": "Created At", + "finance.transaction.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/finance/withdrawal.ts b/web/locales/en_US/finance/withdrawal.ts new file mode 100644 index 0000000..9592436 --- /dev/null +++ b/web/locales/en_US/finance/withdrawal.ts @@ -0,0 +1,24 @@ +export default { + "finance.withdrawal.page.title": "Runner Withdrawals", + "finance.withdrawal.page.description": "Manage runner withdrawal requests", + "finance.withdrawal.id": "ID", + "finance.withdrawal.withdraw_no": "Withdrawal No", + "finance.withdrawal.user_id": "User ID", + "finance.withdrawal.worker_id": "Runner ID", + "finance.withdrawal.amount": "Amount", + "finance.withdrawal.fee": "Fee", + "finance.withdrawal.channel": "Channel", + "finance.withdrawal.channel.wechat": "WeChat", + "finance.withdrawal.channel.alipay": "Alipay", + "finance.withdrawal.channel.bank": "Bank", + "finance.withdrawal.account_info": "Account Info", + "finance.withdrawal.status": "Status", + "finance.withdrawal.status.0": "Pending", + "finance.withdrawal.status.1": "Approved", + "finance.withdrawal.status.2": "Completed", + "finance.withdrawal.status.3": "Rejected", + "finance.withdrawal.remark": "Remark", + "finance.withdrawal.processed_at": "Processed At", + "finance.withdrawal.created_at": "Created At", + "finance.withdrawal.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/index.ts b/web/locales/en_US/index.ts index e48faec..e1fa32a 100644 --- a/web/locales/en_US/index.ts +++ b/web/locales/en_US/index.ts @@ -38,6 +38,24 @@ import merchantProduct from "./merchant/product"; import merchantPrinter from "./merchant/printer"; import merchantPrintTask from "./merchant/print-task"; +import taskCategory from "./task/category"; +import taskOrderErrand from "./task/order-errand"; +import taskOrderPickup from "./task/order-pickup"; +import taskOrderRental from "./task/order-rental"; +import taskBid from "./task/bid"; + +import runnerApplication from "./runner/application"; +import runnerWorker from "./runner/worker"; +import runnerCreditLog from "./runner/credit-log"; +import runnerComplaint from "./runner/complaint"; +import runnerComplaintAppeal from "./runner/complaint-appeal"; + +import financeTaskPayment from "./finance/task-payment"; +import financeDeposit from "./finance/deposit"; +import financeDepositPayment from "./finance/deposit-payment"; +import financeWithdrawal from "./finance/withdrawal"; +import financeTransaction from "./finance/transaction"; + import userProfile from "./user/profile"; import xinForm from "./components/xin-form"; @@ -80,6 +98,21 @@ export default { ...merchantProduct, ...merchantPrinter, ...merchantPrintTask, + ...taskCategory, + ...taskOrderErrand, + ...taskOrderPickup, + ...taskOrderRental, + ...taskBid, + ...runnerApplication, + ...runnerWorker, + ...runnerCreditLog, + ...runnerComplaint, + ...runnerComplaintAppeal, + ...financeTaskPayment, + ...financeDeposit, + ...financeDepositPayment, + ...financeWithdrawal, + ...financeTransaction, ...userProfile, ...xinForm, ...xinTable, diff --git a/web/locales/en_US/menu.ts b/web/locales/en_US/menu.ts index b2a4429..1a21152 100644 --- a/web/locales/en_US/menu.ts +++ b/web/locales/en_US/menu.ts @@ -61,5 +61,24 @@ export default { "menu.merchant.product": "Products", "menu.merchant.printer": "Printers", "menu.merchant.print-task": "Print Tasks", + "menu.task": "Campus Tasks", + "menu.task.orders": "Task Orders", + "menu.task.category": "Categories", + "menu.task.order_errand": "Errand Orders", + "menu.task.order_pickup": "Pickup Orders", + "menu.task.order_rental": "Rental Orders", + "menu.task.bid": "Bid Records", + "menu.runner": "Runner Management", + "menu.runner.application": "Applications", + "menu.runner.worker": "Runner List", + "menu.runner.credit_log": "Credit Logs", + "menu.runner.complaint": "Complaints", + "menu.runner.complaint_appeal": "Appeals", + "menu.finance": "Finance", + "menu.finance.task_payment": "Task Payments", + "menu.finance.deposit": "Deposits", + "menu.finance.deposit_payment": "Deposit Payments", + "menu.finance.withdrawal": "Withdrawals", + "menu.finance.transaction": "Transactions", "menu.xin-admin": "XinAdmin", } diff --git a/web/locales/en_US/runner/application.ts b/web/locales/en_US/runner/application.ts new file mode 100644 index 0000000..b6a3b26 --- /dev/null +++ b/web/locales/en_US/runner/application.ts @@ -0,0 +1,20 @@ +export default { + "runner.application.page.title": "Runner Applications", + "runner.application.page.description": "Review and manage runner registration applications", + "runner.application.id": "ID", + "runner.application.user_id": "User ID", + "runner.application.real_name": "Real Name", + "runner.application.mobile": "Phone", + "runner.application.resume": "Resume", + "runner.application.id_card": "ID Card", + "runner.application.id_card_front": "ID Card Front", + "runner.application.id_card_back": "ID Card Back", + "runner.application.status": "Status", + "runner.application.status.0": "Pending Review", + "runner.application.status.1": "Approved", + "runner.application.status.2": "Rejected", + "runner.application.review_remark": "Review Remark", + "runner.application.reviewed_at": "Reviewed At", + "runner.application.created_at": "Applied At", + "runner.application.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/runner/complaint-appeal.ts b/web/locales/en_US/runner/complaint-appeal.ts new file mode 100644 index 0000000..4e2f043 --- /dev/null +++ b/web/locales/en_US/runner/complaint-appeal.ts @@ -0,0 +1,17 @@ +export default { + "runner.complaint_appeal.page.title": "Appeal Management", + "runner.complaint_appeal.page.description": "Review runner complaint appeals", + "runner.complaint_appeal.id": "ID", + "runner.complaint_appeal.complaint_id": "Complaint ID", + "runner.complaint_appeal.worker_id": "Runner ID", + "runner.complaint_appeal.content": "Appeal Content", + "runner.complaint_appeal.images": "Evidence Images", + "runner.complaint_appeal.status": "Status", + "runner.complaint_appeal.status.0": "Pending Review", + "runner.complaint_appeal.status.1": "Approved", + "runner.complaint_appeal.status.2": "Rejected", + "runner.complaint_appeal.reply": "Reply", + "runner.complaint_appeal.reviewed_at": "Reviewed At", + "runner.complaint_appeal.created_at": "Created At", + "runner.complaint_appeal.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/runner/complaint.ts b/web/locales/en_US/runner/complaint.ts new file mode 100644 index 0000000..25dda0a --- /dev/null +++ b/web/locales/en_US/runner/complaint.ts @@ -0,0 +1,26 @@ +export default { + "runner.complaint.page.title": "Complaint Management", + "runner.complaint.page.description": "Manage user complaints against runners", + "runner.complaint.id": "ID", + "runner.complaint.complaint_no": "Complaint No", + "runner.complaint.user_id": "Complainant ID", + "runner.complaint.worker_id": "Runner ID", + "runner.complaint.order_id": "Order ID", + "runner.complaint.type": "Complaint Type", + "runner.complaint.type.late": "Late/Timeout", + "runner.complaint.type.attitude": "Poor Attitude", + "runner.complaint.type.damage": "Item Damaged", + "runner.complaint.type.lost": "Item Lost", + "runner.complaint.type.other": "Other", + "runner.complaint.content": "Content", + "runner.complaint.images": "Evidence Images", + "runner.complaint.status": "Status", + "runner.complaint.status.0": "Pending", + "runner.complaint.status.1": "Resolved", + "runner.complaint.status.2": "Dismissed", + "runner.complaint.result": "Result", + "runner.complaint.result_remark": "Result Remark", + "runner.complaint.handled_at": "Handled At", + "runner.complaint.created_at": "Created At", + "runner.complaint.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/runner/credit-log.ts b/web/locales/en_US/runner/credit-log.ts new file mode 100644 index 0000000..972c932 --- /dev/null +++ b/web/locales/en_US/runner/credit-log.ts @@ -0,0 +1,20 @@ +export default { + "runner.credit_log.page.title": "Credit Score Logs", + "runner.credit_log.page.description": "View runner credit score change history", + "runner.credit_log.id": "ID", + "runner.credit_log.worker_id": "Runner ID", + "runner.credit_log.score": "Score Change", + "runner.credit_log.score_after": "Score After", + "runner.credit_log.type": "Change Type", + "runner.credit_log.type.order_complete": "Order Completed", + "runner.credit_log.type.order_cancel": "Order Cancelled", + "runner.credit_log.type.order_timeout": "Order Timeout", + "runner.credit_log.type.complaint": "Complaint Received", + "runner.credit_log.type.appeal_success": "Appeal Won", + "runner.credit_log.type.manual": "Manual Adjust", + "runner.credit_log.description": "Description", + "runner.credit_log.related_type": "Related Type", + "runner.credit_log.related_id": "Related ID", + "runner.credit_log.created_at": "Created At", + "runner.credit_log.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/runner/worker.ts b/web/locales/en_US/runner/worker.ts new file mode 100644 index 0000000..02a700b --- /dev/null +++ b/web/locales/en_US/runner/worker.ts @@ -0,0 +1,20 @@ +export default { + "runner.worker.page.title": "Runner List", + "runner.worker.page.description": "Manage approved campus runners", + "runner.worker.id": "ID", + "runner.worker.user_id": "User ID", + "runner.worker.real_name": "Real Name", + "runner.worker.mobile": "Phone", + "runner.worker.id_card": "ID Card", + "runner.worker.total_income": "Total Income", + "runner.worker.total_order": "Total Orders", + "runner.worker.cancel_order": "Cancelled Orders", + "runner.worker.credit_score": "Credit Score", + "runner.worker.verified_at": "Verified At", + "runner.worker.status": "Status", + "runner.worker.status.0": "Banned", + "runner.worker.status.1": "Active", + "runner.worker.status.2": "Resting", + "runner.worker.created_at": "Created At", + "runner.worker.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/task/bid.ts b/web/locales/en_US/task/bid.ts new file mode 100644 index 0000000..db6090d --- /dev/null +++ b/web/locales/en_US/task/bid.ts @@ -0,0 +1,16 @@ +export default { + "task.bid.page.title": "Task Bids", + "task.bid.page.description": "View task bid and acceptance records", + "task.bid.id": "ID", + "task.bid.task_id": "Task ID", + "task.bid.user_id": "Bidder ID", + "task.bid.price": "Bid Price", + "task.bid.message": "Message", + "task.bid.status": "Status", + "task.bid.status.0": "Pending", + "task.bid.status.1": "Accepted", + "task.bid.status.2": "Rejected", + "task.bid.accepted_at": "Accepted At", + "task.bid.created_at": "Created At", + "task.bid.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/task/category.ts b/web/locales/en_US/task/category.ts new file mode 100644 index 0000000..e6ba3ad --- /dev/null +++ b/web/locales/en_US/task/category.ts @@ -0,0 +1,16 @@ +export default { + "task.category.page.title": "Task Categories", + "task.category.page.description": "Manage campus task categories including errand, pickup, and rental", + "task.category.id": "ID", + "task.category.name": "Name", + "task.category.slug": "Slug", + "task.category.description": "Description", + "task.category.icon": "Icon", + "task.category.form_schema": "Form Schema", + "task.category.sort": "Sort", + "task.category.status": "Status", + "task.category.status.0": "Disabled", + "task.category.status.1": "Active", + "task.category.created_at": "Created At", + "task.category.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/task/order-errand.ts b/web/locales/en_US/task/order-errand.ts new file mode 100644 index 0000000..d6f608a --- /dev/null +++ b/web/locales/en_US/task/order-errand.ts @@ -0,0 +1,29 @@ +export default { + "task.order_errand.page.title": "Errand Orders", + "task.order_errand.page.description": "Manage errand/delivery task orders", + "task.order_errand.id": "ID", + "task.order_errand.order_no": "Order No", + "task.order_errand.user_id": "User ID", + "task.order_errand.runner_id": "Runner ID", + "task.order_errand.title": "Title", + "task.order_errand.price": "Price", + "task.order_errand.contact_name": "Contact", + "task.order_errand.contact_mobile": "Phone", + "task.order_errand.deadline": "Deadline", + "task.order_errand.pay_type": "Pay Method", + "task.order_errand.pay_type.0": "Balance", + "task.order_errand.pay_type.1": "WeChat Pay", + "task.order_errand.pay_status": "Pay Status", + "task.order_errand.pay_status.0": "Unpaid", + "task.order_errand.pay_status.1": "Paid", + "task.order_errand.pay_status.2": "Refunding", + "task.order_errand.pay_status.3": "Refunded", + "task.order_errand.status": "Order Status", + "task.order_errand.status.0": "Pending", + "task.order_errand.status.1": "Accepted", + "task.order_errand.status.2": "In Progress", + "task.order_errand.status.3": "Completed", + "task.order_errand.status.4": "Cancelled", + "task.order_errand.created_at": "Created At", + "task.order_errand.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/task/order-pickup.ts b/web/locales/en_US/task/order-pickup.ts new file mode 100644 index 0000000..96495b4 --- /dev/null +++ b/web/locales/en_US/task/order-pickup.ts @@ -0,0 +1,29 @@ +export default { + "task.order_pickup.page.title": "Pickup Orders", + "task.order_pickup.page.description": "Manage proxy pickup task orders", + "task.order_pickup.id": "ID", + "task.order_pickup.order_no": "Order No", + "task.order_pickup.user_id": "User ID", + "task.order_pickup.runner_id": "Runner ID", + "task.order_pickup.title": "Title", + "task.order_pickup.price": "Price", + "task.order_pickup.contact_name": "Contact", + "task.order_pickup.contact_mobile": "Phone", + "task.order_pickup.deadline": "Deadline", + "task.order_pickup.pay_type": "Pay Method", + "task.order_pickup.pay_type.0": "Balance", + "task.order_pickup.pay_type.1": "WeChat Pay", + "task.order_pickup.pay_status": "Pay Status", + "task.order_pickup.pay_status.0": "Unpaid", + "task.order_pickup.pay_status.1": "Paid", + "task.order_pickup.pay_status.2": "Refunding", + "task.order_pickup.pay_status.3": "Refunded", + "task.order_pickup.status": "Order Status", + "task.order_pickup.status.0": "Pending", + "task.order_pickup.status.1": "Accepted", + "task.order_pickup.status.2": "In Progress", + "task.order_pickup.status.3": "Completed", + "task.order_pickup.status.4": "Cancelled", + "task.order_pickup.created_at": "Created At", + "task.order_pickup.updated_at": "Updated At", +}; diff --git a/web/locales/en_US/task/order-rental.ts b/web/locales/en_US/task/order-rental.ts new file mode 100644 index 0000000..4ddea22 --- /dev/null +++ b/web/locales/en_US/task/order-rental.ts @@ -0,0 +1,29 @@ +export default { + "task.order_rental.page.title": "Rental Orders", + "task.order_rental.page.description": "Manage item rental task orders", + "task.order_rental.id": "ID", + "task.order_rental.order_no": "Order No", + "task.order_rental.user_id": "User ID", + "task.order_rental.runner_id": "Runner ID", + "task.order_rental.title": "Title", + "task.order_rental.price": "Price", + "task.order_rental.contact_name": "Contact", + "task.order_rental.contact_mobile": "Phone", + "task.order_rental.deadline": "Deadline", + "task.order_rental.pay_type": "Pay Method", + "task.order_rental.pay_type.0": "Balance", + "task.order_rental.pay_type.1": "WeChat Pay", + "task.order_rental.pay_status": "Pay Status", + "task.order_rental.pay_status.0": "Unpaid", + "task.order_rental.pay_status.1": "Paid", + "task.order_rental.pay_status.2": "Refunding", + "task.order_rental.pay_status.3": "Refunded", + "task.order_rental.status": "Order Status", + "task.order_rental.status.0": "Pending", + "task.order_rental.status.1": "Accepted", + "task.order_rental.status.2": "In Progress", + "task.order_rental.status.3": "Completed", + "task.order_rental.status.4": "Cancelled", + "task.order_rental.created_at": "Created At", + "task.order_rental.updated_at": "Updated At", +}; diff --git a/web/locales/zh_CN/finance/deposit-payment.ts b/web/locales/zh_CN/finance/deposit-payment.ts new file mode 100644 index 0000000..eec673a --- /dev/null +++ b/web/locales/zh_CN/finance/deposit-payment.ts @@ -0,0 +1,21 @@ +export default { + "finance.deposit_payment.page.title": "保证金支付", + "finance.deposit_payment.page.description": "查看保证金的支付记录", + "finance.deposit_payment.id": "ID", + "finance.deposit_payment.payment_no": "支付单号", + "finance.deposit_payment.deposit_id": "保证金ID", + "finance.deposit_payment.user_id": "用户ID", + "finance.deposit_payment.payment_transaction_id": "交易ID", + "finance.deposit_payment.amount": "金额", + "finance.deposit_payment.pay_type": "支付方式", + "finance.deposit_payment.pay_type.0": "余额支付", + "finance.deposit_payment.pay_type.1": "微信支付", + "finance.deposit_payment.status": "状态", + "finance.deposit_payment.status.0": "未支付", + "finance.deposit_payment.status.1": "已支付", + "finance.deposit_payment.status.2": "已退款", + "finance.deposit_payment.paid_at": "支付时间", + "finance.deposit_payment.refund_at": "退款时间", + "finance.deposit_payment.created_at": "创建时间", + "finance.deposit_payment.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/finance/deposit.ts b/web/locales/zh_CN/finance/deposit.ts new file mode 100644 index 0000000..36caaa4 --- /dev/null +++ b/web/locales/zh_CN/finance/deposit.ts @@ -0,0 +1,20 @@ +export default { + "finance.deposit.page.title": "保证金管理", + "finance.deposit.page.description": "管理接单员的保证金", + "finance.deposit.id": "ID", + "finance.deposit.deposit_no": "保证金编号", + "finance.deposit.worker_id": "接单员ID", + "finance.deposit.user_id": "用户ID", + "finance.deposit.amount": "金额", + "finance.deposit.status": "状态", + "finance.deposit.status.0": "未支付", + "finance.deposit.status.1": "已支付", + "finance.deposit.status.2": "已退款", + "finance.deposit.status.3": "已扣除", + "finance.deposit.deduct_reason": "扣除原因", + "finance.deposit.paid_at": "支付时间", + "finance.deposit.refund_at": "退款时间", + "finance.deposit.deducted_at": "扣除时间", + "finance.deposit.created_at": "创建时间", + "finance.deposit.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/finance/task-payment.ts b/web/locales/zh_CN/finance/task-payment.ts new file mode 100644 index 0000000..68705b1 --- /dev/null +++ b/web/locales/zh_CN/finance/task-payment.ts @@ -0,0 +1,21 @@ +export default { + "finance.task_payment.page.title": "任务支付", + "finance.task_payment.page.description": "查看任务的支付记录", + "finance.task_payment.id": "ID", + "finance.task_payment.payment_no": "支付单号", + "finance.task_payment.order_id": "订单ID", + "finance.task_payment.user_id": "用户ID", + "finance.task_payment.payment_transaction_id": "交易ID", + "finance.task_payment.amount": "金额", + "finance.task_payment.pay_type": "支付方式", + "finance.task_payment.pay_type.0": "余额支付", + "finance.task_payment.pay_type.1": "微信支付", + "finance.task_payment.status": "状态", + "finance.task_payment.status.0": "未支付", + "finance.task_payment.status.1": "已支付", + "finance.task_payment.status.2": "已退款", + "finance.task_payment.paid_at": "支付时间", + "finance.task_payment.refund_at": "退款时间", + "finance.task_payment.created_at": "创建时间", + "finance.task_payment.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/finance/transaction.ts b/web/locales/zh_CN/finance/transaction.ts new file mode 100644 index 0000000..fa19037 --- /dev/null +++ b/web/locales/zh_CN/finance/transaction.ts @@ -0,0 +1,26 @@ +export default { + "finance.transaction.page.title": "三方支付流水", + "finance.transaction.page.description": "全系统统一微信/支付宝支付流水记录,包含任务、保证金、商城等所有业务的三方支付回调数据", + "finance.transaction.id": "ID", + "finance.transaction.transaction_no": "第三方交易号", + "finance.transaction.out_trade_no": "商户订单号", + "finance.transaction.pay_type": "支付方式", + "finance.transaction.pay_type.wechat": "微信支付", + "finance.transaction.pay_type.alipay": "支付宝", + "finance.transaction.amount": "支付金额", + "finance.transaction.status": "支付状态", + "finance.transaction.status.0": "待支付", + "finance.transaction.status.1": "支付成功", + "finance.transaction.status.2": "支付失败", + "finance.transaction.status.3": "已退款", + "finance.transaction.business_type": "业务类型", + "finance.transaction.business_type.task": "任务订单", + "finance.transaction.business_type.deposit": "保证金", + "finance.transaction.business_type.order": "商城订单", + "finance.transaction.business_id": "业务ID", + "finance.transaction.user_id": "用户ID", + "finance.transaction.openid": "微信OpenID", + "finance.transaction.paid_at": "支付时间", + "finance.transaction.created_at": "创建时间", + "finance.transaction.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/finance/withdrawal.ts b/web/locales/zh_CN/finance/withdrawal.ts new file mode 100644 index 0000000..13fa0f1 --- /dev/null +++ b/web/locales/zh_CN/finance/withdrawal.ts @@ -0,0 +1,24 @@ +export default { + "finance.withdrawal.page.title": "提现管理", + "finance.withdrawal.page.description": "管理接单员的提现申请", + "finance.withdrawal.id": "ID", + "finance.withdrawal.withdraw_no": "提现单号", + "finance.withdrawal.user_id": "用户ID", + "finance.withdrawal.worker_id": "接单员ID", + "finance.withdrawal.amount": "提现金额", + "finance.withdrawal.fee": "手续费", + "finance.withdrawal.channel": "提现渠道", + "finance.withdrawal.channel.wechat": "微信", + "finance.withdrawal.channel.alipay": "支付宝", + "finance.withdrawal.channel.bank": "银行卡", + "finance.withdrawal.account_info": "账户信息", + "finance.withdrawal.status": "状态", + "finance.withdrawal.status.0": "待审核", + "finance.withdrawal.status.1": "已通过", + "finance.withdrawal.status.2": "已拒绝", + "finance.withdrawal.status.3": "已拒绝", + "finance.withdrawal.remark": "备注", + "finance.withdrawal.processed_at": "处理时间", + "finance.withdrawal.created_at": "创建时间", + "finance.withdrawal.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/index.ts b/web/locales/zh_CN/index.ts index e48faec..e1fa32a 100644 --- a/web/locales/zh_CN/index.ts +++ b/web/locales/zh_CN/index.ts @@ -38,6 +38,24 @@ import merchantProduct from "./merchant/product"; import merchantPrinter from "./merchant/printer"; import merchantPrintTask from "./merchant/print-task"; +import taskCategory from "./task/category"; +import taskOrderErrand from "./task/order-errand"; +import taskOrderPickup from "./task/order-pickup"; +import taskOrderRental from "./task/order-rental"; +import taskBid from "./task/bid"; + +import runnerApplication from "./runner/application"; +import runnerWorker from "./runner/worker"; +import runnerCreditLog from "./runner/credit-log"; +import runnerComplaint from "./runner/complaint"; +import runnerComplaintAppeal from "./runner/complaint-appeal"; + +import financeTaskPayment from "./finance/task-payment"; +import financeDeposit from "./finance/deposit"; +import financeDepositPayment from "./finance/deposit-payment"; +import financeWithdrawal from "./finance/withdrawal"; +import financeTransaction from "./finance/transaction"; + import userProfile from "./user/profile"; import xinForm from "./components/xin-form"; @@ -80,6 +98,21 @@ export default { ...merchantProduct, ...merchantPrinter, ...merchantPrintTask, + ...taskCategory, + ...taskOrderErrand, + ...taskOrderPickup, + ...taskOrderRental, + ...taskBid, + ...runnerApplication, + ...runnerWorker, + ...runnerCreditLog, + ...runnerComplaint, + ...runnerComplaintAppeal, + ...financeTaskPayment, + ...financeDeposit, + ...financeDepositPayment, + ...financeWithdrawal, + ...financeTransaction, ...userProfile, ...xinForm, ...xinTable, diff --git a/web/locales/zh_CN/menu.ts b/web/locales/zh_CN/menu.ts index e95366c..5cebcac 100644 --- a/web/locales/zh_CN/menu.ts +++ b/web/locales/zh_CN/menu.ts @@ -61,5 +61,24 @@ export default { "menu.merchant.product": "商品管理", "menu.merchant.printer": "打印机管理", "menu.merchant.print-task": "打印任务", + "menu.task": "校园任务", + "menu.task.category": "任务分类", + "menu.task.order_errand": "跑腿订单", + "menu.task.order_pickup": "代取订单", + "menu.task.order_rental": "租借订单", + "menu.task.bid": "接单记录", + "menu.task.orders": "兼职订单", + "menu.runner": "接单员管理", + "menu.runner.application": "接单员申请", + "menu.runner.worker": "接单员列表", + "menu.runner.credit_log": "信誉分记录", + "menu.runner.complaint": "投诉管理", + "menu.runner.complaint_appeal": "申诉管理", + "menu.finance": "财务管理", + "menu.finance.task_payment": "任务支付日志", + "menu.finance.deposit": "保证金管理", + "menu.finance.deposit_payment": "保证金支付日志", + "menu.finance.withdrawal": "接单员提现", + "menu.finance.transaction": "三方支付流水", "menu.xin-admin": "XinAdmin", }; diff --git a/web/locales/zh_CN/runner/application.ts b/web/locales/zh_CN/runner/application.ts new file mode 100644 index 0000000..7542f3e --- /dev/null +++ b/web/locales/zh_CN/runner/application.ts @@ -0,0 +1,20 @@ +export default { + "runner.application.page.title": "接单申请", + "runner.application.page.description": "审核用户申请成为接单员的请求", + "runner.application.id": "ID", + "runner.application.user_id": "用户ID", + "runner.application.real_name": "真实姓名", + "runner.application.mobile": "手机号", + "runner.application.resume": "简历", + "runner.application.id_card": "身份证号", + "runner.application.id_card_front": "身份证正面", + "runner.application.id_card_back": "身份证反面", + "runner.application.status": "状态", + "runner.application.status.0": "待审核", + "runner.application.status.1": "通过", + "runner.application.status.2": "拒绝", + "runner.application.review_remark": "审核备注", + "runner.application.reviewed_at": "审核时间", + "runner.application.created_at": "创建时间", + "runner.application.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/runner/complaint-appeal.ts b/web/locales/zh_CN/runner/complaint-appeal.ts new file mode 100644 index 0000000..10b6306 --- /dev/null +++ b/web/locales/zh_CN/runner/complaint-appeal.ts @@ -0,0 +1,17 @@ +export default { + "runner.complaint_appeal.page.title": "申诉管理", + "runner.complaint_appeal.page.description": "管理接单员的投诉申诉", + "runner.complaint_appeal.id": "ID", + "runner.complaint_appeal.complaint_id": "投诉ID", + "runner.complaint_appeal.worker_id": "接单员ID", + "runner.complaint_appeal.content": "申诉内容", + "runner.complaint_appeal.images": "图片", + "runner.complaint_appeal.status": "状态", + "runner.complaint_appeal.status.0": "待审核", + "runner.complaint_appeal.status.1": "通过", + "runner.complaint_appeal.status.2": "驳回", + "runner.complaint_appeal.reply": "回复", + "runner.complaint_appeal.reviewed_at": "审核时间", + "runner.complaint_appeal.created_at": "创建时间", + "runner.complaint_appeal.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/runner/complaint.ts b/web/locales/zh_CN/runner/complaint.ts new file mode 100644 index 0000000..18e2e72 --- /dev/null +++ b/web/locales/zh_CN/runner/complaint.ts @@ -0,0 +1,26 @@ +export default { + "runner.complaint.page.title": "投诉管理", + "runner.complaint.page.description": "管理用户对接单员的投诉", + "runner.complaint.id": "ID", + "runner.complaint.complaint_no": "投诉编号", + "runner.complaint.user_id": "投诉人ID", + "runner.complaint.worker_id": "被投诉人ID", + "runner.complaint.order_id": "订单ID", + "runner.complaint.type": "投诉类型", + "runner.complaint.type.late": "迟到/超时", + "runner.complaint.type.attitude": "服务态度", + "runner.complaint.type.damage": "物品损坏", + "runner.complaint.type.lost": "物品丢失", + "runner.complaint.type.other": "其他", + "runner.complaint.content": "投诉内容", + "runner.complaint.images": "图片", + "runner.complaint.status": "状态", + "runner.complaint.status.0": "待处理", + "runner.complaint.status.1": "已处理", + "runner.complaint.status.2": "已驳回", + "runner.complaint.result": "处理结果", + "runner.complaint.result_remark": "处理备注", + "runner.complaint.handled_at": "处理时间", + "runner.complaint.created_at": "创建时间", + "runner.complaint.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/runner/credit-log.ts b/web/locales/zh_CN/runner/credit-log.ts new file mode 100644 index 0000000..291645c --- /dev/null +++ b/web/locales/zh_CN/runner/credit-log.ts @@ -0,0 +1,20 @@ +export default { + "runner.credit_log.page.title": "信用记录", + "runner.credit_log.page.description": "查看接单员的信用分变动记录", + "runner.credit_log.id": "ID", + "runner.credit_log.worker_id": "接单员ID", + "runner.credit_log.score": "变动分值", + "runner.credit_log.score_after": "变动后分值", + "runner.credit_log.type": "类型", + "runner.credit_log.type.order_complete": "完成订单", + "runner.credit_log.type.order_cancel": "取消订单", + "runner.credit_log.type.order_timeout": "超时", + "runner.credit_log.type.complaint": "被投诉", + "runner.credit_log.type.appeal_success": "申诉成功", + "runner.credit_log.type.manual": "管理员调整", + "runner.credit_log.description": "描述", + "runner.credit_log.related_type": "关联类型", + "runner.credit_log.related_id": "关联ID", + "runner.credit_log.created_at": "创建时间", + "runner.credit_log.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/runner/worker.ts b/web/locales/zh_CN/runner/worker.ts new file mode 100644 index 0000000..37c4ee5 --- /dev/null +++ b/web/locales/zh_CN/runner/worker.ts @@ -0,0 +1,20 @@ +export default { + "runner.worker.page.title": "接单员列表", + "runner.worker.page.description": "管理已审核通过的接单员", + "runner.worker.id": "ID", + "runner.worker.user_id": "用户ID", + "runner.worker.real_name": "真实姓名", + "runner.worker.mobile": "手机号", + "runner.worker.id_card": "身份证号", + "runner.worker.total_income": "总收入", + "runner.worker.total_order": "总订单", + "runner.worker.cancel_order": "取消订单", + "runner.worker.credit_score": "信用分", + "runner.worker.verified_at": "认证时间", + "runner.worker.status": "状态", + "runner.worker.status.0": "禁用", + "runner.worker.status.1": "正常", + "runner.worker.status.2": "休息中", + "runner.worker.created_at": "创建时间", + "runner.worker.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/task/bid.ts b/web/locales/zh_CN/task/bid.ts new file mode 100644 index 0000000..81dbf1a --- /dev/null +++ b/web/locales/zh_CN/task/bid.ts @@ -0,0 +1,16 @@ +export default { + "task.bid.page.title": "接单记录", + "task.bid.page.description": "查看任务的接单记录", + "task.bid.id": "ID", + "task.bid.task_id": "任务ID", + "task.bid.user_id": "接单人ID", + "task.bid.price": "报价", + "task.bid.message": "留言", + "task.bid.status": "状态", + "task.bid.status.0": "待确认", + "task.bid.status.1": "已接受", + "task.bid.status.2": "已拒绝", + "task.bid.accepted_at": "接单时间", + "task.bid.created_at": "创建时间", + "task.bid.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/task/category.ts b/web/locales/zh_CN/task/category.ts new file mode 100644 index 0000000..c101dab --- /dev/null +++ b/web/locales/zh_CN/task/category.ts @@ -0,0 +1,18 @@ +export default { + "task.category.page.title": "任务分类", + "task.category.page.description": "管理校园任务分类", + "task.category.id": "ID", + "task.category.name": "分类名称", + "task.category.name.required": "分类名称不能为空", + "task.category.slug": "标识", + "task.category.slug.required": "分类标识不能为空", + "task.category.description": "描述", + "task.category.icon": "图标", + "task.category.form_schema": "表单配置", + "task.category.sort": "排序", + "task.category.status": "状态", + "task.category.status.0": "禁用", + "task.category.status.1": "正常", + "task.category.created_at": "创建时间", + "task.category.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/task/order-errand.ts b/web/locales/zh_CN/task/order-errand.ts new file mode 100644 index 0000000..90da532 --- /dev/null +++ b/web/locales/zh_CN/task/order-errand.ts @@ -0,0 +1,29 @@ +export default { + "task.order_errand.page.title": "跑腿订单", + "task.order_errand.page.description": "管理跑腿类任务订单", + "task.order_errand.id": "ID", + "task.order_errand.order_no": "订单号", + "task.order_errand.user_id": "用户ID", + "task.order_errand.runner_id": "接单员ID", + "task.order_errand.title": "标题", + "task.order_errand.price": "价格", + "task.order_errand.contact_name": "联系人", + "task.order_errand.contact_mobile": "联系电话", + "task.order_errand.deadline": "截止时间", + "task.order_errand.pay_type": "支付方式", + "task.order_errand.pay_type.0": "余额支付", + "task.order_errand.pay_type.1": "微信支付", + "task.order_errand.pay_status": "支付状态", + "task.order_errand.pay_status.0": "未支付", + "task.order_errand.pay_status.1": "已支付", + "task.order_errand.pay_status.2": "退款中", + "task.order_errand.pay_status.3": "已退款", + "task.order_errand.status": "状态", + "task.order_errand.status.0": "待接单", + "task.order_errand.status.1": "已接单", + "task.order_errand.status.2": "进行中", + "task.order_errand.status.3": "已完成", + "task.order_errand.status.4": "已取消", + "task.order_errand.created_at": "创建时间", + "task.order_errand.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/task/order-pickup.ts b/web/locales/zh_CN/task/order-pickup.ts new file mode 100644 index 0000000..6bd5870 --- /dev/null +++ b/web/locales/zh_CN/task/order-pickup.ts @@ -0,0 +1,29 @@ +export default { + "task.order_pickup.page.title": "代取订单", + "task.order_pickup.page.description": "管理代取类任务订单", + "task.order_pickup.id": "ID", + "task.order_pickup.order_no": "订单号", + "task.order_pickup.user_id": "用户ID", + "task.order_pickup.runner_id": "接单员ID", + "task.order_pickup.title": "标题", + "task.order_pickup.price": "价格", + "task.order_pickup.contact_name": "联系人", + "task.order_pickup.contact_mobile": "联系电话", + "task.order_pickup.deadline": "截止时间", + "task.order_pickup.pay_type": "支付方式", + "task.order_pickup.pay_type.0": "余额支付", + "task.order_pickup.pay_type.1": "微信支付", + "task.order_pickup.pay_status": "支付状态", + "task.order_pickup.pay_status.0": "未支付", + "task.order_pickup.pay_status.1": "已支付", + "task.order_pickup.pay_status.2": "退款中", + "task.order_pickup.pay_status.3": "已退款", + "task.order_pickup.status": "状态", + "task.order_pickup.status.0": "待接单", + "task.order_pickup.status.1": "已接单", + "task.order_pickup.status.2": "进行中", + "task.order_pickup.status.3": "已完成", + "task.order_pickup.status.4": "已取消", + "task.order_pickup.created_at": "创建时间", + "task.order_pickup.updated_at": "更新时间", +}; diff --git a/web/locales/zh_CN/task/order-rental.ts b/web/locales/zh_CN/task/order-rental.ts new file mode 100644 index 0000000..a90dc4a --- /dev/null +++ b/web/locales/zh_CN/task/order-rental.ts @@ -0,0 +1,29 @@ +export default { + "task.order_rental.page.title": "租借订单", + "task.order_rental.page.description": "管理租借类任务订单", + "task.order_rental.id": "ID", + "task.order_rental.order_no": "订单号", + "task.order_rental.user_id": "用户ID", + "task.order_rental.runner_id": "接单员ID", + "task.order_rental.title": "标题", + "task.order_rental.price": "价格", + "task.order_rental.contact_name": "联系人", + "task.order_rental.contact_mobile": "联系电话", + "task.order_rental.deadline": "截止时间", + "task.order_rental.pay_type": "支付方式", + "task.order_rental.pay_type.0": "余额支付", + "task.order_rental.pay_type.1": "微信支付", + "task.order_rental.pay_status": "支付状态", + "task.order_rental.pay_status.0": "未支付", + "task.order_rental.pay_status.1": "已支付", + "task.order_rental.pay_status.2": "退款中", + "task.order_rental.pay_status.3": "已退款", + "task.order_rental.status": "状态", + "task.order_rental.status.0": "待接单", + "task.order_rental.status.1": "已接单", + "task.order_rental.status.2": "进行中", + "task.order_rental.status.3": "已完成", + "task.order_rental.status.4": "已取消", + "task.order_rental.created_at": "创建时间", + "task.order_rental.updated_at": "更新时间", +}; diff --git a/web/pages/finance/deposit-payment/index.tsx b/web/pages/finance/deposit-payment/index.tsx new file mode 100644 index 0000000..40f0433 --- /dev/null +++ b/web/pages/finance/deposit-payment/index.tsx @@ -0,0 +1,155 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IDepositPayment from '@/domain/iDepositPayment'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('finance.deposit_payment.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('finance.deposit_payment.payment_no'), + dataIndex: 'payment_no', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit_payment.deposit_id'), + dataIndex: 'deposit_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit_payment.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit_payment.payment_transaction_id'), + dataIndex: 'payment_transaction_id', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('finance.deposit_payment.amount'), + dataIndex: 'amount', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit_payment.pay_type'), + dataIndex: 'pay_type', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit_payment.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('finance.deposit_payment.status.0') }, + { value: 1, label: t('finance.deposit_payment.status.1') }, + { value: 2, label: t('finance.deposit_payment.status.2') }, + ], + }, + render: (value: number) => { + if (value === 1) return {t('finance.deposit_payment.status.1')}; + if (value === 2) return {t('finance.deposit_payment.status.2')}; + return {t('finance.deposit_payment.status.0')}; + }, + filters: [ + { text: t('finance.deposit_payment.status.0'), value: 0 }, + { text: t('finance.deposit_payment.status.1'), value: 1 }, + { text: t('finance.deposit_payment.status.2'), value: 2 }, + ], + align: 'center', + }, + { + title: t('finance.deposit_payment.paid_at'), + dataIndex: 'paid_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.deposit_payment.refund_at'), + dataIndex: 'refund_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.deposit_payment.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.deposit_payment.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/deposit-payment', + columns, + rowKey: 'id', + accessName: 'runner.deposit_payment', + addShow: false, + editShow: false, + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('finance.deposit_payment.page.title')} + {t('finance.deposit_payment.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/finance/deposit/index.tsx b/web/pages/finance/deposit/index.tsx new file mode 100644 index 0000000..3dde443 --- /dev/null +++ b/web/pages/finance/deposit/index.tsx @@ -0,0 +1,158 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IRunnerDeposit from '@/domain/iRunnerDeposit'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('finance.deposit.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('finance.deposit.deposit_no'), + dataIndex: 'deposit_no', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit.worker_id'), + dataIndex: 'worker_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit.amount'), + dataIndex: 'amount', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.deposit.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('finance.deposit.status.0') }, + { value: 1, label: t('finance.deposit.status.1') }, + { value: 2, label: t('finance.deposit.status.2') }, + { value: 3, label: t('finance.deposit.status.3') }, + ], + }, + render: (value: number) => { + if (value === 1) return {t('finance.deposit.status.1')}; + if (value === 2) return {t('finance.deposit.status.2')}; + if (value === 3) return {t('finance.deposit.status.3')}; + return {t('finance.deposit.status.0')}; + }, + filters: [ + { text: t('finance.deposit.status.0'), value: 0 }, + { text: t('finance.deposit.status.1'), value: 1 }, + { text: t('finance.deposit.status.2'), value: 2 }, + { text: t('finance.deposit.status.3'), value: 3 }, + ], + align: 'center', + }, + { + title: t('finance.deposit.deduct_reason'), + dataIndex: 'deduct_reason', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('finance.deposit.paid_at'), + dataIndex: 'paid_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.deposit.refund_at'), + dataIndex: 'refund_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.deposit.deducted_at'), + dataIndex: 'deducted_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.deposit.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.deposit.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/deposit', + columns, + rowKey: 'id', + accessName: 'runner.deposit', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('finance.deposit.page.title')} + {t('finance.deposit.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/finance/task-payment/index.tsx b/web/pages/finance/task-payment/index.tsx new file mode 100644 index 0000000..ac87e58 --- /dev/null +++ b/web/pages/finance/task-payment/index.tsx @@ -0,0 +1,155 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type ITaskPayment from '@/domain/iTaskPayment'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('finance.task_payment.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('finance.task_payment.payment_no'), + dataIndex: 'payment_no', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.task_payment.order_id'), + dataIndex: 'order_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.task_payment.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.task_payment.payment_transaction_id'), + dataIndex: 'payment_transaction_id', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('finance.task_payment.amount'), + dataIndex: 'amount', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.task_payment.pay_type'), + dataIndex: 'pay_type', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.task_payment.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('finance.task_payment.status.0') }, + { value: 1, label: t('finance.task_payment.status.1') }, + { value: 2, label: t('finance.task_payment.status.2') }, + ], + }, + render: (value: number) => { + if (value === 1) return {t('finance.task_payment.status.1')}; + if (value === 2) return {t('finance.task_payment.status.2')}; + return {t('finance.task_payment.status.0')}; + }, + filters: [ + { text: t('finance.task_payment.status.0'), value: 0 }, + { text: t('finance.task_payment.status.1'), value: 1 }, + { text: t('finance.task_payment.status.2'), value: 2 }, + ], + align: 'center', + }, + { + title: t('finance.task_payment.paid_at'), + dataIndex: 'paid_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.task_payment.refund_at'), + dataIndex: 'refund_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.task_payment.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.task_payment.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/task/payment', + columns, + rowKey: 'id', + accessName: 'task.payment', + addShow: false, + editShow: false, + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('finance.task_payment.page.title')} + {t('finance.task_payment.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/finance/transaction/index.tsx b/web/pages/finance/transaction/index.tsx new file mode 100644 index 0000000..044913d --- /dev/null +++ b/web/pages/finance/transaction/index.tsx @@ -0,0 +1,197 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IPaymentTransaction from '@/domain/iPaymentTransaction'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const statusMap: Record = { + 0: { color: 'processing', text: '待支付' }, + 1: { color: 'success', text: '支付成功' }, + 2: { color: 'error', text: '支付失败' }, + 3: { color: 'warning', text: '已退款' }, +}; + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('finance.transaction.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('finance.transaction.transaction_no'), + dataIndex: 'transaction_no', + valueType: 'text', + align: 'center', + width: 220, + }, + { + title: t('finance.transaction.out_trade_no'), + dataIndex: 'out_trade_no', + valueType: 'text', + align: 'center', + width: 200, + }, + { + title: t('finance.transaction.pay_type'), + dataIndex: 'pay_type', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 'wechat', label: t('finance.transaction.pay_type.wechat') }, + { value: 'alipay', label: t('finance.transaction.pay_type.alipay') }, + ], + }, + render: (value: string) => ( + {value === 'wechat' ? t('finance.transaction.pay_type.wechat') : t('finance.transaction.pay_type.alipay')} + ), + filters: [ + { text: t('finance.transaction.pay_type.wechat'), value: 'wechat' }, + { text: t('finance.transaction.pay_type.alipay'), value: 'alipay' }, + ], + align: 'center', + width: 100, + }, + { + title: t('finance.transaction.amount'), + dataIndex: 'amount', + valueType: 'text', + align: 'center', + width: 120, + render: (value: string) => `¥${value || '0.00'}`, + }, + { + title: t('finance.transaction.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: '待支付' }, + { value: 1, label: '支付成功' }, + { value: 2, label: '支付失败' }, + { value: 3, label: '已退款' }, + ], + }, + render: (value: number) => { + const item = statusMap[value] || { color: 'default', text: '未知' }; + return {item.text}; + }, + filters: [ + { text: '待支付', value: 0 }, + { text: '支付成功', value: 1 }, + { text: '支付失败', value: 2 }, + { text: '已退款', value: 3 }, + ], + align: 'center', + width: 100, + }, + { + title: t('finance.transaction.business_type'), + dataIndex: 'business_type', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 'task', label: t('finance.transaction.business_type.task') }, + { value: 'deposit', label: t('finance.transaction.business_type.deposit') }, + { value: 'order', label: t('finance.transaction.business_type.order') }, + ], + }, + render: (value: string) => { + const labels: Record = { + task: t('finance.transaction.business_type.task'), + deposit: t('finance.transaction.business_type.deposit'), + order: t('finance.transaction.business_type.order'), + }; + return {labels[value] || value}; + }, + filters: [ + { text: t('finance.transaction.business_type.task'), value: 'task' }, + { text: t('finance.transaction.business_type.deposit'), value: 'deposit' }, + { text: t('finance.transaction.business_type.order'), value: 'order' }, + ], + align: 'center', + width: 110, + }, + { + title: t('finance.transaction.business_id'), + dataIndex: 'business_id', + valueType: 'text', + align: 'center', + width: 90, + }, + { + title: t('finance.transaction.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + width: 90, + }, + { + title: t('finance.transaction.paid_at'), + dataIndex: 'paid_at', + valueType: 'date', + hideInSearch: true, + align: 'center', + width: 180, + render: (value: string) => (value ? dayjs(value).format('YYYY-MM-DD HH:mm:ss') : '-'), + }, + { + title: t('finance.transaction.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + width: 160, + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/finance/payment-transaction', + columns, + rowKey: 'id', + accessName: 'finance.transaction', + addShow: false, + editShow: false, + scroll: { x: 1500 }, + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('finance.transaction.page.title')} + {t('finance.transaction.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/finance/withdrawal/index.tsx b/web/pages/finance/withdrawal/index.tsx new file mode 100644 index 0000000..75e0d0e --- /dev/null +++ b/web/pages/finance/withdrawal/index.tsx @@ -0,0 +1,158 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IRunnerWithdrawal from '@/domain/iRunnerWithdrawal'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('finance.withdrawal.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('finance.withdrawal.withdraw_no'), + dataIndex: 'withdraw_no', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.withdrawal.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.withdrawal.worker_id'), + dataIndex: 'worker_id', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.withdrawal.amount'), + dataIndex: 'amount', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.withdrawal.fee'), + dataIndex: 'fee', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.withdrawal.channel'), + dataIndex: 'channel', + valueType: 'text', + align: 'center', + }, + { + title: t('finance.withdrawal.account_info'), + dataIndex: 'account_info', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('finance.withdrawal.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('finance.withdrawal.status.0') }, + { value: 1, label: t('finance.withdrawal.status.1') }, + { value: 2, label: t('finance.withdrawal.status.2') }, + ], + }, + render: (value: number) => { + if (value === 1) return {t('finance.withdrawal.status.1')}; + if (value === 2) return {t('finance.withdrawal.status.2')}; + return {t('finance.withdrawal.status.0')}; + }, + filters: [ + { text: t('finance.withdrawal.status.0'), value: 0 }, + { text: t('finance.withdrawal.status.1'), value: 1 }, + { text: t('finance.withdrawal.status.2'), value: 2 }, + ], + align: 'center', + }, + { + title: t('finance.withdrawal.remark'), + dataIndex: 'remark', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('finance.withdrawal.processed_at'), + dataIndex: 'processed_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.withdrawal.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('finance.withdrawal.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/withdrawal', + columns, + rowKey: 'id', + accessName: 'runner.withdrawal', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('finance.withdrawal.page.title')} + {t('finance.withdrawal.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/runner/application/index.tsx b/web/pages/runner/application/index.tsx new file mode 100644 index 0000000..6837cfa --- /dev/null +++ b/web/pages/runner/application/index.tsx @@ -0,0 +1,161 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IRunnerApplication from '@/domain/iRunnerApplication'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('runner.application.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('runner.application.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.application.real_name'), + dataIndex: 'real_name', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.application.mobile'), + dataIndex: 'mobile', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.application.resume'), + dataIndex: 'resume', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.application.id_card'), + dataIndex: 'id_card', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.application.id_card_front'), + dataIndex: 'id_card_front', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.application.id_card_back'), + dataIndex: 'id_card_back', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.application.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('runner.application.status.0') }, + { value: 1, label: t('runner.application.status.1') }, + { value: 2, label: t('runner.application.status.2') }, + ], + }, + render: (value: number) => { + if (value === 1) return {t('runner.application.status.1')}; + if (value === 2) return {t('runner.application.status.2')}; + return {t('runner.application.status.0')}; + }, + filters: [ + { text: t('runner.application.status.0'), value: 0 }, + { text: t('runner.application.status.1'), value: 1 }, + { text: t('runner.application.status.2'), value: 2 }, + ], + align: 'center', + }, + { + title: t('runner.application.review_remark'), + dataIndex: 'review_remark', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.application.reviewed_at'), + dataIndex: 'reviewed_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.application.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.application.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/application', + columns, + rowKey: 'id', + accessName: 'runner.application', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('runner.application.page.title')} + {t('runner.application.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/runner/complaint-appeal/index.tsx b/web/pages/runner/complaint-appeal/index.tsx new file mode 100644 index 0000000..11aa54e --- /dev/null +++ b/web/pages/runner/complaint-appeal/index.tsx @@ -0,0 +1,141 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IRunnerComplaintAppeal from '@/domain/iRunnerComplaintAppeal'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('runner.complaint_appeal.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('runner.complaint_appeal.complaint_id'), + dataIndex: 'complaint_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.complaint_appeal.worker_id'), + dataIndex: 'worker_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.complaint_appeal.content'), + dataIndex: 'content', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.complaint_appeal.images'), + dataIndex: 'images', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.complaint_appeal.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('runner.complaint_appeal.status.0') }, + { value: 1, label: t('runner.complaint_appeal.status.1') }, + { value: 2, label: t('runner.complaint_appeal.status.2') }, + ], + }, + render: (value: number) => { + if (value === 1) return {t('runner.complaint_appeal.status.1')}; + if (value === 2) return {t('runner.complaint_appeal.status.2')}; + return {t('runner.complaint_appeal.status.0')}; + }, + filters: [ + { text: t('runner.complaint_appeal.status.0'), value: 0 }, + { text: t('runner.complaint_appeal.status.1'), value: 1 }, + { text: t('runner.complaint_appeal.status.2'), value: 2 }, + ], + align: 'center', + }, + { + title: t('runner.complaint_appeal.reply'), + dataIndex: 'reply', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.complaint_appeal.reviewed_at'), + dataIndex: 'reviewed_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.complaint_appeal.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.complaint_appeal.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/complaint-appeal', + columns, + rowKey: 'id', + accessName: 'runner.complaint_appeal', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('runner.complaint_appeal.page.title')} + {t('runner.complaint_appeal.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/runner/complaint/index.tsx b/web/pages/runner/complaint/index.tsx new file mode 100644 index 0000000..3b9bdb3 --- /dev/null +++ b/web/pages/runner/complaint/index.tsx @@ -0,0 +1,164 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IRunnerComplaint from '@/domain/iRunnerComplaint'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('runner.complaint.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('runner.complaint.complaint_no'), + dataIndex: 'complaint_no', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.complaint.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.complaint.worker_id'), + dataIndex: 'worker_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.complaint.order_id'), + dataIndex: 'order_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.complaint.type'), + dataIndex: 'type', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.complaint.content'), + dataIndex: 'content', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.complaint.images'), + dataIndex: 'images', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.complaint.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('runner.complaint.status.0') }, + { value: 1, label: t('runner.complaint.status.1') }, + ], + }, + render: (value: number) => { + return value === 1 + ? {t('runner.complaint.status.1')} + : {t('runner.complaint.status.0')}; + }, + filters: [ + { text: t('runner.complaint.status.0'), value: 0 }, + { text: t('runner.complaint.status.1'), value: 1 }, + ], + align: 'center', + }, + { + title: t('runner.complaint.result'), + dataIndex: 'result', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.complaint.result_remark'), + dataIndex: 'result_remark', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.complaint.handled_at'), + dataIndex: 'handled_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.complaint.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.complaint.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/complaint', + columns, + rowKey: 'id', + accessName: 'runner.complaint', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('runner.complaint.page.title')} + {t('runner.complaint.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/runner/credit-log/index.tsx b/web/pages/runner/credit-log/index.tsx new file mode 100644 index 0000000..252d1bc --- /dev/null +++ b/web/pages/runner/credit-log/index.tsx @@ -0,0 +1,124 @@ +import { Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IRunnerCreditLog from '@/domain/iRunnerCreditLog'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('runner.credit_log.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('runner.credit_log.worker_id'), + dataIndex: 'worker_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.credit_log.score'), + dataIndex: 'score', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.credit_log.score_after'), + dataIndex: 'score_after', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.credit_log.type'), + dataIndex: 'type', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.credit_log.description'), + dataIndex: 'description', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.credit_log.related_type'), + dataIndex: 'related_type', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.credit_log.related_id'), + dataIndex: 'related_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.credit_log.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.credit_log.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/credit-log', + columns, + rowKey: 'id', + accessName: 'runner.credit_log', + addShow: false, + editShow: false, + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('runner.credit_log.page.title')} + {t('runner.credit_log.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/runner/worker/index.tsx b/web/pages/runner/worker/index.tsx new file mode 100644 index 0000000..07cdc35 --- /dev/null +++ b/web/pages/runner/worker/index.tsx @@ -0,0 +1,159 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type IRunnerWorker from '@/domain/iRunnerWorker'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('runner.worker.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('runner.worker.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.worker.real_name'), + dataIndex: 'real_name', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.worker.mobile'), + dataIndex: 'mobile', + valueType: 'text', + align: 'center', + }, + { + title: t('runner.worker.id_card'), + dataIndex: 'id_card', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.worker.total_income'), + dataIndex: 'total_income', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.worker.total_order'), + dataIndex: 'total_order', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.worker.cancel_order'), + dataIndex: 'cancel_order', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.worker.credit_score'), + dataIndex: 'credit_score', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('runner.worker.verified_at'), + dataIndex: 'verified_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.worker.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('runner.worker.status.0') }, + { value: 1, label: t('runner.worker.status.1') }, + ], + }, + render: (value: number) => { + return value === 1 + ? {t('runner.worker.status.1')} + : {t('runner.worker.status.0')}; + }, + filters: [ + { text: t('runner.worker.status.0'), value: 0 }, + { text: t('runner.worker.status.1'), value: 1 }, + ], + align: 'center', + }, + { + title: t('runner.worker.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('runner.worker.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/runner/worker', + columns, + rowKey: 'id', + accessName: 'runner.worker', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('runner.worker.page.title')} + {t('runner.worker.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/task/bid/index.tsx b/web/pages/task/bid/index.tsx new file mode 100644 index 0000000..d990d2f --- /dev/null +++ b/web/pages/task/bid/index.tsx @@ -0,0 +1,116 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type ITaskBid from '@/domain/iTaskBid'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('task.bid.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('task.bid.task_id'), + dataIndex: 'task_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.bid.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.bid.price'), + dataIndex: 'price', + hideInForm: true, + align: 'center', + render: (value: string) => `¥${value || '0.00'}`, + }, + { + title: t('task.bid.message'), + dataIndex: 'message', + valueType: 'text', + align: 'center', + }, + { + title: t('task.bid.status'), + dataIndex: 'status', + valueType: 'text', + align: 'center', + }, + { + title: t('task.bid.accepted_at'), + dataIndex: 'accepted_at', + hideInForm: true, + hideInSearch: true, + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('task.bid.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('task.bid.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/task/bid', + columns, + rowKey: 'id', + accessName: 'task.bid', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('task.bid.page.title')} + {t('task.bid.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/task/category/index.tsx b/web/pages/task/category/index.tsx new file mode 100644 index 0000000..1a0eb1c --- /dev/null +++ b/web/pages/task/category/index.tsx @@ -0,0 +1,142 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type ITaskCategory from '@/domain/iTaskCategory'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('task.category.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('task.category.name'), + dataIndex: 'name', + valueType: 'text', + align: 'center', + required: true, + rules: [{ required: true, message: t('task.category.name.required') }], + }, + { + title: t('task.category.slug'), + dataIndex: 'slug', + valueType: 'text', + align: 'center', + required: true, + rules: [{ required: true, message: t('task.category.slug.required') }], + }, + { + title: t('task.category.description'), + dataIndex: 'description', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('task.category.icon'), + dataIndex: 'icon', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('task.category.form_schema'), + dataIndex: 'form_schema', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('task.category.sort'), + dataIndex: 'sort', + valueType: 'text', + align: 'center', + hideInSearch: true, + }, + { + title: t('task.category.status'), + dataIndex: 'status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('task.category.status.0') }, + { value: 1, label: t('task.category.status.1') }, + ], + }, + render: (value: number) => { + return value === 1 + ? {t('task.category.status.1')} + : {t('task.category.status.0')}; + }, + filters: [ + { text: t('task.category.status.0'), value: 0 }, + { text: t('task.category.status.1'), value: 1 }, + ], + align: 'center', + }, + { + title: t('task.category.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('task.category.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/task/category', + columns, + rowKey: 'id', + accessName: 'task.category', + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 600, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('task.category.page.title')} + {t('task.category.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/task/order-errand/index.tsx b/web/pages/task/order-errand/index.tsx new file mode 100644 index 0000000..d7635f5 --- /dev/null +++ b/web/pages/task/order-errand/index.tsx @@ -0,0 +1,161 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type ITaskOrder from '@/domain/iTaskOrder'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('task.order_errand.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('task.order_errand.order_no'), + dataIndex: 'order_no', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.runner_id'), + dataIndex: 'runner_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.title'), + dataIndex: 'title', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.price'), + dataIndex: 'price', + hideInForm: true, + align: 'center', + render: (value: string) => `¥${value || '0.00'}`, + }, + { + title: t('task.order_errand.contact_name'), + dataIndex: 'contact_name', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.contact_mobile'), + dataIndex: 'contact_mobile', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.deadline'), + dataIndex: 'deadline', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.pay_type'), + dataIndex: 'pay_type', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.pay_status'), + dataIndex: 'pay_status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('task.order_errand.pay_status.0') }, + { value: 1, label: t('task.order_errand.pay_status.1') }, + ], + }, + render: (value: number) => { + return value === 1 + ? {t('task.order_errand.pay_status.1')} + : {t('task.order_errand.pay_status.0')}; + }, + filters: [ + { text: t('task.order_errand.pay_status.0'), value: 0 }, + { text: t('task.order_errand.pay_status.1'), value: 1 }, + ], + align: 'center', + }, + { + title: t('task.order_errand.status'), + dataIndex: 'status', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_errand.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('task.order_errand.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/task/order', + columns, + rowKey: 'id', + accessName: 'task.order', + requestParams: { category_slug: 'errand' }, + scroll: { x: 1400 }, + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('task.order_errand.page.title')} + {t('task.order_errand.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/task/order-pickup/index.tsx b/web/pages/task/order-pickup/index.tsx new file mode 100644 index 0000000..2ed0591 --- /dev/null +++ b/web/pages/task/order-pickup/index.tsx @@ -0,0 +1,161 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type ITaskOrder from '@/domain/iTaskOrder'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('task.order_pickup.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('task.order_pickup.order_no'), + dataIndex: 'order_no', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.runner_id'), + dataIndex: 'runner_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.title'), + dataIndex: 'title', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.price'), + dataIndex: 'price', + hideInForm: true, + align: 'center', + render: (value: string) => `¥${value || '0.00'}`, + }, + { + title: t('task.order_pickup.contact_name'), + dataIndex: 'contact_name', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.contact_mobile'), + dataIndex: 'contact_mobile', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.deadline'), + dataIndex: 'deadline', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.pay_type'), + dataIndex: 'pay_type', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.pay_status'), + dataIndex: 'pay_status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('task.order_pickup.pay_status.0') }, + { value: 1, label: t('task.order_pickup.pay_status.1') }, + ], + }, + render: (value: number) => { + return value === 1 + ? {t('task.order_pickup.pay_status.1')} + : {t('task.order_pickup.pay_status.0')}; + }, + filters: [ + { text: t('task.order_pickup.pay_status.0'), value: 0 }, + { text: t('task.order_pickup.pay_status.1'), value: 1 }, + ], + align: 'center', + }, + { + title: t('task.order_pickup.status'), + dataIndex: 'status', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_pickup.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('task.order_pickup.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/task/order', + columns, + rowKey: 'id', + accessName: 'task.order', + requestParams: { category_slug: 'pickup' }, + scroll: { x: 1400 }, + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('task.order_pickup.page.title')} + {t('task.order_pickup.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table; diff --git a/web/pages/task/order-rental/index.tsx b/web/pages/task/order-rental/index.tsx new file mode 100644 index 0000000..ed34b38 --- /dev/null +++ b/web/pages/task/order-rental/index.tsx @@ -0,0 +1,161 @@ +import { Tag, Typography } from 'antd'; +import React from 'react'; +import XinTable from '@/components/XinTable'; +import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings'; +import type ITaskOrder from '@/domain/iTaskOrder'; +import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const { Title, Text } = Typography; +dayjs.extend(relativeTime); + +const Table: React.FC = () => { + const { t } = useTranslation(); + + const columns: XinTableColumn[] = [ + { + title: t('task.order_rental.id'), + dataIndex: 'id', + hideInForm: true, + sorter: true, + align: 'center', + width: 80, + }, + { + title: t('task.order_rental.order_no'), + dataIndex: 'order_no', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.user_id'), + dataIndex: 'user_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.runner_id'), + dataIndex: 'runner_id', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.title'), + dataIndex: 'title', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.price'), + dataIndex: 'price', + hideInForm: true, + align: 'center', + render: (value: string) => `¥${value || '0.00'}`, + }, + { + title: t('task.order_rental.contact_name'), + dataIndex: 'contact_name', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.contact_mobile'), + dataIndex: 'contact_mobile', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.deadline'), + dataIndex: 'deadline', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.pay_type'), + dataIndex: 'pay_type', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.pay_status'), + dataIndex: 'pay_status', + valueType: 'radioButton', + fieldProps: { + options: [ + { value: 0, label: t('task.order_rental.pay_status.0') }, + { value: 1, label: t('task.order_rental.pay_status.1') }, + ], + }, + render: (value: number) => { + return value === 1 + ? {t('task.order_rental.pay_status.1')} + : {t('task.order_rental.pay_status.0')}; + }, + filters: [ + { text: t('task.order_rental.pay_status.0'), value: 0 }, + { text: t('task.order_rental.pay_status.1'), value: 1 }, + ], + align: 'center', + }, + { + title: t('task.order_rental.status'), + dataIndex: 'status', + valueType: 'text', + align: 'center', + }, + { + title: t('task.order_rental.created_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'created_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + { + title: t('task.order_rental.updated_at'), + hideInForm: true, + hideInSearch: true, + dataIndex: 'updated_at', + align: 'center', + render: (value: string) => (value ? dayjs(value).fromNow() : '-'), + }, + ]; + + const tableProps: XinTableProps = { + api: '/task/order', + columns, + rowKey: 'id', + accessName: 'task.order', + requestParams: { category_slug: 'rental' }, + scroll: { x: 1400 }, + formProps: { + grid: true, + colProps: { span: 12 }, + rowProps: { gutter: [30, 0] }, + layout: 'vertical', + }, + modalProps: { + width: 800, + }, + cardProps: { + variant: 'borderless', + }, + pagination: { + size: 'small', + style: { marginBottom: 0 }, + }, + }; + + return ( + <> +
+ {t('task.order_rental.page.title')} + {t('task.order_rental.page.description')} +
+ {...tableProps} /> + + ); +}; + +export default Table;