用户行为统计
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 20:58:01 +08:00
parent 279011e652
commit d653cd97d6
5 changed files with 137 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useParams, history, useLocation, useSearchParams } from '@umijs/max';
import {
Card,
@@ -206,6 +206,55 @@ const JobDetailPage: React.FC = () => {
const [industryTree, setIndustryTree] = useState<any[]>([]);
const [complaintVisible, setComplaintVisible] = useState(false);
// 行为上报:浏览岗位时长统计
const enterTimeRef = useRef<number>(0);
const reportedRef = useRef<boolean>(false);
const jobIdRef = useRef<string>('');
// 页面进入/离开时上报浏览行为
useEffect(() => {
enterTimeRef.current = Date.now();
reportedRef.current = false;
jobIdRef.current = String(originalJobData?.jobId || originalJobData?.id || id || '');
const calcDuration = () =>
Math.max(1, Math.floor((Date.now() - enterTimeRef.current) / 1000));
const doReport = (durationSeconds: number) => {
if (reportedRef.current) return;
reportedRef.current = true;
const actorId = localStorage.getItem('appUserId');
const targetId = jobIdRef.current;
if (!actorId || !targetId || durationSeconds <= 0) return;
fetch('/api/cms/behavior/report', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
actorType: '1',
actorId: String(actorId),
targetType: '2',
targetId: String(targetId),
viewDuration: String(durationSeconds),
}),
keepalive: true,
}).catch(() => {});
};
const handleBeforeUnload = () => {
doReport(calcDuration());
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
doReport(calcDuration());
};
}, []);
const detailTagGroups = useMemo(
() => [
{ label: '薪资范围与构成', values: jobDetail.salaryComposition },