zhaozp 3 年之前
父節點
當前提交
0da45ecd1d

+ 1 - 2
config/index.js

@@ -12,7 +12,7 @@ module.exports = {
     assetsPublicPath: '/',
     proxyTable: {
       '/api': {  //  连接一
-        target: 'http://114.215.254.174:8050/',
+        target: 'https://www.gzjlzhwy.com:4433/',
         // target: 'http://10.0.141.96:80/',
         // target: 'http://172.18.0.15:8080/',
         changeOrigin: true,
@@ -21,7 +21,6 @@ module.exports = {
         }
       },
     },
-
     // Various Dev Server settings
     host: '127.0.0.1', // can be overwritten by process.env.HOST
     port: 80, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined

+ 14 - 1
src/App.vue

@@ -5,8 +5,21 @@
 </template>
 
 <script>
+import { setStore } from '@/utils/store'
 export default {
-  name: 'App'
+  name: 'App',
+  created() {
+          // 1 考勤页  2 人员管理页
+      let type = this.$route.query.type || 1
+      if(type) {
+        setStore({'name':'type', 'content': type, 'type':''})
+      }
+      // token 
+      let token = this.$route.query.token
+      if(token) {
+        setStore({'name':'token', 'content': token, 'type':''})
+      }
+    }
 }
 </script>
 

+ 19 - 8
src/api/index.js

@@ -11,26 +11,37 @@
 // )
 
 // export default result
-import request from '@/utils/request'
+import { request } from '@/utils/request'
+
+// 获取用户信息
+export const userInfoHead = () => { return request({ url: "/attendance/api/manage/userInfoHead",method: "post" }) }
 
 // 获取当前按钮状态
-export const getButtonState = () => { return request({ url: "/attendance/api/manage/getButtonState" }) }
+export const getButtonState = () => { return request({ url: "/attendance/api/manage/getButtonState",method: "post" }) }
 
 // 获取当天打卡信息
-export const getTodaySignRecord = () => { return request({ url: "/attendance/api/manage/getTodaySignRecord" }) }
+export const getTodaySignRecord = () => { return request({ url: "/attendance/api/manage/getTodaySignRecord",method: "post" }) }
 
 // 打卡
-export const signRecord = () => { return request({ url: "/attendance/api/manage/signRecord" }) }
+export const signRecord = () => { return request({ url: "/attendance/api/manage/signRecord",method: "post" }) }
 
 // 统计顶部数量
-export const statisticsTop = (data) => { return request({ url: "/attendance/api/manage/statisticsTop/"+data }) }
+export const statisticsTop = (data) => { return request({ url: "/attendance/api/manage/statisticsTop/"+data,method: "post" }) }
 
 // 统计
-export const statistics = (data) => { return request({ url: "/attendance/api/manage/statistics/"+data}) }
+export const statistics = (data) => { return request({ url: "/attendance/api/manage/statistics/"+data,method: "post"}) }
 
 // 获取用户当天上下班时间
-export const getUserUpDownWorkTime = () => { return request({ url: "/attendance/api/manage/getUserUpDownWorkTime" }) }
+export const getUserUpDownWorkTime = () => { return request({ url: "/attendance/api/manage/getUserUpDownWorkTime",method: "post" }) }
 
 // 上传用户定位信息
-export const uploadUserPosition = () => { return request({ url: "/attendance/api/manage/uploadUserPosition" }) }
+export const uploadUserPosition = () => { return request({ url: "/attendance/api/manage/uploadUserPosition",method: "post" }) }
+
+// 人员管理列表
+export const userManageList = (data) => { return request({ url: "/attendance/api/manage/userManageList/"+data, method: "post" }) }
+
+// 部门人员签到列表
+export const userSignList = (data) => { return request({ url: "/attendance/api/manage/userSignList",method: "post",data: data }) }
 
+// 获取项目
+export const getProjectList = () => { return request({ url: "/attendance/api/manage/getProjectList", method: "post"}) }

二進制
src/assets/line.png


二進制
src/assets/user.png


+ 2 - 2
src/components/headInfo.vue

@@ -4,8 +4,8 @@
       <van-image round width="4rem" height="4rem" :src="head" />
     </div>
     <div class="head-style-last">
-      <div class="head-style-last-one">您好,张三</div>
-      <div class="head-style-last-two">区域-项目-部门</div>
+      <div class="head-style-last-one">您好,{{ this.$store.state.userInfo.userName }}</div>
+      <div class="head-style-last-two">{{ this.$store.state.userInfo.areaName }}-{{ this.$store.state.userInfo.projectName }}-{{ this.$store.state.userInfo.deptName }}</div>
     </div>
     <div class="head-style-time" v-if="nowYearMonth">
       <van-icon name="arrow-left" tag="i" @click="lastMonth" />

+ 62 - 13
src/components/navBar.vue

@@ -1,27 +1,76 @@
 <template>
-   <van-nav-bar
-      :title="ifPunch ? '考勤打卡' : '统计'"
-      left-text="返回"
-      left-arrow
-      @click-left="onClickLeft"
-    />
+  <van-nav-bar
+    :title="ifPunch ? '考勤打卡' : '统计'"
+    :left-text="leftText"
+    :left-arrow="leftArrow"
+    @click-left="onClickLeft"
+  >
+    <template #title v-if="type === 2">
+      <template v-if="!ifProject">
+        <div style="display: flex; align-items: center">
+          <van-icon
+            style="margin-right: 20px"
+            name="cross"
+            @click="jumpModule"
+          />
+          <div @click="$router.push('/chooseProject')">
+            {{ $store.state.pName }}
+          </div>
+          <van-icon name="arrow-down" />
+        </div>
+      </template>
+      <template v-else>
+        <span>选择项目</span>
+      </template>
+    </template>
+  </van-nav-bar>
 </template>
 
 <script>
+import { getStore } from "@/utils/store";
 export default {
   props: {
-    // 是否为打卡页
     ifPunch: {
       type: Boolean,
-      default: false
+      default: false,
+    },
+    // 是否为选择项目页
+    ifProject: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      type: getStore({ name: "type", type: "", debug: "" }),
+      leftArrow: true,
+      leftText: "返回",
+    };
+  },
+  created() {
+    if (this.type === 2) {
+      if (!this.$store.state.pName) {
+        this.leftArrow = false;
+        this.leftText = "";
+      }
     }
   },
   methods: {
-    onClickLeft () {
-      console.log('跳出')
-    }
-  }
-}
+    onClickLeft() {
+      // 人员管理
+      if (this.type === 2) {
+        if (this.ifPunch) {
+          return this.$router.back();
+        }
+      }
+      this.jumpModule();
+    },
+    // 跳出当前模块
+    jumpModule() {
+      console.log("跳出");
+    },
+  },
+};
 </script>
 
 <style lang="scss" scoped>

