瀏覽代碼

feat: 更新

zqf 5 月之前
父節點
當前提交
140209eaa6
共有 6 個文件被更改,包括 284 次插入23 次删除
  1. 11 0
      src/api/common.js
  2. 8 0
      src/api/labour.js
  3. 61 0
      src/components/Labour/JobItem.vue
  4. 6 0
      src/pages.json
  5. 91 0
      src/pages/labour/detail.vue
  6. 107 23
      src/pages/labour/index.vue

+ 11 - 0
src/api/common.js

@@ -17,6 +17,7 @@ export const getTravelProjectList = (data) => {
     data,
   });
 };
+
 export const getDirectoryList = (data) => {
   const query = `?${Object.keys(data)
     .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
@@ -26,3 +27,13 @@ export const getDirectoryList = (data) => {
     method: 'GET',
   });
 };
+
+export const getProjects = (data) => {
+  const query = `?${Object.keys(data)
+    .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
+    .join('&')}`;
+  return request({
+    url: `/website/basic/jobProject/list${query}`,
+    method: 'GET',
+  });
+};

+ 8 - 0
src/api/labour.js

@@ -0,0 +1,8 @@
+import { request } from '@/utils/request.js';
+
+export const getLabourDetail = (id) => {
+  return request({
+    url: `website/basic/jobProject/detail?id=${id}`,
+    method: 'GET',
+  });
+};

+ 61 - 0
src/components/Labour/JobItem.vue

@@ -0,0 +1,61 @@
+<template>
+  <view
+    class="flex space-x-10 py-15 border-b box-border"
+    @click="navigateToDetail"
+  >
+    <image
+      :src="itemData.jobUrlsAfterConvert[0]"
+      class="w-108 h-114 shrink"
+    />
+    <view class="flex-1 w-0">
+      <view class="text-base text-black-3 truncate font-semibold">
+        {{ itemData.jobTitle }}
+      </view>
+      <view class="text-sm text-[#999999] line-clamp-3 pt-5">
+        {{ itemData.remarks }}
+      </view>
+      <view class="flex items-center flex-wrap text-sm mt-5 gap-5 content-start">
+        <span
+          v-for="item in lableList"
+          :key="item"
+          class="bg-[#FFF5ED] text-[#555D6C] h-18 px-3 flex items-center justify-center"
+        >{{ item }}</span>
+      </view>
+      <view class="text-sm text-[#666666] mt-10 flex justify-end">
+        {{ itemData.updateTime.split(" ")[0] }}发布
+      </view>
+      <view class="flex justify-end">
+        <span class="text-xl font-semibold text-[#FF3D00]">
+          {{ itemData.salaryCap }}-{{ itemData.salaryFloor }}{{ itemData.salaryUnit }}
+        </span>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { computed } from 'vue';
+
+const props = defineProps({
+  itemData: {
+    type: Object,
+    default: () => {},
+  },
+});
+
+const lableList = computed(() => {
+  const tmpList = props.itemData.jobLabel?.split("&") ?? [];
+  return [
+    `招聘人数:${props.itemData.jobPeople}人`,
+    ...tmpList,
+    `${props.itemData.jobArea}`,
+  ];
+});
+
+// 导航到详情页
+const navigateToDetail = () => {
+  uni.navigateTo({
+    url: `/pages/labour/detail?id=${props.itemData.id}`
+  });
+};
+</script>

+ 6 - 0
src/pages.json

@@ -35,6 +35,12 @@
       }
     },
     {
+      "path": "pages/labour/detail",
+      "style": {
+        "navigationBarTitleText": "出国劳务"
+      }
+    },
+    {
       "path": "pages/profile/index",
       "style": {
         "navigationBarTitleText": "我的"

+ 91 - 0
src/pages/labour/detail.vue

@@ -0,0 +1,91 @@
+<template>
+  <div>
+    <div class="px-15 pt-10 pb-100">
+      <image
+        :src="detailData.jobUrlsAfterConvert[0]"
+        mode="widthFix"
+      />
+      <div class="flex items-center mt-10 justify-between">
+        <span class="text-base text-black-3 font-semibold">{{ detailData.jobTitle }}</span>
+        <span class="text-xl font-semibold text-[#FF3D00] shrink"
+          >{{ detailData.salaryCap }}-{{ detailData.salaryFloor }}{{ detailData.salaryUnit }}</span
+        >
+      </div>
+      <div class="flex items-center flex-wrap text-sm mt-5 gap-5 content-start">
+        <span
+          v-for="item in lableList"
+          :key="item"
+          class="bg-[#FFF5ED] text-[#555D6C] h-18 px-3 flex items-center justify-center"
+          >{{ item }}</span
+        >
+      </div>
+      <div class="mt-15 text-xl font-semibold text-black-3">职位详情</div>
+      <div v-html="detailData.jobContent?.content" class="mt-10 text-black-3 text-base"></div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { getLabourDetail } from '@/api/labour';
+import { useRoute } from 'vue-router';
+import { computed } from 'vue';
+const router = useRoute();
+const lableList = computed(() => {
+  const tmpList = detailData.value.jobLabel?.split('&') ?? [];
+  return [`招聘人数:${detailData.value.jobPeople}人`, ...tmpList, `${detailData.value.jobArea}`];
+});
+onLoad((options) => {
+  requestLabourDetail(options.id);
+});
+
+const detailData = ref({});
+async function requestLabourDetail(id) {
+  const { data } = await getLabourDetail(id);
+  detailData.value = data;
+}
+
+function richTxtFilter(content) {
+  if (!content) return '';
+  let val = content.replace(/<img/gi, '<img class="rich-txt-img" ');
+  return val;
+}
+</script>
+
+<style lang="scss" scoped>
+.project-detail {
+  padding: 10px 10px 30px 10px;
+}
+.project-title {
+  font-size: 20px;
+  line-height: 30px;
+  color: #333;
+  font-weight: bold;
+}
+.project-label {
+  border: 1px solid #fd9a00;
+  color: #fd9a00;
+  padding: 0 8px;
+  display: inline-block;
+  height: 22px;
+  line-height: 22px;
+  font-size: 14px;
+  margin-top: 15px;
+  & + .project-label {
+    margin-left: 10px;
+  }
+}
+.project-concat {
+  margin-top: 10px;
+  color: #666666b2;
+  div + div {
+    margin-top: 10px;
+  }
+}
+::v-deep rich-text {
+  margin-top: 15px;
+}
+
+image {
+  width: 100%;
+}
+</style>

+ 107 - 23
src/pages/labour/index.vue

@@ -1,40 +1,124 @@
 <template>
   <div>
-    <swiper class="swiper" circular autoplay :interval="5000">
-      <swiper-item
-        v-for="item in bannerList"
-        :key="item.id"
-        class="swiper-item"
-      >
-        <image :src="item.imgUrlsAfterConvert[0]" mode="aspectFill" />
-      </swiper-item>
-    </swiper>
+    <!-- <Navbar title="出国劳务" /> -->
+
+    <div class="px-15 pt-15">
+      <swiper class="h-150 rounded-lg overflow-hidden" circular autoplay :interval="5000">
+        <swiper-item v-for="item in bannerList" :key="item.id" class="h-full w-full">
+          <image
+            class="object-cover w-full h-full"
+            :src="item.imgUrlsAfterConvert[0]"
+            mode="aspectFill"
+          />
+        </swiper-item>
+      </swiper>
+
+      <div class="pt-15 flex justify-between items-center">
+        <input
+          v-model="searchQuery.searchString"
+          placeholder="请输入搜索关键词"
+          shape="round"
+          @search="onSearch"
+          class="flex-1"
+        />
+        <div class="w-40 flex items-center justify-center" @click="handleFilter">
+          <icon name="filter-o" color="#fe8e2c" size="25" />
+        </div>
+      </div>
+
+      <scroll-view v-if="dataList.length" type="list" @scrolltolower="loadMore">
+        <LabourJobItem v-for="item in dataList" :key="item.id" :item-data="item" >
+        </LabourJobItem>
+      </scroll-view>
+      <!-- <Empty v-else-if="!dataList.length && !loading" /> -->
+    </div>
+    <Tabbar />
+
   </div>
 </template>
 
 <script setup>
-import { getBannerList } from '@/api/common';
-
+import LabourJobItem from '@/components/Labour/JobItem.vue'
+import { getBannerList, getDirectoryList, getProjects } from '@/api/common';
 const bannerList = ref([]);
 async function requestBannerList() {
   const { data } = await getBannerList({ belongTab: 10 });
   bannerList.value = data.dataList;
 }
 
+const defaultFirstArea = {
+  id: 16,
+  menuName: '全部',
+};
+
+const searchQuery = reactive({
+  belongTab: defaultFirstArea.id,
+  searchString: '',
+  pageNum: 1,
+  pageSize: 10,
+});
+
+const dataList = ref([]);
+const loading = ref(true);
+const finished = ref(false);
+async function requestProjects() {
+  const { data } = await getProjects(searchQuery);
+  dataList.value = dataList.value.concat(data.dataList);
+  loading.value = false;
+  if (dataList.value.length >= data.totalCount) {
+    finished.value = true;
+  }
+}
+
+function loadMore() {
+  searchQuery.pageNum++;
+  requestProjects();
+}
+
+function onSearch() {
+  searchQuery.pageNum = 1;
+  dataList.value = [];
+  finished.value = false;
+  requestProjects();
+}
+
 onMounted(() => {
   requestBannerList();
+  requestProjects();
+  getAreaList();
 });
-</script>
 
-<style lang="scss" scoped>
-.swiper {
-  height: 500rpx;
-  .swiper-item {
-    height: 100%;
-    image {
-      width: 100%;
-      height: 100%;
-    }
-  }
+// 侧边过滤逻辑
+const showFilter = ref(false);
+function handleFilter() {
+  showFilter.value = !showFilter.value;
+}
+const areaList = ref([]);
+const currentArea = ref(defaultFirstArea);
+async function getAreaList() {
+  const { data } = await getDirectoryList({ parentId: 16 });
+  areaList.value = [defaultFirstArea, ...data.dataList];
 }
-</style>
+
+function handleClick(item) {
+  currentArea.value = item;
+}
+
+function handleReset() {
+  currentArea.value = defaultFirstArea;
+}
+function handleConfirm() {
+  searchQuery.belongTab = currentArea.value.id;
+  showFilter.value = false;
+  reSearch();
+}
+
+function reSearch() {
+  searchQuery.pageNum = 1;
+  dataList.value = [];
+  finished.value = false;
+  requestProjects();
+}
+</script>
+
+<style lang="scss" scoped></style>