瀏覽代碼

职位发布、职位列表

Xiao_123 11 月之前
父節點
當前提交
37cfd354ad

+ 16 - 0
src/api/position.js

@@ -126,4 +126,20 @@ export const getSubscribeEnterprise = async (data) => {
     url: '/app-api/menduner/system/person/get/enterprise/subscribe/page',
     data
   })
+}
+
+// 招聘端-发布职位
+export const saveJobAdvertised = async (data) => {
+  return await request.post({
+    url: '/app-admin-api/menduner/system/job-advertised/save',
+    data
+  })
+}
+
+// 招聘端-职位列表
+export const getJobAdvertisedList = async (params) => {
+  return await request.get({
+    url: '/app-admin-api/menduner/system/job-advertised/page',
+    params
+  })
 }

+ 1 - 1
src/components/jobTypeCard/index.vue

@@ -93,7 +93,7 @@ const isPage = props.page
 const selectItems = ref([])
 
 // 回显
-if (props.select.length) selectItems.value = props.select.map(e => Number(e))
+if (props.select.length) selectItems.value = props.select.map(e => e)
 
 const route = useRoute()
 const routeQuery = route?.query

+ 0 - 1
src/layout/enterprise.vue

@@ -20,7 +20,6 @@ defineOptions({ name: 'enterprise-layout-index' })
 // 不展示侧边栏名单
 const whiteList = ['/enterprise/enterpriseCenter']
 const router = useRouter()
-console.log('router.currentRoute.value.path', router.currentRoute.value.path)
 </script>
 
 <style lang="scss" scoped>

+ 37 - 5
src/views/enterprise/positionManagement/components/add.vue

@@ -11,12 +11,13 @@
           <div>
             <h2 class="mt-n1 headline font-weight-regular">{{ val.title }}</h2>
             <div class="mb-4 desc">{{ val.desc }}</div>
-            <component class="mt-10" :is="val.path"></component>
+            <component class="mt-10" :is="val.path" :ref="val.ref"></component>
           </div>
         </v-timeline-item>
       </v-timeline>
-      <div class="text-center">
-        <v-btn class="buttons" color="primary">发 布</v-btn>
+      <div class="text-center mb">
+        <v-btn class="half-button mr-3" color="primary" variant="outlined" @click="handleCancel">取 消</v-btn>
+        <v-btn class="half-button" color="primary" @click="handleSave">发 布</v-btn>
       </div>
     </v-card>
   </div>
@@ -24,25 +25,50 @@
 
 <script setup>
 defineOptions({ name: 'enterprise-position-add'})
+import { ref } from 'vue'
+import { useRouter } from 'vue-router'
+import { saveJobAdvertised } from '@/api/position'
 import baseInfo from './baseInfo.vue'
 import jobRequirements from './jobRequirements.vue'
+import Snackbar from '@/plugins/snackbar'
 
+const router = useRouter()
+const baseInfoRef = ref()
+const jobRequirementsRef = ref()
 const list = [
   {
     color: '#00897B',
     icon: 'mdi-numeric-1',
     title: '职位基本信息',
     desc: '职位发布成功后,招聘类型、职位名称、职位类型、工作城市,将无法修改',
-    path: baseInfo
+    path: baseInfo,
+    ref: baseInfoRef
   },
   {
     color: 'indigo-lighten-2',
     icon: 'mdi-numeric-2',
     title: '职位要求',
     desc: '我们将通过以下条件,为您精确推荐合适的人才,请尽量详细填写',
-    path: jobRequirements
+    path: jobRequirements,
+    ref: jobRequirementsRef
   }
 ]
+
+// 取消
+const handleCancel = () => {
+  router.push('/enterprise/position')
+}
+
+// 发布
+const handleSave = async () => {
+  const baseInfo = await baseInfoRef.value[0].getQuery()
+  const requirement = await jobRequirementsRef.value[0].getQuery()
+  if (!baseInfo || !requirement) return Snackbar.warning('请将信息填写完整')
+  const query = Object.assign(baseInfo, requirement)
+  await saveJobAdvertised(query)
+  Snackbar.success('发布成功')
+  router.push('/enterprise/position')
+}
 </script>
 
 <style scoped lang="scss">
