From 27dc9eb3b0c6674db6c1e90d5558bff745dcdad6 Mon Sep 17 00:00:00 2001 From: Mars <3361409208a@gmail.com> Date: Mon, 22 Jun 2026 14:10:54 +0800 Subject: [PATCH] =?UTF-8?q?sync(theme-2):=20=E5=90=8C=E6=AD=A5=20main=20?= =?UTF-8?q?=E6=9C=80=E6=96=B0=20API/Admin=20=E4=B8=8E=E7=8E=A9=E5=AE=B6?= =?UTF-8?q?=E7=AB=AF=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从 main 同步站内信手动发送、媒体库选择、列表子路由重构等 API/Admin 改动;玩家端仅合并 ADMIN_CUSTOM 富文本、消息预览与充值截图压缩逻辑,保留 theme-2 样式。 --- apps/admin/components.d.ts | 1 + apps/admin/src/App.vue | 22 +- .../src/components/ContentImageField.vue | 23 +- .../src/components/ContentRichEditor.vue | 23 +- .../admin/src/components/LeagueRowActions.vue | 98 +++ .../components/PlayerWalletLedgerDialog.vue | 22 +- .../agent-direct-players-context.ts | 24 + apps/admin/src/i18n/admin-messages.ts | 21 + apps/admin/src/i18n/admin-pages-ms.ts | 67 ++ apps/admin/src/i18n/admin-pages.ts | 18 + apps/admin/src/i18n/pages/en.ts | 65 ++ apps/admin/src/i18n/pages/zh.ts | 67 +- apps/admin/src/layouts/ManageLayout.vue | 6 +- apps/admin/src/router/index.ts | 26 + apps/admin/src/utils/admin-breadcrumb.ts | 31 +- apps/admin/src/utils/html.ts | 59 ++ apps/admin/src/utils/matchesListState.ts | 32 +- apps/admin/src/utils/media-library.ts | 25 + apps/admin/src/views/AgentManager.vue | 605 +++----------- apps/admin/src/views/Contents.vue | 561 ++++++++++++- apps/admin/src/views/DepositOrders.vue | 41 +- apps/admin/src/views/Matches.vue | 479 +++++------ apps/admin/src/views/MatchesOutrights.vue | 123 ++- apps/admin/src/views/MediaLibrary.vue | 310 +++++++- apps/admin/src/views/Settlement.vue | 749 +++++++++++++----- .../views/agent/AgentDirectPlayersView.vue | 233 ++++++ .../src/views/agent/GlobalSettingsView.vue | 368 +++++++++ .../src/views/matches/LeagueMatchesPage.vue | 254 ++++++ .../src/views/matches/LeagueMatchesPanel.vue | 265 ++++++- .../views/matches/LeagueOutrightOddsPanel.vue | 35 +- .../src/views/matches/LeagueOutrightsPage.vue | 53 ++ .../src/views/matches/MatchEventEditor.vue | 32 +- .../views/outrights/OutrightEditRedirect.vue | 6 +- .../migration.sql | 27 + .../migration.sql | 9 + apps/api/prisma/schema.prisma | 40 +- .../applications/admin/admin.controller.ts | 248 +++++- .../src/domains/catalog/matches.service.ts | 45 +- .../deposit-screenshot-cleanup.service.ts | 121 +++ .../api/src/domains/deposit/deposit.module.ts | 5 +- .../player-messages.service.spec.ts | 66 +- .../player-messages.service.ts | 250 +++++- .../domains/settlement/settlement.service.ts | 77 ++ .../shared/config/system-config.service.ts | 27 + .../src/components/MessageListPanel.vue | 4 +- .../src/composables/usePlayerMessages.ts | 3 +- apps/player/src/views/MessageDetailView.vue | 34 +- apps/player/src/views/RechargeView.vue | 39 +- packages/shared/src/api-errors.js | 50 ++ packages/shared/src/api-errors.ts | 50 ++ 50 files changed, 4653 insertions(+), 1186 deletions(-) create mode 100644 apps/admin/src/components/LeagueRowActions.vue create mode 100644 apps/admin/src/composables/agent-direct-players-context.ts create mode 100644 apps/admin/src/utils/media-library.ts create mode 100644 apps/admin/src/views/agent/AgentDirectPlayersView.vue create mode 100644 apps/admin/src/views/agent/GlobalSettingsView.vue create mode 100644 apps/admin/src/views/matches/LeagueMatchesPage.vue create mode 100644 apps/admin/src/views/matches/LeagueOutrightsPage.vue create mode 100644 apps/api/prisma/migrations/20260622120000_player_message_broadcasts/migration.sql create mode 100644 apps/api/prisma/migrations/20260622140000_player_message_broadcast_translations/migration.sql create mode 100644 apps/api/src/domains/deposit/deposit-screenshot-cleanup.service.ts diff --git a/apps/admin/components.d.ts b/apps/admin/components.d.ts index 13b5d35..b2383bf 100644 --- a/apps/admin/components.d.ts +++ b/apps/admin/components.d.ts @@ -69,6 +69,7 @@ declare module 'vue' { InviteHistoryPanel: typeof import('./src/components/InviteHistoryPanel.vue')['default'] InviteManageDialog: typeof import('./src/components/InviteManageDialog.vue')['default'] LeagueArchiveDialog: typeof import('./src/components/LeagueArchiveDialog.vue')['default'] + LeagueRowActions: typeof import('./src/components/LeagueRowActions.vue')['default'] LogoUrlField: typeof import('./src/components/LogoUrlField.vue')['default'] MatchArchiveDialog: typeof import('./src/components/MatchArchiveDialog.vue')['default'] MatchesSubNav: typeof import('./src/components/MatchesSubNav.vue')['default'] diff --git a/apps/admin/src/App.vue b/apps/admin/src/App.vue index 4d8bc84..6dc29bc 100644 --- a/apps/admin/src/App.vue +++ b/apps/admin/src/App.vue @@ -65,6 +65,7 @@ body::-webkit-scrollbar { height: 100%; min-height: 0; overflow: hidden; + gap: 14px; } .admin-list-page > .page-toolbar, .admin-list-page > .filter-card, @@ -78,16 +79,16 @@ body::-webkit-scrollbar { justify-content: flex-end; align-items: center; gap: 8px; - margin: 0 0 8px; + margin: 0; } .admin-list-page > .tool-card { - margin-bottom: 8px; + margin-bottom: 0; } .admin-list-page > .filter-card { - margin-bottom: 8px; + margin-bottom: 0; } .admin-list-page > .list-chrome { - margin-bottom: 8px; + margin-bottom: 0; display: flex; flex-direction: column; gap: 6px; @@ -204,7 +205,7 @@ body::-webkit-scrollbar { margin-right: 0; } .admin-list-page > .list-settings { - margin-bottom: 8px; + margin-bottom: 0; } .list-settings :deep(.el-collapse-item__header) { height: 36px; @@ -250,7 +251,16 @@ body::-webkit-scrollbar { min-height: 0; display: flex; flex-direction: column; - padding: 0 12px 12px; + padding: 12px; +} + +/* data-card 内不再嵌套第二层卡片边框,避免双层顶边重合 */ +.admin-list-page > .data-card .table-wrap, +.admin-list-page > .data-card .admin-table-wrap { + border: none; + border-radius: 0; + box-shadow: none; + background: transparent; } .admin-list-page .table-wrap { flex: 1; diff --git a/apps/admin/src/components/ContentImageField.vue b/apps/admin/src/components/ContentImageField.vue index 1459588..69c9edb 100644 --- a/apps/admin/src/components/ContentImageField.vue +++ b/apps/admin/src/components/ContentImageField.vue @@ -3,6 +3,8 @@ import { ref } from 'vue'; import { ElMessage } from 'element-plus'; import { useAdminLocale } from '../composables/useAdminLocale'; import api from '../api'; +import { fetchMediaLibraryImages } from '../utils/media-library'; +import { resolveApiError } from '../i18n/form-validation'; const props = withDefaults( defineProps<{ @@ -23,7 +25,7 @@ const MAX_UPLOAD_SIZE = 5 * 1024 * 1024; const uploading = ref(false); const mediaPickerVisible = ref(false); -const mediaFiles = ref>([]); +const mediaFiles = ref>([]); const mediaLoading = ref(false); async function uploadImage(file: File) { @@ -67,12 +69,10 @@ async function openMediaPicker() { mediaPickerVisible.value = true; mediaLoading.value = true; try { - const res = await api.get('/admin/files', { - params: { category: props.category, pageSize: 200 }, - }); - mediaFiles.value = res.data.data.items ?? []; - } catch { + mediaFiles.value = await fetchMediaLibraryImages({ pageSize: 200 }); + } catch (err: unknown) { mediaFiles.value = []; + ElMessage.error(resolveApiError(err, t, 'content.upload.load_media_failed')); } finally { mediaLoading.value = false; } @@ -133,6 +133,7 @@ function pickMediaFile(url: string) { width="680px" destroy-on-close append-to-body + :z-index="4000" >
{{ t('common.loading') }}
{{ t('content.upload.no_media') }}
@@ -148,6 +149,7 @@ function pickMediaFile(url: string) {
SVG
{{ file.filename }}
+
{{ file.category }}
@@ -306,11 +308,18 @@ function pickMediaFile(url: string) { } .media-name { - padding: 6px 8px; + padding: 6px 8px 2px; font-size: 11px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + +.media-category { + padding: 0 8px 6px; + font-size: 10px; + color: var(--text-muted); + opacity: 0.85; +} diff --git a/apps/admin/src/components/ContentRichEditor.vue b/apps/admin/src/components/ContentRichEditor.vue index 4590f00..85d014b 100644 --- a/apps/admin/src/components/ContentRichEditor.vue +++ b/apps/admin/src/components/ContentRichEditor.vue @@ -3,6 +3,8 @@ import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'; import { ElMessage } from 'element-plus'; import { useAdminLocale } from '../composables/useAdminLocale'; import api from '../api'; +import { fetchMediaLibraryImages } from '../utils/media-library'; +import { resolveApiError } from '../i18n/form-validation'; const props = withDefaults( defineProps<{ @@ -27,7 +29,7 @@ const editorRef = ref(null); const mediaPickerVisible = ref(false); /** blob/object URL -> File,保存时由父组件调用 uploadPendingImages 上传 */ const pendingFiles = new Map(); -const mediaFiles = ref>([]); +const mediaFiles = ref>([]); const mediaLoading = ref(false); const syncing = ref(false); let savedRange: Range | null = null; @@ -241,12 +243,10 @@ async function openMediaPicker() { mediaPickerVisible.value = true; mediaLoading.value = true; try { - const res = await api.get('/admin/files', { - params: { category: props.uploadCategory, pageSize: 200 }, - }); - mediaFiles.value = res.data.data.items ?? []; - } catch { + mediaFiles.value = await fetchMediaLibraryImages({ pageSize: 200 }); + } catch (err: unknown) { mediaFiles.value = []; + ElMessage.error(resolveApiError(err, t, 'content.upload.load_media_failed')); } finally { mediaLoading.value = false; } @@ -352,6 +352,7 @@ onBeforeUnmount(() => { width="680px" destroy-on-close append-to-body + :z-index="4000" >
{{ t('common.loading') }}
{{ t('content.upload.no_media') }}
@@ -367,6 +368,7 @@ onBeforeUnmount(() => {
SVG
{{ file.filename }}
+
{{ file.category }}
@@ -521,11 +523,18 @@ onBeforeUnmount(() => { } .media-name { - padding: 6px 8px; + padding: 6px 8px 2px; font-size: 11px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + +.media-category { + padding: 0 8px 6px; + font-size: 10px; + color: var(--text-muted); + opacity: 0.85; +} diff --git a/apps/admin/src/components/LeagueRowActions.vue b/apps/admin/src/components/LeagueRowActions.vue new file mode 100644 index 0000000..40f87f1 --- /dev/null +++ b/apps/admin/src/components/LeagueRowActions.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/apps/admin/src/components/PlayerWalletLedgerDialog.vue b/apps/admin/src/components/PlayerWalletLedgerDialog.vue index 55574ca..6cedd7f 100644 --- a/apps/admin/src/components/PlayerWalletLedgerDialog.vue +++ b/apps/admin/src/components/PlayerWalletLedgerDialog.vue @@ -139,7 +139,7 @@ watch( - + @@ -181,7 +181,7 @@ watch( - + @@ -193,35 +193,35 @@ watch( - + - + - + - + - + - + @@ -298,6 +298,10 @@ watch( diff --git a/apps/admin/src/views/DepositOrders.vue b/apps/admin/src/views/DepositOrders.vue index 2d41b28..e39bd5c 100644 --- a/apps/admin/src/views/DepositOrders.vue +++ b/apps/admin/src/views/DepositOrders.vue @@ -311,8 +311,11 @@ onActivated(() => { {{ row.methodType }} {{ formatAmount(row.amount) }} + + {{ t('media.cleanup_expired_tag') || '已清理' }} + {
{{ t('deposit.screenshot') }}: - +
+ {{ t('media.cleanup_expired_tag') || '已清理' }} +
+
@@ -763,6 +769,37 @@ onActivated(() => { color: #ffffff; } +.expired-screenshot-tag { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 4px 10px; + font-size: 11px; + color: var(--text-muted); + background: var(--accent-hover); + border: 1px dashed var(--border); + border-radius: 6px; + user-select: none; + font-weight: 700; +} + +.expired-screenshot-box { + width: 120px; + height: 120px; + display: inline-flex; + align-items: center; + justify-content: center; + background: var(--accent-hover); + border: 1px dashed var(--border); + border-radius: 6px; + margin-top: 4px; +} +.expired-screenshot-box .expired-text { + font-size: 12px; + color: var(--text-muted); + font-weight: 700; +} + @media (max-width: 700px) { .toolbar, .filters { diff --git a/apps/admin/src/views/Matches.vue b/apps/admin/src/views/Matches.vue index 33fb7d4..7cd1cbd 100644 --- a/apps/admin/src/views/Matches.vue +++ b/apps/admin/src/views/Matches.vue @@ -1,15 +1,15 @@ diff --git a/apps/admin/src/views/MatchesOutrights.vue b/apps/admin/src/views/MatchesOutrights.vue index 243c086..fe5011b 100644 --- a/apps/admin/src/views/MatchesOutrights.vue +++ b/apps/admin/src/views/MatchesOutrights.vue @@ -1,13 +1,12 @@