<template>
  <div class="gl-page-content">

    <div class="page-filter-box">
      <el-form :model="filterFprmData" inline>
        <el-form-item label="用户组：">
          <el-select v-model="filterFprmData.userGroupId" class="mw200" @change="filterWorkLoadFun">
            <el-option v-for="item in groupList" :key="item.id" :label="item.groupName" :value="item.id">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="开始时间：">
          <el-date-picker
            v-model="filterFprmData.beginTime"
            type="datetime"
            placeholder="请选择开始时间"
            format="YYYY-MM-DD HH:mm:ss"
            @change="filterWorkLoadFun"
          />
        </el-form-item>
        <el-form-item label="结束时间：">
          <el-date-picker
            v-model="filterFprmData.endTime"
            type="datetime"
            placeholder="请选择开始时间"
            format="YYYY-MM-DD HH:mm:ss"
            @change="filterWorkLoadFun"
          />
        </el-form-item>
        <el-form-item>
          <el-radio-group v-model="filterFprmData.dateType" @change="changeDateTypeFun">
            <el-radio value="month">月</el-radio>
            <el-radio value="week">周</el-radio>
            <el-radio value="day">日</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item class="mr0">
          <el-button type="primary" @change="filterWorkLoadFun">查询</el-button>
          <el-button type="" @click="clearParamFun">清空</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="page-content">
      <div ref="ganttRef" class="gant-page" v-loading="loading"></div>
    </div>
    <div class="page-footer">
      <template v-for="(item, index) in colorList" :key="index">
        <div class="color-item" v-if="index > 0">
          <div :style="{ background: item }"></div>
          <div>{{ index >= 5 ? '大于或等于5个任务' : index + '个任务' }}</div>
        </div>
      </template>
    </div>

  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, nextTick, onBeforeUnmount } from 'vue';
import { gantt } from 'dhtmlx-gantt';
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css';
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
import isoWeek from 'dayjs/plugin/isoWeek';
import weekOfYear from 'dayjs/plugin/weekOfYear';
import { userQueryGroupApi, userQueryGroupDetailApi } from '@/api/system/user';
import { getListUserWorkloadsApi } from '@/api/project/task';
import { ElMessage } from 'element-plus';
import { isWorkday } from 'chinese-workday';

dayjs.extend(isBetween);
dayjs.extend(weekOfYear);
dayjs.extend(isoWeek);
let Gantt: any = gantt;
const ganttEvents = ref<any>([]);
const colorList: string[] = ['#ffffff', '#fff6e6', '#ffdca3', '#ff9729', '#ff7d00', '#d96200']; // 格子颜色
const taskOriginData = ref<any>([]); // 所有用户的任务数据
const loading = ref<boolean>(false);
const workDaysRange = ref<number>(0);

const filterFprmData = reactive<any>({
  userGroupId: '',
  userIds: [],
  beginTime: '',
  endTime: '',
  dateType: 'week',
});

const ganttRef = ref();

const changeDateTypeFun = () => {
  loading.value = true;
  // 加载动画
  setTimeout(() => {
    setUserDayWork(filterFprmData.beginTime, filterFprmData.endTime);
    Gantt.ext.zoom.setLevel(filterFprmData.dateType);
    loading.value = false;
  }, 200);
};

const groupList = ref<any>([]);
const getUserGroupFun = async () => {
  const res: any = await userQueryGroupApi({
    current: 1,
    size: 999,
  });
  if (res && res.code === 200) {
    groupList.value = res.data.data;
    if (groupList.value?.length) {
      filterFprmData.userGroupId = groupList.value[0].id;
      filterFprmData.userIds = await queryGroupUserListFun(filterFprmData.userGroupId);
    }
  }
};

// 获取用户组内成员
const queryGroupUserListFun = async (id: any) => {
  const res: any = await userQueryGroupDetailApi({
    id,
    current: 1,
    size: 999,
  });

  if (res && res.code === 200) {
    const usrids = res.data.users.data.map((item: any) => {
      return item.userId;
    });

    return usrids;
  } else {
    return [];
  }
};

