Procházet zdrojové kódy

发布众聘岗位

Xiao_123 před 10 měsíci
rodič
revize
a5f6441455

+ 3 - 2
src/api/enterprise.js

@@ -64,9 +64,10 @@ export const getPersonCvPage = async (params) => {
 }
 
 // 招聘端-牛人管理-获取发布的职位列表
-export const getJobAdvertised = async () => {
+export const getJobAdvertised = async (params) => {
   return await request.get({
-    url: '/app-admin-api/menduner/system/job-advertised/list'
+    url: '/app-admin-api/menduner/system/job-advertised/list',
+    params
   })
 }
 

+ 39 - 0
src/api/recruit/enterprise/system/post/index.js

@@ -0,0 +1,39 @@
+import request from '@/config/axios'
+
+// 岗位列表分页
+export const getEnterprisePostPage = async (params) => {
+  return await request.get({
+    url: '/app-admin-api/menduner/system/enterprise-post/page',
+    params
+  })
+}
+
+// 岗位详情
+export const getEnterprisePostDetail = async (id) => {
+  return await request.get({
+    url: `/app-admin-api/menduner/system/enterprise-post/get?id=${id}`
+  })
+}
+
+// 岗位新增
+export const createEnterprisePost = async (data) => {
+  return await request.post({
+    url: '/app-admin-api/menduner/system/enterprise-post/create',
+    data
+  })
+}
+
+// 岗位更新
+export const updateEnterprisePost = async (data) => {
+  return await request.put({
+    url: '/app-admin-api/menduner/system/enterprise-post/update',
+    data
+  })
+}
+
+// 岗位删除
+export const deleteEnterprisePost = async (id) => {
+  return await request.delete({
+    url: `/app-admin-api/menduner/system/enterprise-post/delete?id=${id}`
+  })
+}

+ 2 - 8
src/components/FormUI/TextInput/index.vue

@@ -8,11 +8,10 @@
       :rules="item.rules"
       :disabled="item.disabled"
       :style="{width: item.width}"
-      color="primary"
+      :color="item.color || 'primary'"
       :label="item.label"
       :placeholder="item.placeholder || item.label"
       :autofocus="item.autofocus"
-      :focused="item.focused"
       :required="item.required"
       :class="item.class"
       :suffix="item.suffix"
@@ -26,7 +25,6 @@
       :hide-details="item.hideDetails || false"
       @wheel="$event => handleWheel($event, item)"
       @update:modelValue="modelValueUpDate"
-      @update:focused="focusedEvent"
       @click:append="appendClick"
       @click:append-inner="appendInnerClick"
       @keyup.enter="handleKeyup"
@@ -39,7 +37,7 @@ import { defineEmits, ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-text-field'})
 
 const props = defineProps({item: Object, modelValue: [String, Number]})
-const emit = defineEmits(['update:modelValue', 'change', 'appendClick', 'appendInnerClick', 'enter', 'focused'])
+const emit = defineEmits(['update:modelValue', 'change', 'appendClick', 'appendInnerClick', 'enter'])
 const item = props.item
 const value = ref(props.modelValue)
 const searchDebouncedTime = item?.searchDebouncedTime === 0 ? ref(0) : ref(500)
@@ -69,10 +67,6 @@ const handleKeyup = () => {
   emit('enter', value.value)
 }
 
-const focusedEvent = (focused) => { // Emitted when the input is focused or blurred
-  emit('focused', focused, value.value)
-}
-
 const handleWheel = (event, item) => {
   if (item.type !== 'number') return
   event.preventDefault()

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
src/components/Position/item.vue


+ 1 - 0
src/locales/en.js

@@ -5,6 +5,7 @@ export default {
     delete: 'Delete',
     cancel: 'Cancel',
     save: 'Save',
+    submit: 'Submit',
     add: 'Add',
     toUpload: 'Go upload',
     change: 'Change',

+ 1 - 0
src/locales/zh-CN.js

@@ -5,6 +5,7 @@ export default {
     delete: '删除',
     cancel: '取消',
     save: '保存',
+    submit: '提交',
     add: '新增',
     toUpload: '去上传',
     change: '更改',

+ 26 - 3
src/router/modules/enterprise.js

@@ -166,7 +166,6 @@ const enterprise = [
         path: '/recruit/enterprise/publicRecruitmentManagement/deliver',
         meta: {
           title: '投递管理',
-          isAdmin: true,
           enName: 'Delivery Management'
         },
         component: () => import('@/views/recruit/enterprise/publicRecruitmentManagement/deliver')
@@ -196,7 +195,7 @@ const enterprise = [
         path: '/recruit/enterprise/informationManagement/informationSettings',
         meta: {
           title: '企业信息设置',
-          isAdmin: true,
+          // isAdmin: true,
           enName: 'Enterprise Information Settings'
         },
         component: () => import('@/views/recruit/enterprise/informationManagement/informationSettings.vue')
@@ -230,7 +229,31 @@ const enterprise = [
           enName: 'User Management '
         },
         component: () => import('@/views/recruit/enterprise/systemManagement/userManagement/index.vue')
-      }
+      },
+      {
+        path: '/recruit/enterprise/systemManagement/postManagement',
+        meta: {
+          title: '岗位管理',
+          enName: 'Post Management '
+        },
+        component: () => import('@/views/recruit/enterprise/systemManagement/postManagement/index.vue')
+      },
+      {
+        path: '/recruit/enterprise/systemManagement/postManagement/add',
+        show: true,
+        meta: {
+          title: '新增岗位'
+        },
+        component: () => import('@/views/recruit/enterprise/systemManagement/postManagement/save.vue')
+      },
+      {
+        path: '/recruit/enterprise/systemManagement/postManagement/edit',
+        show: true,
+        meta: {
+          title: '岗位编辑'
+        },
+        component: () => import('@/views/recruit/enterprise/systemManagement/postManagement/save.vue')
+      },
     ]
   },
   {

+ 1 - 1
src/views/recruit/enterprise/personnelManagement/components/screen.vue

@@ -75,7 +75,7 @@ list.value.forEach(k => {
     })
   }
   if (k.api) {
-    k.api().then(data => {
+    k.api({ hire: false }).then(data => {
       if (data.length) {
         const list = dealDictArrayData([], data)
         k.items = list.map(e => {

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

@@ -36,8 +36,8 @@ const props = defineProps({
 })
 
 const handleChangePublic = () => {
-  const value = items.value.options.find(e => e.key === 'isPublicRecruitment').value
-  const obj = items.value.options.find(e => e.key === 'moneyReward')
+  const value = items.value.options.find(e => e.key === 'hire').value
+  const obj = items.value.options.find(e => e.key === 'hirePrice')
   obj.hide = value === '1' ? false : true
 }
 
@@ -47,11 +47,10 @@ const items = ref({
   options: [
     {
       type: 'ifRadio',
-      key: 'isPublicRecruitment',
+      key: 'hire',
       value: '0',
       label: '众聘岗位 *',
       width: 90,
-      noParam: true,
       items: [
         { label: '是', value: '1' },
         { label: '否', value: '0' }
@@ -60,11 +59,11 @@ const items = ref({
     },
     {
       type: 'number',
-      key: 'moneyReward',
+      key: 'hirePrice',
       value: null,
       label: '众聘赏金 *',
+      suffix: '元',
       hide: true,
-      noParam: true,
       rules: [v => !!v || '请填写众聘赏金']
     },
     {
@@ -151,7 +150,11 @@ watch(
         return
       }
       if (e.noParam) return
-      e.value = val[e.key]
+      if (e.key === 'hire') {
+        e.value = val[e.key] ? '1' : '0'
+        handleChangePublic()
+      }
+      else e.value = val[e.key]
     })
   },
   { immediate: true },
@@ -175,7 +178,8 @@ const getQuery = async () => {
   const obj = {}
   items.value.options.forEach(e => {
     if (e.noParam) return
-    obj[e.key] = e.value
+    if (e.key === 'hire') obj[e.key] = e.value === '1' ? true : false
+    else obj[e.key] = e.value
   })
   query = Object.assign(query, obj)
   return query

+ 10 - 3
src/views/recruit/enterprise/positionManagement/components/item.vue

@@ -9,8 +9,8 @@
       </div>
       <v-btn v-if="tab === 2" class="ml-8" :disabled="!selectAll" color="primary" variant="tonal" size="small" @click="handleAction(1, 'activation', {})">{{ $t('common.activation') }}</v-btn>
     </div>
-    <div v-for="val in items" :key="val.id" class="itemBox mb-3">
-      <div class="d-flex justify-space-between pa-5">
+    <div v-for="val in items" :key="val.id" class="itemBox mb-3" :style="{'height': (val?.hire && val?.hirePrice) ? '162px' : '134px'}">
+      <div class="d-flex justify-space-between" style="padding: 10px 20px;">
         <div class="position">
           <div class="item-select">
             <v-checkbox v-model="val.select" hide-details color="primary" @update:model-value="handleChangeSelect"></v-checkbox>
@@ -31,6 +31,9 @@
             <span class="lines"></span>
             <span>{{ val.positionName }}</span>
           </div>
+          <div v-if="val?.hire && val?.hirePrice" class="ml-10 mt-2">
+            <v-chip label color="primary" size="small">赏金:{{ val.hirePrice }}</v-chip>
+          </div>
         </div>
         <div class="d-flex align-center">
           <div v-if="tab === 1">
@@ -165,8 +168,8 @@ const handleToStatistics = () => {
 
 <style scoped lang="scss">
 .itemBox {
+  position: relative;
   border: 1px solid #e5e6eb;
-  height: 145px;
 }
 .position-name {
   color: var(--color-333);
@@ -198,6 +201,10 @@ const handleToStatistics = () => {
   color: var(--color-666);
 }
 .bottom {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
   height: 40px;
   background-color: #f7f8fa;
   font-size: 14px;

+ 8 - 2
src/views/recruit/enterprise/positionManagement/index.vue

@@ -47,7 +47,10 @@ const total = ref(0)
 const tipsText = ref(t('common.noData'))
 const query = ref({
   pageSize: 10,
-  pageNo: 1
+  pageNo: 1,
+  status: 0, // 0招聘中 1已关闭
+  hasExpiredData: false, // true 到期职位
+  hire: false // true 众聘岗位
 })
 const tabList = [
   { label: t('position.recruitmentInProgress'), value: 1 },
@@ -72,9 +75,12 @@ const handleAdd = () => {
 // 获取职位列表
 const getPositionList = async () => {
   query.value.hasExpiredData = tab.value === 3 ? true : false
+  query.value.hire = tab.value === 4 ? true : false
+
   if (tab.value !== 3) {
-    query.value.status = tab.value === 1 ? 0 : 1
+    query.value.status = tab.value === 1 ? 0 : (tab.value === 2 ? 1 : null)
   } else delete query.value.status
+
   const { list, total: number } = await getJobAdvertisedList(query.value)
   if (!list.length) {
     if (query.value.name) tipsText.value = '暂无数据,请更换关键词后再试'

+ 90 - 0
src/views/recruit/enterprise/systemManagement/postManagement/index.vue

@@ -0,0 +1,90 @@
+<template>
+  <v-card class="pa-5 card-box">
+    <div class="text-end">
+      <v-btn prepend-icon="mdi-plus" color="primary" @click="handleAdd">{{ $t('common.add') }}</v-btn>
+    </div>
+    <v-data-table
+      :headers="headers"
+      :items="items"
+      hide-default-header
+      height="70vh"
+      item-value="id"
+    >
+      <template #bottom></template>
+      <template v-slot:item.actions="{ item }">
+        <v-btn color="primary" variant="text" @click="handleEdit(item)">{{ $t('common.edit') }}</v-btn>
+        <v-btn color="primary" variant="text" @click="handleDelete(item)">{{ $t('common.delete') }}</v-btn>
+      </template>
+    </v-data-table>
+    <CtPagination
+      :total="total"
+      :page="query.pageNo"
+      :limit="query.pageSize"
+      @handleChange="handleChangePage"
+    ></CtPagination>
+  </v-card>
+</template>
+
+<script setup>
+defineOptions({ name: 'system-post-index'})
+import { ref } from 'vue'
+import { useRouter } from 'vue-router'
+import { timesTampChange } from '@/utils/date'
+import { useI18n } from '@/hooks/web/useI18n'
+import { getEnterprisePostPage, deleteEnterprisePost } from '@/api/recruit/enterprise/system/post'
+import Confirm from '@/plugins/confirm'
+import Snackbar from '@/plugins/snackbar'
+
+const { t } = useI18n()
+const router = useRouter()
+const total = ref(10)
+const items = ref([])
+const query = ref({
+  pageNo: 1,
+  pageSize: 10
+})
+
+const headers = [
+  { title: '岗位名称', key: 'nameCn' },
+  { title: '英文名称', key: 'nameEn' },
+  { title: '岗位缩写', key: 'code' },
+  { title: '显示顺序', key: 'sort' },
+  { title: '状态', key: 'status', value: item => item.status === '1' ? '停用' : '正常'},
+  { title: '备注', key: 'remark' },
+  { title: '更新时间', key: 'updateTime', value: item => timesTampChange(item.updateTime)},
+  { title: t('common.actions'), key: 'actions' }
+]
+
+const getList = async () => {
+  const res = await getEnterprisePostPage(query.value)
+  items.value = res.list
+  total.value = res.total
+}
+getList()
+
+const handleChangePage = (e) => {
+  query.value.pageNo = e
+  getList()
+}
+
+const handleAdd = () => {
+  router.push('/recruit/enterprise/systemManagement/postManagement/add')
+}
+
+const handleEdit = (item) => {
+  if (!item.id) return
+  router.push(`/recruit/enterprise/systemManagement/postManagement/edit?id=${item.id}`)
+}
+
+const handleDelete = ({ id }) => {
+  Confirm(t('common.confirmTitle'), '是否确认删除此项内容?').then(async () => {
+    await deleteEnterprisePost(id)
+    Snackbar.success(t('common.delMsg'))
+    getList()
+  })
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 105 - 0
src/views/recruit/enterprise/systemManagement/postManagement/save.vue

@@ -0,0 +1,105 @@
+<template>
+  <v-card class="pa-5 card-box d-flex align-center justify-center flex-column" style="height: 600px;">
+    <CtForm ref="formPageRef" :items="items" style="width: 600px;"></CtForm>
+    <div>
+      <v-btn class="half-button mr-3" color="primary" variant="outlined" @click="handleCancel">{{ $t('common.cancel') }}</v-btn>
+      <v-btn color="primary" class="half-button" @click="handleSave">{{ $t('common.submit') }}</v-btn>
+    </div>
+  </v-card>
+</template>
+
+<script setup>
+defineOptions({ name: 'system-post-add'})
+import CtForm from '@/components/CtForm'
+import { reactive, ref } from 'vue'
+import { useRouter, useRoute } from 'vue-router'
+import { useI18n } from '@/hooks/web/useI18n'
+import { getEnterprisePostDetail, createEnterprisePost, updateEnterprisePost } from '@/api/recruit/enterprise/system/post'
+import Snackbar from '@/plugins/snackbar'
+
+const route = useRoute()
+const router = useRouter()
+const { t } = useI18n()
+const formPageRef = ref()
+let query = reactive({})
+const items = ref({
+  options: [
+    {
+      type: 'ifRadio',
+      key: 'status',
+      value: '0',
+      label: '状态 *',
+      width: 90,
+      items: [
+        { label: '正常', value: '0' },
+        { label: '停用', value: '1' }
+      ]
+    },
+    {
+      type: 'text',
+      key: 'nameCn',
+      value: null,
+      label: '岗位中文名称 *',
+      rules: [v => !!v || '请填写岗位中文名称']
+    },
+    {
+      type: 'text',
+      key: 'nameEn',
+      value: null,
+      label: '岗位英文名称 *',
+      rules: [v => !!v || '请填写岗位英文名称']
+    },
+    {
+      type: 'text',
+      key: 'code',
+      value: null,
+      label: '岗位缩写'
+    },
+    {
+      type: 'number',
+      key: 'sort',
+      value: null,
+      label: '显示顺序 *',
+      rules: [v => !!v || '请填写显示顺序']
+    },
+    {
+      type: 'text',
+      key: 'remark',
+      value: null,
+      label: '备注'
+    }
+  ]
+})
+
+const getPostDetail = async (id) => {
+  const data = await getEnterprisePostDetail(id)
+  if (!data) return
+  query.id = data.id
+  items.value.options.forEach(val => {
+    val.value = data[val.key]
+  })
+}
+
+const handleCancel = () => {
+  router.push('/recruit/enterprise/systemManagement/postManagement')
+}
+
+const handleSave = async () => {
+  const { valid } = await formPageRef.value.formRef.validate()
+  if (!valid) return
+  items.value.options.forEach(val => {
+    query[val.key] = val.value
+  })
+  const api = query.id ? updateEnterprisePost : createEnterprisePost
+  await api(query)
+  Snackbar.success(t('common.submittedSuccessfully'))
+  handleCancel()
+}
+
+if (route.query && route.query.id) {
+  if (route.query.id) getPostDetail(route.query.id)
+}
+</script>
+
+<style scoped lang="scss">
+</style>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů