flat: 合并

This commit is contained in:
史典卓
2025-04-23 15:47:46 +08:00
8 changed files with 784 additions and 858 deletions

View File

@@ -1,64 +1,77 @@
html,
body,
#root {
height: 100%;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
}
.colorWeak {
filter: invert(80%);
}
.ant-layout {
min-height: 100vh !important;
}
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
left: unset;
}
.ant-table-row {
&-level-1 .ant-table-cell:first-child {
padding-left: 24px !important;
}
&-level-2 .ant-table-cell:first-child {
padding-left: 48px !important;
}
// 可根据需要添加更多层级
}
canvas {
display: block;
}
body {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
ul,
ol {
list-style: none;
}
@media (max-width: 768px) {
.ant-table {
width: 100%;
overflow-x: auto;
&-thead > tr,
&-tbody > tr {
> th,
> td {
white-space: pre;
> span {
display: block;
}
}
}
}
}
html,
body,
#root {
height: 100%;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
}
.colorWeak {
filter: invert(80%);
}
.ant-layout {
min-height: 100vh !important;
}
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
left: unset;
}
.ant-table-cell .ant-table-row-expand-icon {
vertical-align: middle;
margin-right: 8px;
}
.ant-table-row {
&-level-0 .ant-table-cell:first-child {
padding-left: 16px !important;
}
&-level-1 .ant-table-cell:first-child {
padding-left: 40px !important;
}
&-level-2 .ant-table-cell:first-child {
padding-left: 64px !important;
}
}
.ant-table-row .ant-table-cell:first-child {
display: flex;
align-items: center;
}
.ant-table-row-level-2 .ant-table-row-expand-icon {
display: none;
}
canvas {
display: block;
}
body {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
ul,
ol {
list-style: none;
}
@media (max-width: 768px) {
.ant-table {
width: 100%;
overflow-x: auto;
&-thead > tr,
&-tbody > tr {
> th,
> td {
white-space: pre;
> span {
display: block;
}
}
}
}
}

View File

@@ -1,189 +1,190 @@
import React, { useEffect } from 'react';
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormRadio,
ProFormTreeSelect,
ProFormText,
ProDescriptions,
} from '@ant-design/pro-components';
import { Form } from 'antd';
import { DictValueEnumObj } from '@/components/DictTag';
import { FormattedMessage } from '@@/exports';
import { getCmsIndustryTreeList } from '@/services/classify/industry'; // 修改导入为 getCmsIndustryTreeList
interface IndustryDetail {
id?: number;
industryName?: string;
orderNum?: number;
status?: string;
parentId?: number;
parentName?: string;
}
export type ListFormProps = {
onCancel: (flag?: boolean, formVars?: unknown) => void;
onSubmit: (values: any) => Promise<void>;
open: boolean;
values?: Partial<IndustryDetail>;
industryStatusEnum: DictValueEnumObj;
mode?: 'view' | 'edit' | 'create';
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const { industryStatusEnum, mode = props.values ? 'edit' : 'create', values } = props;
useEffect(() => {
form.resetFields();
if (values) {
form.setFieldsValue({
...values,
parentId: values?.parentId ?? 0
});
}
}, [form, values?.id]);
const getSafeDetailData = (data?: Partial<IndustryDetail>): IndustryDetail => {
return {
id: data?.id ?? 0,
industryName: data?.industryName ?? '',
orderNum: data?.orderNum ?? 0,
parentId: data?.parentId ?? 0,
parentName: data?.parentName ?? '顶级节点',
status: data?.status ?? '0',
};
};
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
const submitValues = {
...values,
parentId: values.parentId === 0 ? undefined : values.parentId
};
props.onSubmit(submitValues);
};
// 获取行业树数据
const fetchIndustryTree = async () => {
const res = await getCmsIndustryTreeList();
return [
{
id: 0,
label: '顶级节点',
value: 0,
children: res.data || []
}
];
};
if (mode === 'view') {
return (
<ModalForm
title="行业详情"
open={props.open}
width={800}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
footer: null,
}}
submitter={false}
>
<ProDescriptions<IndustryDetail>
column={1}
dataSource={getSafeDetailData(values)}
loading={!values}
>
<ProDescriptions.Item label="行业ID" dataIndex="id" />
<ProDescriptions.Item label="行业名称" dataIndex="industryName" />
<ProDescriptions.Item label="显示顺序" dataIndex="orderNum" />
<ProDescriptions.Item
label="父行业"
dataIndex="parentName"
renderText={(text, record) => record.parentId === 0 ? '顶级节点' : text}
/>
<ProDescriptions.Item
label="行业状态"
dataIndex="status"
valueEnum={industryStatusEnum}
/>
</ProDescriptions>
</ModalForm>
);
}
return (
<ModalForm
title={`${values ? '编辑' : '新增'}行业`}
form={form}
autoFocusFirstInput
open={props.open}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
>
<ProFormDigit name="id" disabled hidden={true} />
<ProForm.Group>
<ProFormText
width="md"
name="industryName"
label="行业名称"
placeholder="请输入行业名称"
rules={[{ required: true, message: '请输入行业名称' }]}
/>
<ProFormDigit
label="显示顺序"
name="orderNum"
width="md"
min={0}
placeholder="请输入显示顺序"
rules={[{ required: true, message: '请输入显示顺序' }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormTreeSelect
name="parentId"
label="父行业"
placeholder="请选择父行业"
allowClear
width="md"
request={fetchIndustryTree}
fieldProps={{
treeDefaultExpandAll: true,
showSearch: true,
filterTreeNode: true,
fieldNames: {
label: 'label',
value: 'id',
children: 'children',
},
dropdownStyle: {
maxHeight: 400,
overflow: 'auto',
},
}}
rules={[{ required: true, message: '请选择父行业' }]}
/>
<ProFormRadio.Group
valueEnum={industryStatusEnum}
name="status"
label="行业状态"
width="md"
initialValue="0"
rules={[{ required: true, message: '请选择行业状态' }]}
/>
</ProForm.Group>
</ModalForm>
);
};
import React, { useEffect } from 'react';
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormRadio,
ProFormTreeSelect,
ProFormText,
ProDescriptions,
} from '@ant-design/pro-components';
import { Form } from 'antd';
import { DictValueEnumObj } from '@/components/DictTag';
import { FormattedMessage } from '@@/exports';
import { getCmsIndustryTreeList } from '@/services/classify/industry'; // 修改导入为 getCmsIndustryTreeList
interface IndustryDetail {
id?: number;
industryName?: string;
orderNum?: number;
status?: string;
parentId?: number;
parentName?: string;
}
export type ListFormProps = {
onCancel: (flag?: boolean, formVars?: unknown) => void;
onSubmit: (values: any) => Promise<void>;
open: boolean;
values?: Partial<IndustryDetail>;
industryStatusEnum: DictValueEnumObj;
mode?: 'view' | 'edit' | 'create';
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm<IndustryDetail>();
const { industryStatusEnum, mode = props.values ? 'edit' : 'create', values } = props;
useEffect(() => {
form.resetFields();
if (values) {
form.setFieldsValue({
...values,
parentId: values?.parentId ?? 0
});
}
}, [form, values?.id]);
const getSafeDetailData = (data?: Partial<IndustryDetail>): IndustryDetail => {
return {
id: data?.id ?? 0,
industryName: data?.industryName ?? '',
orderNum: data?.orderNum ?? 0,
parentId: data?.parentId ?? 0,
parentName: data?.parentName ?? '顶级节点',
status: data?.status ?? '0',
};
};
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
const submitValues = {
...values,
parentId: values.parentId === 0 ? undefined : values.parentId
};
props.onSubmit(submitValues);
};
// 获取行业树数据
const fetchIndustryTree = async () => {
const res = await getCmsIndustryTreeList();
return [
{
id: 0,
label: '顶级节点',
value: 0,
children: res.data || []
}
];
};
if (mode === 'view') {
return (
<ModalForm
title="行业详情"
open={props.open}
width={800}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
footer: null,
}}
submitter={false}
>
<ProDescriptions<IndustryDetail>
column={1}
dataSource={getSafeDetailData(values)}
loading={!values}
>
<ProDescriptions.Item label="行业ID" dataIndex="id" />
<ProDescriptions.Item label="行业名称" dataIndex="industryName" />
<ProDescriptions.Item label="显示顺序" dataIndex="orderNum" />
<ProDescriptions.Item
label="父行业"
dataIndex="parentName"
renderText={(text, record) => record.parentId === 0 ? '顶级节点' : text}
/>
<ProDescriptions.Item
label="行业状态"
dataIndex="status"
valueEnum={industryStatusEnum}
/>
</ProDescriptions>
</ModalForm>
);
}
return (
<ModalForm
title={`${values ? '编辑' : '新增'}行业`}
form={form}
autoFocusFirstInput
open={props.open}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
>
<ProFormDigit name="id" disabled hidden={true} />
<ProForm.Group>
<ProFormText
width="md"
name="industryName"
label="行业名称"
placeholder="请输入行业名称"
rules={[{ required: true, message: '请输入行业名称' }]}
/>
<ProFormDigit
label="显示顺序"
name="orderNum"
width="md"
min={0}
placeholder="请输入显示顺序"
rules={[{ required: true, message: '请输入显示顺序' }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormTreeSelect
name="parentId"
label="父行业"
placeholder="请选择父行业"
allowClear
width="md"
request={fetchIndustryTree}
fieldProps={{
virtual:true,
treeDefaultExpandAll: true,
showSearch: true,
filterTreeNode: true,
fieldNames: {
label: 'label',
value: 'id',
children: 'children',
},
dropdownStyle: {
maxHeight: 400,
overflow: 'auto',
},
}}
rules={[{ required: true, message: '请选择父行业' }]}
/>
<ProFormRadio.Group
valueEnum={industryStatusEnum}
name="status"
label="行业状态"
width="md"
initialValue="0"
rules={[{ required: true, message: '请选择行业状态' }]}
/>
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;

View File

@@ -1,159 +1,159 @@
import React,{ useEffect,useState } from 'react';
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormText,
ProFormTextArea,
ProFormTreeSelect,
ProFormSelect
} from '@ant-design/pro-components';
import { Form } from 'antd';
import { getCmsJobTitleList } from '@/services/classify/jobs';
import { getDictValueEnum } from '@/services/system/dict';
// tree
type JobListParams = API.ClassifyJobs.Params;
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: any) => Promise<void>;
open: boolean;
values?: Partial<API.ClassifyJobs.Job>;
// jobGroupOptions: DictOptionType[];
// statusOptions: DictValueEnumObj;
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const [treeData, setTreeData] = useState<API.ClassifyJobs.Job[]>([]);
const [statusOptions, setStatusOptions] = useState<Record<string, any>>({});
const [loading, setLoading] = useState(false);
const buildTree = (data: API.ClassifyJobs.Job[], parentId: number = 0): API.ClassifyJobs.Job[] => {
return data
.filter(item => item.parentId === parentId)
.map(item => ({
...item,
children: buildTree(data, item.jobId),
}));
};
useEffect(() => {
const fetchData = async () => {
const res = await getCmsJobTitleList({
tree: false,
// 明确传递所有必要参数
pageSize: 1000, // 确保获取全部数据
current: 1
} as JobListParams);
setLoading(true);
try {
// 获取状态枚举
const statusData = await getDictValueEnum('sys_jobs_status', true);
setStatusOptions(statusData);
// 获取岗位数据
const res = await getCmsJobTitleList({ tree: false } as JobListParams);
console.log('原始数据:', res.rows);
const treeData = buildTree(res.rows || []);
console.log('转换后的树形数据:', treeData);
setTreeData(treeData);
// 设置表单初始值
if (props.values) {
form.setFieldsValue({
...props.values,
parentId: props.values.parentId || undefined,
});
}
} catch (error) {
console.error('数据加载失败:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
await props.onSubmit(values);
};
return (
<ModalForm
title={`${props.values ? '编辑' : '新增'}企业`}
form={form}
autoFocusFirstInput
open={props.open}
width={600}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
>
<ProFormDigit label="InputNumber" name="jobId" disabled hidden={true} />
{/* 新增:父级岗位选择 */}
<ProFormTreeSelect
name="parentId"
label="父级岗位"
width="md"
placeholder="请选择父级岗位"
allowClear
fieldProps={{
treeData,
fieldNames: { label: 'jobName', value: 'jobId', children: 'children' },
treeDefaultExpandAll: true,
showSearch: true,
variant:'outlined',
dropdownStyle: { maxHeight: 400, overflow: 'auto' },
filterTreeNode: (input, option) =>
String(option?.title ?? '').toLowerCase().includes(input.toLowerCase())
}}
/>
<ProForm.Group>
<ProFormText width="md" name="jobname" label="单位名称" placeholder="请输入单位名称" />
<ProFormDigit
width="md"
name="orderNum"
label="显示顺序"
placeholder="请输入显示顺序"
min={0}
fieldProps={{ precision: 0 }}
rules={[{ required: true, message: '请输入显示顺序' }]}
/>
</ProForm.Group>
<ProFormSelect
name="status"
label="状态"
width="md"
valueEnum={statusOptions}
placeholder="请选择状态"
/>
<ProForm.Group>
<ProFormText width="md" name="code" label="信用代码" placeholder="请输入信用代码" />
<ProFormText width="md" name="industry" label="主要行业" placeholder="请输入主要行业" />
</ProForm.Group>
<ProForm.Group>
<ProFormTextArea width="xl" name="location" label="单位地点" placeholder="请输入单位地点" />
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;
import React,{ useEffect,useState } from 'react';
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormText,
ProFormTextArea,
ProFormTreeSelect,
ProFormSelect
} from '@ant-design/pro-components';
import { Form } from 'antd';
import { getCmsJobTitleList } from '@/services/classify/jobs';
import { getDictValueEnum } from '@/services/system/dict';
// tree
type JobListParams = API.ClassifyJobs.Params;
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: any) => Promise<void>;
open: boolean;
values?: Partial<API.ClassifyJobs.Jobs>;
// jobGroupOptions: DictOptionType[];
// statusOptions: DictValueEnumObj;
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const [treeData, setTreeData] = useState<API.ClassifyJobs.Jobs[]>([]);
const [statusOptions, setStatusOptions] = useState<Record<string, any>>({});
const [loading, setLoading] = useState(false);
const buildTree = (data: API.ClassifyJobs.Jobs[], parentId: number = 0): API.ClassifyJobs.Jobs[] => {
return data
.filter(item => item.parentId === parentId)
.map(item => ({
...item,
children: buildTree(data, item.jobId),
}));
};
useEffect(() => {
const fetchData = async () => {
const res = await getCmsJobTitleList({
tree: false,
// 明确传递所有必要参数
pageSize: 1000, // 确保获取全部数据
current: 1
} as JobListParams);
setLoading(true);
try {
// 获取状态枚举
const statusData = await getDictValueEnum('sys_jobs_status', true);
setStatusOptions(statusData);
// 获取岗位数据
const res = await getCmsJobTitleList({ tree: false } as JobListParams);
console.log('原始数据:', res.rows);
const treeData = buildTree(res.rows || []);
console.log('转换后的树形数据:', treeData);
setTreeData(treeData);
// 设置表单初始值
if (props.values) {
form.setFieldsValue({
...props.values,
parentId: props.values.parentId || undefined,
});
}
} catch (error) {
console.error('数据加载失败:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
await props.onSubmit(values);
};
return (
<ModalForm
title={`${props.values ? '编辑' : '新增'}企业`}
form={form}
autoFocusFirstInput
open={props.open}
width={600}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
>
<ProFormDigit label="InputNumber" name="jobId" disabled hidden={true} />
{/* 新增:父级岗位选择 */}
<ProFormTreeSelect
name="parentId"
label="父级岗位"
width="md"
placeholder="请选择父级岗位"
allowClear
fieldProps={{
treeData,
fieldNames: { label: 'jobName', value: 'jobId', children: 'children' },
treeDefaultExpandAll: true,
showSearch: true,
variant:'outlined',
dropdownStyle: { maxHeight: 400, overflow: 'auto' },
filterTreeNode: (input, option) =>
String(option?.title ?? '').toLowerCase().includes(input.toLowerCase())
}}
/>
<ProForm.Group>
<ProFormText width="md" name="jobname" label="单位名称" placeholder="请输入单位名称" />
<ProFormDigit
width="md"
name="orderNum"
label="显示顺序"
placeholder="请输入显示顺序"
min={0}
fieldProps={{ precision: 0 }}
rules={[{ required: true, message: '请输入显示顺序' }]}
/>
</ProForm.Group>
<ProFormSelect
name="status"
label="状态"
width="md"
valueEnum={statusOptions}
placeholder="请选择状态"
/>
<ProForm.Group>
<ProFormText width="md" name="code" label="信用代码" placeholder="请输入信用代码" />
<ProFormText width="md" name="industry" label="主要行业" placeholder="请输入主要行业" />
</ProForm.Group>
<ProForm.Group>
<ProFormTextArea width="xl" name="location" label="单位地点" placeholder="请输入单位地点" />
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;

View File

@@ -9,34 +9,6 @@ import { exportCmsJobTitleList, getCmsJobTitleList } from '@/services/classify/j
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
declare namespace API {
namespace ClassifyJobs {
interface Params {
tree?: boolean;
pageSize?: number;
current?: number;
jobName?: string;
status?: string;
}
interface Jobs {
jobId: number;
parentId: number;
jobName: string;
orderNum?: number;
status?: string;
createTime?: string;
parentName?: string;
children?: Jobs[];
depth?: number; // 添加这行
}
}
}
// params类型
type JobListParams = API.ClassifyJobs.Params & {
tree?: boolean;
};
const handleRemoveOne = async (jobId: string) => {
const hide = message.loading('正在删除');
if (!jobId) return true;
@@ -74,16 +46,14 @@ const buildTree = (
parentId: number = 0,
depth = 0,
): API.ClassifyJobs.Jobs[] => {
return data
const children = data
.filter((item) => item.parentId === parentId)
.map((item) => {
const child = buildTree(data, item.jobId, depth + 1);
return {
...item,
depth,
children: child.length ? child : undefined,
};
});
.map((item) => ({
...item,
depth,
children: buildTree(data, item.jobId, depth + 1),
}));
return children || [];
};
const ManagementList: React.FC = () => {
@@ -107,13 +77,12 @@ const ManagementList: React.FC = () => {
title: '岗位名称',
dataIndex: 'jobName',
align: 'center',
align: 'left',
render: (text, record) => (
<span
style={{
paddingLeft: `${(record.depth || 0) * 20}px`,
display: 'inline-block',
width: '100%',
display: 'flex',
alignItems: 'center',
}}
>
{text}
@@ -144,67 +113,22 @@ const ManagementList: React.FC = () => {
return <DictTag enums={jobsStatusEnum} value={record.status} />;
},
},
// {
// title: '操作',
// hideInSearch: true,
// align: 'center',
// dataIndex: 'jobId',
// width: 300,
// render: (_, record) => [
// <Button
// type="link"
// size="small"
// key="edit"
// icon={<FormOutlined />}
// hidden={!access.hasPerms('system:job:edit')}
// onClick={() => {
// setModalVisible(true);
// setCurrentRow(record);
// }}
// >
// 编辑
// </Button>,
// // <Button
// // type="link"
// // size="small"
// // danger
// // key="delete"
// // icon={<DeleteOutlined />}
// // hidden={!access.hasPerms('system:job:remove')}
// // onClick={async () => {
// // Modal.confirm({
// // title: '删除',
// // content: '确定删除该项吗?',
// // okText: '确认',
// // cancelText: '取消',
// // onOk: async () => {
// // if(record.jobId){
// // const success = await handleRemoveOne(record.jobId.toString());
//
// // if (success && actionRef.current) {
// // actionRef.current.reload();
// // }
// // }
// // },
// // });
// // }}
// // >
// // 删除
// // </Button>,
// ],
// },
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.ClassifyJobs.Jobs>
// params 是需要自带的参数
// 这个参数优先级更高,会覆盖查询表单的参数
actionRef={actionRef}
formRef={formTableRef}
rowKey="jobId"
key="index"
columns={columns}
expandable={{
childrenColumnName: 'children',
defaultExpandAllRows: true,
indentSize: 24,
rowExpandable: (record) => Array.isArray(record.children) && record.children.length > 0,
}}
search={{
labelWidth: 120,
}}
@@ -215,7 +139,6 @@ const ManagementList: React.FC = () => {
pageSize: 1000,
});
const treeData = buildTree(res.rows);
console.log('完整树形结构:', JSON.stringify(treeData, null, 2));
return {
data: treeData,
total: res.total,
@@ -223,12 +146,6 @@ const ManagementList: React.FC = () => {
};
}}
pagination={false}
expandable={{
childrenColumnName: 'children',
defaultExpandAllRows: true,
indentSize: 30,
rowExpandable: (record) => !!record.children?.length,
}}
toolBarRender={() => [
<Button
type="primary"

View File

@@ -1,207 +1,207 @@
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormSelect,
ProFormText,
ProFormTextArea,
ProDescriptions,
} from '@ant-design/pro-components';
import { Form } from 'antd';
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import { getCmsCompanyList } from '@/services/company/list';
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: API.ManagementList.Manage) => Promise<void>;
open: boolean;
values?: Partial<API.ManagementList.Manage>;
educationEnum: DictValueEnumObj;
experienceEnum: DictValueEnumObj;
areaEnum: DictValueEnumObj;
mode?: 'view' | 'edit' | 'create';
};
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm<{ name: string; company: string; companyName: number }>();
const { educationEnum, experienceEnum, areaEnum } = props;
const { mode = props.values ? 'edit' : 'create' } = props;
useEffect(() => {
form.resetFields();
if (props.values) {
form.setFieldsValue({
...props.values,
jobLocationAreaCode: String(props.values.jobLocationAreaCode || ''),
});
}
}, [form, props.values?.jobID]);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit(values as API.ManagementList.Manage);
};
const handleChange = (_: string, value: any) => {
form.setFieldValue('companyName', value.label);
};
if (mode === 'view') {
return (
<ModalForm
title="岗位详情"
open={props.open}
width={800}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
footer: null,
}}
submitter={false}
>
<ProDescriptions<API.ManagementList.Manage>
column={2}
dataSource={props.values || {}}
>
<ProDescriptions.Item dataIndex="jobTitle" label="岗位名称" />
<ProDescriptions.Item dataIndex="companyName" label="招聘公司" />
<ProDescriptions.Item dataIndex="minSalary" label="最低薪资(元/月)" />
<ProDescriptions.Item dataIndex="maxSalary" label="最高薪资(元/月)" />
<ProDescriptions.Item
dataIndex="education"
label="学历要求"
valueEnum={educationEnum}
/>
<ProDescriptions.Item
dataIndex="experience"
label="工作经验"
valueEnum={experienceEnum}
/>
<ProDescriptions.Item
dataIndex="jobLocationAreaCode"
label="工作区县"
valueEnum={areaEnum}
/>
<ProDescriptions.Item dataIndex="vacancies" label="招聘人数" />
<ProDescriptions.Item dataIndex="jobLocation" label="工作地点" />
<ProDescriptions.Item
dataIndex="description"
label="岗位描述"
span={2} // 跨两列显示
/>
</ProDescriptions>
</ModalForm>
);
}
return (
<ModalForm<{
name: string;
company: string;
}>
title={mode === 'edit' ? '编辑岗位' : '新建岗位'}
form={form}
autoFocusFirstInput
open={props.open}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
>
<ProForm.Group>
<ProFormText width="md" hidden name="jobId" />
<ProFormText width="md" hidden name="companyName" />
<ProFormText width="md" name="jobTitle" label="岗位名称" placeholder="请输入岗位名称" />
<ProFormSelect
showSearch
width="md"
name="companyId"
onChange={handleChange}
request={async ({ keyWords }) => {
let resData = await getCmsCompanyList({ name: keyWords });
return resData.rows.map((item) => ({ label: item.name, value: item.companyId }));
}}
placeholder="请输入公司名称选择公司"
rules={[{ required: true, message: '请输入公司名称选择公司!' }]}
label="招聘会公司"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormDigit
name="minSalary"
width="md"
min={0}
label="最小薪资(元/月)"
placeholder="请输入最小薪资(元)"
/>
<ProFormDigit
name="maxSalary"
width="md"
min={0}
label="最大薪资(元/月)"
placeholder="请输入最大薪资(元)"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
width="md"
name="education"
label={'学历要求'}
valueEnum={educationEnum}
placeholder="请选择学历要求"
rules={[{ required: true, message: '请选择学历要求!' }]}
/>
<ProFormSelect
width="md"
name="experience"
label={'工作经验'}
valueEnum={experienceEnum}
placeholder="请选择岗位"
rules={[{ required: true, message: '请选择工作经验!' }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
width="md"
name="jobLocationAreaCode"
label={'工作区县'}
valueEnum={areaEnum}
placeholder="请选择区县"
rules={[{ required: true, message: '请选择区县!' }]}
/>
<ProFormDigit
label="招聘人数"
name="vacancies"
width="md"
min={0}
placeholder="请输入招聘人数"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText width="lg" name="jobLocation" label="工作地点" placeholder="请输入工作地点" />
</ProForm.Group>
<ProForm.Group>
<ProFormTextArea
width="lg"
name="description"
label="岗位描述"
placeholder="请输入岗位描述"
/>
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormSelect,
ProFormText,
ProFormTextArea,
ProDescriptions,
} from '@ant-design/pro-components';
import { Form } from 'antd';
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import { getCmsCompanyList } from '@/services/company/list';
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: API.ManagementList.Manage) => Promise<void>;
open: boolean;
values?: Partial<API.ManagementList.Manage>;
educationEnum: DictValueEnumObj;
experienceEnum: DictValueEnumObj;
areaEnum: DictValueEnumObj;
mode?: 'view' | 'edit' | 'create';
};
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm<API.ManagementList.Manage>();
const { educationEnum, experienceEnum, areaEnum } = props;
const { mode = props.values ? 'edit' : 'create' } = props;
useEffect(() => {
if(props.open){
form.resetFields();
if (props.values) {
form.setFieldsValue({
...props.values,
jobLocationAreaCode: String(props.values.jobLocationAreaCode || ''),
});
}
}
}, [form, props.values?.jobId,props.open]);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit(values as API.ManagementList.Manage);
};
const handleChange = (_: string, value: any) => {
form.setFieldValue('companyName', value.label);
};
if (mode === 'view') {
return (
<ModalForm
title="岗位详情"
open={props.open}
width={800}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
footer: null,
}}
submitter={false}
>
<ProDescriptions<API.ManagementList.Manage>
column={2}
dataSource={props.values || {}}
>
<ProDescriptions.Item dataIndex="jobTitle" label="岗位名称" />
<ProDescriptions.Item dataIndex="companyName" label="招聘公司" />
<ProDescriptions.Item dataIndex="minSalary" label="最低薪资(元/月)" />
<ProDescriptions.Item dataIndex="maxSalary" label="最高薪资(元/月)" />
<ProDescriptions.Item
dataIndex="education"
label="学历要求"
valueEnum={educationEnum}
/>
<ProDescriptions.Item
dataIndex="experience"
label="工作经验"
valueEnum={experienceEnum}
/>
<ProDescriptions.Item
dataIndex="jobLocationAreaCode"
label="工作区县"
valueEnum={areaEnum}
/>
<ProDescriptions.Item dataIndex="vacancies" label="招聘人数" />
<ProDescriptions.Item dataIndex="jobLocation" label="工作地点" />
<ProDescriptions.Item
dataIndex="description"
label="岗位描述"
span={2} // 跨两列显示
/>
</ProDescriptions>
</ModalForm>
);
}
return (
<ModalForm<API.ManagementList.Manage>
title={mode === 'edit' ? '编辑岗位' : '新建岗位'}
form={form}
autoFocusFirstInput
open={props.open}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
>
<ProForm.Group>
<ProFormText width="md" hidden name="jobId" />
<ProFormText width="md" hidden name="companyName" />
<ProFormText width="md" name="jobTitle" label="岗位名称" placeholder="请输入岗位名称" />
<ProFormSelect
showSearch
width="md"
name="companyId"
onChange={handleChange}
request={async ({ keyWords }) => {
let resData = await getCmsCompanyList({ name: keyWords });
return resData.rows.map((item) => ({ label: item.name, value: item.companyId }));
}}
placeholder="请输入公司名称选择公司"
rules={[{ required: true, message: '请输入公司名称选择公司!' }]}
label="招聘会公司"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormDigit
name="minSalary"
width="md"
min={0}
label="最小薪资(元/月)"
placeholder="请输入最小薪资(元)"
/>
<ProFormDigit
name="maxSalary"
width="md"
min={0}
label="最大薪资(元/月)"
placeholder="请输入最大薪资(元)"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
width="md"
name="education"
label={'学历要求'}
valueEnum={educationEnum}
placeholder="请选择学历要求"
rules={[{ required: true, message: '请选择学历要求!' }]}
/>
<ProFormSelect
width="md"
name="experience"
label={'工作经验'}
valueEnum={experienceEnum}
placeholder="请选择岗位"
rules={[{ required: true, message: '请选择工作经验!' }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
width="md"
name="jobLocationAreaCode"
label={'工作区县'}
valueEnum={areaEnum}
placeholder="请选择区县"
rules={[{ required: true, message: '请选择区县!' }]}
/>
<ProFormDigit
label="招聘人数"
name="vacancies"
width="md"
min={0}
placeholder="请输入招聘人数"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText width="lg" name="jobLocation" label="工作地点" placeholder="请输入工作地点" />
</ProForm.Group>
<ProForm.Group>
<ProFormTextArea
width="lg"
name="description"
label="岗位描述"
placeholder="请输入岗位描述"
/>
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;

View File

@@ -1,72 +1,72 @@
declare namespace API.ManagementList {
export interface Manage {
applyNum: number;
companyId: number;
companyName: string;
education: string;
experience: string;
isApply: number;
isCollection: number;
isHot: number;
jobId: number;
jobLocation: string;
jobLocationAreaCode: number;
jobTitle: string;
latitude: number;
longitude: number;
maxSalary: number;
minSalary: number;
postingDate: string;
vacancies: number;
view: number;
release: number;
isPublish: number;
}
export interface AddParams {
applyNum?: number;
companyId?: number;
companyName?: string;
education?: string;
experience?: string;
isApply?: number;
isCollection?: number;
isHot?: number;
jobId?: number;
jobLocation?: string;
jobLocationAreaCode?: number;
jobTitle?: string;
latitude?: number;
longitude?: number;
maxSalary?: number;
minSalary?: number;
postingDate?: string;
vacancies?: number;
view?: number;
release?: number;
isPublish?: number;
}
export interface ListParams {
createTime?: string;
updateTime?: string;
remark?: string;
pageSize?: number;
current?: number;
}
export interface ManageIdResult {
code: number;
msg: string;
data: Manage;
rows: Array<any>;
total: number;
}
export interface ManagePageResult {
code: number;
msg: string;
total: number;
rows: Array<Manage>;
}
}
declare namespace API.ManagementList {
export interface Manage {
applyNum?: number;
companyId?: number;
companyName?: string;
education?: string;
experience?: string;
isApply?: number;
isCollection?: number;
isHot?: number;
jobId?: number;
jobLocation?: string;
jobLocationAreaCode?: string;
jobTitle?: string;
latitude?: number;
longitude?: number;
maxSalary?: number;
minSalary?: number;
postingDate?: string;
vacancies?: number;
view?: number;
release?: number;
isPublish?: number;
}
export interface AddParams {
applyNum?: number;
companyId?: number;
companyName?: string;
education?: string;
experience?: string;
isApply?: number;
isCollection?: number;
isHot?: number;
jobId?: number;
jobLocation?: string;
jobLocationAreaCode?: string;
jobTitle?: string;
latitude?: number;
longitude?: number;
maxSalary?: number;
minSalary?: number;
postingDate?: string;
vacancies?: number;
view?: number;
release?: number;
isPublish?: number;
}
export interface ListParams {
createTime?: string;
updateTime?: string;
remark?: string;
pageSize?: number;
current?: number;
}
export interface ManageIdResult {
code: number;
msg: string;
data: Manage;
rows: Array<any>;
total: number;
}
export interface ManagePageResult {
code: number;
msg: string;
total: number;
rows: Array<Manage>;
}
}

View File

@@ -1,26 +1,33 @@
declare namespace API.ClassifyJobs {
export interface Result {
total: number;
rows: Jobs[];
code: number;
msg: string;
}
export interface Jobs {
[x: string]: number;
createTime?: any;
jobId: number;
parentId: number;
jobName: string;
orderNum: number;
status: string;
}
export interface Params {
jobId?: number;
parentId?: number;
jobName?: string;
orderNum?: number;
status?: string;
}
}
declare namespace API.ClassifyJobs {
export interface Result {
total: number;
rows: Jobs[];
code: number;
msg: string;
}
export interface Jobs {
createTime?: string;
jobId: number;
parentId: number;
jobName: string;
orderNum: number;
status: string;
children?:Jobs[];
depth?: number;
parentName?: string;
}
export interface JobTreeNode extends Jobs {
children: JobTreeNode[];
depth: number;
}
export interface Params {
jobId?: number;
parentId?: number;
jobName?: string;
orderNum?: number;
status?: string;
tree?:boolean;
}
}

74
src/typings.d.ts vendored
View File

@@ -1,44 +1,32 @@
declare module 'slash2';
declare module '*.css';
declare module '*.less';
declare module '*.scss';
declare module '*.sass';
declare module '*.svg';
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.gif';
declare module '*.bmp';
declare module '*.tiff';
declare module 'omit.js';
declare module 'numeral';
declare module '@antv/data-set';
declare module 'mockjs';
declare module 'react-fittext';
declare module 'bizcharts-plugin-slider';
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
declare namespace API {
namespace ClassifyJobs {
interface Params {
tree?: boolean;
pageSize?: number;
current?: number;
jobName?: string;
status?: string;
[key: string]: any; // 允许其他未定义属性
}
// 表格和表单使用的职业数据
interface Job {
jobId: number;
parentId: number;
jobName: string;
orderNum?: number;
status?: string;
createTime?: string;
parentName?: string;
children?: Job[];
}
}
declare module 'slash2';
declare module '*.css';
declare module '*.less';
declare module '*.scss';
declare module '*.sass';
declare module '*.svg';
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.gif';
declare module '*.bmp';
declare module '*.tiff';
declare module 'omit.js';
declare module 'numeral';
declare module '@antv/data-set';
declare module 'mockjs';
declare module 'react-fittext';
declare module 'bizcharts-plugin-slider';
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
declare namespace API {
namespace ClassifyJobs {
interface Params {
tree?: boolean;
pageSize?: number;
current?: number;
jobName?: string;
status?: string;
[key: string]: any; // 允许其他未定义属性
}
}
}