优化页面翻译,优化统一订单页面审核操作
This commit is contained in:
@@ -4,6 +4,7 @@ namespace app\admin\controller\mall;
|
|||||||
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use app\common\controller\Backend;
|
use app\common\controller\Backend;
|
||||||
|
use app\common\library\MallBonusGrantPush;
|
||||||
use app\common\model\MallOrder;
|
use app\common\model\MallOrder;
|
||||||
use app\common\model\MallUserAsset;
|
use app\common\model\MallUserAsset;
|
||||||
use support\think\Db;
|
use support\think\Db;
|
||||||
@@ -251,7 +252,7 @@ class Order extends Backend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动重试(仅红利推送失败可重试)
|
* 手动推送红利(同步调用 PlayX,不限制自动重试次数;成功则 ACCEPTED,失败写入 fail_reason)
|
||||||
*/
|
*/
|
||||||
public function retry(Request $request): Response
|
public function retry(Request $request): Response
|
||||||
{
|
{
|
||||||
@@ -276,17 +277,42 @@ class Order extends Backend
|
|||||||
if ($order->type !== MallOrder::TYPE_BONUS) {
|
if ($order->type !== MallOrder::TYPE_BONUS) {
|
||||||
return $this->error(__('Only BONUS can retry'));
|
return $this->error(__('Only BONUS can retry'));
|
||||||
}
|
}
|
||||||
if ($order->grant_status !== MallOrder::GRANT_FAILED_RETRYABLE) {
|
if ($order->status !== MallOrder::STATUS_PENDING) {
|
||||||
return $this->error(__('Only FAILED_RETRYABLE can retry'));
|
return $this->error(__('Order status must be PENDING'));
|
||||||
}
|
|
||||||
if (($order->retry_count ?? 0) >= 3) {
|
|
||||||
return $this->error(__('Retry count exceeded'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$order->grant_status = MallOrder::GRANT_NOT_SENT;
|
$allowedStatuses = [
|
||||||
|
MallOrder::GRANT_NOT_SENT,
|
||||||
|
MallOrder::GRANT_SENT_PENDING,
|
||||||
|
MallOrder::GRANT_FAILED_RETRYABLE,
|
||||||
|
MallOrder::GRANT_FAILED_FINAL,
|
||||||
|
];
|
||||||
|
if (!in_array($order->grant_status, $allowedStatuses, true)) {
|
||||||
|
return $this->error(__('Current grant status cannot be manually pushed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strval(config('playx.api.base_url', '')) === '') {
|
||||||
|
return $this->error(__('PlayX API not configured'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = MallBonusGrantPush::push($order);
|
||||||
|
if ($result['ok']) {
|
||||||
|
$order->grant_status = MallOrder::GRANT_ACCEPTED;
|
||||||
|
$order->playx_transaction_id = $result['playx_transaction_id'];
|
||||||
|
$order->fail_reason = null;
|
||||||
|
$order->update_time = time();
|
||||||
|
$order->save();
|
||||||
|
|
||||||
|
return $this->success(__('Push succeeded'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$failReason = __('Manual push failed') . ': ' . $result['message'];
|
||||||
|
$order->fail_reason = $failReason;
|
||||||
|
$order->grant_status = MallOrder::GRANT_FAILED_FINAL;
|
||||||
|
$order->update_time = time();
|
||||||
$order->save();
|
$order->save();
|
||||||
|
|
||||||
return $this->success(__('Retry queued'));
|
return $this->error($failReason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,4 +95,9 @@ return [
|
|||||||
'%d records and files have been deleted' => '%d records and files have been deleted',
|
'%d records and files have been deleted' => '%d records and files have been deleted',
|
||||||
'Please input correct username' => 'Please enter the correct username',
|
'Please input correct username' => 'Please enter the correct username',
|
||||||
'Group Name Arr' => 'Group Name Arr',
|
'Group Name Arr' => 'Group Name Arr',
|
||||||
|
'Push succeeded' => 'Push succeeded',
|
||||||
|
'Manual push failed' => 'Manual push failed',
|
||||||
|
'PlayX API not configured' => 'PlayX API not configured',
|
||||||
|
'Current grant status cannot be manually pushed' => 'Current grant status cannot be manually pushed',
|
||||||
|
'Order status must be PENDING' => 'Order status must be PENDING',
|
||||||
];
|
];
|
||||||
@@ -114,4 +114,9 @@ return [
|
|||||||
'%d records and files have been deleted' => '已删除%d条记录和文件',
|
'%d records and files have been deleted' => '已删除%d条记录和文件',
|
||||||
'Please input correct username' => '请输入正确的用户名',
|
'Please input correct username' => '请输入正确的用户名',
|
||||||
'Group Name Arr' => '分组名称数组',
|
'Group Name Arr' => '分组名称数组',
|
||||||
|
'Push succeeded' => '推送成功',
|
||||||
|
'Manual push failed' => '手动推送失败',
|
||||||
|
'PlayX API not configured' => 'PlayX 接口未配置',
|
||||||
|
'Current grant status cannot be manually pushed' => '当前发放状态不可手动推送',
|
||||||
|
'Order status must be PENDING' => '订单状态须为处理中',
|
||||||
];
|
];
|
||||||
85
app/common/library/MallBonusGrantPush.php
Normal file
85
app/common/library/MallBonusGrantPush.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\common\library;
|
||||||
|
|
||||||
|
use app\common\model\MallItem;
|
||||||
|
use app\common\model\MallOrder;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 红利订单调用 PlayX bonus/grant(与定时任务、后台手动推送共用)
|
||||||
|
*/
|
||||||
|
final class MallBonusGrantPush
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array{ok: bool, message: string, playx_transaction_id: string}
|
||||||
|
*/
|
||||||
|
public static function push(MallOrder $order): array
|
||||||
|
{
|
||||||
|
$baseUrl = rtrim(strval(config('playx.api.base_url', '')), '/');
|
||||||
|
if ($baseUrl === '') {
|
||||||
|
return [
|
||||||
|
'ok' => false,
|
||||||
|
'message' => 'PlayX base_url not configured',
|
||||||
|
'playx_transaction_id' => '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = strval(config('playx.api.bonus_grant_url', '/api/v1/bonus/grant'));
|
||||||
|
$url = $baseUrl . $path;
|
||||||
|
|
||||||
|
$item = MallItem::where('id', $order->mall_item_id)->find();
|
||||||
|
$rewardName = $item ? strval($item->title) : '';
|
||||||
|
$category = $item ? strval($item->category) : 'daily';
|
||||||
|
$categoryTitle = $item ? strval($item->category_title) : '';
|
||||||
|
$multiplier = intval($order->multiplier ?? 0);
|
||||||
|
if ($multiplier <= 0) {
|
||||||
|
$multiplier = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = new Client([
|
||||||
|
'timeout' => 20,
|
||||||
|
'http_errors' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$requestId = 'mall_bonus_' . uniqid();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$res = $client->post($url, [
|
||||||
|
'json' => [
|
||||||
|
'request_id' => $requestId,
|
||||||
|
'externalTransactionId' => $order->external_transaction_id,
|
||||||
|
'user_id' => $order->user_id,
|
||||||
|
'amount' => $order->amount,
|
||||||
|
'rewardName' => $rewardName,
|
||||||
|
'category' => $category,
|
||||||
|
'categoryTitle' => $categoryTitle,
|
||||||
|
'multiplier' => $multiplier,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = json_decode(strval($res->getBody()), true) ?? [];
|
||||||
|
if ($res->getStatusCode() === 200 && ($data['status'] ?? '') === 'accepted') {
|
||||||
|
return [
|
||||||
|
'ok' => true,
|
||||||
|
'message' => '',
|
||||||
|
'playx_transaction_id' => strval($data['playx_transaction_id'] ?? ''),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'ok' => false,
|
||||||
|
'message' => strval($data['message'] ?? 'PlayX bonus grant not accepted'),
|
||||||
|
'playx_transaction_id' => '',
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return [
|
||||||
|
'ok' => false,
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'playx_transaction_id' => '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace app\process;
|
namespace app\process;
|
||||||
|
|
||||||
use app\common\model\MallItem;
|
use app\common\library\MallBonusGrantPush;
|
||||||
use app\common\model\MallOrder;
|
use app\common\model\MallOrder;
|
||||||
use app\common\model\MallUserAsset;
|
use app\common\model\MallUserAsset;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
@@ -99,9 +99,6 @@ class PlayxJobs
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$bonusPath = strval(config('playx.api.bonus_grant_url', '/api/v1/bonus/grant'));
|
|
||||||
$bonusUrl = rtrim($baseUrl, '/') . $bonusPath;
|
|
||||||
|
|
||||||
$maxRetry = 3;
|
$maxRetry = 3;
|
||||||
$list = MallOrder::where('type', MallOrder::TYPE_BONUS)
|
$list = MallOrder::where('type', MallOrder::TYPE_BONUS)
|
||||||
->whereIn('grant_status', [
|
->whereIn('grant_status', [
|
||||||
@@ -124,14 +121,12 @@ class PlayxJobs
|
|||||||
$order->retry_count = intval($order->retry_count ?? 0) + 1;
|
$order->retry_count = intval($order->retry_count ?? 0) + 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->sendGrantByOrder($order, $bonusUrl, $maxRetry);
|
$this->sendGrantByOrder($order, $maxRetry);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$order->fail_reason = $e->getMessage();
|
$order->fail_reason = $e->getMessage();
|
||||||
if (intval($order->retry_count) >= $maxRetry) {
|
if (intval($order->retry_count) >= $maxRetry) {
|
||||||
$order->grant_status = MallOrder::GRANT_FAILED_FINAL;
|
$order->grant_status = MallOrder::GRANT_FAILED_FINAL;
|
||||||
$order->status = MallOrder::STATUS_REJECTED;
|
|
||||||
$order->save();
|
$order->save();
|
||||||
$this->refundPoints($order);
|
|
||||||
} else {
|
} else {
|
||||||
$order->grant_status = MallOrder::GRANT_FAILED_RETRYABLE;
|
$order->grant_status = MallOrder::GRANT_FAILED_RETRYABLE;
|
||||||
$order->save();
|
$order->save();
|
||||||
@@ -167,61 +162,31 @@ class PlayxJobs
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sendGrantByOrder(MallOrder $order, string $bonusUrl, int $maxRetry): void
|
private function sendGrantByOrder(MallOrder $order, int $maxRetry): void
|
||||||
{
|
{
|
||||||
$item = null;
|
if ($order->type !== MallOrder::TYPE_BONUS) {
|
||||||
if ($order->mallItem) {
|
|
||||||
$item = $order->mallItem;
|
|
||||||
} else {
|
|
||||||
$item = MallItem::where('id', $order->mall_item_id)->find();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($order->type === MallOrder::TYPE_BONUS) {
|
|
||||||
$rewardName = $item ? strval($item->title) : '';
|
|
||||||
$category = $item ? strval($item->category) : 'daily';
|
|
||||||
$categoryTitle = $item ? strval($item->category_title) : '';
|
|
||||||
$multiplier = intval($order->multiplier ?? 0);
|
|
||||||
if ($multiplier <= 0) {
|
|
||||||
$multiplier = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$requestId = 'mall_retry_bonus_' . uniqid();
|
|
||||||
$res = $this->http->post($bonusUrl, [
|
|
||||||
'json' => [
|
|
||||||
'request_id' => $requestId,
|
|
||||||
'externalTransactionId' => $order->external_transaction_id,
|
|
||||||
'user_id' => $order->user_id,
|
|
||||||
'amount' => $order->amount,
|
|
||||||
'rewardName' => $rewardName,
|
|
||||||
'category' => $category,
|
|
||||||
'categoryTitle' => $categoryTitle,
|
|
||||||
'multiplier' => $multiplier,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$data = json_decode(strval($res->getBody()), true) ?? [];
|
|
||||||
if ($res->getStatusCode() === 200 && ($data['status'] ?? '') === 'accepted') {
|
|
||||||
$order->grant_status = MallOrder::GRANT_ACCEPTED;
|
|
||||||
$order->playx_transaction_id = strval($data['playx_transaction_id'] ?? '');
|
|
||||||
$order->save();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$order->fail_reason = strval($data['message'] ?? 'PlayX bonus grant not accepted');
|
|
||||||
if (intval($order->retry_count) >= $maxRetry) {
|
|
||||||
$order->grant_status = MallOrder::GRANT_FAILED_FINAL;
|
|
||||||
$order->status = MallOrder::STATUS_REJECTED;
|
|
||||||
$order->save();
|
|
||||||
$this->refundPoints($order);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$order->grant_status = MallOrder::GRANT_FAILED_RETRYABLE;
|
|
||||||
$order->save();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 非 BONUS 订单不参与 PlayX 发放重试(提现/实物由后台流程处理)
|
$result = MallBonusGrantPush::push($order);
|
||||||
|
if ($result['ok']) {
|
||||||
|
$order->grant_status = MallOrder::GRANT_ACCEPTED;
|
||||||
|
$order->playx_transaction_id = $result['playx_transaction_id'];
|
||||||
|
$order->save();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$order->fail_reason = $result['message'];
|
||||||
|
if (intval($order->retry_count) >= $maxRetry) {
|
||||||
|
$order->grant_status = MallOrder::GRANT_FAILED_FINAL;
|
||||||
|
$order->save();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$order->grant_status = MallOrder::GRANT_FAILED_RETRYABLE;
|
||||||
|
$order->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function refundPoints(MallOrder $order): void
|
private function refundPoints(MallOrder $order): void
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* backend common language package
|
* backend common language package
|
||||||
*/
|
*/
|
||||||
|
import menu from './en/menu'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
menu,
|
||||||
Balance: 'Balance',
|
Balance: 'Balance',
|
||||||
Integral: 'Integral',
|
Integral: 'Integral',
|
||||||
Connection: 'connection',
|
Connection: 'connection',
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
export default {
|
export default {
|
||||||
id: 'id',
|
approve: 'Review',
|
||||||
|
manual_retry: 'Retry grant',
|
||||||
|
retry_confirm: 'Queue this order for grant retry?',
|
||||||
|
id: 'ID',
|
||||||
user_id: 'user_id',
|
user_id: 'user_id',
|
||||||
type: 'type',
|
type: 'type',
|
||||||
'type BONUS': 'Bonus(BONUS)',
|
'type BONUS': 'Bonus(BONUS)',
|
||||||
|
|||||||
119
web/src/lang/backend/en/menu.ts
Normal file
119
web/src/lang/backend/en/menu.ts
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* Admin menu titles (admin_rule.name → menu.names.{name with / as _})
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
names: {
|
||||||
|
dashboard: 'Dashboard',
|
||||||
|
dashboard_index: 'Browse',
|
||||||
|
dashboard_dashboard: 'Dashboard',
|
||||||
|
auth: 'Access control',
|
||||||
|
auth_group: 'Admin groups',
|
||||||
|
auth_group_index: 'Browse',
|
||||||
|
auth_group_add: 'Add',
|
||||||
|
auth_group_edit: 'Edit',
|
||||||
|
auth_group_del: 'Delete',
|
||||||
|
auth_admin: 'Administrators',
|
||||||
|
auth_admin_index: 'Browse',
|
||||||
|
auth_admin_add: 'Add',
|
||||||
|
auth_admin_edit: 'Edit',
|
||||||
|
auth_admin_del: 'Delete',
|
||||||
|
auth_rule: 'Menu rules',
|
||||||
|
auth_rule_index: 'Browse',
|
||||||
|
auth_rule_add: 'Add',
|
||||||
|
auth_rule_edit: 'Edit',
|
||||||
|
auth_rule_del: 'Delete',
|
||||||
|
auth_rule_sortable: 'Sort',
|
||||||
|
auth_adminLog: 'Admin logs',
|
||||||
|
auth_adminLog_index: 'Browse',
|
||||||
|
user: 'Members',
|
||||||
|
user_user: 'Members',
|
||||||
|
user_user_index: 'Browse',
|
||||||
|
user_user_add: 'Add',
|
||||||
|
user_user_edit: 'Edit',
|
||||||
|
user_user_del: 'Delete',
|
||||||
|
user_group: 'Member groups',
|
||||||
|
user_group_index: 'Browse',
|
||||||
|
user_group_add: 'Add',
|
||||||
|
user_group_edit: 'Edit',
|
||||||
|
user_group_del: 'Delete',
|
||||||
|
user_rule: 'Member rules',
|
||||||
|
user_rule_index: 'Browse',
|
||||||
|
user_rule_add: 'Add',
|
||||||
|
user_rule_edit: 'Edit',
|
||||||
|
user_rule_del: 'Delete',
|
||||||
|
user_rule_sortable: 'Sort',
|
||||||
|
user_moneyLog: 'Balance logs',
|
||||||
|
user_moneyLog_index: 'Browse',
|
||||||
|
user_moneyLog_add: 'Add',
|
||||||
|
user_scoreLog: 'Points logs',
|
||||||
|
user_scoreLog_index: 'Browse',
|
||||||
|
user_scoreLog_add: 'Add',
|
||||||
|
routine: 'General',
|
||||||
|
routine_config: 'System config',
|
||||||
|
routine_config_index: 'Browse',
|
||||||
|
routine_config_edit: 'Edit',
|
||||||
|
routine_config_add: 'Add',
|
||||||
|
routine_config_del: 'Delete',
|
||||||
|
routine_attachment: 'Attachments',
|
||||||
|
routine_attachment_index: 'Browse',
|
||||||
|
routine_attachment_edit: 'Edit',
|
||||||
|
routine_attachment_del: 'Delete',
|
||||||
|
routine_adminInfo: 'Profile',
|
||||||
|
routine_adminInfo_index: 'Browse',
|
||||||
|
routine_adminInfo_edit: 'Edit',
|
||||||
|
security: 'Data security',
|
||||||
|
security_dataRecycleLog: 'Recycle bin',
|
||||||
|
security_dataRecycleLog_index: 'Browse',
|
||||||
|
security_dataRecycleLog_del: 'Delete',
|
||||||
|
security_dataRecycleLog_restore: 'Restore',
|
||||||
|
security_dataRecycleLog_info: 'Details',
|
||||||
|
security_sensitiveDataLog: 'Sensitive data logs',
|
||||||
|
security_sensitiveDataLog_index: 'Browse',
|
||||||
|
security_sensitiveDataLog_del: 'Delete',
|
||||||
|
security_sensitiveDataLog_rollback: 'Rollback',
|
||||||
|
security_sensitiveDataLog_info: 'Details',
|
||||||
|
security_dataRecycle: 'Recycle rules',
|
||||||
|
security_dataRecycle_index: 'Browse',
|
||||||
|
security_dataRecycle_add: 'Add',
|
||||||
|
security_dataRecycle_edit: 'Edit',
|
||||||
|
security_dataRecycle_del: 'Delete',
|
||||||
|
security_sensitiveData: 'Sensitive field rules',
|
||||||
|
security_sensitiveData_index: 'Browse',
|
||||||
|
security_sensitiveData_add: 'Add',
|
||||||
|
security_sensitiveData_edit: 'Edit',
|
||||||
|
security_sensitiveData_del: 'Delete',
|
||||||
|
buildadmin: 'BuildAdmin',
|
||||||
|
buildadmin_buildadmin: 'BuildAdmin',
|
||||||
|
moduleStore_moduleStore: 'Module store',
|
||||||
|
moduleStore_moduleStore_index: 'Browse',
|
||||||
|
moduleStore_moduleStore_install: 'Install',
|
||||||
|
moduleStore_moduleStore_changeState: 'Change state',
|
||||||
|
moduleStore_moduleStore_uninstall: 'Uninstall',
|
||||||
|
moduleStore_moduleStore_update: 'Update',
|
||||||
|
crud_crud: 'CRUD generator',
|
||||||
|
crud_crud_index: 'Browse',
|
||||||
|
crud_crud_generate: 'Generate',
|
||||||
|
crud_crud_delete: 'Delete',
|
||||||
|
mall: 'Points mall',
|
||||||
|
mall_userAsset: 'User assets',
|
||||||
|
mall_userAsset_index: 'Browse',
|
||||||
|
mall_userAsset_edit: 'Edit',
|
||||||
|
mall_userAsset_del: 'Delete',
|
||||||
|
mall_address: 'Shipping addresses',
|
||||||
|
mall_order: 'Orders',
|
||||||
|
mall_order_add: 'Add',
|
||||||
|
mall_order_edit: 'Edit',
|
||||||
|
mall_order_del: 'Delete',
|
||||||
|
mall_order_approve: 'Approve',
|
||||||
|
mall_dailyPush: 'Daily push',
|
||||||
|
mall_claimLog: 'Claim log',
|
||||||
|
mall_item: 'Products',
|
||||||
|
mall_playxOrder: 'PlayX orders',
|
||||||
|
mall_playxCenter: 'PlayX center',
|
||||||
|
mall_playxClaimLog: 'PlayX claim log',
|
||||||
|
mall_playxDailyPush: 'PlayX daily push',
|
||||||
|
mall_playxUserAsset: 'PlayX user assets',
|
||||||
|
mall_pintsOrder: 'Points orders',
|
||||||
|
mall_redemptionOrder: 'Redemption orders',
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -2,7 +2,10 @@
|
|||||||
* 后台公共语言包
|
* 后台公共语言包
|
||||||
* 覆盖风险:请避免使用页面语言包的目录名、文件名作为翻译 key
|
* 覆盖风险:请避免使用页面语言包的目录名、文件名作为翻译 key
|
||||||
*/
|
*/
|
||||||
|
import menu from './zh-cn/menu'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
menu,
|
||||||
Balance: '余额',
|
Balance: '余额',
|
||||||
Integral: '积分',
|
Integral: '积分',
|
||||||
Connection: '连接标识',
|
Connection: '连接标识',
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export default {
|
export default {
|
||||||
|
approve: '审核',
|
||||||
|
manual_retry: '手动重试',
|
||||||
|
retry_confirm: '确认将该订单加入重试队列?',
|
||||||
id: 'ID',
|
id: 'ID',
|
||||||
user_id: '用户ID',
|
user_id: '用户ID',
|
||||||
type: '类型',
|
type: '类型',
|
||||||
|
|||||||
120
web/src/lang/backend/zh-cn/menu.ts
Normal file
120
web/src/lang/backend/zh-cn/menu.ts
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* 后台菜单标题(与 admin_rule.name 对应:menu.names.{name 中 / 改为 _})
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
names: {
|
||||||
|
/** version202 后菜单 name 为 dashboard,不再使用 dashboard/dashboard */
|
||||||
|
dashboard: '控制台',
|
||||||
|
dashboard_index: '查看',
|
||||||
|
dashboard_dashboard: '控制台',
|
||||||
|
auth: '权限管理',
|
||||||
|
auth_group: '角色组管理',
|
||||||
|
auth_group_index: '查看',
|
||||||
|
auth_group_add: '添加',
|
||||||
|
auth_group_edit: '编辑',
|
||||||
|
auth_group_del: '删除',
|
||||||
|
auth_admin: '管理员管理',
|
||||||
|
auth_admin_index: '查看',
|
||||||
|
auth_admin_add: '添加',
|
||||||
|
auth_admin_edit: '编辑',
|
||||||
|
auth_admin_del: '删除',
|
||||||
|
auth_rule: '菜单规则管理',
|
||||||
|
auth_rule_index: '查看',
|
||||||
|
auth_rule_add: '添加',
|
||||||
|
auth_rule_edit: '编辑',
|
||||||
|
auth_rule_del: '删除',
|
||||||
|
auth_rule_sortable: '快速排序',
|
||||||
|
auth_adminLog: '管理员日志管理',
|
||||||
|
auth_adminLog_index: '查看',
|
||||||
|
user: '会员管理',
|
||||||
|
user_user: '会员管理',
|
||||||
|
user_user_index: '查看',
|
||||||
|
user_user_add: '添加',
|
||||||
|
user_user_edit: '编辑',
|
||||||
|
user_user_del: '删除',
|
||||||
|
user_group: '会员分组管理',
|
||||||
|
user_group_index: '查看',
|
||||||
|
user_group_add: '添加',
|
||||||
|
user_group_edit: '编辑',
|
||||||
|
user_group_del: '删除',
|
||||||
|
user_rule: '会员规则管理',
|
||||||
|
user_rule_index: '查看',
|
||||||
|
user_rule_add: '添加',
|
||||||
|
user_rule_edit: '编辑',
|
||||||
|
user_rule_del: '删除',
|
||||||
|
user_rule_sortable: '快速排序',
|
||||||
|
user_moneyLog: '会员余额管理',
|
||||||
|
user_moneyLog_index: '查看',
|
||||||
|
user_moneyLog_add: '添加',
|
||||||
|
user_scoreLog: '会员积分管理',
|
||||||
|
user_scoreLog_index: '查看',
|
||||||
|
user_scoreLog_add: '添加',
|
||||||
|
routine: '常规管理',
|
||||||
|
routine_config: '系统配置',
|
||||||
|
routine_config_index: '查看',
|
||||||
|
routine_config_edit: '编辑',
|
||||||
|
routine_config_add: '添加',
|
||||||
|
routine_config_del: '删除',
|
||||||
|
routine_attachment: '附件管理',
|
||||||
|
routine_attachment_index: '查看',
|
||||||
|
routine_attachment_edit: '编辑',
|
||||||
|
routine_attachment_del: '删除',
|
||||||
|
routine_adminInfo: '个人资料',
|
||||||
|
routine_adminInfo_index: '查看',
|
||||||
|
routine_adminInfo_edit: '编辑',
|
||||||
|
security: '数据安全管理',
|
||||||
|
security_dataRecycleLog: '数据回收站',
|
||||||
|
security_dataRecycleLog_index: '查看',
|
||||||
|
security_dataRecycleLog_del: '删除',
|
||||||
|
security_dataRecycleLog_restore: '还原',
|
||||||
|
security_dataRecycleLog_info: '查看详情',
|
||||||
|
security_sensitiveDataLog: '敏感数据修改记录',
|
||||||
|
security_sensitiveDataLog_index: '查看',
|
||||||
|
security_sensitiveDataLog_del: '删除',
|
||||||
|
security_sensitiveDataLog_rollback: '回滚',
|
||||||
|
security_sensitiveDataLog_info: '查看详情',
|
||||||
|
security_dataRecycle: '数据回收规则管理',
|
||||||
|
security_dataRecycle_index: '查看',
|
||||||
|
security_dataRecycle_add: '添加',
|
||||||
|
security_dataRecycle_edit: '编辑',
|
||||||
|
security_dataRecycle_del: '删除',
|
||||||
|
security_sensitiveData: '敏感字段规则管理',
|
||||||
|
security_sensitiveData_index: '查看',
|
||||||
|
security_sensitiveData_add: '添加',
|
||||||
|
security_sensitiveData_edit: '编辑',
|
||||||
|
security_sensitiveData_del: '删除',
|
||||||
|
buildadmin: 'BuildAdmin',
|
||||||
|
buildadmin_buildadmin: 'BuildAdmin',
|
||||||
|
moduleStore_moduleStore: '模块市场',
|
||||||
|
moduleStore_moduleStore_index: '查看',
|
||||||
|
moduleStore_moduleStore_install: '安装',
|
||||||
|
moduleStore_moduleStore_changeState: '调整状态',
|
||||||
|
moduleStore_moduleStore_uninstall: '卸载',
|
||||||
|
moduleStore_moduleStore_update: '更新',
|
||||||
|
crud_crud: 'CRUD代码生成',
|
||||||
|
crud_crud_index: '查看',
|
||||||
|
crud_crud_generate: '生成',
|
||||||
|
crud_crud_delete: '删除',
|
||||||
|
mall: '积分商城',
|
||||||
|
mall_userAsset: '用户资产',
|
||||||
|
mall_userAsset_index: '查看',
|
||||||
|
mall_userAsset_edit: '编辑',
|
||||||
|
mall_userAsset_del: '删除',
|
||||||
|
mall_address: '收货地址管理',
|
||||||
|
mall_order: '统一订单',
|
||||||
|
mall_order_add: '新增',
|
||||||
|
mall_order_edit: '编辑',
|
||||||
|
mall_order_del: '删除',
|
||||||
|
mall_order_approve: '审核通过',
|
||||||
|
mall_dailyPush: '每日推送',
|
||||||
|
mall_claimLog: '领取记录',
|
||||||
|
mall_item: '商品管理',
|
||||||
|
mall_playxOrder: 'PlayX订单',
|
||||||
|
mall_playxCenter: 'PlayX中心',
|
||||||
|
mall_playxClaimLog: 'PlayX领取记录',
|
||||||
|
mall_playxDailyPush: 'PlayX每日推送',
|
||||||
|
mall_playxUserAsset: 'PlayX用户资产',
|
||||||
|
mall_pintsOrder: '积分订单',
|
||||||
|
mall_redemptionOrder: '兑换订单',
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<el-sub-menu @click="onClickSubMenu(menu)" :index="getMenuKey(menu)" :key="getMenuKey(menu)">
|
<el-sub-menu @click="onClickSubMenu(menu)" :index="getMenuKey(menu)" :key="getMenuKey(menu)">
|
||||||
<template #title>
|
<template #title>
|
||||||
<Icon :color="config.getColorVal('menuColor')" :name="menu.meta?.icon ? menu.meta?.icon : config.layout.menuDefaultIcon" />
|
<Icon :color="config.getColorVal('menuColor')" :name="menu.meta?.icon ? menu.meta?.icon : config.layout.menuDefaultIcon" />
|
||||||
<span>{{ menu.meta?.title ? menu.meta?.title : $t('noTitle') }}</span>
|
<span>{{ menuTitleFromRoute(menu) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<MenuTree :extends="{ ...props.extends, level: props.extends.level + 1 }" :menus="menu.children" />
|
<MenuTree :extends="{ ...props.extends, level: props.extends.level + 1 }" :menus="menu.children" />
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
<el-menu-item @click="onClickMenu(menu)" :index="getMenuKey(menu)" :key="getMenuKey(menu)">
|
<el-menu-item @click="onClickMenu(menu)" :index="getMenuKey(menu)" :key="getMenuKey(menu)">
|
||||||
<Icon :color="config.getColorVal('menuColor')" :name="menu.meta?.icon ? menu.meta?.icon : config.layout.menuDefaultIcon" />
|
<Icon :color="config.getColorVal('menuColor')" :name="menu.meta?.icon ? menu.meta?.icon : config.layout.menuDefaultIcon" />
|
||||||
<span>{{ menu.meta?.title ? menu.meta?.title : $t('noTitle') }}</span>
|
<span>{{ menuTitleFromRoute(menu) }}</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@@ -23,6 +23,7 @@ import { ElNotification } from 'element-plus'
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
import type { RouteRecordRaw } from 'vue-router'
|
||||||
import { useConfig } from '/@/stores/config'
|
import { useConfig } from '/@/stores/config'
|
||||||
|
import { menuTitleFromRoute } from '/@/utils/menuI18n'
|
||||||
import { getFirstRoute, getMenuKey, onClickMenu } from '/@/utils/router'
|
import { getFirstRoute, getMenuKey, onClickMenu } from '/@/utils/router'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
:ref="tabsRefs.set"
|
:ref="tabsRefs.set"
|
||||||
:key="idx"
|
:key="idx"
|
||||||
>
|
>
|
||||||
{{ item.meta.title }}
|
{{ menuTitleFromRoute(item) }}
|
||||||
<transition @after-leave="selectNavTab(tabsRefs[navTabs.state.activeIndex])" name="el-fade-in">
|
<transition @after-leave="selectNavTab(tabsRefs[navTabs.state.activeIndex])" name="el-fade-in">
|
||||||
<Icon v-show="navTabs.state.tabsView.length > 1" class="close-icon" @click.stop="closeTab(item)" size="15" name="el-icon-Close" />
|
<Icon v-show="navTabs.state.tabsView.length > 1" class="close-icon" @click.stop="closeTab(item)" size="15" name="el-icon-Close" />
|
||||||
</transition>
|
</transition>
|
||||||
@@ -29,6 +29,7 @@ import type { ContextMenuItem, ContextMenuItemClickEmitArg } from '/@/components
|
|||||||
import useCurrentInstance from '/@/utils/useCurrentInstance'
|
import useCurrentInstance from '/@/utils/useCurrentInstance'
|
||||||
import Contextmenu from '/@/components/contextmenu/index.vue'
|
import Contextmenu from '/@/components/contextmenu/index.vue'
|
||||||
import horizontalScroll from '/@/utils/horizontalScroll'
|
import horizontalScroll from '/@/utils/horizontalScroll'
|
||||||
|
import { menuTitleFromRoute } from '/@/utils/menuI18n'
|
||||||
import { getFirstRoute, routePush } from '/@/utils/router'
|
import { getFirstRoute, routePush } from '/@/utils/router'
|
||||||
import { adminBaseRoutePath } from '/@/router/static/adminBase'
|
import { adminBaseRoutePath } from '/@/router/static/adminBase'
|
||||||
|
|
||||||
|
|||||||
33
web/src/utils/menuI18n.ts
Normal file
33
web/src/utils/menuI18n.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
|
||||||
|
import { i18n } from '/@/lang/index'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台菜单/标签标题:优先按路由 name(对应 admin_rule.name)匹配 menu.names.*
|
||||||
|
*/
|
||||||
|
export function menuI18nKeyFromName(name: string | symbol | null | undefined): string {
|
||||||
|
if (name == null || name === '') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const n = String(name).trim()
|
||||||
|
if (!n) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return `menu.names.${n.replace(/\//g, '_')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function menuTitleFromName(name: string | symbol | null | undefined, fallback?: string): string {
|
||||||
|
const key = menuI18nKeyFromName(name)
|
||||||
|
if (key && i18n.global.te(key)) {
|
||||||
|
return String(i18n.global.t(key))
|
||||||
|
}
|
||||||
|
if (fallback && i18n.global.te(fallback)) {
|
||||||
|
return String(i18n.global.t(fallback))
|
||||||
|
}
|
||||||
|
return fallback || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function menuTitleFromRoute(route: RouteRecordRaw | RouteLocationNormalized): string {
|
||||||
|
const name = route.name
|
||||||
|
const metaTitle = route.meta && typeof route.meta.title === 'string' ? route.meta.title : ''
|
||||||
|
return menuTitleFromName(name, metaTitle) || metaTitle || String(i18n.global.t('noTitle'))
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@ const optButtons: OptButton[] = defaultOptButtons(['edit', 'delete']).map((btn)
|
|||||||
btn.name === 'edit'
|
btn.name === 'edit'
|
||||||
? {
|
? {
|
||||||
...btn,
|
...btn,
|
||||||
title: '审核',
|
title: t('mall.order.approve'),
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
class: 'table-row-edit',
|
class: 'table-row-edit',
|
||||||
icon: 'fa fa-check',
|
icon: 'fa fa-check',
|
||||||
@@ -235,7 +235,7 @@ const baTable = new baTableClass(
|
|||||||
{
|
{
|
||||||
label: t('Operate'),
|
label: t('Operate'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 80,
|
width: 120,
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
@@ -243,16 +243,20 @@ const baTable = new baTableClass(
|
|||||||
{
|
{
|
||||||
render: 'confirmButton',
|
render: 'confirmButton',
|
||||||
name: 'retry',
|
name: 'retry',
|
||||||
title: 'Retry',
|
title: t('mall.order.manual_retry'),
|
||||||
text: '手动重试',
|
text: '',
|
||||||
type: 'warning',
|
type: 'primary',
|
||||||
icon: '',
|
class: 'table-row-edit',
|
||||||
display: (row: TableRow) => row.type === 'BONUS' && row.grant_status === 'FAILED_RETRYABLE' && row.status === 'PENDING',
|
icon: 'fa fa-refresh',
|
||||||
|
display: (row: TableRow) =>
|
||||||
|
row.type === 'BONUS' &&
|
||||||
|
row.status === 'PENDING' &&
|
||||||
|
['NOT_SENT', 'SENT_PENDING', 'FAILED_RETRYABLE', 'FAILED_FINAL'].includes(String(row.grant_status)),
|
||||||
popconfirm: {
|
popconfirm: {
|
||||||
title: '确认将该订单加入重试队列?',
|
title: t('mall.order.retry_confirm'),
|
||||||
confirmButtonText: '确认',
|
confirmButtonText: t('Confirm'),
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: t('Cancel'),
|
||||||
confirmButtonType: 'warning',
|
confirmButtonType: 'primary',
|
||||||
},
|
},
|
||||||
click: async (row: TableRow) => {
|
click: async (row: TableRow) => {
|
||||||
await createAxios(
|
await createAxios(
|
||||||
|
|||||||
@@ -116,7 +116,10 @@ const baTable = new baTableClass(
|
|||||||
text: '手动重试',
|
text: '手动重试',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
icon: '',
|
icon: '',
|
||||||
display: (row: TableRow) => row.type === 'BONUS' && row.grant_status === 'FAILED_RETRYABLE' && row.status === 'PENDING',
|
display: (row: TableRow) =>
|
||||||
|
row.type === 'BONUS' &&
|
||||||
|
row.status === 'PENDING' &&
|
||||||
|
['NOT_SENT', 'SENT_PENDING', 'FAILED_RETRYABLE', 'FAILED_FINAL'].includes(String(row.grant_status)),
|
||||||
popconfirm: {
|
popconfirm: {
|
||||||
title: '确认将该订单加入重试队列?',
|
title: '确认将该订单加入重试队列?',
|
||||||
confirmButtonText: '确认',
|
confirmButtonText: '确认',
|
||||||
@@ -126,7 +129,7 @@ const baTable = new baTableClass(
|
|||||||
click: async (row: TableRow) => {
|
click: async (row: TableRow) => {
|
||||||
await createAxios(
|
await createAxios(
|
||||||
{
|
{
|
||||||
url: '/admin/mall.PlayxOrder/retry',
|
url: '/admin/mall.Order/retry',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: {
|
data: {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user