liyong
16 小时以前 93b8ceac34e2fbd5c57fe5ab4f5bac32c85408aa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<template>
  <div :class="classObj"
       class="app-wrapper"
       :style="{ '--current-color': theme }">
    <div v-if="device === 'mobile' && sidebar.opened"
         class="drawer-bg"
         @click="handleClickOutside" />
    <sidebar v-if="!sidebar.hide"
             class="sidebar-container" />
    <div :class="{ hasTagsView: showTagsView, sidebarHide: sidebar.hide }"
         class="main-container main-layout">
      <div :class="{ 'fixed-header': fixedHeader, 'with-tags': showTagsView }">
        <navbar @setLayout="setLayout" />
        <tags-view v-if="showTagsView" />
      </div>
      <app-main />
      <settings ref="settingRef" />
    </div>
    <AIChatSidebar v-if="showGlobalAiChat" />
  </div>
</template>
 
<script setup>
  import { useWindowSize } from "@vueuse/core";
  import { useRoute } from "vue-router";
  import Sidebar from "./components/Sidebar/index.vue";
  import { AppMain, Navbar, Settings, TagsView } from "./components";
  import AIChatSidebar from "@/components/AIChatSidebar/index.vue";
  import defaultSettings from "@/settings";
 
  import useAppStore from "@/store/modules/app";
  import useUserStore from "@/store/modules/user";
  import useSettingsStore from "@/store/modules/settings";
  import useTagsViewStore from "@/store/modules/tagsView";
 
  const settingsStore = useSettingsStore();
  const tagsViewStore = useTagsViewStore();
  const userStore = useUserStore();
  const route = useRoute();
  const theme = computed(() => settingsStore.theme);
  const sideTheme = computed(() => settingsStore.sideTheme);
  const sidebar = computed(() => useAppStore().sidebar);
  const device = computed(() => useAppStore().device);
  const needTagsView = computed(() => settingsStore.tagsView);
  const showTagsView = computed(() => needTagsView.value && tagsViewStore.visitedViews.length > 1);
  const fixedHeader = computed(() => settingsStore.fixedHeader);
  const aiEnabled = computed(() => Number(userStore.aiEnabled) === 1);
  const showGlobalAiChat = computed(() => {
    const isIndustrialBrainRoute = String(route.path || "").startsWith("/ai-industrial-brain");
    return !isIndustrialBrainRoute && aiEnabled.value;
  });
 
  const classObj = computed(() => ({
    hideSidebar: !sidebar.value.opened,
    openSidebar: sidebar.value.opened,
    withoutAnimation: sidebar.value.withoutAnimation,
    mobile: device.value === "mobile",
  }));
 
  const { width, height } = useWindowSize();
  const WIDTH = 992; // refer to Bootstrap's responsive design
 
  watch(
    () => device.value,
    () => {
      if (device.value === "mobile" && sidebar.value.opened) {
        useAppStore().closeSideBar({ withoutAnimation: false });
      }
    }
  );
 
  watchEffect(() => {
    if (width.value - 1 < WIDTH) {
      useAppStore().toggleDevice("mobile");
      useAppStore().closeSideBar({ withoutAnimation: true });
    } else {
      useAppStore().toggleDevice("desktop");
    }
  });
 
  function handleClickOutside() {
    useAppStore().closeSideBar({ withoutAnimation: false });
  }
 
  const settingRef = ref(null);
  function setLayout() {
    settingRef.value.openSetting();
  }
</script>
 
<style lang="scss" scoped>
  @import "@/assets/styles/mixin.scss";
 
  .app-wrapper {
    @include clearfix;
    position: relative;
    min-height: 100%;
    width: 100%;
    background:
      radial-gradient(circle at 14% -8%, rgba(59, 130, 246, 0.14), transparent 36%),
      radial-gradient(circle at 88% -12%, rgba(56, 189, 248, 0.1), transparent 30%),
      linear-gradient(165deg, #f3f7fc 0%, #eef5ff 56%, #f8fbff 100%);
 
    &.mobile.openSidebar {
      position: fixed;
      top: 0;
    }
  }
 
  .drawer-bg {
    background: rgba(15, 23, 42, 0.22);
    width: 100%;
    top: 0;
    height: 100%;
    position: absolute;
    z-index: 999;
  }
 
  .main-layout {
    min-height: 100vh;
    margin-left: var(--sidebar-width);
    transition: margin-left 0.25s ease;
    display: flex;
    flex-direction: column;
  }
 
  .fixed-header {
    position: sticky;
    top: 0;
    z-index: var(--layout-header-z);
    width: 100%;
    padding: 8px var(--content-gap) 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    background: transparent;
    backdrop-filter: none;
  }
 
  .fixed-header.with-tags {
    padding-bottom: 6px;
  }
 
  .hideSidebar .fixed-header {
    width: 100%;
  }
 
  .hideSidebar .main-layout {
    margin-left: var(--sidebar-collapsed-width);
  }
 
  .mobile .fixed-header {
    width: 100%;
    padding: 8px 10px 0;
  }
 
  .mobile .main-layout,
  .sidebarHide.main-layout {
    margin-left: 0;
  }
</style>