Newer
Older
jh-business-system / src / views / workbench / index.vue
dutingting 2 days ago 24 KB 数据管理
<script lang="ts" setup name="Statistics">
import { getCurrentInstance, ref } from 'vue'
import type { Ref } from 'vue'
import { type DateModelType, ElMessage } from 'element-plus'
import dayjs from 'dayjs'
import {
  getDeptExpireTrend,
  getEquipmentAmount,
  getEquipmentStatus,
  getEquipmentType,
  getStandardDeviceType,
  getTestEquipmentAmount,
  getTestEquipmentMeasuredTrend,
  getTestEquipmentNoMeasureAmount,
  getTestEquipmentShouldMeasuredTrend,
} from '@/api/workBench/workBench'
// import groupPng from '@/assets/images/dashboard/group.png'
// import devicePng from '@/assets/images/dashboard/device.png'
// import productPng from '@/assets/images/dashboard/product.png'
// import dataPng from '@/assets/images/dashboard/data.png'
import { getDictByCode } from '@/api/system/dict'
import useUserStore from '@/store/modules/user'
// import { getGroupListPage } from '@/api/basic/group'
// import { getDeviceListPage } from '@/api/basic/device'
const router = useRouter()
const user = useUserStore()// 用户信息

const checkedPng = new URL('@/assets/images/workBench/checked.png', import.meta.url)
const equipmentPng = new URL('@/assets/images/workBench/equipment.png', import.meta.url)
const standardPng = new URL('@/assets/images/workBench/standard.png', import.meta.url)
const notCheckPng = new URL('@/assets/images/workBench/not-check.png', import.meta.url)
const orderPng = new URL('@/assets/images/workBench/order.png', import.meta.url)
// 每个展示块高度
const blockHeight = ref(300)
const deptId = ref('')
// ---------------------------------标准设备种类分析-----------------------------------------------
// 默认查询条件
const standardDeviceTypeListQuery = ref({
  deptId: '',
})
const standardDeviceTypeList: any = ref([])
const standardDeviceTypeColumn: any = [
  { text: '标准设备名称', value: 'name', align: 'center' },
  { text: '数量', value: 'count', align: 'center' },
]
const standardDeviceTypeLoadingTable = ref(false)

// 标准设备种类分析
function fetchStandardDeviceType() {
  standardDeviceTypeLoadingTable.value = true
  const params = {
    ...standardDeviceTypeListQuery.value,
    deptId: deptId.value,
  }
  getStandardDeviceType(params).then((res) => {
    standardDeviceTypeList.value = []
    for (const i in res.data) {
      standardDeviceTypeList.value.push({ name: i, count: res.data[i] })
    }
    standardDeviceTypeList.value.reverse()
    standardDeviceTypeLoadingTable.value = false
  }).catch(() => {
    standardDeviceTypeLoadingTable.value = false
  })
}

