Explorar el Código

tags页签修改

wuhongbo hace 1 año
padre
commit
52ba8f1d48

+ 20 - 0
client/src/api/oa/attendanceCenter/index.ts

@@ -9,3 +9,23 @@ export const getAttendanceSheetListMine = (params) => {
 export const getWorkdayList = (params) => {
   return request.get({ url: '/adm/workday/list', params })
 }
+
+// 获得行政管理_部门考勤列表
+export const getWorkdaySheetList = (params) => {
+  return request.get({ url: '/adm/attendance-sheet/list', params })
+}
+
+// 获得行政管理_全部考勤列表
+export const getWorkdayGetList = (params) => {
+  return request.get({ url: '/adm/attendance-sheet/get', params })
+}
+
+// 更新行政管理_考勤
+export const updateWorkdayList = (data) => {
+  return request.put({ url: '/adm/attendance-sheet/update', data })
+}
+
+// 导出行政管理_考勤 Excel
+export const exportWorkdayList = (params) => {
+  return request.get({ url: '/adm/attendance-sheet/export-excel', params })
+}

+ 1 - 2
client/src/config/axios/index.ts

@@ -14,8 +14,7 @@ const request = (option: any) => {
     ...config,
     responseType: responseType,
     headers: {
-      'Content-Type': headersType || default_headers,
-      tag: 'dev'
+      'Content-Type': headersType || default_headers
     }
   })
 }

+ 53 - 1
client/src/views/OaSystem/attendanceCenter/attendAuth.ts

@@ -27,7 +27,7 @@ export function isAttendNormal(data: any) {
 }
 
 /**
- * 数组去重
+ * 数组根据date去重
  */
 export function isArrayDelRepeat(arr: any) {
   const newArr: any = arr
@@ -42,6 +42,22 @@ export function isArrayDelRepeat(arr: any) {
   }
   return newArr
 }
+/**
+ * 数组根据nickname去重
+ */
+export function isArrayDelOrNickname(arr: any) {
+  const newArr: any = arr
+  for (let i = 0; i < newArr.length - 1; i++) {
+    for (let j = i + 1; j < newArr.length; j++) {
+      if (newArr[i].nickname == newArr[j].nickname) {
+        newArr.splice(j, 1)
+        //因为数组长度减小1,所以直接 j++ 会漏掉一个元素,所以要 j--
+        j--
+      }
+    }
+  }
+  return newArr
+}
 
 /**
  * 返回日历数组
@@ -60,3 +76,39 @@ export function allArrayCalendar(workArr: any, dateArr: any) {
   })
   return workArr
 }
+
+/**
+ * 返回部门数组
+ */
+export function allDeptsArr(workArr: any, dateArr: any, namesArr: any) {
+  const userList: any = []
+  const monthArr: any = []
+  workArr.forEach((l: any) => {
+    const obj = {
+      dayOfWeek: l.dayOfWeek,
+      date: l.date,
+      isworkday: l.isworkday,
+      holidayRemark: l.holidayRemark
+    }
+    monthArr.push(obj)
+  })
+  namesArr.forEach((item: any) => {
+    const obj = {
+      nickName: item.nickname,
+      deptName: item.deptName,
+      id: item.id,
+      deptId: item.deptId,
+      userId: item.userId,
+      username: item.username,
+      attendArray: { monthArr }
+    }
+    userList.push(obj)
+  })
+  userList.forEach((item) => {
+    dateArr.forEach((l) => {
+      if (item.date == l.date) {
+      }
+    })
+  })
+  console.log(userList)
+}

+ 178 - 18
client/src/views/OaSystem/attendanceCenter/dep.vue

@@ -1,28 +1,188 @@
 <template>
