|
|
@@ -0,0 +1,371 @@
|
|
|
+<script setup>
|
|
|
+import {onMounted, reactive, ref} from 'vue'
|
|
|
+import {ElMessage, ElMessageBox} from 'element-plus'
|
|
|
+import {Edit, Plus, Trash2} from 'lucide-vue-next'
|
|
|
+import request from '@/utils/request.js'
|
|
|
+
|
|
|
+// 响应式数据
|
|
|
+const jobs = ref([])
|
|
|
+const total = ref(0)
|
|
|
+const dialogVisible = ref(false)
|
|
|
+const detailVisible = ref(false)
|
|
|
+const isEdit = ref(false)
|
|
|
+const loading = ref(false)
|
|
|
+const selectedJob = ref(null)
|
|
|
+const formRef = ref()
|
|
|
+const currentPage = ref(1)
|
|
|
+const pageSize = ref(10)
|
|
|
+
|
|
|
+// 批量选择
|
|
|
+const selectedJobIds = ref([])
|
|
|
+
|
|
|
+// 表单数据
|
|
|
+const formData = reactive({
|
|
|
+ id: '',
|
|
|
+ jobOpenings: '',
|
|
|
+ keyTerms: '',
|
|
|
+ jobRequirements: '',
|
|
|
+ numberRecruits: '',
|
|
|
+ salary: '',
|
|
|
+ workLocation: '',
|
|
|
+ contact: '',
|
|
|
+ contactInformation: '',
|
|
|
+ remarks: ''
|
|
|
+})
|
|
|
+
|
|
|
+// 表单验证规则
|
|
|
+const rules = {
|
|
|
+ jobOpenings: [{ required: true, message: '请输入招聘岗位', trigger: 'blur' }],
|
|
|
+ keyTerms: [{ required: true, message: '请输入关键词条', trigger: 'blur' }],
|
|
|
+ jobRequirements: [{ required: true, message: '请输入招聘详情', trigger: 'blur' }],
|
|
|
+ numberRecruits: [{ required: true, message: '请输入招聘人数', trigger: 'blur' }],
|
|
|
+ salary: [{ required: true, message: '请输入薪资', trigger: 'blur' }],
|
|
|
+ workLocation: [{ required: true, message: '请输入工作地点', trigger: 'blur' }],
|
|
|
+ contact: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
|
|
+ contactInformation: [{ required: true, message: '请输入联系方式', trigger: 'blur' }]
|
|
|
+}
|
|
|
+
|
|
|
+// 获取数据
|
|
|
+const getList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await request.get('/smartEmployment/findByPage', {
|
|
|
+ params: {
|
|
|
+ pageNum: currentPage.value,
|
|
|
+ pageSize: pageSize.value
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (res.code !== 200) {
|
|
|
+ ElMessage.error(res.msg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ jobs.value = res.data.records || []
|
|
|
+ total.value = res.data.total || 0
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('获取数据失败')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 打开新增对话框
|
|
|
+const openAddDialog = () => {
|
|
|
+ isEdit.value = false
|
|
|
+ resetForm()
|
|
|
+ dialogVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+// 编辑职位
|
|
|
+const editJob = async (job) => {
|
|
|
+ isEdit.value = true
|
|
|
+ try {
|
|
|
+ const res = await request.get(`/smartEmployment/getById/${job.id}`)
|
|
|
+ if (res.code !== 200) {
|
|
|
+ ElMessage.error(res.msg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ Object.assign(formData, res.data)
|
|
|
+ dialogVisible.value = true
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('获取职位详情失败')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 删除职位
|
|
|
+const deleteJob = async (id) => {
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm('确定要删除这个职位吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ const res = await request.post('/smartEmployment/deleteBatch', [id])
|
|
|
+ if (res.code !== 200) {
|
|
|
+ ElMessage.error(res.msg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ElMessage.success('删除成功')
|
|
|
+ getList()
|
|
|
+ } catch (error) {
|
|
|
+ if (error !== 'cancel') {
|
|
|
+ ElMessage.error('删除失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 批量删除
|
|
|
+const deleteSelectedJobs = async () => {
|
|
|
+ if (selectedJobIds.value.length === 0) {
|
|
|
+ ElMessage.warning('请先选择要删除的职位')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(`确定要删除选中的 ${selectedJobIds.value.length} 个职位吗?`, '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ const res = await request.post('/smartEmployment/deleteBatch', selectedJobIds.value)
|
|
|
+ if (res.code !== 200) {
|
|
|
+ ElMessage.error(res.msg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ElMessage.success('批量删除成功')
|
|
|
+ selectedJobIds.value = []
|
|
|
+ getList()
|
|
|
+ } catch (error) {
|
|
|
+ if (error !== 'cancel') {
|
|
|
+ ElMessage.error('批量删除失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 提交表单
|
|
|
+const handleSubmit = async () => {
|
|
|
+ if (!formRef.value) return
|
|
|
+ try {
|
|
|
+ await formRef.value.validate()
|
|
|
+ loading.value = true
|
|
|
+ let success = false
|
|
|
+ if (isEdit.value) {
|
|
|
+ success = await update(formData)
|
|
|
+ } else {
|
|
|
+ success = await add(formData)
|
|
|
+ }
|
|
|
+ if (success) {
|
|
|
+ dialogVisible.value = false
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('表单验证失败', error)
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const add = async (data) => {
|
|
|
+ try {
|
|
|
+ const res = await request.post('/smartEmployment/save', data)
|
|
|
+ if (res.code !== 200) {
|
|
|
+ ElMessage.error(res.msg)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ ElMessage.success(res.msg)
|
|
|
+ return true
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('添加失败')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const update = async (data) => {
|
|
|
+ try {
|
|
|
+ const res = await request.post('/smartEmployment/update', data)
|
|
|
+ if (res.code !== 200) {
|
|
|
+ ElMessage.error(res.msg)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ ElMessage.success(res.msg)
|
|
|
+ return true
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('更新失败')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 查看详情
|
|
|
+const viewJobDetail = (job) => {
|
|
|
+ selectedJob.value = job
|
|
|
+ detailVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const handleClose = () => {
|
|
|
+ dialogVisible.value = false
|
|
|
+ resetForm()
|
|
|
+}
|
|
|
+
|
|
|
+const resetForm = () => {
|
|
|
+ Object.keys(formData).forEach(key => {
|
|
|
+ formData[key] = ''
|
|
|
+ })
|
|
|
+ if (formRef.value) {
|
|
|
+ formRef.value.resetFields()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleSizeChange = (val) => {
|
|
|
+ pageSize.value = val
|
|
|
+ currentPage.value = 1
|
|
|
+ getList()
|
|
|
+}
|
|
|
+
|
|
|
+const handleCurrentChange = (val) => {
|
|
|
+ currentPage.value = val
|
|
|
+ getList()
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getList()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="min-h-screen bg-gray-50 p-6">
|
|
|
+ <div class="w-full mx-auto mb-6 bg-white p-4 rounded-lg shadow">
|
|
|
+ <el-button type="primary" @click="openAddDialog">
|
|
|
+ <Plus class="w-4 h-4 mr-1" /> 发布职位
|
|
|
+ </el-button>
|
|
|
+ <el-button type="danger" @click="deleteSelectedJobs">
|
|
|
+ <Trash2 class="w-4 h-4 mr-1" /> 批量删除
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 表格 -->
|
|
|
+ <div class="w-full mx-auto bg-white p-4 rounded-lg shadow">
|
|
|
+ <el-table
|
|
|
+ :data="jobs"
|
|
|
+ style="width: 100%"
|
|
|
+ @selection-change="(rows)=>selectedJobIds = rows.map(r=>r.id)"
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="55" />
|
|
|
+ <el-table-column prop="jobOpenings" label="岗位名称" width="150" />
|
|
|
+ <el-table-column prop="workLocation" label="工作地点" width="120" />
|
|
|
+ <el-table-column prop="salary" label="薪资" width="120" />
|
|
|
+ <el-table-column prop="numberRecruits" label="招聘人数" width="100" />
|
|
|
+ <el-table-column prop="contact" label="联系人" width="100" />
|
|
|
+ <el-table-column prop="contactInformation" label="联系方式" width="150" />
|
|
|
+ <el-table-column prop="keyTerms" label="关键词" />
|
|
|
+ <el-table-column label="操作" width="180">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button size="small" type="primary" text @click="editJob(scope.row)">
|
|
|
+ <Edit class="w-4 h-4" /> 编辑
|
|
|
+ </el-button>
|
|
|
+ <el-button size="small" type="danger" text @click="deleteJob(scope.row.id)">
|
|
|
+ <Trash2 class="w-4 h-4" /> 删除
|
|
|
+ </el-button>
|
|
|
+ <el-button size="small" type="info" text @click="viewJobDetail(scope.row)">
|
|
|
+ 详情
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <div class="flex justify-center mt-6">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="currentPage"
|
|
|
+ v-model:page-size="pageSize"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ :total="total"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleSizeChange"
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 添加/编辑对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="dialogVisible"
|
|
|
+ :title="isEdit ? '编辑职位' : '发布职位'"
|
|
|
+ width="600px"
|
|
|
+ :before-close="handleClose"
|
|
|
+ >
|
|
|
+ <el-form :model="formData" :rules="rules" ref="formRef" label-width="100px">
|
|
|
+ <el-form-item label="招聘岗位" prop="jobOpenings">
|
|
|
+ <el-input v-model="formData.jobOpenings" placeholder="请输入招聘岗位" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="关键词条" prop="keyTerms">
|
|
|
+ <el-input v-model="formData.keyTerms" placeholder="请输入关键词,用逗号分隔" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="招聘详情" prop="jobRequirements">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.jobRequirements"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入招聘详情"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="招聘人数" prop="numberRecruits">
|
|
|
+ <el-input v-model="formData.numberRecruits" placeholder="请输入招聘人数" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="薪资" prop="salary">
|
|
|
+ <el-input v-model="formData.salary" placeholder="请输入薪资" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="工作地点" prop="workLocation">
|
|
|
+ <el-input v-model="formData.workLocation" placeholder="请输入工作地点" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="联系人" prop="contact">
|
|
|
+ <el-input v-model="formData.contact" placeholder="请输入联系人" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="联系方式" prop="contactInformation">
|
|
|
+ <el-input v-model="formData.contactInformation" placeholder="请输入联系方式" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.remarks"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ placeholder="请输入备注信息"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button @click="dialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleSubmit" :loading="loading">
|
|
|
+ {{ isEdit ? '更新' : '发布' }}
|
|
|
+ </el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 职位详情对话框 -->
|
|
|
+ <el-dialog v-model="detailVisible" title="职位详情" width="700px">
|
|
|
+ <div v-if="selectedJob" class="space-y-4">
|
|
|
+ <div class="bg-gray-50 rounded-lg p-4">
|
|
|
+ <h3 class="text-xl font-bold text-gray-800 mb-2">{{ selectedJob.jobOpenings }}</h3>
|
|
|
+ <div class="grid grid-cols-2 gap-4 text-sm">
|
|
|
+ <div><strong>工作地点:</strong>{{ selectedJob.workLocation }}</div>
|
|
|
+ <div><strong>薪资:</strong>{{ selectedJob.salary }}</div>
|
|
|
+ <div><strong>招聘人数:</strong>{{ selectedJob.numberRecruits }}</div>
|
|
|
+ <div><strong>联系人:</strong>{{ selectedJob.contact }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h4 class="font-semibold mb-2">职位要求:</h4>
|
|
|
+ <p class="text-gray-700 leading-relaxed">{{ selectedJob.jobRequirements }}</p>
|
|
|
+ </div>
|
|
|
+ <div v-if="selectedJob.remarks">
|
|
|
+ <h4 class="font-semibold mb-2">备注:</h4>
|
|
|
+ <p class="text-gray-700">{{ selectedJob.remarks }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.dialog-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+</style>
|