const getWorkLoadDataFun = async () => {
  if (!filterFprmData.userIds.length) {
    return;
  }

  loading.value = true;
  Gantt.clearAll();
  taskOriginData.value = [];

  const res: any = await getListUserWorkloadsApi({
    ...filterFprmData,
  });

  if (res && res.code === 200) {
    taskOriginData.value = res.data;

    Gantt.config.start_date = filterFprmData.beginTime;
    Gantt.config.end_date = filterFprmData.endTime;
    Gantt.ext.zoom.setLevel(filterFprmData.dateType);
    if (res.data.length > 0) {
      calculateWorkDay([filterFprmData.beginTime, filterFprmData.endTime]);
      formatUserTask(res.data, [filterFprmData.beginTime, filterFprmData.endTime]);
    }

    setUserDayWork(filterFprmData.beginTime, filterFprmData.endTime);
    nextTick(() => {
      Gantt.render();
    });
    loading.value = false;
  }
};

const formatUserTask = (data: any, time: any) => {
  const ganttData = data.map((item: any, index: any) => {
    let jobSaturation = 0;
    if (item.taskList?.length > 0) {
      item.taskList.forEach((item_1: any) => {
        jobSaturation = jobSaturation + workDaysRange.value * item_1.workRate;
      });
    }
    return {
      id: index + 1,
      userName: item.userName,
      userId: item.userId,
      taskNum: item.taskNum ? item.taskNum : 0,
      jobSaturation: jobSaturation.toFixed(2),
      start_date: time[0],
      duration: dayjs(time[1]).diff(dayjs(time[0]), 'day'),
    };
  });
  Gantt.clearAll();
  Gantt.parse({
    data: ganttData,
  });
};

// 获取用户工作负载信息
const filterWorkLoadFun = async () => {

  // 判断开始时间和截止时间
  const begin = new Date(filterFprmData.beginTime).getTime();
  const end = new Date(filterFprmData.endTime).getTime();
  if (end < begin) {
    ElMessage.warning('结束时间无法小于开始时间！');
    filterFprmData.endTime = dayjs(new Date(filterFprmData.beginTime)).add(3, 'months').format('YYYY-MM-DD HH:mm:ss');
  }
  filterFprmData.userIds = await queryGroupUserListFun(filterFprmData.userGroupId);
  await refreshGanttFun();

};

const clearParamFun = async () => {
  await getUserGroupFun();
  filterFprmData.beginTime = dayjs().subtract(3, 'month').format('YYYY-MM-DD HH:mm:ss');
  filterFprmData.endTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
  await filterWorkLoadFun();

};

// 计算时间段中的工作日天数
const calculateWorkDay = ([startDate, endDate]: any) => {

  let workdays = 0;
  let currentDate = dayjs(startDate);
  while (currentDate.isBefore(dayjs(endDate)) || currentDate.isSame(dayjs(endDate), 'day')) {
    if (isWorkday(currentDate)) {
      workdays++;
    }
    currentDate = currentDate.add(1, 'day');
  }
  workDaysRange.value = workdays;
};

// 生成日期列表的函数
const generateDateList = (startDate: any, endDate: any, mode = 'day') => {
  const result = [];
  let formatStart = null;
  let formatEnd = null;
  if (mode === 'day') {
    formatStart = dayjs(startDate);
    formatEnd = dayjs(endDate);
  } else if (mode === 'week') {
    formatStart = dayjs(startDate).startOf('isoWeek');
    formatEnd = dayjs(endDate).startOf('isoWeek');
  } else if (mode === 'month') {
    formatStart = dayjs(startDate).startOf('month');
    formatEnd = dayjs(endDate).startOf('month');
  }
  if (!formatStart || !formatEnd) {
    return [];
  }
  // 根据模式生成不同的日期列表
  while (formatStart.isBefore(endDate) || formatStart.isSame(formatEnd)) {
    result.push(formatStart.format('YYYY-MM-DD')); // 将日期加入结果列表
    if (mode === 'day') {
      formatStart = formatStart.add(1, 'day'); // 每天
    } else if (mode === 'week') {
      formatStart = formatStart.startOf('isoWeek').add(1, 'week'); // 每周第一天（星期一）
    } else if (mode === 'month') {
      formatStart = formatStart.startOf('month').add(1, 'month'); // 每月第一天
    }
  }

  return result;
};

