|
|
@@ -3,84 +3,215 @@
|
|
|
<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>
|
|
|
|
|
|
- <el-row :gutter="16">
|
|
|
- <el-col v-for="item in folderItems" :key="item.id" :xs="24" :sm="12" :md="8" :lg="6" :xl="6" class="mb16">
|
|
|
- <el-card shadow="hover" class="project-card" @click="handleProjectClick(item)">
|
|
|
- <div class="card-body">
|
|
|
- <div class="card-icon">
|
|
|
- <svg-icon icon-class="folder" />
|
|
|
+ <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>
|
|
|
+
|
|
|
+ <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-info">
|
|
|
- <div class="card-title">{{ item.name }}</div>
|
|
|
- <div class="card-meta">
|
|
|
- <span class="meta-time">{{ parseTime(item.date, '{y}-{m}-{d}') }}</span>
|
|
|
+ <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>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
|
|
|
- <el-empty v-if="!loading && folderItems.length === 0" description="暂无工程数据" />
|
|
|
+ <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" />
|
|
|
+ </div>
|
|
|
|
|
|
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getFolderList" />
|
|
|
+ <el-dialog title="添加工程" v-model="addDialogVisible" width="450px" append-to-body>
|
|
|
+ <el-form ref="addFormRef" :model="addForm" :rules="addRules" label-width="100px">
|
|
|
+ <el-form-item label="工程名称" prop="name">
|
|
|
+ <el-input v-model="addForm.name" placeholder="请输入工程名称" maxlength="100" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="工程描述" prop="description">
|
|
|
+ <el-input v-model="addForm.description" type="textarea" :rows="3" placeholder="请输入工程描述(200字以内)" maxlength="200" show-word-limit />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="设置进度" prop="planValue">
|
|
|
+ <el-slider v-model="addForm.planValue" :min="0" :max="100" show-input style="width: 320px" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button type="primary" @click="submitAdd">立即提交</el-button>
|
|
|
+ <el-button @click="resetAddForm">重置</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup name="Zdgc">
|
|
|
-import { folderList } from "@/api/efinder/finder"
|
|
|
-import { parseTime } from "@/utils/goldenwater"
|
|
|
+import { folderList, mkdir, deleteFolderRecursive } from "@/api/efinder/finder"
|
|
|
|
|
|
+const { proxy } = getCurrentInstance()
|
|
|
const router = useRouter()
|
|
|
|
|
|
-const folderItems = ref([])
|
|
|
+const categoryTabs = ref([])
|
|
|
+const activeTab = ref('-1')
|
|
|
+const projectList = ref([])
|
|
|
const total = ref(0)
|
|
|
-const loading = ref(true)
|
|
|
+const loading = ref(false)
|
|
|
+const ids = ref([])
|
|
|
+const multiple = ref(true)
|
|
|
+
|
|
|
+const queryParams = reactive({ pageNum: 1, pageSize: 20, fdCate: 'zdgc', name: undefined, pid: undefined })
|
|
|
+
|
|
|
+const addDialogVisible = ref(false)
|
|
|
+const addFormRef = ref(null)
|
|
|
+const addForm = reactive({ name: '', description: '', planValue: 0 })
|
|
|
+const addRules = { name: [{ required: true, message: '工程名称不能为空', trigger: 'blur' }] }
|
|
|
+
|
|
|
+function getPlanColor(val) {
|
|
|
+ if (!val && val !== 0) return '#909399'
|
|
|
+ if (val >= 100) return '#409eff'
|
|
|
+ if (val >= 90) return '#67c23a'
|
|
|
+ if (val >= 50) return '#e6a23c'
|
|
|
+ return '#f56c6c'
|
|
|
+}
|
|
|
+
|
|
|
+function loadTabs() {
|
|
|
+ folderList({ fdCate: 'zdgc', pageSize: 999 }).then(res => {
|
|
|
+ const list = res.rows || res.data || []
|
|
|
+ const tree = proxy.handleTree(list, 'id', 'pid')
|
|
|
+ categoryTabs.value = tree
|
|
|
+ if (tree.length > 0) {
|
|
|
+ activeTab.value = String(tree[0].id)
|
|
|
+ queryParams.pid = tree[0].id
|
|
|
+ fetchProjects()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
|
|
|
-const data = reactive({
|
|
|
- queryParams: { pageNum: 1, pageSize: 20, fdCate: "zdgc" }
|
|
|
-})
|
|
|
-const { queryParams } = toRefs(data)
|
|
|
+function handleTabClick() {
|
|
|
+ queryParams.pid = Number(activeTab.value)
|
|
|
+ queryParams.pageNum = 1
|
|
|
+ fetchProjects()
|
|
|
+}
|
|
|
|
|
|
-function getFolderList() {
|
|
|
+function fetchProjects() {
|
|
|
+ if (!queryParams.pid) return
|
|
|
loading.value = true
|
|
|
- folderList(queryParams.value).then(response => {
|
|
|
- folderItems.value = response.data || response.rows || []
|
|
|
- total.value = response.total || folderItems.value.length
|
|
|
+ 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 })
|
|
|
}
|
|
|
|
|
|
+function handleQuery() {
|
|
|
+ queryParams.pageNum = 1
|
|
|
+ fetchProjects()
|
|
|
+}
|
|
|
+
|
|
|
+function resetQuery() {
|
|
|
+ proxy.resetForm('queryRef')
|
|
|
+ queryParams.pid = Number(activeTab.value)
|
|
|
+ handleQuery()
|
|
|
+}
|
|
|
+
|
|
|
+function handleCheckChange() {
|
|
|
+ ids.value = projectList.value.filter(i => i._checked).map(i => i.id)
|
|
|
+ multiple.value = ids.value.length === 0
|
|
|
+}
|
|
|
+
|
|
|
function handleProjectClick(item) {
|
|
|
router.push({ path: '/zdgc/detail/' + item.id })
|
|
|
}
|
|
|
|
|
|
function handleAddProject() {
|
|
|
- router.push({ path: '/pms/addProject', query: { folderId: 0, zggcPrarms: '2' } })
|
|
|
+ resetAddForm()
|
|
|
+ addDialogVisible.value = true
|
|
|
}
|
|
|
|
|
|
-function handleQuery() {
|
|
|
- queryParams.value.pageNum = 1
|
|
|
- getFolderList()
|
|
|
+function resetAddForm() {
|
|
|
+ addForm.name = ''
|
|
|
+ addForm.description = ''
|
|
|
+ addForm.planValue = 0
|
|
|
+}
|
|
|
+
|
|
|
+function submitAdd() {
|
|
|
+ addFormRef.value.validate(valid => {
|
|
|
+ if (!valid) return
|
|
|
+ mkdir({ name: addForm.name, fdCate: 'zdgc', pid: Number(activeTab.value), planValue: addForm.planValue }).then(res => {
|
|
|
+ if (res.code === 200) {
|
|
|
+ proxy.$modal.msgSuccess('添加成功')
|
|
|
+ addDialogVisible.value = false
|
|
|
+ fetchProjects()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function handleDelete(item) {
|
|
|
+ proxy.$modal.confirm('是否确认删除"' + item.name + '"?').then(() => {
|
|
|
+ return deleteFolderRecursive(item.id)
|
|
|
+ }).then(() => {
|
|
|
+ proxy.$modal.msgSuccess('删除成功')
|
|
|
+ fetchProjects()
|
|
|
+ }).catch(() => {})
|
|
|
+}
|
|
|
+
|
|
|
+async function handleBatchDelete() {
|
|
|
+ if (ids.value.length === 0) {
|
|
|
+ proxy.$modal.msgWarning('请先选择要删除的项目')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await proxy.$modal.confirm('是否确认删除选中的' + ids.value.length + '个项目?')
|
|
|
+ for (const id of ids.value) {
|
|
|
+ await deleteFolderRecursive(id)
|
|
|
+ }
|
|
|
+ proxy.$modal.msgSuccess('删除成功')
|
|
|
+ fetchProjects()
|
|
|
+ } catch (_) {}
|
|
|
}
|
|
|
|
|
|
-onMounted(() => { getFolderList() })
|
|
|
+onMounted(() => { loadTabs() })
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
-.portal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
|
|
|
+.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-body { display: flex; align-items: center; gap: 12px; }
|
|
|
-.card-icon { font-size: 32px; color: var(--el-color-primary); }
|
|
|
-.card-info { flex: 1; min-width: 0; }
|
|
|
-.card-title { font-size: 15px; font-weight: 500; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
-.card-meta { display: flex; align-items: center; gap: 8px; font-size: 12px; }
|
|
|
-.meta-time { color: #999; }
|
|
|
+.card-header-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
|
|
+.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-progress { margin-top: 4px; }
|
|
|
.mb16 { margin-bottom: 16px; }
|
|
|
</style>
|