WXL
3 天以前 4c9fdc87987140e8b2c3f0dfc2f6608cdb6be774
src/views/home/index.vue
@@ -1,2162 +1,860 @@
<template>
  <div>
    <div v-loading="isloading" style="padding: 10px">
      <div>
        <el-image
          style="width: 100%; height: 72px"
          :src="img.head"
          fit="contain"
        ></el-image>
  <div v-loading="loading" class="cockpit">
    <!-- 顶部标题栏 -->
    <header class="cockpit-header">
      <div class="header-left">
        <span class="header-logo"></span>
        <h1 class="header-title">青岛大学附属医院 · OPO 器官捐献管理驾驶舱</h1>
      </div>
      <div class="header-right">
        <span class="header-clock">{{ now }}</span>
        <el-button type="text" class="header-logout" @click="handleLogout"
          >退出</el-button
        >
      </div>
    </header>
      <el-row :gutter="20">
        <el-col :span="6">
          <div class="iwc-dv-box" style="margin-bottom: 0.5rem">
            <dv-border-box-7
              :color="['#0a336e', '#1a7ade']"
              :backgroundColor="'#030e40'"
            >
              <div class="iwc-box-head">占比统计</div>
              <div style="padding: 0 2rem">
                <div class="iwc-box-a" :style="'height:' + heightA + 'px'">
                  <div class="iwc-box-a-1">
                    <span
                      class="iwc-before-o"
                      style="border-color: #38a5f8"
                    ></span
                    >性别占比:{{
                      currentZb.sex == -1 ? "" : arrZb.sex[currentZb.sex].label
                    }}
                  </div>
                  <el-progress
                    :text-inside="true"
                    :stroke-width="15"
                    :percentage="
                      currentZb.sex == -1
                        ? 0
                        : Number(
                            (arrZb.sex[currentZb.sex].value * 100).toFixed(0)
                          )
                    "
                    :color="'#38a5f8'"
                  ></el-progress>
                </div>
                <div class="iwc-box-a" :style="'height:' + heightA + 'px'">
                  <div class="iwc-box-a-1">
                    <span
                      class="iwc-before-o"
                      style="border-color: #9078e5"
                    ></span
                    >年龄占比:{{
                      currentZb.age == -1 ? "" : arrZb.age[currentZb.age].label
                    }}
                  </div>
                  <el-progress
                    :text-inside="true"
                    :stroke-width="15"
                    :percentage="
                      currentZb.age == -1
                        ? 0
                        : Number(
                            (arrZb.age[currentZb.age].value * 100).toFixed(0)
                          )
                    "
                    :color="'#9078e5'"
                  ></el-progress>
                </div>
                <div class="iwc-box-a" :style="'height:' + heightA + 'px'">
                  <div class="iwc-box-a-1">
                    <span
                      class="iwc-before-o"
                      style="border-color: #3fc529"
                    ></span
                    >捐献分类占比:{{
                      currentZb.type == -1
                        ? ""
                        : arrZb.type[currentZb.type].label
                    }}
                  </div>
                  <el-progress
                    :text-inside="true"
                    :stroke-width="15"
                    :percentage="
                      currentZb.type == -1
                        ? 0
                        : Number(
                            (arrZb.type[currentZb.type].value * 100).toFixed(0)
                          )
                    "
                    :color="'#3fc529'"
                  ></el-progress>
                </div>
                <div class="iwc-box-a" :style="'height:' + heightA + 'px'">
                  <div class="iwc-box-a-1">
                    <span
                      class="iwc-before-o"
                      style="border-color: #2a65b5"
                    ></span
                    >疾病占比:{{
                      currentZb.d == -1 ? "" : arrZb.d[currentZb.d].label
                    }}
                  </div>
                  <el-progress
                    :text-inside="true"
                    :stroke-width="15"
                    :percentage="
                      currentZb.d == -1
                        ? 0
                        : Number((arrZb.d[currentZb.d].value * 100).toFixed(0))
                    "
                    :color="'#2a65b5'"
                  ></el-progress>
                </div>
                <div class="iwc-box-a" :style="'height:' + heightA + 'px'">
                  <div class="iwc-box-a-1">
                    <span
                      class="iwc-before-o"
                      style="border-color: #fbc329"
                    ></span
                    >血型占比:{{
                      currentZb.x == -1 ? "" : arrZb.x[currentZb.x].label
                    }}
                  </div>
                  <el-progress
                    :text-inside="true"
                    :stroke-width="15"
                    :percentage="
                      currentZb.x == -1
                        ? 0
                        : Number((arrZb.x[currentZb.x].value * 100).toFixed(0))
                    "
                    :color="'#fbc329'"
                  ></el-progress>
                </div>
              </div>
            </dv-border-box-7>
    <!-- KPI 指标卡 -->
    <section class="kpi-row">
      <div v-for="kpi in kpiCards" :key="kpi.label" class="kpi-card">
        <div class="kpi-icon" :style="{ background: kpi.gradient }">
          <i :class="kpi.icon"></i>
        </div>
        <div class="kpi-body">
          <div class="kpi-label">{{ kpi.label }}</div>
          <div class="kpi-value">
            <count-to
              :start-val="0"
              :end-val="kpi.value"
              :duration="1400"
              :decimals="kpi.decimals || 0"
              separator=","
            />
            <span class="kpi-unit">{{ kpi.unit }}</span>
          </div>
        </div>
      </div>
    </section>
          <div class="iwc-dv-box" style="margin-bottom: 0.5rem">
            <dv-border-box-7
              :color="['#0a336e', '#1a7ade']"
              :backgroundColor="'#030e40'"
            >
              <div class="iwc-box-head">机构捐献统计</div>
    <!-- 仪表盘指标 -->
    <section class="gauge-row">
      <div v-for="g in gaugeCharts" :key="g.name" class="panel">
        <div class="panel-title">{{ g.name }}</div>
        <G2PlotChart type="gauge" :options="g.options" :height="150" />
      </div>
    </section>
              <div
                style="padding: 0 2rem"
                :style="'height:' + (height * 0.35 - 54) + 'px'"
              >
                <dv-scroll-board
                  :config="tableConfig"
                  style="width: 100%"
                  class="iwc-h-rb-table"
                  :style="'height:' + (height * 0.35 - 54) + 'px'"
    <!-- 主区:地图居中,其他图环绕 -->
    <el-row :gutter="16">
      <el-col :span="6">
        <div class="col-stack">
          <div class="panel">
            <div class="panel-title">案例月度趋势</div>
            <G2PlotChart type="area" :options="trendOptions" :height="205" />
          </div>
          <div class="panel">
            <div class="panel-title">器官获取 / 移植趋势</div>
            <G2PlotChart type="line" :options="organMoonOptions" :height="205" />
          </div>
        </div>
      </el-col>
      <el-col :span="12">
        <div class="panel panel--map">
          <div class="panel-title">地区分布</div>
          <MapChart
            :cdata="raw.mapData"
            :height="'480px'"
            :zoom="1.4"
            left="center"
            top="middle"
            label-mode="name"
            dark
            :roam="true"
            @click="mapClick"
          />
        </div>
      </el-col>
      <el-col :span="6">
        <div class="col-stack">
          <div class="panel">
            <div class="panel-title">地区捐献对比</div>
            <G2PlotChart type="column" :options="areaOptions" :height="205" />
          </div>
          <div class="panel panel--carousel">
            <div class="panel-title">{{ currentCarousel.title }}</div>
            <transition name="fade" mode="out-in">
              <div :key="carouselIndex" class="carousel-body">
                <G2PlotChart
                  :type="currentCarousel.type"
                  :options="currentCarousel.options"
                  :height="205"
                />
              </div>
            </dv-border-box-7>
          </div>
        </el-col>
        <el-col :span="12">
          <div class="iwc-box-d" style="height: 125px">
            <div class="iwc-box-d-1">
              <div class="iwc-box-d-img">
                <el-image
                  style="width: 100%; height: 100%"
                  :src="img.btn1"
                  fit="cover"
                ></el-image>
              </div>
              <div class="iwc-box-d-f">
                <div class="iwc-box-d-f1">{{ leijishuju.processOrgans }}</div>
                <div class="iwc-box-d-f2">捐献案例累计</div>
              </div>
            </div>
            <div class="iwc-box-d-1">
              <div class="iwc-box-d-img">
                <el-image
                  style="width: 100%; height: 100%"
                  :src="img.btn2"
                  fit="cover"
                ></el-image>
              </div>
              <div class="iwc-box-d-f">
                <div class="iwc-box-d-f1">{{ leijishuju.finishedOrgans }}</div>
                <div class="iwc-box-d-f2">捐献完成累计</div>
              </div>
            </div>
            <div class="iwc-box-d-1">
              <div class="iwc-box-d-img">
                <el-image
                  style="width: 100%; height: 100%"
                  :src="img.btn3"
                  fit="cover"
                ></el-image>
              </div>
              <div class="iwc-box-d-f">
                <div class="iwc-box-d-f1">{{ leijishuju.Organsnum }}</div>
                <div class="iwc-box-d-f2">捐献器官累计</div>
              </div>
            </div>
            <div class="iwc-box-d-1" style="flex: 1.4">
              <div class="iwc-box-d-img">
                <el-image
                  style="width: 100%; height: 100%"
                  :src="img.btn4"
                  fit="cover"
                ></el-image>
              </div>
              <div class="iwc-box-d-f">
                <div class="iwc-box-d-f1">{{ leijishuju.PMP }}</div>
                <div class="iwc-box-d-f2">每百万人口器官捐献率(PMP)</div>
              </div>
            </transition>
            <div class="carousel-dots">
              <span
                v-for="(item, i) in carouselItems"
                :key="i"
                class="dot"
                :class="{ active: i === carouselIndex }"
                @click="carouselIndex = i"
              ></span>
            </div>
          </div>
        </div>
      </el-col>
    </el-row>
          <div class="iwc-box-e" style="margin-bottom: 10px; padding-left: 12%">
            <el-col :span="17">
              <MapChart
                :cdata="cdata"
                :height="height * 0.72 - 128 + 'px'"
                @click="mapClick"
                :chartType="chartType"
              />
            </el-col>
            <el-col :span="7">
              <div
                style="backgroun-color:black; margin-bottom:5px;height:100%;padding-top:50px;"
              >
                <el-row>
                  <div style="color:white;font-size:15px;text-align:center">
                    当前各地市潜在捐献案例
                  </div>
                </el-row>
                <el-row>
                  <el-col
                    :span="12"
                    style="color:white;font-size:14px;text-align:center;margin-top:10px"
                    v-for="(item, index) in cityDonoateCaseArr"
                    :key="index"
                  >
                    {{ item.cityName }}<br />
                    <span style="color:#ffd200">{{ item.donoateNum }}</span
                    >例
                  </el-col>
                </el-row>
              </div>
            </el-col>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="iwc-dv-box" style="margin-bottom: 0.5rem">
            <dv-border-box-7
              :color="['#0a336e', '#1a7ade']"
              :backgroundColor="'#030e40'"
            >
              <div class="iwc-box-head">器官获取统计</div>
              <el-row
                style="padding: 0 2rem"
                :style="'height:' + (height * 0.35 - 54) + 'px'"
              >
                <el-col
                  :span="8"
                  v-for="(item, index) in organSumData"
                  :key="index"
                >
                  <div
                    style="
                      color: #fff;
                      padding-bottom: 10px;
                    "
                  >
                    {{ item.name }}:<span style="font-size: 18px">{{
                      item.value
                    }}</span>
                  </div>
                </el-col>
              </el-row>
            </dv-border-box-7>
          </div>
          <div class="iwc-dv-box" style="margin-bottom: 0.5rem">
            <dv-border-box-7
              :color="['#0a336e', '#1a7ade']"
              :backgroundColor="'#030e40'"
            >
              <div class="iwc-box-head">机构接受器官统计</div>
              <el-row
                style="padding: 0 1rem"
                :style="'height:' + (height * 0.35 - 54) + 'px'"
              >
                <dv-scroll-board
                  v-if="configHosOrgan.data.length > 0"
                  :config="configHosOrgan"
                  class="iwc-box-b-table"
                  style="width: 100%"
                  :style="'height:' + (height * 0.35 - 54) + 'px'"
                />
              </el-row>
            </dv-border-box-7>
          </div>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="6">
          <div class="iwc-dv-box" style="margin-bottom: 0.5rem">
            <dv-border-box-7
              :color="['#0a336e', '#1a7ade']"
              :backgroundColor="'#030e40'"
            >
              <div class="iwc-box-head">历年捐献数据</div>
              <el-row
                style="padding: 0 1rem"
                :style="'height:' + (height * 0.28 - 80) + 'px'"
              >
                <BarChartH
                  :cdata="cdataYear"
                  :organData="organYearData"
                  :height="height * 0.28 - 80 + 'px'"
                />
              </el-row>
            </dv-border-box-7>
          </div>
        </el-col>
        <el-col :span="12">
          <div class="iwc-dv-box" style="margin-bottom: 0.5rem">
            <dv-border-box-7
              :color="['#0a336e', '#1a7ade']"
              :backgroundColor="'#030e40'"
            >
              <div class="iwc-box-head">捐献案例月度统计</div>
              <div style="padding: 0 2rem">
                <LineChart
                  :cdata="anlidata"
                  :height="height * 0.28 - 80 + 'px'"
                />
              </div>
            </dv-border-box-7>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="iwc-dv-box">
            <dv-border-box-7
              :color="['#0a336e', '#1a7ade']"
              :backgroundColor="'#030e40'"
            >
              <div class="iwc-box-head">质控指标</div>
              <div
                style="padding: 0 2rem"
                :style="'height:' + (height * 0.28 - 80) + 'px'"
              >
                <div class="iwc-box-c">
                  <div class="iwc-box-c1" style="color: #fac738">
                    <div class="iwc-box-c1-o">
                      {{
                        leijishuju.donateTransferRate
                          ? leijishuju.donateTransferRate.toFixed(2)
                          : ""
                      }}
                    </div>
                    <div class="iwc-box-c1-l" style="font-size:0.8rem">
                      器官捐献转化率
                    </div>
                  </div>
                  <div class="iwc-box-c1" style="color: #34bc1d">
                    <div class="iwc-box-c1-o">
                      {{
                        leijishuju.organProductionRate
                          ? leijishuju.organProductionRate.toFixed(2)
                          : ""
                      }}
                    </div>
                    <div class="iwc-box-c1-l" style="font-size:0.8rem">
                      平均器官产出率
                    </div>
                  </div>
                  <div class="iwc-box-c1" style="color: #2f9ef4">
                    <div class="iwc-box-c1-o">
                      {{
                        leijishuju.organUsedRate
                          ? leijishuju.organUsedRate.toFixed(2)
                          : ""
                      }}
                    </div>
                    <div class="iwc-box-c1-l" style="font-size:0.8rem">
                      获取器官利用率
                    </div>
                  </div>
                </div>
              </div>
            </dv-border-box-7>
          </div>
        </el-col>
      </el-row>
      <!-- <el-row v-if="0" class="c-home" :gutter="10">
        <el-col :span="8">
          <div style="padding-top: 25px; padding-bottom: 10px">
            <dv-border-box-2 :color="['#1b88a3']">
              <div class="box-title" style="position: absolute; top: -8px">
                <span><b>对比分析</b></span>
              </div>
              <div style="padding: 40px 10px">
                <div
                  class="c-table-title light"
                  v-if="0"
                  style="height: 50px; line-height: 50px"
                >
                  器官统计
                </div>
                <LineChart :cdata="anlidata" :height="height / 7 + 'px'" />
                <Line2Chart :cdata="yiyuan" :height="height / 7 + 'px'" />
                <Line1Chart :cdata="organsum" :height="height / 7 + 'px'" />
                <BarChart :cdata="organData" :height="height / 7 + 'px'" />
                <BarChart2
                  :cdata="hosGetData"
                  :height="(height / 7) * 2 + 'px'"
                />
                <BarChart3
                  :cdata="organSumData"
                  :height="(height - 10) / 7 + 'px'"
                />
              </div>
            </dv-border-box-2>
          </div>
        </el-col>
        <el-col :span="8" style="margin-top: 28px">
          <dv-border-box-12 :color="['#1b88a3']" style="padding: -20px">
            <div class="box-title" style="position: absolute; top: -8px">
              <span><b>全省概况</b></span>
            </div>
            <div style="padding: 30px 20px 30px; margin: 0 auto">
              <el-row>
                <el-col :span="8" class="box-num">
                  <div class="box-num-main" style="text-align: center">
                    <p>潜在捐献累计</p>
                    <span class="box-num-main-n">{{
                      leijishuju.processOrgans
                    }}</span>
                  </div>
                  <div class="box-num-ex">
                    <span></span>
                  </div>
                </el-col>
                <el-col :span="8" class="box-num">
                  <div class="box-num-main" style="text-align: center">
                    <p>捐献完成累计</p>
                    <span class="box-num-main-n">{{
                      leijishuju.finishedOrgans
                    }}</span>
                  </div>
                  <div style="height: 20px"></div>
                  <div class="box-num-ex">
                    <span></span>
                  </div>
                </el-col>
                <el-col :span="8" class="box-num">
                  <div class="box-num-main" style="text-align: center">
                    <p>捐献器官累计</p>
                    <span class="box-num-main-n">{{
                      leijishuju.Organsnum
                    }}</span>
                  </div>
                  <div class="box-num-ex">
                    <span></span>
                  </div>
                </el-col>
              </el-row>
              <el-row style="margin-bottom: 10px">
                <el-col :span="12" class="box-num">
                  <div class="box-num-main" style="text-align: center">
                    <p>每百万人口器官捐献率(PMP)</p>
                    <span class="box-num-main-n">{{ leijishuju.PMP }}</span>
                  </div>
                  <div class="box-num-ex">
                    <span></span>
                  </div>
                </el-col>
                <el-col :span="12" class="box-num">
                  <div class="box-num-main" style="text-align: center">
                    <p>潜献转化率/器官产出率/器官利用率</p>
                    <span class="box-num-main-n">
                      {{ leijishuju.donateTransferRate.toFixed(2) }}/{{
                        leijishuju.organProductionRate.toFixed(2)
                      }}/{{ leijishuju.organUsedRate.toFixed(2) }}</span
                    >
                  </div>
                  <div class="box-num-ex">
                    <span></span>
                  </div>
                </el-col>
              </el-row>
            </div>
          </dv-border-box-12>
          <dv-border-box-7 :color="['#fff']">
            <dv-border-box-8>
              <div style="padding: 40px 20px">
                <div style="padding-top: 12px"></div>
                <MapChart
                  :cdata="cdata"
                  :height="height - 220 + 'px'"
                  @click="mapClick"
                  :chartType="chartType"
                /></div></dv-border-box-8
          ></dv-border-box-7>
        </el-col>
        <el-col :span="8" v-loading="tableLoading" style="padding-top: 28px">
          <dv-border-box-6 :color="['#1b88a3']">
            <div class="box-title" style="position: absolute; top: -8px">
              <span><b>占比统计</b></span>
            </div>
            <div
              class="iwc-ring"
              v-if="1"
              style="
                padding: 30px 10px 20px;
                min-height: 280px;
                text-align: center;
              "
            >
              <el-row
                ><el-col :span="8">
                  <dv-active-ring-chart
                    v-if="configSex.data.length > 0"
                    :config="configSex"
                    style="width: 100%; height: 100px"
                  />
                  <div>性别占比</div></el-col
                ><el-col :span="8">
                  <dv-active-ring-chart
                    v-if="configAge.data.length > 0"
                    :config="configAge"
                    style="width: 100%; height: 100px"
                  />
                  <div>年龄占比</div></el-col
                ><el-col :span="8">
                  <dv-active-ring-chart
                    v-if="configDd.data.length > 0"
                    :config="configDd"
                    style="width: 100%; height: 100px"
                  />
                  <div>捐献分类占比</div></el-col
                ></el-row
              >
              <el-row
                ><el-col :span="12">
                  <dv-active-ring-chart
                    v-if="configD.data.length > 0"
                    :config="configD"
                    style="width: 100%; height: 100px"
                  />
                  <div>疾病占比</div></el-col
                ><el-col :span="12">
                  <dv-active-ring-chart
                    v-if="configX.data.length > 0"
                    :config="configX"
                    style="width: 100%; height: 100px"
                  />
                  血型占比</el-col
                ></el-row
              >
            </div>
            <div v-if="0" style="padding: 30px 10px 20px; min-height: 280px">
              <el-row style="margin-bottom: 10px">
                <el-col :span="7" style="text-align: right">男女占比</el-col>
                <el-col :span="17">
                  <div style="display: flex; text-align: center">
                    <div style="flex: 1">
                      <span class="fc-white">男</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.manRate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">女</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.womanRate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                  </div>
                </el-col>
              </el-row>
              <el-row style="margin-bottom: 10px">
                <el-col :span="7" style="text-align: right"
                  >捐献分类占比</el-col
                >
                <el-col :span="17">
                  <div style="display: flex; text-align: center">
                    <div style="flex: 1">
                      <span class="fc-white">DBD</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.dbdrate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">DCD</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.dcdrate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">DBCD</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.dbcdrate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                  </div>
                </el-col>
              </el-row>
              <el-row style="margin-bottom: 10px">
                <el-col :span="7" style="text-align: right">年龄占比</el-col>
                <el-col :span="17">
                  <div style="display: flex; text-align: center">
                    <div style="flex: 1">
                      <span class="fc-white">1-17岁</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.a1Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">18-49岁</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.a2Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">49-69岁</span>&nbsp;<span
                        class="fc-sp"
                        >{{ (objZb.a3Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                  </div>
                </el-col>
              </el-row>
              <el-row style="margin-bottom: 10px">
                <el-col
                  :span="24"
                  style="margin-bottom: 10px; text-align: center"
                  >血型占比</el-col
                >
                <el-col :span="24">
                  <div style="display: flex; text-align: center">
                    <div style="flex: 1">
                      <span class="fc-white">A型</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.xarate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">B型</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.xbrate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">AB型</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.xabrate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">O型</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.xorate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                  </div>
                </el-col>
              </el-row>
              <el-row>
                <el-col
                  :span="24"
                  style="margin-bottom: 10px; text-align: center"
                  >病因占比</el-col
                >
                <el-col :span="24">
                  <div style="display: flex; text-align: center">
                    <div style="flex: 1">
                      <span class="fc-white">脑血管意外</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.d0Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">脑外伤</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.d1Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">缺血缺氧性脑病</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.d2Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">脑肿瘤</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.d3Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                    <div style="flex: 1">
                      <span class="fc-white">心血管疾病</span><br /><span
                        class="fc-sp"
                        >{{ (objZb.d4Rate * 100).toFixed(2) + "%" }}</span
                      >
                    </div>
                  </div>
                </el-col>
              </el-row>
            </div>
          </dv-border-box-6>
          <dv-border-box-6 :color="['#1b88a3']" style="margin-top: 30px">
            <div class="box-title" style="position: absolute; top: -8px">
              <span><b>机构统计</b></span>
            </div>
            <div style="padding: 20px">
              <el-row class="c-table-title">
                <el-col :span="18" :class="isAll ? 'active' : ''">
                  <el-divider content-position="left"
                    ><span>浙江省</span></el-divider
                  ></el-col
                >
                <el-col :span="6"><el-divider></el-divider></el-col>
              </el-row>
              <dv-scroll-board
                :config="tableConfig"
                style="width: 100%; border: 1px solid #142984"
                class="iwc-h-rb-table"
                :style="{ height: height - 310 + 'px' }"
              />
            </div>
          </dv-border-box-6>
        </el-col>
      </el-row> -->
      <el-dialog title="登陆" :visible.sync="dialogVisible" width="30%">
        <el-form :model="form">
          <el-form-item label="账号" label-width="80px">
            <el-input
              v-model="defaultAccount"
              autocomplete="off"
              @keyup.enter.native="loginFn"
            ></el-input>
          </el-form-item>
          <el-form-item
            label="密码"
            label-width="80px"
    <!-- 登录弹窗 -->
    <el-dialog
      title="登录"
      :visible.sync="dialogVisible"
      width="380px"
      :close-on-click-modal="false"
      :show-close="false"
      append-to-body
      custom-class="login-dialog"
    >
      <el-form :model="form" @submit.native.prevent>
        <el-form-item label="账号" label-width="60px">
          <el-input
            v-model="defaultAccount"
            autocomplete="off"
            placeholder="请输入账号"
            @keyup.enter.native="loginFn"
          >
            <el-input
              v-model="defaultPassword"
              show-password
              autocomplete="off"
            ></el-input>
          </el-form-item>
          <el-form-item prop="code" label-width="80px">
            <el-input
              v-model="code"
              auto-complete="off"
              placeholder="验证码"
              style="width: 63%"
              @keyup.enter.native="loginFn"
            >
              <svg-icon
                slot="prefix"
                icon-class="validCode"
                class="el-input__icon input-icon"
              />
            </el-input>
            <div class="login-code">
              <img :src="codeUrl" @click="getCode" class="login-code-img" />
            </div>
          </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
          <el-button @click="dialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="loginFn">确 定</el-button>
        </span>
      </el-dialog>
    </div>
          ></el-input>
        </el-form-item>
        <el-form-item label="密码" label-width="60px">
          <el-input
            v-model="defaultPassword"
            show-password
            autocomplete="off"
            placeholder="请输入密码"
            @keyup.enter.native="loginFn"
          ></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" :loading="loginLoading" @click="loginFn"
          >登 录</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>
<script>
import {
  getNumberOfOrgan,
  getOrgansOfHospital,
  getAllOrganInfo,
  countDonateorgan,
  countDonateHostipal,
  countorganHostipal,
  getDonateNumber,
  getdonateBaseInfoByMonth,
  getdonatePeopleByMonth,
  getdonateNumberByMonth,
  getdonateHospitalByMonth,
  getacceptHospitalByMonths,
  getOrgansOfHospitalByMonth,
  getDonateorganPMP,
  getDonateorganQuality,
  getDonationwitnessStats,
  getTransplantHospitalNum,
  getDonateorganSum,
  getDonateorganDistrictDonateCalculate
} from "@/api/project/donateorgan";
import { listData } from "@/api/system/dict/data";
import { login, logout, getInfo, getCodeImg } from "@/api/login";
import { listDonatebaseinfo } from "@/api/project/donatebaseinfo";
import { getToken, setToken, removeToken } from "@/utils/auth";
import MapChart from "./components/MapChart";
import BarChart from "./components/BarChart";
import BarChart2 from "./components/BarChart2";
import BarChart3 from "./components/BarChart3";
import BarChartH from "./components/BarChartH";
import LineChart from "./components/lineChart";
import Line1Chart from "./components/line1Chart";
import Line2Chart from "./components/line2Chart";
const DEF_TABLE_CONFIG = {
  header: ["区域", "机构", "捐献登记", "捐献完成"],
  data: [],
  headerBGC: "#0a3073",
  oddRowBGC: "",
  evenRowBGC: "",
  rowNum: 6
<script>
import CountTo from 'vue-count-to';
import G2PlotChart from '@/components/charts/G2PlotChart.vue';
import MapChart from './components/MapChart';
import { login } from '@/api/login';
import { encrypts } from '@/utils/crypto';
import { setToken, removeToken } from '@/utils/auth';
import { xAxis, yAxis, legend, tooltip } from '@/utils/g2Dark';
import { toMonth, toNum } from '@/utils/totals';
import { mockCockpitData } from './cockpitMock';
const AGE_LABELS = {
  '1': '≤17岁',
  '2': '18-49岁',
  '3': '50-69岁',
  '4': '≥70岁',
  '0-17': '≤17岁',
  '18-49': '18-49岁',
  '50-69': '50-69岁',
  '70-100': '≥70岁'
};
export default {
  name: "home",
  props: {},
  components: {
    MapChart,
    BarChart,
    BarChart2,
    BarChart3,
    BarChartH,
    LineChart,
    Line1Chart,
    Line2Chart
  },
  name: 'home',
  components: { CountTo, G2PlotChart, MapChart },
  data() {
    return {
      img: {
        head: require("../../assets/images/dv-head.png"),
        btn1: require("../../assets/images/dv-btn-1.png"),
        btn2: require("../../assets/images/dv-btn-2.png"),
        btn3: require("../../assets/images/dv-btn-3.png"),
        btn4: require("../../assets/images/dv-btn-4.png")
      },
      leijishuju: {},
      arrrrr: [],
      captchaOnOff: true,
      uuid: "",
      form: {},
      hospitallist: [],
      year: "",
      code: "",
      codeUrl: "",
      now: '',
      clockTimer: null,
      carouselTimer: null,
      loading: false,
      loginLoading: false,
      dialogVisible: true,
      isloading: false,
      tableLoading: false,
      showTable: false,
      currentArea: null,
      tableList: [],
      defaultAccount: "",
      defaultPassword: "",
      pageData: {
        pageNum: 1,
        pageSize: 10
      },
      total: 0,
      height: 1080,
      width: 1920,
      isAll: true,
      chartType: "map",
      tableConfig: { ...DEF_TABLE_CONFIG },
      totalCount: 0,
      allInfo: {
        finishedOrgans: 0,
        processOrgans: 4,
        Organsnum: 0
      },
      anlidata: [
        {
          name: "1月",
          value: 0
        },
        {
          name: "2月",
          value: 0
        },
        {
          name: "3月",
          value: 0
        },
        {
          name: "4月",
          value: 0
        },
        {
          name: "5月",
          value: 0
        },
        {
          name: "6月",
          value: 0
        },
        {
          name: "7月",
          value: 0
        },
        {
          name: "8月",
          value: 0
        },
        {
          name: "9月",
          value: 0
        },
        {
          name: "10月",
          value: 0
        },
        {
          name: "11月",
          value: 0
        },
        {
          name: "12月",
          value: 0
        }
      ],
      organsum: [
        {
          name: "一月",
          value: 0
        },
        {
          name: "二月",
          value: 0
        },
        {
          name: "三月",
          value: 0
        },
        {
          name: "四月",
          value: 0
        },
        {
          name: "五月",
          value: 0
        },
        {
          name: "六月",
          value: 0
        },
        {
          name: "七月",
          value: 0
        },
        {
          name: "八月",
          value: 0
        },
        {
          name: "九月",
          value: 0
        },
        {
          name: "十月",
          value: 0
        },
        {
          name: "十一月",
          value: 0
        },
        {
          name: "十二月",
          value: 0
        }
      ],
      yiyuan: [
        {
          name: "一月",
          value: 0
        },
        {
          name: "二月",
          value: 0
        },
        {
          name: "三月",
          value: 0
        },
        {
          name: "四月",
          value: 0
        },
        {
          name: "五月",
          value: 0
        },
        {
          name: "六月",
          value: 0
        },
        {
          name: "七月",
          value: 0
        },
        {
          name: "八月",
          value: 0
        },
        {
          name: "九月",
          value: 0
        },
        {
          name: "十月",
          value: 0
        },
        {
          name: "十一月",
          value: 0
        },
        {
          name: "十二月",
          value: 0
        }
      ],
      organData: [
        {
          key: "heart",
          name: "心脏",
          value: 0
        },
        {
          key: "fullLiver",
          name: "肝脏",
          value: 0
        },
        {
          key: "leftRenal",
          name: "左肾",
          value: 0
        },
        {
          key: "rightRenal",
          name: "右肾",
          value: 0
        },
        {
          key: "fullLung",
          name: "全肺",
          value: 0
        },
        {
          key: "leftLung",
          name: "左肺",
          value: 0
        },
        {
          key: "rightLung",
          name: "右肺",
          value: 0
        },
        {
          key: "leftEye",
          name: "左眼膜",
          value: 0
        },
        {
          key: "rightEye",
          name: "右眼膜",
          value: 0
        }
        //  遗体换成全肝了
      ],
      hosGetData: [],
      configHosOrgan: {
        data: [],
        oddRowBGC: "",
        evenRowBGC: "",
        rowNum: 6
      },
      organSumData: [],
      cdata: [
        {
          // 名字需要与 “common/map/zhejiang.js” 地图数据文件里面定义的一一对应,不能是 “福州” 或者 “闽” 之类的缩写
          name: "杭州市",
          district: "1",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          district: "2",
          name: "宁波市",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          district: "3",
          name: "温州市",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "嘉兴市",
          district: "4",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "湖州市",
          district: "5",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "绍兴市",
          district: "6",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "金华市",
          district: "7",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "衢州市",
          district: "8",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "舟山市",
          district: "9",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "台州市",
          district: "A",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        },
        {
          name: "丽水市",
          district: "B",
          value: 0,
          elseData: {
            value2: 0,
            value3: 0
          }
        }
      ],
      hospitalarr: [],
      objZb: {}, //占比
      arrZb: {},
      currentZb: {
        sex: -1,
        age: -1,
        type: -1,
        d: -1,
        x: -1
      },
      loopShowZb: null,
      cdataYear: [],
      organYearData: [],
      configSex: {
        data: [],
        lineWidth: 6,
        digitalFlopStyle: {
          fontSize: 14
        }
      },
      configAge: {
        data: [],
        lineWidth: 6,
        digitalFlopStyle: {
          fontSize: 14
        }
      },
      configDd: {
        data: [],
        lineWidth: 6,
        digitalFlopStyle: {
          fontSize: 14
        }
      },
      configD: {
        data: [],
        lineWidth: 6,
        digitalFlopStyle: {
          fontSize: 14
        }
      },
      configX: {
        data: [],
        lineWidth: 6,
        digitalFlopStyle: {
          fontSize: 14
        }
      },
      cityDonoateCaseArr: []
      defaultAccount: '',
      defaultPassword: '',
      form: {},
      carouselIndex: 0,
      raw: {
        mapData: [],
        gauges: [],
        caseTrend: [],
        organMoon: [],
        caseBloodType: [],
        caseSex: [],
        organType: [],
        organDiscard: [],
        caseTrendArea: [],
        totals: [],
        caseAvgAge: []
      }
    };
  },
  computed: {
    kpiCards() {
      const t = this.raw.totals[0] || {};
      const potential = toNum(t.totalPotential);
      const completed = toNum(t.totalCompletion);
      const age = toNum((this.raw.caseAvgAge[0] || {}).avgAge);
      const getTotal = this.raw.organMoon.reduce(
        (s, i) => s + toNum(i.getCount),
        0
      );
      const useTotal = this.raw.organMoon.reduce(
        (s, i) => s + toNum(i.useCount),
        0
      );
      return [
        {
          label: '总潜在捐献案例',
          value: potential,
          unit: '例',
          icon: 'el-icon-s-flag',
          gradient: 'linear-gradient(135deg,#1d4ed8,#38bdf8)'
        },
        {
          label: '总完成捐献',
          value: completed,
          unit: '例',
          icon: 'el-icon-circle-check',
          gradient: 'linear-gradient(135deg,#059669,#34d399)'
        },
        {
          label: '平均年龄',
          value: age,
          unit: '岁',
          icon: 'el-icon-user',
          decimals: 1,
          gradient: 'linear-gradient(135deg,#7c3aed,#a78bfa)'
        },
        {
          label: '器官获取总数',
          value: getTotal,
          unit: '个',
          icon: 'el-icon-box',
          gradient: 'linear-gradient(135deg,#0e7490,#22d3ee)'
        },
        {
          label: '器官移植总数',
          value: useTotal,
          unit: '个',
          icon: 'el-icon-s-help',
          gradient: 'linear-gradient(135deg,#d97706,#fbbf24)'
        }
      ];
    },
    gaugeCharts() {
      return this.raw.gauges.map(g => ({ name: g.name, options: this.buildGauge(g) }));
    },
    trendOptions() {
      const data = [];
      this.raw.caseTrend.forEach(d => {
        data.push({
          time: this.fmtMonth(d.donateTime),
          type: '潜在捐献',
          value: toNum(d.potentialCount)
        });
        data.push({
          time: this.fmtMonth(d.donateTime),
          type: '完成捐献',
          value: toNum(d.completeCount)
        });
      });
      return {
        data,
        xField: 'time',
        yField: 'value',
        seriesField: 'type',
        smooth: true,
        color: ['#38a5f8', '#34d399'],
        legend: legend(),
        xAxis: xAxis(),
        yAxis: yAxis(),
        tooltip: tooltip(),
        line: { size: 3 },
        areaStyle: { fillOpacity: 0.16 }
      };
    },
    organMoonOptions() {
      const data = [];
      this.raw.organMoon.forEach(d => {
        data.push({
          time: this.fmtMonth(d.donateTime),
          type: '获取',
          value: toNum(d.getCount)
        });
        data.push({
          time: this.fmtMonth(d.donateTime),
          type: '移植',
          value: toNum(d.useCount)
        });
      });
      return {
        data,
        xField: 'time',
        yField: 'value',
        seriesField: 'type',
        smooth: true,
        color: ['#22d3ee', '#fbbf24'],
        lineStyle: { lineWidth: 3 },
        point: { size: 4, shape: 'circle' },
        legend: legend(),
        xAxis: xAxis(),
        yAxis: yAxis(),
        tooltip: tooltip()
      };
    },
    // 男女比例(按年龄段汇总为总体男女)
    sexRatioOptions() {
      let man = 0;
      let woman = 0;
      this.raw.caseSex.forEach(d => {
        man += toNum(d.manCount);
        woman += toNum(d.womanCount);
      });
      const data = [
        { type: '男', value: man },
        { type: '女', value: woman }
      ];
      return {
        data,
        angleField: 'value',
        colorField: 'type',
        radius: 0.85,
        innerRadius: 0.62,
        color: ['#38a5f8', '#fb7185'],
        label: {
          type: 'spider',
          content: '{percentage}',
          style: { fill: '#c3cde4' }
        },
        legend: legend({ position: 'bottom' }),
        tooltip: tooltip({ showTitle: false })
      };
    },
    // 年龄与性别分布
    ageSexOptions() {
      const data = [];
      this.raw.caseSex.forEach(d => {
        const g = AGE_LABELS[d.ageGroup] || d.ageGroup;
        data.push({ age: g, type: '男', value: toNum(d.manCount) });
        data.push({ age: g, type: '女', value: toNum(d.womanCount) });
      });
      return {
        data,
        xField: 'age',
        yField: 'value',
        seriesField: 'type',
        isGroup: true,
        columnWidthRatio: 0.4,
        color: ['#38a5f8', '#fb7185'],
        legend: legend(),
        xAxis: xAxis(),
        yAxis: yAxis(),
        tooltip: tooltip()
      };
    },
    organTypeOptions() {
      const data = [];
      this.raw.organType.forEach(d => {
        data.push({ organ: d.organName, type: '获取', value: toNum(d.getCount) });
        data.push({ organ: d.organName, type: '移植', value: toNum(d.useCount) });
      });
      return {
        data,
        xField: 'value',
        yField: 'organ',
        seriesField: 'type',
        isGroup: true,
        barWidthRatio: 0.6,
        color: ['#22d3ee', '#fbbf24'],
        legend: legend(),
        xAxis: yAxis(),
        yAxis: xAxis(),
        tooltip: tooltip()
      };
    },
    // 器官弃用情况
    discardOptions() {
      const data = this.raw.organDiscard.map(d => ({
        organ: d.organName,
        value: toNum(d.discardCount)
      }));
      return {
        data,
        xField: 'organ',
        yField: 'value',
        columnWidthRatio: 0.5,
        color: '#fb7185',
        legend: false,
        xAxis: xAxis({ label: { autoRotate: true } }),
        yAxis: yAxis(),
        tooltip: tooltip()
      };
    },
    areaOptions() {
      const data = [];
      this.raw.caseTrendArea.forEach(d => {
        const name = String(d.area || '').replace('地区', '');
        data.push({
          area: name,
          type: '潜在捐献',
          value: toNum(d.potentialCount)
        });
        data.push({
          area: name,
          type: '完成捐献',
          value: toNum(d.completeCount)
        });
      });
      return {
        data,
        xField: 'area',
        yField: 'value',
        seriesField: 'type',
        isGroup: true,
        columnWidthRatio: 0.45,
        color: ['#38a5f8', '#34d399'],
        legend: legend(),
        xAxis: xAxis({ label: { autoRotate: true } }),
        yAxis: yAxis(),
        tooltip: tooltip()
      };
    },
    carouselItems() {
      return [
        { title: '男女比例', type: 'ring', options: this.sexRatioOptions },
        { title: '器官类型分布', type: 'bar', options: this.organTypeOptions },
        { title: '器官弃用情况', type: 'column', options: this.discardOptions },
        { title: '年龄与性别分布', type: 'column', options: this.ageSexOptions }
      ];
    },
    currentCarousel() {
      return this.carouselItems[this.carouselIndex] || this.carouselItems[0];
    }
  },
  created() {
    this.height = window.innerHeight - 72;
    this.getCode();
    //this.getinfos();
    //this.getOrgansOfHospitalByMonthss();
    this.startClock();
  },
  mounted() {
    removeToken();
    // let defaultAccount = "cockpit";
    // let defaultPassword = "Admin@123";
  },
  beforeDestroy() {
    if (this.clockTimer) clearInterval(this.clockTimer);
    if (this.carouselTimer) clearInterval(this.carouselTimer);
  },
  methods: {
    getCode() {
      getCodeImg().then(res => {
        this.captchaOnOff =
          res.captchaOnOff === undefined ? true : res.captchaOnOff;
        if (this.captchaOnOff) {
          this.codeUrl = "data:image/gif;base64," + res.img;
          this.uuid = res.uuid;
    fmtMonth(value) {
      const m = toMonth(value);
      if (!m) return '';
      const mm = Number(m.split('-')[1]);
      return mm ? `${mm}月` : m;
    },
    buildGauge(g) {
      const pct = g.max ? Math.min(Math.max(g.value / g.max, 0), 1) : 0;
      const suffix = g.max === 100 ? '%' : '';
      return {
        percent: pct,
        startAngle: Math.PI,
        endAngle: Math.PI * 2,
        radius: 0.85,
        innerRadius: 0.72,
        range: { color: [g.color, '#1c2a4d'], width: 10 },
        axis: {
          label: null,
          tickLine: { style: { stroke: '#2a3a63' } }
        },
        indicator: {
          pointer: { style: { stroke: '#e6edff', lineWidth: 2 } },
          pin: { style: { stroke: '#e6edff', lineWidth: 2, r: 4 } }
        },
        statistic: {
          content: {
            content: `${g.value}${suffix}`,
            style: {
              color: '#ffffff',
              fontSize: 30,
              fontWeight: 700,
              lineHeight: 1,
              opacity: 1
            }
          }
        }
      });
      };
    },
    startClock() {
      const tick = () => {
        this.now = this.$moment().format('YYYY-MM-DD HH:mm:ss');
      };
      tick();
      this.clockTimer = setInterval(tick, 1000);
    },
    startCarousel() {
      if (this.carouselTimer) clearInterval(this.carouselTimer);
      this.carouselTimer = setInterval(() => {
        this.carouselIndex =
          (this.carouselIndex + 1) % this.carouselItems.length;
      }, 5000);
    },
    loginFn() {
      login(this.defaultAccount, this.defaultPassword, this.code, this.uuid)
        .then(async res => {
          if (res.code == 200) {
      if (!this.defaultAccount || !this.defaultPassword) {
        this.$message.warning('请输入账号和密码');
        return;
      }
      this.loginLoading = true;
      login(encrypts(this.defaultAccount), encrypts(this.defaultPassword))
        .then(res => {
          if (res.code === 200) {
            setToken(res.token);
            this.dialogVisible = false;
            this.$message.success("登陆成功");
            const loading = this.$loading({
              lock: true,
              text: "Loading",
              spinner: "el-icon-loading",
              background: "rgba(0, 0, 0, 0.7)"
            });
            setTimeout(() => {
              loading.close();
            }, 2000);
            await this.getDictData();
            this.getinfos();
            this.getData();
            // this.getList();
            this.getAllInfo();
            this.getdonatecount();
            this.getorgancount();
            this.getDonateNumbers();
            this.get();
            this.getcountDonateHostipal();
            //按月度统计的器官数  折线图
            //this.getcurrentmonthorgan();
            // this.getcurrentPeopleBymonth();
            this.getOrgansOfHospitalByMonths();
            //this.getOrgansOfHospitalByMonthss();
            //resolve()
            this.$message.success('登录成功');
            this.loadData();
          } else {
            this.$message.error(res.msg);
            this.$message.error(res.msg || '登录失败');
          }
        })
        .catch(error => {
          // this.$message.error(error);
          console.log(error);
        });
    },
    getOrgansOfHospitalByMonthss() {
      var date = new Date();
      var year = date.getFullYear();
      var month = date.getMonth();
      month = Number(month) + 1;
      if (month < 10) {
        month = "0" + month;
      }
      var data = date.getDate();
      if (data < 10) {
        data = "0" + data;
      }
      var hours = date.getHours();
      var minute = date.getMinutes();
      var second = date.getSeconds();
      var time =
        year +
        "-" +
        month +
        "-" +
        data +
        " " +
        hours +
        ":" +
        minute +
        ":" +
        second;
      let params = {
        starttime: "1998-01-01 00:00:00",
        endtime: time
      };
      getOrgansOfHospitalByMonth(params).then(res => {
        let hospitalarr = res.data;
        // this.hospitalarr = hospitalarr
        let shi = [
          { name: "省本级", value: "0" },
          { name: "杭州市", value: "1" },
          { name: "宁波市", value: "2" },
          { name: "温州市", value: "3" },
          { name: "嘉兴市", value: "4" },
          { name: "湖州市", value: "5" },
          { name: "绍兴市", value: "6" },
          { name: "金华市", value: "7" },
          { name: "衢州市", value: "8" },
          { name: "舟山市", value: "9" },
          { name: "台州市", value: "A" },
          { name: "丽水市", value: "B" }
        ];
        for (let i = 0; i < hospitalarr.length; i++) {
          for (let j = 0; j < shi.length; j++) {
            if (hospitalarr[i].regionLevel == shi[j].value) {
              hospitalarr[i].regionLevel = shi[j].name;
            }
          }
        }
      });
    },
    getOrgansOfHospitalByMonths() {
      let curYear = this.$moment().year();
      let params = {
        starttime: this.$moment().format(curYear + "-01-01 00:00:00"),
        endtime: this.$moment().format("YYYY-MM-DD 00:00:00")
      };
      getOrgansOfHospitalByMonth(params).then(res => {
        let arr = [];
        arr = res.data;
        let shi = [
          { name: "省本级", value: "0" },
          { name: "杭州市", value: "1" },
          { name: "宁波市", value: "2" },
          { name: "温州市", value: "3" },
          { name: "嘉兴市", value: "4" },
          { name: "湖州市", value: "5" },
          { name: "绍兴市", value: "6" },
          { name: "金华市", value: "7" },
          { name: "衢州市", value: "8" },
          { name: "舟山市", value: "9" },
          { name: "台州市", value: "A" },
          { name: "丽水市", value: "B" }
        ];
        let newConfig = {
          ...DEF_TABLE_CONFIG
        };
        let arrr = [];
        for (let i = 0; i < arr.length; i++) {
          for (let j = 0; j < shi.length; j++) {
            if (arr[i].regionLevel == shi[j].value) {
              arr[i].regionLevel = shi[j].name;
            }
          }
          arrr.push({
            regionLevel: arr[i].regionLevel,
            hospitalName: arr[i].hospitalName,
            donateNumber: arr[i].baseInfoCount,
            acceptNumber: arr[i].completionCount
          });
        }
        this.arrrrr = arrr;
        newConfig.data = arrr;
        this.tableConfig = newConfig;
      });
    },
    refresh() {
      if (this.showTable) {
        this.getList();
      } else {
        this.getData();
      }
    },
    //柱状图数据
    getinfos() {},
    //当前年份按月度统计的捐献器官数
    getcurrentmonthorgan() {
      let nowYear = this.$moment().year();
      let params = {
        starttime: this.$moment(nowYear + "-01-01").format(
          "YYYY-01-01 00:00:00"
        ),
        endtime: this.$moment().format("YYYY-MM-DD 00:00:00")
      };
      getdonateNumberByMonth(params).then(res => {
        let donateorgans = res.data;
        let arr1 = [];
        let num = 0;
        for (let i = 0; i < donateorgans.length; i++) {
          num = donateorgans[i].donatemonth.substring(0, 4);
          // if (this.year == num) {
          arr1.push(donateorgans[i]);
          for (let i = 0; i < arr1.length; i++) {
            let month = arr1[i].donatemonth;
            month = month.substring(month.length - 2, month.length);
            let donatecount = arr1[i].donatecount;
            this.organsum[month - 1].value = donatecount;
          }
          // }
        }
      });
    },
    getcountDonateHostipal() {
      let nowYear = this.$moment().year();
      let a = {
        // starttime: "2020-01-01 00:00:00",
        // endtime: "2022-02-01 00:00:00", //????
        starttime: this.$moment(nowYear + "-01-01").format(
          "YYYY-01-01 00:00:00"
        ),
        endtime: this.$moment().format("YYYY-MM-DD 00:00:00")
      };
      countDonateHostipal(a).then(res => {
        let donateorgans = res.data;
        let arr3 = [];
        let num = 0;
        for (let i = 0; i < donateorgans.length; i++) {
          num = donateorgans[i].donatemonth.substring(0, 4);
          arr3.push(donateorgans[i]);
          for (let i = 0; i < arr3.length; i++) {
            let month = arr3[i].donatemonth;
            month = month.substring(month.length - 2, month.length);
            let donatecount = arr3[i].donatecount;
            this.yiyuan[month - 1].value = donatecount;
          }
        }
      });
    },
    get() {},
    //捐献累计信息
    getDonateNumbers() {
      let paramStartTime = null;
      let nowDateYear = this.$moment().year();
      paramStartTime = this.$moment(nowDateYear + "-01-01").format(
        "YYYY-MM-DD HH:mm:ss"
      );
      let a = {
        starttime: paramStartTime,
        endtime: this.$moment().format("YYYY-MM-DD HH:mm:ss")
      };
      getDonateorganDistrictDonateCalculate(a).then(res => {
        let cityCaseArr = [];
        let data = res.data;
        for (let i = 0; i < data.length; i++) {
          let ii = this.cdata.findIndex(
            item => item.district == data[i].district
          );
          if (ii > -1) {
            this.cdata[ii].value = data[i].donateCount;
            this.cdata[ii].elseData.value2 = data[i].completeCount;
            this.cdata[ii].elseData.value3 = data[i].totalOrganCount;
            cityCaseArr.push({
              cityName: this.cdata[ii].name,
              donoateNum: data[i].donateCount
            });
          }
        }
        this.cityDonoateCaseArr = cityCaseArr;
      });
      getDonateNumber(a).then(res => {
        console.log("捐献累计信息", res);
        this.leijishuju.processOrgans = res.data.numberOfDonate;
        this.leijishuju.finishedOrgans = res.data.numberOfCompletion;
        this.leijishuju.Organsnum = res.data.numberOfOrgans;
      });
      getDonateorganPMP(a).then(res => {
        console.log("PMP", res);
        let data = res.data;
        this.leijishuju.PMP = ((data.pmprate * 100) / 64).toFixed(2);
      });
      getDonateorganQuality(a).then(res => {
        let data = res.data;
        this.leijishuju.donateTransferRate = data.donateTransferRate;
        this.leijishuju.organProductionRate = data.organProductionRate;
        this.leijishuju.organUsedRate = data.organUsedRate;
        this.$forceUpdate();
      });
      getDonationwitnessStats(a).then(res => {
        console.log("各种占比", res);
        let data = res.data;
        this.objZb = { ...data };
        this.arrZb = {
          sex: [
            { label: "男", value: data.manRate },
            { label: "女", value: data.womanRate }
          ],
          age: [
            { label: "1-17岁", value: data.a1Rate },
            { label: "18-48岁", value: data.a2Rate },
            { label: "49-69岁", value: data.a2Rate }
          ],
          type: [
            { label: "DBD", value: data.dbdrate },
            { label: "DCD", value: data.dcdrate },
            { label: "DBCD", value: data.dbcdrate }
          ],
          d: [
            { label: "脑血管意外", value: data.d0Rate },
            { label: "脑外伤", value: data.d1Rate },
            { label: "缺血缺氧性脑病", value: data.d2Rate },
            { label: "脑肿瘤", value: data.d3Rate },
            { label: "心血管疾病", value: data.d4Rate }
          ],
          x: [
            { label: "A型", value: data.xarate },
            { label: "B型", value: data.xbrate },
            { label: "AB型", value: data.xabrate },
            { label: "O型", value: data.xorate }
          ]
        };
        window.clearInterval(this.loopShowZb);
        this.loopShowZb = setInterval(() => {
          if (this.currentZb.sex < this.arrZb.sex.length - 1) {
            this.currentZb.sex += 1;
          } else {
            this.currentZb.sex = 0;
          }
          if (this.currentZb.age < this.arrZb.age.length - 1) {
            this.currentZb.age += 1;
          } else {
            this.currentZb.age = 0;
          }
          if (this.currentZb.type < this.arrZb.type.length - 1) {
            this.currentZb.type += 1;
          } else {
            this.currentZb.type = 0;
          }
          if (this.currentZb.d < this.arrZb.d.length - 1) {
            this.currentZb.d += 1;
          } else {
            this.currentZb.d = 0;
          }
          if (this.currentZb.x < this.arrZb.x.length - 1) {
            this.currentZb.x += 1;
          } else {
            this.currentZb.x = 0;
          }
        }, 3000);
      });
      getTransplantHospitalNum(a).then(res => {
        console.log("每家移植医院获取的器官总数", res);
        let data = res.data;
        let list = data.map(item => {
          return [item.orgName, item.organCount];
        });
        list = list.filter(item => !item[0].includes("眼"));
        this.configHosOrgan.data = list;
        this.hosGetData = data.map(item => {
          return {
            name: item.orgName,
            value: item.organCount
          };
        });
      });
      getDonateorganSum(a).then(res => {
        console.log("各种器官的获取总数", res);
        let data = res.data;
        let list = this.organSumData.map(item => item);
        for (let i = 0; i < data.length; i++) {
          let k = data[i].organNo;
          let ii = this.organSumData.findIndex(item => item.key == k);
          if (ii > -1) {
            this.organSumData[ii].value = data[i].count;
          }
        }
      });
      //历年数据
      let startTime = "2019-01-01 00:00:00";
      let endTime = this.$moment().format("YYYY-01-01 00:00:00");
      endTime = this.$moment(endTime)
        .add(1, "years")
        .format("YYYY-01-01 00:00:00");
      let dYear = this.$moment(endTime).diff(this.$moment(startTime), "years");
      if (dYear > 5) {
        startTime ==
          this.$moment(endtime)
            .add(-5, "year")
            .format("YYYY-01-01 00:00:00");
      }
      let arrYear = [];
      for (let i = 0; i < 6; i++) {
        let year = this.$moment(startTime)
          .add(i, "year")
          .format("YYYY");
        if (i >= dYear) {
          year = "";
          continue;
        }
        arrYear.push({
          year: year,
          num: year ? 0 : ""
        });
      }
      let params = {
        starttime: startTime,
        endtime: endTime
      };
      // getdonateNumberByMonth ???//带注释
      getdonatePeopleByMonth(params).then(res => {
        let data = res.data;
        for (let i = 0; i < data.length; i++) {
          let year = this.$moment(data[i].donatemonth).format("YYYY");
          let ii = arrYear.findIndex(item => item.year == year);
          if (ii > -1) {
            arrYear[ii].num += data[i].donatecount;
          }
        }
        this.cdataYear = arrYear;
        console.log("cdataYear:" + JSON.stringify(this.cdataYear));
      });
    },
    async getDictData() {
      try {
        let res = await listData({
          pageNum: 1,
          pageSize: 20,
          dictType: "sys_Organ"
        });
        let list = res.rows.map(item => {
          return {
            key: item.dictValue,
            name: item.dictLabel,
            value: 0
          };
        });
        this.organSumData = list.filter(it => it.key != "C00");
      } catch (e) {}
    },
    async getdonatecount() {
      let nowDateYear = this.$moment().year();
      let nowDateMonth = this.$moment().month() + 1;
      let startTime;
      let endTime = this.$moment()
        .add(1, "month")
        .format("YYYY-MM-01");
      if (nowDateMonth <= 5) {
        startTime = this.$moment()
          .add(-6, "month")
          .format("YYYY-MM-01");
      } else {
        startTime = this.$moment().format(nowDateYear + "-01-01");
      }
      let donateorgans = [];
      let organList = [];
      let params = {
        starttime: startTime,
        endtime: endTime
      };
      try {
        let res = await countDonateorgan(params);
        donateorgans = res.data;
        console.log("donateorgans:" + JSON.stringify(donateorgans));
      } catch (e) {}
      //debugger
      try {
        let res = await getdonateNumberByMonth(params);
        organList = res.data;
        console.log("organList:" + JSON.stringify(organList));
      } catch (e) {}
      //debugger
      console.log(donateorgans);
      let arr = [];
      for (let i = 0; i < 12; i++) {
        //统计捐献案例月度统计数据
        let mm = this.$moment(startTime)
          .add(i, "month")
          .format("YYYY-MM");
        let num = "";
        let num2 = "";
        let ii = donateorgans.findIndex(item => item.donatemonth == mm);
        if (ii > -1) {
          num = donateorgans[ii].donatecount;
        }
        let oi = organList.findIndex(item => item.donatemonth == mm);
        if (oi > -1) {
          num2 = organList[oi].donatecount;
        }
        arr.push({
          name: this.$moment(mm).format("M月"),
          value: num,
          value2: num2
        });
      }
      let organYearArr = [];
      this.anlidata = arr;
      for (let k = 0; k < organList.length; k++) {
        let yearNo = this.$moment(organList[k].donatemonth + "-01").format(
          "YYYY"
        );
        let organNum = organList[k].donatecount;
        //判断当前年份是否在数组中
        let yearIndex = organYearArr.findIndex(item => item.year == yearNo);
        if (yearIndex > -1) {
          organYearArr[yearIndex].num += organNum;
        } else {
          organYearArr.push({ year: yearNo, num: organNum });
        }
      }
      this.organYearData = organYearArr;
    },
    getorgancount() {},
    getData() {},
    getAllInfo() {
      let params = {
        starttime: "2022-01-01 00:00:00",
        endtime: this.$moment().format("YYYY-MM-DD HH:mm:ss")
      };
      getAllOrganInfo(params)
        .then(response => {
          if (response.data) {
            this.allInfo = response.data;
            let list = this.organData.map(item => item);
            for (let i = 0; i < list.length; i++) {
              let k = list[i].key;
              if (this.allInfo[k]) {
                list.value = this.allInfo[k];
                this.organData[i].value = list.value;
              }
            }
            this.organData = list;
            let organsums = 0;
          }
        .catch(() => {
          // 请求失败由 request 拦截器统一提示
        })
        .catch(erroe => {})
        .finally(() => {});
        .finally(() => {
          this.loginLoading = false;
        });
    },
    async getTempList() {
      let total = 0;
      let pageIndex = 1;
      let list = [];
    handleLogout() {
      removeToken();
      this.dialogVisible = true;
      this.$message.info('已退出登录');
    },
    mapClick() {
      // 区县点击可在此扩展下钻
    },
    async loadData() {
      this.loading = true;
      try {
        let searchInfo = {
          pageNum: 1,
          pageSize: 1
        };
        let response = await listDonatebaseinfo(searchInfo);
        this.totalCount = response.total;
      } catch (error) {}
    },
    mapClick(data) {
      let newConfig = {
        ...DEF_TABLE_CONFIG
      };
      let arr = [];
      for (let i = 0; i < this.arrrrr.length; i++) {
        if (data.name == this.arrrrr[i].regionLevel) {
          arr.push(this.arrrrr[i]);
        }
        // 后端接口就绪后,将下面模拟数据替换为真实接口:
        // 趋势/性别/器官/地区/KPI → /opo/totals/*(@/api/businessApi/statistics.js)
        // 区县地图 → getDonateorganDistrictDonateCalculate;
        // 仪表盘 → getDonateorganQuality / getDonateorganPMP;
        // 器官弃用 → 统计模块器官弃用相关接口(@/api/businessApi/statistics.js)
        const m = mockCockpitData();
        this.raw.mapData = m.mapData;
        this.raw.gauges = m.gauges;
        this.raw.caseTrend = m.caseTrend;
        this.raw.organMoon = m.organMoon;
        this.raw.caseBloodType = m.caseBloodType;
        this.raw.caseSex = m.caseSex;
        this.raw.organType = m.organType;
        this.raw.organDiscard = m.organDiscard;
        this.raw.caseTrendArea = m.caseTrendArea;
        this.raw.totals = m.totals;
        this.raw.caseAvgAge = m.caseAvgAge;
        this.startCarousel();
      } catch (e) {
        console.error('驾驶舱数据加载失败', e);
      } finally {
        this.loading = false;
      }
      newConfig.data = arr;
      this.tableConfig = newConfig;
      // let name = data.name;
      // let arr = [];
      // for(let i=0;i<this.arrrrr.length;i++){
      //   if(this.arrrr[i].regionLevel == name){
      //     arr.push({
      //      regionLevel   : this.arrrrr[i].regionLevel,
      //       hospitalName  : this.arrrrr[i].hospitalName,
      //      donateNumber  : this.arrrrr[i].baseInfoCount,
      //      acceptNumber  : this.arrrrr[i].completionCount
      //     })
      //   }
      // }
      //   this.arrrr = arr;
      // this.currentArea = { ...data };
      // this.tableList = [];
      // this.total = 0;
      // this.pageData.pageNum = 1;
      // this.showTable = true;
      // this.getList(data.name);
    },
    getRanNum() {
      return Math.round(Math.random() * 40);
    }
  },
  computed: {
    heightA() {
      let h = (this.height * 0.36 - 54) / 5;
      return h;
    },
    totalValue() {
      let sum = 0;
      for (let i = 0; i < this.cdata.length; i++) {
        sum += this.cdata[i].value;
      }
      return sum;
    },
    totalValue2() {
      let sum = 0;
      for (let i = 0; i < this.cdata.length; i++) {
        sum += this.cdata[i].elseData.value2;
      }
      return sum;
    },
    totalValue3() {
      let sum = 0;
      for (let i = 0; i < this.cdata.length; i++) {
        sum += this.cdata[i].elseData.value3;
      }
      return sum;
    }
  }
};
</script>
<style lang="scss" scoped>
#app {
  overflow: hidden;
.cockpit {
  min-height: 100vh;
  padding: 14px 16px 20px;
  box-sizing: border-box;
  color: #e6edff;
  background: radial-gradient(
      1200px 640px at 18% -10%,
      #12275a 0%,
      rgba(18, 39, 90, 0) 60%
    ),
    radial-gradient(1000px 600px at 110% 10%, #0c2a52 0%, rgba(12, 42, 82, 0) 55%),
    linear-gradient(180deg, #0a1226 0%, #070c1c 60%, #050812 100%);
}
.iwc-dv-box {
  .iwc-box-head {
    text-align: center;
    font-size: 18px;
    padding: 7px 0 25px;
    color: #fff;
    background-image: url("../../assets/images/dv-box-title.png");
    background-size: 100% 150%;
    height: 54px;
  }
  .iwc-box-a {
    font-size: 13px;
    .iwc-box-a-1 {
      color: #5ba2ff;
      margin-bottom: 5px;
    }
  }
  .iwc-before-o {
    display: inline-block;
    width: 11px;
    height: 10px;
    border-radius: 50%;
    border: 0.15rem solid;
    margin-right: 0.5rem;
  }
  .iwc-box-c {
    display: flex;
    padding: 1rem 0;
    .iwc-box-c1 {
      flex: 1;
      font-size: 1rem;
      text-align: center;
      .iwc-box-c1-o {
        display: inline-block;
        width: 3.6rem;
        height: 3.6rem;
        line-height: 3.6rem;
        margin: 0 auto;
        border: 0.2rem solid;
        border-radius: 50%;
      }
      .iwc-box-c1-l {
        padding: 1rem 0;
      }
    }
  }
::v-deep .el-loading-mask {
  background-color: rgba(5, 8, 18, 0.75);
}
.iwc-box-d {
  display: flex;
  padding-top: 2rem;
  .iwc-box-d-1 {
    flex: 1;
    position: relative;
    .iwc-box-d-img {
      width: 3.6rem;
      height: 3.6rem;
      position: absolute;
    }
  }
  .iwc-box-d-f {
    padding-left: 4rem;
    padding-top: 0.5rem;
    .iwc-box-d-f1 {
      font-size: 1.4rem;
      color: #07dbff;
      height: 2rem;
    }
    .iwc-box-d-f2 {
      color: #fff;
      font-size: 0.75rem;
    }
  }
}
.c-home {
  .fc-white {
    color: #fff;
  }
  .fc-sp {
    color: #409eff;
  }
  .box-title {
    width: 100%;
    span {
      display: block;
      width: 130px;
      height: 25px;
      -webkit-transform: skew(20deg);
      -moz-transform: skew(20deg);
      -o-transform: skew(20deg);
      background: #1356a1;
      line-height: 25px;
      align-self: center;
      border: 1px transparent solid;
      border-image: linear-gradient(#070a17, #7be6fc) 10 10;
      border-image: linear-gradient(#070a17, #7be6fc) 10 10;
      border-image: linear-gradient(#070a17, #7be6fc) 10 10;
      margin: 0 auto;
    }
    b {
      display: block;
      color: #fff;
      text-align: center;
      transform: skewY(-20deg);
      transform: skewX(-20deg);
    }
  }
  .box-num {
    position: relative;
    .box-num-main {
      p {
        margin: 0 0 10px;
      }
      text-align: right;
      .box-num-main-n {
        color: #409eff;
        font-size: 25px;
      }
    }
    .box-num-ex {
      position: absolute;
      bottom: 5px;
      right: 10px;
      width: 45px;
      span {
        color: #409eff;
        font-size: 12px;
      }
    }
/* 顶部标题栏 */
.cockpit-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 4px 14px;
  .header-left {
    display: flex;
    align-items: center;
  }
}
::v-deep .c-table-title {
  .el-divider.el-divider--horizontal {
    background-color: #95a1ec;
    .el-divider__text.is-left {
      color: #303133;
      background: #fafafa;
    }
  .header-logo {
    width: 10px;
    height: 26px;
    border-radius: 3px;
    margin-right: 12px;
    background: linear-gradient(180deg, #38a5f8, #22d3ee);
    box-shadow: 0 0 12px rgba(56, 165, 248, 0.7);
  }
  .active {
    .el-divider.el-divider--horizontal {
      .el-divider__text.is-left {
        color: #409eff;
      }
    }
  .header-title {
    margin: 0;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: 2px;
    background: linear-gradient(90deg, #eaf2ff, #6db8ff);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
::v-deep .iwc-ring {
  .dv-active-ring-chart .active-ring-info .active-ring-name {
    position: absolute;
    top: 82px;
  .header-right {
    display: flex;
    align-items: center;
  }
}
::v-deep .iwc-box-b-table.dv-scroll-board {
  .rows {
    .row-item:nth-child(2) {
      border: 1px solid #02406e;
      background-color: rgba(19, 187, 206, 0.13);
      background-blend-mode: multiply;
      //filter: drop-shadow(3px 3px 4px #07dbff);
      box-shadow: 0 0 10px rgb(0, 153, 184) inset;
    }
    .ceil:nth-child(1) {
      flex: 1;
    }
    .ceil:nth-child(2) {
      width: 70px !important;
    }
  }
}
::v-deep .iwc-h-rb-table.dv-scroll-board {
  .header {
    color: #07dbff;
    .header-item:nth-child(1) {
      width: 70px !important;
    }
    .header-item:nth-child(2) {
      flex: 1;
    }
    .header-item:nth-child(3) {
      width: 80px !important;
    }
    .header-item:nth-child(4) {
      width: 80px !important;
    }
  }
  .rows {
    .row-item {
      border-bottom: 1px solid #036492;
    }
    .row-item:nth-child(2) {
      border: 1px solid #07dbff;
      background-color: rgba(19, 187, 206, 0.13);
      background-blend-mode: multiply;
      box-shadow: 0 0 10px rgb(0, 153, 184) inset;
      //filter: drop-shadow(3px 3px 4px #07dbff);
    }
    .ceil:nth-child(1) {
      width: 70px;
    }
    .ceil:nth-child(2) {
      flex: 1;
      padding-left: 0;
      padding-right: 0;
    }
    .ceil:nth-child(3) {
      width: 80px;
      text-align: center;
      padding-left: 0;
      padding-right: 0;
    }
    .ceil:nth-child(4) {
      width: 80px;
      text-align: center;
      padding-left: 0;
      padding-right: 0;
    }
  }
}
::v-deep .el-dialog {
  -webkit-transform: none;
  transform: none;
  background-color: rgb(3, 14, 64);
  box-shadow: rgb(10, 51, 110) 0px 0px 40px inset;
  border: 1px solid rgb(10, 51, 110);
  color: #fff !important;
  left: 0;
  position: relative;
  margin: 0 auto;
  .el-dialog__title {
    color: #fff;
  }
  .el-form-item__label {
    text-align: right;
    vertical-align: middle;
    float: left;
  .header-clock {
    color: #9aa7c7;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    letter-spacing: 1px;
    margin-right: 16px;
  }
  .header-logout {
    color: #9aa7c7;
    &:hover {
      color: #38a5f8;
    }
  }
}
/* KPI 指标卡 */
.kpi-row {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
  margin-bottom: 16px;
}
.kpi-card {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  border-radius: 12px;
  border: 1px solid rgba(90, 120, 190, 0.28);
  background: linear-gradient(
    135deg,
    rgba(40, 52, 96, 0.72),
    rgba(16, 24, 52, 0.9)
  );
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.kpi-icon {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  color: #fff;
  margin-right: 12px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
}
.kpi-body {
  min-width: 0;
}
.kpi-label {
  font-size: 13px;
  color: #8aa0c8;
  margin-bottom: 2px;
}
.kpi-value {
  font-size: 24px;
  font-weight: 700;
  color: #fff;
  line-height: 1.2;
}
.kpi-unit {
  font-size: 13px;
  font-weight: 400;
  color: #8aa0c8;
  margin-left: 4px;
}
/* 仪表盘行 */
.gauge-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 16px;
}
/* 面板 */
.panel {
  height: 100%;
  padding: 14px 16px;
  border-radius: 12px;
  border: 1px solid rgba(80, 110, 180, 0.25);
  background: linear-gradient(
    180deg,
    rgba(25, 35, 70, 0.82),
    rgba(13, 20, 43, 0.82)
  );
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
  box-sizing: border-box;
}
.panel-title {
  position: relative;
  font-size: 15px;
  font-weight: 600;
  color: #dbe4ff;
  margin-bottom: 10px;
  padding-left: 12px;
  &::before {
    content: '';
    position: absolute;
    left: 0;
    top: 2px;
    bottom: 2px;
    width: 4px;
    border-radius: 2px;
    background: linear-gradient(180deg, #38a5f8, #22d3ee);
  }
}
/* 左右两列堆叠 */
.col-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
  .panel {
    flex: 1;
  }
}
/* 轮播 */
.panel--carousel {
  position: relative;
}
.carousel-body {
  height: 205px;
}
.carousel-dots {
  position: absolute;
  right: 16px;
  top: 16px;
  display: flex;
  gap: 6px;
}
.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(120, 140, 190, 0.35);
  cursor: pointer;
  transition: all 0.3s;
  &.active {
    width: 20px;
    border-radius: 4px;
    background: #38a5f8;
  }
}
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.4s;
}
.fade-enter,
.fade-leave-to {
  opacity: 0;
}
</style>
<!-- 登录弹窗通过 append-to-body 挂到 body 下,scoped 样式无法命中,故用全局样式 -->
<style lang="scss">
.el-dialog.login-dialog {
  background: linear-gradient(180deg, rgba(28, 40, 78, 0.97), rgba(13, 20, 43, 0.99));
  border: 1px solid rgba(74, 120, 200, 0.45);
  border-radius: 14px;
  box-shadow: 0 0 0 1px rgba(56, 165, 248, 0.12), 0 0 44px rgba(56, 165, 248, 0.28),
    0 24px 60px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  .el-dialog__header {
    padding: 22px 26px 14px;
    border-bottom: 1px solid rgba(74, 120, 200, 0.22);
  }
  .el-dialog__title {
    color: #eaf2ff;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: 2px;
    &::before {
      content: '';
      display: inline-block;
      width: 4px;
      height: 16px;
      margin-right: 10px;
      border-radius: 2px;
      background: linear-gradient(180deg, #38a5f8, #22d3ee);
      box-shadow: 0 0 8px rgba(56, 165, 248, 0.8);
      vertical-align: -2px;
    }
  }
  .el-dialog__body {
    padding: 26px 26px 8px;
    color: #c3cde4;
  }
  .el-dialog__footer {
    padding: 8px 26px 24px;
    text-align: right;
  }
  .el-form-item__label {
    color: #aab6d4;
    font-weight: 500;
    letter-spacing: 1px;
  }
  .el-input__inner {
    background: rgba(8, 15, 34, 0.9);
    border: 1px solid rgba(90, 124, 200, 0.35);
    border-radius: 6px;
    color: #e6edff;
    transition: border-color 0.25s, box-shadow 0.25s;
    &::placeholder {
      color: rgba(154, 167, 199, 0.6);
    }
    &:hover {
      border-color: rgba(90, 124, 200, 0.55);
    }
    &:focus {
      border-color: #38a5f8;
      box-shadow: 0 0 0 3px rgba(56, 165, 248, 0.18);
    }
  }
  .el-button {
    background: rgba(24, 36, 68, 0.9);
    border: 1px solid rgba(90, 124, 200, 0.4);
    color: #c3cde4;
    &:hover {
      border-color: #38a5f8;
      color: #eaf2ff;
    }
  }
  .el-button--primary {
    background: linear-gradient(135deg, #2563eb, #22d3ee);
    border: none;
    color: #fff;
    line-height: 40px;
    padding: 0 12px 0 0;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    box-shadow: 0 4px 14px rgba(56, 165, 248, 0.4);
    &:hover,
    &:focus {
      background: linear-gradient(135deg, #2f6ff0, #2fd8f2);
      color: #fff;
    }
  }
}
::v-deep .iwc-box-a {
  .el-progress-bar__outer {
    background-color: #29345c;
  }
  .el-progress-bar__innerText {
    margin-right: -27px;
  }
}
.login-code {
  width: 33%;
  height: 38px;
  float: right;
  img {
    cursor: pointer;
    vertical-align: middle;
  }
}
.login-code-img {
  height: 38px;
}
</style>