Преглед на файлове

重写岸线数据页面: 总览卡片+明细表格+太湖/望虞河/太浦河图表

Lin Qilong преди 5 дни
родител
ревизия
59b93d4478
променени са 2 файла, в които са добавени 161 реда и са изтрити 46 реда
  1. 14 12
      gw-ui/src/views/hlgl/riverproject/index.vue
  2. 147 34
      gw-ui/src/views/hlgl/syaxgl/index.vue

+ 14 - 12
gw-ui/src/views/hlgl/riverproject/index.vue

@@ -25,11 +25,11 @@
       <el-table-column label="项目名称" prop="sProjectName" :show-overflow-tooltip="true" min-width="180" />
       <el-table-column label="建设单位" prop="sDept" :show-overflow-tooltip="true" width="160" />
       <el-table-column label="法人代表" prop="projectLegalPerson" width="120" />
-      <el-table-column label="联系人" prop="S_LINKMAN" width="100" />
-      <el-table-column label="联系电话" prop="S_PHONE" width="130" />
-      <el-table-column label="建设阶段" prop="S_P_BUILD_STAGE" width="110" />
-      <el-table-column label="申请日期" prop="S_PGOA_DATE" width="120" />
-      <el-table-column label="项目地点" prop="S_LOCATION" :show-overflow-tooltip="true" width="160" />
+      <el-table-column label="联系人" prop="sLinkman" width="100" />
+      <el-table-column label="联系电话" prop="sPhone" width="130" />
+      <el-table-column label="建设阶段" prop="sPBuildStage" width="110" />
+      <el-table-column label="申请日期" prop="sPgoaDate" width="120" />
+      <el-table-column label="项目地点" prop="sLocation" :show-overflow-tooltip="true" width="160" />
       <el-table-column label="操作" align="center" width="150" fixed="right">
         <template #default="scope">
           <el-button link type="primary" icon="View" @click="handleDetail(scope.row)">详情</el-button>
@@ -44,13 +44,15 @@
     <el-dialog :title="dialogTitle" v-model="dialogVisible" width="700px" append-to-body>
       <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
         <el-row :gutter="20">
-          <el-col :span="12"><el-form-item label="项目名称" prop="sProjectName"><el-input v-model="form.sProjectName" /></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="建设单位" prop="sDept"><el-input v-model="form.sDept" /></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="联系人" prop="sLinkman"><el-input v-model="form.sLinkman" /></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="联系电话" prop="sPhone"><el-input v-model="form.sPhone" /></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="建设阶段" prop="sPBuildStage"><el-input v-model="form.sPBuildStage" /></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="项目性质" prop="sType"><el-input v-model="form.sType" /></el-form-item></el-col>
-          <el-col :span="24"><el-form-item label="项目地点" prop="sLocation"><el-input v-model="form.sLocation" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="项目名称" prop="sProjectName"><el-input v-model="form.sProjectName" placeholder="请输入项目名称" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="建设单位" prop="sDept"><el-input v-model="form.sDept" placeholder="请输入建设单位" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="法人代表" prop="projectLegalPerson"><el-input v-model="form.projectLegalPerson" placeholder="请输入法人代表" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="联系人" prop="sLinkman"><el-input v-model="form.sLinkman" placeholder="请输入联系人" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="联系电话" prop="sPhone"><el-input v-model="form.sPhone" placeholder="请输入联系电话" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="建设阶段" prop="sPBuildStage"><el-input v-model="form.sPBuildStage" placeholder="请输入建设阶段" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="项目性质" prop="sType"><el-input v-model="form.sType" placeholder="请输入项目性质" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="申请日期" prop="sPgoaDate"><el-date-picker v-model="form.sPgoaDate" type="date" placeholder="选择申请日期" style="width: 100%" /></el-form-item></el-col>
+          <el-col :span="24"><el-form-item label="项目地点" prop="sLocation"><el-input v-model="form.sLocation" placeholder="请输入项目地点" /></el-form-item></el-col>
         </el-row>
       </el-form>
       <template #footer>

+ 147 - 34
gw-ui/src/views/hlgl/syaxgl/index.vue

@@ -1,49 +1,162 @@
 <template>
