wuzhen update招生就业
This commit is contained in:
1 parent
7e122d76dd
commit
e5c6fd7a24
55 files changed
+3563
-2397
No files matched your search
+102
-11
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* 企业信息管理 API
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-25
|
||||
* @date 2026-03-30
|
||||
*/
|
||||
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { EnterpriseVO, EnterpriseForm, EnterpriseQuery } from './types';
|
||||
import { EnterpriseVO, EnterpriseForm, EnterpriseQuery, EnterpriseJobForm, EnterpriseBrochureVO } from './types';
|
||||
|
||||
// TableDataInfo 接口定义
|
||||
export interface TableDataInfo<T> {
|
||||
@@ -19,7 +19,6 @@ export interface TableDataInfo<T> {
|
||||
/**
|
||||
* 查询企业信息列表
|
||||
* @param query 查询参数
|
||||
* @returns Promise<TableDataInfo<EnterpriseVO>>
|
||||
*/
|
||||
export function listEnterprise(query?: EnterpriseQuery): AxiosPromise<TableDataInfo<EnterpriseVO>> {
|
||||
return request({
|
||||
@@ -32,9 +31,8 @@ export function listEnterprise(query?: EnterpriseQuery): AxiosPromise<TableDataI
|
||||
/**
|
||||
* 查询企业信息详细
|
||||
* @param id 企业主键
|
||||
* @returns Promise<EnterpriseVO>
|
||||
*/
|
||||
export function getEnterprise(id: string | number): AxiosPromise<EnterpriseVO> {
|
||||
export function getEnterprise(id: string | number): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/zsjy/enterprise/${id}`,
|
||||
method: 'get'
|
||||
@@ -42,9 +40,8 @@ export function getEnterprise(id: string | number): AxiosPromise<EnterpriseVO> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增企业信息
|
||||
* 新增企业信息(含岗位)
|
||||
* @param data 企业信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
export function addEnterprise(data: EnterpriseForm): AxiosPromise<any> {
|
||||
return request({
|
||||
@@ -55,9 +52,8 @@ export function addEnterprise(data: EnterpriseForm): AxiosPromise<any> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改企业信息
|
||||
* 修改企业信息(含岗位)
|
||||
* @param data 企业信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
export function updateEnterprise(data: EnterpriseForm): AxiosPromise<any> {
|
||||
return request({
|
||||
@@ -70,7 +66,6 @@ export function updateEnterprise(data: EnterpriseForm): AxiosPromise<any> {
|
||||
/**
|
||||
* 删除企业信息
|
||||
* @param id 企业主键
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
export function delEnterprise(id: string | number | Array<string | number>): AxiosPromise<any> {
|
||||
return request({
|
||||
@@ -82,7 +77,6 @@ export function delEnterprise(id: string | number | Array<string | number>): Axi
|
||||
/**
|
||||
* 导出企业信息
|
||||
* @param query 查询参数
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
export function exportEnterprise(query: EnterpriseQuery): AxiosPromise<any> {
|
||||
return request({
|
||||
@@ -92,3 +86,100 @@ export function exportEnterprise(query: EnterpriseQuery): AxiosPromise<any> {
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取企业下拉选项
|
||||
*/
|
||||
export function listEnterpriseOptions(): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/zsjy/enterprise/options',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载导入模板
|
||||
*/
|
||||
export function getImportTemplate(): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/zsjy/enterprise/importTemplate',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入企业信息
|
||||
* @param file Excel文件
|
||||
* @param updateSupport 是否支持更新(同名覆盖)
|
||||
*/
|
||||
export function importEnterprise(file: File, updateSupport: boolean = false): AxiosPromise<any> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('updateSupport', String(updateSupport));
|
||||
return request({
|
||||
url: '/zsjy/enterprise/importData',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成招聘简章PDF(单个)
|
||||
* @param enterpriseId 企业ID
|
||||
*/
|
||||
export function generateBrochure(enterpriseId: number | string): AxiosPromise<EnterpriseBrochureVO> {
|
||||
return request({
|
||||
url: `/zsjy/enterprise/brochure/${enterpriseId}`,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量生成招聘简章PDF
|
||||
* @param enterpriseIds 企业ID列表(逗号分隔)
|
||||
*/
|
||||
export function generateBrochureBatch(enterpriseIds: string): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/zsjy/enterprise/brochure/batch/${enterpriseIds}`,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新简章信息
|
||||
* @param enterpriseId 企业ID
|
||||
*/
|
||||
export function getBrochure(enterpriseId: number | string): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/zsjy/enterprise/brochure/${enterpriseId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载招聘简章PDF(通过企业ID)
|
||||
* @param enterpriseId 企业ID
|
||||
*/
|
||||
export function downloadBrochure(enterpriseId: number | string): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/zsjy/enterprise/brochure/download/${enterpriseId}`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载招聘简章PDF(通过简章记录ID)
|
||||
* @param id 简章记录ID
|
||||
*/
|
||||
export function downloadBrochureById(id: number | string): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/zsjy/enterprise/brochure/downloadById/${id}`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
+46
-1737
File diff suppressed because it is too large.
Load diff
@@ -248,17 +248,22 @@ service.interceptors.response.use(
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
// 通用下载方法
|
||||
export function download(url: string, params: any, fileName: string) {
|
||||
// 通用下载方法(支持GET和POST)
|
||||
export function download(url: string, params: any, fileName: string, method: string = 'post') {
|
||||
downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
|
||||
const isGet = method.toLowerCase() === 'get';
|
||||
// prettier-ignore
|
||||
return service.post(url, params, {
|
||||
transformRequest: [
|
||||
return service({
|
||||
url: url,
|
||||
method: method,
|
||||
params: isGet ? params : undefined,
|
||||
data: isGet ? undefined : params,
|
||||
transformRequest: isGet ? undefined : [
|
||||
(params: any) => {
|
||||
return tansParams(params);
|
||||
}
|
||||
],
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
headers: isGet ? undefined : { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
responseType: 'blob',
|
||||
timeout: 1200000 // 导出接口单独设置20分钟超时
|
||||
}).then(async (resp: any) => {
|
||||
|
||||
@@ -63,6 +63,12 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button icon="Download" @click="handleExport" v-hasPermi="['zsjy:enterprise:export']">导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button icon="Upload" @click="showImportDialog = true" v-hasPermi="['zsjy:enterprise:import']">导入</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button icon="Document" :disabled="multiple" type="success" @click="handleGenerateBrochureBatch" v-hasPermi="['zsjy:enterprise:brochure']">批量生成简章</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
@@ -83,15 +89,18 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="联系人" align="center" prop="contactName" width="100" show-overflow-tooltip />
|
||||
<el-table-column label="联系电话" align="center" prop="contactPhone" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="企业邮箱" align="center" prop="email" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="企业地址" align="center" prop="address" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="岗位数量" align="center" prop="jobCount" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag type="primary" effect="plain">{{ scope.row.jobCount || 0 }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status" width="80">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="320" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看" placement="top">
|
||||
<el-button
|
||||
@@ -115,6 +124,17 @@
|
||||
v-hasPermi="['zsjy:enterprise:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="生成简章" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="success"
|
||||
icon="Document"
|
||||
size="default"
|
||||
style="font-size: 16px; margin-right: 8px"
|
||||
@click="handleGenerateBrochure(scope.row)"
|
||||
v-hasPermi="['zsjy:enterprise:brochure']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button
|
||||
link
|
||||
@@ -137,52 +157,74 @@
|
||||
</el-card>
|
||||
|
||||
<!-- 添加或修改企业信息对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="1000px" append-to-body>
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="1100px" append-to-body class="enterprise-dialog">
|
||||
<el-form ref="enterpriseFormRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-divider content-position="left">企业基本信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="企业名称" prop="enterpriseName">
|
||||
<el-input v-model="form.enterpriseName" placeholder="请输入企业名称" />
|
||||
<el-input v-model="form.enterpriseName" placeholder="请输入企业名称" maxlength="200" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属行业" prop="industry">
|
||||
<el-select v-model="form.industry" placeholder="请选择所属行业" style="width: 100%">
|
||||
<el-select v-model="form.industry" placeholder="请选择所属行业" clearable style="width: 100%">
|
||||
<el-option v-for="dict in zsjy_enterprise_industry" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人姓名" prop="contactName">
|
||||
<el-input v-model="form.contactName" placeholder="请输入联系人姓名" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="办公电话" prop="officePhone">
|
||||
<el-input v-model="form.officePhone" placeholder="请输入办公电话" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="电子邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入电子邮箱" maxlength="100" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="企业地址" prop="address">
|
||||
<el-input v-model="form.address" placeholder="请输入企业地址" maxlength="255" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="企业简介" prop="enterpriseIntro">
|
||||
<el-input v-model="form.enterpriseIntro" type="textarea" placeholder="请输入企业简介(用于招聘简章展示)" :rows="4" maxlength="1500" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="企业规模" prop="enterpriseScale">
|
||||
<el-select v-model="form.enterpriseScale" placeholder="请选择企业规模" style="width: 100%">
|
||||
<el-select v-model="form.enterpriseScale" placeholder="请选择企业规模" clearable style="width: 100%">
|
||||
<el-option v-for="dict in zsjy_enterprise_scale" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人姓名" prop="contactName">
|
||||
<el-input v-model="form.contactName" placeholder="请输入联系人姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="企业邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入企业邮箱" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
@@ -192,30 +234,42 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="企业地址" prop="address">
|
||||
<el-input v-model="form.address" placeholder="请输入企业地址" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 岗位信息区域 -->
|
||||
<el-divider content-position="left">
|
||||
招聘岗位信息
|
||||
<el-button type="primary" link icon="Plus" style="margin-left: 8px" @click="handleAddJob">添加岗位</el-button>
|
||||
</el-divider>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="主营业务" prop="mainBusiness">
|
||||
<el-input v-model="form.mainBusiness" type="textarea" placeholder="请输入主营业务" :autosize="{ minRows: 3, maxRows: 5 }" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注信息" :autosize="{ minRows: 2, maxRows: 4 }" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="job-table-container">
|
||||
<el-table :data="form.jobList" border style="width: 100%" size="small">
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="岗位名称" min-width="150">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.positionName" placeholder="请输入岗位名称" maxlength="100" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="岗位要求" min-width="200">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.requirements" type="textarea" placeholder="请输入岗位要求" :rows="2" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="待遇" min-width="200">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.benefits" type="textarea" placeholder="请输入待遇信息" :rows="2" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="danger" icon="Delete" @click="handleRemoveJob(scope.$index)" :disabled="form.jobList.length <= 1">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="!form.jobList || form.jobList.length === 0" class="empty-job-tip">
|
||||
暂无岗位信息,点击上方「添加岗位」按钮新增
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
@@ -236,27 +290,135 @@
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联系人姓名">{{ viewForm.contactName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ viewForm.contactPhone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="企业邮箱">{{ viewForm.email }}</el-descriptions-item>
|
||||
<el-descriptions-item label="办公电话">{{ viewForm.officePhone || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="电子邮箱">{{ viewForm.email }}</el-descriptions-item>
|
||||
<el-descriptions-item label="企业地址" span="2">{{ viewForm.address }}</el-descriptions-item>
|
||||
<el-descriptions-item label="主营业务" span="2">{{ viewForm.mainBusiness }}</el-descriptions-item>
|
||||
<el-descriptions-item label="企业简介" span="2">{{ viewForm.enterpriseIntro || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<dict-tag :options="sys_normal_disable" :value="viewForm.status" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ viewForm.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" span="2">{{ viewForm.remark || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 岗位信息展示 -->
|
||||
<el-divider content-position="left">招聘岗位信息</el-divider>
|
||||
<el-table v-if="viewForm.jobList && viewForm.jobList.length > 0" :data="viewForm.jobList" border size="small">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="positionName" label="岗位名称" min-width="150" />
|
||||
<el-table-column prop="requirements" label="岗位要求" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="benefits" label="待遇" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="status" label="状态" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-else description="暂无岗位信息" :image-size="60" />
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="success" icon="Document" @click="handleViewGenerateBrochure(viewForm)" v-hasPermi="['zsjy:enterprise:brochure']">生成简章</el-button>
|
||||
<el-button @click="viewDialog.visible = false">关 闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 导入对话框 -->
|
||||
<el-dialog title="导入企业信息" v-model="showImportDialog" width="500px" append-to-body>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
class="upload-demo"
|
||||
drag
|
||||
:limit="1"
|
||||
accept=".xlsx, .xls"
|
||||
:auto-upload="false"
|
||||
:headers="uploadHeaders"
|
||||
:action="importUrl"
|
||||
:disabled="importLoading"
|
||||
:on-progress="handleImportProgress"
|
||||
:on-success="handleImportSuccess"
|
||||
:on-error="handleImportError"
|
||||
>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将Excel文件拖到此处,或<em>点击上传</em></div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
<el-checkbox v-model="importUpdateSupport" />是否更新已存在的企业数据
|
||||
<br />
|
||||
仅支持 .xlsx 和 .xls 格式,<el-link type="primary" :underline="false" @click="handleDownloadTemplate">下载模板</el-link>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" :loading="importLoading" @click="submitImport">确 定</el-button>
|
||||
<el-button @click="showImportDialog = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 简章生成/预览对话框 -->
|
||||
<el-dialog
|
||||
title="招聘简章"
|
||||
v-model="brochureDialog.visible"
|
||||
width="900px"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<div class="brochure-actions">
|
||||
<el-button type="success" icon="Download" @click="handleDownloadBrochure" :loading="brochureLoading">下载PDF</el-button>
|
||||
<el-button icon="Refresh" @click="handleReGenerateBrochure" :loading="brochureLoading">重新生成</el-button>
|
||||
</div>
|
||||
<div v-if="brochureDialog.brochureInfo" class="brochure-info">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="企业名称">{{ brochureDialog.brochureInfo.enterpriseName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="生成人">{{ brochureDialog.brochureInfo.generateByName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="生成时间" :span="2">{{ brochureDialog.brochureInfo.generateTime }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<!-- PDF预览区 -->
|
||||
<div class="pdf-preview-wrapper">
|
||||
<div v-if="brochureLoading && !brochureDialog.previewUrl" class="pdf-loading">
|
||||
<el-icon class="is-loading"><Loading /></el-icon>
|
||||
<span>加载中...</span>
|
||||
</div>
|
||||
<iframe
|
||||
v-else-if="brochureDialog.previewUrl"
|
||||
:src="brochureDialog.previewUrl"
|
||||
class="pdf-iframe"
|
||||
title="招聘简章预览"
|
||||
/>
|
||||
<div v-else class="pdf-empty">暂无预览,请先生成简章</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="brochureDialog.visible = false">关 闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Enterprise" lang="ts">
|
||||
import { listEnterprise, getEnterprise, delEnterprise, addEnterprise, updateEnterprise } from '@/api/zsjy/enterprise';
|
||||
import { EnterpriseVO, EnterpriseForm, EnterpriseQuery } from '@/api/zsjy/types';
|
||||
import {
|
||||
listEnterprise,
|
||||
getEnterprise,
|
||||
delEnterprise,
|
||||
addEnterprise,
|
||||
updateEnterprise,
|
||||
exportEnterprise,
|
||||
importEnterprise,
|
||||
getImportTemplate,
|
||||
generateBrochure,
|
||||
getBrochure,
|
||||
downloadBrochure
|
||||
} from '@/api/zsjy/enterprise';
|
||||
import { Loading } from '@element-plus/icons-vue';
|
||||
import { EnterpriseVO, EnterpriseJobForm } from '@/api/zsjy/types';
|
||||
import request from '@/utils/request';
|
||||
import { globalHeaders } from '@/utils/request';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@@ -268,6 +430,28 @@ const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const importLoading = ref(false);
|
||||
const brochureLoading = ref(false);
|
||||
|
||||
// 导入相关
|
||||
const showImportDialog = ref(false);
|
||||
const importUpdateSupport = ref(false);
|
||||
const uploadRef = ref();
|
||||
const importUrl = computed(() => import.meta.env.VITE_APP_BASE_API + '/zsjy/enterprise/importData?updateSupport=' + importUpdateSupport.value);
|
||||
const uploadHeaders = globalHeaders();
|
||||
|
||||
// 简章相关
|
||||
const brochureDialog = reactive<{
|
||||
visible: boolean;
|
||||
enterpriseId: any;
|
||||
brochureInfo: any;
|
||||
previewUrl: string | null;
|
||||
}>({
|
||||
visible: false,
|
||||
enterpriseId: null,
|
||||
brochureInfo: null,
|
||||
previewUrl: null
|
||||
});
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const enterpriseFormRef = ref<ElFormInstance>();
|
||||
@@ -277,21 +461,25 @@ const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'))
|
||||
const { zsjy_enterprise_industry } = toRefs<any>(proxy?.useDict('zsjy_enterprise_industry'));
|
||||
const { zsjy_enterprise_scale } = toRefs<any>(proxy?.useDict('zsjy_enterprise_scale'));
|
||||
|
||||
const initFormData: EnterpriseForm = {
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
enterpriseName: '',
|
||||
industry: '',
|
||||
mainBusiness: '',
|
||||
enterpriseScale: '',
|
||||
enterpriseIntro: '',
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
officePhone: '',
|
||||
email: '',
|
||||
website: '',
|
||||
address: '',
|
||||
status: '0',
|
||||
remark: ''
|
||||
remark: '',
|
||||
jobList: [] as EnterpriseJobForm[]
|
||||
};
|
||||
|
||||
const data = reactive<PageData<EnterpriseForm, EnterpriseQuery>>({
|
||||
const data = reactive<PageData<typeof initFormData, any>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
@@ -303,20 +491,16 @@ const data = reactive<PageData<EnterpriseForm, EnterpriseQuery>>({
|
||||
},
|
||||
rules: {
|
||||
enterpriseName: [{ required: true, message: '企业名称不能为空', trigger: 'blur' }],
|
||||
industry: [{ required: true, message: '所属行业不能为空', trigger: 'change' }],
|
||||
mainBusiness: [{ required: true, message: '主营业务不能为空', trigger: 'blur' }],
|
||||
enterpriseScale: [{ required: true, message: '企业规模不能为空', trigger: 'change' }],
|
||||
contactName: [{ required: true, message: '联系人姓名不能为空', trigger: 'blur' }],
|
||||
contactPhone: [
|
||||
{ required: true, message: '联系电话不能为空', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
],
|
||||
email: [
|
||||
{ required: true, message: '企业邮箱不能为空', trigger: 'blur' },
|
||||
{ required: true, message: '电子邮箱不能为空', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
|
||||
],
|
||||
address: [{ required: true, message: '企业地址不能为空', trigger: 'blur' }],
|
||||
status: [{ required: true, message: '状态不能为空', trigger: 'change' }]
|
||||
address: [{ required: true, message: '企业地址不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
@@ -338,10 +522,13 @@ const viewForm = ref<EnterpriseVO>({} as EnterpriseVO);
|
||||
/** 查询企业信息列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listEnterprise(queryParams.value);
|
||||
enterpriseList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
try {
|
||||
const res = await listEnterprise(queryParams.value);
|
||||
enterpriseList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
@@ -352,7 +539,7 @@ const cancel = () => {
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
form.value = { ...initFormData, jobList: [] };
|
||||
enterpriseFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
@@ -380,16 +567,28 @@ const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '添加企业信息';
|
||||
// 初始化至少一个空岗位行
|
||||
form.value.jobList = [{ positionName: '', requirements: '', benefits: '', status: '0' }];
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: EnterpriseVO) => {
|
||||
reset();
|
||||
const id = row?.id || ids.value[0];
|
||||
const res = await getEnterprise(id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改企业信息';
|
||||
loading.value = true;
|
||||
try {
|
||||
reset();
|
||||
const id = row?.id || ids.value[0];
|
||||
const res = await getEnterprise(id);
|
||||
// 显式设置 jobList,避免 Object.assign 后 jobList 被其他引用污染
|
||||
Object.assign(form.value, res.data, { jobList: res.data.jobList || [] });
|
||||
// 确保岗位列表不为空(至少有一行空岗位方便用户继续添加)
|
||||
if (!form.value.jobList || form.value.jobList.length === 0) {
|
||||
form.value.jobList = [{ positionName: '', requirements: '', benefits: '', status: '0' }];
|
||||
}
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改企业信息';
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 查看详情 */
|
||||
@@ -399,27 +598,51 @@ const handleView = async (row: EnterpriseVO) => {
|
||||
viewDialog.visible = true;
|
||||
};
|
||||
|
||||
/** 添加岗位 */
|
||||
const handleAddJob = () => {
|
||||
if (!form.value.jobList) {
|
||||
form.value.jobList = [];
|
||||
}
|
||||
form.value.jobList.push({ positionName: '', requirements: '', benefits: '', status: '0' });
|
||||
};
|
||||
|
||||
/** 删除岗位 */
|
||||
const handleRemoveJob = (index: number) => {
|
||||
if (form.value.jobList && form.value.jobList.length > 1) {
|
||||
form.value.jobList.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
enterpriseFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
await updateEnterprise(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addEnterprise(form.value).finally(() => (buttonLoading.value = false));
|
||||
try {
|
||||
// 过滤掉空岗位(岗位名称为空的不提交)
|
||||
const validJobList = (form.value.jobList || []).filter((job) => job.positionName && job.positionName.trim() !== '');
|
||||
const submitData = { ...form.value, jobList: validJobList };
|
||||
|
||||
if (form.value.id) {
|
||||
await updateEnterprise(submitData);
|
||||
proxy?.$modal.msgSuccess('修改成功');
|
||||
} else {
|
||||
await addEnterprise(submitData);
|
||||
proxy?.$modal.msgSuccess('新增成功');
|
||||
}
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: EnterpriseVO) => {
|
||||
const idList = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除企业信息编号为"' + idList + '"的数据项?');
|
||||
const idList = row?.id ? [row.id] : ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除选中的企业信息?删除后将同时删除关联的岗位信息。');
|
||||
await delEnterprise(idList);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
@@ -427,13 +650,271 @@ const handleDelete = async (row?: EnterpriseVO) => {
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'zsjy/enterprise/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`enterprise_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
proxy?.download('zsjy/enterprise/export', { ...queryParams.value }, `enterprise_${new Date().getTime()}.xlsx`);
|
||||
};
|
||||
|
||||
/** 下载导入模板 */
|
||||
const handleDownloadTemplate = () => {
|
||||
proxy?.download('zsjy/enterprise/importTemplate', {}, 'enterprise_import_template.xlsx', 'GET');
|
||||
};
|
||||
|
||||
/** 提交导入 */
|
||||
const submitImport = () => {
|
||||
if (!uploadRef.value) {
|
||||
proxy?.$modal.msgError('上传组件未初始化');
|
||||
return;
|
||||
}
|
||||
importLoading.value = true;
|
||||
uploadRef.value?.submit();
|
||||
};
|
||||
|
||||
/** 导入文件上传中 */
|
||||
const handleImportProgress = () => {
|
||||
importLoading.value = true;
|
||||
};
|
||||
|
||||
/** 导入文件上传成功 */
|
||||
const handleImportSuccess = (response: any) => {
|
||||
importLoading.value = false;
|
||||
showImportDialog.value = false;
|
||||
proxy?.$modal.msgSuccess(response.msg || '导入成功');
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 导入文件上传失败 */
|
||||
const handleImportError = (err: any) => {
|
||||
importLoading.value = false;
|
||||
console.error('导入失败:', err);
|
||||
proxy?.$modal.msgError(err?.message || '导入失败');
|
||||
};
|
||||
|
||||
/** 生成简章(单个) */
|
||||
const handleGenerateBrochure = async (row: EnterpriseVO) => {
|
||||
brochureLoading.value = true;
|
||||
// 生成前清理旧预览
|
||||
if (brochureDialog.previewUrl) {
|
||||
window.URL.revokeObjectURL(brochureDialog.previewUrl);
|
||||
brochureDialog.previewUrl = null;
|
||||
}
|
||||
try {
|
||||
const res = await generateBrochure(row.id);
|
||||
brochureDialog.enterpriseId = row.id;
|
||||
brochureDialog.brochureInfo = res.data;
|
||||
brochureDialog.visible = true;
|
||||
// 生成成功后自动加载预览
|
||||
await loadBrochurePreview(row.id);
|
||||
proxy?.$modal.msgSuccess('简章生成成功');
|
||||
} catch (err: any) {
|
||||
proxy?.$modal.msgError(err?.msg || '生成失败');
|
||||
} finally {
|
||||
brochureLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 批量生成简章 */
|
||||
const handleGenerateBrochureBatch = async () => {
|
||||
if (ids.value.length === 0) {
|
||||
proxy?.$modal.msgWarning('请先选择要生成简章的企业');
|
||||
return;
|
||||
}
|
||||
await proxy?.$modal.confirm(`确认要批量生成 ${ids.value.length} 家企业的招聘简章吗?\n生成后将下载一个包含 ${ids.value.length} 页的多页PDF文件。`);
|
||||
brochureLoading.value = true;
|
||||
proxy?.$modal.loading('正在生成多页PDF,请稍候...');
|
||||
try {
|
||||
const response: any = await request({
|
||||
url: '/zsjy/enterprise/brochure/batch/download',
|
||||
method: 'post',
|
||||
data: ids.value,
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
});
|
||||
|
||||
proxy?.$modal.closeLoading();
|
||||
|
||||
// 处理响应
|
||||
if (!response) {
|
||||
throw new Error('下载响应为空');
|
||||
}
|
||||
|
||||
// 检查是否是 Blob 对象
|
||||
const blob = response instanceof Blob ? response : null;
|
||||
if (!blob) {
|
||||
throw new Error('下载响应格式错误');
|
||||
}
|
||||
|
||||
// 检查文件大小
|
||||
if (blob.size === 0) {
|
||||
throw new Error('下载文件为空');
|
||||
}
|
||||
|
||||
// 检查是否是 JSON 错误响应
|
||||
if (blob.type === 'application/json' || blob.type === 'text/plain') {
|
||||
const text = await blob.text();
|
||||
try {
|
||||
const json = JSON.parse(text);
|
||||
throw new Error(json.msg || '下载失败');
|
||||
} catch (e) {
|
||||
if (e.message !== '下载失败') {
|
||||
throw new Error('下载失败,请重试');
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// 下载文件
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `企业招聘简章_${new Date().getTime()}.pdf`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
proxy?.$modal.msgSuccess('批量生成成功,共下载 ' + ids.value.length + ' 页');
|
||||
} catch (err: any) {
|
||||
console.error('批量生成失败:', err);
|
||||
proxy?.$modal.msgError(err?.message || err?.msg || '批量生成失败');
|
||||
} finally {
|
||||
brochureLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 查看详情时生成简章 */
|
||||
const handleViewGenerateBrochure = async (row: EnterpriseVO) => {
|
||||
await handleGenerateBrochure(row);
|
||||
viewDialog.visible = false;
|
||||
};
|
||||
|
||||
/** 下载PDF */
|
||||
const handleDownloadBrochure = async () => {
|
||||
if (!brochureDialog.enterpriseId) return;
|
||||
|
||||
// 显示下载加载状态
|
||||
const loadingInstance = ElLoading.service({ text: '正在下载,请稍候...', background: 'rgba(0, 0, 0, 0.7)' });
|
||||
|
||||
try {
|
||||
// 使用API中已有的downloadBrochure函数,确保认证正确
|
||||
const blob: any = await downloadBrochure(brochureDialog.enterpriseId);
|
||||
|
||||
// 检查响应
|
||||
if (!blob) {
|
||||
throw new Error('下载响应为空');
|
||||
}
|
||||
|
||||
// 检查是否是 Blob 对象
|
||||
if (!(blob instanceof Blob)) {
|
||||
throw new Error('下载响应格式错误');
|
||||
}
|
||||
|
||||
// 检查文件大小
|
||||
if (blob.size === 0) {
|
||||
throw new Error('下载文件为空');
|
||||
}
|
||||
|
||||
// 检查是否是 JSON 错误响应
|
||||
if (blob.type === 'application/json' || (blob.type === 'text/plain')) {
|
||||
const text = await blob.text();
|
||||
try {
|
||||
const json = JSON.parse(text);
|
||||
throw new Error(json.msg || '下载失败');
|
||||
} catch {
|
||||
throw new Error('下载失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
// 下载文件
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `招聘简章_${brochureDialog.brochureInfo?.enterpriseName || '未知企业'}.pdf`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
proxy?.$modal.msgSuccess('下载成功');
|
||||
} catch (err: any) {
|
||||
console.error('下载PDF失败:', err);
|
||||
proxy?.$modal.msgError(err?.message || '下载失败');
|
||||
} finally {
|
||||
loadingInstance.close();
|
||||
}
|
||||
};
|
||||
|
||||
/** 加载简章预览 */
|
||||
const loadBrochurePreview = async (enterpriseId: any) => {
|
||||
if (!enterpriseId) return;
|
||||
brochureLoading.value = true;
|
||||
try {
|
||||
console.log('开始加载预览,企业ID:', enterpriseId);
|
||||
const response = await downloadBrochure(enterpriseId);
|
||||
|
||||
console.log('预览响应类型:', typeof response, 'response:', response);
|
||||
|
||||
// 检查响应
|
||||
if (!response) {
|
||||
console.error('预览响应为空');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否是 Blob 对象
|
||||
if (!(response instanceof Blob)) {
|
||||
console.error('预览响应不是Blob对象:', typeof response);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Blob大小:', response.size, '类型:', response.type);
|
||||
|
||||
// 检查文件大小
|
||||
if (response.size === 0) {
|
||||
console.error('预览文件为空');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否是 JSON 错误响应
|
||||
if (response.type === 'application/json' || response.type === 'text/plain') {
|
||||
const text = await response.text();
|
||||
console.error('服务端返回了JSON错误:', text);
|
||||
try {
|
||||
const json = JSON.parse(text);
|
||||
console.error('预览加载失败,服务端返回错误:', json.msg || json.message);
|
||||
} catch {
|
||||
console.error('预览加载失败,未知错误');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 清理旧的预览URL
|
||||
if (brochureDialog.previewUrl) {
|
||||
window.URL.revokeObjectURL(brochureDialog.previewUrl);
|
||||
}
|
||||
|
||||
// 创建新的预览URL
|
||||
brochureDialog.previewUrl = window.URL.createObjectURL(response);
|
||||
console.log('预览加载成功');
|
||||
} catch (err: any) {
|
||||
console.error('预览加载失败:', err);
|
||||
// 显示错误消息
|
||||
proxy?.$modal.msgError('预览加载失败: ' + (err?.message || err?.msg || '未知错误'));
|
||||
} finally {
|
||||
brochureLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 重新生成 */
|
||||
const handleReGenerateBrochure = async () => {
|
||||
if (!brochureDialog.enterpriseId) return;
|
||||
brochureLoading.value = true;
|
||||
try {
|
||||
const res = await generateBrochure(brochureDialog.enterpriseId);
|
||||
brochureDialog.brochureInfo = res.data;
|
||||
await loadBrochurePreview(brochureDialog.enterpriseId);
|
||||
proxy?.$modal.msgSuccess('重新生成成功');
|
||||
} catch (err: any) {
|
||||
proxy?.$modal.msgError(err?.msg || '重新生成失败');
|
||||
} finally {
|
||||
brochureLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
@@ -442,7 +923,6 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 继承后勤管理的样式
|
||||
.page-container {
|
||||
.search-btn-container {
|
||||
text-align: right;
|
||||
@@ -473,26 +953,54 @@ onMounted(() => {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
// 表格适应性样式
|
||||
.pdf-preview-wrapper {
|
||||
margin-top: 15px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
background: #f5f7fa;
|
||||
min-height: 400px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.pdf-loading,
|
||||
.pdf-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #909399;
|
||||
padding: 40px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.pdf-iframe {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
.el-table__cell {
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式表格
|
||||
:deep(.el-table__body-wrapper) {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
// 表格列宽自适应
|
||||
.el-table {
|
||||
width: 100%;
|
||||
table-layout: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// 描述列表样式优化
|
||||
:deep(.el-descriptions) {
|
||||
.el-descriptions__label {
|
||||
font-weight: 600;
|
||||
@@ -504,6 +1012,7 @@ onMounted(() => {
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.search-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
@@ -513,4 +1022,55 @@ onMounted(() => {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.enterprise-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.job-table-container {
|
||||
margin-top: 10px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
|
||||
.empty-job-tip {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
padding: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.brochure-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.brochure-info {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.upload-demo {
|
||||
text-align: center;
|
||||
|
||||
.el-icon-upload {
|
||||
font-size: 67px;
|
||||
color: #409eff;
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
.el-upload__text {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
|
||||
em {
|
||||
color: #409eff;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -175,7 +175,30 @@
|
||||
<el-radio v-for="dict in zsjy_poster_type" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联岗位" prop="positionId" v-if="form.posterType === '2'">
|
||||
<!-- 新增岗位海报时,支持岗位多选 -->
|
||||
<el-form-item
|
||||
v-if="form.posterType === '2' && !form.id"
|
||||
label="关联岗位"
|
||||
prop="positionIdList"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.positionIdList"
|
||||
placeholder="请选择关联岗位(可多选)"
|
||||
style="width: 100%"
|
||||
:disabled="!form.enterpriseId"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
>
|
||||
<el-option v-for="item in formPositionOptions" :key="item.id" :label="item.positionName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 编辑岗位海报时,保持单选,避免修改已生成数据的关联关系过于复杂 -->
|
||||
<el-form-item
|
||||
v-else-if="form.posterType === '2' && !!form.id"
|
||||
label="关联岗位"
|
||||
prop="positionId"
|
||||
>
|
||||
<el-select v-model="form.positionId" placeholder="请选择关联岗位" style="width: 100%" :disabled="!form.enterpriseId">
|
||||
<el-option v-for="item in formPositionOptions" :key="item.id" :label="item.positionName" :value="item.id" />
|
||||
</el-select>
|
||||
@@ -199,28 +222,17 @@
|
||||
<!-- 预览对话框 -->
|
||||
<el-dialog title="海报预览" v-model="previewOpen" width="900px" append-to-body>
|
||||
<div v-if="previewOpen && previewData.posterPath" class="poster-preview-container">
|
||||
<!-- 海报图片预览 -->
|
||||
<div class="poster-image-section">
|
||||
<image-preview :src="previewData.posterPath" :width="400" :height="600" :preview="true" style="margin: 0 auto" />
|
||||
</div>
|
||||
|
||||
<!-- 海报详情信息 -->
|
||||
<div class="poster-info-section">
|
||||
<el-descriptions title="海报详情" :column="2" border>
|
||||
<el-descriptions-item label="海报类型">
|
||||
<dict-tag :options="zsjy_poster_type" :value="previewData.posterType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="所属企业">
|
||||
{{ enterpriseDetail.enterpriseName || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="关联岗位" v-if="previewData.posterType === '2'">
|
||||
{{ positionDetail.positionName || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ previewData.createTime || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<!-- 使用 PosterPreview 组件生成带企业/岗位信息的海报,并支持导出 -->
|
||||
<PosterPreview
|
||||
:posterData="{
|
||||
posterPath: previewData.posterPath,
|
||||
enterpriseName: enterpriseDetail.enterpriseName || previewData.enterpriseName || '',
|
||||
positionName: positionDetail.positionName || previewData.positionName || '',
|
||||
posterType: previewData.posterType
|
||||
}"
|
||||
:enterpriseDetail="enterpriseDetail"
|
||||
:positionDetail="positionDetail"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 无海报图片提示 -->
|
||||
@@ -256,6 +268,7 @@ import { listEnterpriseOptions } from '@/api/zsjy/jobPosition';
|
||||
import { getEnterprise } from '@/api/zsjy/enterprise';
|
||||
import { getJobPosition } from '@/api/zsjy/jobPosition';
|
||||
import { RecruitmentPosterVO, RecruitmentPosterForm, RecruitmentPosterQuery } from '@/api/zsjy/types';
|
||||
import PosterPreview from '@/components/PosterPreview/index.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@@ -295,10 +308,11 @@ const queryParams = ref<RecruitmentPosterQuery>({
|
||||
});
|
||||
|
||||
// 表单参数
|
||||
const form = ref<RecruitmentPosterForm>({
|
||||
const form = ref<RecruitmentPosterForm & { positionIdList?: Array<number | string> }>({
|
||||
id: undefined,
|
||||
enterpriseId: '',
|
||||
positionId: undefined,
|
||||
positionIdList: [],
|
||||
posterPath: '',
|
||||
posterType: '1'
|
||||
});
|
||||
@@ -307,8 +321,17 @@ const form = ref<RecruitmentPosterForm>({
|
||||
const rules = {
|
||||
enterpriseId: [{ required: true, message: '请选择所属企业', trigger: 'change' }],
|
||||
posterType: [{ required: true, message: '请选择海报类型', trigger: 'change' }],
|
||||
posterPath: [{ required: true, message: '请上传海报图片', trigger: 'change' }]
|
||||
};
|
||||
posterPath: [{ required: true, message: '请上传海报图片', trigger: 'change' }],
|
||||
// 仅在新增岗位海报且岗位多选时生效
|
||||
positionIdList: [
|
||||
{
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: '请选择至少一个关联岗位',
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
} as const;
|
||||
|
||||
// 预览数据
|
||||
const previewOpen = ref(false);
|
||||
@@ -378,6 +401,7 @@ const handleEnterpriseChange = (val: number | string) => {
|
||||
/** 表单企业选择改变 */
|
||||
const handleFormEnterpriseChange = (val: number | string) => {
|
||||
form.value.positionId = undefined;
|
||||
form.value.positionIdList = [];
|
||||
if (val) {
|
||||
getFormPositionOptions(val);
|
||||
} else {
|
||||
@@ -389,6 +413,7 @@ const handleFormEnterpriseChange = (val: number | string) => {
|
||||
const handlePosterTypeChange = (val: string) => {
|
||||
if (val === '1') {
|
||||
form.value.positionId = undefined;
|
||||
form.value.positionIdList = [];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -460,17 +485,48 @@ const handlePreview = async (row: RecruitmentPosterVO) => {
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
posterFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
if (form.value.id) {
|
||||
await updateRecruitmentPoster(form.value);
|
||||
proxy?.$modal.msgSuccess('修改成功');
|
||||
} else {
|
||||
await addRecruitmentPoster(form.value);
|
||||
proxy?.$modal.msgSuccess('新增成功');
|
||||
}
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 编辑模式:保持原有单条更新逻辑
|
||||
if (form.value.id) {
|
||||
await updateRecruitmentPoster(form.value);
|
||||
proxy?.$modal.msgSuccess('修改成功');
|
||||
open.value = false;
|
||||
getList();
|
||||
return;
|
||||
}
|
||||
|
||||
// 新增岗位海报且选择了多个岗位时,批量生成多条记录
|
||||
if (
|
||||
form.value.posterType === '2' &&
|
||||
Array.isArray(form.value.positionIdList) &&
|
||||
form.value.positionIdList.length > 0
|
||||
) {
|
||||
const { positionIdList, ...baseForm } = form.value as RecruitmentPosterForm & {
|
||||
positionIdList: Array<number | string>;
|
||||
};
|
||||
|
||||
const requests = positionIdList.map((pid) =>
|
||||
addRecruitmentPoster({
|
||||
...baseForm,
|
||||
positionId: pid
|
||||
})
|
||||
);
|
||||
|
||||
await Promise.all(requests);
|
||||
proxy?.$modal.msgSuccess(`新增成功(共生成 ${positionIdList.length} 条岗位海报)`);
|
||||
open.value = false;
|
||||
getList();
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他情况(企业海报或单个岗位海报),按原有逻辑新增一条记录
|
||||
await addRecruitmentPoster(form.value);
|
||||
proxy?.$modal.msgSuccess('新增成功');
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -502,6 +558,7 @@ const resetForm = () => {
|
||||
id: undefined,
|
||||
enterpriseId: '',
|
||||
positionId: undefined,
|
||||
positionIdList: [],
|
||||
posterPath: '',
|
||||
posterType: '1'
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user