-
+
+
+
+
+
请先登录
+
登录后才能访问 Web 端页面和生产运营数据。
+
立即登录
+
+
@@ -19,10 +27,13 @@ import { useTemplateRef, watch, provide, onMounted } from 'vue';
import layoutHeader from "./components/header.vue";
import layoutFooter from "./components/footer.vue";
import { useMemberStore } from '@/stores/member';
+import { useConfigStore } from '@/stores/config';
+import { Icon } from '~/components/icon';
const route = useRoute();
const mainScrollbarRef = useTemplateRef('mainScrollbarRef');
const memberStore = useMemberStore();
+const configStore = useConfigStore();
// 计算滚动区域高度
const calcHeight = (headerHeight: number) => {
@@ -162,6 +173,41 @@ provide('mainScrollbarRef', mainScrollbarRef);
right: 0;
}
+.auth-required {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: var(--content-min-height, 500px);
+ padding: 32px 20px;
+ background: var(--el-bg-color-page);
+}
+
+.auth-required-card {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: min(420px, 100%);
+ padding: 42px 28px;
+ border: 1px solid var(--el-border-color-light);
+ border-radius: 16px;
+ background: var(--el-bg-color);
+ box-shadow: 0 8px 28px rgb(31 56 88 / 8%);
+ text-align: center;
+}
+
+.auth-required-card h2 {
+ margin: 18px 0 8px;
+ color: var(--el-text-color-primary);
+ font-size: 22px;
+}
+
+.auth-required-card p {
+ margin: 0 0 24px;
+ color: var(--el-text-color-secondary);
+ font-size: 14px;
+}
+
/* 页面特定样式 */
.page-index {
.layout-content {
@@ -248,4 +294,4 @@ provide('mainScrollbarRef', mainScrollbarRef);
}
}
}
-
\ No newline at end of file
+
diff --git a/frontend/web/app/middleware/auth.global.ts b/frontend/web/app/middleware/auth.global.ts
new file mode 100644
index 0000000..6f30664
--- /dev/null
+++ b/frontend/web/app/middleware/auth.global.ts
@@ -0,0 +1,16 @@
+import { useMemberStore } from '~/stores/member'
+import { useConfigStore } from '~/stores/config'
+
+export default defineNuxtRouteMiddleware(async () => {
+ if (import.meta.server) return
+
+ const memberStore = useMemberStore()
+ const configStore = useConfigStore()
+
+ // 等待后台配置加载完成后再判断,避免关闭登录要求时误弹登录框
+ await configStore.getWebGroupConfigs()
+
+ if (configStore.siteSetting.require_login && !memberStore.token) {
+ memberStore.logOpen()
+ }
+})
diff --git a/frontend/web/app/pages/index.vue b/frontend/web/app/pages/index.vue
index eb64d20..3572d6e 100644
--- a/frontend/web/app/pages/index.vue
+++ b/frontend/web/app/pages/index.vue
@@ -1,399 +1,101 @@
-
-
-
\ No newline at end of file
+.home-page { min-height: 100%; background: #f5f7fb; color: #18243a; }
+.home-shell { max-width: 1440px; margin: 0 auto; padding: 32px 40px 72px; }
+.hero-card { position: relative; display: flex; min-height: 330px; overflow: hidden; border-radius: 24px; background: linear-gradient(120deg, #132d5b 0%, #1d4c87 60%, #2875a7 100%); color: #fff; box-shadow: 0 16px 40px rgba(21, 52, 97, .16); }
+.hero-copy { position: relative; z-index: 1; max-width: 650px; padding: 52px 56px; }.eyebrow, .section-kicker { font-size: 11px; letter-spacing: .18em; font-weight: 700; color: #78c8ff; }.hero-copy h1 { margin: 18px 0 14px; font-size: clamp(30px, 4vw, 48px); line-height: 1.15; letter-spacing: -.03em; }.hero-copy p { max-width: 510px; margin: 0; color: rgba(255,255,255,.72); font-size: 16px; line-height: 1.8; }.hero-actions { display: flex; gap: 12px; margin-top: 32px; }.hero-actions :deep(.el-button) { border-radius: 10px; padding: 0 20px; }.hero-actions :deep(.el-button--default) { color: #fff; border-color: rgba(255,255,255,.28); background: rgba(255,255,255,.08); }
+.hero-visual { position: absolute; inset: 0 0 0 54%; }.orb { position: absolute; border-radius: 50%; }.orb-one { width: 330px; height: 330px; top: -70px; right: 70px; background: rgba(121, 213, 255, .14); }.orb-two { width: 220px; height: 220px; right: -30px; bottom: -80px; background: rgba(255, 255, 255, .1); }.hero-panel { position: absolute; top: 76px; right: 12%; width: 260px; padding: 24px; border: 1px solid rgba(255,255,255,.16); border-radius: 18px; background: rgba(8, 33, 75, .42); backdrop-filter: blur(12px); }.panel-topline, .panel-footer { display: flex; justify-content: space-between; align-items: center; color: rgba(255,255,255,.66); font-size: 12px; }.live-dot { color: #8df0bb; }.live-dot::before { content: ''; display: inline-block; width: 6px; height: 6px; margin-right: 5px; border-radius: 50%; background: #62e7a4; }.hero-panel strong { display: block; margin: 24px 0 14px; font-size: 52px; letter-spacing: -.06em; }.hero-panel strong span { margin-left: 3px; font-size: 24px; }.progress-track { height: 7px; overflow: hidden; border-radius: 5px; background: rgba(255,255,255,.14); }.progress-track i { display: block; height: 100%; border-radius: inherit; background: #75d5ff; }.panel-footer { margin-top: 12px; }.panel-footer span:last-child { color: #8df0bb; }
+.metric-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 18px; }.metric-card, .quick-card, .surface-card, .insight-banner { border: 1px solid #e7ebf3; background: #fff; box-shadow: 0 5px 18px rgba(28, 50, 86, .04); }.metric-card { display: flex; align-items: center; gap: 14px; padding: 20px; border-radius: 16px; }.metric-icon, .quick-icon { display: grid; place-items: center; flex: 0 0 auto; border-radius: 12px; }.metric-icon { width: 44px; height: 44px; font-size: 21px; }.metric-content { display: grid; gap: 4px; }.metric-content > span { color: #8490a5; font-size: 12px; }.metric-content strong { font-size: 26px; line-height: 1; letter-spacing: -.04em; }.metric-content small { font-size: 11px; }.up { color: #20aa6a; }.warning { color: #e88b2b; }.neutral { color: #8792a8; }.blue { color: #3a86f7; background: #eaf3ff; }.violet { color: #8063e8; background: #f0edff; }.orange { color: #e99532; background: #fff2df; }.green { color: #24a873; background: #e6f8f0; }
+.section-block { margin-top: 42px; }.section-heading, .card-heading { display: flex; align-items: end; justify-content: space-between; }.section-heading h2, .card-heading h2, .insight-banner h2 { margin: 7px 0 0; font-size: 22px; letter-spacing: -.02em; }.section-hint { color: #98a3b5; font-size: 13px; }.quick-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 18px; }.quick-card { position: relative; display: flex; align-items: center; gap: 14px; padding: 18px; border-radius: 15px; transition: transform .2s ease, box-shadow .2s ease; }.quick-card:hover { transform: translateY(-3px); box-shadow: 0 12px 26px rgba(28, 50, 86, .1); }.quick-icon { width: 42px; height: 42px; font-size: 20px; }.quick-card strong, .quick-card span { display: block; }.quick-card strong { font-size: 15px; }.quick-card span { margin-top: 5px; color: #8a95a8; font-size: 12px; }.arrow { margin-left: auto; color: #aab4c4; }
+.dashboard-grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: 16px; margin-top: 18px; }.surface-card { padding: 24px; border-radius: 16px; }.card-heading a { display: inline-flex; align-items: center; gap: 3px; color: #4b8bf5; font-size: 12px; }.process-list, .activity-list { margin-top: 22px; }.process-row + .process-row { margin-top: 22px; }.order-title { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }.order-title strong { font-size: 13px; }.order-title span { color: #8a95a8; font-size: 12px; }.process-track { height: 8px; overflow: hidden; border-radius: 6px; background: #edf1f6; }.process-track i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, #4b8bf5, #71c9f5); }.process-meta { display: flex; justify-content: space-between; margin-top: 7px; color: #8a95a8; font-size: 11px; }.process-meta b { color: #4b8bf5; }.activity-row { display: flex; align-items: flex-start; gap: 11px; }.activity-row + .activity-row { margin-top: 19px; }.activity-dot { width: 8px; height: 8px; margin-top: 5px; border-radius: 50%; box-shadow: 0 0 0 4px currentColor; opacity: .75; }.activity-row div { flex: 1; }.activity-row strong, .activity-row span { display: block; }.activity-row strong { font-size: 13px; }.activity-row span { margin-top: 4px; color: #8a95a8; font-size: 12px; }.activity-row time { color: #a5afbd; font-size: 11px; }
+.insight-banner { display: flex; align-items: center; justify-content: space-between; gap: 24px; margin-top: 18px; padding: 28px 32px; border-radius: 16px; background: linear-gradient(100deg, #f2f7ff, #fbfcff); }.insight-banner p { margin: 9px 0 0; color: #8490a5; font-size: 13px; }.insight-banner :deep(.el-button) { border-radius: 9px; }
+@media (max-width: 1100px) { .home-shell { padding: 24px; }.hero-card { min-height: 360px; }.hero-visual { opacity: .75; right: -80px; }.metric-grid, .quick-grid { grid-template-columns: repeat(2, 1fr); }.dashboard-grid { grid-template-columns: 1fr; } }
+@media (max-width: 640px) { .home-shell { padding: 16px 12px 48px; }.hero-card { min-height: 440px; }.hero-copy { padding: 34px 26px; }.hero-copy h1 { font-size: 32px; }.hero-copy p { font-size: 14px; }.hero-actions { flex-direction: column; align-items: flex-start; }.hero-visual { inset: auto 0 20px; height: 150px; opacity: .9; }.hero-panel { top: 10px; right: 26px; width: 220px; padding: 17px; }.hero-panel strong { margin: 13px 0 9px; font-size: 38px; }.metric-grid, .quick-grid { grid-template-columns: 1fr; }.metric-card { padding: 16px; }.section-block { margin-top: 32px; }.section-heading h2, .card-heading h2 { font-size: 19px; }.section-hint { display: none; }.surface-card { padding: 18px; }.insight-banner { align-items: flex-start; flex-direction: column; padding: 22px; } }
+
diff --git a/frontend/web/app/stores/config.ts b/frontend/web/app/stores/config.ts
index 473dc79..639e60b 100644
--- a/frontend/web/app/stores/config.ts
+++ b/frontend/web/app/stores/config.ts
@@ -67,6 +67,7 @@ interface analyticsConfig {
* 用于管理站点基础设置相关的配置选项
*/
interface siteSettingConfig {
+ require_login: number | boolean, // Web页面是否要求登录
copyright: string, // 版权信息
icp: string, // ICP备案号
icp_url: string, // ICP备案链接
@@ -134,6 +135,7 @@ export const useConfigStore = defineStore('config', {
baidu_tongji_enabled: 0 // 默认不启用百度统计
},
siteSetting: {
+ require_login: 1, // 默认要求登录后访问 Web 页面
copyright: '', // 默认版权信息为空
icp: '', // 默认ICP备案号为空
icp_url: 'https://beian.miit.gov.cn/', // 默认ICP备案链接
@@ -192,6 +194,7 @@ export const useConfigStore = defineStore('config', {
// 更新站点设置
const siteSetting = siteSettingRes?.data || siteSettingRes || {}
if (siteSetting && !Array.isArray(siteSetting)) {
+ this.siteSetting.require_login = Number(siteSetting.require_login ?? 1)
this.siteSetting.copyright = siteSetting.copyright || ''
this.siteSetting.icp = siteSetting.icp || ''
this.siteSetting.icp_url = siteSetting.icp_url || 'https://beian.miit.gov.cn/'