@@ -51,3 +77,9 @@ const list = [
   color: #777;
 }
 </style>
+
+<style lang="scss" scoped>
+.mb {
+  margin-bottom: 100px;
+}
+</style>

+ 45 - 8
src/views/enterprise/positionManagement/components/baseInfo.vue

@@ -32,7 +32,7 @@ import textUI from '@/components/FormUI/TextInput'
 import jobTypeCard from '@/components/jobTypeCard'
 
 const formPageRef = ref()
-const query = reactive({})
+let query = reactive({})
 const items = ref({
   options: [
     {
@@ -40,20 +40,22 @@ const items = ref({
       key: 'enterpriseName',
       disabled: true,
       value: '辞图科技·计算机软件·广州辞图科技有限公司',
-      label: '公司名称 *'
+      label: '公司名称 *',
+      noParam: true
     },
     {
       type: 'text',
       key: 'name',
       value: '',
       label: '职位名称 *',
-      rules: [v => !!v || '请选择职位名称']
+      rules: [v => !!v || '请填写职位名称']
     },
     {
       slotName: 'positionId',
       key: 'positionId',
       value: '',
       label: '职位类型 *',
+      noParam: true,
       rules: [v => !!v || '请选择职位类型']
     },
     {
@@ -61,13 +63,32 @@ const items = ref({
       key: 'content',
       rows: 10,
       value: '',
-      label: '职位描述 *',
+      label: '岗位职责 *',
       counter: 5000,
       clearable: true,
       rules: [
         value => {
           if (value) return true
-          return '请输入职位描述'
+          return '请输入岗位职责'
+        },
+        value => {
+          if (value?.length <= 5000) return true
+          return '请输入2-5000个字符'
+        }
+      ]
+    },
+    {
+      type: 'textarea',
+      key: 'requirement',
+      rows: 10,
+      value: '',
+      label: '岗位要求 *',
+      counter: 5000,
+      clearable: true,
+      rules: [
+        value => {
+          if (value) return true
+          return '请输入岗位要求'
         },
         value => {
           if (value?.length <= 5000) return true
@@ -82,16 +103,32 @@ const setValue = (key, value) => {
   items.value.options.find(e => e.key === key).value = value
 }
 
-// 期望职位
+// 职位类型
 const handleJobClickItem = (list, name) => {
-  if (!list.length) return
+  if (!list.length) {
+    delete query.positionId
+    setValue('positionId', '')
+    return
+  }
   query.positionId = list[0]
   setValue('positionId', name)
 }
 
+const getQuery = async () => {
+  const { valid } = await formPageRef.value.formRef.validate()
+  if (!valid) return
+  const obj = {}
+  items.value.options.forEach(e => {
+    if (e.noParam) return
+    obj[e.key] = e.value
+  })
+  query = Object.assign(query, obj)
+  return query
+}
+
 defineExpose({
   formPageRef,
-  query
+  getQuery
 })
 </script>
 

+ 5 - 35
src/views/enterprise/positionManagement/components/item.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <div v-for="val in list" :key="val.id" class="itemBox mb-3">
+    <div v-for="val in items" :key="val.id" class="itemBox mb-3">
       <div class="d-flex justify-space-between pa-5">
         <div class="position">
           <div>
@@ -13,9 +13,9 @@
             <span class="lines"></span>
             <span>{{ val.expName }}</span>
             <span class="lines"></span>
-            <span>{{ val.salary }}</span>
+            <span>{{ val.payFrom }}-{{ val.payTo }}/{{ val.payName }}</span>
             <span class="lines"></span>
-            <span>{{ val.positionTypeName }}</span>
+            <span>{{ val.positionName }}</span>
           </div>
         </div>
         <div class="d-flex align-center">
@@ -54,43 +54,13 @@
 
 <script setup>
 defineOptions({ name: 'enterprise-position-item'})
-import { ref } from 'vue'
 defineProps({
   tab: {
     type: Number,
     default: 1
-  }
-})
-
-const list = ref([
-  {
-    id: '1',
-    name: '销售总监',
-    areaName: '广东 广州 越秀区',
-    eduName: '本科',
-    expName: '3年以上',
-    salary: '1万到1.5万',
-    positionTypeName: '销售总监'
   },
-  {
-    id: '2',
-    name: '市场总监',
-    areaName: '广东 广州 越秀区',
-    eduName: '本科',
-    expName: '3年以上',
-    salary: '1万到1.5万',
-    positionTypeName: '销售总监'
-  },
-  {
-    id: '3',
-    name: '行政总监',
-    areaName: '广东 广州 越秀区',
-    eduName: '本科',
-    expName: '3年以上',
-    salary: '1万到1.5万',
-    positionTypeName: '销售总监'
-  }
-])
+  items: Array
+})
 </script>
 
 <style scoped lang="scss">

+ 52 - 20
src/views/enterprise/positionManagement/components/jobRequirements.vue

@@ -1,7 +1,7 @@
 <template>
   <div style="width: 100%;">
     <CtForm ref="formPageRef" :items="items" style="width: 600px;">
-      <template #workAreaId="{ item }">
+      <template #areaId="{ item }">
         <v-menu :close-delay="1" :open-delay="0" v-bind="$attrs">
             <template v-slot:activator="{  props }">
               <textUI
@@ -11,7 +11,7 @@
                 style="position: relative;"
               ></textUI>
             </template>
-            <areaType :select="[query.workAreaId].filter(Boolean)" @handleAreaClick="handleArea" class="jobTypeCardBox" isSingle></areaType>
+            <areaType :select="[query.areaId].filter(Boolean)" @handleAreaClick="handleArea" class="jobTypeCardBox" isSingle></areaType>
           </v-menu>
       </template>
     </CtForm>
@@ -23,23 +23,22 @@ defineOptions({ name: 'position-add-job-requirements'})
 import CtForm from '@/components/CtForm'
 import areaType from '@/components/AreaSelect'
 import textUI from '@/components/FormUI/TextInput'
-import { reactive, ref } from 'vue'
+import { reactive, ref, defineExpose } from 'vue'
 import { getDict } from '@/hooks/web/useDictionaries'
 
 const formPageRef = ref()
-const query = reactive({})
-console.log(query, 'qqq')
+let query = reactive({})
 const items = ref({
   options: [
     {
       type: 'autocomplete',
-      key: 'jobType',
+      key: 'type',
       value: null,
-      label: '职位性质 *',
+      label: '招聘类型 *',
       itemText: 'label',
       itemValue: 'value',
       dictTypeName: 'menduner_job_type',
-      rules: [v => !!v || '请选择职位性质'],
+      rules: [v => !!v || '招聘类型'],
       items: []
     },
     {
@@ -70,9 +69,8 @@ const items = ref({
     {
       type: 'text',
       key: 'payFrom',
-      value: '',
-      col: 6,
-      flexStyle: 'mr-3',
+      value: '12000',
+      col: 4,
       label: '最低薪资 *',
       suffix: '元',
       rules: [v => !!v || '请填写最低薪资'],
@@ -80,23 +78,37 @@ const items = ref({
     {
       type: 'text',
       key: 'payTo',
-      value: '',
-      col: 6,
+      value: '15000',
+      col: 4,
       label: '最高薪资 *',
+      flexStyle: 'mx-3',
       suffix: '元',
       rules: [v => !!v || '请填写最高薪资'],
     },
     {
-      slotName: 'workAreaId',
-      key: 'workAreaId',
+      type: 'autocomplete',
+      key: 'payUnit',
+      value: null,
+      label: '薪酬单位 *',
+      itemText: 'label',
+      itemValue: 'value',
+      col: 4,
+      dictTypeName: 'menduner_pay_unit',
+      rules: [v => !!v || '请选择薪酬单位'],
+      items: []
+    },
+    {
+      slotName: 'areaId',
+      key: 'areaId',
       value: null,
+      noParam: true,
       label: '工作城市 *',
-      rules: [v => !!v || '请选择最高学历']
+      rules: [v => !!v || '请选择工作城市']
     },
     {
       type: 'text',
       key: 'address',
-      value: '',
+      value: '先烈中路100号大院8栋',
       label: '详情地址 *',
       rules: [v => !!v || '请填写详细地址'],
     },
@@ -113,12 +125,32 @@ items.value.options.forEach(async (e) => {
 
 // 工作城市
 const handleArea = (list, name) => {
-  if (!list.length) return
-  query.workAreaId = list[0]
-  const obj = items.value.options.find(e => e.key === 'workAreaId')
+  if (!list.length) {
+    delete query.areaId
+    items.value.options.find(e => e.key === 'areaId').value = ''
+    return
+  }
+  query.areaId = list[0]
+  const obj = items.value.options.find(e => e.key === 'areaId')
   obj.value = name
 }
 
+const getQuery = async () => {
+  const { valid } = await formPageRef.value.formRef.validate()
+  if (!valid) return
+  const obj = {}
+  items.value.options.forEach(e => {
+    if (e.noParam) return
+    obj[e.key] = e.value
+  })
+  query = Object.assign(query, obj)
+  return query
+}
+
+defineExpose({
+  formPageRef,
+  getQuery
+})
 </script>
 
 <style scoped lang="scss">

+ 29 - 1
src/views/enterprise/positionManagement/index.vue

@@ -17,7 +17,7 @@
         </v-tabs>
         <v-window v-model="tab" class="mt-3">
           <v-window-item :value="1">
-            <PositionItem :tab="tab"></PositionItem>
+            <PositionItem :tab="tab" :items="items"></PositionItem>
           </v-window-item>
           <v-window-item :value="2">
             <PositionItem :tab="tab"></PositionItem>
@@ -29,6 +29,12 @@
             <PositionItem :tab="tab"></PositionItem>
           </v-window-item>
         </v-window>
+        <CtPagination
+          :total="total"
+          :page="page.pageNo"
+          :limit="page.pageSize"
+          @handleChange="handleChangePage"
+        ></CtPagination>
       </div>
     </v-card>
   </div>
@@ -40,9 +46,17 @@ import { ref } from 'vue'
 import TextUI from '@/components/FormUI/TextInput'
 import PositionItem from './components/item.vue'
 import { useRouter } from 'vue-router'
+import { getJobAdvertisedList } from '@/api/position'
+import { dealDictArrayData } from '@/views/recruit/position/components/dict'
 
 const router = useRouter()
 const tab = ref(1)
+const total = ref(0)
+const page = ref({
+  pageSize: 10,
+  pageNo: 1
+})
+const items = ref([])
 const textItem = ref({
   type: 'text',
   width: 600,
@@ -55,6 +69,20 @@ const handleScreen = () => {}
 const handleAdd = () => {
   router.push('/enterprise/position/add')
 }
+
+// 获取职位列表
+const getPositionList = async () => {
+  const { list, total: number } = await getJobAdvertisedList(page.value)
+  if (!list.length) return
+  total.value = number
+  items.value = dealDictArrayData([], list)
+}
+getPositionList()
+
+const handleChangePage = (index) => {
+  page.value.pageNo = index
+  getPositionList()
+}
 </script>
 
 <style scoped lang="scss">

+ 2 - 1
src/views/recruit/position/components/dict.js

@@ -17,7 +17,8 @@ const dictList = ref([
   { type: 'menduner_industry_type', value: 'industry', key: 'industryId', label: 'industryName', params: {}, apiType: 'industryList', nameKey: 'nameCn', valueKey: 'id' },
   { type: 'menduner_education_type', value: 'edu', key: 'eduType', label: 'eduName' },
   { type: 'menduner_exp_type', value: 'exp', key: 'expType', label: 'expName' },
-  { type: 'menduner_area_type', value: 'area', key: 'areaId', label: 'areaName', params: {}, apiType: 'areaList', nameKey: 'name', valueKey: 'id' }
+  { type: 'menduner_area_type', value: 'area', key: 'areaId', label: 'areaName', params: {}, apiType: 'areaList', nameKey: 'name', valueKey: 'id' },
+  { type: 'positionData', value: 'position', key: 'positionId', label: 'positionName', params: {}, apiType: 'positionData', nameKey: 'nameCn', valueKey: 'id' }
 ])
 
 // 字典