riku
5 天以前 f19e5267cc23b1c714dc746239864f33ed715dd9
src/views/fysp/task/components/CompMonitorPlan.vue
@@ -1,44 +1,160 @@
<template>
  <el-calendar
    v-loading="dayTaskLoading"
    v-model="dateValue"
    :range="dateRange"
    @update:model-value="onDateChange"
  >
    <template #header="{ date }">
      <span>{{ title }}</span>
      <el-space>
        <el-tag>总计:{{ taskStatistic.total }}</el-tag>
        <el-tag>完成:{{ taskStatistic.complete }}</el-tag>
        <el-tag>整改:{{ taskStatistic.changed }}</el-tag>
      </el-space>
      <!-- <span>{{ date }}</span> -->
      <div style="width: 100%">
        <el-row justify="space-between">
          <el-space>
            <el-tag type="default"
              >巡查量:{{
                `${taskStatistic.complete}/${taskStatistic.total}`
              }}</el-tag
            >
            <el-tag type="default"
              >综合整改率:{{
                formatPercent(
                  taskStatistic.changedProblemNum /
                    taskStatistic.totalProblemNum
                )
              }}</el-tag
            >
            <!-- <el-tag type="default">整改:{{ taskStatistic.changed }}</el-tag> -->
          </el-space>
          <el-space>
            <el-text>聚焦用户:</el-text>
            <el-select
              v-model="selectedUsers"
              multiple
              clearable
              collapse-tags
              :max-collapse-tags="1"
              style="width: 150px"
            >
              <el-option
                v-for="user in taskStatistic.progressPerUser"
                :key="user.userId"
                :label="user.userName"
                :value="user.userName"
              />
            </el-select>
          </el-space>
        </el-row>
        <el-row class="m-t-4">
          <el-space wrap>
            <el-tag
              type="default"
              v-for="user in taskStatistic.progressPerUser"
              :key="user.userId"
            >
              <!-- {{
                `${user.userName}:巡查量 ${
                  user.completeTaskNum
                },即时整改率 ${formatPercent(
                  user.changedProblemNumOnTime / user.totalProblemNum
                )},平均耗时 ${
                  user.avgInspectionTime ? user.avgInspectionTime : '--'
                }`
              }} -->
                {{
                `${user.userName}:${
                  user.completeTaskNum
                } | ${formatPercent(
                  user.changedProblemNumOnTime / user.totalProblemNum
                )} | ${
                  user.avgInspectionTime ? user.avgInspectionTime : '--'
                }`
              }}
            </el-tag>
          </el-space>
        </el-row>
      </div>
    </template>
    <template #date-cell="{ data }">
      <div :class="calendarDayClz(data.day)">
        <div style="background-color: #f8f4f4">{{ getDay(data.day) }}</div>
        <template v-if="computeDayTask(data.day)">
          <!-- <el-divider></el-divider> -->
          <el-row justify="space-between" class="m-t-16">
          <el-row
            v-if="computeDayTask(data.day).totalTaskNum > 0"
            justify="space-between"
          >
            <el-space direction="vertical">
              <el-text size="small">总计</el-text>
              <el-text>{{ computeDayTask(data.day).totalTaskNum }}</el-text>
              <el-text size="small" tag="b">巡查量</el-text>
              <el-text size="small"
                >{{ computeDayTask(data.day).completeTaskNum }} /
                {{ computeDayTask(data.day).totalTaskNum }}</el-text
              >
            </el-space>
            <el-space direction="vertical">
              <el-text size="small">完成</el-text>
              <el-text>{{ computeDayTask(data.day).completeTaskNum }}</el-text>
              <el-text size="small" tag="b">综合整改率</el-text>
              <el-text size="small">{{
                formatPercent(
                  computeDayTask(data.day).changedProblemNum /
                    computeDayTask(data.day).totalProblemNum
                )
              }}</el-text>
            </el-space>
            <el-space direction="vertical">
              <el-text size="small">整改</el-text>
              <el-text>{{ computeDayTask(data.day).changedTaskNum }}</el-text>
            </el-space>
            <!-- <el-statistic title="总计" :value="computeDayTask(data.day).totalTaskNum" />
            <el-statistic title="完成" :value="computeDayTask(data.day).completeTaskNum" />
            <el-statistic title="整改" :value="computeDayTask(data.day).changedTaskNum" /> -->
          </el-row>
          <!-- <div>任务总计:{{ computeDayTask(data.day).totalTaskNum }}</div>
          <div>任务完成:{{ computeDayTask(data.day).completeTaskNum }}</div>
          <div>任务整改:{{ computeDayTask(data.day).changedTaskNum }}</div> -->
          <div style="border-top: 1px solid #0000002f" class="m-t-4"></div>
          <div
            v-for="item in computeDayTask(data.day).progressPerUser"
            :key="item.userId"
            class="m-t-4"
          >
            <el-row justify="space-between">
              <el-text
                title="巡查人员"
                size="small"
                :type="
                  selectedUsers.includes(item.userName) ? 'primary' : 'info'
                "
                :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'"
                >{{ item.userName }}</el-text
              >
            </el-row>
            <el-row justify="space-between">
              <!-- <el-space> -->
              <el-text
                title="巡查量"
                size="small"
                style="text-align: center; flex: 1"
                :type="
                  selectedUsers.includes(item.userName) ? 'primary' : 'info'
                "
                :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'"
                >{{ item.completeTaskNum }}</el-text
              >
              <el-text
                title="即时整改率"
                size="small"
                style="text-align: center; flex: 1"
                :type="
                  selectedUsers.includes(item.userName) ? 'primary' : 'info'
                "
                :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'"
                >{{
                  formatPercent(
                    item.changedProblemNumOnTime / item.totalProblemNum
                  )
                }}</el-text
              >
              <el-text
                title="平均耗时"
                size="small"
                style="text-align: center; flex: 1"
                :type="
                  selectedUsers.includes(item.userName) ? 'primary' : 'info'
                "
                :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'"
                >{{
                  timeUtil.formatSecondsToChinese(item.avgInspectionTime)
                }}</el-text
              >
              <!-- </el-space> -->
            </el-row>
          </div>
        </template>
      </div>
    </template>
