feat: 整合 Preline UI 3.x 與重寫 README 為 Docker 架構
All checks were successful
Star-Cloud-Deploy-System / deploy-demo (push) Successful in 44s
Star-Cloud-Deploy-System / deploy-production (push) Has been skipped

- 新增 Preline UI 3.2.3 作為 UI 組件庫
- 更新 tailwind.config.js 整合 Preline
- 更新 app.js 初始化 Preline
- 完全重寫 README.md 以 Docker 容器化架構為核心
- 新增 Docker 常用指令大全
- 新增故障排除與生產部署指南
- 新增會員系統相關功能(會員、錢包、點數、會籍、禮物)
- 新增社交登入測試功能
This commit is contained in:
2026-01-13 10:17:37 +08:00
parent 55ba08c88f
commit 84ef0c24e2
49 changed files with 3593 additions and 98 deletions

View File

@@ -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('members', function (Blueprint $table) {
$table->id();
$table->uuid('uuid')->unique();
$table->string('name');
$table->string('email')->nullable()->unique();
$table->string('phone')->nullable()->unique();
$table->string('password')->nullable();
$table->date('birthday')->nullable();
$table->enum('gender', ['male', 'female', 'other'])->nullable();
$table->string('avatar')->nullable();
$table->boolean('is_active')->default(true);
$table->timestamp('email_verified_at')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('members');
}
};

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('social_accounts', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->enum('provider', ['line', 'google', 'facebook']);
$table->string('provider_id');
$table->text('access_token')->nullable();
$table->text('refresh_token')->nullable();
$table->json('profile_data')->nullable();
$table->timestamp('token_expires_at')->nullable();
$table->timestamps();
// 同一平台同一用戶只能綁定一次
$table->unique(['provider', 'provider_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('social_accounts');
}
};

View File

@@ -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('member_wallets', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->decimal('balance', 12, 2)->default(0)->comment('錢包餘額');
$table->decimal('bonus_balance', 12, 2)->default(0)->comment('回饋金餘額');
$table->timestamps();
$table->unique('member_id');
});
}
public function down(): void
{
Schema::dropIfExists('member_wallets');
}
};

View File

@@ -0,0 +1,34 @@
<?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('wallet_transactions', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->enum('type', ['deposit', 'consume', 'refund', 'bonus', 'adjust'])->comment('交易類型');
$table->decimal('amount', 12, 2)->comment('異動金額');
$table->decimal('balance_after', 12, 2)->comment('異動後餘額');
$table->string('description')->nullable()->comment('說明');
$table->string('reference_type')->nullable()->comment('關聯類型');
$table->unsignedBigInteger('reference_id')->nullable()->comment('關聯ID');
$table->timestamp('created_at')->useCurrent();
$table->index(['member_id', 'created_at']);
$table->index(['reference_type', 'reference_id']);
});
}
public function down(): void
{
Schema::dropIfExists('wallet_transactions');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* 儲值回饋規則
*/
public function up(): void
{
Schema::create('deposit_bonus_rules', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('規則名稱');
$table->decimal('min_amount', 12, 2)->comment('最低儲值金額');
$table->enum('bonus_type', ['fixed', 'percentage'])->comment('回饋類型');
$table->decimal('bonus_value', 12, 2)->comment('回饋值');
$table->boolean('is_active')->default(true);
$table->datetime('start_at')->nullable()->comment('開始時間');
$table->datetime('end_at')->nullable()->comment('結束時間');
$table->timestamps();
$table->index(['is_active', 'start_at', 'end_at']);
});
}
public function down(): void
{
Schema::dropIfExists('deposit_bonus_rules');
}
};

View 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('member_points', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->integer('available_points')->default(0)->comment('可用點數');
$table->integer('pending_points')->default(0)->comment('待生效點數');
$table->integer('expired_points')->default(0)->comment('已過期點數(統計)');
$table->integer('used_points')->default(0)->comment('已使用點數(統計)');
$table->timestamps();
$table->unique('member_id');
});
}
public function down(): void
{
Schema::dropIfExists('member_points');
}
};

View File

