chore: init saasshop repo + sql migrations runner + gitee go
This commit is contained in:
1
database/.gitignore
vendored
Normal file
1
database/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.sqlite*
|
||||
44
database/factories/UserFactory.php
Normal file
44
database/factories/UserFactory.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
52
database/migrations/0001_01_01_000000_create_users_table.php
Normal file
52
database/migrations/0001_01_01_000000_create_users_table.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('merchant_id')->nullable()->index();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->string('phone', 30)->nullable();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->string('status', 30)->default('active');
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->longText('payload');
|
||||
$table->integer('last_activity')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
||||
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration')->index();
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
57
database/migrations/0001_01_01_000002_create_jobs_table.php
Normal file
57
database/migrations/0001_01_01_000002_create_jobs_table.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
|
||||
Schema::create('job_batches', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->string('name');
|
||||
$table->integer('total_jobs');
|
||||
$table->integer('pending_jobs');
|
||||
$table->integer('failed_jobs');
|
||||
$table->longText('failed_job_ids');
|
||||
$table->mediumText('options')->nullable();
|
||||
$table->integer('cancelled_at')->nullable();
|
||||
$table->integer('created_at');
|
||||
$table->integer('finished_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('merchants', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('slug')->unique();
|
||||
$table->string('domain')->nullable()->unique();
|
||||
$table->string('contact_name')->nullable();
|
||||
$table->string('contact_phone', 30)->nullable();
|
||||
$table->string('contact_email')->nullable();
|
||||
$table->string('plan', 50)->default('basic');
|
||||
$table->string('status', 30)->default('active');
|
||||
$table->timestamp('trial_ends_at')->nullable();
|
||||
$table->timestamp('activated_at')->nullable();
|
||||
$table->json('settings')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('merchants');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('admins', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('merchant_id')->nullable()->constrained('merchants')->nullOnDelete();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->string('phone', 30)->nullable();
|
||||
$table->string('password');
|
||||
$table->string('role', 30)->default('owner');
|
||||
$table->string('status', 30)->default('active');
|
||||
$table->timestamp('last_login_at')->nullable();
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admins');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('orders', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('merchant_id')->constrained('merchants')->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->string('order_no', 50)->unique();
|
||||
$table->string('status', 30)->default('pending');
|
||||
$table->decimal('product_amount', 10, 2)->default(0);
|
||||
$table->decimal('discount_amount', 10, 2)->default(0);
|
||||
$table->decimal('shipping_amount', 10, 2)->default(0);
|
||||
$table->decimal('pay_amount', 10, 2)->default(0);
|
||||
$table->string('buyer_name')->nullable();
|
||||
$table->string('buyer_phone', 30)->nullable();
|
||||
$table->string('buyer_email')->nullable();
|
||||
$table->text('remark')->nullable();
|
||||
$table->timestamp('paid_at')->nullable();
|
||||
$table->timestamp('shipped_at')->nullable();
|
||||
$table->timestamp('completed_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('orders');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('products', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('merchant_id')->constrained('merchants')->cascadeOnDelete();
|
||||
$table->string('title');
|
||||
$table->string('slug');
|
||||
$table->string('sku', 80)->unique();
|
||||
$table->text('summary')->nullable();
|
||||
$table->longText('content')->nullable();
|
||||
$table->decimal('price', 10, 2)->default(0);
|
||||
$table->decimal('original_price', 10, 2)->nullable();
|
||||
$table->integer('stock')->default(0);
|
||||
$table->string('status', 30)->default('draft');
|
||||
$table->json('images')->nullable();
|
||||
$table->timestamps();
|
||||
$table->unique(['merchant_id', 'slug']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('products');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('register_source', 30)->default('pc')->after('status');
|
||||
$table->string('last_login_source', 30)->nullable()->after('register_source');
|
||||
$table->string('wechat_openid', 64)->nullable()->after('last_login_source');
|
||||
$table->string('wechat_unionid', 64)->nullable()->after('wechat_openid');
|
||||
$table->string('mini_openid', 64)->nullable()->after('wechat_unionid');
|
||||
});
|
||||
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->string('platform', 30)->default('pc')->after('status');
|
||||
$table->string('payment_channel', 30)->nullable()->after('platform');
|
||||
$table->string('payment_status', 30)->default('unpaid')->after('payment_channel');
|
||||
$table->string('device_type', 30)->nullable()->after('payment_status');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn(['register_source', 'last_login_source', 'wechat_openid', 'wechat_unionid', 'mini_openid']);
|
||||
});
|
||||
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->dropColumn(['platform', 'payment_channel', 'payment_status', 'device_type']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('oauth_accounts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->foreignId('merchant_id')->nullable()->constrained('merchants')->nullOnDelete();
|
||||
$table->string('platform', 30);
|
||||
$table->string('provider', 30);
|
||||
$table->string('openid', 100)->nullable();
|
||||
$table->string('unionid', 100)->nullable();
|
||||
$table->string('app_id', 100)->nullable();
|
||||
$table->string('nickname')->nullable();
|
||||
$table->string('avatar')->nullable();
|
||||
$table->json('raw_payload')->nullable();
|
||||
$table->timestamps();
|
||||
$table->index(['platform', 'provider']);
|
||||
$table->unique(['provider', 'openid']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_accounts');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('system_configs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('config_key')->unique();
|
||||
$table->string('config_name');
|
||||
$table->text('config_value')->nullable();
|
||||
$table->string('value_type', 30)->default('string');
|
||||
$table->boolean('autoload')->default(true);
|
||||
$table->string('group', 50)->default('system')->index();
|
||||
$table->string('remark')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('system_configs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('channel_configs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('channel_code', 50)->unique();
|
||||
$table->string('channel_name');
|
||||
$table->string('channel_type', 50)->default('sales');
|
||||
$table->string('status', 30)->default('enabled')->index();
|
||||
$table->string('entry_path')->nullable();
|
||||
$table->boolean('supports_login')->default(false);
|
||||
$table->boolean('supports_payment')->default(false);
|
||||
$table->boolean('supports_share')->default(false);
|
||||
$table->unsignedInteger('sort')->default(0);
|
||||
$table->json('settings')->nullable();
|
||||
$table->string('remark')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('channel_configs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('payment_configs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('payment_code', 50)->unique();
|
||||
$table->string('payment_name');
|
||||
$table->string('provider', 50);
|
||||
$table->string('status', 30)->default('disabled')->index();
|
||||
$table->boolean('is_sandbox')->default(true);
|
||||
$table->boolean('supports_refund')->default(false);
|
||||
$table->json('settings')->nullable();
|
||||
$table->string('remark')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('payment_configs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('product_categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('merchant_id')->constrained('merchants')->cascadeOnDelete();
|
||||
$table->string('name');
|
||||
$table->string('slug');
|
||||
$table->string('status', 30)->default('active');
|
||||
$table->unsignedInteger('sort')->default(0);
|
||||
$table->text('description')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['merchant_id', 'slug']);
|
||||
});
|
||||
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->foreignId('category_id')->nullable()->after('merchant_id')->constrained('product_categories')->nullOnDelete();
|
||||
$table->index(['merchant_id', 'category_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->dropConstrainedForeignId('category_id');
|
||||
});
|
||||
|
||||
Schema::dropIfExists('product_categories');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('order_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('merchant_id')->constrained('merchants')->cascadeOnDelete();
|
||||
$table->foreignId('order_id')->constrained('orders')->cascadeOnDelete();
|
||||
$table->foreignId('product_id')->nullable()->constrained('products')->nullOnDelete();
|
||||
$table->string('product_title');
|
||||
$table->string('product_sku', 80)->nullable();
|
||||
$table->decimal('product_price', 10, 2)->default(0);
|
||||
$table->unsignedInteger('quantity')->default(1);
|
||||
$table->decimal('line_total_amount', 10, 2)->default(0);
|
||||
$table->json('snapshot')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['merchant_id', 'order_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('order_items');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('product_import_histories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('scope', 30);
|
||||
$table->foreignId('merchant_id')->nullable()->constrained('merchants')->nullOnDelete();
|
||||
$table->foreignId('admin_id')->nullable()->constrained('admins')->nullOnDelete();
|
||||
$table->string('file_name');
|
||||
$table->unsignedInteger('success_count')->default(0);
|
||||
$table->unsignedInteger('failed_count')->default(0);
|
||||
$table->string('failure_file')->nullable();
|
||||
$table->timestamp('imported_at');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['scope', 'imported_at']);
|
||||
$table->index(['merchant_id', 'imported_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('product_import_histories');
|
||||
}
|
||||
};
|
||||
31
database/migrations/2026_03_10_000100_create_plans_table.php
Normal file
31
database/migrations/2026_03_10_000100_create_plans_table.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('plans', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 50)->unique();
|
||||
$table->string('name', 100);
|
||||
$table->string('billing_cycle', 30)->default('monthly');
|
||||
$table->decimal('price', 10, 2)->default(0);
|
||||
$table->decimal('list_price', 10, 2)->default(0);
|
||||
$table->string('status', 30)->default('active');
|
||||
$table->unsignedInteger('sort')->default(0);
|
||||
$table->text('description')->nullable();
|
||||
$table->json('settings')->nullable();
|
||||
$table->timestamp('published_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('plans');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('site_subscriptions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('merchant_id')->constrained('merchants')->cascadeOnDelete();
|
||||
$table->foreignId('plan_id')->nullable()->constrained('plans')->nullOnDelete();
|
||||
$table->string('status', 30)->default('pending');
|
||||
$table->string('source', 30)->default('manual');
|
||||
$table->string('subscription_no', 50)->unique();
|
||||
$table->string('plan_name', 100)->nullable();
|
||||
$table->string('billing_cycle', 30)->nullable();
|
||||
$table->unsignedInteger('period_months')->default(1);
|
||||
$table->decimal('amount', 10, 2)->default(0);
|
||||
$table->timestamp('starts_at')->nullable();
|
||||
$table->timestamp('ends_at')->nullable();
|
||||
$table->timestamp('trial_ends_at')->nullable();
|
||||
$table->timestamp('activated_at')->nullable();
|
||||
$table->timestamp('cancelled_at')->nullable();
|
||||
$table->json('snapshot')->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['merchant_id', 'status']);
|
||||
$table->index(['plan_id', 'status']);
|
||||
$table->index('ends_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('site_subscriptions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('platform_orders', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('merchant_id')->constrained('merchants')->cascadeOnDelete();
|
||||
$table->foreignId('plan_id')->nullable()->constrained('plans')->nullOnDelete();
|
||||
$table->foreignId('site_subscription_id')->nullable()->constrained('site_subscriptions')->nullOnDelete();
|
||||
$table->foreignId('created_by_admin_id')->nullable()->constrained('admins')->nullOnDelete();
|
||||
$table->string('order_no', 50)->unique();
|
||||
$table->string('order_type', 30)->default('new_purchase');
|
||||
$table->string('status', 30)->default('pending');
|
||||
$table->string('payment_status', 30)->default('unpaid');
|
||||
$table->string('payment_channel', 30)->nullable();
|
||||
$table->string('plan_name', 100)->nullable();
|
||||
$table->string('billing_cycle', 30)->nullable();
|
||||
$table->unsignedInteger('period_months')->default(1);
|
||||
$table->unsignedInteger('quantity')->default(1);
|
||||
$table->decimal('list_amount', 10, 2)->default(0);
|
||||
$table->decimal('discount_amount', 10, 2)->default(0);
|
||||
$table->decimal('payable_amount', 10, 2)->default(0);
|
||||
$table->decimal('paid_amount', 10, 2)->default(0);
|
||||
$table->timestamp('placed_at')->nullable();
|
||||
$table->timestamp('paid_at')->nullable();
|
||||
$table->timestamp('activated_at')->nullable();
|
||||
$table->timestamp('cancelled_at')->nullable();
|
||||
$table->timestamp('refunded_at')->nullable();
|
||||
$table->json('plan_snapshot')->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
$table->text('remark')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['merchant_id', 'status']);
|
||||
$table->index(['payment_status', 'status']);
|
||||
$table->index(['plan_id', 'status']);
|
||||
$table->index('placed_at');
|
||||
$table->index('paid_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('platform_orders');
|
||||
}
|
||||
};
|
||||
3
database/migrations/V1__baseline.sql
Normal file
3
database/migrations/V1__baseline.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- V1 baseline
|
||||
-- 说明:用于初始化 SQL 迁移体系的基线版本。
|
||||
-- 注意:本文件不做任何结构变更,仅作为版本占位。
|
||||
15
database/seeders/DatabaseSeeder.php
Normal file
15
database/seeders/DatabaseSeeder.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$this->call([
|
||||
InitialDemoSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
392
database/seeders/InitialDemoSeeder.php
Normal file
392
database/seeders/InitialDemoSeeder.php
Normal file
@@ -0,0 +1,392 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Admin;
|
||||
use App\Models\ChannelConfig;
|
||||
use App\Models\Order;
|
||||
use App\Models\OrderItem;
|
||||
use App\Models\PaymentConfig;
|
||||
use App\Models\Plan;
|
||||
use App\Models\PlatformOrder;
|
||||
use App\Models\Product;
|
||||
use App\Models\ProductCategory;
|
||||
use App\Models\SiteSubscription;
|
||||
use App\Models\SystemConfig;
|
||||
use App\Models\Merchant;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class InitialDemoSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$this->seedPlatformConfigs();
|
||||
|
||||
$merchant = Merchant::query()->firstOrCreate(
|
||||
['slug' => 'demo-shop'],
|
||||
[
|
||||
'name' => '演示店铺',
|
||||
'domain' => null,
|
||||
'contact_name' => '林哥',
|
||||
'contact_phone' => '13800000000',
|
||||
'contact_email' => 'demo@example.com',
|
||||
'plan' => 'pro',
|
||||
'status' => 'active',
|
||||
'activated_at' => now(),
|
||||
'settings' => ['currency' => 'CNY'],
|
||||
]
|
||||
);
|
||||
|
||||
$platformAdmin = Admin::query()->updateOrCreate(
|
||||
['email' => 'platform.admin@demo.local'],
|
||||
[
|
||||
'merchant_id' => null,
|
||||
'name' => '平台管理员',
|
||||
'phone' => '13900000000',
|
||||
'password' => Hash::make('Platform@123456'),
|
||||
'role' => 'platform_owner',
|
||||
'status' => 'active',
|
||||
]
|
||||
);
|
||||
|
||||
$merchantAdmin = Admin::query()->updateOrCreate(
|
||||
['email' => 'merchant.admin@demo.local'],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'name' => '商家管理员',
|
||||
'phone' => '13900000001',
|
||||
'password' => Hash::make('Merchant@123456'),
|
||||
'role' => 'merchant_owner',
|
||||
'status' => 'active',
|
||||
]
|
||||
);
|
||||
|
||||
Admin::query()->where('email', 'admin@demo.local')->delete();
|
||||
|
||||
$user = User::query()->firstOrCreate(
|
||||
['email' => 'user@demo.local'],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'name' => '演示用户',
|
||||
'phone' => '13700000000',
|
||||
'password' => Hash::make('User@123456'),
|
||||
'status' => 'active',
|
||||
'register_source' => 'pc',
|
||||
'last_login_source' => 'pc',
|
||||
]
|
||||
);
|
||||
|
||||
$defaultCategory = ProductCategory::query()->firstOrCreate(
|
||||
['merchant_id' => $merchant->id, 'slug' => 'default'],
|
||||
[
|
||||
'name' => '默认分类',
|
||||
'status' => 'active',
|
||||
'sort' => 10,
|
||||
'description' => '系统初始化生成的默认商品分类',
|
||||
]
|
||||
);
|
||||
|
||||
$featuredCategory = ProductCategory::query()->firstOrCreate(
|
||||
['merchant_id' => $merchant->id, 'slug' => 'featured'],
|
||||
[
|
||||
'name' => '精选商品',
|
||||
'status' => 'active',
|
||||
'sort' => 20,
|
||||
'description' => '用于首页和推荐位的精选分类',
|
||||
]
|
||||
);
|
||||
|
||||
$product = Product::query()->firstOrCreate(
|
||||
['sku' => 'SKU-DEMO-001'],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'category_id' => $defaultCategory->id,
|
||||
'title' => '演示商品',
|
||||
'slug' => 'demo-product',
|
||||
'summary' => '这是 SaaS 电商项目的演示商品。',
|
||||
'content' => '后续可扩展商品详情、规格、库存与多图。',
|
||||
'price' => 199.00,
|
||||
'original_price' => 299.00,
|
||||
'stock' => 100,
|
||||
'status' => 'published',
|
||||
'images' => ['https://via.placeholder.com/600x600.png?text=Demo+Product'],
|
||||
]
|
||||
);
|
||||
|
||||
$plans = [
|
||||
[
|
||||
'code' => 'starter_monthly',
|
||||
'name' => '基础版(月付)',
|
||||
'billing_cycle' => 'monthly',
|
||||
'price' => 99,
|
||||
'list_price' => 129,
|
||||
'status' => 'active',
|
||||
'sort' => 10,
|
||||
'description' => '适合刚开站的试运营阶段,可用于 Demo 场景。',
|
||||
'published_at' => now()->subDays(5),
|
||||
],
|
||||
[
|
||||
'code' => 'pro_yearly',
|
||||
'name' => '专业版(年付)',
|
||||
'billing_cycle' => 'yearly',
|
||||
'price' => 1999,
|
||||
'list_price' => 2599,
|
||||
'status' => 'active',
|
||||
'sort' => 20,
|
||||
'description' => '面向成长型站点,后续搭配授权项配置。',
|
||||
'published_at' => now()->subDays(3),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($plans as $planData) {
|
||||
Plan::query()->updateOrCreate(
|
||||
['code' => $planData['code']],
|
||||
$planData
|
||||
);
|
||||
}
|
||||
|
||||
$subscription = SiteSubscription::query()->firstOrCreate(
|
||||
['subscription_no' => 'SUB202603100001'],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'plan_id' => Plan::query()->where('code', 'starter_monthly')->value('id'),
|
||||
'status' => 'activated',
|
||||
'source' => 'manual',
|
||||
'plan_name' => '基础版(月付)',
|
||||
'billing_cycle' => 'monthly',
|
||||
'period_months' => 1,
|
||||
'amount' => 99,
|
||||
'starts_at' => now()->subDays(20),
|
||||
'ends_at' => now()->addDays(10),
|
||||
'activated_at' => now()->subDays(20),
|
||||
'snapshot' => ['features' => ['基础功能']],
|
||||
]
|
||||
);
|
||||
|
||||
PlatformOrder::query()->updateOrCreate(
|
||||
['order_no' => 'PO202603100001'],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'plan_id' => $subscription->plan_id,
|
||||
'site_subscription_id' => $subscription->id,
|
||||
'created_by_admin_id' => $platformAdmin->id,
|
||||
'order_type' => 'new_purchase',
|
||||
'status' => 'activated',
|
||||
'payment_status' => 'paid',
|
||||
'payment_channel' => 'manual',
|
||||
'plan_name' => '基础版(月付)',
|
||||
'billing_cycle' => 'monthly',
|
||||
'period_months' => 1,
|
||||
'quantity' => 1,
|
||||
'list_amount' => 129,
|
||||
'discount_amount' => 30,
|
||||
'payable_amount' => 99,
|
||||
'paid_amount' => 99,
|
||||
'placed_at' => now()->subDays(21),
|
||||
'paid_at' => now()->subDays(20),
|
||||
'activated_at' => now()->subDays(20),
|
||||
'plan_snapshot' => ['name' => '基础版(月付)', 'cycle' => 'monthly'],
|
||||
'meta' => ['note' => '初始化演示订单'],
|
||||
]
|
||||
);
|
||||
|
||||
$secondProduct = Product::query()->firstOrCreate(
|
||||
['sku' => 'SKU-DEMO-002'],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'category_id' => $featuredCategory->id,
|
||||
'title' => '精选礼包',
|
||||
'slug' => 'featured-bundle',
|
||||
'summary' => '用于验证分类和订单明细的第二个演示商品。',
|
||||
'content' => '后续可以扩展为组合商品、营销礼包、加价购等场景。',
|
||||
'price' => 99.00,
|
||||
'original_price' => 129.00,
|
||||
'stock' => 50,
|
||||
'status' => 'published',
|
||||
'images' => ['https://via.placeholder.com/600x600.png?text=Featured+Bundle'],
|
||||
]
|
||||
);
|
||||
|
||||
$orders = [
|
||||
[
|
||||
'order_no' => 'ORD202603080001',
|
||||
'status' => 'pending',
|
||||
'platform' => 'pc',
|
||||
'payment_channel' => 'wechat_pay',
|
||||
'payment_status' => 'unpaid',
|
||||
'device_type' => 'desktop',
|
||||
'product_amount' => 397.00,
|
||||
'discount_amount' => 0,
|
||||
'shipping_amount' => 0,
|
||||
'pay_amount' => 397.00,
|
||||
'remark' => '初始化演示订单',
|
||||
'items' => [
|
||||
['product' => $product, 'price' => 199.00, 'quantity' => 1, 'category' => $defaultCategory->name],
|
||||
['product' => $secondProduct, 'price' => 99.00, 'quantity' => 2, 'category' => $featuredCategory->name],
|
||||
],
|
||||
],
|
||||
[
|
||||
'order_no' => 'ORD202603080002',
|
||||
'status' => 'paid',
|
||||
'platform' => 'h5',
|
||||
'payment_channel' => 'alipay',
|
||||
'payment_status' => 'paid',
|
||||
'device_type' => 'mobile',
|
||||
'product_amount' => 99.00,
|
||||
'discount_amount' => 0,
|
||||
'shipping_amount' => 0,
|
||||
'pay_amount' => 99.00,
|
||||
'remark' => '已支付待发货演示订单',
|
||||
'items' => [
|
||||
['product' => $secondProduct, 'price' => 99.00, 'quantity' => 1, 'category' => $featuredCategory->name],
|
||||
],
|
||||
],
|
||||
[
|
||||
'order_no' => 'ORD202603080003',
|
||||
'status' => 'shipped',
|
||||
'platform' => 'wechat_mini',
|
||||
'payment_channel' => 'wechat_pay',
|
||||
'payment_status' => 'paid',
|
||||
'device_type' => 'mini-program',
|
||||
'product_amount' => 199.00,
|
||||
'discount_amount' => 10.00,
|
||||
'shipping_amount' => 0,
|
||||
'pay_amount' => 189.00,
|
||||
'remark' => '已发货演示订单',
|
||||
'items' => [
|
||||
['product' => $product, 'price' => 199.00, 'quantity' => 1, 'category' => $defaultCategory->name],
|
||||
],
|
||||
],
|
||||
[
|
||||
'order_no' => 'ORD202603080004',
|
||||
'status' => 'completed',
|
||||
'platform' => 'wechat_mp',
|
||||
'payment_channel' => 'wechat_pay',
|
||||
'payment_status' => 'paid',
|
||||
'device_type' => 'mobile-webview',
|
||||
'product_amount' => 99.00,
|
||||
'discount_amount' => 0,
|
||||
'shipping_amount' => 0,
|
||||
'pay_amount' => 99.00,
|
||||
'remark' => '已完成演示订单',
|
||||
'items' => [
|
||||
['product' => $secondProduct, 'price' => 99.00, 'quantity' => 1, 'category' => $featuredCategory->name],
|
||||
],
|
||||
],
|
||||
[
|
||||
'order_no' => 'ORD202603080005',
|
||||
'status' => 'cancelled',
|
||||
'platform' => 'app',
|
||||
'payment_channel' => 'wechat_pay',
|
||||
'payment_status' => 'failed',
|
||||
'device_type' => 'app-api',
|
||||
'product_amount' => 199.00,
|
||||
'discount_amount' => 0,
|
||||
'shipping_amount' => 0,
|
||||
'pay_amount' => 199.00,
|
||||
'remark' => '已取消演示订单',
|
||||
'items' => [
|
||||
['product' => $product, 'price' => 199.00, 'quantity' => 1, 'category' => $defaultCategory->name],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($orders as $index => $orderData) {
|
||||
$order = Order::query()->updateOrCreate(
|
||||
['order_no' => $orderData['order_no']],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'user_id' => $user->id,
|
||||
'status' => $orderData['status'],
|
||||
'platform' => $orderData['platform'],
|
||||
'payment_channel' => $orderData['payment_channel'],
|
||||
'payment_status' => $orderData['payment_status'],
|
||||
'device_type' => $orderData['device_type'],
|
||||
'product_amount' => $orderData['product_amount'],
|
||||
'discount_amount' => $orderData['discount_amount'],
|
||||
'shipping_amount' => $orderData['shipping_amount'],
|
||||
'pay_amount' => $orderData['pay_amount'],
|
||||
'buyer_name' => $user->name,
|
||||
'buyer_phone' => $user->phone,
|
||||
'buyer_email' => $user->email,
|
||||
'remark' => $orderData['remark'],
|
||||
'paid_at' => in_array($orderData['payment_status'], ['paid', 'refunded'], true) ? now()->subDays(5 - $index) : null,
|
||||
'shipped_at' => in_array($orderData['status'], ['shipped', 'completed'], true) ? now()->subDays(3 - min($index, 2)) : null,
|
||||
'completed_at' => $orderData['status'] === 'completed' ? now()->subDay() : null,
|
||||
'created_at' => now()->subDays(6 - $index),
|
||||
'updated_at' => now()->subDays(max(0, 5 - $index)),
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($orderData['items'] as $item) {
|
||||
OrderItem::query()->updateOrCreate(
|
||||
['order_id' => $order->id, 'product_id' => $item['product']->id],
|
||||
[
|
||||
'merchant_id' => $merchant->id,
|
||||
'product_title' => $item['product']->title,
|
||||
'product_sku' => $item['product']->sku,
|
||||
'product_price' => $item['price'],
|
||||
'quantity' => $item['quantity'],
|
||||
'line_total_amount' => $item['price'] * $item['quantity'],
|
||||
'snapshot' => [
|
||||
'category' => $item['category'],
|
||||
'price' => number_format($item['price'], 2, '.', ''),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function seedPlatformConfigs(): void
|
||||
{
|
||||
$systemConfigs = [
|
||||
['config_key' => 'platform_name', 'config_name' => '平台名称', 'config_value' => 'SaaSShop', 'value_type' => 'string', 'autoload' => true, 'group' => 'system', 'remark' => '平台展示名称'],
|
||||
['config_key' => 'default_currency', 'config_name' => '默认货币', 'config_value' => 'CNY', 'value_type' => 'string', 'autoload' => true, 'group' => 'system', 'remark' => '全局默认结算货币'],
|
||||
['config_key' => 'default_locale', 'config_name' => '默认语言', 'config_value' => 'zh-CN', 'value_type' => 'string', 'autoload' => true, 'group' => 'system', 'remark' => '后台默认语言'],
|
||||
['config_key' => 'merchant_mode', 'config_name' => '商家模式', 'config_value' => 'multi-merchant', 'value_type' => 'string', 'autoload' => true, 'group' => 'merchant', 'remark' => '当前系统采用多商家平台模式'],
|
||||
['config_key' => 'feature_order_auto_close', 'config_name' => '订单自动关闭开关', 'config_value' => '1', 'value_type' => 'boolean', 'autoload' => true, 'group' => 'feature', 'remark' => '用于演示布尔型配置编辑'],
|
||||
['config_key' => 'default_order_auto_close_minutes', 'config_name' => '默认订单关闭分钟数', 'config_value' => '30', 'value_type' => 'number', 'autoload' => true, 'group' => 'feature', 'remark' => '用于演示数值型配置编辑'],
|
||||
['config_key' => 'platform_theme_tokens', 'config_name' => '平台主题 Tokens', 'config_value' => '{"primary":"#2563eb","success":"#059669"}', 'value_type' => 'json', 'autoload' => true, 'group' => 'theme', 'remark' => '用于演示 JSON 型配置编辑'],
|
||||
['config_key' => 'app_api_status', 'config_name' => 'APP API 状态', 'config_value' => 'reserved', 'value_type' => 'string', 'autoload' => true, 'group' => 'channel', 'remark' => 'APP 前端暂缓,统一 API 已预留'],
|
||||
['config_key' => 'wechat_mp_status', 'config_name' => '公众号状态', 'config_value' => 'placeholder', 'value_type' => 'string', 'autoload' => true, 'group' => 'channel', 'remark' => '公众号能力占位中'],
|
||||
['config_key' => 'wechat_mini_status', 'config_name' => '小程序状态', 'config_value' => 'placeholder', 'value_type' => 'string', 'autoload' => true, 'group' => 'channel', 'remark' => '小程序能力占位中'],
|
||||
];
|
||||
|
||||
foreach ($systemConfigs as $config) {
|
||||
SystemConfig::query()->updateOrCreate(
|
||||
['config_key' => $config['config_key']],
|
||||
$config
|
||||
);
|
||||
}
|
||||
|
||||
$channelConfigs = [
|
||||
['channel_code' => 'pc', 'channel_name' => 'PC 商城', 'channel_type' => 'sales', 'status' => 'enabled', 'entry_path' => '/pc', 'supports_login' => true, 'supports_payment' => true, 'supports_share' => true, 'sort' => 10, 'settings' => ['device' => 'desktop'], 'remark' => '面向桌面浏览器的标准商城入口'],
|
||||
['channel_code' => 'h5', 'channel_name' => 'H5 商城', 'channel_type' => 'sales', 'status' => 'enabled', 'entry_path' => '/h5', 'supports_login' => true, 'supports_payment' => true, 'supports_share' => true, 'sort' => 20, 'settings' => ['device' => 'mobile-web'], 'remark' => '面向移动浏览器和分享链路'],
|
||||
['channel_code' => 'wechat_mp', 'channel_name' => '微信公众号', 'channel_type' => 'wechat', 'status' => 'reserved', 'entry_path' => '/wechat/mp', 'supports_login' => true, 'supports_payment' => true, 'supports_share' => true, 'sort' => 30, 'settings' => ['scene' => 'official-account'], 'remark' => '已预留占位接口,待接入微信能力'],
|
||||
['channel_code' => 'wechat_mini', 'channel_name' => '微信小程序', 'channel_type' => 'wechat', 'status' => 'reserved', 'entry_path' => '/wechat/mini', 'supports_login' => true, 'supports_payment' => true, 'supports_share' => true, 'sort' => 40, 'settings' => ['scene' => 'mini-program'], 'remark' => '已预留占位接口,待接入微信能力'],
|
||||
['channel_code' => 'app_api', 'channel_name' => 'APP API', 'channel_type' => 'api', 'status' => 'reserved', 'entry_path' => '/api/v1', 'supports_login' => true, 'supports_payment' => true, 'supports_share' => false, 'sort' => 50, 'settings' => ['scene' => 'mobile-app-api'], 'remark' => '当前不做 APP 前端,但统一 API 已预留'],
|
||||
];
|
||||
|
||||
foreach ($channelConfigs as $channel) {
|
||||
ChannelConfig::query()->updateOrCreate(
|
||||
['channel_code' => $channel['channel_code']],
|
||||
$channel
|
||||
);
|
||||
}
|
||||
|
||||
$paymentConfigs = [
|
||||
['payment_code' => 'wechat_pay', 'payment_name' => '微信支付', 'provider' => 'wechat', 'status' => 'reserved', 'is_sandbox' => true, 'supports_refund' => true, 'settings' => ['mode' => 'service-provider'], 'remark' => '平台级微信支付配置预留'],
|
||||
['payment_code' => 'alipay', 'payment_name' => '支付宝', 'provider' => 'alipay', 'status' => 'reserved', 'is_sandbox' => true, 'supports_refund' => true, 'settings' => ['mode' => 'standard'], 'remark' => '平台级支付宝配置预留'],
|
||||
];
|
||||
|
||||
foreach ($paymentConfigs as $payment) {
|
||||
PaymentConfig::query()->updateOrCreate(
|
||||
['payment_code' => $payment['payment_code']],
|
||||
$payment
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user