政策筛选功能开发
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:
@@ -51,8 +51,70 @@
|
||||
}
|
||||
}
|
||||
|
||||
.policy-tag-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid @jp-border;
|
||||
|
||||
&__label {
|
||||
flex-shrink: 0;
|
||||
line-height: 22px;
|
||||
font-size: 13px;
|
||||
color: @jp-text-secondary;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
border-radius: @jp-radius;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
color: @jp-primary;
|
||||
border-color: @jp-primary;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: #fff !important;
|
||||
background: @jp-primary !important;
|
||||
border-color: @jp-primary !important;
|
||||
}
|
||||
|
||||
&--recommend {
|
||||
color: #ec4827 !important;
|
||||
background: #fff5f3 !important;
|
||||
border-color: rgba(236, 72, 39, 0.25) !important;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
color: #ec4827 !important;
|
||||
border-color: #ec4827 !important;
|
||||
}
|
||||
|
||||
&.policy-tag-filter__item--active {
|
||||
color: #fff !important;
|
||||
background: #ec4827 !important;
|
||||
border-color: #ec4827 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.policy-list {
|
||||
.policy-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px 0;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid @jp-border;
|
||||
@@ -71,6 +133,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
.policy-item-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.policy-download-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
margin-left: 16px;
|
||||
padding: 6px 14px;
|
||||
font-size: 13px;
|
||||
color: @jp-primary;
|
||||
background: #fff;
|
||||
border: 1px solid @jp-primary;
|
||||
border-radius: @jp-radius;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background: @jp-primary;
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.policy-title {
|
||||
margin: 0 0 10px;
|
||||
color: @jp-text-primary;
|
||||
|
||||
@@ -14,10 +14,13 @@ import {
|
||||
FileTextOutlined,
|
||||
SearchOutlined,
|
||||
BankOutlined,
|
||||
DownloadOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { history } from '@umijs/max';
|
||||
import JobPortalHeader from '@/components/JobPortalHeader';
|
||||
import { getPolicyInfoList } from '@/services/cms/policyInfo';
|
||||
import { getDictValueEnum } from '@/services/system/dict';
|
||||
import type { DictValueEnumObj } from '@/components/DictTag';
|
||||
import './index.less';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
@@ -30,6 +33,43 @@ const PolicyListPage: React.FC = () => {
|
||||
const [pageSize] = useState(10);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [selectedPolicyTag, setSelectedPolicyTag] = useState<string>('__recommended__');
|
||||
const [userTypeEnum, setUserTypeEnum] = useState<DictValueEnumObj>({});
|
||||
|
||||
/** 从 localStorage 读取当前用户的 personnel type */
|
||||
const currentUserType = (() => {
|
||||
try {
|
||||
const raw = localStorage.getItem('userInfo');
|
||||
if (raw) {
|
||||
const userInfo = JSON.parse(raw);
|
||||
return userInfo?.userType ? String(userInfo.userType) : '';
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
return '';
|
||||
})();
|
||||
|
||||
useEffect(() => {
|
||||
getDictValueEnum('user_type', false, true).then((data) => {
|
||||
setUserTypeEnum(data);
|
||||
// 无用户类型时默认选中「全部」
|
||||
if (!currentUserType) {
|
||||
setSelectedPolicyTag('');
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
/** 将字典枚举转为标签数组,按 value 排序 */
|
||||
const userTypeTags = Object.values(userTypeEnum)
|
||||
.map((item) => ({ label: item.label, value: item.value }))
|
||||
.sort((a, b) => Number(a.value) - Number(b.value));
|
||||
|
||||
/** 将内部标记转为实际 API 参数 */
|
||||
const resolvePolicyTag = (tag: string): string | undefined => {
|
||||
if (tag === '__recommended__') {
|
||||
return currentUserType || undefined;
|
||||
}
|
||||
return tag || undefined;
|
||||
};
|
||||
|
||||
const fetchList = useCallback(async () => {
|
||||
try {
|
||||
@@ -38,6 +78,7 @@ const PolicyListPage: React.FC = () => {
|
||||
pageNum,
|
||||
pageSize,
|
||||
searchValue: keyword || undefined,
|
||||
policyTag: resolvePolicyTag(selectedPolicyTag),
|
||||
});
|
||||
if (response?.code === 200) {
|
||||
setList(response.rows || []);
|
||||
@@ -51,7 +92,7 @@ const PolicyListPage: React.FC = () => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [pageNum, pageSize, keyword]);
|
||||
}, [pageNum, pageSize, keyword, selectedPolicyTag]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchList();
|
||||
@@ -62,10 +103,34 @@ const PolicyListPage: React.FC = () => {
|
||||
setKeyword(searchValue.trim());
|
||||
};
|
||||
|
||||
/** 点击人员类型标签:选中/取消选中 */
|
||||
const handleTagClick = (tagValue: string) => {
|
||||
setPageNum(1);
|
||||
if (selectedPolicyTag === tagValue) {
|
||||
setSelectedPolicyTag('');
|
||||
} else {
|
||||
setSelectedPolicyTag(tagValue);
|
||||
}
|
||||
};
|
||||
|
||||
const handleItemClick = (item: API.PolicyInfo.PolicyInfoItem) => {
|
||||
history.push(`/job-portal/policy/detail?id=${item.id}`);
|
||||
};
|
||||
|
||||
/** 下载政策附件 */
|
||||
const handleDownload = (e: React.MouseEvent, item: API.PolicyInfo.PolicyInfoItem) => {
|
||||
e.stopPropagation();
|
||||
if (!item.fileUrl) return;
|
||||
const link = document.createElement('a');
|
||||
link.href = item.fileUrl;
|
||||
link.download = item.fileName || '';
|
||||
link.target = '_blank';
|
||||
link.rel = 'noopener noreferrer';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="policy-page">
|
||||
<JobPortalHeader showSearch={false} showHotJobs={false} />
|
||||
@@ -95,6 +160,34 @@ const PolicyListPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<Spin spinning={loading}>
|
||||
{userTypeTags.length > 0 && (
|
||||
<div className="policy-tag-filter">
|
||||
<span className="policy-tag-filter__label">人员类型:</span>
|
||||
<div className="policy-tag-filter__tags">
|
||||
{currentUserType && (
|
||||
<Tag
|
||||
className={`policy-tag-filter__item policy-tag-filter__item--recommend ${
|
||||
selectedPolicyTag === '__recommended__' ? 'policy-tag-filter__item--active' : ''
|
||||
}`}
|
||||
onClick={() => handleTagClick('__recommended__')}
|
||||
>
|
||||
推荐
|
||||
</Tag>
|
||||
)}
|
||||
{userTypeTags.map((tag) => (
|
||||
<Tag
|
||||
key={tag.value}
|
||||
className={`policy-tag-filter__item ${
|
||||
selectedPolicyTag === tag.value ? 'policy-tag-filter__item--active' : ''
|
||||
}`}
|
||||
onClick={() => handleTagClick(tag.value)}
|
||||
>
|
||||
{tag.label}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{list.length > 0 ? (
|
||||
<>
|
||||
<List
|
||||
@@ -126,6 +219,16 @@ const PolicyListPage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{item.fileUrl && (
|
||||
<span
|
||||
className="policy-download-btn"
|
||||
title={`下载 ${item.fileName || '附件'}`}
|
||||
onClick={(e) => handleDownload(e, item)}
|
||||
>
|
||||
<DownloadOutlined />
|
||||
<span className="policy-download-btn__text">下载</span>
|
||||
</span>
|
||||
)}
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
|
||||
1
src/types/cms/policyInfo.d.ts
vendored
1
src/types/cms/policyInfo.d.ts
vendored
@@ -49,5 +49,6 @@ declare namespace API.PolicyInfo {
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
searchValue?: string;
|
||||
policyTag?: string;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user