+ 87 - 0
src/components/peopleManage/card.vue

@@ -0,0 +1,87 @@
+<template>
+  <div>
+    <div class="userCard" v-for="(item,index) in userList" :key="index">
+      <div class="userCard-one">
+        <div>
+          <span class="userCard-one-userName">{{ item.userName }}</span>
+          <span class="userCard-one-position">{{ item.deptName }}</span>
+        </div>
+        <div
+          class="userCard-one-button"
+          :style="{ background: item.signState === '已签到' ? '#67a2ff' : '#999999' }"
+        >
+          {{ item.signState || '未签到' }}
+        </div>
+      </div>
+      <div class="userCard-two">
+        <span class="userCard-two-place"
+          >上班 <span style="color: #67a2ff">{{ item.upworkTime || '暂无' }}</span></span
+        >
+        <span>下班 <span style="color: #67a2ff">{{ item.downworkTime || '暂无' }}</span></span>
+      </div>
+      <div class="userCard-three">
+        <div class="userCard-three-chunk">工作轨迹</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    userList: Array,
+    default() {
+      return []
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+$borderRadius: 3px;
+$grey: #f2f2f2;
+$blue: #67a2ff;
+.userCard {
+  border-bottom: 10px solid $grey;
+  border-left: 10px solid $grey;
+  border-right: 10px solid $grey;
+  border-radius: $borderRadius;
+  padding: 10px;
+  .userCard-one {
+    display: flex;
+    margin-bottom: 10px;
+    .userCard-one-userName {
+      font-size: 18px;
+      margin-right: 10px;
+    }
+    .userCard-one-position {
+      color: #999999;
+    }
+    .userCard-one-button {
+      margin-left: auto;
+      width: 50px;
+      height: 20px;
+      text-align: center;
+      color: #fff;
+    }
+  }
+  .userCard-two {
+    margin-bottom: 20px;
+    .userCard-two-place {
+      margin-right: 20px;
+    }
+  }
+  .userCard-three {
+    display: flex;
+    justify-content: flex-end;
+    .userCard-three-chunk {
+      border: 1px solid $blue;
+      width: 70px;
+      height: 25px;
+      text-align: center;
+      line-height: 25px;
+      color: $blue;
+    }
+  }
+}
+</style>

+ 85 - 0
src/components/peopleManage/index.vue

@@ -0,0 +1,85 @@
+<template>
+  <div>
+    <div class="chunk" v-for="(item,index) in listData" :key="index" @click="jumpInfo(item.projectId,item.deptId)">
+      <div class="chunk-img"><van-image :src="index === 0 ? user : line" /></div>
+      <div class="chunk-content">
+        <div class="chunk-content-main">{{ item.deptName }}</div>
+        <div class="chunk-content-body">
+          <div class="chunk-content-body-text">{{ index === 0 ? '总' : '共' }}:{{ item.deptUserTotal }} 签到:{{ item.deptUserSignIn }} 休假:0</div>
+          <div class="chunk-content-body-icon">
+            <van-icon name="arrow" color="#aaa" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import user from "@/assets/user.png";
+import line from "@/assets/line.png";
+export default {
+  props: {
+    listData: {
+      type: Array
+    }
+  },
+  data() {
+    return {
+      user,
+      line,
+    };
+  },
+  methods: {
+    jumpInfo(projectId,deptId) {
+      this.$router.push({path:'/departmentStatistics', query: { projectId: projectId, deptId: deptId }})
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+$pray: #bbbbbb;
+$fontSizeOne: 20px;
+$fontSizeTwo: 14px;
+.chunk {
+  display: flex;
+  height: 8vh;
+  .chunk-img {
+    width: 20%;
+  }
+  .chunk-content {
+    width: 80%;
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid $pray;
+    padding: 2vh 2vw 2vh 0;
+    .chunk-content-main {
+      font-size: $fontSizeOne;
+    }
+    .chunk-content-body {
+      font-size: $fontSizeTwo;
+      color: $pray;
+      margin-left: auto;
+      display: flex;
+      align-self: flex-end;
+      .chunk-content-body-text {
+        display: flex;
+        align-self: flex-end;
+      }
+      .chunk-content-body-icon {
+        display: flex;
+        align-items: center;
+      }
+    }
+  }
+}
+/deep/ .chunk-img .van-image {
+  width: 100%;
+  height: 100%;
+}
+/deep/ .chunk-img .van-image__img {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 17 - 13
src/permission.js

@@ -1,7 +1,7 @@
-// import {setStore, getStore, removeStore} from '@/utils/store'
+import { getStore } from '@/utils/store'
 import router from './router'
 // import {getToken} from '@/utils/auth'
-import store from '@/store'
+import store from './store'
 
 router.beforeEach((to, from, next) => {
   // debugger
@@ -9,17 +9,21 @@ router.beforeEach((to, from, next) => {
   // 设置顶部标题
   // store.state.common.heightTitle = to.name
   // Token 校验验证
-  next()
-  return false
-  // if (getToken()) {
-  //   next()
-  // } else {
-  //   if (meta.isAuth === false) {
-  //     next()
-  //   } else {
-  //     next('/')
-  //   }
-  // }
+  // console.log(getStore({'name':'type','type':'','debug':''}) === 2);
+  // 是否为人员管理模块
+
+    // 是否已经选择项目
+    if(!store.state.pName){
+      if (to.name === '人员管理') {
+        next({
+          path: '/chooseProject'
+        })
+      } else {
+        next()
+      }
+    } else {
+      next()
+    }
 })
 
 router.afterEach(() => {

+ 38 - 5
src/router/index.js

@@ -1,13 +1,20 @@
 import Vue from 'vue'
 import Router from 'vue-router'
-
+import { getStore } from '@/utils/store'
 Vue.use(Router)
 
 export default new Router({
   routes: [{
     path: '/',
     name: 'Index',
-    redirect: '/punch',
+    redirect: function () {
+      let type = getStore({'name':'type','type':'','debug':''})
+      if(type == 1){
+        return '/punch'
+      } else {
+        return '/peopleManage'
+      }
+    },
     component: () => import('@/views/Index'),
     meta: {
       keepAlive: true,
@@ -32,7 +39,33 @@ export default new Router({
         isTab: false,
         isAuth: true
       }
+    }, {
+      path: '/peopleManage',
+      name: '人员管理',
+      component: () => import('@/views/base/peopleManage'),
+      meta: {
+        keepAlive: false,
+        isTab: false,
+        isAuth: true
+      }
+    }, {
+      path: '/departmentStatistics',
+      name: '部门签到统计',
+      component: () => import('@/views/base/departmentStatistics'),
+      meta: {
+        keepAlive: false,
+        isTab: false,
+        isAuth: true
+      }
+    }, {
+      path: '/chooseProject',
+      name: '选择项目',
+      component: () => import('@/views/base/chooseProject'),
+      meta: {
+        keepAlive: false,
+        isTab: false,
+        isAuth: true
+      }
     }]
-  }
-  ]
-})
+  }]
+})

+ 15 - 1
src/store/index.js

@@ -1,5 +1,6 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
+import { getStore } from "@/utils/store";
 // import * as getters from './getters'
 
 // // 公共数据
@@ -18,7 +19,13 @@ export default new Vuex.Store({
   state: {
     LOADING: false,
     // loading背景
-    loadBg: false
+    loadBg: false,
+    // 用户信息
+    userInfo: {},
+    // 项目名
+    pName: getStore({'name':'projectName','type':'','debug':''}) || '',
+    // 项目id
+    pid: getStore({'name':'projectId','type':'','debug':''}) || '',
   },
   mutations: {
     showLoading(state,bol) {
@@ -27,6 +34,13 @@ export default new Vuex.Store({
     },
     hideLoading(state) {
       state.LOADING = false
+    },
+    changeProgect(state, pyload) {
+      state.pid = pyload.id
+      state.pName = pyload.name
+    },
+    setUserInfo(state, pyload) {
+      state.userInfo = pyload
     }
   }
 })

+ 29 - 0
src/utils/debounce.js

@@ -0,0 +1,29 @@
+let timeout = null;
+
+/**
+ * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
+ * 
+ * @param {Function} func 要执行的回调函数 
+ * @param {Number} wait 延时的时间
+ * @param {Boolean} immediate 是否立即执行 
+ * @return null
+ */
+function debounce(func, wait = 500, immediate = false) {
+	// 清除定时器
+	if (timeout !== null) clearTimeout(timeout);
+	// 立即执行,此类情况一般用不到
+	if (immediate) {
+		var callNow = !timeout;
+		timeout = setTimeout(function() {
+			timeout = null;
+		}, wait);
+		if (callNow) typeof func === 'function' && func();
+	} else {
+		// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
+		timeout = setTimeout(function() {
+			typeof func === 'function' && func();
+		}, wait);
+	}
+}
+
+export default debounce

+ 15 - 22
src/utils/request.js

@@ -1,5 +1,5 @@
 import axios from 'axios'
-import {getToken} from '@/utils/auth'
+import { getToken } from '@/utils/auth'
 import { Notify } from 'vant'
 import Router from '../router'
 
@@ -8,12 +8,11 @@ import Router from '../router'
  * baseURL = 请求路径
  * timeout = 请求超时配置
  */
-const request = axios.create({
-  baseURL: 'http://172.18.0.15:30000/',
+ export const request = axios.create({
+  baseURL: 'https://www.gzjlzhwy.com:4433/',
   // baseURL: 'http://172.18.0.15:30000/',
   // baseURL: process.env.BASE_API,
   timeout: process.env.TIME_OUT,
-  method: "post",
   type: "JSON"
 })
 // let toast = null
@@ -25,31 +24,27 @@ request.interceptors.request.use(config => {
   //  显示加载
   // Spin.show()
   //  获取accessToken
-  config.headers.Authorization = '886579c851138c69415eca426e529e6f'
-  // let accessToken = getToken()
+  // config.headers.Authorization = '886579c851138c69415eca426e529e6f'
+  // 云服务 token
+  let accessToken = getToken()
   // //  添加请求头信息,处理安全性问题
-  // if (accessToken != undefined) {
-  //   config.headers.Authorization = 'Bearer ' + accessToken
-  // } else {
-  //   config.headers.Authorization = 'Basic dnVlOnZ1ZQ=='
-  // }
+  if (accessToken) {
+    // config.headers.Authorization = 'Bearer ' + accessToken
+    config.headers.Authorization = accessToken
+  } else {
+    // config.headers.Authorization = 'Basic dnVlOnZ1ZQ=='
+    config.headers.Authorization = '374b833554225792a221a64529f8d791'
+  }
   //  添加时间戳防止IE不刷新页面
   if (config.type != 'FORM') {
     if (config.method == 'post') {
-      // console.log(config.params);
-      
-      // if(Object.keys(config.params).length) {
-      //   config.params = {
-      //     ...config.params
-      //   }
-      // }
       config.data = {
         ...config.data
       }
     } else if (config.method == 'get') {
       config.params = {
         ...config.params,
-        _t: Date.parse(new Date()) / 1000
+        // _t: Date.parse(new Date()) / 1000
       }
     }
   } else {
@@ -142,6 +137,4 @@ request.interceptors.response.use(
     // 弹出层
     return Promise.reject(error)
   }
-)
-
-export default request
+)

+ 29 - 0
src/utils/util.js

@@ -65,3 +65,32 @@ export const exitFullScreen = () => {
     document.mozCancelFullScreen()
   }
 }
+/**
+   * 对象数组去重
+   * @param  {Array}  list 原数组
+   * @param  {String} keyWord  指定的key
+   */
+ export const noRepeat = (arr, name) => {
+  let hash = {};
+  return arr.reduce(function (item, next) {
+    hash[next[name]] ? '' : hash[next[name]] = true && item.push(next);
+    return item;
+  }, []);
+}
+
+/**
+   * 使用test方法实现模糊查询
+   * @param  {Array}  list     原数组
+   * @param  {String} keyWord  查询的关键词
+   * @return {Array}           查询的结果
+ */
+ export const fuzzyQuery = (list, keyWord) => {
+  var reg =  new RegExp(keyWord);
+  var arr = [];
+  for (var i = 0; i < list.length; i++) {
+    if (reg.test(list[i].projectName)) {
+      arr.push(list[i]);
+    }
+  }
+  return arr;
+}

+ 3 - 11
src/views/Index.vue

@@ -8,7 +8,7 @@
       <router-view v-if="$route.meta.keepAlive" />
     </keep-alive>
     <router-view v-if="!$route.meta.keepAlive" />
-    <van-tabbar v-model="active">
+    <van-tabbar v-model="active"  v-if="type === 1">
       <van-tabbar-item to="/punch" icon="location-o">打卡</van-tabbar-item>
       <van-tabbar-item to="/statistics" icon="records">统计</van-tabbar-item>
     </van-tabbar>
@@ -17,9 +17,8 @@
 
 <script>
 import { mapState } from "vuex";
-import { setStore } from "@/utils/store";
+import { getStore } from "@/utils/store";
 import Loading from "@/components/loading";
-import { Notify } from "vant"
 export default {
   name: "Index",
   components: {
@@ -28,19 +27,12 @@ export default {
   data() {
     return {
       active: 0,
+      type: getStore({'name':'type','type':'','debug':''})
     };
   },
   computed: {
     ...mapState(["LOADING"]),
   },
-  created() {
-    // let token = this.$route.query.token;
-    // if (token) {
-    //   setStore({ name: "token", content: token, type: "" });
-    // } else {
-    //   Notify({ type: 'warning', message: '无token' })
-    // }
-  },
   watch: {},
   mounted() {
     this.initial();

+ 138 - 0
src/views/base/chooseProject.vue

@@ -0,0 +1,138 @@
+<template>
+  <div>
+    <nav-bar ifPunch ifProject />
+    <div class="place-project-style">
+      <van-sidebar class="place-style" v-model="activeKey">
+        <van-sidebar-item
+          v-for="(item, index) in araeList"
+          :key="index"
+          :title="item.areaName"
+          @click="changeArea(item.areaId)"
+        />
+      </van-sidebar>
+      <div class="project-style">
+        <van-search
+          style="height: 60px"
+          v-model="value"
+          show-action
+          action-text="清除"
+          placeholder=""
+          background="#eee"
+          @input="filterProject"
+          @clear="clearSearch"
+          @cancel="clearSearch"
+        />
+        <div class="project-item-list-style">
+          <div
+            class="project-item-style"
+            v-for="(iten, indey) in projectList"
+            :key="indey"
+            @click="chooseProject(iten.projectId, iten.projectName)"
+          >
+            {{ iten.projectName }}
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import navBar from "@/components/navBar";
+import { setStore } from "@/utils/store";
+import { getProjectList } from "@/api";
+import { noRepeat,fuzzyQuery } from "@/utils/util";
+import debounce from "@/utils/debounce";
+export default {
+  components: {
+    navBar,
+  },
+  data() {
+    return {
+      activeKey: 0,
+      value: "",
+      data: [],
+      araeList: [],
+      projectList: [],
+      projectMainList: [],
+      areaId: "",
+    };
+  },
+  created() {
+    getProjectList().then(res => {
+      let result = res.items;
+      this.data = result;
+      // 过滤获取区域id
+      this.araeList = noRepeat(result, "areaId");
+      // 获取第一个区域id
+      let areaId = result[0].areaId;
+      this.areaId = areaId;
+      // 获取第一个区域id的中项目
+      this.projectList = result.filter((item) => item.areaId == areaId);
+      this.projectMainList = this.projectList;
+    });
+  },
+  methods: {
+    // 切换区域
+    changeArea(id) {
+      this.areaId = id;
+      this.projectList = this.data.filter((item) => item.areaId == id);
+      this.projectMainList = this.projectList;
+    },
+    // 选择项目
+    chooseProject(id, name) {
+      this.$store.commit("changeProgect", { id: id, name: name });
+      setStore({ name: "projectName", content: name, type: "" });
+      setStore({ name: "projectId", content: id, type: "" });
+      this.$router.push("/peopleManage");
+    },
+    // 查询
+    filterProject() {
+      debounce(
+        () => (this.projectList = fuzzyQuery(this.projectMainList, this.value))
+      );
+    },
+    // 清除查询
+    clearSearch() {
+      this.projectList = this.data.filter((item) => item.areaId == this.areaId);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.place-project-style {
+  display: flex;
+  width: 100%;
+  .place-style {
+    width: 25%;
+    height: calc(100vh - 46px);
+    overflow-y: auto;
+  }
+  .project-style {
+    width: 75%;
+    .project-item-list-style {
+      height: calc(100vh - 46px - 60px);
+      overflow-y: auto;
+    }
+    .project-item-style {
+      height: 5vh;
+      padding: 10px 0 10px 20px;
+      line-height: 5vh;
+      border-bottom: 1px solid #eee;
+      font-size: 15px;
+    }
+  }
+}
+/deep/ .van-sidebar-item {
+  background: #e4e4e4;
+  font-size: 15px;
+  color: #7b7778;
+}
+/deep/ .van-sidebar-item--select {
+  background: #dbd7d8;
+}
+/deep/ .van-sidebar-item--select::before {
+  background: transparent;
+}
+</style>

+ 127 - 0
src/views/base/departmentStatistics.vue

@@ -0,0 +1,127 @@
+<template>
+  <div>
+    <nav-bar ifPunch />
+    <van-search
+      v-model="userName"
+      show-action
+      placeholder="搜索人员姓名"
+      background="#F2F2F2"
+    >
+      <template #action>
+        <div @click="getUserSignList(true)">查找</div>
+      </template>
+    </van-search>
+    <div ref="tTop" style="overflow-y: auto" :style="THeight">
+      <van-list
+        v-model="loading"
+        :finished="finished"
+        @load="onLoad"
+      >
+        <card :userList="userList" />
+      </van-list>
+    </div>
+  </div>
+</template>
+
+<script>
+import navBar from "@/components/navBar";
+import card from "@/components/peopleManage/card";
+import { userSignList } from "@/api";
+import { Notify } from "vant";
+export default {
+  name: "departmentStatistics",
+  components: {
+    navBar,
+    card,
+  },
+  data() {
+    return {
+      tHeight: "",
+      loading: false,
+      finished: false,
+      userList: [],
+      pageNum: 1,
+      projectId: "",
+      deptId: "",
+      userName: "",
+      userRemName: ""
+    };
+  },
+  created() {
+    this.projectId = this.$route.query.projectId || this.$store.state.pid;
+    this.deptId = this.$route.query.deptId || "";
+    this.getUserSignList(false);
+    // 获取元素高度
+    this.$nextTick(() => {
+      this.tHeight = this.$refs.tTop.getBoundingClientRect().top;
+    });
+  },
+  computed: {
+    // 计算元素高度
+    THeight() {
+      return `height: calc( 100vh - ${this.tHeight}px )`;
+    },
+  },
+  methods: {
+    async getUserSignList(flag) {
+      if(flag) {
+        this.userList = []
+      }
+      let data = {
+        projectId: this.projectId,
+        pageNum: flag ? this.pageNum = 1 : this.pageNum,
+        pageSize: 10,
+        deptId: this.deptId,
+        userName: this.userName,
+      };
+      await userSignList(data).then((res) => {
+        if (res.status === 10000) {
+          if (!res.data.row.length) {
+            this.finished = true;
+          }
+          this.userList.push(...res.data.row);
+          this.loading = false;
+        } else {
+          Notify({ type: "warning", message: res.message });
+          this.loading = false;
+        }
+      });
+    },
+    onLoad() {
+      this.loading = true;
+      this.finished = false;
+      this.pageNum++;
+      this.getUserSignList(false);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+$borderRadius: 3px;
+$blue: #67a2ff;
+$grey: #f2f2f2;
+/deep/ .van-search {
+  padding: 10px;
+}
+/deep/ .van-search__content {
+  background: #fff;
+  border-top-left-radius: $borderRadius;
+  border-bottom-left-radius: $borderRadius;
+}
+/deep/ .van-search__action {
+  background: $blue;
+  color: #fff;
+  border-top-right-radius: $borderRadius;
+  border-bottom-right-radius: $borderRadius;
+}
+/* /deep/ .van-list__finished-text {
+  border-left: 10px solid $grey;
+  border-right: 10px solid $grey;
+  border-bottom: 10px solid $grey;
+} */
+/deep/ .van-loading {
+  border-left: 10px solid $grey;
+  border-right: 10px solid $grey;
+}
+</style>

+ 42 - 0
src/views/base/peopleManage.vue

@@ -0,0 +1,42 @@
+<template>
+  <div>
+    <nav-bar />
+    <manage-index :listData="listData" style="overflow-y:auto;height:calc( 100vh - 44px );" />
+  </div>
+</template>
+
+<script>
+import navBar from "@/components/navBar";
+import manageIndex from "@/components/peopleManage/index";
+import { Notify } from "vant";
+import { userManageList } from "@/api"
+export default {
+  name: "peopleManage",
+  components: {
+    navBar,
+    manageIndex
+  },
+  created() {
+    this.getUserManageList()
+  },
+  data() {
+    return {
+      listData: []
+    }
+  },
+  methods: {
+    getUserManageList() {
+      userManageList(this.$store.state.pid).then( res => {
+        if(res.status === 10000) {
+          this.listData = res.data
+        } else {
+          Notify({ type: 'warning', message: res.message })
+        }
+      })
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 14 - 5
src/views/base/punch.vue

@@ -18,7 +18,7 @@
     </van-row>
     <!-- </keep-alive> -->
     <van-row style="padding-left: 30px">今日打卡信息</van-row>
-    <template v-if="punchInfo.upSignRecordState != 3">
+    <template v-if="punchInfo.upSignRecordState != 3 && Object.keys(punchInfo).length">
       <punch-info
         :punchItem="punchInfo"
       ></punch-info>
@@ -39,7 +39,7 @@ import headInfo from "@/components/headInfo";
 import punchInfo from "@/components/punchInfo";
 import empty from "@/assets/empty.png";
 import { Toast,Notify } from "vant";
-import { getButtonState,getTodaySignRecord,signRecord } from "@/api"
+import { getButtonState,getTodaySignRecord,signRecord,userInfoHead } from "@/api"
 export default {
   name: "punch",
   components: {
@@ -80,11 +80,9 @@ export default {
   },
   created() {
     this.$store.commit('showLoading')
+    this.getUserInfoHead()
     this.getButtonStateInfo()
   },
-  // mounted() {
-   
-  // },
   activated() {
      this.currentTime();
   },
@@ -93,6 +91,17 @@ export default {
     // clearInterval(this.interTwo)
   },
   methods: {
+    // 获取用户信息
+    getUserInfoHead() {
+      userInfoHead().then(res => {
+        if(res.status === 10000) {
+          this.$store.commit('setUserInfo',res.data)
+        } else {
+          this.$store.commit('hideLoading')
+          Notify({ type: 'warning', message: res.message })
+        }
+      })
+    },
     // 获取按钮信息
     getButtonStateInfo(arg = true) {
       getButtonState().then(res => {