|
|
@@ -1,54 +1,57 @@
|
|
|
<template>
|
|
|
<div class="app-container">
|
|
|
- <div class="portal-header">
|
|
|
- <h2 class="portal-title">重点工程</h2>
|
|
|
- <div class="header-actions">
|
|
|
- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleBatchDelete">删除</el-button>
|
|
|
- <el-button type="primary" icon="Plus" @click="handleAddProject">添加工程</el-button>
|
|
|
+ <div class="content-box">
|
|
|
+ <div class="portal-header">
|
|
|
+ <h2 class="portal-title">重点工程</h2>
|
|
|
+ <div class="header-actions">
|
|
|
+ <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleBatchDelete">删除</el-button>
|
|
|
+ <el-button type="primary" icon="Plus" @click="handleAddProject">添加工程</el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <el-tabs v-model="activeTab" @tab-click="handleTabClick" class="category-tabs">
|
|
|
- <el-tab-pane v-for="tab in categoryTabs" :key="tab.id" :label="tab.name" :name="String(tab.id)" />
|
|
|
- </el-tabs>
|
|
|
+ <el-tabs v-model="activeTab" @tab-click="handleTabClick" class="category-tabs">
|
|
|
+ <el-tab-pane v-for="tab in categoryTabs" :key="tab.id" :label="tab.name" :name="String(tab.id)" />
|
|
|
+ </el-tabs>
|
|
|
|
|
|
- <div v-if="activeTab && activeTab !== '-1'" class="tab-content">
|
|
|
- <el-form :model="queryParams" ref="queryRef" :inline="true" class="search-form">
|
|
|
- <el-form-item label="工程名称" prop="name">
|
|
|
- <el-input v-model="queryParams.name" placeholder="请输入工程名称" clearable style="width: 220px" @keyup.enter="handleQuery" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
- <el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
+ <div v-if="activeTab && activeTab !== '-1'" class="tab-content">
|
|
|
+ <el-form :model="queryParams" ref="queryRef" :inline="true" class="search-form">
|
|
|
+ <el-form-item label="工程名称" prop="name">
|
|
|
+ <el-input v-model="queryParams.name" placeholder="请输入工程名称" clearable style="width: 220px" @keyup.enter="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
+ <el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
|
|
|
- <el-row :gutter="16">
|
|
|
- <el-col v-for="item in projectList" :key="item.id" :xs="24" :sm="12" :md="8" :lg="6" :xl="6" class="mb16">
|
|
|
- <el-card shadow="hover" class="project-card" :style="{ borderTop: '3px solid ' + getPlanColor(item.planValue) }">
|
|
|
- <div class="card-header-row">
|
|
|
- <el-checkbox v-model="item._checked" @change="handleCheckChange" @click.stop />
|
|
|
- <el-button link type="danger" icon="Delete" class="card-delete-btn" @click.stop="handleDelete(item)" />
|
|
|
- </div>
|
|
|
- <div class="card-body" @click="handleProjectClick(item)">
|
|
|
- <div class="card-info">
|
|
|
- <div class="card-title">{{ item.name }}</div>
|
|
|
- <div class="card-progress">
|
|
|
- <el-progress
|
|
|
- :percentage="item.planValue || 0"
|
|
|
- :color="getPlanColor(item.planValue)"
|
|
|
- :stroke-width="10"
|
|
|
- :format="(pct) => pct + '%'"
|
|
|
- />
|
|
|
+ <div class="card-grid">
|
|
|
+ <el-row :gutter="16">
|
|
|
+ <el-col v-for="item in projectList" :key="item.id" :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb16">
|
|
|
+ <el-card shadow="hover" class="project-card" :style="{ borderTop: '3px solid ' + getPlanColor(item.planValue) }" @click="handleProjectClick(item)">
|
|
|
+ <div class="card-header-row" @click.stop>
|
|
|
+ <el-checkbox v-model="item._checked" @change="handleCheckChange" />
|
|
|
+ <el-button link type="danger" icon="Delete" class="card-delete-btn" @click.stop="handleDelete(item)" />
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <div class="card-info">
|
|
|
+ <div class="card-title">{{ item.name }}</div>
|
|
|
+ <div class="card-progress">
|
|
|
+ <el-progress
|
|
|
+ :percentage="item.planValue || 0"
|
|
|
+ :color="getPlanColor(item.planValue)"
|
|
|
+ :stroke-width="10"
|
|
|
+ :format="(pct) => pct + '%'"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-empty v-if="!loading && projectList.length === 0" description="暂无工程数据" />
|
|
|
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="fetchProjects" />
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-empty v-if="!loading && projectList.length === 0" description="暂无工程数据" />
|
|
|
+ </div>
|
|
|
+ <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="showTabProjects" />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<el-dialog title="添加工程" v-model="addDialogVisible" width="450px" append-to-body>
|
|
|
@@ -103,40 +106,46 @@ function getPlanColor(val) {
|
|
|
function loadTabs() {
|
|
|
folderList({ fdCate: 'zdgc', pageSize: 999 }).then(res => {
|
|
|
const list = res.rows || res.data || []
|
|
|
- const tree = proxy.handleTree(list, 'id', 'pid')
|
|
|
+ const tree = proxy.handleTree(JSON.parse(JSON.stringify(list)), 'id', 'pid')
|
|
|
+ // 把children直接存为tab的projects,方便切换时直接取
|
|
|
+ tree.forEach(t => { t.projects = t.children || []; delete t.children })
|
|
|
categoryTabs.value = tree
|
|
|
if (tree.length > 0) {
|
|
|
activeTab.value = String(tree[0].id)
|
|
|
- queryParams.pid = tree[0].id
|
|
|
- fetchProjects()
|
|
|
+ showTabProjects()
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-function handleTabClick() {
|
|
|
- queryParams.pid = Number(activeTab.value)
|
|
|
- queryParams.pageNum = 1
|
|
|
- fetchProjects()
|
|
|
+function handleTabClick(pane) {
|
|
|
+ activeTab.value = String(pane.paneName ?? pane.props?.name ?? pane.name)
|
|
|
}
|
|
|
|
|
|
-function fetchProjects() {
|
|
|
- if (!queryParams.pid) return
|
|
|
+watch(activeTab, (val) => {
|
|
|
+ if (val && val !== '-1') showTabProjects()
|
|
|
+})
|
|
|
+
|
|
|
+function showTabProjects() {
|
|
|
loading.value = true
|
|
|
- folderList({ ...queryParams, fdCate: 'zdgc' }).then(res => {
|
|
|
- projectList.value = (res.rows || res.data || []).map(item => ({ ...item, _checked: false }))
|
|
|
- total.value = res.total || projectList.value.length
|
|
|
- loading.value = false
|
|
|
- }).catch(() => { loading.value = false })
|
|
|
+ const tab = categoryTabs.value.find(t => String(t.id) === activeTab.value)
|
|
|
+ let filtered = tab?.projects || []
|
|
|
+ if (queryParams.name) {
|
|
|
+ filtered = filtered.filter(f => f.name?.includes(queryParams.name))
|
|
|
+ }
|
|
|
+ const ps = queryParams.pageSize || 20
|
|
|
+ const pn = queryParams.pageNum || 1
|
|
|
+ total.value = filtered.length
|
|
|
+ projectList.value = filtered.slice((pn - 1) * ps, pn * ps).map(item => ({ ...item, _checked: false }))
|
|
|
+ loading.value = false
|
|
|
}
|
|
|
|
|
|
function handleQuery() {
|
|
|
queryParams.pageNum = 1
|
|
|
- fetchProjects()
|
|
|
+ showTabProjects()
|
|
|
}
|
|
|
|
|
|
function resetQuery() {
|
|
|
proxy.resetForm('queryRef')
|
|
|
- queryParams.pid = Number(activeTab.value)
|
|
|
handleQuery()
|
|
|
}
|
|
|
|
|
|
@@ -160,6 +169,16 @@ function resetAddForm() {
|
|
|
addForm.planValue = 0
|
|
|
}
|
|
|
|
|
|
+function reloadAll() {
|
|
|
+ folderList({ fdCate: 'zdgc', pageSize: 999 }).then(res => {
|
|
|
+ const list = res.rows || res.data || []
|
|
|
+ const tree = proxy.handleTree(JSON.parse(JSON.stringify(list)), 'id', 'pid')
|
|
|
+ tree.forEach(t => { t.projects = t.children || []; delete t.children })
|
|
|
+ categoryTabs.value = tree
|
|
|
+ showTabProjects()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
function submitAdd() {
|
|
|
addFormRef.value.validate(valid => {
|
|
|
if (!valid) return
|
|
|
@@ -167,7 +186,7 @@ function submitAdd() {
|
|
|
if (res.code === 200) {
|
|
|
proxy.$modal.msgSuccess('添加成功')
|
|
|
addDialogVisible.value = false
|
|
|
- fetchProjects()
|
|
|
+ reloadAll()
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
@@ -178,7 +197,7 @@ function handleDelete(item) {
|
|
|
return deleteFolderRecursive(item.id)
|
|
|
}).then(() => {
|
|
|
proxy.$modal.msgSuccess('删除成功')
|
|
|
- fetchProjects()
|
|
|
+ reloadAll()
|
|
|
}).catch(() => {})
|
|
|
}
|
|
|
|
|
|
@@ -193,7 +212,7 @@ async function handleBatchDelete() {
|
|
|
await deleteFolderRecursive(id)
|
|
|
}
|
|
|
proxy.$modal.msgSuccess('删除成功')
|
|
|
- fetchProjects()
|
|
|
+ reloadAll()
|
|
|
} catch (_) {}
|
|
|
}
|
|
|
|
|
|
@@ -201,17 +220,37 @@ onMounted(() => { loadTabs() })
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
+.content-box {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 20px;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+.tab-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+.card-grid {
|
|
|
+ flex: 1;
|
|
|
+ overflow: auto;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
.portal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
|
|
.portal-title { font-size: 20px; font-weight: 600; margin: 0; }
|
|
|
.header-actions { display: flex; gap: 8px; }
|
|
|
-.category-tabs { margin-bottom: 12px; }
|
|
|
-.search-form { margin-bottom: 12px; }
|
|
|
-.project-card { cursor: pointer; transition: transform 0.2s; &:hover { transform: translateY(-2px); } }
|
|
|
-.card-header-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
|
|
+.category-tabs { margin-bottom: 16px; }
|
|
|
+.search-form { margin-bottom: 16px; }
|
|
|
+.project-card { cursor: pointer; transition: all 0.25s; border-radius: 8px; &:hover { transform: translateY(-3px); box-shadow: 0 6px 20px rgba(0,0,0,0.08); } }
|
|
|
+.card-header-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
|
|
|
.card-delete-btn { font-size: 14px; }
|
|
|
.card-body { cursor: pointer; }
|
|
|
.card-info { min-width: 0; }
|
|
|
-.card-title { font-size: 15px; font-weight: 500; margin-bottom: 8px; }
|
|
|
+.card-title { font-size: 15px; font-weight: 500; margin-bottom: 6px; }
|
|
|
.card-progress { margin-top: 4px; }
|
|
|
.mb16 { margin-bottom: 16px; }
|
|
|
</style>
|