// ---------------------------------设备类型分析-----------------------------------------------
const equipmentTypeListQuery = ref({
  deptId: '',
})
const equipmentType: any = ref([])
const equipmentTypeLoading = ref(false)
// 设备类型分析
const fetchEquipmentType = () => {
  equipmentTypeLoading.value = true
  const params = {
    ...equipmentTypeListQuery.value,
    deptId: deptId.value,
  }
  getEquipmentType(params).then((res) => {
    if (res.data) {
      const tempData = [
        {
          name: '标准设备',
          value: 'standardAmount',
          data: '',
        },
        {
          name: '配套设备',
          value: 'equipmentAmount',
          data: '',
        },
        {
          name: '其他设备',
          value: 'otherAmount',
          data: '',
        },
      ]
      tempData.forEach((item) => {
        item.data = res.data[item.value]
      })
      equipmentType.value = tempData.map(item => ({ name: item.name, value: String(item.data) }))
    }
    equipmentTypeLoading.value = false
  })
}
// ---------------------------------设备状态分析-----------------------------------------------
const equipmentStatusListQuery = ref({
  deptId: '',
})
const equipmentStatusX: any = ref([])
const equipmentStatusY: any = ref([])
const equipmentStatusLoading = ref(false)
// 设备类型分析
const fetchequipmentStatus = () => {
  equipmentStatusLoading.value = true
  const params = {
    ...equipmentStatusListQuery.value,
    deptId: deptId.value,
  }
  getEquipmentStatus(params).then((res) => {
    if (res.data) {
      const data = [
        {
          name: '在用',
          value: 'onUseAmount',
          data: '',
        },
        {
          name: '禁用',
          value: 'disableAmount',
          data: '',
        },
        {
          name: '报废',
          value: 'scrapAmount',
          data: '',
        },
        {
          name: '延用',
          value: 'delayAmount',
          data: '',
        },
        {
          name: '封存',
          value: 'sealAmount',
          data: '',
        },
      ]
      data.forEach((item) => {
        item.data = res.data[item.value]
      })
      equipmentStatusX.value = data.map((item: any) => item.name)
      equipmentStatusY.value = [
        {
          name: '数量',
          data: data.map((item: any) => String(item.data)),
        },
      ]
      equipmentStatusLoading.value = false
    }
  }).catch(() => {
    equipmentStatusLoading.value = false
  })
}
// ---------------------------------受检设备未检设备分析-----------------------------------------------
// 默认查询条件
const testEquipmentNoMeasureListQuery = ref({
  deptId: '',
  timeEnd: dayjs().subtract(5, 'year').format('YYYY-MM-DD HH:mm:ss'),
  timeStart: dayjs().format('YYYY-MM-DD HH:mm:ss'),
})
const dateRangeTestEquipmentNoMeasure = ref<[DateModelType, DateModelType]>(['', ''])// 筛选时间段数据
const testEquipmentNoMeasureList: any = ref([])
const testEquipmentNoMeasureColumn: any = [
  { text: '部门', value: 'dept', align: 'center' },
  { text: '数量', value: 'count', align: 'center' },
]
const testEquipmentNoMeasureLoadingTable = ref(false)
// 受检设备未检设备分析
function fetchTestEquipmentNoMeasureAmount() {
  testEquipmentNoMeasureLoadingTable.value = true
  const params = {
    ...testEquipmentNoMeasureListQuery.value,
    deptId: deptId.value,
    timeEnd: dayjs(testEquipmentNoMeasureListQuery.value.timeEnd).endOf('month').format('YYYY-MM-DD HH:mm:ss'),
    timeStart: dayjs(testEquipmentNoMeasureListQuery.value.timeStart).startOf('month').format('YYYY-MM-DD HH:mm:ss'),
  }
  getTestEquipmentNoMeasureAmount(params).then((response: any) => {
    if (response.code === 200) {
      const tempData = []
      for (const i in response.data) {
        tempData.push({
          dept: i,
          count: response.data[i],
        })
      }
      testEquipmentNoMeasureList.value = tempData
    }
    testEquipmentNoMeasureLoadingTable.value = false
  }).catch(() => {
    testEquipmentNoMeasureLoadingTable.value = false
  })
}
// ---------------------------------受检设备已检、应检设备趋势-----------------------------------------------
const measuredLineX = ref([]) // 受检设备已检设备趋势x轴
const measuredLineY: any = ref([]) // 受检设备已检设备趋势Y轴
const measuredLoading = ref(false)
const shouldMeasuredLineX = ref([]) // 受检设备应检设备趋势x轴
const shouldMeasuredLineY: any = ref([]) // 受检设备应检设备趋势Y轴
const shouldMeasuredLoading = ref(false)
const dateRangeMeasured = ref<[DateModelType, DateModelType]>(['', ''])// 筛选时间段数据
const dateRangeShouldMeasured = ref<[DateModelType, DateModelType]>(['', ''])// 筛选时间段数据
const measuredListQuery = ref({
  checkDestination: '',
  contentType: 0,
  customerId: 0,
  deptId: '',
  helpInstruction: '',
  manufacturer: '',
  model: '',
  sampleName: '',
  timeEnd: dayjs().format('YYYY-MM'),
  timeStart: dayjs().subtract(6, 'month').format('YYYY-MM'),
})
const shouldMeasuredListQuery = ref({
  checkDestination: '',
  contentType: 0,
  customerId: 0,
  deptId: '',
  helpInstruction: '',
  manufacturer: '',
  model: '',
  sampleName: '',
  timeEnd: dayjs().format('YYYY-MM'),
  timeStart: dayjs().subtract(6, 'month').format('YYYY-MM'),
})

