From cd92dd46286ccf6543b073752a372879735484ff Mon Sep 17 00:00:00 2001 From: francis-fh Date: Wed, 22 Jul 2026 18:26:51 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=80=E5=8E=86=E7=AD=9B=E9=80=89=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/proxy.ts | 4 +- src/pages/JobPortal/PersonalCenter/index.tsx | 61 ++++++--- .../Management/List/SeeMatching/index.tsx | 31 ++++- .../List/SeeMatching/resumeFilter.tsx | 119 ++++++++++++++++++ src/services/Management/list.ts | 8 ++ src/services/jobportal/user.ts | 9 ++ 6 files changed, 214 insertions(+), 18 deletions(-) create mode 100644 src/pages/Management/List/SeeMatching/resumeFilter.tsx diff --git a/config/proxy.ts b/config/proxy.ts index a1b58a6..6a91cb1 100644 --- a/config/proxy.ts +++ b/config/proxy.ts @@ -17,9 +17,9 @@ export default { // localhost:8000/api/** -> https://preview.pro.ant.design/api/** '/api/': { // 要代理的地址 - target: localBackendUrl, + // target: localBackendUrl, // target: 'http://39.98.44.136:6024/api/shihezi/', // 线上环境 - // target: 'http://test.xjshzly.longbiosphere.com/api/shihezi/', // 测试环境 + target: 'https://test.xjshzly.longbiosphere.com/api/shihezi/', // 测试环境 // target: 'http://wykj.cdwsx.com/api',// 后端 // target: 'http://ks.zhaopinzao8dian.com/api/ks', // 配置了这个可以从 http 代理到 https diff --git a/src/pages/JobPortal/PersonalCenter/index.tsx b/src/pages/JobPortal/PersonalCenter/index.tsx index 35ea3ce..ac2966a 100644 --- a/src/pages/JobPortal/PersonalCenter/index.tsx +++ b/src/pages/JobPortal/PersonalCenter/index.tsx @@ -9,7 +9,9 @@ import { Progress, Tag, Spin, - Divider + Divider, + Switch, + message, } from 'antd'; import { UserOutlined, @@ -24,7 +26,7 @@ import { history } from '@umijs/max'; import JobPortalHeader from '@/components/JobPortalHeader'; import useAppUserModel from '@/models/jobportal/user'; import { getDictValueEnum } from '@/services/system/dict'; -import { getMyTj } from '@/services/jobportal/user'; +import { getMyTj, changeResumeStatus } from '@/services/jobportal/user'; import defaultAvatar from '@/assets/avatar.jpg'; import './index.less'; @@ -51,7 +53,7 @@ const calculateResumeCompleteness = (userInfo: API.AppUserInfo | null): number = }; const PersonalCenter: React.FC = () => { - const { userInfo, loading, fetchUserInfo } = useAppUserModel(); + const { userInfo, loading, fetchUserInfo, updateUserInfo } = useAppUserModel(); const [dictData, setDictData] = useState<{ sex?: Record; education?: Record; @@ -166,6 +168,25 @@ const PersonalCenter: React.FC = () => { return !!(userInfo?.idCard && userInfo.idCard.trim()); }, [userInfo?.idCard]); + const handleResumeStatusChange = async (checked: boolean) => { + if (!userInfo?.userId) return; + const newStatus = checked ? '1' : '2'; + try { + const response = await changeResumeStatus({ + userId: userInfo.userId, + resumeStatus: newStatus, + }); + if (response?.code === 200) { + // 同步更新 React 状态和本地缓存 + const updatedInfo = { ...userInfo, resumeStatus: newStatus }; + updateUserInfo(updatedInfo); + message.success(checked ? '简历已公开' : '简历已设为不公开'); + } + } catch (error) { + console.error('修改简历公开状态失败:', error); + } + }; + const services = useMemo(() => [ { id: 1, @@ -193,15 +214,6 @@ const PersonalCenter: React.FC = () => { color: '#1677ff', link: '/job-portal/personal-center/interviews' }, - { - id: 2, - title: '在线面试', - icon: , - status: '', - hasArrow: true, - color: '#1890ff', - link: 'https://mc.repohub.cn/pro.html' - }, { id: 4, title: '通知与提醒', @@ -209,8 +221,19 @@ const PersonalCenter: React.FC = () => { status: '已开启', hasArrow: false, color: '#fa8c16' - } - ], [isRealNameVerified]); + }, + { + id: 7, + title: '公开简历', + icon: , + hasArrow: false, + color: '#1677ff', + switchConfig: { + checked: userInfo?.resumeStatus !== '2', + onChange: handleResumeStatusChange, + } + }, + ], [isRealNameVerified, userInfo?.resumeStatus]); const handleServiceClick = (service: any) => { if (service.link) { @@ -348,7 +371,15 @@ const PersonalCenter: React.FC = () => { )} - {service.hasArrow && } + {service.switchConfig ? ( + e.stopPropagation()} + /> + ) : service.hasArrow ? ( + + ) : null} )} /> diff --git a/src/pages/Management/List/SeeMatching/index.tsx b/src/pages/Management/List/SeeMatching/index.tsx index 135fbcc..37cb7b6 100644 --- a/src/pages/Management/List/SeeMatching/index.tsx +++ b/src/pages/Management/List/SeeMatching/index.tsx @@ -2,7 +2,7 @@ import React, { Fragment, useEffect, useRef, useState } from 'react'; import { FormattedMessage, useAccess, useParams } from '@umijs/max'; import { Button, FormInstance, message, Tag } from 'antd'; import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; -import { FormOutlined, PlusOutlined, AlignLeftOutlined, SendOutlined } from '@ant-design/icons'; +import { FormOutlined, PlusOutlined, AlignLeftOutlined, SendOutlined, FilterOutlined } from '@ant-design/icons'; import { getDictValueEnum } from '@/services/system/dict'; import DictTag from '@/components/DictTag'; import { exportCmsAppUserExport } from '@/services/mobileusers/list'; @@ -16,6 +16,7 @@ import Detail from './detail'; import Hire from './hire'; import ResumeView from './resumeView'; import InterviewInvite from '../ResumeRecommend/InterviewInvite'; +import ResumeFilter from './resumeFilter'; const handleExport = async (values: API.MobileUser.ListParams) => { @@ -53,6 +54,7 @@ function ManagementList() { const [matchingDegree, setMatchingDegree] = useState(null); const [resumeVisible, setResumeVisible] = useState(false); const [inviteVisible, setInviteVisible] = useState(false); + const [filterVisible, setFilterVisible] = useState(false); const [hireAdd, setHireAdd] = useState(null); const [mode, setMode] = useState<'view' | 'edit' | 'create'>('create'); const params = useParams(); @@ -250,6 +252,21 @@ function ManagementList() { > 查看匹配详情 + , +
+
], }, @@ -353,6 +370,18 @@ function ManagementList() { } }} /> + { + setFilterVisible(false); + setCurrentRow(undefined); + if (needRefresh) { + actionRef.current?.reload(); + } + }} + /> ); diff --git a/src/pages/Management/List/SeeMatching/resumeFilter.tsx b/src/pages/Management/List/SeeMatching/resumeFilter.tsx new file mode 100644 index 0000000..b7a160f --- /dev/null +++ b/src/pages/Management/List/SeeMatching/resumeFilter.tsx @@ -0,0 +1,119 @@ +import { Modal, Form, Radio, Select, message } from 'antd'; +import React, { useEffect, useState } from 'react'; +import { filterQzz } from '@/services/Management/list'; +import { getDictValueEnum } from '@/services/system/dict'; + +const { Option } = Select; + +export type ResumeFilterProps = { + onClose: (needRefresh?: boolean) => void; + open: boolean; + applyId?: string; + userName?: string; +}; + +const ResumeFilter: React.FC = (props) => { + const { open, applyId, userName } = props; + + const [form] = Form.useForm(); + const [submitting, setSubmitting] = useState(false); + const [filterStatus, setFilterStatus] = useState('0'); + const [reasonEnum, setReasonEnum] = useState({}); + + useEffect(() => { + if (open) { + form.resetFields(); + setFilterStatus('0'); + // 加载不通过筛选原因的字典 + getDictValueEnum('resume_file_type', false, true).then((data) => { + setReasonEnum(data); + }); + } + }, [open]); + + const handleSubmit = async () => { + try { + const values = await form.validateFields(); + setSubmitting(true); + + const payload: { id: string; filterStatus: string; filterReason?: string } = { + id: applyId || '', + filterStatus: values.filterStatus, + }; + + // 如果不通过筛选,拼接原因 + if (values.filterStatus === '2' && values.filterReason && values.filterReason.length > 0) { + payload.filterReason = values.filterReason.join('、'); + } + + const response = await filterQzz(payload); + if (response.code === 200) { + message.success('简历筛选完成'); + form.resetFields(); + props.onClose(true); + } else { + message.error(response.msg || '筛选失败'); + } + } catch (error: any) { + const errMsg = error?.response?.data?.msg || error?.message || '简历筛选失败'; + message.error(errMsg); + console.error('简历筛选失败:', error); + } finally { + setSubmitting(false); + } + }; + + return ( + props.onClose()} + title={`简历筛选${userName ? ` - ${userName}` : ''}`} + width={520} + onOk={handleSubmit} + confirmLoading={submitting} + destroyOnClose + > +
+ + setFilterStatus(e.target.value)} + > + 通过筛选 + 不通过筛选 + + + + {filterStatus === '2' && ( + + + + )} +
+
+ ); +}; + +export default ResumeFilter; diff --git a/src/services/Management/list.ts b/src/services/Management/list.ts index 778d428..f98a9e1 100644 --- a/src/services/Management/list.ts +++ b/src/services/Management/list.ts @@ -158,6 +158,14 @@ export async function getAppSkillList(params?: { userId?: number }) { // ========== 面试消息角标 APIs ========== +/** 简历筛选 */ +export async function filterQzz(params?: { id: string; filterStatus: string; filterReason?: string }) { + return request(`/api/cms/jobApply/filterQzz`, { + method: 'PUT', + data: params, + }); +} + /** 获取面试消息角标数量(后台管理端菜单角标) */ export async function getInterviewBadgeCount() { return request<{ diff --git a/src/services/jobportal/user.ts b/src/services/jobportal/user.ts index 5430411..e1a4c76 100644 --- a/src/services/jobportal/user.ts +++ b/src/services/jobportal/user.ts @@ -182,6 +182,15 @@ export async function submitJobComplaint(params: { }); } +/** 修改简历公开状态 POST /api/cms/appUser/changeResumeStatus */ +export async function changeResumeStatus(params: { userId: number; resumeStatus: string }, options?: Record) { + return request('/api/cms/appUser/changeResumeStatus', { + method: 'POST', + data: params, + ...(options || {}), + }); +} + /** 屏蔽企业 POST /cms/blockCompany */ export async function blockCompany(params: { userId: number; companyId: number }) { return request('/api/cms/blockCompany', {