Преглед изворни кода

feat: 首页周日报概览

qiny пре 1 година
родитељ
комит
434e7b4625

+ 168 - 0
client/src/views/OaSystem/home/components/daily/index.vue

@@ -0,0 +1,168 @@
+<template>
+  <div class="log-list">
+    <el-calendar ref="calendar" v-model="thisMonth">
+      <template #header="{ date }">
+        <div class="title">
+          <div class="check-btn" @click="checkMonth('prev')">
+            <el-icon><ArrowLeft /></el-icon>
+          </div>
+          <div class="show-month">{{ date }}</div>
+          <div class="check-btn" @click="checkMonth('next')">
+            <el-icon><ArrowRight /></el-icon>
+          </div>
+        </div>
+      </template>
+      <template #date-cell="{ data }">
+        <!-- 仅工作日显示角标 -->
+        <div>
+          <div class="date-type">
+            <div
+              class="icon-box"
+              :style="{ backgroundColor: backgroundColorObj[iconType(data.day)] }"
+            >
+              <el-icon>
+                <Check v-if="iconType(data.day) == '已填'" />
+                <Close v-if="iconType(data.day) == '未填'" />
+                <EditPen v-if="iconType(data.day) == '当天'" />
+                <!-- <More v-if="iconType(data.day) == '未到'" /> -->
+              </el-icon>
+            </div>
+          </div>
+          <div>{{ moment(data.day).format('DD') }}</div>
+        </div>
+      </template>
+    </el-calendar>
+  </div>
+</template>
+<script lang="ts" setup>
+/**
+ * @description 首页周报列表
+ * 先获取到最近三个月的工作日列表详情,对工作日进行周数划分
+ * 再获取近三个月的周报列表,对周报填报情况进行判断
+ */
+import moment from 'moment'
+import { http } from '../weekly/service'
+import PubsubService from '@/utils/PubsubService'
+
+const { push } = useRouter()
+const message = useMessage()
+
+// 本月日期
+const thisMonth = ref<any>(moment())
+
+// 日志填报列表
+const logObj = ref<any>({})
+
+// 获取工作日列表
+onMounted(async () => {
+  const logList = await http.getLogList('daily')
+  logList.map((item: any) => {
+    const date = item.reportStartDate
+    logObj.value[date] = item
+  })
+
+  // 订阅点击更多事件
+  PubsubService.subscribe('homepage-click-weeklyAndDaily-more', () => {
+    // 跳转到日志填报页面
+    push('oaSystem/PersonalCenter/dailyCenter')
+  })
+})
+
+// 仅能查看近三个月的
+const checkMonth = (type: 'prev' | 'next') => {
+  if (
+    type == 'prev' &&
+    moment(thisMonth.value).format('YYYY-MM') == moment().subtract(2, 'month').format('YYYY-MM')
+  ) {
+    message.info('仅能查看近三个月的周报,点击更多以查看全部!')
+    return
+  }
+  if (type == 'next' && moment(thisMonth.value).format('YYYY-MM') == moment().format('YYYY-MM')) {
+    message.info('还未到下个月!')
+    return
+  }
+  if (type == 'prev') {
+    thisMonth.value = moment(thisMonth.value).subtract(1, 'month')
+  } else {
+    thisMonth.value = moment(thisMonth.value).add(1, 'month')
+  }
+}
+
+const iconType = (date) => {
+  const formatDate = moment(date).format('YYYY-MM-DD')
+  let text = ''
+  if (!logObj.value[formatDate]) {
+    text = '未填'
+  }
+  if (moment(formatDate).isAfter(moment())) {
+    text = '未到'
+  }
+  if (formatDate == moment().format('YYYY-MM-DD')) {
+    text = '当天'
+  }
+  if (logObj.value[formatDate]) {
+    text = '已填'
+  }
+  return text
+}
+const backgroundColorObj = {
+  未填: '#F85638',
+  当天: '#1B80EB',
+  已填: '#0ACE9D',
+  未到: ''
+  // 未到: '#BDC7CE'
+}
+</script>
+<style scoped lang="scss">
+.log-list {
+  .title {
+    width: 100%;
+    height: 48px;
+    line-height: 48px;
+    background: #f3f6fa;
+    border-radius: 40px 40px 40px 40px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .show-month {
+    }
+    .check-btn {
+      width: 30px;
+      height: 30px;
+      background-color: #fff;
+      border-radius: 50%;
+      line-height: 30px;
+      text-align: center;
+      font-size: 18px;
+      margin: 0 10px;
+      color: #5b656f;
+    }
+  }
+
+  :deep(.el-calendar-table tr td) {
+    border: 0;
+  }
+  :deep(.el-calendar-day) {
+    padding: 0;
+    text-align: center;
+    height: 40px;
+    .date-type {
+      font-size: 12px;
+      display: flex;
+      justify-content: right;
+    }
+  }
+
+  .icon-box {
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-size: 12px;
+    color: #fff;
+    font-weight: bold;
+  }
+}
+</style>