// 受检设备已检设备趋势
const fetchMeasuredLine = () => {
  measuredLoading.value = true
  const params = {
    ...measuredListQuery.value,
    deptId: deptId.value,
    timeEnd: dayjs(measuredListQuery.value.timeEnd).endOf('month').format('YYYY-MM-DD HH:mm:ss'),
    timeStart: dayjs(measuredListQuery.value.timeStart).startOf('month').format('YYYY-MM-DD HH:mm:ss'),
  }
  getTestEquipmentMeasuredTrend(params).then((res) => {
    const tempData = res.data.map((item: { aAmount: any }) => item.aAmount)
    measuredLineY.value = [{ name: '受检设备已检设备趋势', color: '#17d46b', data: [...tempData] }]
    measuredLineX.value = res.data.map((item: { dimension: any }) => item.dimension)
    measuredLoading.value = false
  })
}
// 受检设备应检设备趋势
const fetchshouldMeasuredLine = () => {
  shouldMeasuredLoading.value = true
  const params = {
    ...shouldMeasuredListQuery.value,
    deptId: deptId.value,
    timeEnd: dayjs(shouldMeasuredListQuery.value.timeEnd).endOf('month').format('YYYY-MM-DD HH:mm:ss'),
    timeStart: dayjs(shouldMeasuredListQuery.value.timeStart).startOf('month').format('YYYY-MM-DD HH:mm:ss'),
  }
  getTestEquipmentShouldMeasuredTrend(params).then((res) => {
    const tempData = res.data.map((item: { aAmount: any }) => item.aAmount)
    shouldMeasuredLineY.value = [{ name: '受检设备未检设备趋势', color: '#9A66E4', data: [...tempData] }]
    shouldMeasuredLineX.value = res.data.map((item: { dimension: any }) => item.dimension)
    shouldMeasuredLoading.value = false
  })
}
// -----------------------------------------------------------------------------------
// 点击标题跳转页面
const handleClickTitle = (title = '') => {
  console.log('点击的title', title)
  switch (title) {
    case '分组管理':
      router.push('/basic/group/list')
      break
    case '低电量设备(低于10%)':
      router.push({
        path: '/basic/device/list',
        query: {
          fromPage: 'dashboard',
          queryType: 'lowBattery',
        },
      })
      break
  }
}

