增加积分调整日志

This commit is contained in:
2026-07-21 18:59:45 +08:00
parent 4fbc4500fd
commit 140a068b88
23 changed files with 673 additions and 18 deletions

View File

@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace app\admin\controller\mall;
use app\admin\model\MallPointsLog;
use app\common\controller\Backend;
use app\common\model\MallUserAsset;
use support\Response;
use Webman\Http\Request;
class PointsLog extends Backend
{
protected ?object $model = null;
protected array $withJoinTable = ['userAsset', 'admin'];
protected array|string $preExcludeFields = ['id', 'before', 'after', 'memo', 'admin_id', 'create_time'];
protected array|string $quickSearchField = [
'userAsset.playx_user_id',
'userAsset.username',
'userAsset.phone',
];
protected bool $autoFillAdminId = true;
protected function initController(Request $request): ?Response
{
$this->model = new MallPointsLog();
return null;
}
public function add(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->method() === 'POST') {
return $this->_add();
}
$userAssetId = $request->get('userAssetId', $request->post('userAssetId', 0));
$userAsset = MallUserAsset::where('id', $userAssetId)->find();
if (!$userAsset) {
return $this->error(__('User asset not found'));
}
return $this->success('', ['userAsset' => $userAsset]);
}
public function edit(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
return $this->error(__('Points log cannot be modified'));
}
public function del(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
return $this->error(__('Points log cannot be deleted'));
}
}

View File

