Bläddra i källkod

Merge branch 'master' of http://39.98.153.250:9080/bowintek/EmploymentSite

pengjing 10 månader sedan
förälder
incheckning
4000ecf4a1

+ 11 - 0
h5app/src/App.vue

@@ -204,6 +204,17 @@ ion-content {
 .list-page {
   --background: #fafafa !important;
 
+  .custom {
+    --placeholder-color: gray;
+    --placeholder-opacity: 0.5;
+  }
+
+  .container {
+    display: flex;
+    justify-content: center; /* 水平居中 */
+    align-items: center; /* 垂直居中 */
+  }
+
   .list-content {
     margin: 10px 8px;
     background-color: #f0f2f5;

+ 14 - 0
h5app/src/api/jobHuntInfo/index.ts

@@ -53,3 +53,17 @@ export function saveJobHunt(data: any) {
     );
 }
 
+export function deleteJobHuntAndRecommendMgt(id:any) {
+    return request<object>(
+        {
+            url: 'jobUserService/jobHunt/deleteJobHuntAndRecommendMgt',
+            method: 'post',
+            params: {id},
+        },
+        {
+            isNew: true,
+            successMsg: '删除成功!',
+            errorMsg: '删除失败!'
+        },
+    );
+}

+ 91 - 65
h5app/src/views/pages/jobhunt/recommend/list.vue

@@ -1,5 +1,5 @@
 <template>
-  <ion-page class="list-page company-list-page">
+  <ion-page class="list-page">
     <ion-header class="header-theme2">
       <ion-toolbar>
         <ion-buttons slot="start">
@@ -11,33 +11,50 @@
     <ion-content>
       <ion-item class="search-item">
         <ion-input placeholder="姓名" class="custom"
-                   v-model="searchParams.jobUserName" style="border: 1px solid #f2f2f5;border-radius: 14px;--padding-start: 10px;height: 35px;"></ion-input>
-        <ion-button slot="end" style="height: 33px;width: 70px;margin-left: 10px;--box-shadow: none;--border-radius: 14px;" @click="reload" >搜索
+                   v-model="searchParams.jobUserName"
+                   style="border: 1px solid #f2f2f5;border-radius: 14px;--padding-start: 10px;height: 35px;"></ion-input>
+        <ion-button slot="end"
+                    style="height: 33px;width: 70px;margin-left: 10px;--box-shadow: none;--border-radius: 14px;"
+                    @click="reload">搜索
         </ion-button>
       </ion-item>
-      <ion-list class="list-content">
-        <ion-item v-for="(record,key) in dataList" :key="key">
-          <ion-label>
-            <ion-label style="display: flex;justify-content: space-between;">
-            <h2>{{ record.jobUserName}}</h2>
-            <h2>{{ record.professionName }}</h2>
-            </ion-label>
-            <p>人才类型:{{record.jobUserTypeStr}}</p>
-            <ion-label style="display: flex;justify-content: space-between;">
-              <p>
-                工作年限:{{ record.workYear }}
-              </p>
-              <p>
-                求职类型:{{ record.jobHuntTypeStr }}
-              </p>
-            </ion-label>
-            <p>月薪要求:{{ record.minSalary }}至{{ record.maxSalary }}元</p>
-          </ion-label>
-          <ion-avatar @click="onRecommendJob(record);$event.preventDefault();$event.stopPropagation();" aria-hidden="true" class="container" slot="end">
-            <p style="font-size: 14px !important;">推荐</p>
-          </ion-avatar>
-        </ion-item>
-      </ion-list>
+      <div class="bw-vue-list">
+        <div class="list-content">
+          <ion-list>
+            <div v-for="(record,key) in dataList" :key="key" detail>
+              <ion-item-sliding>
+                <ion-item>
+                  <ion-label>
+                    <div class="multi-title">
+                      <h2>{{ record.jobUserName }}</h2>
+                      <h2>{{ record.professionName }}</h2>
+                    </div>
+                    <p>人才类型:{{ record.jobUserTypeStr }}</p>
+                    <div class="multi-title">
+                      <p>
+                        工作年限:{{ record.workYear }}
+                      </p>
+                      <p>
+                        求职类型:{{ record.jobHuntTypeStr }}
+                      </p>
+                    </div>
+                    <p>月薪要求:{{ record.minSalary }}至{{ record.maxSalary }}元</p>
+                  </ion-label>
+                  <ion-avatar @click="onRecommendJob(record);$event.preventDefault();$event.stopPropagation();"
+                              aria-hidden="true" class="container" slot="end">
+                    <ion-button size="small" fill="outline">推荐</ion-button>
+                  </ion-avatar>
+                </ion-item>
+                <ion-item-options>
+                  <ion-item-option color="danger" @click="onDel(record.jobHuntID)">
+                    <ion-icon :icon="trashOutline"></ion-icon>
+                  </ion-item-option>
+                </ion-item-options>
+              </ion-item-sliding>
+            </div>
+          </ion-list>
+        </div>
+      </div>
       <b-empty v-if="dataList.length<=0" :loading="loading"/>
       <ion-infinite-scroll threshold="100px" @ionInfinite="onScroll($event)">
         <ion-infinite-scroll-content
@@ -54,10 +71,10 @@
 import {computed, defineComponent, reactive, ref} from 'vue';
 import dayjs from "dayjs";
 import {useRoute, useRouter} from "vue-router";
-import {arrowBackOutline} from 'ionicons/icons';
-import {IonIcon, onIonViewDidEnter} from '@ionic/vue';
+import {arrowBackOutline,trashOutline} from 'ionicons/icons';
+import {alertController, IonIcon, onIonViewDidEnter} from '@ionic/vue';
 import BEmpty from "@/components/empty.vue";
-import {getJobHuntList} from '@/api/jobHuntInfo/index'
+import {getJobHuntList, deleteJobHuntAndRecommendMgt} from '@/api/jobHuntInfo/index'
 
 export default defineComponent({
   name: 'RecommendCompanyPostList',
@@ -104,8 +121,46 @@ export default defineComponent({
       }, 500);
     }
 
-    const onRecommendJob = (item: any) =>{
-      router.push({path: './recommend', query: {reload: 1,professionID:item.professionID,professionName:item.professionName,jobHuntID:item.jobHuntID,jobUserName:item.jobUserName,type:0}});
+    const onRecommendJob = (item: any) => {
+      router.push({
+        path: './recommend', query: {
+          reload: 1,
+          professionID: item.professionID,
+          professionName: item.professionName,
+          jobHuntID: item.jobHuntID,
+          jobUserName: item.jobUserName,
+          type: 0,
+          parentProfessionID: item.parentProfessionID,
+          cultureRank: item.cultureRank,
+          workYear: item.workYear,
+          minSalary: item.minSalary,
+          maxSalary: item.maxSalary
+        }
+      });
+    }
+
+    const onDel = async (id: any) => {
+      const alert = await alertController.create({
+        header: '提示!',
+        message: '是否确认删除?',
+        buttons: [
+          {
+            text: '取消',
+            role: 'cancel'
+          },
+          {
+            text: '确认删除',
+            handler: () => {
+              deleteJobHuntAndRecommendMgt(id).then(result => {
+                if (result)
+                  reload();
+              });
+            }
+          }
+        ],
+      });
+
+      await alert.present();
     }
 
     const onBack = () => {
@@ -113,57 +168,28 @@ export default defineComponent({
     }
 
     onIonViewDidEnter(() => {
-      if(route.query.reload)reload();
+      if (route.query.reload) reload();
     });
 
     return {
       arrowBackOutline,
+      trashOutline,
       router,
       total,
       loading,
       dataList,
       pagination,
       searchParams,
+      loadData,
       onBack,
       onRecommendJob,
+      onDel,
       onScroll,
-      loadData,
       reload,
       dayjs,
     }
-  },created() {
+  }, created() {
     this.loadData();
   }
 });
 </script>
-
-<style lang="less">
-.custom{
-  --placeholder-color: gray;
-  --placeholder-opacity: 0.5;
-}
-
-.company-list-page {
-  .list-content {
-    margin: 0px 15px !important;
-    background-color: white !important;
-    border-radius: 0 !important;
-
-    ion-item {
-      margin-top: 10px;
-      font-size: 14px;
-      border: 1px solid rgb(242, 242, 245);
-
-      p {
-        font-size: 12px;
-      }
-    }
-  }
-}
-
-.container {
-  display: flex;
-  justify-content: center; /* 水平居中 */
-  align-items: center; /* 垂直居中 */
-}
-</style>

+ 119 - 53
h5app/src/views/pages/jobhunt/recommend/recommend.vue

@@ -1,5 +1,5 @@
 <template>
-  <ion-page class="list-page company-list-page">
+  <ion-page class="list-page">
     <ion-header class="header-theme2">
       <ion-toolbar>
         <ion-buttons slot="start">
@@ -15,19 +15,49 @@
           <br/>
           <h2>{{ searchParams.professionName }}</h2>
         </ion-label>
+        <ion-button id="popover-checkbox" @click="popoverCheckboxIsOpen = true" slot="end"
+                    style="height: 33px;width: 90px;margin-left: 10px;--box-shadow: none;--border-radius: 14px;">招聘岗位筛选
+        </ion-button>
+        <ion-popover size="auto" trigger="popover-checkbox" :is-open="popoverCheckboxIsOpen" :backdrop-dismiss="false"
+                     :dismiss-on-select="false">
+          <ion-content>
+            <ion-list>
+              <ion-item v-for="(record,key) in recommendPostWhereList" :key="key">
+                <ion-checkbox :detail="false" v-model="record.check" label-placement="end">{{ record.name }}
+                </ion-checkbox>
+              </ion-item>
+              <ion-item>
+                <ion-button @click="onRestRecommendPostWhere" slot="end" fill="clear" size="small">重置</ion-button>
+                <ion-button @click="onPopoverConfirm" slot="end" size="small">确定</ion-button>
+              </ion-item>
+            </ion-list>
+          </ion-content>
+        </ion-popover>
       </ion-item>
-      <ion-list class="list-content">
-        <ion-item v-for="(record,key) in dataList" detail :key="key">
-          <ion-label>
-            <h2>{{ record.professionName }}</h2>
-            <p>单位:{{ record.companyName }}</p>
-            <p>薪资待遇:{{ record.minSalary }}至{{ record.maxSalary }}元</p>
-          </ion-label>
-          <ion-avatar aria-hidden="true" class="container" slot="end">
-            <ion-text style="text-align:right;" @click="onRecommend(record)">推荐</ion-text>
-          </ion-avatar>
-        </ion-item>
-      </ion-list>
+      <div class="bw-vue-list">
+        <div class="list-content">
+          <ion-list>
+            <ion-item v-for="(record,key) in dataList" :key="key">
+              <ion-label>
+                <h2>{{ record.professionName }}</h2>
+                <p>单位:{{ record.companyName }}</p>
+                <div class="multi-title">
+                  <p>
+                    学历:{{ record.cultureRankName }}
+                  </p>
+                  <p>
+                    工作年限:{{ record.workYearName }}
+                  </p>
+                </div>
+                <p>薪资待遇:{{ record.minSalary }}至{{ record.maxSalary }}元</p>
+              </ion-label>
+              <ion-avatar aria-hidden="true" class="container" slot="end">
+                <ion-button size="small" @click="onRecommend(record)" fill="outline">推荐</ion-button>
+              </ion-avatar>
+            </ion-item>
+          </ion-list>
+        </div>
+      </div>
       <b-empty v-if="dataList.length<=0" :loading="loading"/>
       <ion-infinite-scroll threshold="100px" @ionInfinite="onScroll($event)">
         <ion-infinite-scroll-content
@@ -48,6 +78,7 @@ import {computed, defineComponent, reactive, ref, watch} from 'vue';
 import {arrowBackOutline, addCircleOutline} from 'ionicons/icons';
 import {alertController, IonIcon, onIonViewDidEnter} from '@ionic/vue';
 import {getRecommendCompanyPostList, addRecommend} from "@/api/recommendmgt";
+import {getSysDictionaryList} from '@/api/system/dictionary'
 
 export default defineComponent({
   name: 'RecommendCompanyPost',
@@ -69,19 +100,35 @@ export default defineComponent({
       jobHuntID: '',
       professionID: '',
       professionName: null,
-      type: 0
+      type: 0,
+      parentProfessionID: '',
+      cultureRank: null,
+      workYear: null,
+      minSalary: null,
+      maxSalary: null
     })
+    const searchParamsCache = reactive({
+      professionID: '',
+      parentProfessionID: '',
+      cultureRank: null,
+      workYear: null,
+      minSalary: null,
+      maxSalary: null
+    });
     const dataList = ref<any>([]);
     const addRecommendList = ref<any>([]);
-    const colors = ref(["secondary", "tertiary", "success", "warning"]);
+    const recommendPostWhereList = ref<any>([]);
+    const popoverCheckboxIsOpen = ref<boolean>(false);
+
+    const getRecommendTypeList = () => {
+      getSysDictionaryList('RecommendPostWhere').then((data) => {
+        recommendPostWhereList.value = data;
+        recommendPostWhereList.value[0].check = true;
+      });
+    };
 
     const loadData = async function () {
       loading.value = true;
-      searchParams.jobHuntID = route.query.jobHuntID as any;
-      searchParams.jobUserName = route.query.jobUserName as any;
-      searchParams.professionID = route.query.professionID as any;
-      searchParams.professionName = route.query.professionName as any;
-      searchParams.type = route.query.type as any;
       getRecommendCompanyPostList(searchParams).then((data: any) => {
         dataList.value = dataList.value.concat(data.list);
         total.value = data.total;
@@ -99,6 +146,30 @@ export default defineComponent({
       }, 500);
     }
 
+    const onPopoverConfirm = () => {
+      const list = recommendPostWhereList.value.filter((x: any) => x.check == true).map((x: any) => x.value);
+
+      searchParams.professionID = list.findIndex((x: any) => x == 1) >= 0 ? searchParamsCache.professionID : "";
+      searchParams.cultureRank = list.findIndex((x: any) => x == 2) >= 0 ? searchParamsCache.cultureRank : null;
+      searchParams.workYear = list.findIndex((x: any) => x == 3) >= 0 ? searchParamsCache.workYear : null;
+      if (list.findIndex((x: any) => x == 4) >= 0) {
+        searchParams.minSalary = searchParamsCache.minSalary;
+        searchParams.maxSalary = searchParamsCache.maxSalary;
+      } else {
+        searchParams.minSalary = null;
+        searchParams.maxSalary = null;
+      }
+      searchParams.parentProfessionID = list.findIndex((x: any) => x == 5) >= 0 ? searchParamsCache.parentProfessionID : "";
+
+      popoverCheckboxIsOpen.value = false;
+      reload();
+    }
+
+    const onRestRecommendPostWhere = () => {
+      recommendPostWhereList.value.map((x: any) => x.check = false);
+      recommendPostWhereList.value[0].check = true;
+    }
+
     const onRecommend = (item: any) => {
       addRecommendList.value.push({
         recommendMgtID: item.recommendMgtID,
@@ -155,8 +226,25 @@ export default defineComponent({
       searchParams.pageIndex = 1;
       loadData();
     }
+
+    const reloadSearchParams = () => {
+      searchParams.jobHuntID = route.query.jobHuntID as any;
+      searchParams.jobUserName = route.query.jobUserName as any;
+      searchParams.professionID = route.query.professionID as any;
+      searchParams.professionName = route.query.professionName as any;
+      searchParams.type = route.query.type as any;
+      searchParamsCache.professionID = route.query.professionID as any;
+      searchParamsCache.parentProfessionID = route.query.parentProfessionID as any;
+      searchParamsCache.cultureRank = route.query.cultureRank as any;
+      searchParamsCache.workYear = route.query.workYear as any;
+      searchParamsCache.workYear = route.query.workYear as any;
+      searchParamsCache.minSalary = route.query.minSalary as any;
+      searchParamsCache.maxSalary = route.query.maxSalary as any;
+    }
+
     onIonViewDidEnter(() => {
       reload();
+      reloadSearchParams();
     });
 
     return {
@@ -164,56 +252,34 @@ export default defineComponent({
       addCircleOutline,
       router,
       route,
-      colors,
       loading,
       pagination,
       searchParams,
+      searchParamsCache,
       dataList,
+      recommendPostWhereList,
+      popoverCheckboxIsOpen,
       onScroll,
       loadData,
       reload,
       onBack,
       onRecommend,
       onBatchRecommend,
+      getRecommendTypeList,
+      onPopoverConfirm,
+      onRestRecommendPostWhere,
     }
+  }, created() {
+    this.getRecommendTypeList()
   }
 });
 </script>
 
 <style lang="less">
-.custom {
-  --placeholder-color: gray;
-  //--placeholder-font-style: italic;
-  --placeholder-opacity: 1;
-}
-
-.company-list-page {
-  .list-content {
-    margin: 0px 15px !important;
-    background-color: white !important;
-    border-radius: 0 !important;
-
-    ion-item {
-      margin-top: 10px;
-      font-size: 14px;
-      border: 1px solid rgb(242, 242, 245);
-
-      p {
-        font-size: 12px;
-      }
-    }
-  }
-}
-
-.container {
-  display: flex;
-  justify-content: center; /* 水平居中 */
-  align-items: center; /* 垂直居中 */
-}
 
-.footer-ios ion-toolbar:first-of-type{
-  --border-width:0 !important;
-  --background:#ffffff !important;
+.footer-ios ion-toolbar:first-of-type {
+  --border-width: 0 !important;
+  --background: #ffffff !important;
 }
 
 </style>

+ 73 - 79
h5app/src/views/pages/post/list.vue

@@ -1,5 +1,5 @@
 <template>
-  <ion-page class="list-page company-list-page">
+  <ion-page class="list-page">
     <ion-header class="header-theme2">
       <ion-toolbar>
         <ion-buttons slot="start">
@@ -14,42 +14,53 @@
     <ion-content>
       <ion-item class="search-item">
         <ion-input placeholder="岗位名称" class="custom"
-                   v-model="searchParams.professionName" style="border: 1px solid #f2f2f5;border-radius: 14px;--padding-start: 10px;height: 35px;"></ion-input>
-        <ion-button slot="end" style="height: 33px;width: 70px;margin-left: 10px;--box-shadow: none;--border-radius: 14px;" @click="reload" >搜索
+                   v-model="searchParams.professionName"
+                   style="border: 1px solid #f2f2f5;border-radius: 14px;--padding-start: 10px;height: 35px;"></ion-input>
+        <ion-button slot="end"
+                    style="height: 33px;width: 70px;margin-left: 10px;--box-shadow: none;--border-radius: 14px;"
+                    @click="reload">搜索
         </ion-button>
       </ion-item>
-      <ion-list class="list-content">
-        <div v-for="(record,key) in dataList" :key="key">
-          <ion-item-sliding>
-        <ion-item>
-          <ion-label>
-            <h3>{{ record.professionName}}</h3>
-            <p>{{ record.companyName }}</p>
-            <p>{{ dayjs(record.startTime).format("YYYY-MM-DD")}}至{{ dayjs(record.endTime).format("YYYY-MM-DD")}}</p>
-            <ion-label style="display: flex;justify-content: space-between;">
-              <p>
-                招聘人数:{{ record.recruitCount == null ? "0" : record.recruitCount }}人
-              </p>
-              <p>
-                已推荐人数:{{ record.recommendNum }}
-              </p>
-            </ion-label>
-          </ion-label>
-          <ion-avatar @click="onRecommendJob(record);$event.preventDefault();$event.stopPropagation();" aria-hidden="true" class="container" slot="end">
-            <p style="font-size: 14px !important;">推荐</p>
-          </ion-avatar>
-        </ion-item>
-        <ion-item-options>
-          <ion-item-option @click="onEdit(record.postID)">
-            <ion-icon :icon="buildOutline"></ion-icon>
-          </ion-item-option>
-          <ion-item-option color="danger" @click="onDel(record.postID)">
-            <ion-icon :icon="trashOutline"></ion-icon>
-          </ion-item-option>
-        </ion-item-options>
-        </ion-item-sliding>
+      <div class="bw-vue-list">
+        <div class="list-content">
+          <ion-list>
+            <div v-for="(record,key) in dataList" :key="key" detail>
+              <ion-item-sliding>
+                <ion-item>
+                  <ion-label>
+                    <h3>{{ record.professionName }}</h3>
+                    <p>{{ record.companyName }}</p>
+                    <p>
+                      {{ dayjs(record.startTime).format("YYYY-MM-DD") }}至{{
+                        dayjs(record.endTime).format("YYYY-MM-DD")
+                      }}</p>
+                    <div class="multi-title">
+                      <p>
+                        招聘人数:{{ record.recruitCount == null ? "0" : record.recruitCount }}人
+                      </p>
+                      <p>
+                        已推荐人数:{{ record.recommendNum }}
+                      </p>
+                    </div>
+                  </ion-label>
+                  <ion-avatar @click="onRecommendJob(record);$event.preventDefault();$event.stopPropagation();"
+                              aria-hidden="true" class="container" slot="end">
+                    <ion-button size="small" fill="outline">推荐</ion-button>
+                  </ion-avatar>
+                </ion-item>
+                <ion-item-options>
+                  <ion-item-option @click="onEdit(record.postID)">
+                    <ion-icon :icon="buildOutline"></ion-icon>
+                  </ion-item-option>
+                  <ion-item-option color="danger" @click="onDel(record.postID)">
+                    <ion-icon :icon="trashOutline"></ion-icon>
+                  </ion-item-option>
+                </ion-item-options>
+              </ion-item-sliding>
+            </div>
+          </ion-list>
         </div>
-      </ion-list>
+      </div>
       <b-empty v-if="dataList.length<=0" :loading="loading"/>
       <ion-infinite-scroll threshold="100px" @ionInfinite="onScroll($event)">
         <ion-infinite-scroll-content
@@ -66,10 +77,10 @@
 import {computed, defineComponent, reactive, ref} from 'vue';
 import dayjs from "dayjs";
 import {useRoute, useRouter} from "vue-router";
-import {arrowBackOutline, addCircleOutline,buildOutline,trashOutline} from 'ionicons/icons';
+import {arrowBackOutline, addCircleOutline, buildOutline, trashOutline} from 'ionicons/icons';
 import {alertController, IonIcon, onIonViewDidEnter} from '@ionic/vue';
 import BEmpty from "@/components/empty.vue";
-import {getPostList,deletePostAndRecommendMgt} from '@/api/post/index'
+import {getPostList, deletePostAndRecommendMgt} from '@/api/post/index'
 
 export default defineComponent({
   name: 'PostList',
@@ -90,7 +101,6 @@ export default defineComponent({
       professionName: '',
     });
     const dataList = ref<any>([]);
-    const colors = ref(["secondary", "tertiary", "success", "warning"]);
 
     const loadData = async function () {
       loading.value = true;
@@ -119,18 +129,18 @@ export default defineComponent({
     }
 
     const onDetail = () => {
-      router.push({path: './detail', query: {reload: 1,id: null,status: 1}});
+      router.push({path: './detail', query: {reload: 1, id: null, status: 1}});
     }
 
     const onAdd = () => {
-      router.push({path: './edit', query: {reload: 1,id: null,status: 1}});
+      router.push({path: './edit', query: {reload: 1, id: null, status: 1}});
     }
 
-    const onEdit = (postID:string) => {
-      router.push({path: './edit', query: {reload: 1,id: postID,status: 2}});
+    const onEdit = (postID: string) => {
+      router.push({path: './edit', query: {reload: 1, id: postID, status: 2}});
     }
 
-    const onDel = async (postID: any) => {
+    const onDel = async (id: any) => {
       const alert = await alertController.create({
         header: '提示!',
         message: '是否确认删除?',
@@ -142,7 +152,7 @@ export default defineComponent({
           {
             text: '确认删除',
             handler: () => {
-              deletePostAndRecommendMgt(postID).then(result => {
+              deletePostAndRecommendMgt(id).then(result => {
                 if (result)
                   reload();
               });
@@ -154,8 +164,23 @@ export default defineComponent({
       await alert.present();
     }
 
-    const onRecommendJob = (item: any) =>{
-      router.push({path: './recommendJob', query: {reload: 1,professionID:item.professionID,professionName:item.professionName,postID:item.postID,companyName:item.companyName,type:0}});
+    const onRecommendJob = (item: any) => {
+      router.push({
+        path: './recommendJob',
+        query: {
+          reload: 1,
+          professionID: item.professionID,
+          professionName: item.professionName,
+          postID: item.postID,
+          companyName: item.companyName,
+          type: 0,
+          parentProfessionID: item.parentProfessionID,
+          cultureRank: item.cultureRank,
+          workYear: item.workYear,
+          minSalary: item.minSalary,
+          maxSalary: item.maxSalary
+        }
+      });
     }
 
     const onBack = () => {
@@ -163,7 +188,7 @@ export default defineComponent({
     }
 
     onIonViewDidEnter(() => {
-      if(route.query.reload)reload();
+      if (route.query.reload) reload();
     });
 
     return {
@@ -187,39 +212,8 @@ export default defineComponent({
       reload,
       dayjs,
     }
-  },created() {
+  }, created() {
     this.loadData();
   }
 });
-</script>
-
-<style lang="less">
-.custom{
-  --placeholder-color: gray;
-  --placeholder-opacity: 0.5;
-}
-
-.company-list-page {
-  .list-content {
-    margin: 0px 15px !important;
-    background-color: white !important;
-    border-radius: 0 !important;
-
-    ion-item {
-      margin-top: 10px;
-      font-size: 14px;
-      border: 1px solid rgb(242, 242, 245);
-
-      p {
-        font-size: 12px;
-      }
-    }
-  }
-}
-
-.container {
-  display: flex;
-  justify-content: center; /* 水平居中 */
-  align-items: center; /* 垂直居中 */
-}
-</style>
+</script>

+ 110 - 49
h5app/src/views/pages/post/recommendJob.vue

@@ -1,5 +1,5 @@
 <template>
-  <ion-page class="list-page company-list-page">
+  <ion-page class="list-page">
     <ion-header class="header-theme2">
       <ion-toolbar>
         <ion-buttons slot="start">
@@ -15,19 +15,41 @@
           <br/>
           <h2>{{ searchParams.companyName }}</h2>
         </ion-label>
+        <ion-button id="popover-checkbox" @click="popoverCheckboxIsOpen = true" slot="end"
+                    style="height: 33px;width: 90px;margin-left: 10px;--box-shadow: none;--border-radius: 14px;">求职人员筛选
+        </ion-button>
+        <ion-popover size="auto" trigger="popover-checkbox" :is-open="popoverCheckboxIsOpen" :backdrop-dismiss="false"
+                     :dismiss-on-select="false">
+          <ion-content>
+            <ion-list>
+              <ion-item v-for="(record,key) in recommendJobHuntWhereList" :key="key">
+                <ion-checkbox :detail="false" v-model="record.check" label-placement="end">{{ record.name }}
+                </ion-checkbox>
+              </ion-item>
+              <ion-item>
+                <ion-button @click="onRestRecommendWhere" slot="end" fill="clear" size="small">重置</ion-button>
+                <ion-button @click="onPopoverConfirm" slot="end" size="small">确定</ion-button>
+              </ion-item>
+            </ion-list>
+          </ion-content>
+        </ion-popover>
       </ion-item>
-      <ion-list class="list-content">
-        <ion-item v-for="(record,key) in dataList" detail :key="key">
-          <ion-label>
-            <h2>{{ record.userName }}</h2>
-            <p>应聘岗位:{{ record.professionName }}</p>
-            <p>电话:{{ record.userMobile }}</p>
-          </ion-label>
-          <ion-avatar aria-hidden="true" class="container" slot="end">
-            <ion-text style="text-align:right;" @click="onRecommend(record)">推荐</ion-text>
-          </ion-avatar>
-        </ion-item>
-      </ion-list>
+      <div class="bw-vue-list">
+        <div class="list-content">
+          <ion-list>
+            <ion-item v-for="(record,key) in dataList" :key="key">
+              <ion-label>
+                <h2>{{ record.userName }}</h2>
+                <p>应聘岗位:{{ record.professionName }}</p>
+                <p>电话:{{ record.userMobile }}</p>
+              </ion-label>
+              <ion-avatar aria-hidden="true" class="container" slot="end">
+                <ion-button size="small" @click="onRecommend(record)" fill="outline">推荐</ion-button>
+              </ion-avatar>
+            </ion-item>
+          </ion-list>
+        </div>
+      </div>
       <b-empty v-if="dataList.length<=0" :loading="loading"/>
       <ion-infinite-scroll threshold="100px" @ionInfinite="onScroll($event)">
         <ion-infinite-scroll-content
@@ -48,6 +70,7 @@ import {computed, defineComponent, reactive, ref, watch} from 'vue';
 import {arrowBackOutline, addCircleOutline} from 'ionicons/icons';
 import {alertController, IonIcon, onIonViewDidEnter} from '@ionic/vue';
 import {getRecommendJobList, addRecommend} from "@/api/recommendmgt";
+import {getSysDictionaryList} from "@/api/system/dictionary";
 
 export default defineComponent({
   name: 'RecommendJobList',
@@ -69,11 +92,32 @@ export default defineComponent({
       professionID: '',
       companyName: '',
       professionName: '',
-      type: 0
+      type: 0,
+      parentProfessionID: '',
+      cultureRank: null,
+      workYear: null,
+      minSalary: null,
+      maxSalary: null
     })
+    const searchParamsCache = reactive({
+      professionID: '',
+      parentProfessionID: '',
+      cultureRank: null,
+      workYear: null,
+      minSalary: null,
+      maxSalary: null
+    });
     const dataList = ref<any>([]);
     const addRecommendList = ref<any>([]);
-    const colors = ref(["secondary", "tertiary", "success", "warning"]);
+    const recommendJobHuntWhereList = ref<any>([]);
+    const popoverCheckboxIsOpen = ref<boolean>(false);
+
+    const getRecommendTypeList = () => {
+      getSysDictionaryList('RecommendJobHuntWhere').then((data) => {
+        recommendJobHuntWhereList.value = data;
+        recommendJobHuntWhereList.value[0].check = true;
+      });
+    };
 
     const loadData = async function () {
       loading.value = true;
@@ -89,6 +133,30 @@ export default defineComponent({
       loading.value = false;
     }
 
+    const onPopoverConfirm = () => {
+      const list = recommendJobHuntWhereList.value.filter((x: any) => x.check == true).map((x: any) => x.value);
+
+      searchParams.professionID = list.findIndex((x: any) => x == 1) >= 0 ? searchParamsCache.professionID : "";
+      searchParams.cultureRank = list.findIndex((x: any) => x == 2) >= 0 ? searchParamsCache.cultureRank : null;
+      searchParams.workYear = list.findIndex((x: any) => x == 3) >= 0 ? searchParamsCache.workYear : null;
+      if (list.findIndex((x: any) => x == 4) >= 0) {
+        searchParams.minSalary = searchParamsCache.minSalary;
+        searchParams.maxSalary = searchParamsCache.maxSalary;
+      } else {
+        searchParams.minSalary = null;
+        searchParams.maxSalary = null;
+      }
+      searchParams.parentProfessionID = list.findIndex((x: any) => x == 5) >= 0 ? searchParamsCache.parentProfessionID : "";
+
+      popoverCheckboxIsOpen.value = false;
+      reload();
+    }
+
+    const onRestRecommendWhere = () => {
+      recommendJobHuntWhereList.value.map((x: any) => x.check = false);
+      recommendJobHuntWhereList.value[0].check = true;
+    }
+
     const onScroll = (e: any) => {
       setTimeout(() => {
         e.target.complete();
@@ -155,8 +223,25 @@ export default defineComponent({
       searchParams.pageIndex = 1;
       loadData();
     }
+
+    const reloadSearchParams = () => {
+      searchParams.postID = route.query.postID as any;
+      searchParams.companyName = route.query.companyName as any;
+      searchParams.professionID = route.query.professionID as any;
+      searchParams.professionName = route.query.professionName as any;
+      searchParams.type = route.query.type as any;
+      searchParamsCache.professionID = route.query.professionID as any;
+      searchParamsCache.parentProfessionID = route.query.parentProfessionID as any;
+      searchParamsCache.cultureRank = route.query.cultureRank as any;
+      searchParamsCache.workYear = route.query.workYear as any;
+      searchParamsCache.workYear = route.query.workYear as any;
+      searchParamsCache.minSalary = route.query.minSalary as any;
+      searchParamsCache.maxSalary = route.query.maxSalary as any;
+    }
+
     onIonViewDidEnter(() => {
       reload();
+      reloadSearchParams();
     });
 
     return {
@@ -164,56 +249,32 @@ export default defineComponent({
       addCircleOutline,
       router,
       route,
-      colors,
       loading,
       pagination,
       searchParams,
       dataList,
+      recommendJobHuntWhereList,
+      popoverCheckboxIsOpen,
       onScroll,
       loadData,
       reload,
       onBack,
       onRecommend,
       onBatchRecommend,
+      getRecommendTypeList,
+      onPopoverConfirm,
+      onRestRecommendWhere,
     }
+  }, mounted() {
+    this.getRecommendTypeList()
   }
 });
 </script>
 
 <style lang="less">
-.custom {
-  --placeholder-color: gray;
-  //--placeholder-font-style: italic;
-  --placeholder-opacity: 1;
-}
-
-.company-list-page {
-  .list-content {
-    margin: 0px 15px !important;
-    background-color: white !important;
-    border-radius: 0 !important;
-
-    ion-item {
-      margin-top: 10px;
-      font-size: 14px;
-      border: 1px solid rgb(242, 242, 245);
-
-      p {
-        font-size: 12px;
-      }
-    }
-  }
-}
-
-.container {
-  display: flex;
-  justify-content: center; /* 水平居中 */
-  align-items: center; /* 垂直居中 */
-}
-
-.footer-ios ion-toolbar:first-of-type{
-  --border-width:0 !important;
-  --background:#ffffff !important;
+.footer-ios ion-toolbar:first-of-type {
+  --border-width: 0 !important;
+  --background: #ffffff !important;
 }
 
 </style>

+ 25 - 53
h5app/src/views/pages/recommendMgt/list.vue

@@ -1,5 +1,5 @@
 <template>
-  <ion-page class="list-page company-list-page">
+  <ion-page class="list-page">
     <ion-header class="header-theme2">
       <ion-toolbar>
         <ion-buttons slot="start">
@@ -18,25 +18,29 @@
                     @click="reload">搜索
         </ion-button>
       </ion-item>
-      <ion-list class="list-content">
-        <ion-item v-for="(record,key) in dataList" :key="key" detail @click="onDetail(record.recommendMgtID)">
-          <ion-label>
-            <h2>{{ record.name }}</h2>
-            <ion-label style="display: flex;justify-content: space-between;">
-              <p>求职岗位:{{ record.qzProfessionName }}</p>
-              <p>{{ record.entryStateName }}</p>
-            </ion-label>
-            <p>招聘企业:{{ record.companyName }}</p>
-            <ion-label style="display: flex;justify-content: space-between;">
-              <p>联系电话:{{ record.userMobile }}</p>
-              <p>企业电话:{{ record.companyMobile }}</p>
-            </ion-label>
-            <p>
-              推送时间:{{ dayjs(record.createTime).format('YYYY-MM-DD') }}
-            </p>
-          </ion-label>
-        </ion-item>
-      </ion-list>
+      <div class="bw-vue-list">
+        <div class="list-content">
+          <ion-list>
+            <ion-item v-for="(record,key) in dataList" :key="key" detail @click="onDetail(record.recommendMgtID)">
+              <ion-label>
+                <h2>{{ record.name }}</h2>
+                <div class="multi-title">
+                  <p>求职岗位:{{ record.qzProfessionName }}</p>
+                  <p>{{ record.entryStateName }}</p>
+                </div>
+                <p>招聘企业:{{ record.companyName }}</p>
+                <div class="multi-title">
+                  <p>联系电话:{{ record.userMobile }}</p>
+                  <p>企业电话:{{ record.companyMobile }}</p>
+                </div>
+                <p>
+                  推送时间:{{ dayjs(record.createTime).format('YYYY-MM-DD') }}
+                </p>
+              </ion-label>
+            </ion-item>
+          </ion-list>
+        </div>
+      </div>
       <b-empty v-if="dataList.length<=0" :loading="loading"/>
       <ion-infinite-scroll threshold="100px" @ionInfinite="onScroll($event)">
         <ion-infinite-scroll-content
@@ -104,7 +108,7 @@ export default defineComponent({
     }
 
     const onDetail = (recommendMgtID: any) => {
-      router.push({path: './detail', query: {reload: 1, id: recommendMgtID,status: 1}});
+      router.push({path: './detail', query: {reload: 1, id: recommendMgtID, status: 1}});
     }
 
     const onBack = () => {
@@ -135,35 +139,3 @@ export default defineComponent({
   }
 });
 </script>
-
-<style lang="less">
-.custom {
-  --placeholder-color: gray;
-  //--placeholder-font-style: italic;
-  --placeholder-opacity: 1;
-}
-
-.company-list-page {
-  .list-content {
-    margin: 0px 15px !important;
-    background-color: white !important;
-    border-radius: 0 !important;
-
-    ion-item {
-      margin-top: 10px;
-      font-size: 14px;
-      border: 1px solid rgb(242, 242, 245);
-
-      p {
-        font-size: 12px;
-      }
-    }
-  }
-}
-
-.container {
-  display: flex;
-  justify-content: center; /* 水平居中 */
-  align-items: center; /* 垂直居中 */
-}
-</style>

+ 10 - 0
src/main/java/com/hz/employmentsite/controller/jobUserManager/JobHuntController.java

@@ -2,6 +2,7 @@ package com.hz.employmentsite.controller.jobUserManager;
 
 import com.github.pagehelper.PageInfo;
 import com.hz.employmentsite.filter.exception.BaseErrorEnum;
+import com.hz.employmentsite.filter.exception.BaseException;
 import com.hz.employmentsite.filter.exception.BaseResponse;
 import com.hz.employmentsite.filter.exception.RespGenerstor;
 import com.hz.employmentsite.services.service.AccountService;
@@ -68,6 +69,15 @@ public class JobHuntController {
         return RespGenerstor.success(jobhuntService.delete(idList));
     }
 
+    @ResponseBody
+    @PostMapping("/deleteJobHuntAndRecommendMgt")
+    public BaseResponse<Integer> deleteJobHuntAndRecommendMgt(String id) {
+        Integer result = jobhuntService.deleteJobHuntAndRecommendMgt(id);
+        if (result <= 0)
+            throw new BaseException(BaseErrorEnum.DELETE_NOT_DATA_ERROR);
+        return RespGenerstor.success(1);
+    }
+
     @PostMapping("save")
     public BaseResponse<Integer> save(@RequestBody JobHuntVo data) {
         return RespGenerstor.success(jobhuntService.save(data,accountService.getLoginUserID()));

+ 1 - 2
src/main/java/com/hz/employmentsite/services/impl/companyService/PostServiceImpl.java

@@ -197,8 +197,7 @@ public class PostServiceImpl implements PostService {
             PcRecommendMgtExample.Criteria cro = exp.or();
             cro.andPostIDEqualTo(id);
             pcRecommendMgtMapper.deleteByExample(exp);
-            pcPostMapper.deleteByPrimaryKey(id);
-            return 1;
+            return pcPostMapper.deleteByPrimaryKey(id);
         }catch (Exception e){
             e.printStackTrace();
             return 0;

+ 17 - 0
src/main/java/com/hz/employmentsite/services/impl/jobUserManager/JobHuntServiceImpl.java

@@ -6,6 +6,7 @@ import com.hz.employmentsite.filter.exception.BaseException;
 import com.hz.employmentsite.mapper.PcJobhuntMapper;
 import com.hz.employmentsite.mapper.PcJobuserMapper;
 import com.hz.employmentsite.mapper.PcProfessionMapper;
+import com.hz.employmentsite.mapper.PcRecommendMgtMapper;
 import com.hz.employmentsite.mapper.cquery.JobHuntCQuery;
 import com.hz.employmentsite.model.*;
 import com.hz.employmentsite.services.service.jobUserManager.JobHuntService;
@@ -36,6 +37,9 @@ public class JobHuntServiceImpl implements JobHuntService {
     @Autowired
     private PcProfessionMapper pcProfessionMapper;
 
+    @Autowired
+    private PcRecommendMgtMapper pcRecommendMgtMapper;
+
     @Autowired
     private DictionaryService dictionaryService;
 
@@ -75,6 +79,19 @@ public class JobHuntServiceImpl implements JobHuntService {
         return pcJobhuntMapper.deleteByExample(contactExample);
     }
 
+    @Override
+    public Integer deleteJobHuntAndRecommendMgt(String id){
+        try{
+            PcRecommendMgtExample emp = new PcRecommendMgtExample();
+            emp.or().andJobHuntIDEqualTo(id);
+            pcRecommendMgtMapper.deleteByExample(emp);
+            return pcJobhuntMapper.deleteByPrimaryKey(id);
+        }catch (Exception e){
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
     @Override
     public Integer save(JobHuntVo data, String userId) {
         int result = 0;

+ 2 - 0
src/main/java/com/hz/employmentsite/services/service/jobUserManager/JobHuntService.java

@@ -15,6 +15,8 @@ public interface JobHuntService {
 
     Integer delete(List<String> idList);
 
+    Integer deleteJobHuntAndRecommendMgt(String id);
+
     Integer save(JobHuntVo data, String userId);
 
     List<JobHuntVo> importJobHunt(List<JobHuntVo> dataList, String userID);

+ 6 - 0
src/main/java/com/hz/employmentsite/vo/jobUserManager/JobUserVo.java

@@ -29,6 +29,8 @@ public class JobUserVo {
 
     private Integer politicsStatusID;
 
+    private String politicsStatusName;
+
     private String birthPlace;
 
     private Date birthDay;
@@ -37,10 +39,14 @@ public class JobUserVo {
 
     private Integer familyNatureID;
 
+    private String familyNatureName;
+
     private Integer cultureRank;
 
     private Integer healthID;
 
+    private String healthName;
+
     private Integer bloodTypeID;
 
     private String height;

+ 2 - 0
src/main/java/com/hz/employmentsite/vo/jobUserManager/RecommendCompanyPostVo.java

@@ -13,4 +13,6 @@ public class RecommendCompanyPostVo {
     public String professionID;
     public String maxSalary;
     public String minSalary;
+    public String cultureRankName;
+    public String workYearName;
 }

+ 21 - 8
src/main/resources/mapping/cquery/JobUserCQuery.xml

@@ -2,16 +2,29 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 <mapper namespace="com.hz.employmentsite.mapper.cquery.JobUserCQuery">
     <select id="selectJobUserList" resultType="com.hz.employmentsite.vo.jobUserManager.JobUserVo">
-        select  jobuser.* ,gender.name as GenderName,culture.name as CultureName,site.SiteName,jobstatus.name as JobStatusName,keytype.name as KeyTypeName,
-        (select count(*) from pc_recommend recommend where jobuser.JobUserID = recommend.JobuserID and isRead = 1)as RecommendedCount
-        ,case when jobuser.IdentityNumber is not null and jobuser.IdentityNumber <![CDATA[ <> ]]>'' then TIMESTAMPDIFF(YEAR,STR_TO_DATE(SUBSTRING(jobuser.IdentityNumber, 7, 8),'%Y%m%d'),CURRENT_DATE())
-         else null end as age
+        select jobuser.* ,gender.name as GenderName,culture.name as CultureName,site.SiteName,jobstatus.name as
+        JobStatusName,keytype.name as KeyTypeName,sys_politics.name as politicsStatusName,sys_health.name as healthName,
+        sys_family.name as familyNatureName,
+        (select count(*) from pc_recommend recommend where jobuser.JobUserID = recommend.JobuserID and isRead = 1)as
+        RecommendedCount
+        ,case when jobuser.IdentityNumber is not null and jobuser.IdentityNumber <![CDATA[ <> ]]>'' then
+        TIMESTAMPDIFF(YEAR,STR_TO_DATE(SUBSTRING(jobuser.IdentityNumber, 7, 8),'%Y%m%d'),CURRENT_DATE())
+        else null end as age
         from pc_jobuser jobuser
         left join pc_site site on site.SiteID = jobuser.SiteID
-        left join sys_dictionary_item culture on jobuser.CultureRank = culture.value and culture.DictionaryCode='CultureLevel'
-        left join sys_dictionary_item gender  on jobuser.Sex = gender.value and gender.DictionaryCode='Gender'
-        left join sys_dictionary_item jobstatus on jobuser.JobStatusID = jobstatus.value and jobstatus.DictionaryCode='JobStatus'
-        left join sys_dictionary_item keytype on jobuser.KeyPersonTypeID = keytype.value and keytype.DictionaryCode='KeyPersonType'
+        left join sys_dictionary_item culture on jobuser.CultureRank = culture.value and
+        culture.DictionaryCode='CultureLevel'
+        left join sys_dictionary_item gender on jobuser.Sex = gender.value and gender.DictionaryCode='Gender'
+        left join sys_dictionary_item jobstatus on jobuser.JobStatusID = jobstatus.value and
+        jobstatus.DictionaryCode='JobStatus'
+        left join sys_dictionary_item keytype on jobuser.KeyPersonTypeID = keytype.value and
+        keytype.DictionaryCode='KeyPersonType'
+        left join (select * from sys_dictionary_item where DictionaryCode ='PoliticsStatus') sys_politics on
+        jobuser.PoliticsStatusID = sys_politics.Value
+        left join (select * from sys_dictionary_item where DictionaryCode ='Health') sys_health on
+        jobuser.healthID = sys_health.Value
+        left join (select * from sys_dictionary_item where DictionaryCode ='FamilyNature') sys_family on
+        jobuser.familyNatureID = sys_family.Value
         where 1=1
         <if test="jobUserIDList != '' and jobUserIDList != null">
             and jobuser.jobuserID in (${jobUserIDList})

+ 30 - 21
src/main/resources/mapping/cquery/RecommendMgtCQuery.xml

@@ -11,9 +11,9 @@
         ,e.jobuserId,c.companyId
         ,d.workYear
         from pc_recommend_mgt a
-        left join pc_post b on a.PostID = b.PostID
+        inner join pc_post b on a.PostID = b.PostID
         left join pc_company c on b.CompanyID = c.CompanyID
-        left join pc_jobhunt d on a.JobHuntID = d.JobHuntID
+        inner join pc_jobhunt d on a.JobHuntID = d.JobHuntID
         left join pc_jobuser e on d.JobUserID = e.JobuserID
         left join pc_profession f on b.ProfessionID = f.ProfessionID
         left join pc_profession f2 on d.ProfessionID = f2.ProfessionID
@@ -61,11 +61,14 @@
             resultType="com.hz.employmentsite.vo.jobUserManager.RecommendCompanyPostVo">
         select a.postid,b.companyname,c.professionname,a.recruitcount,a.starttime,a.endtime,b.companyAddress,
         case when d.recommendmgtid is null then '未推荐' else '已推荐' end as isRecommend,
-        d.recommendMgtID,a.professionid,c.professionname,a.maxsalary,a.minsalary
+        d.recommendMgtID,a.professionid,a.maxsalary,a.minsalary,
+        dic1.`name` as culturerankname, dic2.`name` as workyearname
         from pc_post a
         left join pc_company b on a.CompanyID = b.CompanyID
         left join pc_profession c on a.ProfessionID = c.ProfessionID
         left join pc_recommend_mgt d on a.PostID = d.PostID and d.JobHuntID = #{jobHuntID}
+        left join (select `Value`,`Name` from sys_dictionary_item where DictionaryCode='CultureLevel') dic1 on a.CultureRank = dic1.`Value`
+        left join (select `Value`,`Name` from sys_dictionary_item where DictionaryCode='WorkYearType') dic2 on a.WorkYear = dic2.`Value`
         <where>
             <if test="type!=null and type==0">
                 and d.RecommendMgtID is null
@@ -102,12 +105,18 @@
                     <otherwise>and 1=1</otherwise>
                 </choose>
             </if>
-            <if test="minSalary!=null and minSalary!=''">
-                and a.MinSalary <![CDATA[<=]]> #{minSalary}
-            </if>
-            <if test="maxSalary!=null and maxSalary!=''">
-                and a.MaxSalary <![CDATA[>=]]> #{maxSalary}
-            </if>
+            <choose>
+                <when test="minSalary!=null and maxSalary!=null">
+                    and a.MinSalary <![CDATA[<=]]> #{maxSalary} and a.MaxSalary <![CDATA[>=]]> #{minSalary}
+                </when>
+                <when test="minSalary!=null and minSalary!=''">
+                    and a.MinSalary <![CDATA[>=]]> #{minSalary}
+                </when>
+                <when test="maxSalary!=null and maxSalary!=''">
+                    and a.MaxSalary <![CDATA[<=]]> #{maxSalary}
+                </when>
+                <otherwise>and 1=1</otherwise>
+            </choose>
         </where>
         order by a.CreateTime desc
     </select>
@@ -154,18 +163,18 @@
             <if test="workYear!=null and workYear!=''">
                 and a.WorkYear <![CDATA[<=]]> #{workYear}
             </if>
-        <choose>
-            <when test="minSalary!=null and maxSalary!=null">
-                and a.MinSalary <![CDATA[<=]]> #{maxSalary} and a.MaxSalary <![CDATA[>=]]> #{minSalary}
-            </when>
-            <when test="minSalary!=null and minSalary!=''">
-                and a.MinSalary <![CDATA[>=]]> #{minSalary}
-            </when>
-            <when test="maxSalary!=null and maxSalary!=''">
-                and a.MaxSalary <![CDATA[<=]]> #{maxSalary}
-            </when>
-            <otherwise>and 1=1</otherwise>
-        </choose>
+            <choose>
+                <when test="minSalary!=null and maxSalary!=null">
+                    and a.MinSalary <![CDATA[<=]]> #{maxSalary} and a.MaxSalary <![CDATA[>=]]> #{minSalary}
+                </when>
+                <when test="minSalary!=null and minSalary!=''">
+                    and a.MinSalary <![CDATA[>=]]> #{minSalary}
+                </when>
+                <when test="maxSalary!=null and maxSalary!=''">
+                    and a.MaxSalary <![CDATA[<=]]> #{maxSalary}
+                </when>
+                <otherwise>and 1=1</otherwise>
+            </choose>
         </where>
         order by a.CreateTime desc
     </select>

BIN
vue/src/assets/images/jl-avt.png


+ 4 - 2
vue/src/plugins/antd.ts

@@ -19,7 +19,8 @@ import {
   Switch,
   Space, Cascader,
   Tree,
-  Transfer,Image,Progress,List,Avatar,Badge,Spin,Pagination
+  Transfer, Image, Progress, List, Avatar, Badge, Spin, Pagination,
+  Timeline
 } from 'ant-design-vue';
 import type { App } from 'vue';
 //导入组件库
@@ -68,5 +69,6 @@ export function setupAntd(app: App<Element>) {
     .use(Transfer)
     .use(Cascader)
     .use(Image)
-    .use(Tree).use(Progress).use(List).use(Avatar).use(Badge).use(Spin).use(Pagination);
+    .use(Tree).use(Progress).use(List).use(Avatar).use(Badge).use(Spin).use(Pagination)
+    .use(Timeline);
 }

+ 1 - 0
vue/src/router/asyncModules/jobUserManager.ts

@@ -2,6 +2,7 @@ export default {
   'views/jobusermgr/jobseeker/index': () => import('@/views/jobUserManager/jobuser/index.vue'),
   'views/jobusermgr/jobseeker/add': () => import('@/views/jobUserManager/jobuser/edit.vue'),
   'views/jobusermgr/jobseeker/edit': () => import('@/views/jobUserManager/jobuser/edit.vue'),
+  'views/jobusermgr/jobseeker/vitae': () => import('@/views/jobUserManager/jobuser/vitae.vue'),
   'views/jobusermgr/jobhunt/index': () => import('@/views/jobUserManager/jobhunt/index.vue'),
   'views/jobusermgr/jobhunt/add': () => import('@/views/jobUserManager/jobhunt/edit.vue'),
   'views/jobusermgr/jobhunt/edit': () => import('@/views/jobUserManager/jobhunt/edit.vue'),

+ 35 - 7
vue/src/views/jobUserManager/jobhunt/recommend.vue

@@ -1,6 +1,6 @@
 <template>
   <a-modal
-    :width="1100"
+    :width="1400"
     v-model:visible="visible"
     :title="title"
     :confirm-loading="confirmLoading"
@@ -165,16 +165,25 @@ export default defineComponent({
         customRender: (item) =>
           `${searchParams.pageSize * (searchParams.pageIndex - 1) + item.index + 1}`,
       },
-      {title: '企业名称', dataIndex: 'companyName', key: 'companyName', width: 100, align: "center",},
-      {title: '招聘岗位', dataIndex: 'professionName', key: 'professionName', width: 150, align: "center",},
-      {title: '招聘人数', dataIndex: 'recruitCount', key: 'recruitCount', width: 150, align: "center",},
-      {title: '工作地点', dataIndex: 'companyAddress', key: 'companyAddress', width: 150, align: "center",},
+      {title: '企业名称', dataIndex: 'companyName', key: 'companyName', align: "center",},
+      {title: '招聘岗位', dataIndex: 'professionName', key: 'professionName', align: "center",},
+      {title: '要求学历', dataIndex: 'cultureRankName', key: 'cultureRankName', align: "center",},
+      {title: '工作年限', dataIndex: 'workYearName', key: 'workYearName', align: "center",},
+      {title: '招聘人数', dataIndex: 'recruitCount', key: 'recruitCount', align: "center",},
       {
-        title: '工作开始时间', dataIndex: 'startTime', key: 'startTime', width: 100, align: "center",
+        title: '薪资要求', dataIndex: 'salary', key: 'salary', align: "center",
+        customRender: (item) => {
+          const salary = showSalary(item.record.minSalary, item.record.maxSalary);
+          return salary;
+        }
+      },
+      {title: '工作地点', dataIndex: 'companyAddress', key: 'companyAddress', align: "center",},
+      {
+        title: '工作开始时间', dataIndex: 'startTime', key: 'startTime', align: "center",
         customRender: ({record}) => record.startTime == null ? "" : dayjs(record.startTime).format('YYYY-MM-DD'),
       },
       {
-        title: '工作结束时间', dataIndex: 'endTime', key: 'endTime', width: 100, align: "center",
+        title: '工作结束时间', dataIndex: 'endTime', key: 'endTime',align: "center",
         customRender: ({record}) => record.endTime == null ? "" : dayjs(record.endTime).format('YYYY-MM-DD'),
       },
       {title: '操作', key: 'operation', width: 60, align: 'center'},
@@ -228,6 +237,7 @@ export default defineComponent({
         indeterminate: false,
       });
     };
+
     watch(
       () => state.checkRecommendPostWhereList,
       val => {
@@ -236,6 +246,22 @@ export default defineComponent({
       },
     );
 
+    const showSalary = (minSalary: any, maxSalary: any) => {
+      if (minSalary != null) {
+        if (maxSalary != null) {
+          return minSalary.toString() + "-" + maxSalary.toString();
+        } else {
+          return "≥" + minSalary.toString();
+        }
+      } else {
+        if (maxSalary != null) {
+          return "≤" + maxSalary.toString();
+        } else {
+          return "";
+        }
+      }
+    }
+
     const show = (professionID: any, professionName: any, jobHuntID: any, jobUserName: any, type: any,
                   parentProfessionID: any, cultureRank: any, workYear: any, minSalary: any, maxSalary: any,
                   titleName: string) => {
@@ -245,6 +271,7 @@ export default defineComponent({
       searchParams.professionID = professionID;
       searchParams.professionName = professionName;
       searchParams.type = type;
+      state.checkRecommendPostWhereList = [1];
       state.professionID = professionID;
       state.parentProfessionID = parentProfessionID;
       state.cultureRank = cultureRank;
@@ -320,6 +347,7 @@ export default defineComponent({
       recommendPostWhereList,
       show,
       onSearch,
+      showSalary,
       onCheckAllChange,
       onRecommend,
       onBatchRecommend,

+ 10 - 5
vue/src/views/jobUserManager/jobuser/index.vue

@@ -123,6 +123,7 @@
         <template #bodyCell="{ column, text, record }">
           <template v-if="column.key === 'operation'">
             <div class="table-operation">
+              <a-button type="link" size="small" functioncode="T01030106" @click='onVitae(record)'>个人简历</a-button>
               <a-button type="link" size="small" functioncode="T01030103" @click='onEdit(record)'>编辑</a-button>
               <a-button type="link" size="small" functioncode="T01030104" @click="onDel(record)">删除</a-button>
             </div>
@@ -134,13 +135,13 @@
 </template>
 
 <script lang="ts">
-import {reactive, ref, computed, defineComponent, createVNode} from 'vue';
-import type {FormInstance, TableColumnsType, TableProps, SelectProps} from 'ant-design-vue';
-import {getList, del} from '@/api/jobUserManager/jobuser';
+import {computed, createVNode, defineComponent, reactive, ref} from 'vue';
+import type {FormInstance, SelectProps, TableColumnsType, TableProps} from 'ant-design-vue';
+import {message, Modal} from "ant-design-vue";
+import {del, getList} from '@/api/jobUserManager/jobuser';
 import {getSysDictionaryList} from '@/api/system/dictionary';
 import {getPaginationTotalTitle} from '@/utils/common';
 import {useTabsViewStore} from "@/store/modules/tabsView";
-import {message, Modal} from "ant-design-vue";
 import {DownOutlined, ExclamationCircleOutlined, UpOutlined} from "@ant-design/icons-vue";
 import BExportExcel from "@/components/basic/excel/exportExcel/exportExcel.vue";
 import BImportExcel from "@/components/basic/excel/importExcel/importExcel.vue";
@@ -193,7 +194,7 @@ export default defineComponent({
       {title: '地址', dataIndex: 'address', key: 'address',align: "center"},
       {title: '就业状态', dataIndex: 'jobStatusName', key: 'jobStatusName',align: "center"},
       {title: '重点人员类别', dataIndex: 'keyTypeName', key: 'keyTypeName',align: "center"},
-      {title: '操作', key: 'operation', width: 100, align: 'center'},
+      {title: '操作', key: 'operation', width: 170, align: 'center'},
     ];
     const pagination = computed(() => ({
       total: formState.total,
@@ -293,6 +294,9 @@ export default defineComponent({
     const onEdit = (item: any) => {
       tabsViewStore.addTabByPath('/jobusermgr/jobseeker/edit', {id: item.jobUserID});
     };
+    const onVitae = (item: any) => {
+      tabsViewStore.addTabByPath('/jobusermgr/jobseeker/vitae', {id: item.jobUserID});
+    };
 
     const onDel = (item: any) => {
       if (item) {
@@ -347,6 +351,7 @@ export default defineComponent({
       getEducationList,
       getEmphasisTypeList,
       calculateAge,
+      onVitae,
       expand
     };
   },

+ 276 - 0
vue/src/views/jobUserManager/jobuser/vitae.vue

@@ -0,0 +1,276 @@
+<template>
+  <div class="card-search">
+    <div class="jl-content">
+      <!-- 头像等信息 -->
+      <div class="avt-content">
+        <!--头像 -->
+        <div class="avt-image">
+          <a-avatar :size="72" :src="avtImg"></a-avatar>
+        </div>
+        <!-- 姓名 -->
+        <h1>{{ jobUserInfo.name }}</h1>
+        <!-- 性别,年龄,民族 -->
+        <div class="age-info">
+          <span>
+            <man-outlined v-if="jobUserInfo.genderName === '男'"/>
+            <woman-outlined v-if="jobUserInfo.genderName === '女'"/>
+            {{ jobUserInfo.genderName }}
+          </span>
+          <span>
+            {{ jobUserInfo.age }}岁
+          </span>
+          <span>
+            {{ jobUserInfo.nation }}
+          </span>
+        </div>
+        <!-- 政治面貌,学历,手机 -->
+        <div class="politics-info">
+          <span class="label-span">
+            政治面貌:
+          </span>
+          <span>
+            {{ jobUserInfo.politicsStatusName }}
+          </span>
+          <span class="label-span">
+            学历:
+          </span>
+          <span>
+            {{ jobUserInfo.cultureName }}
+          </span>
+          <span class="label-span">
+            手机:
+          </span>
+          <span>
+            {{ jobUserInfo.userMobile }}
+          </span>
+        </div>
+      </div>
+      <!-- 基本信息与学历,工作经历 -->
+      <div class="info-content">
+        <a-divider orientation="left">基本信息</a-divider>
+        <a-descriptions :column="2" bordered style="margin-left: 25px;">
+          <a-descriptions-item label="出生地">{{ jobUserInfo.birthPlace }}</a-descriptions-item>
+          <a-descriptions-item label="身份证号">{{ jobUserInfo.identityNumber }}</a-descriptions-item>
+          <a-descriptions-item label="重点人员类别">{{ jobUserInfo.keyTypeName }}</a-descriptions-item>
+          <a-descriptions-item label="健康状况">{{ jobUserInfo.healthName }}</a-descriptions-item>
+          <a-descriptions-item label="就业状态">{{ jobUserInfo.jobStatusName }}</a-descriptions-item>
+          <a-descriptions-item label="户口性质">{{ jobUserInfo.familyNatureName }}</a-descriptions-item>
+          <a-descriptions-item :span="2" label="住址">{{ jobUserInfo.familyAddress }}</a-descriptions-item>
+          <a-descriptions-item :span="2" label="兴趣爱好">{{ jobUserInfo.hobby }}</a-descriptions-item>
+          <a-descriptions-item :span="2" label="专业技术特长">{{ jobUserInfo.personalSkills }}</a-descriptions-item>
+        </a-descriptions>
+        <a-divider orientation="left">教育经历</a-divider>
+        <a-table :columns="educationColumns" :data-source="educationData" :pagination="false" bordered
+                 style="margin-left: 11px;">
+          <template #bodyCell="{ column, index, record}">
+            <template v-if="column.key === 'schoolTime'">
+              <div>
+                {{
+                  dayjs(record.schoolTime).format('YYYY-MM-DD')
+                }}
+              </div>
+            </template>
+            <template v-if="column.key === 'overTime'">
+              <div>
+                {{
+                  dayjs(record.overTime).format('YYYY-MM-DD')
+                }}
+              </div>
+            </template>
+          </template>
+        </a-table>
+        <a-divider orientation="left">工作经历</a-divider>
+        <a-timeline style="margin-left: 25px;">
+          <a-timeline-item v-for="(item, key) in experienceData" :key="key" position="left">
+            <p>{{ dayjs(item.startTime).format('YYYY-MM-DD') }}至{{ dayjs(item.endTime).format('YYYY-MM-DD') }}</p>
+            <h1>{{ item.workAddress }}</h1>
+            <h1>{{ item.duties }}</h1>
+          </a-timeline-item>
+        </a-timeline>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {onMounted, reactive, ref} from "vue";
+import {getDataById, getEducationList, getExperienceList} from "@/api/jobUserManager/jobuser";
+import avtImg from "@/assets/images/jl-avt.png"
+import {ManOutlined, WomanOutlined} from '@ant-design/icons-vue';
+import type {TableColumnsType} from "ant-design-vue";
+import dayjs from "dayjs";
+
+// 求职人员信息
+const jobUserInfo = reactive({
+  name: "",
+  genderName: "",
+  age: null,
+  nation: "",
+  politicsStatusName: "",
+  cultureName: "",
+  userMobile: "",
+  birthPlace: "",
+  identityNumber: "",
+  keyTypeName: "",
+  healthName: "",
+  jobStatusName: "",
+  familyNatureName: "",
+  familyAddress: "",
+  hobby: "",
+  personalSkills: ""
+})
+// 受教育经历
+const educationData = ref<Array<any>>([]);
+// 受教育经历表格定义
+const educationColumns: TableColumnsType = [
+  {
+    title: '序号',
+    align: "center",
+    key: 'educationID',
+    width: 120,
+    customRender: item => `${searchParams.pageSize * (searchParams.pageIndex - 1) + item.index + 1}`
+  },
+  {
+    title: '学校名',
+    dataIndex: 'schoolName',
+    key: 'schoolName',
+    align: "center",
+    width: 120
+  },
+  {
+    title: '文化程度',
+    dataIndex: 'cultureRank',
+    key: 'cultureRank',
+    align: "center",
+    width: 120
+  },
+  {
+    title: '就读时间',
+    dataIndex: 'schoolTime',
+    key: 'schoolTime',
+    align: "center",
+    width: 120
+  },
+  {
+    title: '毕业时间',
+    dataIndex: 'overTime',
+    key: 'overTime',
+    align: "center",
+    width: 120
+  },
+  {
+    title: '专业',
+    dataIndex: 'major',
+    key: 'major',
+    align: "center",
+    width: 120
+  },
+];
+const searchParams = reactive({
+  pageIndex: 1,
+  pageSize: 99
+});
+// 工作经验数据
+const experienceData = ref<Array<any>>([]);
+
+
+// 加载求职人员数据
+const loadData = (id: any) => {
+  getDataById(id).then(data => {
+    Object.keys(jobUserInfo).forEach(key => {
+      jobUserInfo[key] = data[key];
+    })
+  });
+};
+
+// 加载教育经历
+const loadEducation = (id: any) => {
+  getEducationList(id).then(data => {
+    if (data) {
+      educationData.value = data;
+    }
+  });
+}
+
+// 加载工作经历
+const loadExperienceData = (id: any) => {
+  getExperienceList(id).then(data => {
+    if (data) {
+      data.sort((a, b) => {
+        // 将 startTime 字段转换为日期对象进行比较
+        const startTimeA = new Date(a.startTime);
+        const startTimeB = new Date(b.startTime);
+
+        return startTimeB - startTimeA;
+      })
+      experienceData.value = data;
+    }
+  })
+}
+
+// 页面初始化
+onMounted(() => {
+  const id = history.state.params?.id;
+  loadData(id);
+  loadEducation(id);
+  loadExperienceData(id)
+})
+</script>
+
+<style lang="less" scoped>
+.card-search {
+
+  .jl-content {
+    min-height: calc(100vh - 240px);
+    width: 100%;
+    display: flex;
+
+    .avt-content {
+      width: 20%;
+      background-color: #e7e7e7;
+      padding: 10px;
+
+      .avt-image {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: center;
+      }
+
+      .age-info {
+        width: 100%;
+        display: flex;
+        justify-content: space-between;
+        margin-top: 15px;
+        padding: 0 20%;
+      }
+
+      .politics-info {
+        margin-top: 25px;
+        display: grid;
+        row-gap: 22px;
+        grid-template-columns: repeat(2, minmax(0, 1fr));
+
+        .label-span {
+          text-align: right;
+        }
+      }
+
+      h1 {
+        margin-top: 1rem;
+        text-align: center;
+        font-size: 20px;
+        font-weight: 700;
+      }
+
+    }
+
+    .info-content {
+      width: 80%;
+      height: 100%;
+      margin-left: 10px;
+    }
+  }
+}
+
+
+</style>