fix(frontend): 修复移动端菜单栏和使用记录页面 UI 问题
- 修复移动端无法打开菜单栏的问题 - 在 app.ts 中添加 mobileOpen 状态管理 - 修复 AppHeader.vue 中移动端菜单按钮调用错误的方法 - 修复 AppSidebar.vue 使用本地 ref 而非全局状态的问题 - 添加移动端菜单自动关闭功能 - 点击菜单项后自动关闭侧边栏 - 添加 150ms 延迟以显示关闭动画 - 修复使用记录页面总消费卡片溢出问题 - 调整总消费卡片布局,将删除线价格移至说明行 - 添加 min-w-0 flex-1 防止内容溢出 - 保持与其他卡片高度一致 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -207,7 +207,7 @@ const pageDescription = computed(() => {
|
||||
});
|
||||
|
||||
function toggleMobileSidebar() {
|
||||
appStore.toggleSidebar();
|
||||
appStore.toggleMobileSidebar();
|
||||
}
|
||||
|
||||
function toggleDropdown() {
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
class="sidebar-link mb-1"
|
||||
:class="{ 'sidebar-link-active': isActive(item.path) }"
|
||||
:title="sidebarCollapsed ? item.label : undefined"
|
||||
@click="handleMenuItemClick"
|
||||
>
|
||||
<component :is="item.icon" class="w-5 h-5 flex-shrink-0" />
|
||||
<transition name="fade">
|
||||
@@ -58,6 +59,7 @@
|
||||
class="sidebar-link mb-1"
|
||||
:class="{ 'sidebar-link-active': isActive(item.path) }"
|
||||
:title="sidebarCollapsed ? item.label : undefined"
|
||||
@click="handleMenuItemClick"
|
||||
>
|
||||
<component :is="item.icon" class="w-5 h-5 flex-shrink-0" />
|
||||
<transition name="fade">
|
||||
@@ -77,6 +79,7 @@
|
||||
class="sidebar-link mb-1"
|
||||
:class="{ 'sidebar-link-active': isActive(item.path) }"
|
||||
:title="sidebarCollapsed ? item.label : undefined"
|
||||
@click="handleMenuItemClick"
|
||||
>
|
||||
<component :is="item.icon" class="w-5 h-5 flex-shrink-0" />
|
||||
<transition name="fade">
|
||||
@@ -142,9 +145,9 @@ const appStore = useAppStore();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
const sidebarCollapsed = computed(() => appStore.sidebarCollapsed);
|
||||
const mobileOpen = computed(() => appStore.mobileOpen);
|
||||
const isAdmin = computed(() => authStore.isAdmin);
|
||||
const isDark = ref(document.documentElement.classList.contains('dark'));
|
||||
const mobileOpen = ref(false);
|
||||
|
||||
// Site settings
|
||||
const siteName = ref('Sub2API');
|
||||
@@ -303,7 +306,15 @@ function toggleTheme() {
|
||||
}
|
||||
|
||||
function closeMobile() {
|
||||
mobileOpen.value = false;
|
||||
appStore.setMobileOpen(false);
|
||||
}
|
||||
|
||||
function handleMenuItemClick() {
|
||||
if (mobileOpen.value) {
|
||||
setTimeout(() => {
|
||||
appStore.setMobileOpen(false);
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
function isActive(path: string): boolean {
|
||||
|
||||
@@ -12,6 +12,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
// ==================== State ====================
|
||||
|
||||
const sidebarCollapsed = ref<boolean>(false);
|
||||
const mobileOpen = ref<boolean>(false);
|
||||
const loading = ref<boolean>(false);
|
||||
const toasts = ref<Toast[]>([]);
|
||||
|
||||
@@ -50,6 +51,21 @@ export const useAppStore = defineStore('app', () => {
|
||||
sidebarCollapsed.value = collapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle mobile sidebar open state
|
||||
*/
|
||||
function toggleMobileSidebar(): void {
|
||||
mobileOpen.value = !mobileOpen.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mobile sidebar open state explicitly
|
||||
* @param open - Whether mobile sidebar should be open
|
||||
*/
|
||||
function setMobileOpen(open: boolean): void {
|
||||
mobileOpen.value = open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global loading state
|
||||
* @param isLoading - Whether app is in loading state
|
||||
@@ -257,6 +273,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
return {
|
||||
// State
|
||||
sidebarCollapsed,
|
||||
mobileOpen,
|
||||
loading,
|
||||
toasts,
|
||||
|
||||
@@ -275,6 +292,8 @@ export const useAppStore = defineStore('app', () => {
|
||||
// Actions
|
||||
toggleSidebar,
|
||||
setSidebarCollapsed,
|
||||
toggleMobileSidebar,
|
||||
setMobileOpen,
|
||||
setLoading,
|
||||
showToast,
|
||||
showSuccess,
|
||||
|
||||
@@ -43,13 +43,12 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-xs font-medium text-gray-500 dark:text-gray-400">{{ t('usage.totalCost') }}</p>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<p class="text-xl font-bold text-green-600 dark:text-green-400">${{ (usageStats?.total_actual_cost || 0).toFixed(4) }}</p>
|
||||
<span class="text-xs text-gray-400 dark:text-gray-500 line-through">${{ (usageStats?.total_cost || 0).toFixed(4) }}</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('usage.actualCost') }} / {{ t('usage.standardCost') }}</p>
|
||||
<p class="text-xl font-bold text-green-600 dark:text-green-400">${{ (usageStats?.total_actual_cost || 0).toFixed(4) }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('usage.actualCost') }} / <span class="line-through">${{ (usageStats?.total_cost || 0).toFixed(4) }}</span> {{ t('usage.standardCost') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,13 +43,12 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-xs font-medium text-gray-500 dark:text-gray-400">{{ t('usage.totalCost') }}</p>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<p class="text-xl font-bold text-green-600 dark:text-green-400">${{ (usageStats?.total_actual_cost || 0).toFixed(4) }}</p>
|
||||
<span class="text-xs text-gray-400 dark:text-gray-500 line-through">${{ (usageStats?.total_cost || 0).toFixed(4) }}</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('usage.actualCost') }} / {{ t('usage.standardCost') }}</p>
|
||||
<p class="text-xl font-bold text-green-600 dark:text-green-400">${{ (usageStats?.total_actual_cost || 0).toFixed(4) }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('usage.actualCost') }} / <span class="line-through">${{ (usageStats?.total_cost || 0).toFixed(4) }}</span> {{ t('usage.standardCost') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user