From d5ef0fe419c0b3a83c3c73a63fb54353572a8103 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期二, 01 四月 2025 17:48:37 +0800 Subject: [PATCH] 修改布局 --- customer_list/ch/static/config/route.js | 19 + src/views/project/ch/workspace/situation/index.vue | 16 + src/components/chat/Chat.vue | 3 src/views/error/404.vue | 4 src/views/project/ch/gis/situation/index.vue | 16 + src/layout/component/sidebar/GisMenu.vue | 234 +++++++++++++++++++ src/layout/component/header/Header.vue | 74 ++++- src/layout/component/main.vue | 23 + src/api/menu/menuData.ts | 66 +++++ src/layout/component/sidebar/types.ts | 7 src/layout/component/sidebar/WorkSpaceMenu.vue | 234 +++++++++++++++++++ 11 files changed, 671 insertions(+), 25 deletions(-) diff --git a/customer_list/ch/static/config/route.js b/customer_list/ch/static/config/route.js index 319df7c..122790c 100644 --- a/customer_list/ch/static/config/route.js +++ b/customer_list/ch/static/config/route.js @@ -8,6 +8,25 @@ redirect: null, showTitle: false, }, + { + name: 'WorkspaceSituation', + isKeepAlive: true, + isAffix: false, + path: '/workspace/situation', + component: '/project/ch/workspace/situation/index.vue', + redirect: null, + showTitle: true, + }, + + { + name: 'GisSituation', + isKeepAlive: true, + isAffix: false, + path: '/gis/situation', + component: '/project/ch/gis/situation/index.vue', + redirect: null, + showTitle: true, + }, //搴旂敤鍦烘櫙(涓诲満鏅牴鎹綋鍓岻D鏄剧ず娆″満鏅�) { name: 'Scenario', diff --git a/src/api/menu/menuData.ts b/src/api/menu/menuData.ts index dcf099f..2e379eb 100644 --- a/src/api/menu/menuData.ts +++ b/src/api/menu/menuData.ts @@ -16,6 +16,70 @@ Description: '', }, { + Children: [ + { + ID: '1805430930840621056', + ParentID: '0', + Type: 2, + Name: '姒傚喌', + Path: '/workspace/situation', + Permission: '', + Icon: 'ywicon icon-a-appround15', + IsIframe: false, + OutLink: '', + IsHide: false, + Weight: 0, + SortCode: 1, + Description: '', + }, + ], + ID: '1805430930840621056', + ParentID: '0', + Type: 1, + Name: '涓汉宸ヤ綔鍙�', + Path: '/workspace', + Permission: '', + Icon: 'ywicon icon-a-appround15', + IsIframe: false, + OutLink: '', + IsHide: false, + Weight: 0, + SortCode: 1, + Description: '', + }, + { + Children: [ + { + ID: '1805430930840621056', + ParentID: '0', + Type: 2, + Name: '姒傚喌', + Path: '/gis/situation', + Permission: '', + Icon: 'ywicon icon-a-appround15', + IsIframe: false, + OutLink: '', + IsHide: false, + Weight: 0, + SortCode: 1, + Description: '', + }, + ], + ID: '1805430930840621056', + ParentID: '0', + Type: 1, + Name: 'GIS绯荤粺', + Path: '/gis', + Permission: '', + Icon: 'ywicon icon-a-appround15', + IsIframe: false, + OutLink: '', + IsHide: false, + Weight: 0, + SortCode: 1, + Description: '', + }, + { Children: [], ID: '1805430930840621056', ParentID: '0', @@ -111,4 +175,4 @@ SortCode: 5, Description: '', }, -]; \ No newline at end of file +]; diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue index accfaf2..9569345 100644 --- a/src/components/chat/Chat.vue +++ b/src/components/chat/Chat.vue @@ -48,7 +48,6 @@ <script setup lang="ts"> import type { CancelTokenSource } from 'axios'; import axios from 'axios'; -import { orderBy } from 'lodash-es'; import moment from 'moment'; import { computed, nextTick, onActivated, onMounted, ref } from 'vue'; import { loadAmisSource } from '../amis/load'; @@ -60,7 +59,7 @@ import CustomDrawer from '/@/components/drawer/CustomDrawer.vue'; import { Logger } from '/@/model/logger/Logger'; import { triggerRef } from 'vue'; -import { ElLoadingService, ElMessage } from 'element-plus'; +import { ElMessage } from 'element-plus'; import ChatContainer from './components/ChatContainer.vue'; import ShareLinkDlg from './components/shareLink/index.vue'; import router from '/@/router'; diff --git a/src/layout/component/header/Header.vue b/src/layout/component/header/Header.vue index 980d7e6..f0f7c8f 100644 --- a/src/layout/component/header/Header.vue +++ b/src/layout/component/header/Header.vue @@ -1,17 +1,19 @@ <template> <div class="top_text flex justify-between px-6 items-center" :class="sidebarIsShow ? 'px-6' : 'pl-[unset] pr-6'"> <div class="flex-items-center"> - <div - class="flex-items-center space-x-3 mr-4 pr-4 border border-solid border-r-1 border-l-0 border-y-0 border-gray-300" - v-if="!sidebarIsShow" - ></div> - <div v-if="routerMeta.showTitle" class="font-bold flex items-center"> - <span class="flex-center cursor-pointer" v-if="routerMeta.showBack" @click="goBack"> - <SvgIcon name="ele-ArrowLeft" /> - </span> - <span class=""> - {{ routerMeta.title }} - </span> + <div class="nav-menu"> + <router-link :to="{ path: '/ask_answer', query: { id: activeRoomId } }" class="nav-item" active-class="active"> + <i class="icon-park-outline-robot"></i> + 鏅鸿兘鍔╂墜 + </router-link> + <router-link to="/workspace/situation" class="nav-item" active-class="active"> + <i class="icon-park-outline-workbench"></i> + 涓汉宸ヤ綔鍙� + </router-link> + <router-link to="/gis/situation" class="nav-item" active-class="active"> + <i class="icon-park-outline-system"></i> + GIS绯荤粺 + </router-link> </div> </div> <el-dialog @@ -58,16 +60,17 @@ <script setup lang="ts"> import { onClickOutside } from '@vueuse/core'; +import { storeToRefs } from 'pinia'; import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'; import { systemNotifyList } from '/@/api/ai/chat'; import router from '/@/router'; -import { isSharePage, newChatRoomClick } from '/@/stores/chatRoom'; -import emitter from '/@/utils/mitt'; -import { storeToRefs } from 'pinia'; import pinia from '/@/stores'; +import { activeRoomId, isSharePage, newChatRoomClick } from '/@/stores/chatRoom'; import { useThemeConfig } from '/@/stores/themeConfig'; -import { Local } from '/@/utils/storage'; +import emitter from '/@/utils/mitt'; import { userInfoKey } from '/@/utils/request'; +import { Local } from '/@/utils/storage'; + const props = defineProps(['sidebarIsShow']); let state = reactive({ isShowAnnouncement: false, @@ -76,6 +79,9 @@ announcementContent: '', announcementTime: '', }); + + + //#region ====================== 鍏憡鏄惁鐪嬭繃 ====================== const userInfo = ref(Local.get(userInfoKey)); const readKey = `announcementIsRead_${userInfo.value?.id}`; @@ -107,9 +113,6 @@ const globalTitle = computed(() => themeConfig.value.globalTitle); const setHeaderTitle = (title: string) => { - // routerMeta.value.title = title; - // triggerRef(routerMeta); - document.title = `${title} - ${globalTitle.value}`; }; @@ -261,4 +264,39 @@ padding: 10px 20px 20px; box-sizing: border-box; } + +.nav-menu { + display: flex; + align-items: center; + height: 100%; + gap: 8px; + + .nav-item { + display: flex; + align-items: center; + padding: 0 16px; + height: 100%; + color: var(--el-text-color-regular); + text-decoration: none; + font-size: 14px; + transition: all 0.3s ease; + border-bottom: 2px solid transparent; + gap: 4px; + + i { + font-size: 16px; + } + + &:hover { + color: var(--el-color-primary); + background-color: rgba(var(--el-color-primary-rgb), 0.1); + } + + &.active { + color: var(--el-color-primary); + border-bottom-color: var(--el-color-primary); + background-color: rgba(var(--el-color-primary-rgb), 0.1); + } + } +} </style> diff --git a/src/layout/component/main.vue b/src/layout/component/main.vue index c0bcfa2..8a8eded 100644 --- a/src/layout/component/main.vue +++ b/src/layout/component/main.vue @@ -9,8 +9,13 @@ wrap-class="layout-main-scroll flex" view-class="layout-main-scroll bg-[var(--color-bg-side)] flex h100 w-full" > - <SideBar v-if="!isSharePage && sidebarIsShow" :isShow="sidebarIsShow" @toggleSidebar="toggleSidebar" /> - <SidebarOther v-if="!isSharePage && !sidebarIsShow" :isShow="!sidebarIsShow" @toggleSidebar="toggleSidebar" /> + <WorkSpaceMenu v-show="isWorkSpace" /> + <div v-show="isAskAnswer"> + <SideBar v-if="!isSharePage && sidebarIsShow" :isShow="sidebarIsShow" @toggleSidebar="toggleSidebar" /> + <SidebarOther v-if="!isSharePage && !sidebarIsShow" :isShow="!sidebarIsShow" @toggleSidebar="toggleSidebar" /> + </div> + <GisMenu v-show="isGis" /> + <div class="flex-auto flex-col flex right-container" :class="{ @@ -45,9 +50,23 @@ import { useThemeConfig } from '/@/stores/themeConfig'; import { NextLoading } from '/@/utils/loading'; import { Local } from '/@/utils/storage'; +import WorkSpaceMenu from './sidebar/WorkSpaceMenu.vue'; +import GisMenu from './sidebar/GisMenu.vue'; +import router from '/@/router/index'; // 寮曞叆缁勪欢 const LayoutParentView = defineAsyncComponent(() => import('/@/layout/routerView/parent.vue')); const LayoutFooter = defineAsyncComponent(() => import('/@/layout/footer/index.vue')); + +const isWorkSpace = computed(() => { + return router.currentRoute.value.path.startsWith('/workspace'); +}); +const isAskAnswer = computed(() => { + return router.currentRoute.value.path.startsWith('/ask_answer'); +}); +const isGis = computed(() => { + return router.currentRoute.value.path.startsWith('/gis'); +}); + // 瀹氫箟鍙橀噺鍐呭 const layoutMainScrollbarRef = ref(); const route = useRoute(); diff --git a/src/layout/component/sidebar/GisMenu.vue b/src/layout/component/sidebar/GisMenu.vue new file mode 100644 index 0000000..88205bf --- /dev/null +++ b/src/layout/component/sidebar/GisMenu.vue @@ -0,0 +1,234 @@ +<template> + <div class="pc-chat_aside flex-0 relative" :style="`width:252px;transition: 0.7s ease-in;`"> + <!-- Logo 閮ㄥ垎 --> + <div class="h-[40px] w-full bg-[#0084ff] flex justify-between items-center text-white px-2"> + <span>GIS绯荤粺</span> + <!-- <span>瀹樼綉GIS</span> --> + </div> + <!-- 鑿滃崟椤� --> + <div class="menu-container"> + <el-menu :default-active="activeId" class="wi-menu !w-full" :unique-opened="true" @select="handleSelect"> + <template v-for="item in menuData"> + <el-sub-menu :key="`sub-${item.id}`" v-if="item.children?.length" :index="item.id"> + <template #title> + <i v-if="item.icon" :class="item.icon"></i> + <span>{{ item.title }}</span> + </template> + + <template v-for="subItem in item.children"> + <el-sub-menu :key="`sub-${subItem.id}`" v-if="subItem.children?.length" :index="subItem.id"> + <template #title> + <i v-if="subItem.icon" :class="subItem.icon"></i> + <span>{{ subItem.title }}</span> + </template> + <!-- 涓夌骇鑿滃崟椤� --> + <el-menu-item v-for="child in subItem.children" :key="`item-${child.id}`" :index="child.id"> + <i v-if="child.icon" :class="child.icon"></i> + <span>{{ child.title }}</span> + </el-menu-item> + </el-sub-menu> + <!-- 浜岀骇鑿滃崟椤� --> + <el-menu-item v-else :key="`item-${subItem.id}`" :index="subItem.id"> + <i v-if="subItem.icon" :class="subItem.icon"></i> + <span>{{ subItem.title }}</span> + </el-menu-item> + </template> + </el-sub-menu> + <el-menu-item v-else :key="`item-${item.id}`" :index="item.id"> + <i v-if="item.icon" :class="item.icon"></i> + <span>{{ item.title }}</span> + </el-menu-item> + </template> + </el-menu> + </div> + </div> +</template> + +<script setup lang="ts"> +import { computed, ref, onMounted, watch } from 'vue'; +import { useRouter } from 'vue-router'; +import type { MenuItemData } from './types'; + +const router = useRouter(); +const activeId = ref(''); + +// 绀轰緥鑿滃崟鏁版嵁 +const menuData = ref<MenuItemData[]>([ + { + id: 'menu1', + title: '棣栭〉', + icon: 'icon-park-outline-chart-line', + path: '/gis/situation', + }, + { + id: 'menu2', + title: '缁熻', + icon: 'icon-park-outline-folder', + children: [ + { + id: '鑷畾涔夌粺璁�', + title: '鑷畾涔夌粺璁�', + path: '/gis/situation', + }, + { + id: 'menu2-2', + title: '绠$嚎缁熻', + path: '/gis/situation', + }, + ], + }, +]); + +// 璁$畻灞炴�э細鏈夊瓙鑿滃崟鐨勯」 +const parentMenuItems = computed(() => menuData.value.filter((item) => item.children?.length)); + +// 璁$畻灞炴�э細娌℃湁瀛愯彍鍗曠殑椤� +const leafMenuItems = computed(() => menuData.value.filter((item) => !item.children?.length)); + +const handleSelect = (index: string) => { + activeId.value = index; + const findPath = (items: MenuItemData[]): string | undefined => { + for (const item of items) { + if (item.id === index) return item.path; + if (item.children) { + const path = findPath(item.children); + if (path) return path; + } + } + }; + console.log('馃殌 ~ index:', index); + const path = findPath(menuData.value); + if (path) { + router.push(path); + } +}; + +// 閫氳繃 path 鎵� index +const findIndex = (items: MenuItemData[]): string | undefined => { + for (const item of items) { + if (item.path === router.currentRoute.value.path) return item.id; + if (item.children) { + const index = findIndex(item.children); + if (index) return index; + } + } +}; +watch(router.currentRoute, (newRoute) => { + activeId.value = findIndex(menuData.value) || ''; +}); +</script> + +<style scoped lang="scss"> +.pc-chat_aside { + height: 100%; + box-sizing: border-box; + background-color: var(--color-bg-side); + overflow: visible; + transition: width 0.1s ease-in; + position: relative; + display: flex; + flex-direction: column; +} + +.aside_top { + box-sizing: border-box; + position: relative; + width: 100%; + padding: 18px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.layout-logo-medium-img { + width: 28px; + margin-right: 7px; +} + +.menu-container { + flex: 1; + overflow-y: auto; + + :deep(.wi-menu) { + border-right: none; + background-color: transparent; + --hover-menu-bg: rgba(255, 255, 255, 0.1); + --menu-width: 100% !important; + + --active-menu-bg: #333534 !important; + --active-menu-color: var(--color-btn-base) !important; + + .el-menu { + background-color: transparent; + width: var(--menu-width) !important; + } + + // 榧犳爣 hover 鏃堕鑹� + + .el-menu-item { + height: 40px; + line-height: 40px; + color: #ccc; + + &:hover { + background: var(--hover-menu-bg) !important; + } + + &.is-active { + background: var(--active-menu-bg) !important; + color: var(--active-menu-color); + } + + i { + margin-right: 8px; + } + } + + .el-sub-menu { + .el-menu { + width: var(--menu-width) !important; + } + --next-bg-menuBarActiveColor: unset !important; + + .el-sub-menu__title { + height: 40px; + line-height: 40px; + color: #ccc; + + &:hover { + background: var(--hover-menu-bg) !important; + } + + i { + margin-right: 8px; + } + } + + &.is-active { + .el-sub-menu__title { + color: var(--active-menu-color); + } + } + } + + // 瀛愯彍鍗曞脊鍑哄眰鏍峰紡 + .el-menu--popup { + background-color: var(--color-bg-side); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 0; + + .el-menu-item { + background-color: transparent; + color: #ccc; + + &:hover { + background-color: rgba(255, 255, 255, 0.1); + } + + &.is-active { + background: var(--active-menu-bg); + color: var(--active-menu-color); + } + } + } + } +} +</style> diff --git a/src/layout/component/sidebar/WorkSpaceMenu.vue b/src/layout/component/sidebar/WorkSpaceMenu.vue new file mode 100644 index 0000000..fbc25f6 --- /dev/null +++ b/src/layout/component/sidebar/WorkSpaceMenu.vue @@ -0,0 +1,234 @@ +<template> + <div class="pc-chat_aside flex-0 relative" :style="`width:252px;transition: 0.7s ease-in;`"> + <!-- Logo 閮ㄥ垎 --> + <div class="h-[40px] w-full bg-[#0084ff] flex justify-between items-center text-white px-2"> + <span>瀹樼綉GIS</span> + <!-- <span>瀹樼綉GIS</span> --> + </div> + <!-- 鑿滃崟椤� --> + <div class="menu-container"> + <el-menu :default-active="activeId" class="wi-menu !w-full" :unique-opened="true" @select="handleSelect"> + <template v-for="item in menuData"> + <el-sub-menu :key="`sub-${item.id}`" v-if="item.children?.length" :index="item.id"> + <template #title> + <i v-if="item.icon" :class="item.icon"></i> + <span>{{ item.title }}</span> + </template> + + <template v-for="subItem in item.children"> + <el-sub-menu :key="`sub-${subItem.id}`" v-if="subItem.children?.length" :index="subItem.id"> + <template #title> + <i v-if="subItem.icon" :class="subItem.icon"></i> + <span>{{ subItem.title }}</span> + </template> + <!-- 涓夌骇鑿滃崟椤� --> + <el-menu-item v-for="child in subItem.children" :key="`item-${child.id}`" :index="child.id"> + <i v-if="child.icon" :class="child.icon"></i> + <span>{{ child.title }}</span> + </el-menu-item> + </el-sub-menu> + <!-- 浜岀骇鑿滃崟椤� --> + <el-menu-item v-else :key="`item-${subItem.id}`" :index="subItem.id"> + <i v-if="subItem.icon" :class="subItem.icon"></i> + <span>{{ subItem.title }}</span> + </el-menu-item> + </template> + </el-sub-menu> + <el-menu-item v-else :key="`item-${item.id}`" :index="item.id"> + <i v-if="item.icon" :class="item.icon"></i> + <span>{{ item.title }}</span> + </el-menu-item> + </template> + </el-menu> + </div> + </div> +</template> + +<script setup lang="ts"> +import { computed, ref, onMounted, watch } from 'vue'; +import { useRouter } from 'vue-router'; +import type { MenuItemData } from './types'; + +const router = useRouter(); +const activeId = ref(''); + +// 绀轰緥鑿滃崟鏁版嵁 +const menuData = ref<MenuItemData[]>([ + { + id: 'menu1', + title: '棣栭〉', + icon: 'icon-park-outline-chart-line', + path: '/workspace/situation', + }, + { + id: 'menu2', + title: '缁熻', + icon: 'icon-park-outline-folder', + children: [ + { + id: '鑷畾涔夌粺璁�', + title: '鑷畾涔夌粺璁�', + path: '/workspace/situation', + }, + { + id: 'menu2-2', + title: '绠$嚎缁熻', + path: '/workspace/situation', + }, + ], + }, +]); + +// 璁$畻灞炴�э細鏈夊瓙鑿滃崟鐨勯」 +const parentMenuItems = computed(() => menuData.value.filter((item) => item.children?.length)); + +// 璁$畻灞炴�э細娌℃湁瀛愯彍鍗曠殑椤� +const leafMenuItems = computed(() => menuData.value.filter((item) => !item.children?.length)); + +const handleSelect = (index: string) => { + activeId.value = index; + const findPath = (items: MenuItemData[]): string | undefined => { + for (const item of items) { + if (item.id === index) return item.path; + if (item.children) { + const path = findPath(item.children); + if (path) return path; + } + } + }; + console.log('馃殌 ~ index:', index); + const path = findPath(menuData.value); + if (path) { + router.push(path); + } +}; + +// 閫氳繃 path 鎵� index +const findIndex = (items: MenuItemData[]): string | undefined => { + for (const item of items) { + if (item.path === router.currentRoute.value.path) return item.id; + if (item.children) { + const index = findIndex(item.children); + if (index) return index; + } + } +}; +watch(router.currentRoute, (newRoute) => { + activeId.value = findIndex(menuData.value) || ''; +}); +</script> + +<style scoped lang="scss"> +.pc-chat_aside { + height: 100%; + box-sizing: border-box; + background-color: var(--color-bg-side); + overflow: visible; + transition: width 0.1s ease-in; + position: relative; + display: flex; + flex-direction: column; +} + +.aside_top { + box-sizing: border-box; + position: relative; + width: 100%; + padding: 18px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.layout-logo-medium-img { + width: 28px; + margin-right: 7px; +} + +.menu-container { + flex: 1; + overflow-y: auto; + + :deep(.wi-menu) { + border-right: none; + background-color: transparent; + --hover-menu-bg: rgba(255, 255, 255, 0.1); + --menu-width: 100% !important; + + --active-menu-bg: #333534 !important; + --active-menu-color: var(--color-btn-base) !important; + + .el-menu { + background-color: transparent; + width: var(--menu-width) !important; + } + + // 榧犳爣 hover 鏃堕鑹� + + .el-menu-item { + height: 40px; + line-height: 40px; + color: #ccc; + + &:hover { + background: var(--hover-menu-bg) !important; + } + + &.is-active { + background: var(--active-menu-bg) !important; + color: var(--active-menu-color); + } + + i { + margin-right: 8px; + } + } + + .el-sub-menu { + .el-menu { + width: var(--menu-width) !important; + } + --next-bg-menuBarActiveColor: unset !important; + + .el-sub-menu__title { + height: 40px; + line-height: 40px; + color: #ccc; + + &:hover { + background: var(--hover-menu-bg) !important; + } + + i { + margin-right: 8px; + } + } + + &.is-active { + .el-sub-menu__title { + color: var(--active-menu-color); + } + } + } + + // 瀛愯彍鍗曞脊鍑哄眰鏍峰紡 + .el-menu--popup { + background-color: var(--color-bg-side); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 0; + + .el-menu-item { + background-color: transparent; + color: #ccc; + + &:hover { + background-color: rgba(255, 255, 255, 0.1); + } + + &.is-active { + background: var(--active-menu-bg); + color: var(--active-menu-color); + } + } + } + } +} +</style> diff --git a/src/layout/component/sidebar/types.ts b/src/layout/component/sidebar/types.ts new file mode 100644 index 0000000..5f953e4 --- /dev/null +++ b/src/layout/component/sidebar/types.ts @@ -0,0 +1,7 @@ +export interface MenuItemData { + id: string; + title: string; + icon?: string; + children?: MenuItemData[]; + path?: string; +} diff --git a/src/views/error/404.vue b/src/views/error/404.vue index 886a1c1..39ad3a3 100644 --- a/src/views/error/404.vue +++ b/src/views/error/404.vue @@ -7,9 +7,9 @@ <div class="left-item-animation left-item-num">404</div> <div class="left-item-animation left-item-title">{{ $t('message.notFound.foundTitle') }}</div> <div class="left-item-animation left-item-msg">{{ $t('message.notFound.foundMsg') }}</div> - <div class="left-item-animation left-item-btn"> + <!-- <div class="left-item-animation left-item-btn"> <el-button type="primary" size="default" round @click="onGoHome">{{ $t('message.notFound.foundBtn') }}</el-button> - </div> + </div> --> </div> </div> <div class="right"> diff --git a/src/views/project/ch/gis/situation/index.vue b/src/views/project/ch/gis/situation/index.vue new file mode 100644 index 0000000..3695295 --- /dev/null +++ b/src/views/project/ch/gis/situation/index.vue @@ -0,0 +1,16 @@ +<template> + <div class="gis-situation"> + <div class="gis-situation-header"> + <div class="gis-situation-header-title"> + <span>GIS绯荤粺姒傚喌</span> + </div> + </div> + </div> +</template> + +<script setup lang="ts" name="GisSituation"> +import { ref } from 'vue'; + + +</script> +<style scoped lang="scss"></style> diff --git a/src/views/project/ch/workspace/situation/index.vue b/src/views/project/ch/workspace/situation/index.vue new file mode 100644 index 0000000..c7b6c7a --- /dev/null +++ b/src/views/project/ch/workspace/situation/index.vue @@ -0,0 +1,16 @@ +<template> + <div class="workspace-situation"> + <div class="workspace-situation-header"> + <div class="workspace-situation-header-title"> + <span>涓汉宸ヤ綔鍙版鍐�</span> + </div> + </div> + </div> +</template> + +<script setup lang="ts" name="WorkspaceSituation"> +import { ref } from 'vue'; + + +</script> +<style scoped lang="scss"></style> -- Gitblit v1.9.3