二次调研功能开发
Some checks are pending
Node CI / build (14.x, macOS-latest) (push) Waiting to run
Node CI / build (14.x, ubuntu-latest) (push) Waiting to run
Node CI / build (14.x, windows-latest) (push) Waiting to run
Node CI / build (16.x, macOS-latest) (push) Waiting to run
Node CI / build (16.x, ubuntu-latest) (push) Waiting to run
Node CI / build (16.x, windows-latest) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
coverage CI / build (push) Waiting to run
Node pnpm CI / build (16.x, macOS-latest) (push) Waiting to run
Node pnpm CI / build (16.x, ubuntu-latest) (push) Waiting to run
Node pnpm CI / build (16.x, windows-latest) (push) Waiting to run

This commit is contained in:
francis-fh
2026-06-09 16:08:39 +08:00
parent 79e67e307f
commit f2da3d6929
11 changed files with 133 additions and 25 deletions

View File

@@ -279,14 +279,14 @@ const JobPortalHeader: React.FC<JobPortalHeaderProps> = ({
> >
</Button> </Button>
<Button {/* <Button
type="text" type="text"
icon={<FundProjectionScreenOutlined />} icon={<FundProjectionScreenOutlined />}
onClick={() => handleNavClick('/job-portal/career-recommendation')} onClick={() => handleNavClick('/job-portal/career-recommendation')}
className={`nav-btn${isCareerRecommend ? ' active' : ''}`} className={`nav-btn${isCareerRecommend ? ' active' : ''}`}
> >
职业推荐 职业推荐
</Button> </Button> */}
<Button <Button
type="text" type="text"
icon={<ReadOutlined />} icon={<ReadOutlined />}

View File

@@ -17,6 +17,16 @@ import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag'; import DictTag from '@/components/DictTag';
import { postCompanyApproval } from '@/services/company/review'; import { postCompanyApproval } from '@/services/company/review';
const buildListSearchParams = (values: Record<string, any>): API.CompanyList.Params => {
const { dateRange, ...rest } = values || {};
const params = { ...rest } as API.CompanyList.Params;
if (dateRange?.[0] && dateRange?.[1]) {
params.startDate = dateRange[0];
params.endDate = dateRange[1];
}
return params;
};
const loadCompanyDetail = async (record: API.CompanyList.Company) => { const loadCompanyDetail = async (record: API.CompanyList.Company) => {
const resp = await getCmsCompanyDetail(record.companyId); const resp = await getCmsCompanyDetail(record.companyId);
const detail = parseCmsCompanyDetailResponse(resp); const detail = parseCmsCompanyDetailResponse(resp);
@@ -82,6 +92,21 @@ function ManagementList() {
}, []); }, []);
const columns: ProColumns<API.CompanyList.Company>[] = [ const columns: ProColumns<API.CompanyList.Company>[] = [
{
title: '时间范围',
dataIndex: 'dateRange',
hideInTable: true,
valueType: 'dateRange',
fieldProps: {
format: 'YYYY-MM-DD',
},
search: {
transform: (value) => ({
startDate: value[0],
endDate: value[1],
}),
},
},
{ {
title: '公司名称', title: '公司名称',
dataIndex: 'name', dataIndex: 'name',
@@ -279,7 +304,7 @@ function ManagementList() {
hidden={!access.hasPerms('system:user:export')} hidden={!access.hasPerms('system:user:export')}
onClick={async () => { onClick={async () => {
const searchVal = formTableRef.current?.getFieldsValue(); const searchVal = formTableRef.current?.getFieldsValue();
handleExport(searchVal as API.CompanyList.Params); handleExport(buildListSearchParams(searchVal || {}));
}} }}
> >
<PlusOutlined /> <PlusOutlined />

View File

@@ -552,19 +552,19 @@ const JobDetailPage: React.FC = () => {
lineWidth: 2, lineWidth: 2,
}, },
}} }}
meta={{ scale={{
score: { y: {
alias: '评分', domainMin: 0,
min: 0, domainMax: 100,
max: 100,
nice: true, nice: true,
}, },
}} }}
yAxis={{ axis={{
y: {
label: false, label: false,
tickLine: null, tick: false,
line: null, line: false,
grid: null, },
}} }}
height={300} height={300}
/> />

View File

@@ -11,7 +11,6 @@ import {
import { import {
ArrowLeftOutlined, ArrowLeftOutlined,
CalendarOutlined, CalendarOutlined,
EyeOutlined,
FileTextOutlined, FileTextOutlined,
BankOutlined, BankOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
@@ -140,9 +139,6 @@ const PolicyDetailPage: React.FC = () => {
<BankOutlined /> {detail.sourceUnit} <BankOutlined /> {detail.sourceUnit}
</Text> </Text>
)} )}
<Text type="secondary">
<EyeOutlined /> {detail.viewNum ?? 0}
</Text>
</div> </div>
{detail.zcContent?.trim() ? ( {detail.zcContent?.trim() ? (

View File

@@ -11,7 +11,6 @@ import {
} from 'antd'; } from 'antd';
import { import {
CalendarOutlined, CalendarOutlined,
EyeOutlined,
FileTextOutlined, FileTextOutlined,
SearchOutlined, SearchOutlined,
BankOutlined, BankOutlined,
@@ -125,9 +124,6 @@ const PolicyListPage: React.FC = () => {
<CalendarOutlined /> {item.publishTime} <CalendarOutlined /> {item.publishTime}
</span> </span>
)} )}
<span>
<EyeOutlined /> {item.viewNum ?? 0}
</span>
</div> </div>
</div> </div>
</List.Item> </List.Item>

View File

@@ -1,6 +1,6 @@
import React, { useRef, useState, useEffect } from 'react'; import React, { useRef, useState, useEffect } from 'react';
import { useAccess, history } from '@umijs/max'; import { useAccess, history } from '@umijs/max';
import { Button, message, Modal } from 'antd'; import { Button, FormInstance, message, Modal } from 'antd';
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components'; import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, FormOutlined, ExportOutlined, EyeOutlined } from '@ant-design/icons'; import { PlusOutlined, DeleteOutlined, FormOutlined, ExportOutlined, EyeOutlined } from '@ant-design/icons';
import { getDictValueEnum } from '@/services/system/dict'; import { getDictValueEnum } from '@/services/system/dict';
@@ -17,6 +17,7 @@ import EditModal from './components/EditModal';
const PublicJobFairList: React.FC = () => { const PublicJobFairList: React.FC = () => {
const access = useAccess(); const access = useAccess();
const formRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const [modalVisible, setModalVisible] = useState(false); const [modalVisible, setModalVisible] = useState(false);
const [currentRow, setCurrentRow] = useState<API.PublicJobFair.JobFairItem>(); const [currentRow, setCurrentRow] = useState<API.PublicJobFair.JobFairItem>();
@@ -44,10 +45,21 @@ const PublicJobFairList: React.FC = () => {
}); });
}; };
const buildListSearchParams = (values: Record<string, any>): API.PublicJobFair.ListParams => {
const { dateRange, current, pageSize, ...rest } = values || {};
const params = { ...rest } as API.PublicJobFair.ListParams;
if (dateRange?.[0] && dateRange?.[1]) {
params.startDate = dateRange[0];
params.endDate = dateRange[1];
}
return params;
};
const handleExport = async () => { const handleExport = async () => {
message.loading('正在导出...'); message.loading('正在导出...');
try { try {
await exportPublicJobFair(); const searchVal = formRef.current?.getFieldsValue();
await exportPublicJobFair(buildListSearchParams(searchVal || {}));
message.success('导出成功'); message.success('导出成功');
} catch { } catch {
message.error('导出失败'); message.error('导出失败');
@@ -55,6 +67,21 @@ const PublicJobFairList: React.FC = () => {
}; };
const columns: ProColumns<API.PublicJobFair.JobFairItem>[] = [ const columns: ProColumns<API.PublicJobFair.JobFairItem>[] = [
{
title: '时间范围',
dataIndex: 'dateRange',
hideInTable: true,
valueType: 'dateRange',
fieldProps: {
format: 'YYYY-MM-DD',
},
search: {
transform: (value) => ({
startDate: value[0],
endDate: value[1],
}),
},
},
{ {
title: '招聘会标题', title: '招聘会标题',
dataIndex: 'jobFairTitle', dataIndex: 'jobFairTitle',
@@ -85,6 +112,12 @@ const PublicJobFairList: React.FC = () => {
valueType: 'dateTime', valueType: 'dateTime',
hideInSearch: true, hideInSearch: true,
}, },
{
title: '创建时间',
dataIndex: 'createTime',
valueType: 'dateTime',
hideInSearch: true,
},
{ {
title: '操作', title: '操作',
valueType: 'option', valueType: 'option',
@@ -136,6 +169,7 @@ const PublicJobFairList: React.FC = () => {
<ProTable<API.PublicJobFair.JobFairItem> <ProTable<API.PublicJobFair.JobFairItem>
headerTitle="公共招聘会列表" headerTitle="公共招聘会列表"
actionRef={actionRef} actionRef={actionRef}
formRef={formRef}
rowKey="jobFairId" rowKey="jobFairId"
columns={columns} columns={columns}
scroll={{ x: 'max-content' }} scroll={{ x: 'max-content' }}
@@ -149,6 +183,8 @@ const PublicJobFairList: React.FC = () => {
pageSize: params.pageSize, pageSize: params.pageSize,
jobFairTitle: params.jobFairTitle, jobFairTitle: params.jobFairTitle,
jobFairType: params.jobFairType, jobFairType: params.jobFairType,
startDate: params.startDate,
endDate: params.endDate,
}); });
return { data: res.rows, total: res.total, success: true }; return { data: res.rows, total: res.total, success: true };
}} }}

View File

@@ -7,11 +7,12 @@ import {
exportCmsJob, exportCmsJob,
exportJobApply, exportJobApply,
getCmsJobList, getCmsJobList,
importJobRow,
updateCmsJobList, updateCmsJobList,
} from '@/services/Management/list'; } from '@/services/Management/list';
import { Button, FormInstance, message, Modal, Switch } from 'antd'; import { Button, FormInstance, message, Modal, Switch } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { AlignLeftOutlined, BarChartOutlined, DeleteOutlined, FormOutlined, PlusOutlined,DownloadOutlined } from '@ant-design/icons'; import { AlignLeftOutlined, BarChartOutlined, DeleteOutlined, FormOutlined, PlusOutlined, DownloadOutlined, UploadOutlined } from '@ant-design/icons';
import EditManageRow from './edit'; import EditManageRow from './edit';
import { getDictValueEnum } from '@/services/system/dict'; import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag'; import DictTag from '@/components/DictTag';
@@ -76,6 +77,7 @@ function ManagementList() {
const formTableRef = useRef<FormInstance>(); const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const fileInputRef = useRef<HTMLInputElement>(null);
const [educationEnum, setEducationEnum] = useState<any>([]); const [educationEnum, setEducationEnum] = useState<any>([]);
const [experienceEnum, setExperienceEnum] = useState<any>([]); const [experienceEnum, setExperienceEnum] = useState<any>([]);
@@ -120,6 +122,29 @@ function ManagementList() {
} }
} }
const handleBatchUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
const hide = message.loading('正在上传');
try {
const resp = await importJobRow(file);
hide();
if (resp.code === 200) {
message.success('批量上传成功');
actionRef.current?.reload();
} else {
message.error(resp.msg || '上传失败,请重试');
}
} catch (error) {
hide();
message.error('上传失败,请重试');
}
// 清空 input 以便重复选择同一文件
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
const columns: ProColumns<API.ManagementList.Manage>[] = [ const columns: ProColumns<API.ManagementList.Manage>[] = [
{ {
title: '时间范围', title: '时间范围',
@@ -390,9 +415,24 @@ function ManagementList() {
> >
<DownloadOutlined /> <DownloadOutlined />
</Button>, </Button>,
<Button
type="primary"
key="batchUpload"
hidden={!access.hasPerms('manage:List:add')}
onClick={() => fileInputRef.current?.click()}
>
<UploadOutlined />
</Button>,
]} ]}
/> />
</div> </div>
<input
type="file"
ref={fileInputRef}
style={{ display: 'none' }}
accept=".xlsx,.xls"
onChange={handleBatchUpload}
/>
<EditManageRow <EditManageRow
open={modalVisible} open={modalVisible}
mode={mode} mode={mode}

View File

@@ -57,6 +57,16 @@ export async function exportCmsJobCandidates(ids: string) {
}); });
} }
export async function importJobRow(file: File) {
const formData = new FormData();
formData.append('file', file);
return request('/api/app/script/importRow/v2', {
method: 'POST',
// 不显式设置 Content-Type交由浏览器按 multipart/form-data 边界自动设置
data: formData,
});
}
export async function getJobTrend(params) { export async function getJobTrend(params) {
return request(`/api/cms/jobTrend/list`, { return request(`/api/cms/jobTrend/list`, {
method: 'GET', method: 'GET',

View File

@@ -29,7 +29,7 @@ export async function putCmsCompanyList(params?: API.CompanyList.Params) {
} }
export async function exportCmsCompanyList(params?: API.CompanyList.Params) { export async function exportCmsCompanyList(params?: API.CompanyList.Params) {
return downLoadXlsx(`/cms/company/export`, { params }, `dict_data_${new Date().getTime()}.xlsx`); return downLoadXlsx(`/api/cms/company/export`, { params }, `dict_data_${new Date().getTime()}.xlsx`);
} }
/** 解析企业详情接口响应(兼容 data 包裹与平铺字段两种格式) */ /** 解析企业详情接口响应(兼容 data 包裹与平铺字段两种格式) */

View File

@@ -35,5 +35,7 @@ declare namespace API.CompanyList {
industry?: string; industry?: string;
scale?: string; scale?: string;
code?: string; code?: string;
startDate?: string;
endDate?: string;
} }
} }

View File

@@ -8,6 +8,8 @@ declare namespace API.PublicJobFair {
pageSize?: number; pageSize?: number;
jobFairTitle?: string; jobFairTitle?: string;
jobFairType?: string; jobFairType?: string;
startDate?: string;
endDate?: string;
} }
/** 招聘会列表项 */ /** 招聘会列表项 */
@@ -29,6 +31,7 @@ declare namespace API.PublicJobFair {
longitude?: number; longitude?: number;
enterpriseNum?: string; enterpriseNum?: string;
boothNum?: string; boothNum?: string;
createTime?: string;
} }
/** 招聘会列表响应 */ /** 招聘会列表响应 */