pengjing 5 ヶ月 前
コミット
6bd4f87ef3

+ 17 - 2
h5app/src/App.vue

@@ -301,7 +301,7 @@ ion-grid {
       --padding-start: 0px;
     }
 
-    ion-textarea{
+    ion-textarea {
       border-bottom: 1px solid #f1f5f7;
       color: #8c8f93;
       --padding-start: 0px;
@@ -411,7 +411,7 @@ ion-grid {
 }
 
 
-.cascade-model{
+.cascade-model {
   --height: 50%;
   --border-radius: 16px;
   --box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
@@ -477,6 +477,7 @@ ion-grid {
   }
 
   /* 可以根据需要自定义滚动条的样式 */
+
   .custom-scroll::-webkit-scrollbar {
     width: 8px;
   }
@@ -492,4 +493,18 @@ ion-grid {
 
 }
 
+.b-select {
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px solid #f1f5f7;
+
+  ion-input{
+    border: none;
+  }
+
+  a{
+    color: #02a6f1;font-size: 16px;padding: 10px 8px 10px 16px;
+  }
+}
+
 </style>

+ 11 - 0
h5app/src/api/position/index.ts

@@ -26,4 +26,15 @@ export function getLongitudeLatitudeList(userId: string, startDate: any, endDate
             isNew: true,
         },
     );
+}
+
+export function saveSignin(data: any) {
+    return request(
+        {
+            url: 'longitudeLatitude/saveSignin',
+            method: 'post',
+            data: data,
+        },
+        {isNew: true},
+    );
 }

+ 2 - 1
h5app/src/components/bImage.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="img-list" v-viewer>
     <div class="img-item" v-for="(it,key) in imageList" :key="key">
-      <div v-if="it.blobUrl">
+      <div v-if="it.blobUrl" style="height: 100%;">
         <img :src="it.blobUrl"/>
         <ion-icon v-if="!readonly" :icon="closeCircleOutline" color="danger" class="remove-icon"
                   @click="deleteFile(it)"></ion-icon>
@@ -173,6 +173,7 @@ export default defineComponent({
     width: 25%;
     position: relative;
     padding: 0 5px;
+    height: 80px;
 
     img {
       height: 100%;

+ 148 - 0
h5app/src/components/companySelect.vue

@@ -0,0 +1,148 @@
+<template>
+  <div class="b-select" @click="onOpen()">
+    <ion-input placeholder="请选择企业" label-placement="stacked" v-model="resultInfo.text"
+               class="custom"
+               readonly>
+    </ion-input>
+    <a @click="onOpen()">选择</a>
+  </div>
+  <ion-modal :is-open="isOpen" @willPresent="onRest()">
+    <ion-header class="header-theme2">
+      <ion-toolbar>
+        <ion-buttons slot="start">
+          <ion-icon :icon="arrowBackOutline" @click="onClose()"></ion-icon>
+        </ion-buttons>
+        <ion-title>选择企业</ion-title>
+        <ion-buttons slot="end">
+          <ion-button fill="clear" @click="onClose()">关闭</ion-button>
+        </ion-buttons>
+      </ion-toolbar>
+    </ion-header>
+    <ion-content class="ion-padding">
+      <ion-item class="search-item" style="--border-style: unset; --inner-padding-end: 0px;--padding-start: 0px;">
+        <ion-input placeholder="请输入企业名称" class="custom"
+                   v-model="searchParams.companyName"
+                   @input="reload()" :clear-on-edit="true"
+                   style="border: 1px solid #f2f2f5;border-radius: 14px;--padding-start: 10px;height: 35px;">
+          <ion-icon slot="start" :icon="searchOutline" aria-hidden="true"></ion-icon>
+        </ion-input>
+      </ion-item>
+      <div class="bw-vue-list">
+        <div class="list-content">
+          <ion-list>
+            <ion-item v-for="(record,key) in dataList" :key="key">
+              <ion-label @click="onSelect(record)">
+                <span v-html="formatStr(record.companyName)"></span>
+              </ion-label>
+            </ion-item>
+          </ion-list>
+          <b-empty v-if="dataList.length<=0" :loading="loading"/>
+        </div>
+      </div>
+    </ion-content>
+  </ion-modal>
+</template>
+
+<script lang="ts">
+import {computed, defineComponent, reactive, ref, watch} from 'vue';
+import {arrowBackOutline, searchOutline} from 'ionicons/icons';
+import {IonIcon, onIonViewDidEnter} from '@ionic/vue';
+import BEmpty from "@/components/empty.vue";
+import {getCompanyList} from "@/api/company";
+
+export default defineComponent({
+  name: 'companySelect',
+  components: {IonIcon, BEmpty},
+  props: {},
+  setup(props, context) {
+    const total = ref(30);
+    const loading = ref(false);
+    const pagination = computed(() => ({
+      total: total,
+      current: searchParams.pageIndex,
+      pageSize: searchParams.pageSize
+    }));
+    const searchParams = reactive({
+      pageIndex: 1,
+      pageSize: 30,
+      companyName: '',
+    });
+    const isOpen = ref(false);
+    const dataList = ref<any>([]);
+    const resultInfo = reactive({value: '', text: ''})
+
+    const reloadBool = ref(true);
+    const reload = () => {
+      if (searchParams.companyName == '') {
+        dataList.value = [];
+        return;
+      }
+
+      setTimeout(() => {
+        searchParams.pageIndex = 1;
+        if (reloadBool.value == false) {
+          return;
+        }
+
+        reloadBool.value = false;
+        loading.value = true;
+        getCompanyList(searchParams).then(data => {
+          dataList.value = data.list;
+          total.value = data.total;
+          reloadBool.value = true;
+          loading.value = false;
+        })
+      }, 1000)
+    }
+
+    const onSelect = (item: any) => {
+      resultInfo.text = item.companyName;
+      resultInfo.value = item.companyID;
+      context.emit("resultInfo", resultInfo);
+      onClose();
+    }
+
+    const onOpen = () => {
+      isOpen.value = true;
+    }
+
+    const onClose = () => {
+      isOpen.value = false;
+    };
+
+    const onRest = () => {
+      dataList.value = [];
+      searchParams.companyName = '';
+      searchParams.pageIndex = 1;
+      resultInfo.text = '';
+      resultInfo.value = '';
+    }
+
+    const formatStr = (str: any) => {
+      if (!str) {
+        return "";
+      }
+
+      return str.replace(searchParams.companyName, '<span style="color: coral">' + searchParams.companyName + '</span>');
+    }
+
+    return {
+      searchOutline,
+      arrowBackOutline,
+      total,
+      loading,
+      isOpen,
+      dataList,
+      pagination,
+      searchParams,
+      onSelect,
+      onOpen,
+      onClose,
+      reload,
+      onRest,
+      formatStr,
+      resultInfo
+    }
+  }
+});
+</script>

+ 142 - 0
h5app/src/components/jobUserSelect.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="b-select" @click="onOpen()">
+    <ion-input placeholder="请选择求职人员" label-placement="stacked" v-model="resultInfo.text"
+               class="custom"
+               readonly>
+    </ion-input>
+    <a @click="onOpen()">选择</a>
+  </div>
+  <ion-modal :is-open="isOpen" @willPresent="onRest()">
+    <ion-header class="header-theme2">
+      <ion-toolbar>
+        <ion-buttons slot="start">
+          <ion-icon :icon="arrowBackOutline" @click="onClose()"></ion-icon>
+        </ion-buttons>
+        <ion-title>选择人员</ion-title>
+        <ion-buttons slot="end">
+          <ion-button fill="clear" @click="onClose()">关闭</ion-button>
+        </ion-buttons>
+      </ion-toolbar>
+    </ion-header>
+    <ion-content class="ion-padding">
+      <ion-item class="search-item" style="--border-style: unset; --inner-padding-end: 0px;--padding-start: 0px;">
+        <ion-input placeholder="请输入求职人员姓名" class="custom"
+                   v-model="searchParams.name"
+                   @input="reload()" :clear-on-edit="true"
+                   style="border: 1px solid #f2f2f5;border-radius: 14px;--padding-start: 10px;height: 35px;">
+          <ion-icon slot="start" :icon="searchOutline" aria-hidden="true"></ion-icon>
+        </ion-input>
+      </ion-item>
+      <div class="bw-vue-list">
+        <div class="list-content">
+          <ion-list>
+            <ion-item v-for="(record,key) in dataList" :key="key">
+              <ion-label @click="onSelect(record)">
+                <span v-html="formatStr(record.name)"></span>
+              </ion-label>
+            </ion-item>
+          </ion-list>
+          <b-empty v-if="dataList.length<=0" :loading="loading"/>
+        </div>
+      </div>
+    </ion-content>
+  </ion-modal>
+</template>
+
+<script lang="ts">
+import {computed, defineComponent, reactive, ref, watch} from 'vue';
+import {arrowBackOutline, searchOutline} from 'ionicons/icons';
+import {IonIcon, onIonViewDidEnter} from '@ionic/vue';
+import BEmpty from "@/components/empty.vue";
+import {getJobUserList} from "@/api/jobUserInfo";
+import {useUserStore} from "@/store/modules/user";
+
+export default defineComponent({
+  name: 'jobuserSelect',
+  components: {IonIcon, BEmpty},
+  props: {},
+  setup(props, context) {
+    const total = ref(30);
+    const loading = ref(false);
+    const pagination = computed(() => ({
+      total: total,
+      current: searchParams.pageIndex,
+      pageSize: searchParams.pageSize
+    }));
+    const searchParams = reactive({
+      pageIndex: 1,
+      pageSize: 30,
+      name: '',
+      loginUserID: ''
+    });
+    const isOpen = ref(false);
+    const dataList = ref<any>([]);
+    const resultInfo = reactive({value: '', text: ''});
+
+    const reload = () => {
+      setTimeout(() => {
+        searchParams.pageIndex = 1;
+
+        loading.value = true;
+        const loginUserInfo = useUserStore().getUserInfo;
+        searchParams.loginUserID = loginUserInfo.userID || '';
+        getJobUserList(searchParams).then(data => {
+          dataList.value = data.list;
+          total.value = data.total;
+          loading.value = false;
+        })
+      }, 300)
+    }
+
+    const onSelect = (item: any) => {
+      resultInfo.text = item.name;
+      resultInfo.value = item.jobUserID;
+      context.emit("resultInfo", resultInfo);
+      onClose();
+    }
+
+    const onOpen = () => {
+      isOpen.value = true;
+    }
+
+    const onClose = () => {
+      isOpen.value = false;
+    };
+
+    const onRest = () => {
+      dataList.value = [];
+      searchParams.name = '';
+      searchParams.pageIndex = 1;
+      resultInfo.text = '';
+      resultInfo.value = '';
+      reload();
+    }
+
+    const formatStr = (str: any) => {
+      if (!str) {
+        return "";
+      }
+
+      return str.replace(searchParams.name, '<span style="color: coral">' + searchParams.name + '</span>');
+    }
+
+    return {
+      searchOutline,
+      arrowBackOutline,
+      total,
+      loading,
+      isOpen,
+      dataList,
+      pagination,
+      searchParams,
+      onSelect,
+      onOpen,
+      onClose,
+      reload,
+      onRest,
+      formatStr,
+      resultInfo
+    }
+  }
+});
+</script>

+ 1 - 1
h5app/src/utils/position.ts

@@ -35,7 +35,7 @@ export function getPosition() {
                 resolve(data)
             }, function () {
                 // eslint-disable-next-line prefer-rest-params
-                reject(arguments)
+                /*reject(arguments)*/
             }, {
                 enableHighAccuracy: true,
                 timeout: 10000

+ 115 - 23
h5app/src/views/pages/work/signin/index.vue

@@ -12,15 +12,33 @@
       <ion-item class="search-item">
         当前时间:{{ dayjs(new Date()).format("YYYY-MM-DD HH:mm") }}
       </ion-item>
-      <div id='signInMap' style=' width: 100%; height: 65%; z-index: 100'></div>
+      <div id='signInMap' style=' width: 100%; height: 200px; z-index: 100'></div>
       <div class="bw-vue-form">
-        <div class="form-detail">
-          <ion-label>经度</ion-label>
-          <ion-text>{{ position.longitude }}</ion-text>
+        <div class="form-select">
+          <ion-label>打卡类型<span class="danger">*</span></ion-label>
+          <ion-select interface="action-sheet" placeholder="请选择打卡类型" cancel-text="取消"
+                      id="signinType" v-model="dataModel.signinType" @change="signinTypeChange()">
+            <ion-select-option v-for="(record,key) in signinTypeList" :key="key"
+                               v-model:value="record.value">
+              {{ record.name }}
+            </ion-select-option>
+          </ion-select>
         </div>
-        <div class="form-detail">
-          <ion-label>纬度</ion-label>
-          <ion-text>{{ position.latitude }}</ion-text>
+        <div class="form-select" v-if="dataModel.signinType===1">
+          <ion-label>走访企业<span class="danger">*</span></ion-label>
+          <company-select ref="refCompanySelect" @resultInfo="onCompanySelect"></company-select>
+        </div>
+        <div class="form-select" v-if="dataModel.signinType===2">
+          <ion-label>走访人员<span class="danger">*</span></ion-label>
+          <job-user-select ref="refJobuserSelect" @resultInfo="onJobUserSelect"></job-user-select>
+        </div>
+        <div class="form-input">
+          <ion-label>服务内容</ion-label>
+          <ion-textarea v-model="dataModel.content" rows="5" cols="20" placeholder="请填写服务内容"></ion-textarea>
+        </div>
+        <div class="form-input">
+          <ion-label>照片</ion-label>
+          <b-image :file-ref-id="dataModel.signinId" :readonly="false" :is-single="false"></b-image>
         </div>
       </div>
       <div class="btn-box">
@@ -31,7 +49,7 @@
   </ion-page>
 </template>
 <script>
-import {defineComponent, reactive, ref} from "vue";
+import {defineComponent, reactive, ref, toRefs} from "vue";
 import {alertController, onIonViewDidEnter} from "@ionic/vue";
 import {useUserStore} from "../../../../store/modules/user";
 import dayjs from 'dayjs';
@@ -39,7 +57,12 @@ import {getPosition} from "@/utils/position";
 import thIcon from "@/assets/icon/th.jpg"
 import {arrowBackOutline} from "ionicons/icons";
 import {useRouter} from "vue-router";
-import {saveLongitudeLatitude} from "@/api/position";
+import {saveSignin} from "@/api/position";
+import CompanySelect from "@/components/companySelect.vue";
+import JobUserSelect from "@/components/jobUserSelect.vue";
+import {getSysDictionaryList} from "../../../../api/system/dictionary";
+import {v4 as uuidv4} from 'uuid';
+import BImage from "@/components/bImage.vue";
 
 const presentAlert = async (header, message) => {
   const alert = await alertController.create({
@@ -55,6 +78,7 @@ const presentAlert = async (header, message) => {
 
 export default defineComponent({
   name: 'signInMap',
+  components: {CompanySelect, JobUserSelect, BImage},
   methods: {
     arrowBackOutline() {
       return arrowBackOutline
@@ -73,6 +97,27 @@ export default defineComponent({
     let map = null;
     let label = null;
     let marker = null;
+    const refCompanySelect = ref();
+    const refJobuserSelect = ref();
+    const formState = reactive({
+      dataModel: {
+        signinId: null,
+        signinType: null,
+        companyID: null,
+        companyName: '',
+        jobuserID: null,
+        longitude: null,
+        latitude: null,
+        content: '',
+        createUserID: userInfo.value.userID
+      }
+    });
+    const signinTypeList = ref([]);
+
+    const getSigninTypeList = async function () {
+      const signinTypeListResult = await getSysDictionaryList("SigninType");
+      signinTypeList.value = signinTypeListResult;
+    }
 
     const setMarker = () => {
       // 删除点
@@ -125,30 +170,77 @@ export default defineComponent({
 
     // 保存
     function onSave() {
-      if (position.latitude && position.longitude) {
-        const sendData = {
-          userId: userInfo.value.userID,
-          time: Date.now(),
-          longitude: position.longitude,
-          latitude: position.latitude,
-        }
-        // 发送请求
-        saveLongitudeLatitude(sendData).then(() => {
-          presentAlert('提示', '签到成功');
-        });
-      } else {
+      if(!(position.latitude && position.longitude)){
         presentAlert('提示', '获取位置信息失败');
+        return false;
       }
+
+      if (!formState.dataModel.signinType) {
+        presentAlert('提示', '请选择打卡类型');
+        return false;
+      }
+
+      if (formState.dataModel.signinType === 1 && !formState.dataModel.companyID) {
+        presentAlert('提示', '请选择走访企业');
+        return false;
+      }
+
+      if (formState.dataModel.signinType === 2 && !formState.dataModel.jobuserID) {
+        presentAlert('提示', '请选择走访人员');
+        return false;
+      }
+
+      formState.dataModel.latitude = position.latitude;
+      formState.dataModel.longitude = position.longitude;
+      // 发送请求
+      saveSignin(formState.dataModel).then(() => {
+        onBack();
+        presentAlert('提示', '签到成功');
+      });
     }
 
+    const onCompanySelect = (data) => {
+      formState.dataModel.companyID = data.value;
+    };
+
+    const onJobUserSelect = (data) => {
+      formState.dataModel.jobuserID = data.value;
+    };
+
+    const signinTypeChange = () => {
+      formState.dataModel.companyID = '';
+      formState.dataModel.jobuserID = '';
+    };
+
+    const resetData = function () {
+      formState.dataModel.signinId = uuidv4();
+      formState.dataModel.companyID = null;
+      formState.dataModel.jobuserID = '';
+      formState.dataModel.signinType = null;
+      formState.dataModel.longitude = null;
+      formState.dataModel.latitude = null;
+      formState.dataModel.content = '';
+    };
+
     onIonViewDidEnter(() => {
+      resetData();
+
       initMap();
+
+      getSigninTypeList();
     });
 
     return {
+      ...toRefs(formState),
+      refCompanySelect,
+      refJobuserSelect,
+      signinTypeList,
       onBack,
       onSave,
-      position
+      onCompanySelect,
+      onJobUserSelect,
+      getSigninTypeList,
+      signinTypeChange
     }
   }
 });
@@ -159,6 +251,6 @@ export default defineComponent({
   width: 100%;
   display: flex;
   justify-content: center;
-  padding-top: 5px;
+  padding: 15px;
 }
 </style>

+ 16 - 0
src/main/java/com/hz/employmentsite/controller/LongitudeLatitudeController.java

@@ -3,8 +3,11 @@ package com.hz.employmentsite.controller;
 import com.hz.employmentsite.filter.exception.BaseResponse;
 import com.hz.employmentsite.filter.exception.RespGenerstor;
 import com.hz.employmentsite.model.PcLongitudeLatitude;
+import com.hz.employmentsite.model.PcSignin;
+import com.hz.employmentsite.services.service.AccountService;
 import com.hz.employmentsite.services.service.LongitudeLatitudeService;
 import com.hz.employmentsite.vo.taskAndLog.PcLongitudeLatitudeVo;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
@@ -17,6 +20,8 @@ public class LongitudeLatitudeController {
 
     @Resource
     private LongitudeLatitudeService longitudeLatitudeService;
+    @Autowired
+    private AccountService accountService;
 
     @PostMapping("/save")
     public BaseResponse save(@RequestBody PcLongitudeLatitude data) {
@@ -36,4 +41,15 @@ public class LongitudeLatitudeController {
         return RespGenerstor.success(longitudeLatitudeService.newAllList(userName, startDate, regionCode, siteID));
     }
 
+    @PostMapping("/saveSignin")
+    public BaseResponse saveSignin(@RequestBody PcSignin data) {
+        String loginUserID = data.getCreateUserID();
+        try {
+            loginUserID = accountService.getLoginUserID();
+        }
+        catch (Exception e){
+        }
+        return RespGenerstor.success(longitudeLatitudeService.saveSignin(data,loginUserID));
+    }
+
 }

+ 39 - 0
src/main/java/com/hz/employmentsite/services/impl/LongitudeLatitudeServiceImpl.java

@@ -1,9 +1,15 @@
 package com.hz.employmentsite.services.impl;
 
 import com.hz.employmentsite.mapper.PcLongitudeLatitudeMapper;
+import com.hz.employmentsite.mapper.PcSigninMapper;
+import com.hz.employmentsite.mapper.PcSiteUserMapper;
 import com.hz.employmentsite.mapper.cquery.LongitudeLatitudeCQuery;
 import com.hz.employmentsite.model.PcLongitudeLatitude;
+import com.hz.employmentsite.model.PcSignin;
+import com.hz.employmentsite.model.PcSiteUser;
+import com.hz.employmentsite.model.PcSiteUserExample;
 import com.hz.employmentsite.services.service.LongitudeLatitudeService;
+import com.hz.employmentsite.util.StringUtils;
 import com.hz.employmentsite.vo.taskAndLog.PcLongitudeLatitudeVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -22,6 +28,15 @@ public class LongitudeLatitudeServiceImpl implements LongitudeLatitudeService {
     @Autowired
     private LongitudeLatitudeCQuery longitudeLatitudeCQuery;
 
+    @Autowired
+    private PcSigninMapper pcSigninMapper;
+
+    @Autowired
+    private PcSiteUserMapper pcSiteUserMapper;
+
+    @Autowired
+    private StringUtils stringUtils;
+
     @Override
     public Integer save(PcLongitudeLatitude data) {
         Integer result = 0;
@@ -40,4 +55,28 @@ public class LongitudeLatitudeServiceImpl implements LongitudeLatitudeService {
     public List<PcLongitudeLatitudeVo> newAllList(String userName, Date startDate, String regionCode, String siteID) {
         return longitudeLatitudeCQuery.selectNewAllList(userName, startDate, regionCode, siteID);
     }
+
+    @Override
+    public Integer saveSignin(PcSignin data, String userId) {
+        data.setSigninTime(new Date());
+        data.setCreateTime(new Date());
+        data.setCreateUserID(userId);
+
+        if (!stringUtils.IsNullOrEmpty(userId)) {
+            PcSiteUserExample siteUserExp = new PcSiteUserExample();
+            siteUserExp.or().andUserIDEqualTo(userId);
+            PcSiteUser pcSiteUser = pcSiteUserMapper.selectByExample(siteUserExp).stream().findFirst().orElse(null);
+
+            if (pcSiteUser != null)
+                data.setSiteID(pcSiteUser.getSiteID());
+        }
+
+        if (stringUtils.IsNullOrEmpty(data.getCompanyID()))
+            data.setCompanyID(null);
+
+        if (stringUtils.IsNullOrEmpty(data.getJobuserID()))
+            data.setJobuserID(null);
+
+        return pcSigninMapper.insert(data);
+    }
 }

+ 3 - 0
src/main/java/com/hz/employmentsite/services/service/LongitudeLatitudeService.java

@@ -1,6 +1,7 @@
 package com.hz.employmentsite.services.service;
 
 import com.hz.employmentsite.model.PcLongitudeLatitude;
+import com.hz.employmentsite.model.PcSignin;
 import com.hz.employmentsite.vo.taskAndLog.PcLongitudeLatitudeVo;
 
 import java.util.Date;
@@ -12,4 +13,6 @@ public interface LongitudeLatitudeService {
     List<PcLongitudeLatitudeVo> list(String userId, Date startDate, Date endDate);
 
     List<PcLongitudeLatitudeVo> newAllList(String userName, Date startDate, String regionCode, String siteID);
+
+    Integer saveSignin(PcSignin data,String userId);
 }