@@ -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
{
/**
* 點數異動紀錄
*/
public function up(): void
{
Schema::create('point_transactions', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->enum('type', ['earn', 'use', 'expire', 'gift', 'adjust'])->comment('異動類型');
$table->integer('points')->comment('異動點數');
$table->integer('balance_after')->comment('異動後餘額');
$table->string('description')->nullable()->comment('說明');
$table->datetime('expires_at')->nullable()->comment('此筆點數到期日');
$table->string('reference_type')->nullable()->comment('關聯類型');
$table->unsignedBigInteger('reference_id')->nullable()->comment('關聯ID');
$table->timestamp('created_at')->useCurrent();
$table->index(['member_id', 'created_at']);
$table->index('expires_at');
$table->index(['reference_type', 'reference_id']);
});
}
public function down(): void
{
Schema::dropIfExists('point_transactions');
}
};

View File

@@ -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('point_rules', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('規則名稱');
$table->enum('trigger', ['purchase', 'deposit', 'register', 'birthday', 'referral'])->comment('觸發條件');
$table->integer('points_per_unit')->default(1)->comment('每單位獲得點數');
$table->decimal('unit_amount', 12, 2)->default(100)->comment('單位金額');
$table->integer('validity_days')->default(365)->comment('點數有效天數');
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->index('is_active');
});
}
public function down(): void
{
Schema::dropIfExists('point_rules');
}
};

View File

@@ -0,0 +1,34 @@
<?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('membership_tiers', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('等級名稱');
$table->decimal('annual_fee', 12, 2)->default(0)->comment('年費金額');
$table->decimal('discount_rate', 4, 2)->default(1.00)->comment('折扣比例(0.95=95折)');
$table->decimal('point_multiplier', 4, 2)->default(1.00)->comment('點數倍率');
$table->text('description')->nullable()->comment('說明');
$table->boolean('is_default')->default(false)->comment('是否為預設等級');
$table->integer('sort_order')->default(0)->comment('排序');
$table->timestamps();
$table->index('is_default');
$table->index('sort_order');
});
}
public function down(): void
{
Schema::dropIfExists('membership_tiers');
}
};

View File

@@ -0,0 +1,34 @@
<?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('member_memberships', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->foreignId('tier_id')->constrained('membership_tiers')->onDelete('cascade');
$table->datetime('starts_at')->comment('生效日');
$table->datetime('expires_at')->nullable()->comment('到期日');
$table->unsignedBigInteger('payment_id')->nullable()->comment('付款紀錄ID');
$table->boolean('auto_renew')->default(false)->comment('是否自動續約');
$table->enum('status', ['active', 'expired', 'cancelled'])->default('active');
$table->timestamps();
$table->index(['member_id', 'status']);
$table->index('expires_at');
});
}
public function down(): void
{
Schema::dropIfExists('member_memberships');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* 禮品/福利定義
*/
public function up(): void
{
Schema::create('gift_definitions', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('禮品名稱');
$table->enum('type', ['points', 'coupon', 'product', 'discount', 'cash'])->comment('禮品類型');
$table->decimal('value', 12, 2)->default(0)->comment('數值');
$table->foreignId('tier_id')->nullable()->constrained('membership_tiers')->nullOnDelete()->comment('適用等級');
$table->enum('trigger', ['register', 'birthday', 'annual', 'upgrade', 'manual'])->comment('觸發條件');
$table->integer('validity_days')->default(30)->comment('有效天數');
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->index(['is_active', 'trigger']);
});
}
public function down(): void
{
Schema::dropIfExists('gift_definitions');
}
};

View File

@@ -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('member_gifts', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained('members')->onDelete('cascade');
$table->foreignId('gift_definition_id')->constrained('gift_definitions')->onDelete('cascade');
$table->enum('status', ['pending', 'claimed', 'expired'])->default('pending');
$table->datetime('claimed_at')->nullable()->comment('領取時間');
$table->datetime('expires_at')->nullable()->comment('有效期限');
$table->timestamp('created_at')->useCurrent();
$table->index(['member_id', 'status']);
$table->index('expires_at');
});
}
public function down(): void
{
Schema::dropIfExists('member_gifts');
}
};