// ------------------------------------数量-------------------------------------------------------------------
const testEquipmentcount = ref({
  expireAmount: '****', //	受检设备年度到期应检总量
  measuredAmount: '****', //	受检设备已检总量
  modelAmount: '****', //	受检设备规格型号总量
  orderAmount: '****', //	任务单总量
  sampleAmount: '****', //	受检设备总量
})
const equipmentcount = ref({
  equipmentAmount: '****', // 在用设备总量
  expireAmount: '****', // 本年度到期设备总量
  shouldTraceAmount: '****', // 应溯源总数量
  standardAmount: '****', // 在用标准设备总量
})
// 获取受检设备分析
const fetchTestEquipmentAmount = () => {
  const params = {
    checkDestination: '',
    contentType: 0,
    customerId: 0,
    deptId: deptId.value,
    helpInstruction: '',
    manufacturer: '',
    model: '',
    sampleName: '',
    timeEnd: '',
    timeStart: '',
  }

  getTestEquipmentAmount(params).then((res) => {
    testEquipmentcount.value.expireAmount = res.data.expireAmount //	受检设备年度到期应检总量
    testEquipmentcount.value.measuredAmount = res.data.measuredAmount //	受检设备已检总量
    testEquipmentcount.value.modelAmount = res.data.modelAmount //	受检设备规格型号总量
    testEquipmentcount.value.orderAmount = res.data.orderAmount //	任务单总量
    testEquipmentcount.value.sampleAmount = res.data.sampleAmount //	受检设备总量
  })
}
// 获取实验室设备分析
const fetchEquipmentAmount = () => {
  const params = {
    checkDestination: '',
    contentType: 0,
    customerId: 0,
    deptId: deptId.value,
    helpInstruction: '',
    manufacturer: '',
    model: '',
    sampleName: '',
    timeEnd: '',
    timeStart: '',
  }
  getEquipmentAmount(params).then((res) => {
    equipmentcount.value.equipmentAmount = res.data.equipmentAmount // 在用设备总量
    equipmentcount.value.expireAmount = res.data.expireAmount // 本年度到期设备总量
    equipmentcount.value.shouldTraceAmount = res.data.shouldTraceAmount // 应溯源总数量
    equipmentcount.value.standardAmount = res.data.standardAmount // 在用标准设备总量
  })
}
// -----------------------------------------------------------------------------------------------------
watch(dateRangeMeasured, (val) => {
  if (val) {
    measuredListQuery.value.timeStart = `${val[0]}`
    measuredListQuery.value.timeEnd = `${val[1]}`
  }
  else {
    measuredListQuery.value.timeStart = dayjs().subtract(6, 'month').format('YYYY-MM')
    measuredListQuery.value.timeEnd = dayjs().format('YYYY-MM')
  }
  fetchMeasuredLine()
})
watch(dateRangeShouldMeasured, (val) => {
  if (val) {
    shouldMeasuredListQuery.value.timeStart = `${val[0]}`
    shouldMeasuredListQuery.value.timeEnd = `${val[1]}`
  }
  else {
    shouldMeasuredListQuery.value.timeStart = dayjs().subtract(6, 'month').format('YYYY-MM')
    shouldMeasuredListQuery.value.timeEnd = dayjs().format('YYYY-MM')
  }
  fetchshouldMeasuredLine()
})
watch(dateRangeTestEquipmentNoMeasure, (val) => {
  if (val) {
    shouldMeasuredListQuery.value.timeStart = `${val[0]}`
    shouldMeasuredListQuery.value.timeEnd = `${val[1]}`
  }
  else {
    shouldMeasuredListQuery.value.timeStart = dayjs().subtract(5, 'year').format('YYYY')
    shouldMeasuredListQuery.value.timeEnd = dayjs().format('YYYY')
  }
  fetchTestEquipmentNoMeasureAmount()
})

function calcBlockSize() {
  // 计算工作台区域高度 - 顶部-面包屑-边距
  const bodyHeight = document.body.clientHeight - 50 - 80
  blockHeight.value = (bodyHeight - 100) / 2 // 左侧菜单使用
}

watch(() => deptId.value, (newValue) => {
  fetchTestEquipmentAmount()
  fetchEquipmentAmount()
  fetchMeasuredLine() // 受检设备已检设备趋势
  fetchshouldMeasuredLine() // 受检设备应检设备趋势
  fetchTestEquipmentNoMeasureAmount() // 受检设备未检定设备数量分析
  fetchEquipmentType() // 设备类型分析
  fetchequipmentStatus() // 设备状态分析
  fetchStandardDeviceType() // 标准设备种类分析
})

window.addEventListener('resize', () => {
  calcBlockSize()
})

onBeforeMount(() => {
  calcBlockSize()
})
onMounted(() => {
  deptId.value = user.deptId
})
</script>

