diff --git a/apps/admin-web/src/i18n/messages/en-US.ts b/apps/admin-web/src/i18n/messages/en-US.ts index 9113e8c..7e42a9f 100644 --- a/apps/admin-web/src/i18n/messages/en-US.ts +++ b/apps/admin-web/src/i18n/messages/en-US.ts @@ -137,6 +137,9 @@ const enUS = { userFallback: 'Admin', logout: 'Logout', planFallback: 'Free Plan', + openNavigation: 'Open navigation', + collapseNavigation: 'Collapse navigation', + expandNavigation: 'Expand navigation', aiUsageTitle: 'AI Point Usage', aiUsageRecent: 'Recent Usage', aiUsageEmpty: 'No AI point usage yet', diff --git a/apps/admin-web/src/i18n/messages/zh-CN.ts b/apps/admin-web/src/i18n/messages/zh-CN.ts index 1d00783..e97a4fc 100644 --- a/apps/admin-web/src/i18n/messages/zh-CN.ts +++ b/apps/admin-web/src/i18n/messages/zh-CN.ts @@ -134,6 +134,9 @@ const zhCN = { userFallback: "管理员", logout: "退出", planFallback: "免费版", + openNavigation: "打开导航", + collapseNavigation: "收起导航", + expandNavigation: "展开导航", aiUsageTitle: "AI 点数明细", aiUsageRecent: "最近消耗", aiUsageEmpty: "暂无 AI 点数流水", diff --git a/apps/admin-web/src/layouts/AppShell.vue b/apps/admin-web/src/layouts/AppShell.vue index 9728dbb..1c3a980 100644 --- a/apps/admin-web/src/layouts/AppShell.vue +++ b/apps/admin-web/src/layouts/AppShell.vue @@ -1,18 +1,28 @@ - + - {{ t('app.name') }} + {{ t('app.name') }} + 省 - + @@ -251,12 +330,27 @@ async function handleLogout(): Promise { + + + + + {{ pageTitle }} + { + + + + {{ t('app.name') }} + + + + + + + + + {{ item.label }} + + + + + + + + {{ item.label }} + + + + + @@ -371,11 +498,22 @@ async function handleLogout(): Promise { background: #fff; border-right: 1px solid #f0f0f0; z-index: 10; + transition: + width 0.2s ease, + flex-basis 0.2s ease, + max-width 0.2s ease, + min-width 0.2s ease; } .admin-main-layout { margin-left: 250px; isolation: isolate; + min-width: 0; + transition: margin-left 0.2s ease; +} + +.admin-main-layout--collapsed { + margin-left: 80px; } .admin-main-layout--blocked { @@ -395,6 +533,28 @@ async function handleLogout(): Promise { font-weight: 800; font-size: 16px; letter-spacing: 0.05em; + white-space: nowrap; + transition: + margin 0.2s ease, + width 0.2s ease; +} + +.admin-brand__short { + display: none; + letter-spacing: 0; +} + +.admin-sider--collapsed .admin-brand { + width: 40px; + margin-inline: auto; +} + +.admin-sider--collapsed .admin-brand__full { + display: none; +} + +.admin-sider--collapsed .admin-brand__short { + display: inline; } .admin-menu { @@ -402,14 +562,23 @@ async function handleLogout(): Promise { padding-bottom: 32px; } +.admin-sider--collapsed :deep(.ant-menu-item-group-title) { + height: 12px; + padding: 0; + overflow: hidden; + color: transparent; +} + .admin-header { position: sticky; top: 0; background: #fff; - padding: 0 24px; + height: 64px; + padding: 0 24px 0 12px; display: flex; align-items: center; justify-content: space-between; + gap: 12px; z-index: 100; box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); } @@ -418,6 +587,34 @@ async function handleLogout(): Promise { justify-content: flex-end; } +.admin-shell-trigger.ant-btn { + flex: 0 0 auto; + width: 40px; + height: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + color: #595959; + border-radius: 8px; +} + +.admin-shell-trigger.ant-btn:hover { + color: #1677ff; + background: #f0f8ff; +} + +.admin-mobile-title { + display: none; + min-width: 0; + flex: 1; + overflow: hidden; + color: #141414; + font-size: 16px; + font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; +} + .admin-header-breadcrumb { min-width: 0; flex: 1; @@ -579,6 +776,7 @@ async function handleLogout(): Promise { z-index: 0; margin: 24px; min-height: auto; + min-width: 0; } .admin-content--blocked { @@ -621,4 +819,68 @@ async function handleLogout(): Promise { line-height: 1.6; text-align: center; } + +@media (max-width: 991px) { + .admin-sider { + display: none; + } + + .admin-main-layout, + .admin-main-layout--collapsed { + margin-left: 0; + } + + .admin-header { + padding: 0 12px; + } + + .admin-header-breadcrumb { + display: none; + } + + .admin-mobile-title { + display: block; + } + + .admin-header-actions { + gap: 8px; + margin-left: 0; + } + + .quota-pill { + display: none; + } + + .admin-content { + margin: 16px; + } + + .admin-content--blocked { + margin: 0; + } +} + +@media (max-width: 576px) { + .admin-header { + height: 56px; + } + + .admin-shell-trigger.ant-btn { + width: 36px; + height: 36px; + } + + .admin-content { + margin: 12px; + } + + .user-name, + .user-dropdown-icon { + display: none; + } + + .user-dropdown-trigger { + padding: 4px; + } +} diff --git a/apps/admin-web/src/styles.css b/apps/admin-web/src/styles.css index 8508455..2116dd2 100644 --- a/apps/admin-web/src/styles.css +++ b/apps/admin-web/src/styles.css @@ -23,10 +23,15 @@ html, body, #app { min-height: 100vh; + width: 100%; margin: 0; padding: 0; } +body { + overflow-x: hidden; +} + /* Typography Utilities */ .eyebrow { margin: 0 0 8px; @@ -157,6 +162,15 @@ body, .app-root { display: flex; min-height: 100vh; + width: 100%; + min-width: 0; +} + +.ant-app, +.ant-layout, +.ant-layout-content, +.ant-layout .ant-layout { + min-width: 0; } /* Workspace Layout Specifics */ @@ -306,3 +320,160 @@ body, padding: 0 20px !important; font-weight: 500 !important; } + +.ant-drawer-content-wrapper { + max-width: 100vw; +} + +.ant-table-wrapper { + max-width: 100%; +} + +.ant-table-wrapper .ant-table-container, +.ant-table-wrapper .ant-table-content, +.ant-table-wrapper .ant-table-body { + max-width: 100%; + scrollbar-width: thin; +} + +.ant-table-wrapper .ant-table-content, +.ant-table-wrapper .ant-table-body { + -webkit-overflow-scrolling: touch; +} + +@media (max-width: 768px) { + .section-heading, + .page-title-card__header, + .page-title-card__actions, + .table-actions-row, + [class$='__header'], + [class$='__table-head'], + [class*='__toolbar'], + [class*='-toolbar'], + [class*='__filters-inline'], + [class*='__filters'] { + flex-wrap: wrap; + } + + .section-heading, + .page-title-card__header { + align-items: stretch; + gap: 16px; + } + + .section-heading { + margin-bottom: 16px; + } + + .page-title-card__header { + padding: 16px; + } + + .page-title-card__actions { + width: 100%; + } + + .page-title-card__actions > * { + min-width: 0; + } + + .page-title-card__copy h2 { + font-size: 18px; + } + + .ant-card-body { + padding: 16px !important; + } + + .ant-table-wrapper { + display: block; + width: 100%; + overflow-x: auto; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + } + + .ant-table-wrapper .ant-spin-nested-loading, + .ant-table-wrapper .ant-spin-container, + .ant-table-wrapper .ant-table, + .ant-table-wrapper .ant-table-container { + min-width: 0; + } + + .ant-tabs-nav { + margin-bottom: 14px !important; + } + + .ant-tabs-nav-wrap { + overflow: auto !important; + scrollbar-width: none; + } + + .ant-tabs-nav-wrap::-webkit-scrollbar { + display: none; + } + + .ant-tabs-nav-list { + min-width: max-content; + } + + .ant-form, + .ant-form-item, + .ant-picker, + .ant-select, + .ant-input, + .ant-input-number, + .ant-input-affix-wrapper, + .ant-space, + [class*='__filter'], + [class*='filter-item'] { + max-width: 100%; + } + + .ant-form .ant-row, + .ant-space, + [class*='__filters'], + [class*='__filters-inline'] { + row-gap: 12px; + } + + .ant-space { + flex-wrap: wrap; + } + + .ant-modal { + max-width: calc(100vw - 24px) !important; + margin: 12px auto !important; + } + + .ant-modal-root .ant-modal-wrap { + padding: 0 12px !important; + } + + .ant-modal-body { + max-height: calc(100dvh - 180px); + overflow: auto; + } +} + +@media (max-width: 576px) { + .login-screen__form-container { + padding: 40px 20px; + } + + .ant-card-body { + padding: 14px !important; + } + + .ant-table-wrapper { + font-size: 13px; + } + + .ant-pagination { + justify-content: center; + } + + .table-actions-row { + justify-content: flex-start; + } +} diff --git a/apps/admin-web/src/views/TemplateWizardView.vue b/apps/admin-web/src/views/TemplateWizardView.vue index 5960cd9..9312eaa 100644 --- a/apps/admin-web/src/views/TemplateWizardView.vue +++ b/apps/admin-web/src/views/TemplateWizardView.vue @@ -2931,20 +2931,31 @@ function onStructureDragEnd(): void {