job.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <template>
  2. <div class="flex">
  3. <div>
  4. <el-input
  5. v-model="queryParams.name"
  6. placeholder="职位名称(回车搜索)"
  7. class="!w-240px"
  8. clearable
  9. @keyup.enter="handleRefresh"
  10. @clear="handleRefresh"
  11. />
  12. <el-select v-model="queryParams.fairId" placeholder="招聘会" class="!w-240px ml-10px" clearable @change="handleRefresh">
  13. <el-option
  14. v-for="item in jobFairList"
  15. :key="item.id"
  16. :label="item.title"
  17. :value="item.id"
  18. />
  19. <template #footer v-if="jobFairList?.length < +jobFairTotal">
  20. <div class="text-center">
  21. <el-button type="primary" link @click="handleGetMore">加载更多</el-button>
  22. </div>
  23. </template>
  24. </el-select>
  25. </div>
  26. <el-button class="ml-10px" type="success" plain @click="handleRefresh"><Icon icon="ep:refresh" class="mr-5px" /> 刷新</el-button>
  27. </div>
  28. <el-table v-loading="loading" :data="tableData" :stripe="true" class="m-t-20px">
  29. <el-table-column label="职位名称" align="center" prop="name">
  30. <template #default="{ row }">{{ formatName(row.name) }}</template>
  31. </el-table-column>
  32. <el-table-column label="招聘会" align="center" prop="jobFairName" />
  33. <el-table-column label="职位类型" align="center" prop="positionName" />
  34. <el-table-column label="地区" align="center" prop="areaName">
  35. <template #default="scope">
  36. {{ !scope.row.areaId ? '全国' : scope.row.areaName }}
  37. </template>
  38. </el-table-column>
  39. <el-table-column label="薪资" align="center" prop="payFrom">
  40. <template #default="scope">
  41. <span v-if="scope.row.payFrom && scope.row.payTo">
  42. {{ scope.row.payFrom }} - {{ scope.row.payTo }}/{{ payUnit.find(e => e.value === Number(scope.row.payUnit))?.label }}
  43. </span>
  44. <span v-else>面议</span>
  45. </template>
  46. </el-table-column>
  47. <el-table-column label="招聘类型" align="center" prop="type">
  48. <template #default="scope">
  49. <dict-tag :type="DICT_TYPE.MENDUNER_JOB_TYPE" :value="scope.row.type" />
  50. </template>
  51. </el-table-column>
  52. <el-table-column label="要求学历" align="center" prop="eduType">
  53. <template #default="scope">
  54. <dict-tag v-if="scope.row.eduType" :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="scope.row.eduType" />
  55. <el-tag v-else>学历不限</el-tag>
  56. </template>
  57. </el-table-column>
  58. <el-table-column label="工作经验" align="center" prop="expType">
  59. <template #default="scope">
  60. <dict-tag v-if="scope.row.expType" :type="DICT_TYPE.MENDUNER_EXP_TYPE" :value="scope.row.expType" />
  61. <el-tag v-else>经验不限</el-tag>
  62. </template>
  63. </el-table-column>
  64. <el-table-column label="职位状态" align="center" prop="status">
  65. <template #default="scope">
  66. <el-tag v-if="scope.row.status === '99'" type="warning">待支付</el-tag>
  67. <dict-tag v-else :type="DICT_TYPE.MENDUNER_STATUS" :value="scope.row.status" />
  68. </template>
  69. </el-table-column>
  70. <el-table-column label="刷新时间" align="center" prop="updateTime" width="180px">
  71. <template #default="scope">
  72. {{ timesTampChange(scope.row.updateTime, 'Y-M-D h:m') }}
  73. </template>
  74. </el-table-column>
  75. <el-table-column label="操作" align="center">
  76. <template #default="scope">
  77. <el-button link type="primary" @click="openDetail(scope.row)">详情</el-button>
  78. <el-button link type="primary" @click="handleActions(scope.row.id, 0)">刷新</el-button>
  79. <el-button link type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
  80. <el-button v-if="scope.row.status === '1'" link type="success" @click="handleActions(scope.row.id, 1)">开启</el-button>
  81. <el-button v-if="scope.row.status === '0'" link type="danger" @click="handleActions(scope.row.id, 2)">关闭</el-button>
  82. </template>
  83. </el-table-column>
  84. </el-table>
  85. <Pagination
  86. :total="total"
  87. v-model:page="queryParams.pageNo"
  88. v-model:limit="queryParams.pageSize"
  89. @pagination="getList"
  90. />
  91. <Dialog title="职位详情" v-model="dialogVisible" class="!w-60%">
  92. <el-descriptions :column="2" border>
  93. <el-descriptions-item label="职位名称">{{ formatName(itemData.name) }}</el-descriptions-item>
  94. <el-descriptions-item label="招聘会">{{ itemData.jobFairName }}</el-descriptions-item>
  95. <el-descriptions-item label="职位类型">{{ itemData.positionName }}</el-descriptions-item>
  96. <el-descriptions-item label="地区">{{ !itemData.areaId ? '全国' : itemData.areaName }}</el-descriptions-item>
  97. <el-descriptions-item label="详细地址">{{ itemData.address }}</el-descriptions-item>
  98. <el-descriptions-item label="薪资">
  99. <span v-if="itemData.payFrom && itemData.payTo">
  100. {{ itemData.payFrom }} - {{ itemData.payTo }}/{{ payUnit.find(e => e.value === Number(itemData.payUnit))?.label }}
  101. </span>
  102. <span v-else>面议</span>
  103. </el-descriptions-item>
  104. <el-descriptions-item label="招聘类型">
  105. <dict-tag :type="DICT_TYPE.MENDUNER_JOB_TYPE" :value="itemData.type" />
  106. </el-descriptions-item>
  107. <el-descriptions-item label="学历要求">
  108. <dict-tag v-if="itemData.eduType" :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="itemData.eduType" />
  109. <el-tag v-else>学历不限</el-tag>
  110. </el-descriptions-item>
  111. <el-descriptions-item label="工作经验">
  112. <dict-tag v-if="itemData.expType" :type="DICT_TYPE.MENDUNER_EXP_TYPE" :value="itemData.expType" />
  113. <el-tag v-else>经验不限</el-tag>
  114. </el-descriptions-item>
  115. <el-descriptions-item label="职位状态">
  116. <el-tag v-if="itemData.status === '99'" type="warning">待支付</el-tag>
  117. <dict-tag v-else :type="DICT_TYPE.MENDUNER_STATUS" :value="itemData.status" />
  118. </el-descriptions-item>
  119. <el-descriptions-item label="发布时间">{{ timesTampChange(itemData.createTime) }}</el-descriptions-item>
  120. <el-descriptions-item label="刷新时间">{{ timesTampChange(itemData.updateTime) }}</el-descriptions-item>
  121. </el-descriptions>
  122. <el-descriptions :column="1" border>
  123. <el-descriptions-item label="职位关键字">
  124. <el-tag type="primary" v-for="k in itemData.tagList" :key="k" class="m-r-5px">{{ k }}</el-tag>
  125. </el-descriptions-item>
  126. <el-descriptions-item label="岗位职责">
  127. <div v-html="cleanedHtml(itemData.content)"></div>
  128. </el-descriptions-item>
  129. <el-descriptions-item label="岗位要求">
  130. <div v-html="cleanedHtml(itemData.requirement)"></div>
  131. </el-descriptions-item>
  132. </el-descriptions>
  133. <template #footer>
  134. <el-button @click="dialogVisible = false; itemData = {}">取 消</el-button>
  135. </template>
  136. </Dialog>
  137. </template>
  138. <script setup>
  139. defineOptions({ name: 'EnterpriseUserList'})
  140. import { EnterpriseApi } from '@/api/menduner/system/enterprise/message'
  141. import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  142. import { dealDictArrayData } from '@/utils/transform/position'
  143. import { timesTampChange } from '@/utils/transform/date'
  144. import { formatName } from '@/utils'
  145. import { JobFairManageApi } from '@/api/menduner/system/jobFair/manage'
  146. const props = defineProps({
  147. id: String
  148. })
  149. const { t } = useI18n() // 国际化
  150. const message = useMessage() // 消息弹窗
  151. const loading = ref(false)
  152. const tableData = ref([])
  153. const total = ref(0)
  154. const queryParams = reactive({
  155. pageNo: 1,
  156. pageSize: 10,
  157. name: undefined,
  158. fairId: undefined,
  159. enterpriseId: props.id
  160. })
  161. const payUnit = getIntDictOptions(DICT_TYPE.MENDUNER_PAY_UNIT)
  162. const dialogVisible = ref(false)
  163. const itemData = ref({})
  164. // 职位列表
  165. const getList = async () => {
  166. loading.value = true
  167. try {
  168. const data = await EnterpriseApi.getEnterpriseJobPage(queryParams)
  169. tableData.value = dealDictArrayData([], data.list)
  170. total.value = data.total
  171. } finally {
  172. loading.value = false
  173. }
  174. }
  175. getList()
  176. const handleRefresh = () => {
  177. queryParams.pageNo = 1
  178. getList()
  179. }
  180. // 获取招聘会列表
  181. const jobFairTotal = ref(0)
  182. const pageInfo = ref({
  183. pageNo: 1,
  184. pageSize: 10
  185. })
  186. const jobFairList = ref([])
  187. const getJobFairList = async () => {
  188. try {
  189. const data = await JobFairManageApi.getJobFairPage(pageInfo.value)
  190. jobFairList.value = jobFairList.value.concat(data.list)
  191. jobFairTotal.value = data.total
  192. } catch {}
  193. }
  194. getJobFairList()
  195. const handleGetMore = () => {
  196. pageInfo.value.pageNo++
  197. getJobFairList()
  198. }
  199. // 职位刷新、开启、关闭
  200. const arr = [
  201. { api: EnterpriseApi.refreshEnterpriseJob, label: '刷新' },
  202. { api: EnterpriseApi.openEnterpriseJob, label: '开启' },
  203. { api: EnterpriseApi.closeEnterpriseJob, label: '关闭' }
  204. ]
  205. const handleActions = async (id, index) => {
  206. const obj = arr[index]
  207. if (!obj || !id) return
  208. try {
  209. await message.confirm(`确定${obj.label}该职位吗?`)
  210. await obj.api([id])
  211. message.success(obj.label + '成功')
  212. // 刷新列表
  213. await getList()
  214. } catch {}
  215. }
  216. // 富文本去除空格、换行、空标签
  217. const cleanedHtml = (text) => {
  218. let cleaned = text.replace(/\n/g, '</br>')
  219. cleaned = cleaned.replace(/\s+/g, ' ').trim()
  220. cleaned = cleaned.replace(/(^|\s+)<\/p>(\s*<p>|$)/g, '</p><p>').trim()
  221. cleaned = cleaned.replace(/<p>\s*(<br>)\s*<\/p>/g, '')
  222. cleaned = cleaned.replace(/<p>\s*(<\/br>)\s*<\/p>/g, '')
  223. return cleaned
  224. }
  225. // 职位详情
  226. const openDetail = (item) => {
  227. itemData.value = item
  228. dialogVisible.value = true
  229. }
  230. /** 删除按钮操作 */
  231. const handleDelete = async (id) => {
  232. try {
  233. // 删除的二次确认
  234. await message.delConfirm()
  235. // 发起删除
  236. await EnterpriseApi.deleteJob(id)
  237. message.success(t('common.delSuccess'))
  238. // 刷新列表
  239. await getList()
  240. } catch {}
  241. }
  242. </script>
  243. <style scoped lang="scss">
  244. :deep(.el-descriptions__label.el-descriptions__cell.is-bordered-label) {
  245. width: 100px;
  246. }
  247. </style>