-  <div class="app-container">
-    <el-row :gutter="20">
-      <el-col :span="24">
-        <el-card shadow="hover" style="margin-bottom:20px">
-          <template #header><span>岸线功能区统计</span></template>
-          <el-table v-loading="sLoading" :data="shoreData" border stripe size="small">
-            <el-table-column prop="TYPE" label="类别" width="120" />
-            <el-table-column prop="BELONG" label="所属" width="150" />
-            <el-table-column prop="LINELENG" label="岸线长度(km)" width="140" />
-            <el-table-column prop="LINEGN" label="功能区长度(km)" width="140" />
-            <el-table-column prop="COUNT" label="功能区数量" width="120" />
+  <div class="syax-page" v-loading="loading">
+    <!-- 标题 -->
+    <div class="page-header">
+      <h1>水域岸线功能区统计</h1>
+    </div>
+
+    <!-- 数据总览卡片 -->
+    <div class="overview-cards">
+      <div class="card" v-for="rv in overview" :key="rv.name">
+        <div class="card-name">{{ rv.name }}</div>
+        <div class="card-value">{{ rv.total }} <span class="card-unit">km</span></div>
+        <div class="card-sub">{{ rv.zones }} 个功能区</div>
+      </div>
+    </div>
+
+    <!-- 详细表格 + 图表区 -->
+    <div class="content-grid">
+      <!-- 表格 -->
+      <div class="grid-left">
+        <el-card shadow="never">
+          <template #header>岸线数据明细</template>
+          <el-table :data="tableData" border size="small" :span-method="spanMethod">
+            <el-table-column label="河(湖)名称" prop="river" width="90" />
+            <el-table-column label="总长度(km)" prop="lineLeng" width="100" />
+            <el-table-column label="功能区" prop="zone" width="100" />
+            <el-table-column label="功能区长度(km)" prop="zoneLeng" />
+            <el-table-column label="功能区数量" prop="zoneCount" width="100" />
           </el-table>
         </el-card>
-      </el-col>
-      <el-col :span="24">
-        <el-card shadow="hover">
-          <template #header><span>河湖长制工作制度</span></template>
-          <el-table v-loading="wLoading" :data="wpList" border size="small">
-            <el-table-column label="方案编号" prop="wpCode" width="160" />
-            <el-table-column label="方案名称" prop="wpName" show-overflow-tooltip />
-            <el-table-column label="文号" prop="fileNum" width="140" />
-            <el-table-column label="发布日期" prop="rlsTm" width="120" />
-            <el-table-column label="发布单位" prop="releWiunName" width="180" />
-          </el-table>
+      </div>
+
+      <!-- 图表 -->
+      <div class="grid-right">
+        <el-card shadow="never">
+          <template #header>太湖 — 功能区分布</template>
+          <div class="chart-row"><div ref="thBar" class="chart-box" /><div ref="thPie" class="chart-box" /></div>
+        </el-card>
+        <el-card shadow="never">
+          <template #header>望虞河 — 功能区分布</template>
+          <div class="chart-row"><div ref="wyBar" class="chart-box" /><div ref="wyPie" class="chart-box" /></div>
         </el-card>
-      </el-col>
-    </el-row>
+        <el-card shadow="never">
+          <template #header>太浦河 — 功能区分布</template>
+          <div class="chart-row"><div ref="tpBar" class="chart-box" /><div ref="tpPie" class="chart-box" /></div>
+        </el-card>
+      </div>
+    </div>
   </div>
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, nextTick } from 'vue'
 import { getShorelineStats } from '@/api/hzz/shoreline'
-import { listWorkPlan } from '@/api/hzz/workplan'
+import * as echarts from 'echarts'
+
+const loading = ref(false)
+const rawData = ref([])
+const thBar = ref(null), thPie = ref(null), wyBar = ref(null), wyPie = ref(null), tpBar = ref(null), tpPie = ref(null)
+const refMap = { thBar, thPie, wyBar, wyPie, tpBar, tpPie }
+
+const zones = ['保护区', '保留区', '控制利用区']
+const tableData = ref([])
+const overview = ref([])
+
+const spanMethod = ({ columnIndex, rowIndex }) => {
+  if (columnIndex <= 1) {
+    const rows = tableData.value
+    for (let i = rowIndex - 1; i >= 0; i--) { if (rows[i].river === rows[rowIndex].river) return { rowspan: 0, colspan: 1 } }
+    let cnt = 1; for (let i = rowIndex + 1; i < rows.length && rows[i].river === rows[rowIndex].river; i++) cnt++
+    return { rowspan: cnt, colspan: 1 }
+  }
+}
 