// 每个用户gantt单元格的任务
const userTimeItemWorkList: any = new Map();
const setUserDayWork: any = (startDate: any, endDate: any) => {
  userTimeItemWorkList.clear();
  const dateList = generateDateList(startDate, endDate, filterFprmData.dateType);
  taskOriginData.value.forEach((item: any) => {
    const dateWorkMap: any = new Map();
    dateList.forEach((item_1: any) => {
      const tasks = filterUserTask(item.taskList, item_1);
      dateWorkMap.set(item_1, tasks);
    });
    userTimeItemWorkList.set(item.userName, dateWorkMap);
  });
};

// 筛选某一用户在某一周或者某月的任务
const filterUserTask = (taskList: any, date: any) => {
  let filterTask: any = [];
  filterTask = taskList
    ?.filter((item: any) => {
      const startTime = dayjs(item.beginTime);
      const endTime = startTime.add(item.days - 1, 'day');
      const weekOrMonthStart = dayjs(date);
      const addDays = filterFprmData.dateType === 'day' ? 0 : filterFprmData.dateType === 'week' ? 6 : weekOrMonthStart.daysInMonth() - 1;
      const weekOrMonthEnd = weekOrMonthStart.add(addDays, 'day');
      // 判断当前任务的时间段是否在这周
      // 开始时间在这周||结束时间在这周||这周整个在任务的时间段中
      return (
        startTime.isBetween(weekOrMonthStart, weekOrMonthEnd, 'day', '[]') ||
        endTime.isBetween(weekOrMonthStart, weekOrMonthEnd, 'day', '[]') ||
        (weekOrMonthStart.isBetween(startTime, endTime, 'day', '[]') &&
          weekOrMonthEnd.isBetween(startTime, endTime, 'day', '[]'))
      );
    })
    ?.map((item: any) => item.id);
  return filterTask;
};

const initGantt = () => {
  const zoomConfig: any = {
    levels: [
      {
        name: 'day',
        scales: [
          { unit: 'year', step: 1, format: '%Y' },
          { unit: 'month', step: 1, format: '%M' },
          { unit: 'week', step: 1, format: '%W周' },
          { unit: 'day', format: '%d' },
        ],
      },
      {
        name: 'week',
        min_column_width: 50,
        scales: [
          { unit: 'year', step: 1, format: '%Y' },
          { unit: 'month', step: 1, format: '%M' },
          { unit: 'week', step: 1, format: '%W周' },
        ],
      },
      {
        name: 'month',
        scales: [
          { unit: 'year', step: 1, format: '%Y' },
          { unit: 'month', step: 1, format: '%M' },
        ],
      },
    ],
  };
  Gantt.ext.zoom.init(zoomConfig);
  Gantt.ext.zoom.setLevel('week');
  Gantt.config.autosize = false;
  Gantt.config.show_grid = true;
  // 只读模式：打开后不可以操作甘特图
  Gantt.config.readonly = true;
  // 设置空数据
  Gantt.config.show_empty_state = false;
  Gantt.config.fit_tasks = true;
  Gantt.config.min_column_width = 30;
  Gantt.config.date_format = '%Y-%m-%d';
  Gantt.config.scale_height = 28 * 3;
  Gantt.config.select_task = false;
  Gantt.i18n.setLocale('cn');
  Gantt.config.columns = [
    {
      name: 'userName',
      label: '姓名',
      width: 200,
      align: 'left',
      onrender: (task: any, node: any) => {
        console.log(node);

        return `<img src="" style="width:15px;height:15px;margin-right:12px"></img>${task.userName}`;
      },
    },
    {
      name: 'taskNum', label: '任务数量', align: 'left', width: 80,
      onrender: (task: any, node: any) => {
        console.log(node);

        return `${task.taskNum}`;
      },
    },
  ];
  Gantt.templates.timeline_cell_content = function (task: any, date: any) {

    let tasks: any = [];
    if (task.userName && userTimeItemWorkList && userTimeItemWorkList.has(task.userName)) {
      const currentNameMap = userTimeItemWorkList.get(task.userName);
      const dateFormat = dayjs(date).format('YYYY-MM-DD');
      if (currentNameMap && currentNameMap.has(dateFormat)) {
        tasks = currentNameMap.get(dateFormat);
      }
    }
    return `<div class='${tasks?.length > 0 ? 'cell-style' : ''}' style='background:${colorList[tasks?.length >= 5 ? 5 : tasks?.length]
    };cursor:${tasks?.length > 0 ? 'pointer' : 'default'}' userName=${task?.userName} userId=${task?.userId
    }  tasks=${JSON.stringify(tasks)} date=${dayjs(date).format('YYYY-MM-DD')}></div>`;
  };
  // gantt渲染结束添加监听单元格点击事件
  const onGanttRender = Gantt.attachEvent('onGanttRender', function (e:any, date:any) {

    console.log(e, 'e');
    console.log(date, 'date');

    nextTick(() => {
      monitorCellClickFun();
    });
  });
  ganttEvents.value.push(onGanttRender);
  const onLoadStart = Gantt.attachEvent('onGanttScroll', function (e:any, date:any) {
    console.log(e, 'e');
    console.log(date, 'date');
    nextTick(() => {
      monitorCellClickFun();
    });
  });
  ganttEvents.value.push(onLoadStart);
  Gantt.init(ganttRef.value as HTMLElement);
  Gantt.parse({
    data: [],
  });
};

