客户端集成简历生成器
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
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:
francis-fh
2026-07-24 19:28:10 +08:00
parent 0b90547ceb
commit 279011e652
5 changed files with 566 additions and 1053 deletions

View File

@@ -8,31 +8,11 @@
.jp-page-container();
padding: 20px 20px 40px;
}
}
.section {
.jp-card-base();
margin-bottom: 16px;
padding: 0;
.ant-card-head {
border-bottom: 1px solid @jp-border;
.ant-card-head-title {
color: @jp-primary;
font-weight: 600;
}
}
}
.card-profile .name {
color: @jp-text-primary;
font-weight: 600;
}
.ant-btn-primary {
background: @jp-primary;
border-color: @jp-primary;
}
// iframe 区域确保撑满
#resume-generator {
display: block;
}
@media (max-width: 1366px) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useParams, useNavigate, useSearchParams } from '@umijs/max';
import { useModel, useParams, useNavigate, useSearchParams } from '@umijs/max';
import { Button, Card, message, Space, Switch, Typography } from 'antd';
import { ArrowLeftOutlined, EyeOutlined } from '@ant-design/icons';
import Iframe from 'iframe-js';
@@ -253,6 +253,60 @@ function AppUserResume() {
const iframeRef = useRef<HTMLIFrameElement>(null);
const resumeDataRef = useRef<API.CmsAppUser.ResumeData | null>(null);
// 行为上报:记录浏览时长和浏览次数
const { initialState } = useModel('@@initialState');
const enterTimeRef = useRef<number>(0);
const reportedRef = useRef<boolean>(false);
const actorIdRef = useRef<string | undefined>('');
const targetIdRef = useRef<number>(0);
actorIdRef.current = initialState?.currentUser?.userId;
targetIdRef.current = userId;
// 页面进入/离开时上报浏览行为
useEffect(() => {
enterTimeRef.current = Date.now();
reportedRef.current = false;
const doReport = (durationSeconds: number) => {
if (reportedRef.current) return;
reportedRef.current = true;
const actorId = actorIdRef.current;
const targetId = targetIdRef.current;
if (!actorId || !targetId || durationSeconds <= 0) return;
const payload = {
actorType: '2',
actorId: String(actorId),
targetType: '1',
targetId: String(targetId),
viewDuration: String(durationSeconds),
};
fetch('/api/cms/behavior/report', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
keepalive: true,
}).catch(() => {});
};
const calcDuration = () =>
Math.max(1, Math.floor((Date.now() - enterTimeRef.current) / 1000));
const handleBeforeUnload = () => {
doReport(calcDuration());
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
doReport(calcDuration());
};
}, []);
// 字典数据code → 汉字)
const [sexDict, setSexDict] = useState<DictMap>({});
const [educationDict, setEducationDict] = useState<DictMap>({});

View File

@@ -160,12 +160,29 @@ function CompanyUserList() {
align: 'center',
width: 100,
},
{
title: '企业联系人',
dataIndex: 'contactPerson',
valueType: 'text',
align: 'center',
width: 180,
hideInTable: true,
},
{
title: '联系人电话',
dataIndex: 'contactPersonPhone',
valueType: 'text',
align: 'center',
width: 160,
hideInTable: true,
},
{
title: '企业联系人',
dataIndex: 'companyContactList',
valueType: 'text',
align: 'center',
width: 180,
hideInSearch: true,
render: (_, record) => {
const list = record.companyContactList;
if (!list || list.length === 0) return '-';
@@ -356,7 +373,7 @@ function CompanyUserList() {
success: true,
}))
}
search={{ labelWidth: 'auto' }}
search={{ labelWidth: 'auto', defaultCollapsed: false }}
scroll={{ x: 'max-content' }}
pagination={{ defaultPageSize: 10, showSizeChanger: true }}
headerTitle="企业用户管理"

View File

@@ -16,6 +16,7 @@ declare namespace API {
education?: string;
politicalAffiliation?: string | null;
phone?: string;
email?: string;
avatar?: string;
salaryMin?: string;
salaryMax?: string;
@@ -37,9 +38,32 @@ declare namespace API {
company?: string | null;
experiencesList?: WorkExperience[];
appSkillsList?: AppSkill[];
educationsList?: AppUserEducation[];
trainsList?: AppUserTrain[];
fileList?: any[];
}
export interface AppUserEducation {
id?: number;
userId?: number;
schoolName?: string;
major?: string;
degree?: string;
startTime?: string;
endTime?: string;
content?: string;
}
export interface AppUserTrain {
id?: number;
userId?: number;
trainOrg?: string;
trainCourse?: string;
startTime?: string;
endTime?: string;
trainContent?: string;
}
export interface WorkExperience {
createTime?: string;
updateTime?: string;