@@ -17,7 +17,14 @@ class UserAsset extends Backend
*/
protected ?object $model = null;
protected array|string $preExcludeFields = ['id', 'create_time', 'update_time'];
protected array|string $preExcludeFields = [
'id',
'locked_points',
'available_points',
'today_claimed',
'create_time',
'update_time',
];
protected string|array $quickSearchField = [
'playx_user_id',

View File

@@ -0,0 +1,13 @@
<?php
return [
'User asset' => 'User asset',
'Points adjustment' => 'Points adjustment',
'User asset not found' => 'User asset not found',
'Points adjustment must be a non-zero integer' => 'Points adjustment must be a non-zero integer',
'Insufficient available points' => 'Insufficient available points',
'Administrator added %s points' => 'Administrator added %s points',
'Administrator deducted %s points' => 'Administrator deducted %s points',
'Points log cannot be modified' => 'Points log cannot be modified',
'Points log cannot be deleted' => 'Points log cannot be deleted',
];

View File

@@ -0,0 +1,13 @@
<?php
return [
'User asset' => '用户资产',
'Points adjustment' => '调整积分',
'User asset not found' => '用户资产不存在',
'Points adjustment must be a non-zero integer' => '调整积分必须为非零整数',
'Insufficient available points' => '可用积分不足',
'Administrator added %s points' => '管理员增加积分 %s',
'Administrator deducted %s points' => '管理员扣除积分 %s',
'Points log cannot be modified' => '积分流水不允许修改',
'Points log cannot be deleted' => '积分流水不允许删除',
];

View File

@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace app\admin\model;
use app\common\model\MallUserAsset;
use think\model\relation\BelongsTo;
class MallPointsLog extends \app\common\model\MallPointsLog
{
public static function onBeforeInsert($model): void
{
$userAssetId = filter_var($model->user_asset_id, FILTER_VALIDATE_INT);
if ($userAssetId === false || $userAssetId <= 0) {
throw new \InvalidArgumentException(__('User asset not found'));
}
$scoreValue = filter_var($model->score_value, FILTER_VALIDATE_INT);
if ($scoreValue === false || $scoreValue === 0) {
throw new \InvalidArgumentException(__('Points adjustment must be a non-zero integer'));
}
$userAsset = MallUserAsset::where('id', $userAssetId)->lock(true)->find();
if (!$userAsset) {
throw new \RuntimeException(__('User asset not found'));
}
$before = $userAsset->available_points;
$after = $before + $scoreValue;
if ($after < 0) {
throw new \RuntimeException(__('Insufficient available points'));
}
$model->user_asset_id = $userAssetId;
$model->score_value = $scoreValue;
$model->before = $before;
$model->after = $after;
$model->memo = $scoreValue > 0
? __('Administrator added %s points', [abs($scoreValue)])
: __('Administrator deducted %s points', [abs($scoreValue)]);
$userAsset->available_points = $after;
$userAsset->save();
}
public static function onBeforeDelete(): bool
{
return false;
}
public function userAsset(): BelongsTo
{
return $this->belongsTo(MallUserAsset::class, 'user_asset_id');
}
public function admin(): BelongsTo
{
return $this->belongsTo(Admin::class, 'admin_id');
}
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace app\admin\validate;
use think\Validate;
class MallPointsLog extends Validate
{
protected $failException = true;
protected $rule = [
'user_asset_id' => 'require|integer|gt:0',
'score_value' => 'require|integer|notIn:0',
];
protected $scene = [
'add' => ['user_asset_id', 'score_value'],
];
public function __construct()
{
$this->field = [
'user_asset_id' => __('User asset'),
'score_value' => __('Points adjustment'),
];
parent::__construct();
}
}

View File

@@ -847,7 +847,7 @@ class Playx extends Api
}
/**
* 积分流水(领取/兑换/退回)
* 积分流水(领取/兑换/退回/管理员调整
* GET /api/v1/mall/pointsLogs
*
* 鉴权token / session_id / user_id同 assets/orders
@@ -981,6 +981,28 @@ FROM (
FROM mall_order o
LEFT JOIN mall_item i ON i.id = o.mall_item_id
WHERE o.user_id = :user_id_refund AND o.status = 'REJECTED' AND o.points_cost > 0 AND o.update_time IS NOT NULL
UNION ALL
SELECT
'ADMIN_ADJUST' AS biz_type,
CASE WHEN pl.score_value > 0 THEN 'IN' ELSE 'OUT' END AS direction,
ABS(pl.score_value) AS points,
pl.create_time AS ts,
pl.id AS ref_id,
'' AS order_no,
'' AS order_status,
0 AS item_id,
'' AS item_title,
0 AS item_type,
0 AS item_score,
0 AS item_amount,
0 AS item_multiplier,
'' AS item_category,
'' AS item_category_title,
CONCAT(LPAD(pl.create_time, 10, '0'), '_4_', LPAD(pl.id, 10, '0')) AS sort_key
FROM mall_points_log pl
WHERE pl.user_asset_id = :user_asset_id_adjust
) t
WHERE 1=1
SQL;
@@ -989,6 +1011,7 @@ SQL;
'user_id_claim' => $playxUserId,
'user_id_redeem' => $playxUserId,
'user_id_refund' => $playxUserId,
'user_asset_id_adjust' => $assetId,
];
if ($cursor !== '') {
@@ -1016,10 +1039,18 @@ SQL;
if (!is_array($row)) {
continue;
}
$memo = '';
if (($row['biz_type'] ?? '') === 'ADMIN_ADJUST') {
$memoKey = ($row['direction'] ?? '') === 'OUT'
? 'Administrator deducted %s points'
: 'Administrator added %s points';
$memo = __($memoKey, [$row['points'] ?? 0]);
}
$list[] = [
'biz_type' => $row['biz_type'] ?? '',
'direction' => $row['direction'] ?? '',
'points' => $row['points'] ?? 0,
'memo' => $memo,
'ts' => $row['ts'] ?? null,
'ref_id' => $row['ref_id'] ?? '',
'order_no' => $row['order_no'] ?? '',

View File

@@ -78,6 +78,8 @@ return [
'item_id and user_id/session_id required' => 'item_id and user_id/session_id/token are required',
'Item not found or not available' => 'Item not found or not available',
'Insufficient points' => 'Insufficient points',
'Administrator added %s points' => 'Administrator added %s points',
'Administrator deducted %s points' => 'Administrator deducted %s points',
'Redeem submitted, please wait about 10 minutes' => 'Redeem submitted, please wait about 10 minutes',
'Missing required fields' => 'Missing required fields',
'Out of stock' => 'Out of stock',

View File

@@ -79,6 +79,8 @@ return [
'item_id and user_id/session_id required' => 'item_id dan user_id/session_id/token diperlukan',
'Item not found or not available' => 'Item tidak dijumpai atau tidak tersedia',
'Insufficient points' => 'Mata tidak mencukupi',
'Administrator added %s points' => 'Pentadbir menambah %s mata',
'Administrator deducted %s points' => 'Pentadbir menolak %s mata',
'Redeem submitted, please wait about 10 minutes' => 'Penebusan dihantar, sila tunggu kira-kira 10 minit',
'Missing required fields' => 'Medan wajib tiada',
'Out of stock' => 'Stok tidak mencukupi',

View File

@@ -80,6 +80,8 @@ return [
'item_id and user_id/session_id required' => '缺少 item_id或未提供有效的 user_id/session_id/token',
'Item not found or not available' => '商品不存在或已下架',
'Insufficient points' => '积分不足',
'Administrator added %s points' => '管理员增加积分 %s',
'Administrator deducted %s points' => '管理员扣除积分 %s',
'Redeem submitted, please wait about 10 minutes' => '兑换已提交,请等待约 10 分钟',
'Missing required fields' => '缺少必填字段',
'Out of stock' => '库存不足',

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace app\common\model;
use app\common\model\traits\TimestampInteger;
use support\think\Model;
class MallPointsLog extends Model
{
use TimestampInteger;
protected string $table = 'mall_points_log';
protected string $pk = 'id';
protected bool $autoWriteTimestamp = true;
protected bool $updateTime = false;
}