<template>
  <dept-select
    ref="deptSelect"
    v-model="deptId"
    style="position: absolute; right: 10px;top: -40px;z-index: 999;width: 220px;"
    placeholder="实验室"
    :dept-show="true"
  />
  <app-container style="overflow: hidden;padding-top: 10px;">
    <!-- <div class="card"> -->
    <div
      style="display: flex;height: 90px;text-align: center;width: 100%;justify-content: space-between;"
    >
      <div class="item">
        <el-image :src="equipmentPng" class="base-map-image" mode="fill" />
        <div class="item-text">
          <div style="color: #0f67e7;">
            在用设备总量
          </div>
          <div class="num">
            {{ equipmentcount.equipmentAmount }}
          </div>
        </div>
      </div>
      <div class="item">
        <el-image :src="standardPng" class="base-map-image" mode="fill" />
        <div class="item-text">
          <div style="color: #0f67e7;">
            在用标准装置总量
          </div>
          <div class="num">
            {{ equipmentcount.standardAmount }}
            <!-- <span class="unit">台</span> -->
          </div>
        </div>
      </div>
      <div class="item">
        <el-image :src="orderPng" class="base-map-image" mode="fill" />
        <div class="item-text">
          <div style="color: #0f67e7;">
            委托单总量
          </div>
          <div class="num">
            {{ testEquipmentcount.orderAmount }}
            <!-- <span class="unit">%</span> -->
          </div>
        </div>
      </div>
      <div class="item">
        <el-image :src="equipmentPng" class="base-map-image" mode="fill" />
        <div class="item-text">
          <div style="color: #0f67e7;">
            受检设备总量
          </div>
          <div class="num">
            {{ testEquipmentcount.sampleAmount }}
            <!-- <span class="unit">%</span> -->
          </div>
        </div>
      </div>
      <div class="item">
        <el-image :src="notCheckPng" class="base-map-image" mode="fill" />
        <div class="item-text">
          <div style="color: #0f67e7;">
            受检设备年度到期应检总量
          </div>
          <div class="num">
            {{ testEquipmentcount.expireAmount }}
          </div>
        </div>
      </div>
      <div class="item">
        <el-image :src="checkedPng" class="base-map-image" mode="fill" />
        <div class="item-text">
          <div style="color: #0f67e7;">
            受检设备已检总量
          </div>
          <div class="num">
            {{ testEquipmentcount.measuredAmount }}
          </div>
        </div>
      </div>
    </div>
    <!-- </div> -->
    <div class="device-bench">
      <el-row :gutter="10">
        <el-col :span="8">
          <bench-col v-loading="measuredLoading" style="position: relative;" icon="icon-line1" title="受检设备已检设备趋势" :height="blockHeight" @handleClickTitle="handleClickTitle">
            <div style="position: absolute;right: 10px;top: 10px;">
              <el-date-picker
                v-model="dateRangeMeasured"
                class="short-input"
                type="monthrange"
                range-separator="至"
                format="YYYY-MM"
                value-format="YYYY-MM"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                size="small"
                style="width: 220px;float: right;"
              />
            </div>
            <line-chart
              :x-axis-data="measuredLineX"
              :data="measuredLineY"
              :legend="{ show: false }"
            />
          </bench-col>
        </el-col>
        <el-col :span="8">
          <bench-col v-loading="shouldMeasuredLoading" style="position: relative;" icon="icon-line1" title="受检设备应检设备趋势" :height="blockHeight" @handleClickTitle="handleClickTitle">
            <div style="position: absolute;right: 10px;top: 10px;">
              <el-date-picker
                v-model="dateRangeShouldMeasured"
                class="short-input"
                type="monthrange"
                range-separator="至"
                format="YYYY-MM"
                value-format="YYYY-MM"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                size="small"
                style="width: 220px;float: right;"
              />
            </div>
            <line-chart
              :x-axis-data="shouldMeasuredLineX"
              :data="shouldMeasuredLineY"
              :legend="{ show: false }"
            />
          </bench-col>
        </el-col>
        <el-col :span="8">
          <bench-col v-loading="testEquipmentNoMeasureLoadingTable" style="position: relative;" icon="icon-table" title="受检设备未检设备分析" :height="blockHeight" @handleClickTitle="handleClickTitle">
            <div style="position: absolute;right: 10px;top: 10px;">
              <el-date-picker
                v-model="dateRangeTestEquipmentNoMeasure"
                class="short-input"
                type="monthrange"
                range-separator="至"
                format="YYYY-MM"
                value-format="YYYY-MM"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                size="small"
                style="width: 220px;float: right;"
              />
            </div>
            <normal-table
              :data="testEquipmentNoMeasureList" :height="blockHeight - 60" :columns="testEquipmentNoMeasureColumn"
              :pagination="false" :query="testEquipmentNoMeasureListQuery" :list-loading="testEquipmentNoMeasureLoadingTable"
            >
              <template #preColumns>
                <el-table-column label="序号" width="55" align="center">
                  <template #default="scope">
                    {{ scope.$index + 1 }}
                  </template>
                </el-table-column>
              </template>
            </normal-table>
          </bench-col>
        </el-col>
      </el-row>
    </div>
    <div class="device-bench" style="margin-top: 10px;">
      <el-row :gutter="10">
        <el-col :span="8">
          <bench-col v-loading="equipmentTypeLoading" style="position: relative;" icon="icon-pie" title="设备类型分析" :height="blockHeight" @handleClickTitle="handleClickTitle">
            <pie-chart
              v-if="equipmentType.length"
              style="flex: 1;margin-left: 10px;"
              :data="equipmentType"
              :radius="['70%']"
              :label-show="false"
              title="设备类型分析"
              :emphasis="{ show: false }"
            />
            <el-empty v-if="!equipmentType.length" :image-size="100" style="margin: 0 auto;" description="暂无数据" />
          </bench-col>
        </el-col>
        <el-col :span="8">
          <bench-col v-loading="equipmentStatusLoading" style="position: relative;" icon="icon-bar" title="设备状态分析" :height="blockHeight" @handleClickTitle="handleClickTitle">
            <bar-chart-vertical
              v-if="equipmentStatusY.length"
              :x-axis-data="equipmentStatusX"
              :data="equipmentStatusY"
              :legend="{ show: false }"
              :bar-coner="0"
              :gradient="false"
            />
            <el-empty v-if="!equipmentStatusY.length" :image-size="100" style="margin: 0 auto;" description="暂无数据" />
          </bench-col>
        </el-col>
        <el-col :span="8">
          <bench-col v-loading="standardDeviceTypeLoadingTable" style="position: relative;" icon="icon-table" title="标准设备种类分析" :height="blockHeight" @handleClickTitle="handleClickTitle">
            <normal-table
              :data="standardDeviceTypeList" :height="blockHeight - 60" :columns="standardDeviceTypeColumn"
              :pagination="false" :query="standardDeviceTypeListQuery"
            >
              <template #preColumns>
                <el-table-column label="序号" width="55" align="center">
                  <template #default="scope">
                    {{ scope.$index + 1 }}
                  </template>
                </el-table-column>
              </template>
            </normal-table>
          </bench-col>
        </el-col>
      </el-row>
    </div>
  </app-container>