const monitorCellClickFun = () => {

};

const refreshGanttFun = async () => {
  Gantt.clearAll();
  initGantt();

  await getWorkLoadDataFun();

};

onMounted(async () => {
  await getUserGroupFun();
  filterFprmData.beginTime = dayjs().subtract(3, 'month').format('YYYY-MM-DD HH:mm:ss');
  filterFprmData.endTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
  await refreshGanttFun();
  console.log(filterFprmData, 'filterFprmData');
});

onBeforeUnmount(() => {
  ganttEvents.value?.forEach((item: any) => {
    Gantt.detachEvent(item);
  });
  Gantt.templates.timeline_cell_content = function (task: any, date: any) {
    console.log(task);
    console.log(date);

    return '';
  };
  Gantt.clearAll();
  Gantt = null;
});

</script>

<style lang="scss" scoped>
.gl-page-content {
  width: 100%;
  height: 100%;

  .page-filter-box {
    width: 100%;
    height: 50px;
    display: flex;
    align-items: center;

    .mw200 {
      width: 200px;
    }

    .el-form {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: flex-end;

    }

    .mr0 {
      margin-right: 0px;
    }

  }

  .page-content {
    width: 100%;
    height: calc(100% - 80px);

    .gant-page {
      width: 100%;
      height: 100%;
    }
  }

  .page-footer {
    height: 30px;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: flex-end;

    .color-item {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: flex-end;
      margin-left: 12px;

      &>div:first-child {
        height: 16px;
        width: 16px;
        border-radius: 50%;
        margin-right: 3px;
      }
    }
  }

}

:deep(.cell-style) {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
:deep(.gantt_links_area) {
  display: none;
}

:deep(.gantt_bars_area) {
  display: none;
}

:deep(.gantt_tree_icon.gantt_file) {
  background-image: url('~@/assets/imgs/versionTree/user.svg') !important;
  background-size: 60%;
}
:deep(
    .gantt_grid_data .gantt_row.gantt_selected,
    .gantt_grid_data .gantt_row.odd.gantt_selected,
    .gantt_task_row.gantt_selected
  ) {
  background-color: #96bdff;
  &:hover {
    background-color: #96bdff !important;
  }
}
:deep(.gantt_grid_data .gantt_row.odd:hover, .gantt_grid_data .gantt_row:hover) {
  background-color: #ecf7ff;
}
:deep(.gantt_grid_data .gantt_row:hover) {
  background-color: #ecf7ff;
}
:deep(.task-table-container) {
  height: 100%;
  width: 100%;
}
:deep(.gantt_row.gantt_row_task) {
  position: none;
}
</style>
