bug修复
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:
FengHui
2026-05-26 17:06:53 +08:00
parent b7d7437c21
commit 7b38f5b96a
14 changed files with 20726 additions and 121 deletions

View File

@@ -0,0 +1,164 @@
.company-detail {
&__header {
margin: -8px -8px 20px;
padding: 20px 24px;
border-radius: 8px;
background: linear-gradient(135deg, #f0f5ff 0%, #e6f4ff 50%, #f9f0ff 100%);
border: 1px solid #d6e4ff;
}
&__name {
margin: 0 0 10px;
font-size: 20px;
font-weight: 600;
line-height: 1.4;
color: rgba(0, 0, 0, 0.88);
word-break: break-word;
}
&__meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
&__industry {
font-size: 13px;
color: rgba(0, 0, 0, 0.55);
padding: 2px 10px;
background: rgba(255, 255, 255, 0.75);
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.06);
}
&__section {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
&__section-title {
position: relative;
margin-bottom: 12px;
padding-left: 10px;
font-size: 15px;
font-weight: 600;
color: rgba(0, 0, 0, 0.88);
line-height: 1.5;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
width: 3px;
height: 14px;
margin-top: -7px;
border-radius: 2px;
background: #1677ff;
}
}
&__desc {
:global {
.ant-descriptions-item-label {
width: 108px;
font-weight: 500;
color: rgba(0, 0, 0, 0.65);
background: #fafafa !important;
}
.ant-descriptions-item-content {
color: rgba(0, 0, 0, 0.88);
}
}
}
&__intro {
padding: 14px 16px;
font-size: 14px;
line-height: 1.75;
color: rgba(0, 0, 0, 0.75);
white-space: pre-wrap;
word-break: break-word;
background: #fafafa;
border: 1px solid #f0f0f0;
border-radius: 8px;
}
&__contacts {
display: flex;
flex-direction: column;
gap: 10px;
}
&__contact-card {
display: flex;
gap: 14px;
padding: 14px 16px;
background: #fff;
border: 1px solid #f0f0f0;
border-radius: 8px;
transition: box-shadow 0.2s, border-color 0.2s;
&:hover {
border-color: #d6e4ff;
box-shadow: 0 2px 8px rgba(22, 119, 255, 0.08);
}
}
&__contact-avatar {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
font-size: 18px;
color: #1677ff;
background: #e6f4ff;
border-radius: 50%;
}
&__contact-body {
flex: 1;
min-width: 0;
}
&__contact-name {
margin-bottom: 6px;
font-size: 15px;
font-weight: 600;
color: rgba(0, 0, 0, 0.88);
}
&__contact-row {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 4px;
font-size: 13px;
color: rgba(0, 0, 0, 0.65);
&:last-child {
margin-bottom: 0;
}
:global(.anticon) {
color: rgba(0, 0, 0, 0.35);
font-size: 13px;
}
}
&__empty {
color: rgba(0, 0, 0, 0.25);
}
&__footer {
display: flex;
justify-content: flex-end;
}
}

View File

