import React, { useState } from 'react';
|
import { Modal, message, Input } from 'antd';
|
import { useCaseData } from '../../contexts/CaseDataContext';
|
import { translateMediationState } from '../../utils/stateTranslator';
|
import { useTaskTimer } from '../../hooks/useTaskTimer';
|
import ProcessAPIService from '../../services/ProcessAPIService';
|
import { getMergedParams } from '../../utils/urlParams';
|
|
const { TextArea } = Input;
|
|
// 终态状态(不显示人工接管按钮)
|
const TERMINAL_STATES = [2, 3]; // 调解成功、调解失败
|
const TAKEOVER_STATE = 4; // 人工接管
|
const PAUSED_STATE = 5; // 已终止/暂停状态
|
|
/**
|
* 获取案件ID
|
* 优先级:Context > URL参数 > localStorage
|
*/
|
const resolveCaseId = (caseData) => {
|
// 1. 从Context获取
|
if (caseData?.case_id) return String(caseData.case_id);
|
|
// 2. 从 URL 参数获取
|
const params = getMergedParams();
|
if (params.caseId) return String(params.caseId);
|
|
// 3. 从localStorage获取
|
try {
|
const stored = JSON.parse(localStorage.getItem('case_data_timeline') || '{}');
|
if (stored.case_id) return String(stored.case_id);
|
} catch { /* ignore */ }
|
|
return null;
|
};
|
|
/**
|
* 获取当前用户名
|
*/
|
const resolveUserName = () => {
|
try {
|
const user = JSON.parse(localStorage.getItem('currentUser') || '{}');
|
return user.user_name || 'No User';
|
} catch {
|
return 'No User';
|
}
|
};
|
|
/**
|
* 印章组件 - 终态状态展示(调解成功/失败/人工接管)
|
*/
|
const TakeoverStamp = ({ state }) => {
|
const stateTextMap = {
|
2: '调解成功',
|
3: '调解失败',
|
4: '已人工接管'
|
};
|
const text = stateTextMap[state] || '已人工接管';
|
|
return (
|
<div className="takeover-stamp">
|
<span className="takeover-stamp-text">
|
<i className="fas fa-stamp"></i>
|
{text}
|
</span>
|
</div>
|
);
|
};
|
|
/**
|
* 接管按钮组件
|
*/
|
const TakeoverButton = ({ loading, onClick }) => (
|
<button
|
className="floating-control-btn"
|
onClick={onClick}
|
disabled={loading}
|
style={loading ? { opacity: 0.6, cursor: 'not-allowed' } : {}}
|
>
|
{loading ? (
|
<><i className="fas fa-spinner fa-spin"></i>接管中...</>
|
) : (
|
<><i className="fas fa-user-tie"></i>人工接管</>
|
)}
|
</button>
|
);
|
|
/**
|
* 底部悬浮控制面板
|
*/
|
const FloatingControlPanel = () => {
|
const { caseData, taskStartTime, isTaskTimeFallback, refreshData } = useCaseData();
|
const [takeoverLoading, setTakeoverLoading] = useState(false);
|
const [confirmVisible, setConfirmVisible] = useState(false);
|
|
// 状态控制相关状态
|
const [controlLoading, setControlLoading] = useState(false);
|
const [controlConfirmVisible, setControlConfirmVisible] = useState(false);
|
const [controlAction, setControlAction] = useState(null); // 'terminate' or 'resume'
|
const [remark, setRemark] = useState('');
|
|
const timeline = caseData || {};
|
const state = timeline.mediation?.state;
|
const nodeName = timeline.current_node?.node_name || '';
|
const orderNo = timeline.current_node?.order_no || 1;
|
|
const { formattedTime } = useTaskTimer(taskStartTime, isTaskTimeFallback);
|
|
// 生成状态文本
|
const statusText = state === 1
|
? `调解进行中-阶段${orderNo}:${nodeName}`
|
: (translateMediationState(state) || '调解进行中');
|
|
// ==================== 状态控制按钮逻辑 ====================
|
|
/**
|
* 判断是否显示状态控制按钮
|
* 状态为0(未开始)、1(进行中)、5(已终止)时显示
|
*/
|
const shouldShowControlButton = () => {
|
const stateNum = Number(state);
|
// 进行中(1)显示终止按钮,已终止(5)显示恢复按钮
|
return stateNum === 1 || stateNum === 5;
|
};
|
|
/**
|
* 获取状态控制按钮属性
|
*/
|
const getControlButtonProps = () => {
|
const stateNum = Number(state);
|
|
if (stateNum === 1) {
|
return {
|
text: '终止',
|
style: 'terminate',
|
action: 'terminate'
|
};
|
} else if (stateNum === 5) {
|
return {
|
text: '恢复',
|
style: 'resume',
|
action: 'resume'
|
};
|
}
|
|
return null;
|
};
|
|
/**
|
* 处理状态控制按钮点击
|
*/
|
const handleControlButtonClick = () => {
|
const buttonProps = getControlButtonProps();
|
if (!buttonProps) return;
|
|
setControlAction(buttonProps.action);
|
setControlConfirmVisible(true);
|
};
|
|
/**
|
* 处理状态控制确认
|
*/
|
const handleControlConfirmOk = async () => {
|
if (!controlAction) return;
|
|
setControlLoading(true);
|
try {
|
const params = getMergedParams();
|
const actionCode = controlAction === 'terminate' ? 0 : 1;
|
|
if (!params.caseId) {
|
throw new Error('案件ID不能为空');
|
}
|
|
await ProcessAPIService.updateMediationState(params.caseId, {
|
action: actionCode,
|
userName: localStorage.getItem('userName') || '调解员',
|
remark: remark || ''
|
});
|
|
message.success(controlAction === 'terminate' ? '调解已终止' : '调解已恢复');
|
setControlConfirmVisible(false);
|
setRemark('');
|
setControlAction(null);
|
|
refreshData();
|
} catch (error) {
|
console.error('状态更新失败:', error);
|
message.error(error.message || '状态更新失败,请稍后重试');
|
} finally {
|
setControlLoading(false);
|
}
|
};
|
|
/**
|
* 处理状态控制取消
|
*/
|
const handleControlConfirmCancel = () => {
|
setControlConfirmVisible(false);
|
setRemark('');
|
setControlAction(null);
|
};
|
|
// ==================== 人工接管逻辑 ====================
|
|
/**
|
* 处理接管API调用
|
*/
|
const executeTakeover = async () => {
|
console.log('executeTakeover 开始执行');
|
const caseId = resolveCaseId(caseData);
|
console.log('获取到的 caseId:', caseId);
|
|
if (!caseId) {
|
message.error('无法获取案件ID,请刷新页面后重试');
|
return;
|
}
|
|
const userName = resolveUserName();
|
console.log('获取到的 userName:', userName);
|
|
setTakeoverLoading(true);
|
try {
|
console.log('调用 ProcessAPIService.takeover, caseId:', caseId, ', userName:', userName);
|
const response = await ProcessAPIService.takeover(caseId, { userName });
|
console.log('接管API返回:', response);
|
message.success('人工接管成功');
|
refreshData();
|
} catch (err) {
|
console.error('接管API异常:', err);
|
handleTakeoverError(err);
|
} finally {
|
setTakeoverLoading(false);
|
}
|
};
|
|
/**
|
* 处理接管错误响应
|
*/
|
const handleTakeoverError = (err) => {
|
const status = err?.response?.status || err?.status;
|
const msg = err?.response?.data?.message || err?.message || '';
|
|
// 400错误:已被接管或已结束 → 重新加载页面
|
if (status === 400) {
|
console.warn('接管失败(400):', msg);
|
refreshData();
|
return;
|
}
|
|
// 其他错误 → 提示用户
|
console.error('人工接管失败:', err);
|
message.error(msg || '人工接管失败,请稍后重试');
|
};
|
|
/**
|
* 点击接管按钮 - 显示确认对话框
|
*/
|
const handleTakeover = () => {
|
console.log('点击人工接管按钮');
|
setConfirmVisible(true);
|
};
|
|
/**
|
* 确认接管
|
*/
|
const handleConfirmOk = async () => {
|
console.log('用户点击确定,开始执行接管');
|
setConfirmVisible(false);
|
await executeTakeover();
|
};
|
|
/**
|
* 取消接管
|
*/
|
const handleConfirmCancel = () => {
|
console.log('用户点击取消');
|
setConfirmVisible(false);
|
};
|
|
/**
|
* 渲染状态控制按钮(终止/恢复)
|
*/
|
const renderStateControlButton = () => {
|
if (!shouldShowControlButton()) return null;
|
|
const buttonProps = getControlButtonProps();
|
if (!buttonProps) return null;
|
|
const isTerminate = buttonProps.style === 'terminate';
|
|
return (
|
<button
|
className={`state-control-btn ${isTerminate ? 'state-control-btn--terminate' : 'state-control-btn--resume'}`}
|
onClick={handleControlButtonClick}
|
disabled={controlLoading}
|
>
|
{controlLoading ? (
|
<><i className="fas fa-spinner fa-spin"></i>处理中...</>
|
) : (
|
<><i className={isTerminate ? "fas fa-pause-circle" : "fas fa-play-circle"}></i>{buttonProps.text}</>
|
)}
|
</button>
|
);
|
};
|
|
/**
|
* 渲染控制区域(按钮或印章)
|
*/
|
const renderControlAction = () => {
|
// 终态状态(调解成功/失败/人工接管):显示印章
|
if (TERMINAL_STATES.includes(state) || state === TAKEOVER_STATE) {
|
return <TakeoverStamp state={state} />;
|
}
|
|
|
// 调解中(1):显示终止按钮和人工接管按钮
|
return (
|
<>
|
{renderStateControlButton()}
|
<TakeoverButton loading={takeoverLoading} onClick={handleTakeover} />
|
</>
|
);
|
};
|
|
return (
|
<>
|
<div className="floating-control-panel">
|
<div className="control-status">
|
<div className="status-indicator">
|
<span className="status-dot"></span>
|
<span className="status-text">
|
{statusText}{' '}
|
<span style={{ color: 'gray' }}>
|
(已进行:{formattedTime}
|
{isTaskTimeFallback && <span style={{ color: '#faad14' }}> *</span>}
|
)
|
</span>
|
</span>
|
</div>
|
</div>
|
<div className="control-action">
|
{renderControlAction()}
|
</div>
|
</div>
|
|
{/* 状态控制确认对话框(终止/恢复) */}
|
<Modal
|
title={controlAction === 'terminate' ? '确认终止调解' : '确认恢复调解'}
|
visible={controlConfirmVisible}
|
onOk={handleControlConfirmOk}
|
onCancel={handleControlConfirmCancel}
|
okText="确定"
|
cancelText="取消"
|
confirmLoading={controlLoading}
|
>
|
<p>
|
{controlAction === 'terminate'
|
? '确定要终止当前AI调解流程吗?终止后调解将暂停,可在适当时机恢复。'
|
: '确定要恢复AI调解流程吗?恢复后将从当前位置继续调解。'}
|
</p>
|
<div style={{ marginTop: 15 }}>
|
<label style={{ display: 'block', marginBottom: 5, fontWeight: 500 }}>
|
备注(可选):
|
</label>
|
<TextArea
|
value={remark}
|
onChange={(e) => setRemark(e.target.value)}
|
placeholder="请输入操作备注..."
|
rows={3}
|
/>
|
</div>
|
</Modal>
|
|
{/* 人工接管确认对话框 */}
|
<Modal
|
title="人工接管确认"
|
visible={confirmVisible}
|
onOk={handleConfirmOk}
|
onCancel={handleConfirmCancel}
|
okText="确定"
|
cancelText="取消"
|
confirmLoading={takeoverLoading}
|
>
|
<p>确定人工接管本调解案件吗?</p>
|
</Modal>
|
</>
|
);
|
};
|
|
export default FloatingControlPanel;
|