-  <div class="attendanceCenter"> 部门考勤 </div>
+  <div class="attendanceCenterDep">
+    <h1>考勤统计表</h1>
+    <div class="depSearch">
+      <div class="searBox">
+        <span class="span">部门:</span>
+        <el-tree-select
+          v-model="fromParams.deptId"
+          :data="deptList"
+          :props="defaultProps"
+          check-strictly
+          node-key="id"
+          placeholder="请选择部门"
+        />
+      </div>
+      <div class="searBox">
+        <span class="span">月份:</span>
+        <el-date-picker v-model="fromParams.month" type="month" placeholder="请选择月份" />
+      </div>
+      <div class="searBox">
+        <span class="span">人员:</span>
+        <el-input v-model="fromParams.userName" placeholder="请输入人员名称" />
+      </div>
+      <div class="searBtns">
+        <el-button @click="querysClick" type="primary" style="background: #3485ff">
+          <img src="@/assets/imgs/OA/search.png" class="mr-8px" alt="" />
+          查询</el-button
+        >
+        <el-button type="primary">
+          <img src="@/assets/imgs/OA/open.png" class="mr-8px" alt="" />
+          导出</el-button
+        >
+      </div>
+    </div>
+    <div class="depTable">
+      <el-table :data="tableData" style="width: 100%">
+        <el-table-column prop="index" label="序号" width="80" />
+        <el-table-column prop="dep" label="部门" />
+        <el-table-column prop="name" label="姓名" />
+        <!-- <el-table-column label="Delivery Info">
+          <el-table-column prop="name" label="Name" width="120" />
+          <el-table-column label="Address Info">
+            <el-table-column prop="state" label="State" width="120" />
+            <el-table-column prop="city" label="City" width="120" />
+            <el-table-column prop="address" label="Address" />
+            <el-table-column prop="zip" label="Zip" width="120" />
+          </el-table-column>
+        </el-table-column> -->
+
+        <el-table-column prop="1" label="旷工" />
+        <el-table-column prop="1" label="迟到" />
+        <el-table-column prop="1" label="早退" />
+        <el-table-column prop="1" label="出差" />
+        <el-table-column prop="1" label="事假" />
+        <el-table-column prop="1" label="调休" />
+        <el-table-column prop="1" label="病假" />
+        <el-table-column prop="1" label="年假" />
+        <el-table-column prop="1" label="产假" />
+        <el-table-column prop="1" label="其他" />
+      </el-table>
+    </div>
+  </div>
 </template>
 <script setup lang="ts">
-import OaCalendar from '@/views/OaSystem/components/OaCalendar/index.vue'
-import { useAppStore } from '@/store/modules/app'
-import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
 defineOptions({ name: 'AttendanceDep' })
