From 06daa0e336e91b8ae46d64cd8bab79a26e5bc79f Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 16:09:00 +0800
Subject: [PATCH 01/33] feat(navbar): ensure nav-bar width and box-sizing are
set correctly
---
src/components/NavBar.vue | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue
index 8df3d4c..bf3519d 100644
--- a/src/components/NavBar.vue
+++ b/src/components/NavBar.vue
@@ -93,6 +93,8 @@ const authStore = useAuthStore()
}
.nav-bar {
+ width: 100%;
+ box-sizing: border-box;
background-color: transparent;
}
From a1862f2f04f434d7ca9e44318b02bd568d010d42 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 16:34:29 +0800
Subject: [PATCH 02/33] feat(layout): restructure AppLayout component with
NavBar and SiderBar integration
---
src/layouts/AppLayout.vue | 42 +++++++++++++++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/src/layouts/AppLayout.vue b/src/layouts/AppLayout.vue
index eeeb97d..28417a0 100644
--- a/src/layouts/AppLayout.vue
+++ b/src/layouts/AppLayout.vue
@@ -1,4 +1,42 @@
- applayout
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From b2843957852357659713aa13d61bf073ce4aef34 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 16:34:55 +0800
Subject: [PATCH 03/33] feat(SiderBar): add SiderBar component with dynamic
menu items and route-based selection
---
src/components/SiderBar.vue | 61 +++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100644 src/components/SiderBar.vue
diff --git a/src/components/SiderBar.vue b/src/components/SiderBar.vue
new file mode 100644
index 0000000..87febd8
--- /dev/null
+++ b/src/components/SiderBar.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
From b7c3658488ef09c80f5d08482864b82a62fa51f7 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 16:38:29 +0800
Subject: [PATCH 04/33] feat(i18n): add menu translations for dashboard,
account, records, and send in English, Simplified Chinese, and Traditional
Chinese
---
src/i18n/locales/en-US.json | 6 ++++++
src/i18n/locales/zh-CN.json | 6 ++++++
src/i18n/locales/zh-TW.json | 6 ++++++
3 files changed, 18 insertions(+)
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 9616bfe..b97125b 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -243,5 +243,11 @@
"failedVerify": "Failed to verify.",
"success": "Login success"
}
+ },
+ "menu": {
+ "dashboard": "Dashboard",
+ "account": "Account",
+ "records": "Records",
+ "send": "Send"
}
}
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index 91f2c94..a176693 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -241,5 +241,11 @@
"failedVerify": "验证失败。",
"success": "登录成功"
}
+ },
+ "menu": {
+ "dashboard": "仪表板",
+ "account": "帐户",
+ "records": "交易记录",
+ "send": "发起交易"
}
}
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index 9feb361..db88544 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -241,5 +241,11 @@
"failedVerify": "驗證失敗。",
"success": "登入成功"
}
+ },
+ "menu": {
+ "dashboard": "儀表板",
+ "account": "帳戶",
+ "records": "交易記錄",
+ "send": "發起交易"
}
}
From 40fe7e9b8ced3d98eb36152b6479c6a27d032781 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 16:38:37 +0800
Subject: [PATCH 05/33] fix(NavBar): correct size binding for user avatar
component
---
src/components/NavBar.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue
index bf3519d..8e5d4c8 100644
--- a/src/components/NavBar.vue
+++ b/src/components/NavBar.vue
@@ -29,7 +29,7 @@
:max-height="400"
direction="left"
>
-
+
From 17c8689e77997da780514080d6e5d70f5e3dbc5a Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 16:43:35 +0800
Subject: [PATCH 06/33] fix(SiderBar): correct binding for selected menu item
and fix variable name typo
---
src/components/SiderBar.vue | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/components/SiderBar.vue b/src/components/SiderBar.vue
index 87febd8..076c74a 100644
--- a/src/components/SiderBar.vue
+++ b/src/components/SiderBar.vue
@@ -1,7 +1,7 @@
-
-
+
+
@@ -20,28 +20,32 @@ const { t } = useLocale()
const route = useRoute()
-const slectedValue = ref('dashboard')
+const selectedValue = ref('dashboard')
const menuItems = computed(() => [
{
value: 'dashboard',
label: t('menu.dashboard'),
icon: 'dashboard',
+ path: '/dashboard',
},
{
value: 'send',
label: t('menu.send'),
icon: 'send',
+ path: '/send',
},
{
value: 'records',
label: t('menu.records'),
icon: 'tree-list',
+ path: '/records',
},
{
value: 'account',
label: t('menu.account'),
icon: 'user',
+ path: '/account',
},
])
@@ -49,9 +53,9 @@ const menuItems = computed(() => [
watch(
() => route.path,
(newPath) => {
- const menuItem = newPath.split('/')[1] // 获取路径的第一个部分作为菜单项的值
- if (menuItem) {
- slectedValue.value = menuItem
+ const selectedItem = menuItems.value.find((item) => newPath.startsWith(item.path))
+ if (selectedItem) {
+ selectedValue.value = selectedItem.value
}
},
{ immediate: true },
From 80aff7e1b5e3cbe410d017e49611810fab41a751 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 16:47:53 +0800
Subject: [PATCH 07/33] feat(router): add account route with title translation
---
src/router/index.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/router/index.js b/src/router/index.js
index d68fd4d..6207b5b 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -36,6 +36,11 @@ const routes = computed(() => [
meta: { title: t('dashboard.title') },
component: () => import('@/views/DashboardView.vue'),
},
+ {
+ path: 'account',
+ meta: { title: t('account.title') },
+ component: () => import('@/views/AccountView.vue'),
+ }
],
},
])
From 82614c86af7f0ce8c24c5c22a5d2de601284b78a Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 17:52:20 +0800
Subject: [PATCH 08/33] feat(layout): enhance AppLayout structure with class
bindings for better styling
---
src/layouts/AppLayout.vue | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/src/layouts/AppLayout.vue b/src/layouts/AppLayout.vue
index 28417a0..99a40ba 100644
--- a/src/layouts/AppLayout.vue
+++ b/src/layouts/AppLayout.vue
@@ -1,10 +1,10 @@
-
+
-
+
-
+
@@ -23,14 +23,32 @@ import SiderBar from '@/components/SiderBar.vue'
From 54bc47062cba18c2f82e3fb4bf07b6ac86817194 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 17:57:11 +0800
Subject: [PATCH 10/33] feat(i18n): add account localization strings for en-US,
zh-CN, and zh-TW
---
src/i18n/locales/en-US.json | 22 ++++++++++++++++++++++
src/i18n/locales/zh-CN.json | 22 ++++++++++++++++++++++
src/i18n/locales/zh-TW.json | 22 ++++++++++++++++++++++
3 files changed, 66 insertions(+)
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index b97125b..164b6b5 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -2,6 +2,28 @@
"dashboard": {
"title": "Dashboard"
},
+ "account": {
+ "title": "Account",
+ "subtitle": "View your account and organization profile",
+ "profileCardTitle": "Profile",
+ "organizationCardTitle": "Organization",
+ "actions": {
+ "copy": "Copy"
+ },
+ "msg": {
+ "copySuccess": "{label} copied",
+ "copyFailed": "Copy failed"
+ },
+ "fields": {
+ "displayName": "Display Name",
+ "role": "Role",
+ "accountId": "Account ID",
+ "organizationCode": "Organization Code",
+ "organizationId": "Organization ID",
+ "organizationName": "Organization Name",
+ "walletAddress": "Wallet Address"
+ }
+ },
"footer": {
"product": "Product",
"home": "Home",
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index a176693..8898353 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -2,6 +2,28 @@
"dashboard": {
"title": "仪表板"
},
+ "account": {
+ "title": "账户中心",
+ "subtitle": "查看当前账户与所属机构信息",
+ "profileCardTitle": "账户资料",
+ "organizationCardTitle": "机构信息",
+ "actions": {
+ "copy": "复制"
+ },
+ "msg": {
+ "copySuccess": "{label} 已复制",
+ "copyFailed": "复制失败"
+ },
+ "fields": {
+ "displayName": "显示名称",
+ "role": "角色",
+ "accountId": "账户 ID",
+ "organizationCode": "机构代码",
+ "organizationId": "机构 ID",
+ "organizationName": "机构名称",
+ "walletAddress": "钱包地址"
+ }
+ },
"footer": {
"product": "产品",
"home": "首页",
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index db88544..64fa4e0 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -2,6 +2,28 @@
"dashboard": {
"title": "儀表板"
},
+ "account": {
+ "title": "帳戶中心",
+ "subtitle": "檢視目前帳戶與所屬機構資訊",
+ "profileCardTitle": "帳戶資料",
+ "organizationCardTitle": "機構資訊",
+ "actions": {
+ "copy": "複製"
+ },
+ "msg": {
+ "copySuccess": "{label} 已複製",
+ "copyFailed": "複製失敗"
+ },
+ "fields": {
+ "displayName": "顯示名稱",
+ "role": "角色",
+ "accountId": "帳戶 ID",
+ "organizationCode": "機構代碼",
+ "organizationId": "機構 ID",
+ "organizationName": "機構名稱",
+ "walletAddress": "錢包地址"
+ }
+ },
"footer": {
"product": "產品",
"home": "首頁",
From 312ec1b74f44cf91d5fda44bcfdbf658219243e6 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 17:57:15 +0800
Subject: [PATCH 11/33] fix(footer): add margin-top to footer for improved
spacing
---
src/layouts/AppLayout.vue | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/layouts/AppLayout.vue b/src/layouts/AppLayout.vue
index 99a40ba..78a1d9e 100644
--- a/src/layouts/AppLayout.vue
+++ b/src/layouts/AppLayout.vue
@@ -56,5 +56,6 @@ import SiderBar from '@/components/SiderBar.vue'
padding: 1rem;
font: var(--td-font-body-small);
color: var(--td-text-color-placeholder);
+ margin-top: 2rem;
}
From 7595c17b7182c0ad040f99cfd2045dbe24806bfd Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 17:58:18 +0800
Subject: [PATCH 12/33] feat(account): update header font size in AccountView
for better visibility
---
src/views/AccountView.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/views/AccountView.vue b/src/views/AccountView.vue
index e6268fa..a022d9c 100644
--- a/src/views/AccountView.vue
+++ b/src/views/AccountView.vue
@@ -195,7 +195,7 @@ async function copyField(value, label) {
.account-page__header h1 {
margin: 0;
- font: var(--td-font-headline-medium);
+ font: var(--td-font-headline-large);
color: var(--td-text-color-primary);
}
From 6f0fe0288307bbdfd992ee67cd9dd0a22a713454 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sat, 22 Aug 2026 18:39:33 +0800
Subject: [PATCH 13/33] feat(dashboard): add forecast section with real-time
data and localization
---
src/i18n/locales/en-US.json | 24 ++-
src/i18n/locales/zh-CN.json | 24 ++-
src/i18n/locales/zh-TW.json | 24 ++-
src/utils/i18n.js | 4 +-
src/views/DashboardView.vue | 347 +++++++++++++++++++++++++++++++++++-
5 files changed, 416 insertions(+), 7 deletions(-)
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 164b6b5..df17d33 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -1,6 +1,28 @@
{
"dashboard": {
- "title": "Dashboard"
+ "title": "Dashboard",
+ "subtitle": "Real-time monitoring of the settlement window and target block",
+ "forecast": {
+ "title": "Settlement Window Forecast",
+ "desc": "Data is read via an on-chain read-only call. No transaction is sent and no gas is consumed.",
+ "refresh": "Refresh",
+ "active": "Active",
+ "windowId": "Pending Window ID",
+ "settlementBlock": "Target Settlement Block",
+ "blocksRemaining": "Blocks Remaining",
+ "blocksUnit": "blocks",
+ "reached": "Target block reached",
+ "lastUpdated": {
+ "label": "Last updated at {time}",
+ "justNow": "just now",
+ "minutesAgo": "{minutes} minutes ago",
+ "hoursAgo": "{hours} hours ago",
+ "daysAgo": "{days} days ago"
+ },
+ "msg": {
+ "fetchFailed": "Failed to fetch settlement window forecast"
+ }
+ }
},
"account": {
"title": "Account",
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index 8898353..50db1f5 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -1,6 +1,28 @@
{
"dashboard": {
- "title": "仪表板"
+ "title": "仪表板",
+ "subtitle": "实时监控净额结算窗口与目标结算区块",
+ "forecast": {
+ "title": "结算窗口预测",
+ "desc": "数据来自链上合约的只读调用,不发送交易,不消耗 Gas",
+ "refresh": "刷新",
+ "active": "活跃中",
+ "windowId": "待结算窗口 ID",
+ "settlementBlock": "目标结算区块",
+ "blocksRemaining": "剩余区块数",
+ "blocksUnit": "个区块",
+ "reached": "已到达目标区块",
+ "lastUpdated": {
+ "label": "最后更新于 {time}",
+ "justNow": "刚刚",
+ "minutesAgo": "{minutes} 分钟前",
+ "hoursAgo": "{hours} 小时前",
+ "daysAgo": "{days} 天前"
+ },
+ "msg": {
+ "fetchFailed": "获取结算窗口预测失败"
+ }
+ }
},
"account": {
"title": "账户中心",
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index 64fa4e0..4d9ffdc 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -1,6 +1,28 @@
{
"dashboard": {
- "title": "儀表板"
+ "title": "儀表板",
+ "subtitle": "即時監控淨額結算窗口與目標結算區塊",
+ "forecast": {
+ "title": "結算窗口預測",
+ "desc": "數據來自鏈上合約的只讀調用,不發送交易,不消耗 Gas",
+ "refresh": "刷新",
+ "active": "活躍中",
+ "windowId": "待結算窗口 ID",
+ "settlementBlock": "目標結算區塊",
+ "blocksRemaining": "剩餘區塊數",
+ "blocksUnit": "個區塊",
+ "reached": "已到達目標區塊",
+ "lastUpdated": {
+ "label": "最後更新於 {time}",
+ "justNow": "剛剛",
+ "minutesAgo": "{minutes} 分鐘前",
+ "hoursAgo": "{hours} 小時前",
+ "daysAgo": "{days} 天前"
+ },
+ "msg": {
+ "fetchFailed": "獲取結算窗口預測失敗"
+ }
+ }
},
"account": {
"title": "帳戶中心",
diff --git a/src/utils/i18n.js b/src/utils/i18n.js
index 0f17ce5..eb6180e 100644
--- a/src/utils/i18n.js
+++ b/src/utils/i18n.js
@@ -20,9 +20,7 @@ export const useLocale = () => {
}
// 国际化翻译函数
- const t = (key) => {
- return i18n.t(key)
- }
+ const t = (...args) => i18n.t(...args)
// 当前tdesign语言配置
const tdesignLang = computed(() => {
diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue
index 1580f1c..4077bd5 100644
--- a/src/views/DashboardView.vue
+++ b/src/views/DashboardView.vue
@@ -1 +1,346 @@
-dashboard
+
+
+
+
+
+
+
+
+
{{ t('dashboard.forecast.title') }}
+
+
+
+
+
+
+
+
+
{{ t('dashboard.forecast.desc') }}
+
+
+
+
+
+
+
+ {{ t('dashboard.forecast.active') }}
+
+
+
+
+
+
+ {{ t('dashboard.forecast.windowId') }}
+
+ {{ forecast.windowId ?? '-' }}
+
+
+
+ {{ t('dashboard.forecast.settlementBlock') }}
+
+ {{ forecast.settlementBlock ?? '-' }}
+
+
+
+ {{ t('dashboard.forecast.blocksRemaining') }}
+
+
+
+ {{ t('dashboard.forecast.reached') }}
+
+
+ {{ forecast.blocksRemaining ?? '-' }}
+ {{
+ t('dashboard.forecast.blocksUnit')
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 9365f17187db9c59fc8e7773ae5d7394fca5c07b Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 00:28:54 +0800
Subject: [PATCH 14/33] feat(SiderBar): update menu item from 'records' to
'transactions' for consistency
---
src/components/SiderBar.vue | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/SiderBar.vue b/src/components/SiderBar.vue
index 076c74a..6e4837a 100644
--- a/src/components/SiderBar.vue
+++ b/src/components/SiderBar.vue
@@ -36,10 +36,10 @@ const menuItems = computed(() => [
path: '/send',
},
{
- value: 'records',
- label: t('menu.records'),
+ value: 'transactions',
+ label: t('menu.transactions'),
icon: 'tree-list',
- path: '/records',
+ path: '/transactions',
},
{
value: 'account',
From aafad632ac563ec5a69067f38b839d6b1e63aab7 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 01:15:57 +0800
Subject: [PATCH 15/33] feat(SendView): add send transaction form with visual
representation
---
src/components/TradeVisual.vue | 143 +++++++++++
src/views/SendView.vue | 441 +++++++++++++++++++++++++++++++++
2 files changed, 584 insertions(+)
create mode 100644 src/components/TradeVisual.vue
create mode 100644 src/views/SendView.vue
diff --git a/src/components/TradeVisual.vue b/src/components/TradeVisual.vue
new file mode 100644
index 0000000..60906a4
--- /dev/null
+++ b/src/components/TradeVisual.vue
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
{{ fromName }}
+
{{ fromRole }}
+
+
+
+
+ {{ sendLabel }}
+ {{ formatAmount(sendAmount) }} {{ sendAsset }}
+
+
+
+ {{ receiveLabel }}
+ {{ formatAmount(receiveAmount) }} {{ receiveAsset }}
+
+
+
+
+
+
+
+
{{ toName || toPlaceholder }}
+
{{ toRole }}
+
+
+
+
+
+
+
diff --git a/src/views/SendView.vue b/src/views/SendView.vue
new file mode 100644
index 0000000..baee1bc
--- /dev/null
+++ b/src/views/SendView.vue
@@ -0,0 +1,441 @@
+
+
+
+
+
+
+
+
+
+
+
{{ t('send.visual.title') }}
+
{{ t('send.visual.desc') }}
+
+
+
+
+
+
+
+
+
+
{{ t('send.success.desc') }}
+
+ {{ t('send.success.transactionId') }}: #{{ lastTransaction.id }}
+
+
+
+ {{ t('send.success.again') }}
+
+
+ {{ t('send.success.viewDetail') }}
+
+
+
+
+
+
+
+
+
{{ failureReason }}
+
+
+ {{ t('send.failure.close') }}
+
+
+ {{ t('send.failure.retry') }}
+
+
+
+
+
+
+
+
+
+
From b4c84769af749008a1543012d2be726be9d9b197 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 01:16:35 +0800
Subject: [PATCH 16/33] feat(assets): add asset meta data
---
src/utils/assets.js | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 src/utils/assets.js
diff --git a/src/utils/assets.js b/src/utils/assets.js
new file mode 100644
index 0000000..93c6bd5
--- /dev/null
+++ b/src/utils/assets.js
@@ -0,0 +1,20 @@
+// 可交易资产的元数据映射(名称、最小单位小数位等)
+export const ASSETS = {
+ USDC: { code: 'USDC', name: 'USDC', decimals: 6 },
+ BOUND: { code: 'BOUND', name: 'BOUND', decimals: 0 },
+}
+
+export const ASSET_OPTIONS = Object.values(ASSETS).map((asset) => ({
+ label: asset.name,
+ value: asset.code,
+}))
+
+export function getAssetDecimals(code) {
+ return ASSETS[code]?.decimals ?? 0
+}
+
+// 将人类可读数量转换为对应 ERC-20 代币的最小单位整数
+export function toBaseUnits(amount, code) {
+ const decimals = getAssetDecimals(code)
+ return Math.round(Number(amount) * 10 ** decimals)
+}
From e31913383b07b1430bfc309b39e5058600856c75 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 01:16:50 +0800
Subject: [PATCH 17/33] feat(i18n): add asset and transaction related
localization for net positions and liquidity shortfalls
---
src/i18n/locales/en-US.json | 86 ++++++++++++++++++++++++++++++++++++-
src/i18n/locales/zh-CN.json | 86 ++++++++++++++++++++++++++++++++++++-
src/i18n/locales/zh-TW.json | 86 ++++++++++++++++++++++++++++++++++++-
3 files changed, 255 insertions(+), 3 deletions(-)
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index df17d33..0fb0429 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -22,6 +22,37 @@
"msg": {
"fetchFailed": "Failed to fetch settlement window forecast"
}
+ },
+ "asset": "Asset Address",
+ "netPositions": {
+ "title": "Net Settlement Positions",
+ "desc": "Payable/receivable amounts per asset for the current bank",
+ "payable": "Payable Amount",
+ "receivable": "Receivable Amount",
+ "empty": "No net settlement positions",
+ "msg": {
+ "fetchFailed": "Failed to fetch net settlement positions"
+ }
+ },
+ "assetRequirements": {
+ "title": "Settlement Asset Requirements",
+ "desc": "Assets that must be prepared ahead of this settlement round",
+ "required": "Required Amount",
+ "empty": "No settlement assets required",
+ "msg": {
+ "fetchFailed": "Failed to fetch settlement asset requirements"
+ }
+ },
+ "liquidityShortfalls": {
+ "title": "Liquidity Shortfalls",
+ "desc": "Required amount, current balance and estimated borrow amount",
+ "required": "Required Amount",
+ "available": "Available Balance",
+ "borrow": "Estimated Borrow Amount",
+ "empty": "No liquidity shortfalls",
+ "msg": {
+ "fetchFailed": "Failed to fetch liquidity shortfalls"
+ }
}
},
"account": {
@@ -292,6 +323,59 @@
"dashboard": "Dashboard",
"account": "Account",
"records": "Records",
- "send": "Send"
+ "send": "Send",
+ "transactions": "Transactions"
+ },
+ "send": {
+ "title": "Send Transaction",
+ "subtitle": "Choose a counterparty and assets to submit a netting settlement transaction",
+ "form": {
+ "title": "Transaction Details",
+ "desc": "The transaction will enter the next settlement window once submitted",
+ "counterparty": "Counterparty",
+ "counterpartyPlaceholder": "Search and select an organization",
+ "counterpartyEmpty": "No tradable organizations available",
+ "youSend": "You Send",
+ "youReceive": "You Receive",
+ "asset": "Asset",
+ "amount": "Amount",
+ "amountPlaceholder": "Enter an amount",
+ "submit": "Submit Transaction",
+ "reset": "Reset"
+ },
+ "visual": {
+ "title": "Transaction Preview",
+ "desc": "See the counterparties and asset flow at a glance",
+ "you": "Initiator (You)",
+ "counterparty": "Recipient",
+ "counterpartyPlaceholder": "Select a counterparty",
+ "send": "Send",
+ "receive": "Receive"
+ },
+ "msg": {
+ "fetchOrganizationsFailed": "Failed to fetch tradable organizations",
+ "submitFailed": "Failed to submit transaction, please try again later",
+ "validation": {
+ "counterparty": "Please select a counterparty",
+ "sendAmount": "Please enter a valid send amount",
+ "receiveAmount": "Please enter a valid receive amount"
+ }
+ },
+ "errors": {
+ "4001": "The receiving organization does not exist or is unavailable",
+ "4002": "You cannot trade with your own organization"
+ },
+ "success": {
+ "title": "Transaction Submitted",
+ "desc": "The transaction has been submitted to the settlement window",
+ "transactionId": "Transaction ID",
+ "again": "Send Another",
+ "viewDetail": "View Transaction Details"
+ },
+ "failure": {
+ "title": "Transaction Failed",
+ "close": "Close",
+ "retry": "Retry"
+ }
}
}
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index 50db1f5..67055d2 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -22,6 +22,37 @@
"msg": {
"fetchFailed": "获取结算窗口预测失败"
}
+ },
+ "asset": "资产地址",
+ "netPositions": {
+ "title": "净结算头寸",
+ "desc": "当前银行每种资产的应付/应收数量",
+ "payable": "应付数量",
+ "receivable": "应收数量",
+ "empty": "当前无净结算头寸",
+ "msg": {
+ "fetchFailed": "获取净结算头寸失败"
+ }
+ },
+ "assetRequirements": {
+ "title": "结算资产需求",
+ "desc": "本轮结算需要提前准备的资产数量",
+ "required": "结算所需数量",
+ "empty": "当前无需准备的结算资产",
+ "msg": {
+ "fetchFailed": "获取结算资产需求失败"
+ }
+ },
+ "liquidityShortfalls": {
+ "title": "流动性缺口",
+ "desc": "结算所需数量、当前余额与预计借款数量",
+ "required": "结算所需数量",
+ "available": "当前余额",
+ "borrow": "预计借款数量",
+ "empty": "当前无流动性缺口",
+ "msg": {
+ "fetchFailed": "获取流动性缺口失败"
+ }
}
},
"account": {
@@ -290,6 +321,59 @@
"dashboard": "仪表板",
"account": "帐户",
"records": "交易记录",
- "send": "发起交易"
+ "send": "发起交易",
+ "transactions": "交易"
+ },
+ "send": {
+ "title": "发起交易",
+ "subtitle": "选择交易对象与资产,提交一笔净额结算交易",
+ "form": {
+ "title": "交易信息",
+ "desc": "交易提交后将进入下一个结算窗口,等待净额结算完成",
+ "counterparty": "交易对象",
+ "counterpartyPlaceholder": "搜索并选择机构",
+ "counterpartyEmpty": "暂无可交易机构",
+ "youSend": "您发送",
+ "youReceive": "您收到",
+ "asset": "资产",
+ "amount": "数量",
+ "amountPlaceholder": "请输入数量",
+ "submit": "提交交易",
+ "reset": "重置"
+ },
+ "visual": {
+ "title": "交易预览",
+ "desc": "交易双方与资产流向一目了然",
+ "you": "发起方(我方)",
+ "counterparty": "接收方",
+ "counterpartyPlaceholder": "请选择交易对象",
+ "send": "发送",
+ "receive": "接收"
+ },
+ "msg": {
+ "fetchOrganizationsFailed": "获取可交易机构列表失败",
+ "submitFailed": "提交交易失败,请稍后重试",
+ "validation": {
+ "counterparty": "请选择交易对象",
+ "sendAmount": "请输入有效的发送数量",
+ "receiveAmount": "请输入有效的接收数量"
+ }
+ },
+ "errors": {
+ "4001": "接收方机构不存在或不可用",
+ "4002": "不能与当前所属机构进行交易"
+ },
+ "success": {
+ "title": "交易提交成功",
+ "desc": "交易已提交到结算窗口,等待结算完成",
+ "transactionId": "交易 ID",
+ "again": "继续填写下一个",
+ "viewDetail": "查看交易详情"
+ },
+ "failure": {
+ "title": "交易提交失败",
+ "close": "关闭",
+ "retry": "重试"
+ }
}
}
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index 4d9ffdc..1337e7c 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -22,6 +22,37 @@
"msg": {
"fetchFailed": "獲取結算窗口預測失敗"
}
+ },
+ "asset": "資產地址",
+ "netPositions": {
+ "title": "淨結算頭寸",
+ "desc": "當前銀行每種資產的應付/應收數量",
+ "payable": "應付數量",
+ "receivable": "應收數量",
+ "empty": "當前無淨結算頭寸",
+ "msg": {
+ "fetchFailed": "獲取淨結算頭寸失敗"
+ }
+ },
+ "assetRequirements": {
+ "title": "結算資產需求",
+ "desc": "本輪結算需要提前準備的資產數量",
+ "required": "結算所需數量",
+ "empty": "當前無需準備的結算資產",
+ "msg": {
+ "fetchFailed": "獲取結算資產需求失敗"
+ }
+ },
+ "liquidityShortfalls": {
+ "title": "流動性缺口",
+ "desc": "結算所需數量、當前餘額與預計借款數量",
+ "required": "結算所需數量",
+ "available": "當前餘額",
+ "borrow": "預計借款數量",
+ "empty": "當前無流動性缺口",
+ "msg": {
+ "fetchFailed": "獲取流動性缺口失敗"
+ }
}
},
"account": {
@@ -290,6 +321,59 @@
"dashboard": "儀表板",
"account": "帳戶",
"records": "交易記錄",
- "send": "發起交易"
+ "send": "發起交易",
+ "transactions": "交易"
+ },
+ "send": {
+ "title": "發起交易",
+ "subtitle": "選擇交易對象與資產,提交一筆淨額結算交易",
+ "form": {
+ "title": "交易資訊",
+ "desc": "交易提交後將進入下一個結算窗口,等待淨額結算完成",
+ "counterparty": "交易對象",
+ "counterpartyPlaceholder": "搜尋並選擇機構",
+ "counterpartyEmpty": "暫無可交易機構",
+ "youSend": "您發送",
+ "youReceive": "您收到",
+ "asset": "資產",
+ "amount": "數量",
+ "amountPlaceholder": "請輸入數量",
+ "submit": "提交交易",
+ "reset": "重置"
+ },
+ "visual": {
+ "title": "交易預覽",
+ "desc": "交易雙方與資產流向一目了然",
+ "you": "發起方(我方)",
+ "counterparty": "接收方",
+ "counterpartyPlaceholder": "請選擇交易對象",
+ "send": "發送",
+ "receive": "接收"
+ },
+ "msg": {
+ "fetchOrganizationsFailed": "獲取可交易機構列表失敗",
+ "submitFailed": "提交交易失敗,請稍後重試",
+ "validation": {
+ "counterparty": "請選擇交易對象",
+ "sendAmount": "請輸入有效的發送數量",
+ "receiveAmount": "請輸入有效的接收數量"
+ }
+ },
+ "errors": {
+ "4001": "接收方機構不存在或不可用",
+ "4002": "不能與當前所屬機構進行交易"
+ },
+ "success": {
+ "title": "交易提交成功",
+ "desc": "交易已提交到結算窗口,等待結算完成",
+ "transactionId": "交易 ID",
+ "again": "繼續填寫下一個",
+ "viewDetail": "查看交易詳情"
+ },
+ "failure": {
+ "title": "交易提交失敗",
+ "close": "關閉",
+ "retry": "重試"
+ }
}
}
From 55a166ef6980fe03c24101843d6430ff24af2ecc Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 01:16:54 +0800
Subject: [PATCH 18/33] feat(router): add routes for send and transactions
views with localization
---
src/router/index.js | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/router/index.js b/src/router/index.js
index 6207b5b..bb9ea7e 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -36,6 +36,16 @@ const routes = computed(() => [
meta: { title: t('dashboard.title') },
component: () => import('@/views/DashboardView.vue'),
},
+ {
+ path: 'send',
+ meta: { title: t('send.title') },
+ component: () => import('@/views/SendView.vue'),
+ },
+ {
+ path: 'transactions',
+ meta: { title: t('transactions.title') },
+ component: () => import('@/views/TransactionsView.vue'),
+ },
{
path: 'account',
meta: { title: t('account.title') },
From 94f4dd77a01d8fefba8c2db0d85b1ed525b36902 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 01:16:58 +0800
Subject: [PATCH 19/33] feat(DashboardView): add net positions, asset
requirements, and liquidity shortfalls sections with refresh functionality
---
src/views/DashboardView.vue | 344 ++++++++++++++++++++++++++++++++++--
1 file changed, 325 insertions(+), 19 deletions(-)
diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue
index 4077bd5..67cd69a 100644
--- a/src/views/DashboardView.vue
+++ b/src/views/DashboardView.vue
@@ -72,6 +72,155 @@
{{ t('dashboard.forecast.lastUpdated.label', { time: lastUpdatedText }) }}
+
+
+
+
+
{{ t('dashboard.netPositions.title') }}
+
+
+
+
+
+
+
+
+
{{ t('dashboard.netPositions.desc') }}
+
+
+
+ -
+ {{ shortenAddress(item.asset) }}
+
+
+ {{ t('dashboard.netPositions.payable') }}: {{ formatAmount(item.payableAmount) }}
+
+
+ {{ t('dashboard.netPositions.receivable') }}:
+ {{ formatAmount(item.receivableAmount) }}
+
+
+
+
+
+
+
+
+
+
+
{{ t('dashboard.assetRequirements.title') }}
+
+
+
+
+
+
+
+
+
{{ t('dashboard.assetRequirements.desc') }}
+
+
+
+ -
+ {{ shortenAddress(item.asset) }}
+
+
+ {{ t('dashboard.assetRequirements.required') }}:
+ {{ formatAmount(item.requiredAmount) }}
+
+
+
+
+
+
+
+
+
+
+
{{ t('dashboard.liquidityShortfalls.title') }}
+
+
+
+
+
+
+
+
+
{{ t('dashboard.liquidityShortfalls.desc') }}
+
+
+
+ -
+ {{ shortenAddress(item.asset) }}
+
+
+ {{ t('dashboard.liquidityShortfalls.required') }}:
+ {{ formatAmount(item.requiredAmount) }}
+
+
+ {{ t('dashboard.liquidityShortfalls.available') }}:
+ {{ formatAmount(item.availableBalance) }}
+
+
+ {{ t('dashboard.liquidityShortfalls.borrow') }}:
+ {{ formatAmount(item.borrowAmount) }}
+
+
+
+
+
+
+
+
@@ -103,24 +252,7 @@ const currentTime = ref(new Date())
const blockCoreRef = ref(null)
-const lastUpdatedText = computed(() => {
- if (!lastUpdatedAt.value) {
- return '-'
- }
- const diffSeconds = Math.floor((currentTime.value - lastUpdatedAt.value) / 1000)
- if (diffSeconds < 60) {
- return t('dashboard.forecast.lastUpdated.justNow')
- } else if (diffSeconds < 3600) {
- const minutes = Math.floor(diffSeconds / 60)
- return t('dashboard.forecast.lastUpdated.minutesAgo', { minutes })
- } else if (diffSeconds < 86400) {
- const hours = Math.floor(diffSeconds / 3600)
- return t('dashboard.forecast.lastUpdated.hoursAgo', { hours })
- } else {
- const days = Math.floor(diffSeconds / 86400)
- return t('dashboard.forecast.lastUpdated.daysAgo', { days })
- }
-})
+const lastUpdatedText = computed(() => formatRelativeTime(lastUpdatedAt.value))
const GLOW_OFF = '0 0 0px 0px rgba(0, 168, 112, 0)'
const GLOW_ON = '0 0 26px 8px rgba(0, 168, 112, 0.65)'
@@ -172,11 +304,104 @@ async function fetchForecast() {
}
}
+function formatRelativeTime(date) {
+ if (!date) {
+ return '-'
+ }
+ const diffSeconds = Math.floor((currentTime.value - date) / 1000)
+ if (diffSeconds < 60) {
+ return t('dashboard.forecast.lastUpdated.justNow')
+ } else if (diffSeconds < 3600) {
+ return t('dashboard.forecast.lastUpdated.minutesAgo', { minutes: Math.floor(diffSeconds / 60) })
+ } else if (diffSeconds < 86400) {
+ return t('dashboard.forecast.lastUpdated.hoursAgo', { hours: Math.floor(diffSeconds / 3600) })
+ } else {
+ return t('dashboard.forecast.lastUpdated.daysAgo', { days: Math.floor(diffSeconds / 86400) })
+ }
+}
+
+function shortenAddress(address) {
+ if (!address || address.length <= 12) {
+ return address ?? '-'
+ }
+ return `${address.slice(0, 6)}...${address.slice(-4)}`
+}
+
+function formatAmount(amount) {
+ if (amount === null || amount === undefined) {
+ return '-'
+ }
+ return Number(amount).toLocaleString()
+}
+
+const netPositions = ref({ items: [], loading: false, lastUpdatedAt: null })
+const assetRequirements = ref({ items: [], loading: false, lastUpdatedAt: null })
+const liquidityShortfalls = ref({ items: [], loading: false, lastUpdatedAt: null })
+
+async function fetchNetPositions() {
+ netPositions.value.loading = true
+ try {
+ const res = await api({ method: 'get', url: '/dashboard/net-positions' })
+ if (res.data.code === 200) {
+ netPositions.value.items = res.data.data
+ netPositions.value.lastUpdatedAt = new Date()
+ } else {
+ throw new Error(res.data.msg)
+ }
+ } catch (e) {
+ console.error(e)
+ MessagePlugin.error(t('dashboard.netPositions.msg.fetchFailed'))
+ } finally {
+ netPositions.value.loading = false
+ }
+}
+
+async function fetchAssetRequirements() {
+ assetRequirements.value.loading = true
+ try {
+ const res = await api({ method: 'get', url: '/dashboard/settlement-asset-requirements' })
+ if (res.data.code === 200) {
+ assetRequirements.value.items = res.data.data
+ assetRequirements.value.lastUpdatedAt = new Date()
+ } else {
+ throw new Error(res.data.msg)
+ }
+ } catch (e) {
+ console.error(e)
+ MessagePlugin.error(t('dashboard.assetRequirements.msg.fetchFailed'))
+ } finally {
+ assetRequirements.value.loading = false
+ }
+}
+
+async function fetchLiquidityShortfalls() {
+ liquidityShortfalls.value.loading = true
+ try {
+ const res = await api({ method: 'get', url: '/dashboard/liquidity-shortfalls' })
+ if (res.data.code === 200) {
+ liquidityShortfalls.value.items = res.data.data
+ liquidityShortfalls.value.lastUpdatedAt = new Date()
+ } else {
+ throw new Error(res.data.msg)
+ }
+ } catch (e) {
+ console.error(e)
+ MessagePlugin.error(t('dashboard.liquidityShortfalls.msg.fetchFailed'))
+ } finally {
+ liquidityShortfalls.value.loading = false
+ }
+}
+
onMounted(async () => {
clockTimer = setInterval(() => {
currentTime.value = new Date()
}, 1000)
- await fetchForecast()
+ await Promise.all([
+ fetchForecast(),
+ fetchNetPositions(),
+ fetchAssetRequirements(),
+ fetchLiquidityShortfalls(),
+ ])
startBreathing()
pollTimer = setInterval(fetchForecast, 5000)
})
@@ -343,4 +568,85 @@ onBeforeUnmount(() => {
font: var(--td-font-body-small);
color: var(--td-text-color-placeholder);
}
+
+.panel-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: 1.5rem;
+ margin-top: 1.5rem;
+}
+
+.panel-card {
+ padding: 2rem;
+ border-radius: 28px;
+ background-color: var(--td-bg-color-container);
+ border: 1px solid var(--td-component-stroke);
+}
+
+.panel-card__title-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.panel-card__title {
+ font: var(--td-font-title-large);
+ color: var(--td-text-color-primary);
+}
+
+.panel-card__desc {
+ margin: 0.25rem 0 1.5rem;
+ font: var(--td-font-body-small);
+ color: var(--td-text-color-placeholder);
+}
+
+.panel-card__footer {
+ margin: 1.25rem 0 0;
+ text-align: right;
+ font: var(--td-font-body-small);
+ color: var(--td-text-color-placeholder);
+}
+
+.asset-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.asset-list__item {
+ display: flex;
+ flex-direction: column;
+ gap: 0.4rem;
+ padding: 0.85rem 1rem;
+ border-radius: 14px;
+ background-color: var(--td-bg-color-secondarycontainer);
+}
+
+.asset-list__address {
+ font-family: var(--td-font-family, monospace);
+ font: var(--td-font-body-medium);
+ color: var(--td-text-color-primary);
+}
+
+.asset-list__amounts {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.75rem 1.25rem;
+}
+
+.asset-list__amount {
+ font: var(--td-font-body-small);
+ color: var(--td-text-color-secondary);
+}
+
+.asset-list__amount--payable {
+ color: var(--td-error-color-6);
+}
+
+.asset-list__amount--receivable {
+ color: var(--td-success-color-6);
+}
From 4291c9a75a62023bf6f01012d9ff3c484b1df6b8 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 01:25:34 +0800
Subject: [PATCH 20/33] feat(LanguageSelector): add language selector component
and integrate into NavBar and PageFooter
---
src/components/LanguageSelector.vue | 37 +++++++++++++++++++++++++++
src/components/NavBar.vue | 39 ++++++++++++++++++++++++++++-
src/components/PageFooter.vue | 31 +++--------------------
src/i18n/locales/en-US.json | 3 ++-
src/i18n/locales/zh-CN.json | 3 ++-
src/i18n/locales/zh-TW.json | 3 ++-
6 files changed, 84 insertions(+), 32 deletions(-)
create mode 100644 src/components/LanguageSelector.vue
diff --git a/src/components/LanguageSelector.vue b/src/components/LanguageSelector.vue
new file mode 100644
index 0000000..4c913cb
--- /dev/null
+++ b/src/components/LanguageSelector.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue
index 8e5d4c8..d7735e0 100644
--- a/src/components/NavBar.vue
+++ b/src/components/NavBar.vue
@@ -50,6 +50,13 @@
{{ $t('navbar.item.dashboard') }}
+
+
+
+
+ {{ $t('navbar.item.language') }}
+
+
+
+
+
+
+
+
diff --git a/src/components/PageFooter.vue b/src/components/PageFooter.vue
index b150bd0..68f49f4 100644
--- a/src/components/PageFooter.vue
+++ b/src/components/PageFooter.vue
@@ -26,17 +26,7 @@
@@ -46,14 +36,10 @@
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 0fb0429..d3673eb 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -299,7 +299,8 @@
},
"item": {
"logout": "Logout",
- "dashboard": "Dashboard"
+ "dashboard": "Dashboard",
+ "language": "Language"
}
},
"notFound": {
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index 67055d2..ea3e733 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -299,7 +299,8 @@
},
"item": {
"logout": "注销",
- "dashboard": "仪表板"
+ "dashboard": "仪表板",
+ "language": "语言"
}
},
"notFound": {
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index 1337e7c..faa8843 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -299,7 +299,8 @@
},
"item": {
"logout": "註銷",
- "dashboard": "儀表板"
+ "dashboard": "儀表板",
+ "language": "語言"
}
},
"notFound": {
From e401bd1bd34e77d18a15967cb58c0a0473b090ae Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 01:26:20 +0800
Subject: [PATCH 21/33] feat(AccountView): center-align text in summary title
---
src/views/AccountView.vue | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/views/AccountView.vue b/src/views/AccountView.vue
index a022d9c..50449a3 100644
--- a/src/views/AccountView.vue
+++ b/src/views/AccountView.vue
@@ -257,6 +257,7 @@ async function copyField(value, label) {
margin: 0;
font: var(--td-font-title-large);
color: var(--td-text-color-primary);
+ text-align: center;
}
.summary__meta {
From 102d5981e6cf5af4965c0f0c38530d71dd5398e8 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 02:46:02 +0800
Subject: [PATCH 22/33] feat(DashboardView): enhance dashboard layout with grid
system and loading states for overview data
---
src/views/DashboardView.vue | 421 +++++++++++++++++++++---------------
1 file changed, 249 insertions(+), 172 deletions(-)
diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue
index 67cd69a..c0d3f74 100644
--- a/src/views/DashboardView.vue
+++ b/src/views/DashboardView.vue
@@ -7,83 +7,150 @@
{{ t('dashboard.subtitle') }}
-
-
-
{{ t('dashboard.forecast.title') }}
-
-
-
-
-
-
-
-
-
{{ t('dashboard.forecast.desc') }}
-
-
-
-
-
-
-
- {{ t('dashboard.forecast.active') }}
-
+
+
+
+
+ {{ t('dashboard.forecast.title') }}
+
+
+
+
+
+
+
+
+
{{ t('dashboard.forecast.desc') }}
-
-
-
- {{ t('dashboard.forecast.windowId') }}
+
+
+
+
- {{ forecast.windowId ?? '-' }}
-
-
-
- {{ t('dashboard.forecast.settlementBlock') }}
+
+ {{ t('dashboard.forecast.active') }}
- {{ forecast.settlementBlock ?? '-' }}
-
-
- {{ t('dashboard.forecast.blocksRemaining') }}
-
-
-
- {{ t('dashboard.forecast.reached') }}
-
-
- {{ forecast.blocksRemaining ?? '-' }}
- {{
- t('dashboard.forecast.blocksUnit')
- }}
-
-
+
+
+
+
+ {{ t('dashboard.forecast.windowId') }}
+
+
+
+
+ {{ forecast.windowId ?? '-' }}
+
+
+
+ {{ t('dashboard.forecast.settlementBlock') }}
+
+
+
+
+ {{ forecast.settlementBlock ?? '-' }}
+
+
+
+ {{ t('dashboard.forecast.blocksRemaining') }}
+
+
+
+
+
+
+ {{ t('dashboard.forecast.reached') }}
+
+
+ {{ forecast.blocksRemaining ?? '-' }}
+ {{
+ t('dashboard.forecast.blocksUnit')
+ }}
+
+
+
+
+
-
-
+
+
+
+ {{ t('dashboard.walletBalances.title') }}
+
+
+
+
+
+
+
+
+
+
{{ t('dashboard.walletBalances.desc') }}
+
+
+
+
+ -
+ {{
+ item.asset.name || formatAsset(item.asset)
+ }}
+
+
+ {{ t('dashboard.walletBalances.balance') }}: {{ formatAmount(item.amount) }}
+ {{ item.asset.symbol }}
+
+
+
+
+
+
-
-
{{ t('dashboard.netPositions.title') }}
+
+ {{ t('dashboard.netPositions.title') }}
+
@@ -93,44 +160,51 @@
{{ t('dashboard.netPositions.desc') }}
+
- -
- {{ shortenAddress(item.asset) }}
+
-
+ {{
+ item.asset.name || formatAsset(item.asset)
+ }}
- {{ t('dashboard.netPositions.payable') }}: {{ formatAmount(item.payableAmount) }}
-
-
- {{ t('dashboard.netPositions.receivable') }}:
- {{ formatAmount(item.receivableAmount) }}
+ {{ t('dashboard.netPositions.amount') }}: {{ formatAmount(item.amount) }}
+ {{ item.asset.symbol }}
-
-
{{ t('dashboard.assetRequirements.title') }}
+
+ {{ t('dashboard.assetRequirements.title') }}
+
@@ -140,41 +214,51 @@
{{ t('dashboard.assetRequirements.desc') }}
+
- -
- {{ shortenAddress(item.asset) }}
+
-
+ {{
+ item.asset.name || formatAsset(item.asset)
+ }}
- {{ t('dashboard.assetRequirements.required') }}:
- {{ formatAmount(item.requiredAmount) }}
+ {{ t('dashboard.assetRequirements.required') }}: {{ formatAmount(item.amount) }}
+ {{ item.asset.symbol }}
-
-
{{ t('dashboard.liquidityShortfalls.title') }}
+
+ {{ t('dashboard.liquidityShortfalls.title') }}
+
@@ -184,40 +268,36 @@
{{ t('dashboard.liquidityShortfalls.desc') }}
+
-
- {{ shortenAddress(item.asset) }}
+ {{
+ item.asset.name || formatAsset(item.asset)
+ }}
- {{ t('dashboard.liquidityShortfalls.required') }}:
- {{ formatAmount(item.requiredAmount) }}
-
-
- {{ t('dashboard.liquidityShortfalls.available') }}:
- {{ formatAmount(item.availableBalance) }}
-
-
- {{ t('dashboard.liquidityShortfalls.borrow') }}:
- {{ formatAmount(item.borrowAmount) }}
+ {{ t('dashboard.liquidityShortfalls.amount') }}: {{ formatAmount(item.amount) }}
+ {{ item.asset.symbol }}
-
@@ -235,6 +315,11 @@ import {
RootListIcon,
ChartRing1Icon,
HourglassIcon,
+ TaskTimeIcon,
+ WalletIcon,
+ CurrencyExchangeIcon,
+ ChartAnalyticsIcon,
+ MoneyIcon,
} from 'tdesign-icons-vue-next'
import api from '@/utils/api'
import { useLocale } from '@/utils/i18n'
@@ -327,68 +412,45 @@ function shortenAddress(address) {
return `${address.slice(0, 6)}...${address.slice(-4)}`
}
-function formatAmount(amount) {
- if (amount === null || amount === undefined) {
+function formatAsset(asset) {
+ if (!asset) {
return '-'
}
- return Number(amount).toLocaleString()
+ return asset.symbol || shortenAddress(asset.address)
}
-const netPositions = ref({ items: [], loading: false, lastUpdatedAt: null })
-const assetRequirements = ref({ items: [], loading: false, lastUpdatedAt: null })
-const liquidityShortfalls = ref({ items: [], loading: false, lastUpdatedAt: null })
-
-async function fetchNetPositions() {
- netPositions.value.loading = true
- try {
- const res = await api({ method: 'get', url: '/dashboard/net-positions' })
- if (res.data.code === 200) {
- netPositions.value.items = res.data.data
- netPositions.value.lastUpdatedAt = new Date()
- } else {
- throw new Error(res.data.msg)
- }
- } catch (e) {
- console.error(e)
- MessagePlugin.error(t('dashboard.netPositions.msg.fetchFailed'))
- } finally {
- netPositions.value.loading = false
+function formatAmount(amount) {
+ if (amount === null || amount === undefined) {
+ return '-'
}
+ return Number(amount).toLocaleString()
}
-async function fetchAssetRequirements() {
- assetRequirements.value.loading = true
- try {
- const res = await api({ method: 'get', url: '/dashboard/settlement-asset-requirements' })
- if (res.data.code === 200) {
- assetRequirements.value.items = res.data.data
- assetRequirements.value.lastUpdatedAt = new Date()
- } else {
- throw new Error(res.data.msg)
- }
- } catch (e) {
- console.error(e)
- MessagePlugin.error(t('dashboard.assetRequirements.msg.fetchFailed'))
- } finally {
- assetRequirements.value.loading = false
- }
-}
+const overview = ref({
+ balances: [],
+ netAmounts: [],
+ cumulativeGrossTradeAmounts: [],
+ liquidityBufferDebts: [],
+})
+const overviewLoading = ref(false)
+const overviewLastUpdatedAt = ref(null)
+const overviewLastUpdatedText = computed(() => formatRelativeTime(overviewLastUpdatedAt.value))
-async function fetchLiquidityShortfalls() {
- liquidityShortfalls.value.loading = true
+async function fetchOverview() {
+ overviewLoading.value = true
try {
- const res = await api({ method: 'get', url: '/dashboard/liquidity-shortfalls' })
+ const res = await api({ method: 'get', url: '/dashboard/overview' })
if (res.data.code === 200) {
- liquidityShortfalls.value.items = res.data.data
- liquidityShortfalls.value.lastUpdatedAt = new Date()
+ overview.value = res.data.data
+ overviewLastUpdatedAt.value = res.data.time ? new Date(res.data.time * 1000) : new Date()
} else {
throw new Error(res.data.msg)
}
} catch (e) {
console.error(e)
- MessagePlugin.error(t('dashboard.liquidityShortfalls.msg.fetchFailed'))
+ MessagePlugin.error(t('dashboard.overview.msg.fetchFailed'))
} finally {
- liquidityShortfalls.value.loading = false
+ overviewLoading.value = false
}
}
@@ -396,14 +458,9 @@ onMounted(async () => {
clockTimer = setInterval(() => {
currentTime.value = new Date()
}, 1000)
- await Promise.all([
- fetchForecast(),
- fetchNetPositions(),
- fetchAssetRequirements(),
- fetchLiquidityShortfalls(),
- ])
+ await Promise.all([fetchForecast(), fetchOverview()])
startBreathing()
- pollTimer = setInterval(fetchForecast, 5000)
+ pollTimer = setInterval(fetchForecast, 60 * 1000)
})
onBeforeUnmount(() => {
@@ -463,13 +520,25 @@ onBeforeUnmount(() => {
.forecast-card {
position: relative;
- max-width: 640px;
+ grid-column: span 2;
padding: 2rem;
border-radius: 28px;
background-color: var(--td-bg-color-container);
border: 1px solid var(--td-component-stroke);
}
+.dashboard-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: 1.5rem;
+}
+
+@media (max-width: 678px) {
+ .forecast-card {
+ grid-column: span 1;
+ }
+}
+
.forecast-card__title-row {
display: flex;
align-items: center;
@@ -479,6 +548,9 @@ onBeforeUnmount(() => {
.forecast-card__title {
font: var(--td-font-title-large);
color: var(--td-text-color-primary);
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
}
.forecast-card__desc {
@@ -541,6 +613,7 @@ onBeforeUnmount(() => {
align-items: center;
justify-content: space-between;
gap: 1rem;
+ height: 1.5rem;
}
.stat-item__label {
@@ -569,13 +642,6 @@ onBeforeUnmount(() => {
color: var(--td-text-color-placeholder);
}
-.panel-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
- gap: 1.5rem;
- margin-top: 1.5rem;
-}
-
.panel-card {
padding: 2rem;
border-radius: 28px;
@@ -592,6 +658,9 @@ onBeforeUnmount(() => {
.panel-card__title {
font: var(--td-font-title-large);
color: var(--td-text-color-primary);
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
}
.panel-card__desc {
@@ -607,6 +676,14 @@ onBeforeUnmount(() => {
color: var(--td-text-color-placeholder);
}
+.panel-card__data-skeleton {
+ min-height: 6.5rem;
+}
+
+.stat-item__value--loading {
+ width: 7rem;
+}
+
.asset-list {
display: flex;
flex-direction: column;
From 6e02b2ee5fac3d6e5f6027acb5993c9aee371ed7 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 03:08:00 +0800
Subject: [PATCH 23/33] feat(DashboardView): update dashboard components and
localization for account balances, cumulative trades, and liquidity buffer
---
src/i18n/locales/en-US.json | 50 ++++++++-----
src/i18n/locales/zh-CN.json | 50 ++++++++-----
src/i18n/locales/zh-TW.json | 52 +++++++++-----
src/views/DashboardView.vue | 135 +++++++++++++++++++++++++++++++-----
4 files changed, 220 insertions(+), 67 deletions(-)
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index d3673eb..543e5dd 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -4,7 +4,7 @@
"subtitle": "Real-time monitoring of the settlement window and target block",
"forecast": {
"title": "Settlement Window Forecast",
- "desc": "Data is read via an on-chain read-only call. No transaction is sent and no gas is consumed.",
+ "desc": "Stay ahead of settlement and plan your funding with confidence",
"refresh": "Refresh",
"active": "Active",
"windowId": "Pending Window ID",
@@ -23,33 +23,51 @@
"fetchFailed": "Failed to fetch settlement window forecast"
}
},
+ "overview": {
+ "msg": {
+ "fetchFailed": "Failed to fetch dashboard overview"
+ }
+ },
+ "accountBalances": {
+ "title": "Account Balances",
+ "desc": "See the available assets in your account at a glance",
+ "balance": "Balance",
+ "empty": "No account balances"
+ },
+ "cumulativeTradeCount": {
+ "title": "Total Trades",
+ "desc": "Track the total trading activity linked to your account",
+ "label": "Trades"
+ },
"asset": "Asset Address",
- "netPositions": {
- "title": "Net Settlement Positions",
- "desc": "Payable/receivable amounts per asset for the current bank",
+ "settlementNetAmounts": {
+ "title": "Settlement Net Amounts",
+ "desc": "See how your funds will change after this settlement",
"payable": "Payable Amount",
"receivable": "Receivable Amount",
- "empty": "No net settlement positions",
+ "amount": "Net Amount",
+ "empty": "No net settlement obligations",
"msg": {
"fetchFailed": "Failed to fetch net settlement positions"
}
},
- "assetRequirements": {
- "title": "Settlement Asset Requirements",
- "desc": "Assets that must be prepared ahead of this settlement round",
- "required": "Required Amount",
- "empty": "No settlement assets required",
+ "cumulativeTradeAmounts": {
+ "title": "Total Trade Amounts",
+ "desc": "Review the total value of trades linked to your account",
+ "amount": "Cumulative Gross Amount",
+ "empty": "No cumulative gross trade amounts",
"msg": {
"fetchFailed": "Failed to fetch settlement asset requirements"
}
},
- "liquidityShortfalls": {
- "title": "Liquidity Shortfalls",
- "desc": "Required amount, current balance and estimated borrow amount",
- "required": "Required Amount",
+ "liquidityBufferDebts": {
+ "title": "Liquidity Buffer Balance",
+ "desc": "Keep track of funding support that is still to be repaid",
+ "required": "Debt Amount",
"available": "Available Balance",
- "borrow": "Estimated Borrow Amount",
- "empty": "No liquidity shortfalls",
+ "borrow": "Debt Amount",
+ "amount": "Debt Amount",
+ "empty": "No liquidity buffer balance",
"msg": {
"fetchFailed": "Failed to fetch liquidity shortfalls"
}
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index ea3e733..fa8fac8 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -4,7 +4,7 @@
"subtitle": "实时监控净额结算窗口与目标结算区块",
"forecast": {
"title": "结算窗口预测",
- "desc": "数据来自链上合约的只读调用,不发送交易,不消耗 Gas",
+ "desc": "掌握本轮结算进度,提前做好资金安排",
"refresh": "刷新",
"active": "活跃中",
"windowId": "待结算窗口 ID",
@@ -23,33 +23,51 @@
"fetchFailed": "获取结算窗口预测失败"
}
},
+ "overview": {
+ "msg": {
+ "fetchFailed": "获取仪表板概览失败"
+ }
+ },
+ "accountBalances": {
+ "title": "账户余额",
+ "desc": "实时掌握账户中各项资产的可用余额",
+ "balance": "余额",
+ "empty": "当前无账户余额"
+ },
+ "cumulativeTradeCount": {
+ "title": "累计交易笔数",
+ "desc": "了解账户累计参与的交易规模",
+ "label": "交易笔数"
+ },
"asset": "资产地址",
- "netPositions": {
- "title": "净结算头寸",
- "desc": "当前银行每种资产的应付/应收数量",
+ "settlementNetAmounts": {
+ "title": "结算净额",
+ "desc": "一目了然地了解本轮结算后的资金变化",
"payable": "应付数量",
"receivable": "应收数量",
- "empty": "当前无净结算头寸",
+ "amount": "净额",
+ "empty": "当前没有净结算义务",
"msg": {
"fetchFailed": "获取净结算头寸失败"
}
},
- "assetRequirements": {
- "title": "结算资产需求",
- "desc": "本轮结算需要提前准备的资产数量",
- "required": "结算所需数量",
- "empty": "当前无需准备的结算资产",
+ "cumulativeTradeAmounts": {
+ "title": "累计交易金额",
+ "desc": "汇总查看账户参与的累计交易金额",
+ "amount": "累计原始金额",
+ "empty": "当前没有累计原始交易金额",
"msg": {
"fetchFailed": "获取结算资产需求失败"
}
},
- "liquidityShortfalls": {
- "title": "流动性缺口",
- "desc": "结算所需数量、当前余额与预计借款数量",
- "required": "结算所需数量",
+ "liquidityBufferDebts": {
+ "title": "流动性缓冲欠款",
+ "desc": "及时了解待归还的流动性支持金额",
+ "required": "欠款金额",
"available": "当前余额",
- "borrow": "预计借款数量",
- "empty": "当前无流动性缺口",
+ "borrow": "欠款金额",
+ "amount": "欠款金额",
+ "empty": "当前没有流动性缓冲欠款",
"msg": {
"fetchFailed": "获取流动性缺口失败"
}
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index faa8843..d5d26ba 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -4,7 +4,7 @@
"subtitle": "即時監控淨額結算窗口與目標結算區塊",
"forecast": {
"title": "結算窗口預測",
- "desc": "數據來自鏈上合約的只讀調用,不發送交易,不消耗 Gas",
+ "desc": "掌握本輪結算進度,提前做好資金安排",
"refresh": "刷新",
"active": "活躍中",
"windowId": "待結算窗口 ID",
@@ -23,33 +23,51 @@
"fetchFailed": "獲取結算窗口預測失敗"
}
},
+ "overview": {
+ "msg": {
+ "fetchFailed": "獲取儀表板概覽失敗"
+ }
+ },
+ "accountBalances": {
+ "title": "帳戶餘額",
+ "desc": "即時掌握帳戶中各項資產的可用餘額",
+ "balance": "餘額",
+ "empty": "目前無帳戶餘額"
+ },
+ "cumulativeTradeCount": {
+ "title": "累計交易筆數",
+ "desc": "了解帳戶累計參與的交易規模",
+ "label": "交易筆數"
+ },
"asset": "資產地址",
- "netPositions": {
- "title": "淨結算頭寸",
- "desc": "當前銀行每種資產的應付/應收數量",
+ "settlementNetAmounts": {
+ "title": "結算淨額",
+ "desc": "一目了然地了解本輪結算後的資金變化",
"payable": "應付數量",
"receivable": "應收數量",
- "empty": "當前無淨結算頭寸",
+ "amount": "淨額",
+ "empty": "目前沒有淨結算義務",
"msg": {
"fetchFailed": "獲取淨結算頭寸失敗"
}
},
- "assetRequirements": {
- "title": "結算資產需求",
- "desc": "本輪結算需要提前準備的資產數量",
- "required": "結算所需數量",
- "empty": "當前無需準備的結算資產",
+ "cumulativeTradeAmounts": {
+ "title": "累計交易金額",
+ "desc": "彙總查看帳戶參與的累計交易金額",
+ "amount": "累計原始金額",
+ "empty": "目前沒有累計原始交易金額",
"msg": {
"fetchFailed": "獲取結算資產需求失敗"
}
},
- "liquidityShortfalls": {
- "title": "流動性缺口",
- "desc": "結算所需數量、當前餘額與預計借款數量",
- "required": "結算所需數量",
- "available": "當前餘額",
- "borrow": "預計借款數量",
- "empty": "當前無流動性缺口",
+ "liquidityBufferDebts": {
+ "title": "流動性緩衝欠款",
+ "desc": "及時了解待歸還的流動性支援金額",
+ "required": "欠款金額",
+ "available": "目前餘額",
+ "borrow": "欠款金額",
+ "amount": "欠款金額",
+ "empty": "目前沒有流動性緩衝欠款",
"msg": {
"fetchFailed": "獲取流動性缺口失敗"
}
diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue
index c0d3f74..00d6583 100644
--- a/src/views/DashboardView.vue
+++ b/src/views/DashboardView.vue
@@ -88,7 +88,7 @@
- {{ t('dashboard.walletBalances.title') }}
+ {{ t('dashboard.accountBalances.title') }}
-
{{ t('dashboard.walletBalances.desc') }}
+
{{ t('dashboard.accountBalances.desc') }}
-
- {{ t('dashboard.walletBalances.balance') }}: {{ formatAmount(item.amount) }}
+ {{ t('dashboard.accountBalances.balance') }}: {{ formatAmount(item.amount) }}
{{ item.asset.symbol }}
@@ -142,7 +142,7 @@
- {{ t('dashboard.netPositions.title') }}
+ {{ t('dashboard.cumulativeTradeCount.title') }}
-
{{ t('dashboard.netPositions.desc') }}
+
{{ t('dashboard.cumulativeTradeCount.desc') }}
+
+
+ {{ t('dashboard.cumulativeTradeCount.label') }}
+
+
+
+ {{ formatAmount(overview.cumulativeTradeCount) }}
+
+
+
+
+
+
+
+
+ {{ t('dashboard.settlementNetAmounts.title') }}
+
+
+
+
+
+
+
+
+
+
{{ t('dashboard.settlementNetAmounts.desc') }}
-
-
- {{ t('dashboard.netPositions.amount') }}: {{ formatAmount(item.amount) }}
+
+ {{ t('dashboard.settlementNetAmounts.amount') }}: {{ formatAmount(item.amount) }}
{{ item.asset.symbol }}
@@ -196,7 +242,7 @@
- {{ t('dashboard.assetRequirements.title') }}
+ {{ t('dashboard.cumulativeTradeAmounts.title') }}
-
{{ t('dashboard.assetRequirements.desc') }}
+
{{ t('dashboard.cumulativeTradeAmounts.desc') }}
-
- {{ t('dashboard.assetRequirements.required') }}: {{ formatAmount(item.amount) }}
+ {{ t('dashboard.cumulativeTradeAmounts.amount') }}:
+ {{ formatAmount(item.amount) }}
{{ item.asset.symbol }}
@@ -250,7 +297,7 @@
- {{ t('dashboard.liquidityShortfalls.title') }}
+ {{ t('dashboard.liquidityBufferDebts.title') }}
-
{{ t('dashboard.liquidityShortfalls.desc') }}
+
{{ t('dashboard.liquidityBufferDebts.desc') }}
-
- {{ t('dashboard.liquidityShortfalls.amount') }}: {{ formatAmount(item.amount) }}
+ {{ t('dashboard.liquidityBufferDebts.amount') }}:
+ {{ formatAmount(item.amount) }}
{{ item.asset.symbol }}
@@ -317,6 +365,7 @@ import {
HourglassIcon,
TaskTimeIcon,
WalletIcon,
+ ChartBarIcon,
CurrencyExchangeIcon,
ChartAnalyticsIcon,
MoneyIcon,
@@ -482,7 +531,7 @@ onBeforeUnmount(() => {
}
.dashboard-page__bg {
- position: absolute;
+ position: fixed;
inset: 0;
pointer-events: none;
background:
@@ -499,7 +548,9 @@ onBeforeUnmount(() => {
}
.dashboard-page__inner {
+ position: relative;
width: 100%;
+ z-index: 1;
}
.dashboard-page__header {
@@ -669,6 +720,46 @@ onBeforeUnmount(() => {
color: var(--td-text-color-placeholder);
}
+.overview-stat {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 1rem;
+ margin-bottom: 1rem;
+ padding: 0.75rem 1rem;
+ border-radius: 14px;
+ background-color: var(--td-bg-color-secondarycontainer);
+}
+
+.overview-stat__label {
+ font: var(--td-font-body-small);
+ color: var(--td-text-color-secondary);
+}
+
+.overview-stat__value {
+ font: var(--td-font-title-medium);
+ color: var(--td-text-color-primary);
+}
+
+.overview-stat__skeleton {
+ width: 4rem;
+}
+
+.overview-stat--standalone {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.5rem;
+ margin-top: 1.5rem;
+ padding: 1.25rem 1rem;
+}
+
+.overview-stat--standalone .overview-stat__value {
+ font-size: 2rem;
+ font-weight: 700;
+ line-height: 1;
+ color: var(--td-text-color-primary);
+}
+
.panel-card__footer {
margin: 1.25rem 0 0;
text-align: right;
@@ -726,4 +817,12 @@ onBeforeUnmount(() => {
.asset-list__amount--receivable {
color: var(--td-success-color-6);
}
+
+.asset-list__amount--negative {
+ color: var(--td-error-color-6);
+}
+
+.asset-list__amount--positive {
+ color: var(--td-success-color-6);
+}
From 4bcf362771fe67bb76b3255cbb7a4039620b7fb5 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 03:09:29 +0800
Subject: [PATCH 24/33] feat(AccountView, SendView): change background position
to fixed and update inner layout styles
---
src/views/AccountView.vue | 4 +++-
src/views/SendView.vue | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/views/AccountView.vue b/src/views/AccountView.vue
index 50449a3..95fd0ca 100644
--- a/src/views/AccountView.vue
+++ b/src/views/AccountView.vue
@@ -160,7 +160,7 @@ async function copyField(value, label) {
}
.account-page__bg {
- position: absolute;
+ position: fixed;
inset: 0;
pointer-events: none;
background:
@@ -177,7 +177,9 @@ async function copyField(value, label) {
}
.account-page__inner {
+ position: relative;
width: 100%;
+ z-index: 1;
}
.account-layout {
diff --git a/src/views/SendView.vue b/src/views/SendView.vue
index baee1bc..fa377e4 100644
--- a/src/views/SendView.vue
+++ b/src/views/SendView.vue
@@ -314,7 +314,7 @@ onMounted(() => {
}
.send-page__bg {
- position: absolute;
+ position: fixed;
inset: 0;
pointer-events: none;
background:
@@ -331,7 +331,9 @@ onMounted(() => {
}
.send-page__inner {
+ position: relative;
width: 100%;
+ z-index: 1;
}
.send-page__header {
From 867ada7e17bc04942034f5d10f73455a29f91022 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 03:12:48 +0800
Subject: [PATCH 25/33] feat(DashboardView): update font family for stat item
and asset list styles
---
src/views/DashboardView.vue | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue
index 00d6583..bb65dcd 100644
--- a/src/views/DashboardView.vue
+++ b/src/views/DashboardView.vue
@@ -677,6 +677,7 @@ onBeforeUnmount(() => {
.stat-item__value {
font: var(--td-font-title-medium);
+ font-family: 'TCloudNumber', var(--td-font-family);
color: var(--td-text-color-primary);
}
@@ -738,6 +739,7 @@ onBeforeUnmount(() => {
.overview-stat__value {
font: var(--td-font-title-medium);
+ font-family: 'TCloudNumber', var(--td-font-family);
color: var(--td-text-color-primary);
}
@@ -807,6 +809,7 @@ onBeforeUnmount(() => {
.asset-list__amount {
font: var(--td-font-body-small);
+ font-family: 'TCloudNumber', var(--td-font-family);
color: var(--td-text-color-secondary);
}
From 95bfbf35fb7bee499d658c55fc1e8de4f3ffd0f5 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 03:14:55 +0800
Subject: [PATCH 26/33] feat(assets, SendView): update asset metadata and
change receive asset to BOND
---
src/utils/assets.js | 8 ++++----
src/views/SendView.vue | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/utils/assets.js b/src/utils/assets.js
index 93c6bd5..a2290f9 100644
--- a/src/utils/assets.js
+++ b/src/utils/assets.js
@@ -1,11 +1,11 @@
-// 可交易资产的元数据映射(名称、最小单位小数位等)
+// 可交易资产的元数据映射
export const ASSETS = {
- USDC: { code: 'USDC', name: 'USDC', decimals: 6 },
- BOUND: { code: 'BOUND', name: 'BOUND', decimals: 0 },
+ USDC: { code: 'USDC', name: 'Mock USDC', symbol: 'mUSDC', decimals: 6 },
+ BOND: { code: 'BOND', name: 'Mock Bond', symbol: 'mBOND', decimals: 0 },
}
export const ASSET_OPTIONS = Object.values(ASSETS).map((asset) => ({
- label: asset.name,
+ label: `${asset.name} (${asset.symbol})`,
value: asset.code,
}))
diff --git a/src/views/SendView.vue b/src/views/SendView.vue
index fa377e4..7c3fe7c 100644
--- a/src/views/SendView.vue
+++ b/src/views/SendView.vue
@@ -172,7 +172,7 @@ const form = reactive({
receiverOrganizationId: null,
sendAsset: 'USDC',
sendAmount: null,
- receiveAsset: 'BOUND',
+ receiveAsset: 'BOND',
receiveAmount: null,
})
@@ -278,7 +278,7 @@ function resetForm() {
form.receiverOrganizationId = null
form.sendAsset = 'USDC'
form.sendAmount = null
- form.receiveAsset = 'BOUND'
+ form.receiveAsset = 'BOND'
form.receiveAmount = null
}
From 47faac617cb021340078f98aef7d440c3286a4c2 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 03:16:32 +0800
Subject: [PATCH 27/33] feat(TradeVisual): enhance asset display by adding
asset names and symbols
---
src/components/TradeVisual.vue | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/components/TradeVisual.vue b/src/components/TradeVisual.vue
index 60906a4..66f65a6 100644
--- a/src/components/TradeVisual.vue
+++ b/src/components/TradeVisual.vue
@@ -11,12 +11,14 @@
{{ sendLabel }}
- {{ formatAmount(sendAmount) }} {{ sendAsset }}
+ {{ getAssetName(sendAsset) }}
+ {{ formatAmount(sendAmount) }} {{ getAssetSymbol(sendAsset) }}
{{ receiveLabel }}
- {{ formatAmount(receiveAmount) }} {{ receiveAsset }}
+ {{ getAssetName(receiveAsset) }}
+ {{ formatAmount(receiveAmount) }} {{ getAssetSymbol(receiveAsset) }}
@@ -32,6 +34,7 @@
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 543e5dd..f2d6d7e 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -396,5 +396,70 @@
"close": "Close",
"retry": "Retry"
}
+ },
+ "transactions": {
+ "title": "Transactions",
+ "subtitle": "View all platform transactions and track settlement status in real time",
+ "filter": {
+ "all": "All Transactions",
+ "related": "Related to Me"
+ },
+ "table": {
+ "id": "Transaction ID",
+ "createdBy": "Submitted By",
+ "sender": "Sender",
+ "send": "Sent Asset",
+ "receiver": "Receiver",
+ "receive": "Received Asset",
+ "status": "Status",
+ "chainId": "Chain",
+ "windowId": "Settlement Window",
+ "createdAt": "Created At",
+ "settledAt": "Settled At",
+ "operation": "Action"
+ },
+ "status": {
+ "submitted": "Submitted",
+ "settled": "Settled",
+ "failed": "Failed"
+ },
+ "action": {
+ "view": "View"
+ },
+ "empty": "No transactions yet",
+ "msg": {
+ "fetchFailed": "Failed to fetch transactions"
+ }
+ },
+ "transactionDetail": {
+ "title": "Transaction Detail",
+ "subtitle": "View the full details and settlement status of this transaction",
+ "back": "Back to Transactions",
+ "parties": "Parties",
+ "basicInfo": "Basic Information",
+ "hashInfo": "On-chain Hashes",
+ "copy": "Copy",
+ "copySuccess": "{label} copied",
+ "copyFailed": "Copy failed",
+ "notFound": "Transaction not found or not accessible",
+ "fields": {
+ "id": "Transaction ID",
+ "status": "Status",
+ "createdBy": "Submitted By",
+ "sender": "Sender",
+ "receiver": "Receiver",
+ "send": "Send",
+ "receive": "Receive",
+ "chainId": "Chain",
+ "windowId": "Settlement Window",
+ "createdAt": "Created At",
+ "settledAt": "Settled At",
+ "failureReason": "Failure Reason",
+ "submissionHash": "Submission Hash",
+ "settlementHash": "Settlement Hash"
+ },
+ "msg": {
+ "fetchFailed": "Failed to fetch transaction detail"
+ }
}
}
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index fa8fac8..87d312c 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -394,5 +394,70 @@
"close": "关闭",
"retry": "重试"
}
+ },
+ "transactions": {
+ "title": "交易",
+ "subtitle": "查看平台全部交易记录,实时追踪结算状态",
+ "filter": {
+ "all": "全部交易",
+ "related": "与我相关"
+ },
+ "table": {
+ "id": "交易 ID",
+ "createdBy": "提交机构",
+ "sender": "发送方",
+ "send": "发送资产",
+ "receiver": "接收方",
+ "receive": "接收资产",
+ "status": "状态",
+ "chainId": "区块链网络",
+ "windowId": "结算窗口",
+ "createdAt": "创建时间",
+ "settledAt": "结算时间",
+ "operation": "操作"
+ },
+ "status": {
+ "submitted": "已提交",
+ "settled": "已结算",
+ "failed": "结算失败"
+ },
+ "action": {
+ "view": "查看"
+ },
+ "empty": "暂无交易记录",
+ "msg": {
+ "fetchFailed": "获取交易记录失败"
+ }
+ },
+ "transactionDetail": {
+ "title": "交易详情",
+ "subtitle": "查看该笔交易的完整信息与结算状态",
+ "back": "返回交易列表",
+ "parties": "交易双方",
+ "basicInfo": "基本信息",
+ "hashInfo": "链上哈希",
+ "copy": "复制",
+ "copySuccess": "{label} 已复制",
+ "copyFailed": "复制失败",
+ "notFound": "交易记录不存在或无权查看",
+ "fields": {
+ "id": "交易 ID",
+ "status": "状态",
+ "createdBy": "提交机构",
+ "sender": "发送方",
+ "receiver": "接收方",
+ "send": "发送",
+ "receive": "接收",
+ "chainId": "区块链网络",
+ "windowId": "结算窗口",
+ "createdAt": "创建时间",
+ "settledAt": "结算时间",
+ "failureReason": "失败原因",
+ "submissionHash": "提交交易哈希",
+ "settlementHash": "结算交易哈希"
+ },
+ "msg": {
+ "fetchFailed": "获取交易详情失败"
+ }
}
}
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index d5d26ba..4c2d55e 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -394,5 +394,70 @@
"close": "關閉",
"retry": "重試"
}
+ },
+ "transactions": {
+ "title": "交易",
+ "subtitle": "查看平台全部交易記錄,即時追蹤結算狀態",
+ "filter": {
+ "all": "全部交易",
+ "related": "與我相關"
+ },
+ "table": {
+ "id": "交易 ID",
+ "createdBy": "提交機構",
+ "sender": "發送方",
+ "send": "發送資產",
+ "receiver": "接收方",
+ "receive": "接收資產",
+ "status": "狀態",
+ "chainId": "區塊鏈網路",
+ "windowId": "結算窗口",
+ "createdAt": "建立時間",
+ "settledAt": "結算時間",
+ "operation": "操作"
+ },
+ "status": {
+ "submitted": "已提交",
+ "settled": "已結算",
+ "failed": "結算失敗"
+ },
+ "action": {
+ "view": "查看"
+ },
+ "empty": "暫無交易記錄",
+ "msg": {
+ "fetchFailed": "獲取交易記錄失敗"
+ }
+ },
+ "transactionDetail": {
+ "title": "交易詳情",
+ "subtitle": "查看該筆交易的完整信息與結算狀態",
+ "back": "返回交易列表",
+ "parties": "交易雙方",
+ "basicInfo": "基本信息",
+ "hashInfo": "鏈上哈希",
+ "copy": "複製",
+ "copySuccess": "{label} 已複製",
+ "copyFailed": "複製失敗",
+ "notFound": "交易記錄不存在或無權查看",
+ "fields": {
+ "id": "交易 ID",
+ "status": "狀態",
+ "createdBy": "提交機構",
+ "sender": "發送方",
+ "receiver": "接收方",
+ "send": "發送",
+ "receive": "接收",
+ "chainId": "區塊鏈網路",
+ "windowId": "結算窗口",
+ "createdAt": "建立時間",
+ "settledAt": "結算時間",
+ "failureReason": "失敗原因",
+ "submissionHash": "提交交易哈希",
+ "settlementHash": "結算交易哈希"
+ },
+ "msg": {
+ "fetchFailed": "獲取交易詳情失敗"
+ }
}
}
diff --git a/src/router/index.js b/src/router/index.js
index bb9ea7e..e97dcda 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -46,11 +46,16 @@ const routes = computed(() => [
meta: { title: t('transactions.title') },
component: () => import('@/views/TransactionsView.vue'),
},
+ {
+ path: 'transactions/:id',
+ meta: { title: t('transactionDetail.title') },
+ component: () => import('@/views/TransactionDetailView.vue'),
+ },
{
path: 'account',
meta: { title: t('account.title') },
component: () => import('@/views/AccountView.vue'),
- }
+ },
],
},
])
diff --git a/src/views/TransactionDetailView.vue b/src/views/TransactionDetailView.vue
new file mode 100644
index 0000000..7639867
--- /dev/null
+++ b/src/views/TransactionDetailView.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
diff --git a/src/views/TransactionsView.vue b/src/views/TransactionsView.vue
new file mode 100644
index 0000000..e435a89
--- /dev/null
+++ b/src/views/TransactionsView.vue
@@ -0,0 +1,215 @@
+
+
+
+
+
+
+
+
+
+ {{ t('transactions.filter.all') }}
+ {{ t('transactions.filter.related') }}
+
+
+
+
+
+ {{ formatOrganization(row.createdBy) }}
+
+
+ {{ formatOrganization(row.senderOrganization) }}
+
+
+ {{ formatAmount(row.send?.amount) }} {{ row.send?.asset?.symbol }}
+
+
+ {{ formatOrganization(row.receiverOrganization) }}
+
+
+ {{ formatAmount(row.receive?.amount) }} {{ row.receive?.asset?.symbol }}
+
+
+
+ {{ t(`transactions.status.${row.status}`) }}
+
+
+
+ {{ formatDateTime(row.createdAt) }}
+
+
+ {{ row.settledAt ? formatDateTime(row.settledAt) : '-' }}
+
+
+
+ {{ t('transactions.action.view') }}
+
+
+
+
+
+
+
+
+
+
+
From 9582d74c8742277852baff8b5b1311ee3a509863 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 04:13:59 +0800
Subject: [PATCH 29/33] feat(Verify): add transaction verification feature with
UI and localization
---
src/components/SiderBar.vue | 6 +
src/components/TransactionDetailPanel.vue | 300 +++++++++++++---------
src/i18n/locales/en-US.json | 12 +-
src/i18n/locales/zh-CN.json | 12 +-
src/i18n/locales/zh-TW.json | 12 +-
src/router/index.js | 5 +
src/views/VerifyView.vue | 154 +++++++++++
7 files changed, 372 insertions(+), 129 deletions(-)
create mode 100644 src/views/VerifyView.vue
diff --git a/src/components/SiderBar.vue b/src/components/SiderBar.vue
index 6e4837a..58bde63 100644
--- a/src/components/SiderBar.vue
+++ b/src/components/SiderBar.vue
@@ -41,6 +41,12 @@ const menuItems = computed(() => [
icon: 'tree-list',
path: '/transactions',
},
+ {
+ value: 'verify',
+ label: t('menu.verify'),
+ icon: 'verified',
+ path: '/verify',
+ },
{
value: 'account',
label: t('menu.account'),
diff --git a/src/components/TransactionDetailPanel.vue b/src/components/TransactionDetailPanel.vue
index e99a871..5aa063a 100644
--- a/src/components/TransactionDetailPanel.vue
+++ b/src/components/TransactionDetailPanel.vue
@@ -11,132 +11,145 @@
-
-
-
{{ t('transactionDetail.parties') }}
-
-
+
+
+
+ {{ t('verify.stamp') }}
-
-
{{ t('transactionDetail.basicInfo') }}
-
-
- {{ t('transactionDetail.fields.id') }}
- #{{ transaction.id }}
-
-
- {{ t('transactionDetail.fields.status') }}
-
-
- {{ t(`transactions.status.${transaction.status}`) }}
-
-
-
-
- {{ t('transactionDetail.fields.createdBy') }}
- {{ formatOrganization(transaction.createdBy) }}
-
-
- {{ t('transactionDetail.fields.chainId') }}
- {{ transaction.chainId }}
-
-
- {{ t('transactionDetail.fields.windowId') }}
- {{ transaction.windowId }}
-
-
- {{ t('transactionDetail.fields.createdAt') }}
- {{ formatDateTime(transaction.createdAt) }}
-
-
- {{ t('transactionDetail.fields.settledAt') }}
-
- {{ transaction.settledAt ? formatDateTime(transaction.settledAt) : '-' }}
-
-
-
- {{
- t('transactionDetail.fields.failureReason')
- }}
- {{ transaction.failureReason || '-' }}
-
+
+
+
{{ t('transactionDetail.parties') }}
+
+
-
-
-
{{ t('transactionDetail.hashInfo') }}
-
-
-
{{
- t('transactionDetail.fields.submissionHash')
- }}
-
- {{ transaction.submissionHash || '-' }}
-
-
+ {{ t('transactionDetail.basicInfo') }}
+
+
+ {{ t('transactionDetail.fields.id') }}
+ #{{ transaction.id }}
+
+
+ {{ t('transactionDetail.fields.status') }}
+
+
-
-
-
-
-
-
+ {{ t(`transactions.status.${transaction.status}`) }}
+
+
+
+
+ {{ t('transactionDetail.fields.createdBy') }}
+ {{
+ formatOrganization(transaction.createdBy)
+ }}
+
+
+ {{ t('transactionDetail.fields.chainId') }}
+ {{ transaction.chainId }}
+
+
+ {{ t('transactionDetail.fields.windowId') }}
+ {{ transaction.windowId }}
+
+
+ {{ t('transactionDetail.fields.createdAt') }}
+ {{ formatDateTime(transaction.createdAt) }}
+
+
+ {{ t('transactionDetail.fields.settledAt') }}
+
+ {{ transaction.settledAt ? formatDateTime(transaction.settledAt) : '-' }}
+
+
+
+ {{
+ t('transactionDetail.fields.failureReason')
+ }}
+ {{ transaction.failureReason || '-' }}
+
-
- {{
- t('transactionDetail.fields.settlementHash')
- }}
-
- {{ transaction.settlementHash || '-' }}
-
-
-
-
-
-
-
-
+
+
+
+
{{ t('transactionDetail.hashInfo') }}
+
+
+ {{
+ t('transactionDetail.fields.submissionHash')
+ }}
+
+ {{ transaction.submissionHash || '-' }}
+
+
+
+
+
+
+
+
+
+
+ {{
+ t('transactionDetail.fields.settlementHash')
+ }}
+
+ {{ transaction.settlementHash || '-' }}
+
+
+
+
+
+
+
+
+
@@ -145,20 +158,23 @@
From 36ab500798b06847179e6119f4b006b9d7ef32d7 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 04:18:39 +0800
Subject: [PATCH 30/33] feat(VerifyView): enhance input and button size for
better usability
---
src/views/VerifyView.vue | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/views/VerifyView.vue b/src/views/VerifyView.vue
index 4d4cb91..eb6871d 100644
--- a/src/views/VerifyView.vue
+++ b/src/views/VerifyView.vue
@@ -12,10 +12,11 @@
-
+
{{ t('verify.button') }}
From 6b9ca93a50bfaff3148ea0b7cbabd7809a4d8cd5 Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 11:47:27 +0800
Subject: [PATCH 31/33] feat(TransactionDetailPanel, VerifyView): adjust layout
and styling for improved visibility of transaction status
---
src/components/TransactionDetailPanel.vue | 7 +++++--
src/views/VerifyView.vue | 6 +++++-
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/components/TransactionDetailPanel.vue b/src/components/TransactionDetailPanel.vue
index 5aa063a..77df41c 100644
--- a/src/components/TransactionDetailPanel.vue
+++ b/src/components/TransactionDetailPanel.vue
@@ -262,7 +262,10 @@ onMounted(() => {
align-items: center;
justify-content: center;
gap: 0.75rem;
- margin: 0 auto 1.5rem;
+ position: absolute;
+ z-index: 1;
+ top: 1.5rem;
+ left: 50%;
width: fit-content;
padding: 0.75rem 2.5rem;
border: 6px double var(--td-success-color);
@@ -272,7 +275,7 @@ onMounted(() => {
font-weight: 700;
letter-spacing: 0.3em;
text-transform: uppercase;
- transform: rotate(-4deg);
+ transform: translateX(-50%) rotate(-4deg);
opacity: 0.85;
user-select: none;
pointer-events: none;
diff --git a/src/views/VerifyView.vue b/src/views/VerifyView.vue
index eb6871d..75a28a4 100644
--- a/src/views/VerifyView.vue
+++ b/src/views/VerifyView.vue
@@ -21,7 +21,7 @@
-
+
@@ -152,4 +152,8 @@ async function verify() {
.verify-card__result {
margin-top: 1.5rem;
}
+
+.verify-card__result.fail {
+ padding: 4rem 0;
+}
From 46b4cf0cd0f5bd455d91a6ea002a3857a83c1c8c Mon Sep 17 00:00:00 2001
From: Nero978
Date: Sun, 23 Aug 2026 11:57:33 +0800
Subject: [PATCH 32/33] feat(TransactionDetailPanel): add transaction progress
display with localization
---
src/components/TransactionDetailPanel.vue | 58 ++++++++++++++++++++++-
src/i18n/locales/en-US.json | 6 +++
src/i18n/locales/zh-CN.json | 6 +++
src/i18n/locales/zh-TW.json | 6 +++
4 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/src/components/TransactionDetailPanel.vue b/src/components/TransactionDetailPanel.vue
index 77df41c..1641ba4 100644
--- a/src/components/TransactionDetailPanel.vue
+++ b/src/components/TransactionDetailPanel.vue
@@ -39,6 +39,36 @@
/>
+
+
{{ t('transactionDetail.progress') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ t('transactionDetail.basicInfo') }}
@@ -159,7 +189,12 @@