Jelajahi Sumber

Merge branch 'recruit-enterprise' of https://git.citupro.com/zhengnaiwen_citu/menduner-uniapp into recruit-enterprise

Xiao_123 2 bulan lalu
induk
melakukan
2f8df65526
3 mengubah file dengan 177 tambahan dan 79 penghapusan
  1. 21 59
      components/PositionList/index.vue
  2. 7 1
      pages/index/my.vue
  3. 149 19
      pages/index/position.vue

+ 21 - 59
components/PositionList/index.vue

@@ -1,17 +1,5 @@
 <template>
   <view class="ss-m-x-20">
-    <!-- 招聘会 -->
-    <view v-if="props.showJobFairEntrance" class="ss-p-t-20" style="position: relative" @click="handleToJobFair">
-      <image
-        src="https://minio.menduner.com/dev/menduner/miniProgram/Grand-Mercure.jpg"
-        style="width: 100%; height: 100px; border-radius: 8px"
-      ></image>
-      <view
-        style="position: absolute; top: 20rpx; width: 100%; text-align: center; height: 100px; line-height: 100px; font-size: 46px; color: #fff; font-weight: bold;"
-      >
-        招 聘 会
-      </view>
-    </view>
     <!-- 岗位列表 -->
     <view v-if="list.length > 0" class="ss-p-b-30 ss-p-t-20">
       <view v-for="(item, index) in list" :key="index" class="mList" :class="{ 'disable': !jobFairId && item.job?.status === '1'}" @click="toDetail(item)">
@@ -28,18 +16,20 @@
           </view>
           <!-- 薪酬、工作地、学历、工作经验 -->
           <view class="d-flex align-center justify-space-between">
-            <view class="font-size-13 ellipsis" :style="{'max-width': !item.job?.payFrom && !item.job?.payTo ? '78%' : '56%'}">
+            <view class="font-size-13 ellipsis" style="flex: 1;">
               <span class="tag-gap" style="color: #808080;">
                 <span>{{item.job?.area?.str ?? '全国' }}</span>
                 <span class="divider-mx" v-if="item.job?.eduName">|</span>
                 <span>{{item.job?.eduName }}</span>
                 <span class="divider-mx" v-if="item.job?.expName">|</span>
                 <span>{{item.job?.expName }}</span>
+                <span class="divider-mx">|</span>
+                <span>{{!item.job?.payFrom && !item.job?.payTo ? '面议' : `${item.job?.payFrom}-${item.job?.payTo}${item.job?.payName ? '/' + item.job?.payName : ''}` }}</span>
               </span>
             </view>
-            <view>
-              <span v-if="!item.job?.payFrom && !item.job?.payTo" class="salary-text">面议</span>
-              <span v-else class="salary-text">{{ item.job?.payFrom }}-{{ item.job?.payTo }}{{ item.job?.payName ? '/' + item.job?.payName : '' }}</span>
+            <view class="d-flex flex-column align-center justify-center resumeCount">
+              <view style="font-size: 14px;">{{ item.job?.payFrom || 0 }}</view>
+              <view>已投递简历</view>
             </view>
           </view>
           <!-- 岗位tag  -->
@@ -64,18 +54,13 @@
               custom-style="background-color: #e2f0ef; color:#00B760; border-color:#e2f0ef;"
             />
           </view>
-          <view v-if="props.showUpdateTime" class="font-size-13 color-999 ss-m-t-10" :style="`text-align: ${props.updateTimeAlign};`">更新时间:{{ timesTampChange(item?.job?.refreshTime || item.job?.updateTime, 'Y-M-D h:m') }}</view>
-        </view>
-        <!-- 企业信息 -->
-        <view v-if="props.showEntInfo" class="sub-li-bottom" @tap="handleClickEnt(item)">
-          <view class="avatarBox">
-            <image class="enterAvatar ml" :src="item.enterprise?.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'"></image>
+          <view class="font-size-13 color-999 ss-m-t-10">
+            <span>刷新时间:{{ item?.job?.refreshTime || item.job?.updateTime ? timesTampChange(item.job?.refreshTime || item.job.updateTime, 'Y-M-D h:m') : '暂无' }}</span>
+            <span class="divider-mx" v-if="item.job?.expName">|</span>
+            <span>到期时间:{{ item?.job?.expireTime ? timesTampChange(item.job.expireTime, 'Y-M-D') : '长期有效' }}</span>
           </view>
-          <view class="ss-m-l-35">
-            <view class="mr">{{ formatName(item.enterprise?.anotherName || item.enterprise.name) }}</view>
-            <span class="color-999">{{ item.enterprise?.industryName || '' }}</span>
-            <span class="divider tag-gap1" v-if="item.enterprise?.industryName && item.enterprise?.scaleName"> | </span>
-            <span class="mr color-999">{{ item.enterprise?.scaleName || '' }}</span>
+          <view class="sub-li-bottom">
+            <span></span>
           </view>
         </view>
       </view>
