政策下载功能开发
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
This commit is contained in:
@@ -17,8 +17,8 @@ export default {
|
||||
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
|
||||
'/api/': {
|
||||
// 要代理的地址
|
||||
target: localBackendUrl,
|
||||
// target: 'http://39.98.44.136:6024/api/shihezi/', // 线上环境
|
||||
// target: localBackendUrl, // 本地环境
|
||||
target: 'http://39.98.44.136:6024/api/shihezi/', // 线上环境
|
||||
// target: 'http://wykj.cdwsx.com/api',// 后端
|
||||
// target: 'http://ks.zhaopinzao8dian.com/api/ks',
|
||||
// 配置了这个可以从 http 代理到 https
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '@ant-design/icons';
|
||||
import { history } from '@umijs/max';
|
||||
import JobPortalHeader from '@/components/JobPortalHeader';
|
||||
import { getPortalPolicyList } from '@/services/cms/policyInfo';
|
||||
import { getPortalPolicyList, exportPolicy } from '@/services/cms/policyInfo';
|
||||
import { getDictValueEnum } from '@/services/system/dict';
|
||||
import type { DictValueEnumObj } from '@/components/DictTag';
|
||||
import './index.less';
|
||||
@@ -34,7 +34,9 @@ const PolicyListPage: React.FC = () => {
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [selectedPolicyTag, setSelectedPolicyTag] = useState<string>('__recommended__');
|
||||
const [selectedPolicyCategory, setSelectedPolicyCategory] = useState<string>('');
|
||||
const [userTypeEnum, setUserTypeEnum] = useState<DictValueEnumObj>({});
|
||||
const [policyCategoryEnum, setPolicyCategoryEnum] = useState<DictValueEnumObj>({});
|
||||
|
||||
/** 从 localStorage 读取当前用户的 personnel type */
|
||||
const currentUserType = (() => {
|
||||
@@ -56,6 +58,9 @@ const PolicyListPage: React.FC = () => {
|
||||
setSelectedPolicyTag('');
|
||||
}
|
||||
});
|
||||
getDictValueEnum('policy_category', false, true).then((data) => {
|
||||
setPolicyCategoryEnum(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
/** 将字典枚举转为标签数组,按 value 排序 */
|
||||
@@ -63,6 +68,11 @@ const PolicyListPage: React.FC = () => {
|
||||
.map((item) => ({ label: item.label, value: item.value }))
|
||||
.sort((a, b) => Number(a.value) - Number(b.value));
|
||||
|
||||
/** 将政策分类字典转为标签数组 */
|
||||
const policyCategoryTags = Object.values(policyCategoryEnum)
|
||||
.map((item) => ({ label: item.label, value: String(item.value) }))
|
||||
.sort((a, b) => Number(a.value) - Number(b.value));
|
||||
|
||||
/** 将内部标记转为实际 API 参数 */
|
||||
const resolvePolicyTag = (tag: string): string | undefined => {
|
||||
if (tag === '__recommended__') {
|
||||
@@ -79,6 +89,7 @@ const PolicyListPage: React.FC = () => {
|
||||
pageSize,
|
||||
searchValue: keyword || undefined,
|
||||
policyTag: resolvePolicyTag(selectedPolicyTag),
|
||||
policyCategory: selectedPolicyCategory || undefined,
|
||||
});
|
||||
if (response?.code === 200) {
|
||||
setList(response.rows || []);
|
||||
@@ -92,7 +103,7 @@ const PolicyListPage: React.FC = () => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [pageNum, pageSize, keyword, selectedPolicyTag]);
|
||||
}, [pageNum, pageSize, keyword, selectedPolicyTag, selectedPolicyCategory]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchList();
|
||||
@@ -113,6 +124,16 @@ const PolicyListPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 点击政策分类标签:选中/取消选中 */
|
||||
const handlePolicyCategoryClick = (tagValue: string) => {
|
||||
setPageNum(1);
|
||||
if (selectedPolicyCategory === tagValue) {
|
||||
setSelectedPolicyCategory('');
|
||||
} else {
|
||||
setSelectedPolicyCategory(tagValue);
|
||||
}
|
||||
};
|
||||
|
||||
const handleItemClick = (item: API.PolicyInfo.PolicyInfoItem) => {
|
||||
history.push(`/job-portal/policy/detail?id=${item.id}`);
|
||||
};
|
||||
@@ -131,6 +152,31 @@ const PolicyListPage: React.FC = () => {
|
||||
document.body.removeChild(link);
|
||||
};
|
||||
|
||||
/** 导出政策 */
|
||||
const handleExport = async (e: React.MouseEvent, item: API.PolicyInfo.PolicyInfoItem) => {
|
||||
e.stopPropagation();
|
||||
try {
|
||||
const blob = await exportPolicy(item.id);
|
||||
// 如果后端返回 JSON 错误(如 401),blob 可能仍是 JSON 格式
|
||||
if (blob.type === 'application/json') {
|
||||
const text = await blob.text();
|
||||
const err = JSON.parse(text);
|
||||
message.error(err.msg || '导出失败');
|
||||
return;
|
||||
}
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `${item.zcmc || '政策'}.docx`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (err: any) {
|
||||
message.error(err?.message || '导出失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="policy-page">
|
||||
<JobPortalHeader showSearch={false} showHotJobs={false} />
|
||||
@@ -188,6 +234,24 @@ const PolicyListPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{policyCategoryTags.length > 0 && (
|
||||
<div className="policy-tag-filter">
|
||||
<span className="policy-tag-filter__label">政策分类:</span>
|
||||
<div className="policy-tag-filter__tags">
|
||||
{policyCategoryTags.map((tag) => (
|
||||
<Tag
|
||||
key={tag.value}
|
||||
className={`policy-tag-filter__item ${
|
||||
selectedPolicyCategory === tag.value ? 'policy-tag-filter__item--active' : ''
|
||||
}`}
|
||||
onClick={() => handlePolicyCategoryClick(tag.value)}
|
||||
>
|
||||
{tag.label}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{list.length > 0 ? (
|
||||
<>
|
||||
<List
|
||||
@@ -219,6 +283,14 @@ const PolicyListPage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
className="policy-download-btn policy-export-btn"
|
||||
title="导出政策"
|
||||
onClick={(e) => handleExport(e, item)}
|
||||
>
|
||||
<DownloadOutlined />
|
||||
<span className="policy-download-btn__text">导出</span>
|
||||
</span>
|
||||
{item.fileUrl && (
|
||||
<span
|
||||
className="policy-download-btn"
|
||||
|
||||
@@ -19,6 +19,7 @@ const DetailModal: React.FC<DetailModalProps> = ({ open, data, onCancel }) => {
|
||||
<Descriptions column={2} bordered size="small">
|
||||
<Descriptions.Item label="政策名称" span={2}>{data?.zcmc}</Descriptions.Item>
|
||||
<Descriptions.Item label="政策类型">{data?.zclx}</Descriptions.Item>
|
||||
<Descriptions.Item label="政策分类">{data?.policyCategory || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="政策级别">{data?.zcLevel}</Descriptions.Item>
|
||||
<Descriptions.Item label="发文单位">{data?.sourceUnit}</Descriptions.Item>
|
||||
<Descriptions.Item label="受理单位">{data?.acceptUnit}</Descriptions.Item>
|
||||
|
||||
@@ -23,11 +23,15 @@ const EditModal: React.FC<EditModalProps> = ({ open, values, onCancel, onSubmit
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [userTypeEnum, setUserTypeEnum] = useState<DictValueEnumObj>({});
|
||||
const [policyCategoryEnum, setPolicyCategoryEnum] = useState<DictValueEnumObj>({});
|
||||
|
||||
useEffect(() => {
|
||||
getDictValueEnum('user_type', false, true).then((data) => {
|
||||
setUserTypeEnum(data);
|
||||
});
|
||||
getDictValueEnum('policy_category', false, true).then((data) => {
|
||||
setPolicyCategoryEnum(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -59,6 +63,13 @@ const EditModal: React.FC<EditModalProps> = ({ open, values, onCancel, onSubmit
|
||||
}
|
||||
}, [open, values, form]);
|
||||
|
||||
// 字典选项加载完成后,重新回填 policyCategory 确保 Select 正确显示
|
||||
useEffect(() => {
|
||||
if (open && values?.policyCategory && Object.keys(policyCategoryEnum).length > 0) {
|
||||
form.setFieldsValue({ policyCategory: values.policyCategory });
|
||||
}
|
||||
}, [open, policyCategoryEnum, values, form]);
|
||||
|
||||
const handleUpload = async (file: File) => {
|
||||
setUploading(true);
|
||||
try {
|
||||
@@ -113,6 +124,11 @@ const EditModal: React.FC<EditModalProps> = ({ open, values, onCancel, onSubmit
|
||||
value: item.value,
|
||||
}));
|
||||
|
||||
const policyCategoryOptions = Object.values(policyCategoryEnum).map((item) => ({
|
||||
label: item.label,
|
||||
value: item.value,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={values ? '编辑政策' : '新增政策'}
|
||||
@@ -139,6 +155,15 @@ const EditModal: React.FC<EditModalProps> = ({ open, values, onCancel, onSubmit
|
||||
<Input placeholder="请输入政策级别" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="policyCategory" label="政策分类">
|
||||
<Select
|
||||
allowClear
|
||||
placeholder="请选择政策分类"
|
||||
options={policyCategoryOptions}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="policyTag" label="人员类型">
|
||||
<Select
|
||||
|
||||
@@ -24,11 +24,15 @@ const PolicyMgmt: React.FC = () => {
|
||||
const [currentRow, setCurrentRow] = useState<API.PolicyInfo.PolicyInfoItem>();
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
const [userTypeEnum, setUserTypeEnum] = useState<DictValueEnumObj>({});
|
||||
const [policyCategoryEnum, setPolicyCategoryEnum] = useState<DictValueEnumObj>({});
|
||||
|
||||
useEffect(() => {
|
||||
getDictValueEnum('user_type', false, true).then((data) => {
|
||||
setUserTypeEnum(data);
|
||||
});
|
||||
getDictValueEnum('policy_category', false, true).then((data) => {
|
||||
setPolicyCategoryEnum(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleDelete = async (ids: string) => {
|
||||
@@ -103,6 +107,16 @@ const PolicyMgmt: React.FC = () => {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '政策分类',
|
||||
dataIndex: 'policyCategory',
|
||||
hideInSearch: true,
|
||||
width: 120,
|
||||
render: (_, record) => {
|
||||
if (!record.policyCategory) return '-';
|
||||
return <DictTag enums={policyCategoryEnum} value={record.policyCategory} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '发文单位',
|
||||
dataIndex: 'sourceUnit',
|
||||
|
||||
@@ -71,3 +71,12 @@ export async function uploadPolicyFile(file: File) {
|
||||
data: formData,
|
||||
});
|
||||
}
|
||||
|
||||
// 导出/下载政策
|
||||
export async function exportPolicy(id: number | string) {
|
||||
return request('/api/cms/policyInfo/exportUtil', {
|
||||
method: 'GET',
|
||||
params: { id },
|
||||
responseType: 'blob',
|
||||
});
|
||||
}
|
||||
|
||||
2
src/types/cms/policyInfo.d.ts
vendored
2
src/types/cms/policyInfo.d.ts
vendored
@@ -25,6 +25,7 @@ declare namespace API.PolicyInfo {
|
||||
export interface PolicyInfoItem {
|
||||
id: number;
|
||||
policyTag?: string;
|
||||
policyCategory?: string;
|
||||
zcmc: string;
|
||||
zclx: string;
|
||||
zcLevel: string;
|
||||
@@ -51,5 +52,6 @@ declare namespace API.PolicyInfo {
|
||||
pageSize?: number;
|
||||
searchValue?: string;
|
||||
policyTag?: string;
|
||||
policyCategory?: string;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user