From ad56b82944abc409dd92f45a84a777fe33327951 Mon Sep 17 00:00:00 2001
From: sexygoat <1538832180@qq.com>
Date: Fri, 29 May 2026 15:44:53 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E4=BB=A3=E7=90=86?=
=?UTF-8?q?=E6=B5=81=E6=B0=B4=E8=B5=84=E4=BA=A7=E6=A0=87=E8=AF=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../proposal.md | 20 +++
.../specs/commission-management/spec.md | 25 +++
.../tasks.md | 13 ++
src/types/api/commission.ts | 1 +
src/types/components.d.ts | 162 ++++++++++++++++++
.../agent-fund-overview/index.vue | 36 +++-
6 files changed, 256 insertions(+), 1 deletion(-)
create mode 100644 openspec/changes/update-agent-fund-main-wallet-asset-link/proposal.md
create mode 100644 openspec/changes/update-agent-fund-main-wallet-asset-link/specs/commission-management/spec.md
create mode 100644 openspec/changes/update-agent-fund-main-wallet-asset-link/tasks.md
diff --git a/openspec/changes/update-agent-fund-main-wallet-asset-link/proposal.md b/openspec/changes/update-agent-fund-main-wallet-asset-link/proposal.md
new file mode 100644
index 0000000..5d07449
--- /dev/null
+++ b/openspec/changes/update-agent-fund-main-wallet-asset-link/proposal.md
@@ -0,0 +1,20 @@
+# Change: Add asset links to main wallet transactions
+
+## Why
+
+The agent fund overview detail drawer shows main wallet transaction records, but users cannot identify or navigate to the related asset for deductions tied to asset activity. The backend now returns `asset_identifier` from `GET /api/admin/shops/{shop_id}/main-wallet/transactions`, so the UI should expose it.
+
+## What Changes
+
+- Add an "资产标识" column to the "预充值钱包流水" table inside the agent fund overview commission detail drawer.
+- Read and type the new `asset_identifier` response field from main wallet transaction rows.
+- Render non-empty asset identifiers as clickable links that navigate to the asset information page for that identifier.
+- Render empty asset identifiers as `-` and do not make them clickable.
+
+## Impact
+
+- Affected specs: `commission-management`
+- Affected code:
+ - `src/types/api/commission.ts`
+ - `src/views/commission-management/agent-fund-overview/index.vue`
+ - Asset information route query handling is reused via `RoutesAlias.AssetInformation` and `identifier` search behavior.
diff --git a/openspec/changes/update-agent-fund-main-wallet-asset-link/specs/commission-management/spec.md b/openspec/changes/update-agent-fund-main-wallet-asset-link/specs/commission-management/spec.md
new file mode 100644
index 0000000..2e2dbdf
--- /dev/null
+++ b/openspec/changes/update-agent-fund-main-wallet-asset-link/specs/commission-management/spec.md
@@ -0,0 +1,25 @@
+## ADDED Requirements
+
+### Requirement: Main Wallet Transaction Asset Identifier Link
+
+The agent fund overview commission detail drawer SHALL display the `asset_identifier` returned by `GET /api/admin/shops/{shop_id}/main-wallet/transactions` in the "预充值钱包流水" table as "资产标识" and allow users to navigate from that value to the asset information page.
+
+#### Scenario: Display asset identifier in main wallet transactions
+
+- **WHEN** a user opens an agent's commission detail drawer
+- **AND** selects the "预充值钱包流水" tab
+- **AND** a transaction row contains a non-empty `asset_identifier`
+- **THEN** the table displays that value in a column labeled "资产标识"
+- **AND** the value is visually presented as a clickable link
+
+#### Scenario: Navigate to asset information from asset identifier
+
+- **WHEN** a user clicks a non-empty "资产标识" value in the "预充值钱包流水" table
+- **THEN** the system navigates to the asset information page
+- **AND** the asset information page searches or loads using the clicked asset identifier
+
+#### Scenario: Empty asset identifier is not clickable
+
+- **WHEN** a main wallet transaction row has no `asset_identifier`
+- **THEN** the "资产标识" column displays `-`
+- **AND** no navigation action is available for that cell
diff --git a/openspec/changes/update-agent-fund-main-wallet-asset-link/tasks.md b/openspec/changes/update-agent-fund-main-wallet-asset-link/tasks.md
new file mode 100644
index 0000000..8f2945c
--- /dev/null
+++ b/openspec/changes/update-agent-fund-main-wallet-asset-link/tasks.md
@@ -0,0 +1,13 @@
+## 1. Implementation
+
+- [x] 1.1 Add optional `asset_identifier` to `MainWalletTransactionItem`.
+- [x] 1.2 Add an "资产标识" column to the agent fund overview detail drawer's "预充值钱包流水" table.
+- [x] 1.3 Render `asset_identifier` as a clickable link when present and `-` when absent.
+- [x] 1.4 Navigate clicks to the asset information page using the clicked asset identifier as the search query.
+- [x] 1.5 Ensure the click does not trigger unrelated row/table interactions.
+
+## 2. Verification
+
+- [x] 2.1 Verify the changed Vue file with lint or equivalent available project checks.
+- [ ] 2.2 Manually verify rows with `asset_identifier` display and navigate correctly.
+- [ ] 2.3 Manually verify rows without `asset_identifier` display `-` and are not clickable.
diff --git a/src/types/api/commission.ts b/src/types/api/commission.ts
index 4fa8ef7..a66db87 100644
--- a/src/types/api/commission.ts
+++ b/src/types/api/commission.ts
@@ -298,6 +298,7 @@ export interface MainWalletTransactionItem {
amount: number // 交易金额(分,正数为入账,负数为扣款)
balance_before: number // 交易前余额(分)
balance_after: number // 交易后余额(分)
+ asset_identifier?: string // 资产标识(ICCID或设备号)
remark: string // 备注
created_at: string // 交易时间
}
diff --git a/src/types/components.d.ts b/src/types/components.d.ts
index e69de29..e4f441c 100644
--- a/src/types/components.d.ts
+++ b/src/types/components.d.ts
@@ -0,0 +1,162 @@
+/* eslint-disable */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+export {}
+
+/* prettier-ignore */
+declare module 'vue' {
+ export interface GlobalComponents {
+ AgentSelector: typeof import('./../components/business/AgentSelector.vue')['default']
+ ArtBackToTop: typeof import('./../components/core/base/ArtBackToTop.vue')['default']
+ ArtBarChart: typeof import('./../components/core/charts/ArtBarChart.vue')['default']
+ ArtBarChartCard: typeof import('./../components/core/cards/ArtBarChartCard.vue')['default']
+ ArtBasicBanner: typeof import('./../components/core/banners/ArtBasicBanner.vue')['default']
+ ArtBreadcrumb: typeof import('./../components/core/layouts/art-breadcrumb/index.vue')['default']
+ ArtButtonMore: typeof import('./../components/core/forms/ArtButtonMore.vue')['default']
+ ArtButtonTable: typeof import('./../components/core/forms/ArtButtonTable.vue')['default']
+ ArtCardBanner: typeof import('./../components/core/banners/ArtCardBanner.vue')['default']
+ ArtChatWindow: typeof import('./../components/core/layouts/art-chat-window/index.vue')['default']
+ ArtCutterImg: typeof import('./../components/core/media/ArtCutterImg.vue')['default']
+ ArtDataListCard: typeof import('./../components/core/cards/ArtDataListCard.vue')['default']
+ ArtDataViewer: typeof import('./../components/core/views/ArtDataViewer.vue')['default']
+ ArtDonutChartCard: typeof import('./../components/core/cards/ArtDonutChartCard.vue')['default']
+ ArtDragVerify: typeof import('./../components/core/forms/ArtDragVerify.vue')['default']
+ ArtDualBarCompareChart: typeof import('./../components/core/charts/ArtDualBarCompareChart.vue')['default']
+ ArtExcelExport: typeof import('./../components/core/forms/ArtExcelExport.vue')['default']
+ ArtExcelImport: typeof import('./../components/core/forms/ArtExcelImport.vue')['default']
+ ArtException: typeof import('./../components/core/views/exception/ArtException.vue')['default']
+ ArtFastEnter: typeof import('./../components/core/layouts/art-fast-enter/index.vue')['default']
+ ArtFestivalTextScroll: typeof import('./../components/core/text-effect/ArtFestivalTextScroll.vue')['default']
+ ArtFireworksEffect: typeof import('./../components/core/layouts/art-fireworks-effect/index.vue')['default']
+ ArtGlobalSearch: typeof import('./../components/core/layouts/art-global-search/index.vue')['default']
+ ArtHBarChart: typeof import('./../components/core/charts/ArtHBarChart.vue')['default']
+ ArtHeaderBar: typeof import('./../components/core/layouts/art-header-bar/index.vue')['default']
+ ArtHorizontalMenu: typeof import('./../components/core/layouts/art-menus/art-horizontal-menu/index.vue')['default']
+ ArtIconSelector: typeof import('./../components/core/base/ArtIconSelector.vue')['default']
+ ArtImageCard: typeof import('./../components/core/cards/ArtImageCard.vue')['default']
+ ArtKLineChart: typeof import('./../components/core/charts/ArtKLineChart.vue')['default']
+ ArtLayouts: typeof import('./../components/core/layouts/art-layouts/index.vue')['default']
+ ArtLineChart: typeof import('./../components/core/charts/ArtLineChart.vue')['default']
+ ArtLineChartCard: typeof import('./../components/core/cards/ArtLineChartCard.vue')['default']
+ ArtLogo: typeof import('./../components/core/base/ArtLogo.vue')['default']
+ ArtMapChart: typeof import('./../components/core/charts/ArtMapChart.vue')['default']
+ ArtMenuRight: typeof import('./../components/core/others/ArtMenuRight.vue')['default']
+ ArtMixedMenu: typeof import('./../components/core/layouts/art-menus/art-mixed-menu/index.vue')['default']
+ ArtNotification: typeof import('./../components/core/layouts/art-notification/index.vue')['default']
+ ArtPageContent: typeof import('./../components/core/layouts/art-page-content/index.vue')['default']
+ ArtProgressCard: typeof import('./../components/core/cards/ArtProgressCard.vue')['default']
+ ArtRadarChart: typeof import('./../components/core/charts/ArtRadarChart.vue')['default']
+ ArtResultPage: typeof import('./../components/core/views/result/ArtResultPage.vue')['default']
+ ArtRingChart: typeof import('./../components/core/charts/ArtRingChart.vue')['default']
+ ArtScatterChart: typeof import('./../components/core/charts/ArtScatterChart.vue')['default']
+ ArtScreenLock: typeof import('./../components/core/layouts/art-screen-lock/index.vue')['default']
+ ArtSearchBar: typeof import('./../components/core/forms/art-search-bar/index.vue')['default']
+ ArtSearchDate: typeof import('./../components/core/forms/art-search-bar/widget/art-search-date/index.vue')['default']
+ ArtSearchInput: typeof import('./../components/core/forms/art-search-bar/widget/art-search-input/index.vue')['default']
+ ArtSearchRadio: typeof import('./../components/core/forms/art-search-bar/widget/art-search-radio/index.vue')['default']
+ ArtSearchSelect: typeof import('./../components/core/forms/art-search-bar/widget/art-search-select/index.vue')['default']
+ ArtSearchTreeSelect: typeof import('./../components/core/forms/art-search-bar/widget/art-search-tree-select/index.vue')['default']
+ ArtSettingsPanel: typeof import('./../components/core/layouts/art-settings-panel/index.vue')['default']
+ ArtSidebarMenu: typeof import('./../components/core/layouts/art-menus/art-sidebar-menu/index.vue')['default']
+ ArtStatsCard: typeof import('./../components/core/cards/ArtStatsCard.vue')['default']
+ ArtTable: typeof import('./../components/core/tables/ArtTable.vue')['default']
+ ArtTableFullScreen: typeof import('./../components/core/tables/ArtTableFullScreen.vue')['default']
+ ArtTableHeader: typeof import('./../components/core/tables/ArtTableHeader.vue')['default']
+ ArtTextScroll: typeof import('./../components/core/text-effect/ArtTextScroll.vue')['default']
+ ArtTimelineListCard: typeof import('./../components/core/cards/ArtTimelineListCard.vue')['default']
+ ArtVideoPlayer: typeof import('./../components/core/media/ArtVideoPlayer.vue')['default']
+ ArtWangEditor: typeof import('./../components/core/forms/ArtWangEditor.vue')['default']
+ ArtWatermark: typeof import('./../components/core/others/ArtWatermark.vue')['default']
+ ArtWorkTab: typeof import('./../components/core/layouts/art-work-tab/index.vue')['default']
+ BasicSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/BasicSettings.vue')['default']
+ BatchOperationDialog: typeof import('./../components/business/BatchOperationDialog.vue')['default']
+ BoxStyleSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/BoxStyleSettings.vue')['default']
+ CardOperationDialog: typeof import('./../components/business/CardOperationDialog.vue')['default']
+ CardStatusTag: typeof import('./../components/business/CardStatusTag.vue')['default']
+ ChunkErrorBoundary: typeof import('./../components/core/others/ChunkErrorBoundary.vue')['default']
+ CodeGeneratorButton: typeof import('./../components/business/CodeGeneratorButton.vue')['default']
+ ColorSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ColorSettings.vue')['default']
+ CommentItem: typeof import('./../components/custom/comment-widget/widget/CommentItem.vue')['default']
+ CommentWidget: typeof import('./../components/custom/comment-widget/index.vue')['default']
+ CommissionDisplay: typeof import('./../components/business/CommissionDisplay.vue')['default']
+ ContainerSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ContainerSettings.vue')['default']
+ CreateRefundDialog: typeof import('./../components/business/CreateRefundDialog.vue')['default']
+ CustomerAccountDialog: typeof import('./../components/business/CustomerAccountDialog.vue')['default']
+ DetailPage: typeof import('./../components/common/DetailPage.vue')['default']
+ ElAlert: typeof import('element-plus/es')['ElAlert']
+ ElAvatar: typeof import('element-plus/es')['ElAvatar']
+ ElButton: typeof import('element-plus/es')['ElButton']
+ ElCalendar: typeof import('element-plus/es')['ElCalendar']
+ ElCard: typeof import('element-plus/es')['ElCard']
+ ElCascader: typeof import('element-plus/es')['ElCascader']
+ ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
+ ElCol: typeof import('element-plus/es')['ElCol']
+ ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
+ ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+ ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
+ ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
+ ElDialog: typeof import('element-plus/es')['ElDialog']
+ ElDivider: typeof import('element-plus/es')['ElDivider']
+ ElDrawer: typeof import('element-plus/es')['ElDrawer']
+ ElDropdown: typeof import('element-plus/es')['ElDropdown']
+ ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
+ ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
+ ElEmpty: typeof import('element-plus/es')['ElEmpty']
+ ElForm: typeof import('element-plus/es')['ElForm']
+ ElFormItem: typeof import('element-plus/es')['ElFormItem']
+ ElIcon: typeof import('element-plus/es')['ElIcon']
+ ElInput: typeof import('element-plus/es')['ElInput']
+ ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
+ ElMenu: typeof import('element-plus/es')['ElMenu']
+ ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+ ElOption: typeof import('element-plus/es')['ElOption']
+ ElPagination: typeof import('element-plus/es')['ElPagination']
+ ElPopover: typeof import('element-plus/es')['ElPopover']
+ ElProgress: typeof import('element-plus/es')['ElProgress']
+ ElRadio: typeof import('element-plus/es')['ElRadio']
+ ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
+ ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
+ ElRow: typeof import('element-plus/es')['ElRow']
+ ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
+ ElSelect: typeof import('element-plus/es')['ElSelect']
+ ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
+ ElSwitch: typeof import('element-plus/es')['ElSwitch']
+ ElTable: typeof import('element-plus/es')['ElTable']
+ ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+ ElTabPane: typeof import('element-plus/es')['ElTabPane']
+ ElTabs: typeof import('element-plus/es')['ElTabs']
+ ElTag: typeof import('element-plus/es')['ElTag']
+ ElTimeline: typeof import('element-plus/es')['ElTimeline']
+ ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
+ ElTooltip: typeof import('element-plus/es')['ElTooltip']
+ ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
+ ElUpload: typeof import('element-plus/es')['ElUpload']
+ ElWatermark: typeof import('element-plus/es')['ElWatermark']
+ HorizontalSubmenu: typeof import('./../components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue')['default']
+ ImportDialog: typeof import('./../components/business/ImportDialog.vue')['default']
+ LoginLeftView: typeof import('./../components/core/views/login/LoginLeftView.vue')['default']
+ MenuLayoutSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/MenuLayoutSettings.vue')['default']
+ MenuStyleSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/MenuStyleSettings.vue')['default']
+ OperationLogsDialog: typeof import('./../components/business/OperationLogsDialog.vue')['default']
+ OperatorSelect: typeof import('./../components/business/OperatorSelect.vue')['default']
+ PackageSelector: typeof import('./../components/business/PackageSelector.vue')['default']
+ PaymentVoucherDialog: typeof import('./../components/business/PaymentVoucherDialog.vue')['default']
+ RealnamePolicyDialog: typeof import('./../components/device/RealnamePolicyDialog.vue')['default']
+ RouterLink: typeof import('vue-router')['RouterLink']
+ RouterView: typeof import('vue-router')['RouterView']
+ SectionTitle: typeof import('./../components/core/layouts/art-settings-panel/widget/SectionTitle.vue')['default']
+ SettingDrawer: typeof import('./../components/core/layouts/art-settings-panel/widget/SettingDrawer.vue')['default']
+ SettingHeader: typeof import('./../components/core/layouts/art-settings-panel/widget/SettingHeader.vue')['default']
+ SettingItem: typeof import('./../components/core/layouts/art-settings-panel/widget/SettingItem.vue')['default']
+ SidebarSubmenu: typeof import('./../components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue')['default']
+ SpeedLimitDialog: typeof import('./../components/device/SpeedLimitDialog.vue')['default']
+ SwitchCardDialog: typeof import('./../components/device/SwitchCardDialog.vue')['default']
+ TableContextMenuHint: typeof import('./../components/core/others/TableContextMenuHint.vue')['default']
+ ThemeSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ThemeSettings.vue')['default']
+ UpdateRealnameStatusDialog: typeof import('./../components/business/UpdateRealnameStatusDialog.vue')['default']
+ }
+ export interface ComponentCustomProperties {
+ vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+ }
+}
diff --git a/src/views/commission-management/agent-fund-overview/index.vue b/src/views/commission-management/agent-fund-overview/index.vue
index 918a7e5..8c52913 100644
--- a/src/views/commission-management/agent-fund-overview/index.vue
+++ b/src/views/commission-management/agent-fund-overview/index.vue
@@ -291,6 +291,23 @@
{{ formatMoney(scope.row.balance_after) }}
+
+
+
+ {{ scope.row.asset_identifier }}
+
+ -
+
+
@@ -363,7 +380,7 @@