@@ -96,38 +81,17 @@ const emit = defineEmits(['entClick'])
 
 const props = defineProps({
   list: { type: Array, default: () => [] },
-  jobFairId: { type: [String, Number], default: '' }, // 招聘会id
-  showJobFairEntrance: { type: Boolean, default: false }, // 招聘会
-  showEntInfo: { type: Boolean, default: true },
-  updateTimeAlign: { type: String, default: 'end' },
-  showUpdateTime: { type: Boolean, default: true },
   noMore: { type: Boolean, default: false },
   showWelfareTag: { type: Boolean, default: true }
 })
 
 //岗位详情
-const toDetail = (item) =>{
+const toDetail = (item) => {
   if (!item?.job?.id) return
   let url = `/pagesB/positionDetail/index?id=${item.job.id}&area=${item.job.areaName}`
-  if (props.jobFairId) url += `&jobFairId=${props.jobFairId}`
   uni.navigateTo({ url })
 }
 
-//招聘会
-const handleToJobFair = () => {
-	uni.navigateTo({
-		url: '/pagesB/jobFair/index'
-	})
-}
-
-const handleClickEnt = (item) => {
-  const info = {
-    enterpriseId: item?.enterprise?.id || null,
-    anotherName: item?.enterprise?.anotherName || null
-  }
-  emit('entClick', info)
-}
-
 </script>
 
 <style scoped lang="scss">
@@ -165,16 +129,9 @@ const handleClickEnt = (item) => {
 }
 
 .sub-li-bottom {
-  display: flex;
-  align-items: center;
-  background-color: #fff;
-  font-size: 13px;
-  padding: 5px;
-  border-radius: 0 0 12px 12px;
-  .avatarBox {
-    max-width: 40px;
-    max-height: 40px;
-  }
+  text-align: right;
+  border-top: 1px dashed #eee;
+  margin-top: 10px;
 }
 
 .salary-text {
@@ -257,4 +214,9 @@ const handleClickEnt = (item) => {
     background-color: rgba(255, 255, 255, 0.75);
   }
 }
+.resumeCount {
+  color: #00B760;
+  font-size: 12px;
+  margin: 0 10px;
+}
 </style>

+ 7 - 1
pages/index/my.vue

@@ -1,7 +1,7 @@
 <template>
   <layout-page>
 		<view class="pb-150">
-			<view class="text-center ss-p-b-30" :class="vip ? 'vipBox' : 'avatarBox'">
+			<view class="text-center ss-p-b-30" :class="vip ? 'vipBox' : 'avatarBox'" @tap="handleLogin">
 				<img :src="getUserAvatar(userInfo?.avatar, userInfo?.sex)" alt="" class="img-box">
 				<image v-if="vip" src="/static/svg/vip.svg" class="vipIcon"></image>
 				<view v-if="!useUserStore.isLogin" class="font-weight-bold font-size-20">点击登录</view>
@@ -163,6 +163,12 @@ const handleLogoutConfirm = () => {
 	// list.value = defaultList.filter(e => !e.hide) // 重置菜单
   useUserStore.handleLogout()
 }
+const handleLogin = () => {
+  if (!getAccessToken()) {
+		showAuthModal()
+		return
+	}
+}
 </script>
 
 <style scoped lang="scss">

+ 149 - 19
pages/index/position.vue

@@ -1,23 +1,99 @@
 <template>
   <view class="box defaultBgc">
-    <uni-segmented-control :current="current" :values="controlList" @clickItem="handleChange" styleType="text" activeColor="#00897B" style="background-color: #fff"></uni-segmented-control>
-    <scroll-view class="scrollBox" scroll-y="true" @scrolltolower="loadingMore">
-      <view v-if="position.length"></view>
-      <view v-else class="text-center">
-        <view class="nodata-img-parent">
-          <image src="https://minio.citupro.com/dev/static/nodata.png" mode="widthFix" style="width: 100vw;height: 100vh;"></image>
+    <uni-segmented-control :current="current" :values="controlList" @clickItem="handleChange" styleType="text" activeColor="#00B760" style="background-color: #fff"></uni-segmented-control>
+    <scroll-view class="scrollBox" :scroll-y="true" @scrolltolower="loadingMore" style="position:relative;">
+      <view>
+        <!-- -->
+        <view class="white-bgc stick ss-p-t-20" style="border-radius: 5px;">
+          <view class="defaultBgc d-flex ss-m-x-20">
+            <view class="stickBtn" @click="handleClick(0)">待发布(<text class="ss-m-x-2">{{ unpublished }}</text>)</view>
+            <view class="stickBtn newPositionBtn" @click="handleClick(1)">发布新职位</view>
+          </view>
+          <!-- 搜索条 -->
+          <uni-search-bar
+            v-model="query.content"
+            radius="5"
+            placeholder="输入关键字"
+            cancelButton="none"
+            :focus="false"
+            @confirm="onSearch"
+          ></uni-search-bar>
+        </view>
+        <view v-if="noData" class="d-flex flex-column align-center justify-center" style="height: 80vh;">
+          <view class="nodata-img-parent">
+            <image src="https://minio.citupro.com/dev/static/nodata.png" mode="widthFix" style="width: 100vw;height: 100vh;"></image>
+          </view>
+          <view class="color-999">暂无职位</view>
+          <view class="f-horizon-center">
+            <button type="primary" size="default" class="ss-m-t-50" style="width: 60vw;" @click="fabClick">发布新职位</button>
+          </view>
+        </view>
+        <view v-else>
+          <PositionList v-if="positionListData?.length || more !== 'loading'" :list="positionListData" :noMore="false" :showJobFairEntrance="false"></PositionList>
+          <uni-load-more :status="more" />
         </view>
-        <view class="color-999">暂无职位</view>
       </view>
-      <uni-fab ref="fab" :pattern="{ iconColor: '#fff', buttonColor : '#00897B' }" :popMenu="false" vertical="bottom" horizontal="right" @fabClick="fabClick" />
     </scroll-view>
   </view>
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { ref, reactive } from 'vue'
+import PositionList from '@/components/PositionList'
+import { dealDictObjData } from '@/utils/position'
+import { getJobAdvertisedSearch } from '@/api/position'
 import { onShow } from '@dcloudio/uni-app'
 
+
+const more = ref('more')
+const noData = ref(false)
+const unpublished = ref(0)
+
+const positionListData = ref([])
+const query = reactive({
+  pageSize: 20, 
+  pageNo: 1,
+})
+const getData = async () => {
+  if (query.pageNo === 1) positionListData.value = []
+  if (query.pageNo <= 0) return
+  try {
+    more.value = 'loading'
+    const res = await getJobAdvertisedSearch(query)
+    const list = res?.data?.list || []
+    if (!list?.length) {
+      more.value = 'noMore'
+      return
+    }
+    positionListData.value.push(...list.map(e => {
+      if (!e) {
+        return e
+      }
+      e.job = { ...e.job, ...dealDictObjData({}, e.job) }
+      e.enterprise = { ...e.enterprise, ...dealDictObjData({}, e.enterprise)}
+      return e
+    }))
+    if (positionListData.value.length === +res.data.total) {
+      more.value = 'noMore'
+      return
+    }
+  } catch (error) {
+    query.pageNo--
+    more.value = 'more'
+  } finally {
+    if (!positionListData.value?.length) {
+      noData.value = true
+    }
+  }
+}
+
+const current = ref(0)
+const controlList = ['招聘中', '已关闭']
+
+const handleChange = (e) => {
+  current.value = e.currentIndex
+}
+
 // 设置自定义tabbar选中值
 onShow(() => {
   const currentPage = getCurrentPages()[0] // 获取当前页面实例
@@ -25,27 +101,56 @@ onShow(() => {
 
   // 设置当前tab页的下标index
   currentTabBar?.setData({ selected: 1 })
+  getData()
 })
 
-const current = ref(0)
-const controlList = ['招聘中', '已关闭']
-const position = ref([])
-const fab = ref()
+const onSearch = () => {
+  query.pageNo = 1
+  positionListData.value = []
+  getData()
+}
 
-const handleChange = (e) => {
-  current.value = e.currentIndex
+// 加载更多
+const loadingMore = () => {
+  more.value = 'loading'
+  query.pageNo++
+  getData()
 }
 
-const loadingMore = () => {}
+const handleClick = (type) => {
+  let url = type ? '' : ''
+  if (!type && !unpublished.value) return
+  // 
+  if (url) {
+    uni.navigateTo({ url })
+  }
 
-// 发布职位
-const fabClick = () => {
-  
 }
 
 </script>
 
 <style scoped lang="scss">
+.stick {
+  z-index: 1;
+  position: sticky;
+  top: 0;
+}
+.stickFilter {
+  z-index: 1;
+  position: sticky;
+  box-shadow: 0px 10rpx 12rpx 0px rgba(195, 195, 195, .25);
+  top: 110rpx;
+}
+.px-0 { padding-left: 0 !important; padding-right: 0 !important; }
+.pb-10 {
+  padding-bottom: 10px;
+}
+.pb-20 { padding-bottom: 20px; }
+.px-5 { padding-left: 5px; padding-right: 5px; }
+.px-10 { padding-left: 10px; padding-right: 10px; }
+.mx-10 { margin-left: 10px; margin-right: 10px }
+.mx-20 { margin-left: 20px; margin-right: 20px; }
+.mb-10 { margin-bottom: 10px; }
 .box {
   height: 100vh;
   overflow: hidden;
@@ -54,4 +159,29 @@ const fabClick = () => {
   display: flex;
   flex-direction: column;
 }
+.scrollBox{
+  flex: 1;
+  height: 0 !important;
+  padding-bottom: 24rpx;
+  box-sizing: border-box;
+}
+
+.stickBtn{
+  text-align: center;
+  width: calc(50% - 2px);
+  height: 24px;
+  line-height: 24px;
+  margin: 8px 0;
+  color: grey;
+  font-size: 13px;
+}
+
+.newPositionBtn{
+  color: #00B760;
+  border-left: 1px solid #c3c3c3;
+}
+
+// :deep(.uni-searchbar) {
+//   padding: 10px 30rpx;
+// }
 </style>