| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- <template>
- <div class="app-container home">
- <!-- 太浦闸 -->
- <div class="section-header">
- <svg-icon icon-class="monitor" class="section-icon" />
- <span class="section-title">太浦闸</span>
- <span class="section-line"></span>
- <el-button link type="primary" icon="Plus" @click="openAdd('tpz')">添加模块</el-button>
- </div>
- <el-card class="home-card" shadow="never">
- <el-row :gutter="12">
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-for="(item, index) in tpzItems" :key="item.id">
- <div class="card-item" @click="goToPage('/more/tpz?folderId=' + item.id)">
- <span class="card-index">{{ index + 1 }}</span>
- <span class="card-text" :title="item.name">{{ item.name }}</span>
- </div>
- </el-col>
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-if="!loadingTpz && tpzItems.length === 0">
- <div class="empty-text">暂无数据</div>
- </el-col>
- </el-row>
- </el-card>
- <!-- 望亭闸 -->
- <div class="section-header">
- <svg-icon icon-class="example" class="section-icon" />
- <span class="section-title">望亭闸</span>
- <span class="section-line"></span>
- <el-button link type="primary" icon="Plus" @click="openAdd('wyh')">添加模块</el-button>
- </div>
- <el-card class="home-card" shadow="never">
- <el-row :gutter="12">
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-for="(item, index) in wyhItems" :key="item.id">
- <div class="card-item" @click="goToPage('/more/wyh?folderId=' + item.id)">
- <span class="card-index">{{ index + 1 }}</span>
- <span class="card-text" :title="item.name">{{ item.name }}</span>
- </div>
- </el-col>
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-if="!loadingWyh && wyhItems.length === 0">
- <div class="empty-text">暂无数据</div>
- </el-col>
- </el-row>
- </el-card>
- <!-- 直管工程 -->
- <div class="section-header">
- <svg-icon icon-class="build" class="section-icon" />
- <span class="section-title">直管工程</span>
- <span class="section-line"></span>
- <el-button link type="primary" icon="Plus" @click="openAdd('zggc')">添加项目</el-button>
- </div>
- <el-card class="home-card" shadow="never">
- <el-row :gutter="12">
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-for="(item, index) in zggcList" :key="item.id">
- <div class="project-item zggc-card" @click="goToPage('/zggc/detail/' + item.id)">
- <div class="zggc-bar" :style="{ background: 'linear-gradient(to right, rgba(15,105,220,0.7) ' + (item.planValue || 0) + '%, rgb(212,212,212) ' + (item.planValue || 0) + '%)' }"></div>
- <div class="zggc-text" :title="item.name">
- <svg-icon icon-class="build" class="project-icon" />
- <span class="zggc-name">{{ item.name }}</span>
- <span class="zggc-pct">{{ item.planValue || 0 }}%</span>
- </div>
- <span class="status-tag" :class="getZggcStatusClass(item.planValue)">{{ getZggcStatus(item.planValue) }}</span>
- </div>
- </el-col>
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-if="!loadingZggc && zggcList.length === 0">
- <div class="empty-text">暂无数据</div>
- </el-col>
- </el-row>
- </el-card>
- <!-- 重点工程 -->
- <div class="section-header">
- <svg-icon icon-class="star" class="section-icon" />
- <span class="section-title">重点工程</span>
- <span class="section-line"></span>
- <el-button link type="primary" icon="Plus" @click="openAdd('zdgc')">添加分类</el-button>
- </div>
- <el-card class="home-card" shadow="never">
- <el-row :gutter="12">
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-for="(item, index) in zdgcList" :key="item.id">
- <div class="project-item zdgc-card" @click="goToPage('/zdgc/index?folderId=' + item.id)">
- <span class="zdgc-name" :title="item.name">{{ item.name }}</span>
- </div>
- </el-col>
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-if="!loadingZdgc && zdgcList.length === 0">
- <div class="empty-text">暂无数据</div>
- </el-col>
- </el-row>
- </el-card>
- <!-- 督导检查 -->
- <div class="section-header">
- <svg-icon icon-class="search" class="section-icon" />
- <span class="section-title">督导检查</span>
- <span class="section-line"></span>
- <el-button link type="primary" icon="Plus" @click="openAdd('ddjc')">添加检查</el-button>
- </div>
- <el-card class="home-card" shadow="never">
- <el-row :gutter="12">
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-for="(item, index) in ddjcList" :key="item.id">
- <div class="card-item" @click="goToPage('/ddjc/index?folderId=' + item.id)">
- <span class="card-index">{{ index + 1 }}</span>
- <span class="card-text" :title="item.name">{{ item.name }}</span>
- </div>
- </el-col>
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-if="!loadingDdjc && ddjcList.length === 0">
- <div class="empty-text">暂无数据</div>
- </el-col>
- </el-row>
- </el-card>
- <!-- 规章制度 -->
- <div class="section-header">
- <svg-icon icon-class="documentation" class="section-icon" />
- <span class="section-title">规章制度</span>
- <span class="section-line"></span>
- <el-button link type="primary" icon="Plus" @click="openAdd('gzzd')">添加记录</el-button>
- </div>
- <el-card class="home-card" shadow="never">
- <el-row :gutter="12">
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-for="(item, index) in gzzdList" :key="item.id">
- <div class="card-item" @click="goToPage('/gzzd/index?folderId=' + item.id)">
- <svg-icon icon-class="documentation" class="card-item-icon" />
- <span class="card-text" :title="item.name">{{ item.name }}</span>
- </div>
- </el-col>
- <el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="3" v-if="!loadingGzzd && gzzdList.length === 0">
- <div class="empty-text">暂无数据</div>
- </el-col>
- </el-row>
- </el-card>
- <!-- 通用添加对话框 -->
- <el-dialog :title="addTitle" v-model="addVisible" width="480px" append-to-body>
- <el-form ref="addFormRef" :model="addForm" :rules="addRules" label-width="90px">
- <el-form-item :label="nameLabel" prop="name">
- <el-input v-model="addForm.name" placeholder="必填项,请输入名称" maxlength="100" />
- </el-form-item>
- <el-form-item v-if="showPlanInput" label="设置进度">
- <el-input-number v-model="addForm.planValue" :min="0" :max="100" style="width: 150px" />
- <span style="margin-left: 8px;">%</span>
- </el-form-item>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" :loading="addSubmitting" @click="submitAdd">立即提交</el-button>
- <el-button @click="resetAddForm">重置</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup>
- import { ref, onMounted, onActivated } from 'vue'
- import { useRouter } from 'vue-router'
- import { folderList, mkdir } from '@/api/efinder/finder'
- import { addProject } from '@/api/pms/addProject'
- const router = useRouter()
- const { proxy } = getCurrentInstance()
- const tpzItems = ref([])
- const wyhItems = ref([])
- const zggcList = ref([])
- const zdgcList = ref([])
- const ddjcList = ref([])
- const gzzdList = ref([])
- const loadingTpz = ref(false)
- const loadingWyh = ref(false)
- const loadingZggc = ref(false)
- const loadingZdgc = ref(false)
- const loadingDdjc = ref(false)
- const loadingGzzd = ref(false)
- const goToPage = (path) => {
- router.push(path)
- }
- // 添加对话框
- const addVisible = ref(false)
- const addCate = ref('')
- const addSubmitting = ref(false)
- const addFormRef = ref(null)
- const addForm = reactive({ name: '', planValue: 0 })
- const addRules = { name: [{ required: true, message: '名称不能为空', trigger: 'blur' }] }
- const addTitleMap = { tpz: '添加模块', wyh: '添加模块', zggc: '添加项目', zdgc: '添加分类', ddjc: '添加检查', gzzd: '添加记录' }
- const addTitle = computed(() => addTitleMap[addCate.value] || '添加')
- // 标签文字对齐旧版:项目(直管)/ 分类(重点/督导/规章)/ 文件夹(太浦/望亭)
- const nameLabelMap = { tpz: '文件夹名称', wyh: '文件夹名称', zggc: '项目名称', zdgc: '分类名称', ddjc: '分类名称', gzzd: '分类名称' }
- const nameLabel = computed(() => nameLabelMap[addCate.value] || '项目名称')
- // 进度仅直管工程显示(旧版 zggcPrarms=1 才显示)
- const showPlanInput = computed(() => addCate.value === 'zggc')
- function openAdd(cate) {
- addCate.value = cate
- addSubmitting.value = false
- resetAddForm()
- addVisible.value = true
- nextTick(() => proxy.resetForm('addFormRef'))
- }
- function resetAddForm() {
- addForm.name = ''
- addForm.planValue = 0
- }
- function submitAdd() {
- if (addSubmitting.value) return
- addFormRef.value.validate(valid => {
- if (!valid) return
- addSubmitting.value = true
- // 直管工程:走 addProject 接口,自动创建子目录(工程概况/程序管理/... 对齐旧版)
- if (addCate.value === 'zggc') {
- addProject({
- folderId: 0,
- name: addForm.name,
- zggcPrarms: '1',
- planValues: String(addForm.planValue)
- }).then(res => {
- addSubmitting.value = false
- if (res.code === 200) {
- proxy.$modal.msgSuccess('添加成功')
- addVisible.value = false
- refreshByCate('zggc')
- } else {
- proxy.$modal.msgError(res.msg || '添加失败')
- }
- }).catch(() => {
- addSubmitting.value = false
- proxy.$modal.msgError('添加失败')
- })
- return
- }
- // 其余模块(重点工程分类/督导检查/规章制度/太浦闸/望亭闸):直接创建顶层文件夹
- const data = { name: addForm.name, fdCate: addCate.value, pid: 0 }
- mkdir(data).then(res => {
- addSubmitting.value = false
- if (res.code === 200) {
- proxy.$modal.msgSuccess('添加成功')
- addVisible.value = false
- refreshByCate(addCate.value)
- } else {
- proxy.$modal.msgError(res.msg || '添加失败')
- }
- }).catch(() => {
- addSubmitting.value = false
- proxy.$modal.msgError('添加失败')
- })
- })
- }
- function refreshByCate(cate) {
- const map = {
- tpz: [tpzItems, loadingTpz],
- wyh: [wyhItems, loadingWyh],
- zggc: [zggcList, loadingZggc],
- zdgc: [zdgcList, loadingZdgc],
- ddjc: [ddjcList, loadingDdjc],
- gzzd: [gzzdList, loadingGzzd]
- }
- const [listRef, loadingRef] = map[cate] || []
- // 首页统一只展示顶层(pid=0),子级目录(如阶段目录)不作为一级模块展示
- if (listRef) loadByCate(cate, listRef, loadingRef, isTopLevel)
- }
- // 直管工程:状态判断(对齐原版 tba-slgc)
- function getZggcStatus(val) {
- if (!val || val === 0) return '未开工'
- if (val >= 100) return '已完工'
- return '在建'
- }
- function getZggcStatusClass(val) {
- if (!val || val === 0) return 'status-gray'
- if (val >= 100) return 'status-blue'
- return 'status-green'
- }
- // 重点工程:首页展示顶层分类(一轮治太/二轮治太/太湖流域片重大水利工程)
- const isTopLevel = (item) => !item.pid || item.pid === 0
- const loadByCate = (cate, listRef, loadingRef, filterFn) => {
- loadingRef.value = true
- // 拉取该分类全量,前端用 isTopLevel 过滤顶层(兼容 FD_PID=0 与 FD_PID IS NULL 两种数据)
- folderList({ fdCate: cate, pageSize: 999 }).then(res => {
- const list = res.rows || res.data || []
- listRef.value = filterFn ? list.filter(item => filterFn(item, list)) : list
- loadingRef.value = false
- }).catch(() => {
- listRef.value = []
- loadingRef.value = false
- })
- }
- function loadAll() {
- // 首页所有模块统一只展示顶层(pid=0),子级目录不作为一级模块展示
- loadByCate('tpz', tpzItems, loadingTpz, isTopLevel)
- loadByCate('wyh', wyhItems, loadingWyh, isTopLevel)
- loadByCate('zggc', zggcList, loadingZggc, isTopLevel)
- loadByCate('zdgc', zdgcList, loadingZdgc, isTopLevel)
- loadByCate('ddjc', ddjcList, loadingDdjc, isTopLevel)
- loadByCate('gzzd', gzzdList, loadingGzzd, isTopLevel)
- }
- // 首次挂载:onMounted 必定触发加载(onActivated 只在 keep-alive 缓存组件时触发,首次可能不触发)
- // 缓存返回时:onActivated 触发刷新;mounted 标志防止首次挂载时两个钩子重复加载
- let dataLoaded = false
- onMounted(() => {
- dataLoaded = true
- loadAll()
- })
- onActivated(() => {
- if (dataLoaded) loadAll()
- })
- </script>
- <style scoped>
- .home {
- padding: 20px;
- }
- /* 分区标题:图标 + 标题 + 渐变分隔线 */
- .section-header {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 14px;
- }
- .section-icon {
- width: 20px;
- height: 20px;
- color: #409eff;
- flex-shrink: 0;
- }
- .section-title {
- font-size: 18px;
- font-weight: 600;
- color: #303133;
- white-space: nowrap;
- }
- .section-line {
- flex: 1;
- height: 1px;
- background: linear-gradient(to right, #e4e7ed, transparent);
- }
- .home-card {
- margin-bottom: 24px;
- border-radius: 10px;
- border: 1px solid #ebeef5;
- }
- .home-card :deep(.el-card__body) {
- padding: 16px 16px 12px;
- }
- /* 通用卡片:白底 + 左色条 + hover 上浮 */
- .card-item {
- height: 44px;
- line-height: 44px;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 6px;
- background: #fff;
- border: 1px solid #ebeef5;
- border-left: 3px solid #409eff;
- border-radius: 8px;
- cursor: pointer;
- transition: all 0.25s;
- font-size: 13px;
- color: #606266;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- margin: 4px 0;
- padding: 0 8px;
- }
- .card-item:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
- border-color: #409eff;
- color: #409eff;
- }
- .card-index {
- font-size: 12px;
- color: #a8abb2;
- flex-shrink: 0;
- }
- .card-text {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .card-item-icon {
- width: 14px;
- height: 14px;
- flex-shrink: 0;
- color: #409eff;
- }
- /* 项目卡片容器(直管工程与重点工程高度统一为 60px) */
- .project-item {
- height: 60px;
- background: #fff;
- border: 1px solid #e4e7ed;
- border-radius: 10px;
- cursor: pointer;
- transition: all 0.25s;
- position: relative;
- margin: 4px 0;
- overflow: hidden;
- }
- .project-item:hover {
- transform: translateY(-3px);
- box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
- }
- /* 直管工程进度条:蓝灰双色条铺满整个卡片 */
- .zggc-bar {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- }
- .zggc-text {
- position: absolute;
- left: 8%;
- top: 50%;
- transform: translateY(-50%);
- color: #434342;
- font-size: 13px;
- font-weight: 600;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 68%;
- display: flex;
- align-items: center;
- gap: 3px;
- z-index: 1;
- background: rgba(255, 255, 255, 0.75);
- border-radius: 12px;
- padding: 3px 10px;
- }
- .zggc-name {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .zggc-pct {
- flex-shrink: 0;
- color: #fff;
- font-size: 12px;
- background: rgba(0, 0, 0, 0.25);
- border-radius: 8px;
- padding: 1px 6px;
- }
- .project-icon {
- width: 14px;
- height: 14px;
- flex-shrink: 0;
- color: #0f69dc;
- }
- /* 状态标签(右上角) */
- .status-tag {
- position: absolute;
- top: 8px;
- right: 8px;
- font-size: 11px;
- padding: 1px 8px;
- border-radius: 10px;
- color: #fff;
- z-index: 2;
- }
- .status-blue {
- background: rgba(15, 105, 220, 0.8);
- }
- .status-green {
- background: #6cdcf0;
- }
- .status-gray {
- background: #c0c4cc;
- }
- /* 重点工程:分类卡片(旧版逻辑:分类无 type 走 else 分支 → 灰色) */
- .zdgc-card {
- height: 60px;
- display: flex;
- align-items: center;
- padding: 0 10px;
- border: none;
- background: rgb(212, 212, 212);
- }
- .zdgc-name {
- color: #434342;
- font-size: 14px;
- font-weight: 600;
- margin-left: 8%;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- width: 88%;
- }
- .empty-text {
- height: 44px;
- line-height: 44px;
- text-align: center;
- color: #909399;
- font-size: 14px;
- }
- </style>
|