import { useEffect, useRef, useState } from "react"; import { Modal, Message, Tooltip } from "@arco-design/web-react"; import { useNavigate, useLocation } from "react-router-dom"; import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, DragOverlay, } from '@dnd-kit/core'; import { SortableContext, sortableKeyboardCoordinates, horizontalListSortingStrategy, } from '@dnd-kit/sortable'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import Locked from "@/components/Locked"; import jobLevelData from "@/data/joblevel.json"; import "./index.css"; // 可排序的岗位组件 const SortablePosition = ({ id, position, getPositionAvatar }) => { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id }); const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1, cursor: 'grab', userSelect: 'none', WebkitUserSelect: 'none', }; return (
avatar
{position}
{position}
); }; export default ({ locked = false }) => { const navigate = useNavigate(); const location = useLocation(); const batch1Ref = useRef(null); const batch2Ref = useRef(null); const batch3Ref = useRef(null); const [hasChanges, setHasChanges] = useState(false); const [showSaveModal, setShowSaveModal] = useState(false); const [pendingNavigation, setPendingNavigation] = useState(null); const [activeId, setActiveId] = useState(null); // 处理拖拽开始 const handleDragStart = (event) => { const { active } = event; setActiveId(active.id); }; // 处理拖拽结束 const handleDragEnd = (event) => { const { active, over } = event; setActiveId(null); if (!over) return; const activePosition = active.id.split('-').slice(1).join('-'); const activeBatch = active.id.split('-')[0]; // 确定目标批次 let targetBatch = over.id.split('-')[0]; let targetPosition = over.id.split('-').slice(1).join('-'); // 如果目标和源相同,不做任何操作 if (active.id === over.id) return; setBatchPositions((prev) => { const newPositions = { ...prev }; // 如果是同一批次内的移动 if (activeBatch === targetBatch) { const batch = [...newPositions[activeBatch]]; const activeIndex = batch.indexOf(activePosition); const overIndex = batch.indexOf(targetPosition); if (activeIndex !== -1 && overIndex !== -1 && activeIndex !== overIndex) { // 移除原位置 batch.splice(activeIndex, 1); // 计算新位置索引 const newOverIndex = activeIndex < overIndex ? overIndex - 1 : overIndex; // 插入到新位置 batch.splice(newOverIndex, 0, activePosition); newPositions[activeBatch] = batch; } } else { // 跨批次移动 // 从原批次删除 const sourceBatch = [...newPositions[activeBatch]]; const activeIndex = sourceBatch.indexOf(activePosition); if (activeIndex !== -1) { sourceBatch.splice(activeIndex, 1); newPositions[activeBatch] = sourceBatch; } // 添加到目标批次 const targetBatchArray = [...newPositions[targetBatch]]; const overIndex = targetBatchArray.indexOf(targetPosition); if (overIndex !== -1) { // 插入到特定位置 targetBatchArray.splice(overIndex, 0, activePosition); } else { // 如果目标批次为空或找不到目标位置,添加到末尾 targetBatchArray.push(activePosition); } newPositions[targetBatch] = targetBatchArray; } return newPositions; }); setHasChanges(true); }; // 处理拖拽到其他批次 - 仅用于预览,不实际移动 const handleDragOver = (event) => { // 空函数 - 我们只在dragEnd时处理实际的移动 }; // 监听路由变化 useEffect(() => { const handleBeforeUnload = (e) => { if (hasChanges) { e.preventDefault(); e.returnValue = ''; } }; window.addEventListener('beforeunload', handleBeforeUnload); return () => window.removeEventListener('beforeunload', handleBeforeUnload); }, [hasChanges]); // 拦截导航 - 监听所有可能的页面切换 useEffect(() => { if (!hasChanges) return; const handleNavigation = (e) => { // 如果点击的是弹窗内的元素,不拦截 if (e.target.closest('.arco-modal')) { return; } // 检查是否是链接点击 const link = e.target.closest('a') || (e.target.tagName === 'A' ? e.target : null); const button = e.target.closest('button') || (e.target.tagName === 'BUTTON' ? e.target : null); // 检查是否是导航相关的元素 if (link || (button && (button.textContent?.includes('返回') || button.onclick))) { e.preventDefault(); e.stopPropagation(); setShowSaveModal(true); if (link) { setPendingNavigation(link.href); } } }; // 监听点击事件(捕获阶段) document.addEventListener('click', handleNavigation, true); // 监听浏览器后退/前进 const handlePopState = (e) => { if (hasChanges) { e.preventDefault(); setShowSaveModal(true); } }; window.addEventListener('popstate', handlePopState); return () => { document.removeEventListener('click', handleNavigation, true); window.removeEventListener('popstate', handlePopState); }; }, [hasChanges]); useEffect(() => { // 添加鼠标滚轮事件监听,实现横向滚动 const handleWheel = (e, ref) => { if (ref.current && ref.current.contains(e.target)) { e.preventDefault(); ref.current.scrollLeft += e.deltaY; } }; const batch1El = batch1Ref.current; const batch2El = batch2Ref.current; const batch3El = batch3Ref.current; const wheel1Handler = (e) => handleWheel(e, batch1Ref); const wheel2Handler = (e) => handleWheel(e, batch2Ref); const wheel3Handler = (e) => handleWheel(e, batch3Ref); if (batch1El) batch1El.addEventListener('wheel', wheel1Handler, { passive: false }); if (batch2El) batch2El.addEventListener('wheel', wheel2Handler, { passive: false }); if (batch3El) batch3El.addEventListener('wheel', wheel3Handler, { passive: false }); return () => { if (batch1El) batch1El.removeEventListener('wheel', wheel1Handler); if (batch2El) batch2El.removeEventListener('wheel', wheel2Handler); if (batch3El) batch3El.removeEventListener('wheel', wheel3Handler); }; }, []); // 根据岗位名称获取头像 const getPositionAvatar = (positionName) => { const jobData = jobLevelData.data; for (const [key, levelData] of Object.entries(jobData)) { const found = levelData.list.find(item => item.position_name === positionName); if (found) { return found.img; } } return "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_teacher-avatar/recuUpSO4gUtJz.png"; // 默认头像 }; // 定义三个批次的岗位数据 const initialBatchPositions = { batch1: [ "二次元周边店店员", "会展执行助理", "会展讲解员", "会展营销", "商业会展执行专员", "景区运营专员", "文旅运营总监助理", "品牌策划运营专员", "品牌推广专员", "ip运营", "文创产品设计师助理", "新媒体运营专员", "网络运营专员", "社群运营", "直播助理" ], batch2: [ "宠物店店长", "宠物营养师", "二次元周边选品专员", "二次元周边店店长", "会展策划师", "漫展策划师", "活动执行", "活动策划师", "酒店运营专员", "餐厅运营经理", "露营地运营专员", "旅游规划师", "文旅项目投资拓展管培生", "民宿管家", "民宿客房管家", "民宿运营专员", "品牌公关", "ip运营总监助理", "品牌公关管培生", "直播中控", "SEO专员", "SEM专员", "赛事经纪" ], batch3: [ "酒店餐饮主管", "客房经理", "酒店大堂副理", "旅游计调专员", "文创产品策划师", "文创产品设计师", "赛事礼仪", "赛事编辑", "艺人经纪人", "演出执行经理", "场馆运营人员" ] }; const [batchPositions, setBatchPositions] = useState(initialBatchPositions); // 拖拽传感器设置 const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 8, }, }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates, }) ); // 获取所有岗位ID const getAllPositionIds = () => { const ids = []; Object.entries(batchPositions).forEach(([batch, positions]) => { positions.forEach(position => { ids.push(`${batch}-${position}`); }); }); return ids; }; return (
第一批次 ? 第二批次 ? 第三批次 ?
{/* 第一批次 */}
`batch1-${p}`)} strategy={horizontalListSortingStrategy} > {batchPositions.batch1.map((position) => ( ))}
{/* 第二批次 */}
`batch2-${p}`)} strategy={horizontalListSortingStrategy} > {batchPositions.batch2.map((position) => ( ))}
{/* 第三批次 */}
`batch3-${p}`)} strategy={horizontalListSortingStrategy} > {batchPositions.batch3.map((position) => ( ))}
{locked && ( )}
{/* 拖拽覆盖层 */} {activeId ? (
avatar
) : null}
{/* 保存提示模态框 */} 保存更改
} visible={showSaveModal} onCancel={() => { setShowSaveModal(false); setPendingNavigation(null); // 只关闭弹窗,保留hasChanges状态,下次点击返回还会弹出 }} footer={[ ,
{ const tooltip = document.createElement('div'); tooltip.className = 'save-tooltip'; tooltip.textContent = '非导师和学生本人无修改权限'; tooltip.style.cssText = ` position: absolute; bottom: 120%; left: 50%; transform: translateX(-50%); background: linear-gradient(135deg, #1d2129 0%, #2e3440 100%); color: #ffffff; padding: 10px 16px; border-radius: 8px; font-size: 13px; font-weight: 500; white-space: nowrap; z-index: 10000; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); animation: fadeIn 0.3s ease; `; const style = document.createElement('style'); style.textContent = ` @keyframes fadeIn { from { opacity: 0; transform: translateX(-50%) translateY(5px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } } `; document.head.appendChild(style); // 添加小箭头 const arrow = document.createElement('div'); arrow.style.cssText = ` position: absolute; top: 100%; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-style: solid; border-width: 6px 6px 0 6px; border-color: #2e3440 transparent transparent transparent; `; tooltip.appendChild(arrow); e.currentTarget.appendChild(tooltip); }} onMouseLeave={(e) => { const tooltip = e.currentTarget.querySelector('.save-tooltip'); if (tooltip) { tooltip.remove(); } const style = document.querySelector('style'); if (style && style.textContent.includes('fadeIn')) { style.remove(); } }} >
]} style={{ borderRadius: '12px' }} >

您对岗位顺序进行了修改

离开此页面前,是否要保存您的更改?未保存的更改将会丢失。

); };