+ 232 - 0
client/src/views/OaSystem/home/components/weekly/index.vue

@@ -0,0 +1,232 @@
+<template>
+  <div class="log-list">
+    <div class="title">
+      <div class="check-btn" @click="checkMonth('prev')">
+        <el-icon><ArrowLeft /></el-icon>
+      </div>
+      <div class="show-month">{{ moment(thisMonth).format('YYYY年M月') }}</div>
+      <div class="check-btn" @click="checkMonth('next')">
+        <el-icon><ArrowRight /></el-icon>
+      </div>
+    </div>
+    <div class="content">
+      <div
+        v-for="(item, index) in thisMonthLogs"
+        :key="item.week"
+        class="week-item"
+        :style="{ backgroundColor: item.bgColor }"
+        @click="goToWeeklyPage(item)"
+      >
+        <div class="left">
+          <span class="week-title">{{ weekTitleList[index] }}</span>
+          <span class="week-date">{{
+            `${moment(item.startDate).format('M月D日')} ~ ${moment(item.endDate).format('M月D日')}`
+          }}</span>
+        </div>
+        <div class="right">
+          <div class="icon-box" :style="{ backgroundColor: item.color }">
+            <el-icon>
+              <Check v-if="item.icon == 'Check'" />
+              <Close v-if="item.icon == 'Close'" />
+              <EditPen v-if="item.icon == 'EditPen'" />
+              <More v-if="item.icon == 'More'" />
+            </el-icon>
+          </div>
+          <span>{{ item.type }}</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+/**
+ * @description 首页周报列表
+ * 先获取到最近三个月的工作日列表详情,对工作日进行周数划分
+ * 再获取近三个月的周报列表,对周报填报情况进行判断
+ */
+import moment from 'moment'
+import { getMonthRange, setWorkDayListToWeek, mergeWorkDayAndLogs, http } from './service'
+import PubsubService from '@/utils/PubsubService'
+
+const { push } = useRouter()
+
+// 所有的周日报和周划分
+const allWorkDayListAndLogs = ref<any>([])
+// 本月日期
+const thisMonth = ref<any>(moment())
+// 本月的周日报和周划分
+const thisMonthLogs = ref<any>([])
+
+// 获取工作日列表
+onMounted(async () => {
+  const workObj = await workDayList()
+  const logList = await http.getLogList('weekly')
+  allWorkDayListAndLogs.value = mergeWorkDayAndLogs(workObj, logList)
+  initPageList()
+  // 订阅点击更多事件
+  PubsubService.subscribe('homepage-click-weeklyAndDaily-more', () => {
+    // 跳转到周报填报页面
+    push('oaSystem/PersonalCenter/weeklyCenter')
+  })
+})
+
+const message = useMessage()
+// 仅能查看近三个月的
+const checkMonth = (type: 'prev' | 'next') => {
+  if (
+    type == 'prev' &&
+    moment(thisMonth.value).format('YYYY-MM') == moment().subtract(2, 'month').format('YYYY-MM')
+  ) {
+    message.info('仅能查看近三个月的周报,点击更多以查看全部!')
+    return
+  }
+  if (type == 'next' && moment(thisMonth.value).format('YYYY-MM') == moment().format('YYYY-MM')) {
+    message.info('还未到下个月!')
+    return
+  }
+  if (type == 'prev') {
+    thisMonth.value = moment(thisMonth.value).subtract(1, 'month')
+  } else {
+    thisMonth.value = moment(thisMonth.value).add(1, 'month')
+  }
+  initPageList()
+}
+// 获取最近三个月的工作日列表详情
+const workDayList = async () => {
+  const monthRange = getMonthRange()
+  const workDays = await http.getWorkDayList(monthRange[0], monthRange[1])
+  const workDayObj = setWorkDayListToWeek(workDays)
+  return workDayObj
+}
+
+// 合并工作日和周报列表并初始化页面
+const initPageList = () => {
+  const pointer = moment(thisMonth.value).format('YYYY-M')
+  thisMonthLogs.value = allWorkDayListAndLogs.value[pointer].map((item: any) => {
+    // 默认未填
+    item.type = statusObj[1].type
+    item.icon = statusObj[1].icon
+    item.color = statusObj[1].color
+    item.bgColor = statusObj[1].bgColor
+    // 如果本周
+    const startOfWeek = moment().startOf('week')
+    const endOfWeek = moment().endOf('week')
+    if (moment(item.startDate).isBetween(startOfWeek, endOfWeek)) {
+      item.icon = statusObj[2].icon
+      item.color = statusObj[2].color
+      item.bgColor = statusObj[2].bgColor
+      item.type = statusObj[2].type
+    }
+    // 如果已填
+    if (item.isLog.length > 0) {
+      const isLog = item.isLog[0]
+      item.id = isLog.id
+      item.icon = statusObj[0].icon
+      item.color = statusObj[0].color
+      item.bgColor = statusObj[0].bgColor
+      item.type = statusObj[0].type
+    }
+    // 如果未到
+    if (moment(item.startDate).isAfter(moment())) {
+      item.icon = statusObj[3].icon
+      item.color = statusObj[3].color
+      item.bgColor = statusObj[3].bgColor
+      item.type = statusObj[3].type
+    }
+    return item
+  })
+}
+// 颜色列表
+const weekTitleList = ['第一周', '第二周', '第三周', '第四周', '第五周']
+const statusObj = [
+  { type: '已填', icon: 'Check', color: '#0ACE9D', bgColor: '#EAF8F4' },
+  { type: '未填', icon: 'Close', color: '#F85638', bgColor: '#F8EAEA' },
+  { type: '待填', icon: 'EditPen', color: '#1B80EB', bgColor: '#DDEDFD' },
+  { type: '未到', icon: 'More', color: '#BDC7CE', bgColor: '#F2F6FA' }
+]
+// 跳转到周报填写或详情页面
+// const { push } = useRouter()
+const goToWeeklyPage = (item: any) => {
+  if (item.id) {
+    // push(`/logsDetail?id=${item.id}`)
+  } else if (item.type == '未到') {
+    // message.info('还未到这周!')
+  } else {
+    // push(`/weekly?startDate=${item.startDate}&endDate=${item.endDate}`)
+  }
+}
+</script>
+<style scoped lang="scss">
+.log-list {
+  padding: 10px 10px;
+  .title {
+    height: 48px;
+    line-height: 48px;
+    background: #f3f6fa;
+    border-radius: 40px 40px 40px 40px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .show-month {
+    }
+    .check-btn {
+      width: 30px;
+      height: 30px;
+      background-color: #fff;
+      border-radius: 50%;
+      line-height: 30px;
+      text-align: center;
+      font-size: 18px;
+      margin: 0 10px;
+      color: #5b656f;
+    }
+  }
+  .content {
+    margin-top: 20px;
+    height: 280px;
+    overflow-y: scroll;
+
+    .week-item {
+      height: 50px;
+      line-height: 50px;
+      margin-bottom: 15px;
+      border-radius: 4px 4px 4px 4px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 0 10px;
+      .week-title {
+        font-weight: bold;
+        font-size: 16px;
+        color: #2b333c;
+      }
+      .week-date {
+        font-weight: 400;
+        font-size: 15px;
+        color: #2b333c;
+        margin-left: 12px;
+      }
+      .right {
+        display: flex;
+        height: 50px;
+        justify-content: space-between;
+        align-items: center;
+        padding-right: 5px;
+      }
+      .icon-box {
+        width: 20px;
+        height: 20px;
+        border-radius: 50%;
+        line-height: 20px;
+        text-align: center;
+        font-size: 12px;
+        margin: 0 10px;
+        color: #fff;
+      }
+    }
+  }
+  ::-webkit-scrollbar {
+    width: 0 !important;
+  }
+}
+</style>

