diff --git a/app/admin/controller/game/UserWalletRecord.php b/app/admin/controller/game/UserWalletRecord.php
new file mode 100644
index 0000000..34ae598
--- /dev/null
+++ b/app/admin/controller/game/UserWalletRecord.php
@@ -0,0 +1,131 @@
+ 'desc'];
+
+ protected string|array $orderGuarantee = ['id' => 'desc'];
+
+ protected array $withJoinTable = ['gameUser', 'channel', 'operatorAdmin'];
+
+ protected function initController(WebmanRequest $request): ?Response
+ {
+ $this->model = new \app\common\model\GameUserWalletRecord();
+ return null;
+ }
+
+ public function add(WebmanRequest $request): Response
+ {
+ $response = $this->initializeBackend($request);
+ if ($response !== null) {
+ return $response;
+ }
+ return $this->error('钱包流水仅允许业务入账,禁止后台手工新增');
+ }
+
+ public function edit(WebmanRequest $request): Response
+ {
+ $response = $this->initializeBackend($request);
+ if ($response !== null) {
+ return $response;
+ }
+ return $this->error('钱包流水不可编辑');
+ }
+
+ public function del(WebmanRequest $request): Response
+ {
+ $response = $this->initializeBackend($request);
+ if ($response !== null) {
+ return $response;
+ }
+ return $this->error('钱包流水不可删除');
+ }
+
+ public function sortable(WebmanRequest $request): Response
+ {
+ $response = $this->initializeBackend($request);
+ if ($response !== null) {
+ return $response;
+ }
+ return $this->error('不支持排序');
+ }
+
+ /**
+ * 列表:渠道管理员仅看本渠道流水(channel_id 快照)
+ */
+ protected function _index(): Response
+ {
+ if ($this->request && $this->request->get('select')) {
+ return $this->select($this->request);
+ }
+
+ list($where, $alias, $limit, $order) = $this->queryBuilder();
+ $table = strtolower($this->model->getTable());
+ $mainShort = $alias[$table] ?? '';
+ if ($mainShort !== '' && $this->auth && !$this->auth->isSuperAdmin()) {
+ $channelIds = $this->getScopedChannelIdsForFilter();
+ $where[] = [$mainShort . '.channel_id', 'in', $channelIds !== [] ? $channelIds : [0]];
+ }
+
+ $res = $this->model
+ ->withJoin($this->withJoinTable, $this->withJoinType)
+ ->with($this->withJoinTable)
+ ->visible([
+ 'gameUser' => ['username', 'phone'],
+ 'channel' => ['name'],
+ 'operatorAdmin' => ['username'],
+ ])
+ ->alias($alias)
+ ->where($where)
+ ->order($order)
+ ->paginate($limit);
+
+ return $this->success('', [
+ 'list' => $res->items(),
+ 'total' => $res->total(),
+ 'remark' => get_route_remark(),
+ ]);
+ }
+
+ /**
+ * 非超管:与渠道管理一致,仅本账号相关渠道
+ *
+ * @return int[]
+ */
+ private function getScopedChannelIdsForFilter(): array
+ {
+ if (!$this->auth) {
+ return [0];
+ }
+ if ($this->auth->isSuperAdmin()) {
+ return [];
+ }
+ $admin = Db::name('admin')
+ ->field(['id', 'channel_id'])
+ ->where('id', $this->auth->id)
+ ->find();
+ $ids = [];
+ if ($admin && !empty($admin['channel_id'])) {
+ $ids[] = $admin['channel_id'];
+ }
+ $owned = Db::name('channel')->where('top_admin_id', $this->auth->id)->column('id');
+ $created = Db::name('channel')->where('admin_id', $this->auth->id)->column('id');
+ return array_values(array_unique(array_merge($ids, $owned, $created)));
+ }
+}
diff --git a/app/common/model/GameUserWalletRecord.php b/app/common/model/GameUserWalletRecord.php
new file mode 100644
index 0000000..704e740
--- /dev/null
+++ b/app/common/model/GameUserWalletRecord.php
@@ -0,0 +1,41 @@
+ 'integer',
+ 'amount' => 'string',
+ 'balance_before' => 'string',
+ 'balance_after' => 'string',
+ ];
+
+ public function gameUser(): \think\model\relation\BelongsTo
+ {
+ return $this->belongsTo(GameUser::class, 'user_id', 'id');
+ }
+
+ public function channel(): \think\model\relation\BelongsTo
+ {
+ return $this->belongsTo(Channel::class, 'channel_id', 'id');
+ }
+
+ public function operatorAdmin(): \think\model\relation\BelongsTo
+ {
+ return $this->belongsTo(\app\admin\model\Admin::class, 'operator_admin_id', 'id');
+ }
+}
diff --git a/web/src/lang/backend/en/game/walletRecord.ts b/web/src/lang/backend/en/game/walletRecord.ts
new file mode 100644
index 0000000..0106799
--- /dev/null
+++ b/web/src/lang/backend/en/game/walletRecord.ts
@@ -0,0 +1,33 @@
+export default {
+ id: 'Record ID',
+ user_id: 'User ID',
+ 'game_user__username': 'Username',
+ 'channel__name': 'Channel',
+ biz_type: 'Biz type',
+ direction: 'Direction',
+ amount: 'Amount',
+ balance_before: 'Balance before',
+ balance_after: 'Balance after',
+ ref_type: 'Ref type',
+ ref_id: 'Ref ID',
+ idempotency_key: 'Idempotency key',
+ 'operator_admin__username': 'Operator',
+ remark: 'Remark',
+ create_time: 'Created at',
+ 'quick Search Fields': 'ID, biz type, ref type, remark, idempotency key',
+ 'direction in': 'Credit',
+ 'direction out': 'Debit',
+ 'biz deposit': 'Deposit',
+ 'biz withdraw': 'Withdraw',
+ 'biz withdraw_freeze': 'Withdraw freeze',
+ 'biz withdraw_unfreeze': 'Withdraw unfreeze',
+ 'biz platform_in': 'Platform credit',
+ 'biz platform_out': 'Platform debit',
+ 'biz admin_credit': 'Admin credit',
+ 'biz admin_deduct': 'Admin debit',
+ 'biz bet': 'Bet',
+ 'biz payout': 'Payout',
+ 'biz fee': 'Fee',
+ 'biz void_refund': 'Void refund',
+ 'biz adjust': 'Adjustment',
+}
diff --git a/web/src/lang/backend/zh-cn/game/walletRecord.ts b/web/src/lang/backend/zh-cn/game/walletRecord.ts
new file mode 100644
index 0000000..d6ead7a
--- /dev/null
+++ b/web/src/lang/backend/zh-cn/game/walletRecord.ts
@@ -0,0 +1,33 @@
+export default {
+ id: '流水ID',
+ user_id: '用户ID',
+ 'game_user__username': '用户名',
+ 'channel__name': '渠道',
+ biz_type: '业务类型',
+ direction: '方向',
+ amount: '变动额',
+ balance_before: '变动前余额',
+ balance_after: '变动后余额',
+ ref_type: '关联类型',
+ ref_id: '关联ID',
+ idempotency_key: '幂等键',
+ 'operator_admin__username': '操作管理员',
+ remark: '备注',
+ create_time: '创建时间',
+ 'quick Search Fields': 'ID、业务类型、关联类型、备注、幂等键',
+ 'direction in': '入金',
+ 'direction out': '出金',
+ 'biz deposit': '充值入账',
+ 'biz withdraw': '提现出账',
+ 'biz withdraw_freeze': '提现冻结',
+ 'biz withdraw_unfreeze': '提现解冻',
+ 'biz platform_in': '平台划入',
+ 'biz platform_out': '平台划出',
+ 'biz admin_credit': '管理员加币',
+ 'biz admin_deduct': '管理员扣币',
+ 'biz bet': '下注扣款',
+ 'biz payout': '派彩',
+ 'biz fee': '手续费',
+ 'biz void_refund': '作废退款',
+ 'biz adjust': '其他调账',
+}
diff --git a/web/src/views/backend/game/walletRecord/index.vue b/web/src/views/backend/game/walletRecord/index.vue
new file mode 100644
index 0000000..8fe1694
--- /dev/null
+++ b/web/src/views/backend/game/walletRecord/index.vue
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+