-const { wsCache } = useCache()
-const appStore = useAppStore()
-const user = wsCache.get(CACHE_KEY.USER)
-const userName = user.user.nickname ? user.user.nickname : 'Admin'
-const calendarList = ref([])
+import * as DeptApi from '@/api/system/dept'
+import { defaultProps, handleTree } from '@/utils/tree'
+import * as MineApi from '@/api/oa/attendanceCenter'
+import {
+  isAttendNormal,
+  isArrayDelRepeat,
+  allArrayCalendar,
+  isArrayDelOrNickname,
+  allDeptsArr
+} from './attendAuth'
+import moment from 'moment'
+const fromParams: any = ref({
+  deptId: '',
+  month: '',
+  userName: ''
+})
+const deptList = ref<Tree[]>([]) // 树形结构
+const tableData = ref([
+  {
+    date: '2016-05-03',
+    name: 'Tom',
+    state: 'California',
+    city: 'Los Angeles',
+    address: 'No. 189, Grove St, Los Angeles',
+    zip: 'CA 90036'
+  }
+])
+const initTreeDeps = async () => {
+  deptList.value = handleTree(await DeptApi.getSimpleDeptList())
+}
+const querysClick = async () => {
+  // initInsMouth()
+  let month = fromParams.value.month
+  let toMoseMonths: any = []
+  toMoseMonths[0] = moment(month).startOf('months').format('YYYY-MM-DD') + ' 00:00:00'
+  toMoseMonths[1] = moment(month).endOf('months').format('YYYY-MM-DD') + ' 23:59:59'
+  initInsMouth(toMoseMonths)
+}
+const initInsMouth = async (date: any) => {
+  let params = {
+    attendanceTime: date, //	考勤时间
+    attendanceStatus: '', //	考勤状态,示例值(2)
+    attendanceType: '', //	考勤类型(1:上午;2:下午),示例值(1)
+    otherMinute: '', //	其他考勤状态分钟(除了出勤)
+    nickname: fromParams.value.userName, //用户昵称
+    deptId: fromParams.value.deptId //部门ID
+  }
+  initWorkDay(date).then((restall) => {
+    MineApi.getWorkdaySheetList(params).then((res) => {
+      let namesArr: any = isArrayDelOrNickname(res)
+      let resArr: any = res
+      resArr.forEach((item: any) => {
+        item.date = moment(item.attendanceTime).format('YYYY-MM-DD')
+      })
+      let arr = allDeptsArr(restall, resArr, namesArr)
+      // console.log(arr)
+    })
+  })
+}
+const initWorkDay = async (date: any) => {
+  let params = {
+    dateDay: date, //		日期(数组)
+    dayOfWeek: '', //			星期几
+    holidayRemark: '', //			节假备注,示例值(国庆节)
+    isworkday: '', //		是否工作日
+    year: '', //		年份
+    month: '', //		月份
+    week: '' //		周
+  }
+  const res = await MineApi.getWorkdayList(params)
+  let arr = res
+  arr.forEach((item: any) => {
+    item.date = moment(item.dateDay).format('YYYY-MM-DD')
+  })
 
-const titleOne = ref('浙江万维')
-onMounted(() => {})
+  return await arr
+}
+onMounted(() => {
+  let toMonth = moment().format('YYYY-MM')
+  fromParams.value.month = toMonth
+  // 加载部门树
+  initTreeDeps()
+  let toMoseMonths: any = []
+  toMoseMonths[0] = moment().startOf('months').format('YYYY-MM-DD') + ' 00:00:00'
+  toMoseMonths[1] = moment().endOf('months').format('YYYY-MM-DD') + ' 23:59:59'
+  initInsMouth(toMoseMonths)
+})
 </script>
 <style lang="scss" scoped>