-const sLoading = ref(false), shoreData = ref([])
-const wLoading = ref(false), wpList = ref([])
+const rivers = [
+  { name: '太湖', key: 'th', indices: [0,1,2], chartRefs: { bar: 'thBar', pie: 'thPie' } },
+  { name: '望虞河', key: 'wy', indices: [3,4,5], chartRefs: { bar: 'wyBar', pie: 'wyPie' } },
+  { name: '太浦河', key: 'tp', indices: [6,8], chartRefs: { bar: 'tpBar', pie: 'tpPie' } },
+]
+
+const buildTable = () => {
+  const d = rawData.value
+  tableData.value = [
+    { river: '太湖', lineLeng: d[0]?.lineLeng || '-', zone: '保护区', zoneLeng: d[0]?.lineGn || '-', zoneCount: d[0]?.count || '-' },
+    { river: '太湖', lineLeng: '', zone: '保留区', zoneLeng: d[1]?.lineGn || '-', zoneCount: d[1]?.count || '-' },
+    { river: '太湖', lineLeng: '', zone: '控制利用区', zoneLeng: d[2]?.lineGn || '-', zoneCount: d[2]?.count || '-' },
+    { river: '望虞河', lineLeng: d[3]?.lineLeng || '-', zone: '保护区', zoneLeng: d[3]?.lineGn || '-', zoneCount: d[3]?.count || '-' },
+    { river: '望虞河', lineLeng: '', zone: '保留区', zoneLeng: d[4]?.lineGn || '-', zoneCount: d[4]?.count || '-' },
+    { river: '望虞河', lineLeng: '', zone: '控制利用区', zoneLeng: d[5]?.lineGn || '-', zoneCount: d[5]?.count || '-' },
+    { river: '太浦河', lineLeng: d[6]?.lineLeng || '-', zone: '保护区', zoneLeng: d[6]?.lineGn || '-', zoneCount: d[6]?.count || '-' },
+    { river: '太浦河', lineLeng: '', zone: '控制利用区', zoneLeng: d[8]?.lineGn || '-', zoneCount: d[8]?.count || '-' },
+  ]
+  overview.value = [
+    { name: '太湖', total: d[0]?.lineLeng || '-', zones: 3 },
+    { name: '望虞河', total: d[3]?.lineLeng || '-', zones: 3 },
+    { name: '太浦河', total: d[6]?.lineLeng || '-', zones: 2 },
+  ]
+}
+
+const renderCharts = () => {
+  const d = rawData.value
+  nextTick(() => {
+    rivers.forEach(rv => {
+      const vals = rv.indices.map(i => Number(d[i]?.lineGn || 0))
+      const names = rv.indices.map(i => zones[i === 8 ? 2 : i === 6 && rv.key === 'tp' ? 0 : rv.indices.indexOf(i)])
+      const labels = rv.key === 'tp' ? ['保护区', '控制利用区'] : zones
+
+      const makeChart = (r, type) => {
+        const el = refMap[rv.key + (type === 'bar' ? 'Bar' : 'Pie')].value
+        if (!el) return
+        const c = echarts.init(el)
+        c.setOption(type === 'bar' ? {
+          grid: { top: 20, bottom: 30, left: 40, right: 20 },
+          xAxis: { type: 'category', data: labels }, yAxis: { type: 'value', name: 'km' },
+          series: [{ type: 'bar', data: vals, itemStyle: { color: '#409EFF' }, barMaxWidth: 50 }]
+        } : {
+          series: [{ type: 'pie', radius: ['45%','70%'], center: ['50%','55%'], data: labels.map((n,i)=>({name:n,value:vals[i]})), label: { formatter: '{b}\n{d}%', fontSize: 12 } }]
+        })
+        window.addEventListener('resize', () => c.resize())
+      }
+      makeChart(rv, 'bar')
+      makeChart(rv, 'pie')
+    })
+  })
+}
 
 onMounted(async () => {
-  sLoading.value = true; wLoading.value = true
+  loading.value = true
   try {
-    const [sr, wr] = await Promise.all([getShorelineStats(), listWorkPlan('')])
-    shoreData.value = sr.data || []
-    wpList.value = wr.data || []
-  } catch { /* ok */ }
-  finally { sLoading.value = false; wLoading.value = false }
+    const res = await getShorelineStats()
+    rawData.value = res.data || []
+    buildTable()
+    renderCharts()
+  } finally { loading.value = false }
 })
 </script>
+
+<style scoped>
+.syax-page { padding: 20px 24px; overflow-y: auto; height: calc(100vh - 84px); background: #f0f2f5; }
+.page-header { margin-bottom: 20px; }
+.page-header h1 { font-size: 20px; color: #1a1a2e; font-weight: 600; margin: 0; }
+.page-header h1::before { content: ''; display: inline-block; width: 4px; height: 20px; background: #409EFF; margin-right: 10px; vertical-align: middle; border-radius: 2px; }
+
+/* 总览卡片 */
+.overview-cards { display: flex; gap: 16px; margin-bottom: 20px; }
+.card { flex: 1; background: #fff; border-radius: 8px; padding: 20px; text-align: center; box-shadow: 0 1px 4px rgba(0,0,0,.06); }
+.card-name { font-size: 14px; color: #666; margin-bottom: 8px; }
+.card-value { font-size: 28px; font-weight: 700; color: #0d4b80; }
+.card-unit { font-size: 13px; font-weight: 400; color: #999; }
+.card-sub { font-size: 12px; color: #999; margin-top: 4px; }
+
+/* 内容区 */
+.content-grid { display: flex; gap: 16px; align-items: flex-start; }
+.grid-left { width: 520px; flex-shrink: 0; }
+.grid-right { flex: 1; display: flex; flex-direction: column; gap: 16px; min-width: 0; }
+
+.chart-row { display: flex; gap: 12px; }
+.chart-box { flex: 1; height: 240px; }
+
+:deep(.el-card__header) { font-size: 14px; font-weight: 600; color: #333; padding: 12px 16px; }
+:deep(.el-card__body) { padding: 12px 16px; }
+</style>