+ 213 - 0
client/src/views/OaSystem/home/components/weekly/service.ts

@@ -0,0 +1,213 @@
+/**
+ * @description 所有周日报通用的方法
+ */
+import moment from 'moment'
+import request from '@/config/axios'
+import { getUserInfo } from '@/utils/tool'
+
+const userInfo = getUserInfo()
+
+// 所有请求
+const api = {
+  workDayList: '/adm/workday/list', // 获取工作日列表
+  logList: '/adm/report/list' // 获取周报日志列表
+}
+export const http = {
+  // 获取工作日列表 YYYY-MM-DD HH:mm:ss
+  getWorkDayList: async (startDate: string, endDate: string) => {
+    // 用一种不太优雅的方式实现请求效果
+    const params = {
+      dateDay: [startDate, endDate]
+    }
+    const result: any = await request.get({ url: api.workDayList, params })
+    return result ?? []
+  },
+
+  // 获取近三个月周日报日志列表
+  getLogList: async (type: 'weekly' | 'daily') => {
+    const nearThreeMonth = getNearThreeMonth()
+    const requests = [
+      request.get({
+        url: api.logList,
+        params: {
+          reportType: type,
+          reportYear: nearThreeMonth[0].reportYear,
+          reportMonth: nearThreeMonth[0].reportMonth,
+          userId: userInfo.id ?? ''
+        }
+      }),
+      request.get({
+        url: api.logList,
+        params: {
+          reportType: type,
+          reportYear: nearThreeMonth[1].reportYear,
+          reportMonth: nearThreeMonth[1].reportMonth,
+          userId: userInfo.id ?? ''
+        }
+      }),
+      request.get({
+        url: api.logList,
+        params: {
+          reportType: type,
+          reportYear: nearThreeMonth[2].reportYear,
+          reportMonth: nearThreeMonth[2].reportMonth,
+          userId: userInfo.id ?? ''
+        }
+      })
+    ]
+    const result: any = await Promise.all(requests)
+    const allLog = [...(result?.[0] ?? []), ...(result?.[1] ?? []), ...(result?.[2] ?? [])]
+    return allLog
+  }
+}
+
+// 写一个方法,把人员及部门的列表数据转换为树状数据
+export const transformUserListToTree = (arr: any) => {
+  const map: any = {}
+  const roots: any = []
+  // 将数组转换为以id为key的对象
+  arr.forEach((item: any) => {
+    map[item.id] = { ...item, label: item.name, children: [] }
+  })
+  // 将子节点挂载到父节点的children字段下
+  arr.forEach((item: any) => {
+    const node = {
+      id: map[item.id].id,
+      name: map[item.id].name,
+      value: map[item.id].id,
+      children: map[item.id].children ?? []
+    }
+    if (item.pid && map[item.pid]) {
+      map[item.pid].children.push(node)
+    } else if (item.pid) {
+      // console.log(`找不到对应id的父节点,删除数据: ${item.name}`)
+      // delete map[item.id]
+    } else {
+      roots.push(node)
+    }
+  })
+  return roots
+}
+// 提交校验
+export const onSubmitCheck = (formData: any) => {
+  if (formData.reportContent == '') {
+    return {
+      msg: '请填写今日工作',
+      success: false
+    }
+  }
+  if (formData.weeklyWorkloadList.length == 0) {
+    return {
+      msg: '请分配工作量',
+      success: false
+    }
+  }
+  if (formData.receiveUserIds.length == 0) {
+    return {
+      msg: '请选择接收人',
+      success: false
+    }
+  }
+  return {
+    msg: '',
+    success: true
+  }
+}
+// 判断是否是本人的评论,由于只能删除自己发出的评论,所以做一个判断
+export const isMyComment = (data: any) => {
+  return data.commentUserId == userInfo.id
+}
+// 返回从当前日期计算起的三个月
+export const getNearThreeMonth = () => {
+  return [
+    {
+      reportYear: moment().format('YYYY'),
+      reportMonth: moment().format('M')
+    },
+    {
+      reportYear: moment().subtract(1, 'month').format('YYYY'),
+      reportMonth: moment().subtract(1, 'month').format('M')
+    },
+    {
+      reportYear: moment().subtract(2, 'month').format('YYYY'),
+      reportMonth: moment().subtract(2, 'month').format('M')
+    }
+  ]
+}
+// 返回当前月尾那周周日 到 上上个月初那周的周一前一天的日期
+export const getMonthRange = () => {
+  const endTime = moment().endOf('month').endOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss')
+  const startTime = moment()
+    .subtract(2, 'month')
+    .startOf('month')
+    .startOf('week')
+    .format('YYYY-MM-DD HH:mm:ss')
+  return [startTime, endTime]
+}
+// 将工作日数据进行整理,转成按日期划分的对象
+export const setWorkDayListToObj = (data: any) => {
+  const obj: any = {}
+  data.forEach((item: any) => {
+    const date = moment(item.dateDay).format('YYYY-MM-DD')
+    obj[date] = item
+  })
+  return obj
+}
+// 将工作日数据进行整理,按周划分(传回来的周的划分是错的,但是时间紧迫,所以先这样)
+export const setWorkDayListToWeek = (data: any) => {
+  const weekObj: any = {}
+  data.forEach((item: any) => {
+    const { dateDay, dayOfWeek, week, month, year } = item
+    const date = moment(dateDay).format('YYYY-MM-DD')
+    const desc = `这天是${year}-${month}的第${week}周的第${dayOfWeek}天`
+    // week 表示第几周, dayOfWeek 表示本周的第几天
+    const title = `${year}-${month}`
+    if (weekObj[title]) {
+      if (weekObj[title][week]) {
+        weekObj[title][week].push({ ...item, date, desc })
+      } else {
+        weekObj[title][week] = [{ ...item, date, desc }]
+      }
+    } else {
+      weekObj[title] = {
+        [week]: [{ ...item, date, desc }]
+      }
+    }
+  })
+  // console.log("weekObj", weekObj);
+  return weekObj
+}
+// 处理数据,将工作周划分和周日报填报情况进行合并
+export const mergeWorkDayAndLogs = (workObj: any, logList: any) => {
+  const workList: any = []
+  // 把复杂的对象拆为数组
+  for (const key in workObj) {
+    for (const week in workObj[key]) {
+      const data = workObj[key][week]
+      const logs = logList.filter((item: any) => {
+        const { reportStartDate, reportEndDate } = item
+        const checkData = moment(data[data.length - 1].date)
+        return checkData.isBetween(reportStartDate, reportEndDate, null, '[]')
+      })
+      workList.push({
+        month: key,
+        week,
+        data,
+        startDate: data[0].date,
+        endDate: data[data.length - 1].date,
+        isLog: logs
+      })
+    }
+  }
+  // 再把数组重组为以月划分的对象
+  const monthObj: any = {}
+  workList.map((item: any) => {
+    const { month } = item
+    if (monthObj[month]) {
+      monthObj[month].push(item)
+    } else {
+      monthObj[month] = [item]
+    }
+  })
+  return monthObj
+}