@@ -8,10 +8,26 @@ import {
ProFormTextArea,
ProFormTreeSelect,
} from '@ant-design/pro-components';
import { Form, Button, message, Modal, Descriptions, Space } from 'antd';
import { PlusOutlined, MinusCircleOutlined, DeleteOutlined } from '@ant-design/icons';
import { Form, Button, message, Modal, Descriptions, Space, Spin, Empty, Tag } from 'antd';
import {
PlusOutlined,
MinusCircleOutlined,
DeleteOutlined,
IdcardOutlined,
PhoneOutlined,
UserOutlined,
} from '@ant-design/icons';
import DictTag, { DictValueEnumObj } from '@/components/DictTag';
import { getCmsIndustryTreeList } from '@/services/classify/industry';
import './detail.less';
const renderDetailText = (value?: string | null) => {
const text = value?.toString().trim();
if (!text) {
return <span className="company-detail__empty"></span>;
}
return text;
};
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: API.CompanyList.Company) => Promise<void>;
@@ -189,52 +205,125 @@ export const CompanyDetailView = ({
open,
onCancel,
record,
scaleEnum
scaleEnum,
loading,
}: {
open: boolean;
onCancel: () => void;
record?: API.CompanyList.Company;
scaleEnum?: DictValueEnumObj;
loading?: boolean;
}) => {
const contacts = record?.companyContactList?.filter(
(c) => c.contactPerson || c.contactPersonPhone || c.position,
);
const statusTag =
record?.status === 1 ? (
<Tag color="success"></Tag>
) : record?.status === 2 ? (
<Tag color="error"></Tag>
) : record?.status !== undefined ? (
<Tag></Tag>
) : null;
return (
<Modal
title="公司详情"
title="企业详情"
open={open}
width={600}
width={720}
centered
onCancel={onCancel}
footer={[
<Button key="back" onClick={onCancel}>
</Button>,
]}
destroyOnClose
styles={{ body: { paddingTop: 16 } }}
footer={
<div className="company-detail__footer">
<Button type="primary" onClick={onCancel}>
</Button>
</div>
}
>
<div style={{ padding: '20px' }}>
<Descriptions column={1} bordered>
<Descriptions.Item label="单位名称">{record?.name}</Descriptions.Item>
<Descriptions.Item label="主要行业">{record?.industry}</Descriptions.Item>
<Descriptions.Item label="单位规模">
<DictTag enums={scaleEnum} value={record?.scale} />
</Descriptions.Item>
<Descriptions.Item label="公司位置">{record?.location}</Descriptions.Item>
<Descriptions.Item label="信用代码">{record?.code}</Descriptions.Item>
<Descriptions.Item label="单位介绍">{record?.description}</Descriptions.Item>
<Descriptions.Item label="企业联系人">
{record?.companyContactList && record.companyContactList.length > 0 ? (
<div>
{record.companyContactList.map((contact, index) => (
<div key={index} style={{ marginBottom: 8 }}>
<div><strong></strong>{contact.contactPerson}</div>
<div><strong></strong>{contact.contactPersonPhone}</div>
<div><strong></strong>{contact.position}</div>
<Spin spinning={loading}>
<div className="company-detail">
<div className="company-detail__header">
<h3 className="company-detail__name">{renderDetailText(record?.name)}</h3>
<div className="company-detail__meta">
{record?.scale != null && record.scale !== '' && (
<DictTag enums={scaleEnum} value={record.scale} />
)}
{statusTag}
{record?.industry ? (
<span className="company-detail__industry">{record.industry}</span>
) : null}
</div>
</div>
<div className="company-detail__section">
<div className="company-detail__section-title"></div>
<Descriptions
column={2}
bordered
size="middle"
className="company-detail__desc"
>
<Descriptions.Item label="公司位置" span={2}>
{renderDetailText(record?.location as string)}
</Descriptions.Item>
<Descriptions.Item label="信用代码" span={2}>
{renderDetailText(record?.code)}
</Descriptions.Item>
</Descriptions>
</div>
<div className="company-detail__section">
<div className="company-detail__section-title"></div>
{record?.description?.trim() ? (
<div className="company-detail__intro">{record.description}</div>
) : (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="暂无单位介绍"
/>
)}
</div>
<div className="company-detail__section">
<div className="company-detail__section-title"></div>
{contacts && contacts.length > 0 ? (
<div className="company-detail__contacts">
{contacts.map((contact, index) => (
<div key={index} className="company-detail__contact-card">
<div className="company-detail__contact-avatar">
<UserOutlined />
</div>
<div className="company-detail__contact-body">
<div className="company-detail__contact-name">
{renderDetailText(contact.contactPerson)}
</div>
<div className="company-detail__contact-row">
<PhoneOutlined />
<span>{renderDetailText(contact.contactPersonPhone)}</span>
</div>
{contact.position?.trim() ? (
<div className="company-detail__contact-row">
<IdcardOutlined />
<span>{contact.position}</span>
</div>
) : null}
</div>
</div>
))}
</div>
) : (
<span></span>
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="暂无联系人信息"
/>
)}
</Descriptions.Item>
</Descriptions>
</div>
</div>
</div>
</Spin>
</Modal>
);
};

View File

@@ -1,69 +1,29 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, FormInstance, message, Modal, Descriptions } from 'antd';
import { Button, FormInstance, message, Modal } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined, FormOutlined, PlusOutlined, EyeOutlined, AlignLeftOutlined, AuditOutlined } from '@ant-design/icons';
import EditCompanyListRow from './edit';
import { DeleteOutlined, FormOutlined, PlusOutlined, AlignLeftOutlined, AuditOutlined } from '@ant-design/icons';
import EditCompanyListRow, { CompanyDetailView } from './edit';
import {
addCmsCompanyList,
delCmsCompanyList,
exportCmsCompanyList,
getCmsCompanyList,
getCmsCompanyDetail,
parseCmsCompanyDetailResponse,
putCmsCompanyList,
} from '@/services/company/list';
import { getCmsCompanyDetail } from '@/services/company/list';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
import { postCompanyApproval } from '@/services/company/review';
// 详情查看组件
const CompanyDetailModal = ({
visible,
onCancel,
record,
scaleEnum
}: {
visible: boolean;
onCancel: () => void;
record?: API.CompanyList.Company;
scaleEnum: Record<string, any>;
}) => {
return (
<Modal
title="公司详情"
open={visible}
width={600}
onCancel={onCancel}
footer={[
<Button key="back" onClick={onCancel}>
</Button>,
]}
>
<Descriptions column={1} bordered>
<Descriptions.Item label="公司名称">{record?.name}</Descriptions.Item>
<Descriptions.Item label="公司行业">{record?.industry}</Descriptions.Item>
<Descriptions.Item label="公司规模">
<DictTag enums={scaleEnum} value={record?.scale} />
</Descriptions.Item>
<Descriptions.Item label="公司位置">{record?.location}</Descriptions.Item>
<Descriptions.Item label="企业联系人">
{record?.companyContactList && record.companyContactList.length > 0 ? (
<div>
{record.companyContactList.map((contact, index) => (
<div key={index} style={{ marginBottom: 8 }}>
<div><strong></strong>{contact.contactPerson}</div>
<div><strong></strong>{contact.contactPersonPhone}</div>
</div>
))}
</div>
) : (
<span></span>
)}
</Descriptions.Item>
</Descriptions>
</Modal>
);
const loadCompanyDetail = async (record: API.CompanyList.Company) => {
const resp = await getCmsCompanyDetail(record.companyId);
const detail = parseCmsCompanyDetailResponse(resp);
if (!detail) {
return { ...record };
}
return { ...record, ...detail };
};
function ManagementList() {
@@ -203,12 +163,12 @@ function ManagementList() {
icon={<AlignLeftOutlined />}
hidden={!access.hasPerms('area:business:List.view')}
onClick={async () => {
setCurrentRow(record);
setDetailData({ ...record });
setDetailVisible(true);
setDetailLoading(true);
try {
const resp = await getCmsCompanyDetail(record.companyId);
setDetailData(resp?.data);
setDetailVisible(true);
const merged = await loadCompanyDetail(record);
setDetailData(merged);
} catch (e) {
message.error('获取详情失败');
} finally {
@@ -227,9 +187,8 @@ function ManagementList() {
onClick={async () => {
const hide = message.loading('正在加载详情');
try {
const resp = await getCmsCompanyDetail(record.companyId);
const detail = resp?.data || {};
setCurrentRow({ ...record, ...detail });
const merged = await loadCompanyDetail(record);
setCurrentRow(merged);
setModalVisible(true);
} catch (e) {
message.error('获取详情失败');
@@ -354,11 +313,11 @@ function ManagementList() {
scaleEnum={scaleEnum}
/>
<CompanyDetailModal
visible={detailVisible}
<CompanyDetailView
open={detailVisible}
loading={detailLoading}
onCancel={() => {
setDetailVisible(false);
setCurrentRow(undefined);
setDetailData(undefined);
}}
record={detailData}

View File

@@ -1,7 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Card, Descriptions, Spin, Typography } from 'antd';
import { useParams } from 'umi';
import { getCompanyDetail } from '@/services/company/review';
import { Button, Card, Descriptions, Spin, Typography } from 'antd';
import { history, useParams } from '@umijs/max';
const { Title } = Typography;
@@ -57,6 +56,11 @@ export default function CompanyDetail() {
return (
<Spin spinning={loading}>
<Card className="company-detail-card">
<div style={{ marginBottom: 16 }}>
<Button type="link" onClick={() => history.back()}>
</Button>
</div>
<Title level={4}></Title>
<Descriptions column={1} bordered>
<Descriptions.Item label="公司名称">{companyDetail.name}</Descriptions.Item>

View File

@@ -0,0 +1,202 @@
import React, { useEffect, useState } from 'react';
import { Spin, message } from 'antd';
import { history, useLocation, useModel } from '@umijs/max';
import { getAccessToken } from '@/access';
import { getRoutersInfo, setRemoteMenu } from '@/services/session';
import { flushSync } from 'react-dom';
/** 过渡页文案:避免「登录」表述,强调无缝进入 */
const STATUS_TEXT = {
entering: '正在进入系统…',
verifying: '正在核验访问信息…',
preparing: '正在准备页面…',
loadingProfile: '正在加载您的资料…',
noCredential: '未检测到有效访问凭证,请从原系统入口进入',
credentialInvalid: '访问凭证已失效,请从原系统重新进入',
profileFailed: '暂时无法加载您的信息,请稍后重试',
} as const;
const HINT_TEXT = '请稍候,页面即将呈现';
const pageStyle: React.CSSProperties = {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh',
padding: '24px',
background: 'linear-gradient(180deg, #f0f5ff 0%, #f5f7fa 48%, #fafafa 100%)',
};
const cardStyle: React.CSSProperties = {
textAlign: 'center',
width: '100%',
maxWidth: 420,
padding: '48px 40px 40px',
borderRadius: 16,
background: '#fff',
boxShadow: '0 8px 24px rgba(0, 0, 0, 0.06)',
border: '1px solid rgba(0, 0, 0, 0.04)',
};
const titleStyle: React.CSSProperties = {
marginTop: 28,
marginBottom: 0,
fontSize: 20,
fontWeight: 600,
color: 'rgba(0, 0, 0, 0.88)',
lineHeight: 1.4,
};
const statusStyle: React.CSSProperties = {
marginTop: 12,
marginBottom: 0,
fontSize: 15,
color: 'rgba(0, 0, 0, 0.65)',
lineHeight: 1.6,
};
const hintStyle: React.CSSProperties = {
marginTop: 8,
fontSize: 14,
color: 'rgba(0, 0, 0, 0.45)',
};
export default function ThirdPartyRedirect() {
const location = useLocation();
const { initialState, setInitialState } = useModel('@@initialState');
const [loading, setLoading] = useState(true);
const [status, setStatus] = useState<string>(STATUS_TEXT.entering);
const [isError, setIsError] = useState(false);
useEffect(() => {
handleLoginRedirect();
}, [location.search]);
const fetchUserInfo = async () => {
try {
const userInfo = await initialState?.fetchUserInfo?.();
if (userInfo) {
console.log('userInfo', userInfo);
console.log('user roles:', userInfo?.roles);
console.log('first role:', userInfo?.roles?.[0]);
flushSync(() => {
setInitialState((s) => ({
...s,
currentUser: userInfo,
}));
});
if (Number(userInfo?.userType) === 1101) {
Number(userInfo?.userType)
Number(userInfo?.userType)
const params = new URLSearchParams(location.search);
const pageName = params.get('pageName');
console.log('userType value:', userInfo?.userType, 'type:', typeof userInfo?.userType);
if (!pageName) {
history.replace(`/job-portal`);
}
if (pageName === 'message') {
history.replace(`/job-portal/${pageName}`);
}
if (pageName === 'jobDetail') {
history.replace(`/job-portal/detail/${params.get('jobId')}`);
}
if (pageName === 'personal-center') {
history.replace(`/job-portal/${pageName}`);
}
return;
} else {
const menus = await getRoutersInfo();
console.log('userType value:', userInfo?.userType, 'type:', typeof userInfo?.userType);
if (menus && menus.length > 0 && Number(userInfo?.userType) !== 1101) {
setRemoteMenu(menus);
window.location.replace('http://39.98.44.136:6024/shihezi/management/management/list/index')
}
}
} else {
message.error('暂时无法加载您的信息');
setIsError(true);
setStatus(STATUS_TEXT.profileFailed);
}
} catch (error) {
setIsError(true);
setStatus(STATUS_TEXT.profileFailed);
}
};
const handleLoginRedirect = async () => {
try {
setIsError(false);
const params = new URLSearchParams(location.search);
const code = params.get('code');
const token = params.get('token');
const pageName = params.get('pageName');
if (!code && !token && !pageName) {
setIsError(true);
setStatus(STATUS_TEXT.noCredential);
}
if (code || token) {
const sessionToken = getAccessToken();
if (!sessionToken) {
setIsError(true);
setStatus(STATUS_TEXT.credentialInvalid);
return;
}
setStatus(STATUS_TEXT.loadingProfile);
await fetchUserInfo();
return;
}
if (!token) {
if (!pageName) {
history.replace(`/job-portal`);
}
if (pageName === 'message') {
history.replace(`/job-portal/${pageName}`);
}
if (pageName === 'jobDetail') {
history.replace(`/job-portal/detail/${params.get('jobId')}`);
}
if (pageName === 'personal-center') {
history.replace(`/job-portal/${pageName}`);
}
return;
}
} catch (error) {
console.error('单点进入失败:', error);
setIsError(true);
message.error('进入系统失败,请稍后重试');
setStatus(STATUS_TEXT.credentialInvalid);
} finally {
setLoading(false);
}
};
return (
<div style={pageStyle}>
<div style={cardStyle}>
<Spin size="large" spinning={loading && !isError} />
{!loading && isError && (
<div
style={{
width: 48,
height: 48,
margin: '0 auto',
borderRadius: '50%',
background: '#fff2f0',
color: '#ff4d4f',
fontSize: 24,
lineHeight: '48px',
}}
>
!
</div>
)}
<h1 style={titleStyle}>{isError ? '暂时无法进入' : '正在进入系统'}</h1>
<p style={statusStyle}>{status}</p>
{!isError && <p style={hintStyle}>{HINT_TEXT}</p>}
</div>
</div>
);
}