feat: 手动充值、邀请码注册与后台管理增强

新增玩家手动充值全流程(收款方式配置、充值下单/审核、钱包上分),
支持邀请码注册、邀请历史与专属返水率;完善后台代理/玩家管理与响应式操作栏,
并补充前台注册、充值页及多语言错误码。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-11 12:20:11 +08:00
parent 618fb49511
commit 10485ecfaf
98 changed files with 7908 additions and 856 deletions

View File

@@ -0,0 +1,61 @@
-- CreateTable
CREATE TABLE "payment_methods" (
"id" BIGSERIAL NOT NULL,
"method_type" VARCHAR(20) NOT NULL,
"bank_name" VARCHAR(128),
"account_holder" VARCHAR(128),
"account_number" VARCHAR(128),
"usdt_address" VARCHAR(256),
"qr_code_url" VARCHAR(500),
"display_name" VARCHAR(128),
"sort_order" INTEGER NOT NULL DEFAULT 0,
"is_active" BOOLEAN NOT NULL DEFAULT true,
"show_on_player" BOOLEAN NOT NULL DEFAULT true,
"created_by" BIGINT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "payment_methods_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "deposit_orders" (
"id" BIGSERIAL NOT NULL,
"order_no" VARCHAR(64) NOT NULL,
"player_id" BIGINT NOT NULL,
"payment_method_id" BIGINT NOT NULL,
"method_type" VARCHAR(20) NOT NULL,
"amount" DECIMAL(18,4) NOT NULL,
"screenshot_url" VARCHAR(500) NOT NULL,
"status" VARCHAR(20) NOT NULL DEFAULT 'PENDING',
"approved_amount" DECIMAL(18,4),
"reviewer_id" BIGINT,
"reviewed_at" TIMESTAMP(3),
"reject_reason" VARCHAR(500),
"remark" VARCHAR(500),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "deposit_orders_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "payment_methods_method_type_is_active_idx" ON "payment_methods"("method_type", "is_active");
-- CreateIndex
CREATE UNIQUE INDEX "deposit_orders_order_no_key" ON "deposit_orders"("order_no");
-- CreateIndex
CREATE INDEX "deposit_orders_player_id_idx" ON "deposit_orders"("player_id");
-- CreateIndex
CREATE INDEX "deposit_orders_status_idx" ON "deposit_orders"("status");
-- CreateIndex
CREATE INDEX "deposit_orders_created_at_idx" ON "deposit_orders"("created_at");
-- AddForeignKey
ALTER TABLE "deposit_orders" ADD CONSTRAINT "deposit_orders_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "deposit_orders" ADD CONSTRAINT "deposit_orders_payment_method_id_fkey" FOREIGN KEY ("payment_method_id") REFERENCES "payment_methods"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@@ -0,0 +1 @@
-- This is an empty migration.

View File

@@ -0,0 +1,11 @@
-- AlterTable
ALTER TABLE "users" ADD COLUMN "invite_code" VARCHAR(16);
-- Backfill existing admins and agents with deterministic unique codes
UPDATE "users"
SET "invite_code" = UPPER(SUBSTR(MD5("id"::text || ':invite'), 1, 8))
WHERE "user_type" IN ('ADMIN', 'AGENT')
AND "invite_code" IS NULL;
-- CreateIndex
CREATE UNIQUE INDEX "users_invite_code_key" ON "users"("invite_code");

View File

@@ -0,0 +1,8 @@
-- AlterTable
ALTER TABLE "users" ADD COLUMN "invite_sponsor_id" BIGINT;
-- CreateIndex
CREATE INDEX "users_invite_sponsor_id_idx" ON "users"("invite_sponsor_id");
-- AddForeignKey
ALTER TABLE "users" ADD CONSTRAINT "users_invite_sponsor_id_fkey" FOREIGN KEY ("invite_sponsor_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@@ -0,0 +1,56 @@
-- CreateTable
CREATE TABLE "user_invites" (
"id" BIGSERIAL NOT NULL,
"code" VARCHAR(16) NOT NULL,
"sponsor_id" BIGINT NOT NULL,
"status" VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
"register_count" INTEGER NOT NULL DEFAULT 0,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"revoked_at" TIMESTAMP(3),
CONSTRAINT "user_invites_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "user_invites_code_key" ON "user_invites"("code");
CREATE INDEX "user_invites_sponsor_id_idx" ON "user_invites"("sponsor_id");
CREATE INDEX "user_invites_status_idx" ON "user_invites"("status");
CREATE INDEX "user_invites_created_at_idx" ON "user_invites"("created_at");
-- AddForeignKey
ALTER TABLE "user_invites" ADD CONSTRAINT "user_invites_sponsor_id_fkey" FOREIGN KEY ("sponsor_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AlterTable
ALTER TABLE "users" ADD COLUMN "used_invite_id" BIGINT;
CREATE INDEX "users_used_invite_id_idx" ON "users"("used_invite_id");
ALTER TABLE "users" ADD CONSTRAINT "users_used_invite_id_fkey" FOREIGN KEY ("used_invite_id") REFERENCES "user_invites"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- Backfill existing invite codes into history
INSERT INTO "user_invites" ("code", "sponsor_id", "status", "register_count", "created_at")
SELECT u."invite_code", u."id", 'ACTIVE', 0, COALESCE(u."updated_at", u."created_at")
FROM "users" u
WHERE u."invite_code" IS NOT NULL
AND u."user_type" IN ('ADMIN', 'AGENT')
ON CONFLICT ("code") DO NOTHING;
-- Link players to invite records when possible
UPDATE "users" p
SET "used_invite_id" = ui."id"
FROM "user_invites" ui
WHERE p."invite_sponsor_id" = ui."sponsor_id"
AND p."user_type" = 'PLAYER'
AND p."used_invite_id" IS NULL
AND ui."status" = 'ACTIVE'
AND ui."code" = (
SELECT s."invite_code" FROM "users" s WHERE s."id" = p."invite_sponsor_id"
);
UPDATE "user_invites" ui
SET "register_count" = sub.cnt
FROM (
SELECT "used_invite_id" AS id, COUNT(*)::int AS cnt
FROM "users"
WHERE "used_invite_id" IS NOT NULL
GROUP BY "used_invite_id"
) sub
WHERE ui."id" = sub.id;

View File

@@ -0,0 +1,3 @@
-- Per-invite cashback rate (admin can set when generating)
ALTER TABLE "user_invites"
ADD COLUMN "cashback_rate" DECIMAL(8, 4);