+ 17 - 3
client/src/views/OaSystem/home/homeStaff.vue

@@ -38,11 +38,17 @@
       <div class="handle-events"> <HandleEvents /> </div>
     </div>
     <div class="card-item-common card-flex-col">
-      <CardTitle title="知识库" showMore />
+      <CardTitle title="日志情况" showMore @moreClick="moreClick" />
       <!-- <div>
         <el-input style="width: calc(100% - 60px); color: #f7f7f7" placeholder="输入关键字搜索" />
       </div> -->
-      <div style="flex: 1"> <BarList :list="barListData" unit="条" /></div>
+      <div style="flex: 1">
+        <!-- <BarList :list="barListData" unit="条" /> -->
+        <!-- 首页显示周报 -->
+        <!-- <WeeklySummary/> -->
+        <!-- 首页显示日报 -->
+        <dailySummary />
+      </div>
     </div>
   </div>
 </template>
@@ -53,7 +59,10 @@ import CardTitle from './components/CardTitle.vue'
 import CardItemSeven3 from './components/CardItemSeven3.vue'
 import HandleEvents from './components/HandleEvents.vue'
 import ProjectTimeChart from './components/TimeChart.vue'
-import BarList from './components/BarList.vue'
+// import BarList from './components/BarList.vue'
+import WeeklySummary from './components/weekly/index.vue'
+import dailySummary from './components/daily/index.vue'
+import PubsubService from '@/utils/PubsubService'
 
 const router = useRouter()
 const moreHandle = () => {
@@ -62,6 +71,11 @@ const moreHandle = () => {
 const moreAnnounceClick = () => {
   router.push({ path: '/noticeLook' })
 }
+// 点击周日报更多
+const moreClick = () => {
+  // 发布点击更多事件
+  PubsubService.publish('homepage-click-weeklyAndDaily-more', {})
+}
 const barListData = [
   {
     name: '规划类',

+ 1 - 4
client_h5/src/pages/myLogs/Weekly/index.vue

@@ -61,10 +61,7 @@ interface FormData {
 
 // 页面数据
 const thisWeek = ref(
-  `${moment()
-    .startOf("week")
-    .subtract(1, "day")
-    .format("YYYY/MM/DD")} ~ ${moment()
+  `${moment().startOf("week").add(1, "day").format("YYYY/MM/DD")} ~ ${moment()
     .endOf("week")
     .add(1, "day")
     .format("YYYY/MM/DD")}`