</template>

<style lang="scss" scoped>
.card {
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 0 12px rgb(0 0 0 / 12%);
  padding-top: 8px;
  margin-bottom: 10px;
}

.device-bench {
  width: 100%;
  height: 100%;
  box-sizing: border-box;

  .the-month-total-Data {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    padding: 0 20px;

    .title {
      display: flex;
      justify-content: space-between;
      font-weight: 500;
      margin-bottom: 3px;
    }

    .content {
      width: 100%;

      .item {
        display: flex;
        flex-direction: column;
        flex: 1;
        margin-right: 10px;
        padding: 3px 0;
        justify-content: center;
        align-items: center;
        background-image: linear-gradient(to bottom, #e9f5ff, #3d7eff);
        border-radius: 8px;

        &:last-child {
          margin-right: 0;
        }
      }
    }
  }

  .my-equipment {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    padding: 20px;

    .item {
      height: 40%;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background-image: linear-gradient(to right, #caddff, #3d7eff);
      border-radius: 16px;
    }
  }
}

.item {
  // width: 300px;
  padding-right: 20px;
  padding-left: 20px;
  display: flex;
  justify-content: left;
  align-items: center;
  height: 80px;
  border-radius: 10px;
  border: 2px solid #398bff;

  &:hover {
    background-color: #e7f1fd;
    cursor: pointer;
    color: #398bff;
  }
}
</style>

<style lang="scss">
.bench-table {
  .el-table__header-wrapper {
    border-radius: 8px;
  }
}

.bench-table-header {
  th {
    font-weight: normal;
    font-size: 14px;
  }
}

.bench-table-row {
  border-radius: 8px;
}

.num {
  text-shadow: 0 0 5px #0f67e7;
  color: #0f67e7;
  font-size: 30px;
  padding-top: 2px;
  font-weight: bold;
}

.unit {
  color: #0f67e7;
  font-size: 14px;
  margin-left: 3px;
}

.item-text {
  text-shadow: 0 0 2px #0f67e7;
  flex: 1;
  text-align: center;
  font-size: 18px;
}

.base-map-image {
  width: 50px;
  height: 50px;
  // margin-left: 20px;
  margin-right: 20px;
}
</style>