-h1 {
-  font-size: 20px;
-  margin-bottom: 20px;
-}
-.attendanceCenter {
+.attendanceCenterDep {
   width: 100%;
-  height: 100%;
-  padding: 15px 220px;
+  height: calc(100% - 15px);
+  background: #ffffff;
+  border-radius: 10px;
+  margin-top: 15px;
+  padding: 15px 30px;
+  h1 {
+    font-size: 20px;
+    color: #121518;
+    font-weight: 600;
+    margin-bottom: 20px;
+  }
+  .depSearch {
+    width: 100%;
+    display: flex;
+    align-items: center;
+    margin-bottom: 20px;
+    .searBox {
+      display: flex;
+      align-items: center;
+      margin-right: 25px;
+      .span {
+        white-space: nowrap;
+        font-size: 16px;
+      }
+    }
+  }
+  .depTable {
+    width: 100%;
+    height: calc(100% - 100px);
+  }
 }
 </style>

+ 1 - 1
client/src/views/OaSystem/oaLayout/header.vue

@@ -23,7 +23,7 @@ onMounted(() => {})
 .header {
   width: calc(100%);
   height: 60px;
-  margin-bottom: 10px;
+  margin-bottom: 4px;
   // background: #183868;
   display: flex;
   align-items: center;

+ 80 - 21
client/src/views/OaSystem/oaLayout/tagList.vue

@@ -69,19 +69,22 @@
           <li>
             <router-link :to="{ ...item }" exact v-slot="{ navigate }" v-if="index == 0">
               <div class="homeBox" @click="navigate">
-                <Icon :icon="item.meta.icon || ''" />
-                <p>{{ item.meta.title }}</p>
+                <div @click="tagsHomeClick(item, index)" class="tagsFlex">
+                  <Icon :icon="item.meta.icon || ''" />
+                  <p>{{ item.meta.title }}</p>
+                </div>
               </div>
             </router-link>
             <router-link :to="{ ...item }" exact v-slot="{ navigate }" v-else>
               <div class="fhomeBox" @click="navigate">
-                <div>
-                  <p>{{ item.meta.title }}</p>
+                <div class="tagsFlex">
+                  <div class="pBox">
+                    <p>{{ item.meta.title }}</p>
+                  </div>
+                  <div @click.stop.prevent="closeSelectedTag(item)" class="close">
+                    <span>×</span>
+                  </div>
                 </div>
-                <img
-                  @click.stop.prevent="closeSelectedTag(item)"
-                  src="@/assets/imgs/OA/layout/close.png"
-                />
               </div>
             </router-link>
           </li>
@@ -113,6 +116,7 @@ const affixTagArr = ref<RouteLocationNormalizedLoaded[]>([])
 // 所有右键菜单组件的元素
 const itemRefs = useTemplateRefsList<ComponentRef<typeof ContextMenu & ContextMenuExpose>>()
 const visitedViews = computed(() => tagsViewStore.getVisitedViews)
+
 // 初始化tag
 const initTags = () => {
   affixTagArr.value = filterAffixTags(unref(routers))
@@ -166,6 +170,8 @@ const closeRightTags = () => {
 const addTags = () => {
   const { name } = unref(currentRoute)
   if (name) {
+    console.log(name)
+
     selectedTag.value = unref(currentRoute)
     tagsViewStore.addView(unref(currentRoute))
   }
@@ -231,10 +237,10 @@ li {
 }
 ._tagList {
   width: 100%;
-  height: 30px;
+  height: 36px;
   display: flex;
   align-items: center;
-  background: rgba(255, 255, 255, 0.5);
+  background: rgba(255, 255, 255, 1);
   border-radius: 10px;
   .tag-view {
     width: 100%;
@@ -258,33 +264,59 @@ li {
           box-sizing: border-box;
         }
         .homeBox {
-          width: 90px;
-          height: 100%;
+          width: 70px;
+          height: 16px;
           opacity: 1;
           display: flex;
           align-items: center;
           justify-content: center;
+          .tagsFlex {
+            width: 100%;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+          }
           p {
             margin-left: 5px;
             font-size: 16px;
           }
         }
         .fhomeBox {
-          width: 130px;
-          height: 100%;
+          height: 16px;
           display: flex;
           align-items: center;
           justify-content: space-between;
-          padding: 0 10px;
-          div {
+          padding: 0 15px;
+          border-right: 2px solid rgb(209, 197, 197);
+          .tagsFlex {
+            width: 100%;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+          }
+          .pBox {
             display: flex;
             align-items: center;
             justify-content: center;
             p {
-              margin-left: 5px;
               font-size: 16px;
             }
           }
+          .close {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            width: 12px;
+            height: 12px;
+            background-color: #878b91;
+            border-radius: 50%;
+            margin-left: 10px;
+            span {
+              color: #fff;
+            }
+          }
           img {
             cursor: pointer;
             margin-top: 4px;
@@ -297,11 +329,38 @@ li {
 }
 
 ::v-deep .router-link-active {
-  border: 2px solid #2e77e6;
-  padding: 0px !important;
+  // border: 2px solid #2e77e6;
+  p {
+    color: #2e77e6;
+    font-weight: 600;
+  }
+  .el-icon {
+    color: #2e77e6;
+  }
+  .close {
+    background-color: #2e77e6 !important;
+  }
 }
 
-.el-dropdown {
-  height: 100%;
+.el-dropdown:hover {
+  p {
+    color: #2e77e6;
+    font-weight: 600;
+  }
+}
+
+.tag-view {
+  ul {
+    .el-dropdown:nth-child(2) {
+      .fhomeBox {
+        border-left: 2px solid rgb(209, 197, 197);
+      }
+    }
+    .el-dropdown:last-child {
+      .fhomeBox {
+        border-right: 0;
+      }
+    }
+  }
 }
 </style>