@@ -48,25 +164,23 @@
import { ref, computed, onMounted, watch } from 'vue';
import taskApi from '@/api/fysp/taskApi';
import dayjs from 'dayjs';
import timeUtil from '@/utils/time-util';
const props = defineProps({
  task: {
    type: Object,
    default: () => {}
  },
  dayTaskList: {
    type: Array,
    default: () => []
  }
});
const emit = defineEmits(['dateChange']);
// 选中日期
const dateValue = ref(new Date());
// 日历标题
const title = computed(() => {
  if (props.task) {
    // return `${props.task.name}计划`;
    return `巡查计划`;
  } else {
    return '';
  }
});
const selectedUsers = ref([]);
// const dateValue = ref(new Date());
const dateValue = ref();
// 日历范围
const startDay = computed(() => dayjs(props.task.starttime));
const endDay = computed(() => dayjs(props.task.endtime));
@@ -74,7 +188,6 @@
  startDay.value.toDate(),
  endDay.value.toDate()
]);
// const dateRange = computed(() => [new Date(2024, 4, 27), new Date(2024, 5, 30)]);
// 日期是否在任务范围内
function isDayEnable(day) {
@@ -98,18 +211,32 @@
/********************** 任务数据 *********************************/
// 获取日任务统计信息
const dayTaskLoading = ref(false);
const dayTaskList = ref([]);
function fetchDayTasks(topTaskId) {
  dayTaskLoading.value = true;
  taskApi
    .fetchDayTasks(topTaskId)
    .then((res) => {
      dayTaskList.value = res;
    })
    .finally(() => (dayTaskLoading.value = false));
}
watch(
  () => props.dayTaskList,
  (nV, oV) => {
    if (nV && dateValue.value) {
      onDateChange(dateValue.value);
    }
  },
  { immediate: false }
);
// // 获取日任务统计信息
// const dayTaskLoading = ref(false);
// const dayTaskList = ref([]);
// function fetchDayTasks() {
//   dayTaskLoading.value = true;
//   return taskApi
//     .fetchDayTasks(props.task.tguid)
//     .then((res) => {
//       dayTaskList.value = res;
//       // 如果已选日期存在,在重新获取日任务统计信息后,再次触发点击事件
//       if (dateValue.value) {
//         onDateChange(dateValue.value);
//       }
//     })
//     .finally(() => (dayTaskLoading.value = false));
// }
// 日任务数据展示
const compMap = new Map();
@@ -119,7 +246,7 @@
    return compMap.get(key).value;
  }
  const result = computed(() => {
    return dayTaskList.value.find((v) => {
    return props.dayTaskList.find((v) => {
      return dayjs(v.date).isSame(dayjs(day));
    });
  });
@@ -131,31 +258,72 @@
  if (isDayEnable(e)) {
    const day = dayjs(e).format('YYYY-MM-DD');
    const t = computeDayTask(day);
    emit('dateChange', t);
    emit('dateChange', t, day);
  }
}
// 总任务统计
const taskStatistic = computed(() => {
  const res = { total: 0, complete: 0, changed: 0 };
  dayTaskList.value.forEach((e) => {
  // const resMap = new Map()
  const res = {
    total: 0,
    complete: 0,
    changed: 0,
    changedProblemNum: 0,
    totalProblemNum: 0
  };
  const userMap = new Map();
  props.dayTaskList.forEach((e) => {
    res.total += e.totalTaskNum;
    res.complete += e.completeTaskNum;
    res.changed += e.changedTaskNum;
    res.changedProblemNum += e.changedProblemNum;
    res.totalProblemNum += e.totalProblemNum;
    e.progressPerUser.forEach((user) => {
      if (!userMap.has(user.userId)) {
        userMap.set(user.userId, {
          userName: user.userName,
          completeTaskNum: 0,
          changedProblemNumOnTime: 0,
          totalProblemNum: 0,
          totalInspectionTime: 0,
          dayTaskNum: 0
        });
      }
      const userItem = userMap.get(user.userId);
      userItem.completeTaskNum += user.completeTaskNum;
      userItem.changedProblemNumOnTime += user.changedProblemNumOnTime;
      userItem.totalProblemNum += user.totalProblemNum;
      userItem.totalInspectionTime += user.avgInspectionTime;
      userItem.dayTaskNum++;
    });
  });
  res.progressPerUser = Array.from(userMap.values()).map((user) => ({
    ...user,
    completeTaskNum: Math.round(user.completeTaskNum * 100) / 100,
    avgInspectionTime: timeUtil.formatSecondsToChinese(
      user.totalInspectionTime / user.dayTaskNum
    )
  }));
  return res;
});
const formatPercent = (num) => {
  return isNaN(num) ? '0%' : parseInt(num * 100) + '%';
};
/********************** 初始化 *********************************/
watch(
  () => props.task,
  (nV) => {
    if (nV.tguid) {
      fetchDayTasks(nV.tguid);
    }
  },
  { immediate: true }
);
// watch(
//   () => props.task,
//   (nV) => {
//     if (nV && nV.tguid) {
//       fetchDayTasks();
//     }
//   },
//   { immediate: true }
// );
// defineExpose({ fetchDayTasks });
</script>
<style scoped>
.li-01 {
@@ -173,16 +341,16 @@
  top: 5px;
}
::v-deep .el-calendar-table .el-calendar-day {
:deep(.el-calendar-table .el-calendar-day) {
  height: initial;
  padding: initial;
}
::v-deep .el-calendar-table .el-calendar-day:hover {
:deep(.el-calendar-table .el-calendar-day:hover) {
  background-color: transparent;
}
/* ::v-deep .el-calendar-table td.is-selected {
/* :deep(.el-calendar-table td.is-selected) {
  background-color: initial;
} */
@@ -209,15 +377,15 @@
  cursor: not-allowed;
}
/* ::v-deep .el-calendar-table tr td:first-child {
/* :deep(.el-calendar-table tr td:first-child) {
  border-left: none !important;
} */
/* ::v-deep .el-calendar-table tr:first-child td {
/* :deep(.el-calendar-table tr:first-child td) {
  border-top: none;
} */
/* ::v-deep .el-calendar-table td {
/* :deep(.el-calendar-table td) {
  border-bottom: none;
  border-right: none;
  vertical-align: top;
@@ -225,7 +393,7 @@
  transition: background-color 0.2s ease;
} */
::v-deep .el-calendar-table thead th {
:deep(.el-calendar-table thead th) {
  padding: 12px 0;
  color: #606266;
  font-weight: normal;