feat(web): 移动端适配

- 侧边栏在窄屏改为抽屉:汉堡按钮唤起、遮罩点击关闭、切换路由自动收起
- 页头纵向排列,操作按钮与筛选控件撑满一行
- 对话框改用视口百分比宽度,表单标签改为顶部对齐,内容区限高可滚动
- 表格隐藏次要列并把操作列固定在右侧,仍可横向滚动查看全部
- 仪表盘倒计时环与信息上下排列,统计卡改两列
- 分页器在窄屏收缩为精简布局
- 输入框字号提到 16px,避免 iOS Safari 聚焦时自动缩放
- 新增 useIsMobile composable 处理 CSS 覆盖不到的部分

顺带修复汉堡按钮在桌面端未隐藏:.menu-btn 与后声明的 .icon-btn
特异性相同被覆盖,改用 .icon-btn.menu-btn 复合选择器。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mei
2026-07-26 22:57:52 +08:00
co-authored by Claude Fable 5
parent 0d766020bc
commit f8c6115737
10 changed files with 507 additions and 42 deletions
+29 -10
View File
@@ -8,6 +8,9 @@ import type { Account, Rule, Timer } from '@/api/types'
import { useMetaStore } from '@/stores/meta'
import { formatDateTime } from '@/utils/format'
import ConfigForm from '@/components/ConfigForm.vue'
import { useIsMobile } from '@/composables/useBreakpoint'
const isMobile = useIsMobile()
const metaStore = useMetaStore()
@@ -231,7 +234,7 @@ onMounted(async () => {
v-model="filterTimerId"
placeholder="按定时器筛选"
clearable
style="width: 200px"
class="filter-select"
>
<el-option v-for="t in timers" :key="t.id" :label="t.name" :value="t.id" />
</el-select>
@@ -244,28 +247,29 @@ onMounted(async () => {
</el-empty>
<el-card v-else class="table-card gb-rise">
<el-table :data="filteredRules">
<el-table-column prop="name" label="名称" min-width="130" />
<el-table-column label="类型" width="160">
<el-table :data="filteredRules" :size="isMobile ? 'small' : 'default'">
<el-table-column prop="name" label="名称" min-width="110" />
<el-table-column label="类型" :width="isMobile ? 120 : 160">
<template #default="{ row }">
<el-tag>{{ metaStore.ruleLabel(row.type) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="定时器" min-width="120">
<!-- 窄屏隐藏定时器/账号/创建时间,保留名称、类型与操作 -->
<el-table-column v-if="!isMobile" label="定时器" min-width="120">
<template #default="{ row }">{{ timerName(row.timer_id) }}</template>
</el-table-column>
<el-table-column label="账号" min-width="120">
<el-table-column v-if="!isMobile" label="账号" min-width="120">
<template #default="{ row }">{{ accountName(row.account_id) }}</template>
</el-table-column>
<el-table-column label="创建时间" width="170">
<el-table-column v-if="!isMobile" label="创建时间" width="170">
<template #default="{ row }">{{ formatDateTime(row.create_at) }}</template>
</el-table-column>
<el-table-column label="启用" width="80">
<el-table-column label="启用" :width="isMobile ? 60 : 80">
<template #default="{ row }">
<el-switch v-model="row.enabled" size="small" @change="toggleEnabled(row)" />
</template>
</el-table-column>
<el-table-column label="操作" width="240">
<el-table-column label="操作" :width="isMobile ? 200 : 240" fixed="right">
<template #default="{ row }">
<el-button
size="small"
@@ -284,7 +288,7 @@ onMounted(async () => {
<!-- 创建/编辑对话框 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px">
<el-form label-width="110px">
<el-form :label-width="isMobile ? 'auto' : '110px'" :label-position="isMobile ? 'top' : 'right'">
<el-form-item label="规则名称" required>
<el-input v-model="form.name" placeholder="给这条规则起个名字" maxlength="64" />
</el-form-item>
@@ -354,4 +358,19 @@ onMounted(async () => {
display: flex;
gap: 12px;
}
.filter-select {
width: 200px;
}
@media (max-width: 768px) {
.header-tools {
flex-wrap: wrap;
gap: 10px;
}
.filter-select {
width: 100%;
}
}
</style>