This commit is contained in:
zwgczx committed 2026-02-25 17:59:10 +08:00
1 parent 5734cfa534
commit 1609f19b9c
14 files changed
+2481 -433

No files matched your search

+40 -9
View File
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, defineAsyncComponent, markRaw, onBeforeUnmount, onMounted, ref } from 'vue'
import { computed, defineAsyncComponent, markRaw, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import type { ComponentPublicInstance } from 'vue'
import draggable from 'vuedraggable'
import { useTabStore } from '@/pinia/tab'
import { Button } from '@/components/ui/button'
@@ -35,6 +36,7 @@ interface DataPackage {
const componentMap: Record<string, any> = {
XmView: markRaw(defineAsyncComponent(() => import('@/components/views/Xm.vue'))),
ContractDetailView: markRaw(defineAsyncComponent(() => import('@/components/views/ContractDetailView.vue'))),
ZxFwView: markRaw(defineAsyncComponent(() => import('@/components/views/ZxFwView.vue'))),
}
const tabStore = useTabStore()
@@ -53,6 +55,7 @@ const tabContextRef = ref<HTMLElement | null>(null)
const dataMenuOpen = ref(false)
const dataMenuRef = ref<HTMLElement | null>(null)
const importFileRef = ref<HTMLInputElement | null>(null)
const tabItemElMap = new Map<string, HTMLElement>()
const tabsModel = computed({
get: () => tabStore.tabs,
@@ -114,6 +117,21 @@ const canMoveTab = (event: any) => {
return true
}
const setTabItemRef = (id: string, el: Element | ComponentPublicInstance | null) => {
if (el instanceof HTMLElement) {
tabItemElMap.set(id, el)
return
}
tabItemElMap.delete(id)
}
const ensureActiveTabVisible = () => {
const activeId = tabStore.activeTabId
const el = tabItemElMap.get(activeId)
if (!el) return
el.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' })
}
const readWebStorage = (storageObj: Storage): DataEntry[] => {
const entries: DataEntry[] = []
for (let i = 0; i < storageObj.length; i++) {
@@ -174,7 +192,7 @@ const exportData = async () => {
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = `jgjs-data-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-')}.json`
link.download = `造价项目-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-')}.json`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
@@ -231,27 +249,40 @@ const handleReset = async () => {
onMounted(() => {
window.addEventListener('mousedown', handleGlobalMouseDown)
void nextTick(() => {
ensureActiveTabVisible()
})
})
onBeforeUnmount(() => {
window.removeEventListener('mousedown', handleGlobalMouseDown)
})
watch(
() => tabStore.activeTabId,
() => {
void nextTick(() => {
ensureActiveTabVisible()
})
}
)
</script>
<template>
<div class="flex flex-col w-full h-screen bg-background overflow-hidden">
<div class="flex items-center border-b bg-muted/30 px-2 pt-2 flex-none">
<ScrollArea class="flex-1 whitespace-nowrap">
<div class="flex items-start gap-2 border-b bg-muted/30 px-2 pt-2 flex-none">
<ScrollArea type="auto" class="min-w-0 flex-1 whitespace-nowrap pb-2">
<draggable
v-model="tabsModel"
item-key="id"
tag="div"
class="flex gap-1"
class="flex w-max gap-1"
:animation="180"
:move="canMoveTab"
>
<template #item="{ element: tab }">
<div
:ref="el => setTabItemRef(tab.id, el)"
@click="tabStore.activeTabId = tab.id"
@contextmenu.prevent="openTabContextMenu($event, tab.id)"
:class="[
@@ -276,10 +307,10 @@ onBeforeUnmount(() => {
</div>
</template>
</draggable>
<ScrollBar orientation="horizontal" class="invisible" />
<ScrollBar orientation="horizontal" />
</ScrollArea>
<div ref="dataMenuRef" class="relative ml-2 mb-2">
<div ref="dataMenuRef" class="relative mb-2 shrink-0">
<Button variant="outline" size="sm" @click="dataMenuOpen = !dataMenuOpen">
<ChevronDown class="h-4 w-4 mr-1" />
导入/导出
@@ -312,7 +343,7 @@ onBeforeUnmount(() => {
<AlertDialogRoot>
<AlertDialogTrigger as-child>
<Button variant="destructive" size="sm" class="ml-2 mb-2">
<Button variant="destructive" size="sm" class="mb-2 shrink-0">
<RotateCcw class="h-4 w-4 mr-1" />
重置
</Button>
@@ -322,7 +353,7 @@ onBeforeUnmount(() => {
<AlertDialogContent class="fixed left-1/2 top-1/2 z-50 w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">
<AlertDialogTitle class="text-base font-semibold">确认重置</AlertDialogTitle>
<AlertDialogDescription class="mt-2 text-sm text-muted-foreground">
将清空本地缓存(IndexDB / LocalStorage / SessionStorage)并恢复默认页面,确认继续吗?
将清空所有项目数据,并恢复默认页面,确认继续吗?
</AlertDialogDescription>
<div class="mt-4 flex items-center justify-end gap-2">
<AlertDialogCancel as-child>