修复回显
This commit is contained in:
@@ -1410,6 +1410,10 @@ export interface OutputCustomSettlementApplyApprove {
|
|||||||
apply_status_name?: string | null;
|
apply_status_name?: string | null;
|
||||||
/** 最终结算金额 */
|
/** 最终结算金额 */
|
||||||
final_settlement_price?: number | null;
|
final_settlement_price?: number | null;
|
||||||
|
/** 申请理由 */
|
||||||
|
apply_reason?: string;
|
||||||
|
/** 折扣 */
|
||||||
|
discount_ratio?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,6 +29,17 @@ interface ExamAddonPanelProps {
|
|||||||
|
|
||||||
export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
||||||
const [addonList, setAddonList] = useState<AddonItem[]>([]);
|
const [addonList, setAddonList] = useState<AddonItem[]>([]);
|
||||||
|
const allAddons = useMemo(() => addonList, [addonList]);
|
||||||
|
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
|
const currentAddItemId = useMemo(() => {
|
||||||
|
const currentSelectedItems = allAddons.filter(item => selectedIds.has(item.id || item.name));
|
||||||
|
return currentSelectedItems
|
||||||
|
.map(item => item.combinationItemCode)
|
||||||
|
.filter((code): code is number => code !== null && code !== undefined)
|
||||||
|
.join(',');
|
||||||
|
}, [allAddons, selectedIds]);
|
||||||
|
|
||||||
// 防抖:内部输入值(用于显示)
|
// 防抖:内部输入值(用于显示)
|
||||||
const [addonSearchInput, setAddonSearchInput] = useState('');
|
const [addonSearchInput, setAddonSearchInput] = useState('');
|
||||||
// 防抖:实际用于 API 调用的值(延迟更新)
|
// 防抖:实际用于 API 调用的值(延迟更新)
|
||||||
@@ -82,6 +93,10 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
apply_status?: number;
|
apply_status?: number;
|
||||||
apply_status_name?: string | null;
|
apply_status_name?: string | null;
|
||||||
final_settlement_price?: number | null;
|
final_settlement_price?: number | null;
|
||||||
|
apply_reason?: string | null;
|
||||||
|
settlement_type?: number | null;
|
||||||
|
discount_ratio?: number | null;
|
||||||
|
add_item_id?: string | null;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
const [customSettlementLoading, setCustomSettlementLoading] = useState(false);
|
const [customSettlementLoading, setCustomSettlementLoading] = useState(false);
|
||||||
const [customSettlementType, setCustomSettlementType] = useState<1 | 2>(1); // 1-按比例折扣 2-自定义结算价
|
const [customSettlementType, setCustomSettlementType] = useState<1 | 2>(1); // 1-按比例折扣 2-自定义结算价
|
||||||
@@ -91,6 +106,33 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
const [waitingSeconds, setWaitingSeconds] = useState<number>(0); // 等待审核的秒数
|
const [waitingSeconds, setWaitingSeconds] = useState<number>(0); // 等待审核的秒数
|
||||||
const waitingTimerRef = useRef<number | null>(null); // 等待计时器
|
const waitingTimerRef = useRef<number | null>(null); // 等待计时器
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (showCustomSettlementModal && customSettlementStatus) {
|
||||||
|
// 已通过(3) 或 已拒绝(4) 且 add_item_id 匹配才需要回显
|
||||||
|
if ((customSettlementStatus.apply_status === 3 || customSettlementStatus.apply_status === 4) &&
|
||||||
|
customSettlementStatus.add_item_id === currentAddItemId) {
|
||||||
|
if (customSettlementStatus.settlement_type === 1 || customSettlementStatus.settlement_type === 2) {
|
||||||
|
setCustomSettlementType(customSettlementStatus.settlement_type as 1 | 2);
|
||||||
|
}
|
||||||
|
if (typeof customSettlementStatus.discount_ratio === 'number') {
|
||||||
|
setCustomDiscountRatio(customSettlementStatus.discount_ratio);
|
||||||
|
}
|
||||||
|
if (typeof customSettlementStatus.final_settlement_price === 'number') {
|
||||||
|
setCustomFinalPrice(customSettlementStatus.final_settlement_price);
|
||||||
|
}
|
||||||
|
if (customSettlementStatus.apply_reason) {
|
||||||
|
setCustomApplyReason(customSettlementStatus.apply_reason);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 其他状态(如取消后再点开)重置表单为默认值
|
||||||
|
setCustomSettlementType(1);
|
||||||
|
setCustomDiscountRatio(null);
|
||||||
|
setCustomFinalPrice(0);
|
||||||
|
setCustomApplyReason('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [showCustomSettlementModal, customSettlementStatus, currentAddItemId]);
|
||||||
|
|
||||||
// 点击外部关闭下拉框
|
// 点击外部关闭下拉框
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
@@ -276,10 +318,6 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
fetchList();
|
fetchList();
|
||||||
}, [debouncedAddonSearch, customerInfo?.scrm_account_id, customerInfo?.scrm_account_name, client.id, customerInfo, channelDiscounts, discountRatio]);
|
}, [debouncedAddonSearch, customerInfo?.scrm_account_id, customerInfo?.scrm_account_name, client.id, customerInfo, channelDiscounts, discountRatio]);
|
||||||
|
|
||||||
const allAddons = useMemo(() => addonList, [addonList]);
|
|
||||||
|
|
||||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
|
||||||
|
|
||||||
const maxSelect = 15;
|
const maxSelect = 15;
|
||||||
const selectedCount = selectedIds.size;
|
const selectedCount = selectedIds.size;
|
||||||
|
|
||||||
@@ -433,19 +471,8 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
// 获取自定义结算审批状态(带节流,最多每秒一次)
|
// 获取自定义结算审批状态(带节流,最多每秒一次)
|
||||||
const fetchCustomSettlementStatus = useCallback(async () => {
|
const fetchCustomSettlementStatus = useCallback(async () => {
|
||||||
const physical_exam_id = Number(client.id);
|
const physical_exam_id = Number(client.id);
|
||||||
const currentSelectedItems = allAddons.filter(item => selectedIds.has(item.id || item.name));
|
|
||||||
|
|
||||||
if (!physical_exam_id || currentSelectedItems.length === 0) {
|
if (!physical_exam_id || !currentAddItemId) {
|
||||||
setCustomSettlementStatus(null);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const add_item_id = currentSelectedItems
|
|
||||||
.map(item => item.combinationItemCode)
|
|
||||||
.filter((code): code is number => code !== null && code !== undefined)
|
|
||||||
.join(',');
|
|
||||||
|
|
||||||
if (!add_item_id) {
|
|
||||||
setCustomSettlementStatus(null);
|
setCustomSettlementStatus(null);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -454,7 +481,7 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const timeSinceLastCall = now - lastFetchStatusTimeRef.current;
|
const timeSinceLastCall = now - lastFetchStatusTimeRef.current;
|
||||||
if (timeSinceLastCall < 800) {
|
if (timeSinceLastCall < 800) {
|
||||||
// 返回当前状态是否需要轮询
|
// 从 ref 获取当前状态判断是否需要轮询
|
||||||
return customSettlementStatus?.apply_status === 1;
|
return customSettlementStatus?.apply_status === 1;
|
||||||
}
|
}
|
||||||
lastFetchStatusTimeRef.current = now;
|
lastFetchStatusTimeRef.current = now;
|
||||||
@@ -462,19 +489,27 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
try {
|
try {
|
||||||
const res = await getCustomSettlementApproveStatus({
|
const res = await getCustomSettlementApproveStatus({
|
||||||
physical_exam_id,
|
physical_exam_id,
|
||||||
add_item_id,
|
add_item_id: currentAddItemId,
|
||||||
});
|
});
|
||||||
if (res.Status === 200 && res.Data) {
|
if (res.Status === 200 && res.Data) {
|
||||||
const status = {
|
const status = {
|
||||||
apply_status: res.Data.apply_status,
|
apply_status: res.Data.apply_status,
|
||||||
apply_status_name: res.Data.apply_status_name,
|
apply_status_name: res.Data.apply_status_name,
|
||||||
final_settlement_price: res.Data.final_settlement_price,
|
final_settlement_price: res.Data.final_settlement_price,
|
||||||
|
apply_reason: (res.Data as any).apply_reason,
|
||||||
|
settlement_type: (res.Data as any).settlement_type,
|
||||||
|
discount_ratio: (res.Data as any).discount_ratio,
|
||||||
|
add_item_id: currentAddItemId,
|
||||||
};
|
};
|
||||||
setCustomSettlementStatus(status);
|
|
||||||
// 如果状态变为审核中,重置等待时间
|
// 获取旧状态用于判断是否刚进入审核中
|
||||||
if (res.Data.apply_status === 1 && customSettlementStatus?.apply_status !== 1) {
|
setCustomSettlementStatus(prev => {
|
||||||
setWaitingSeconds(0);
|
if (status.apply_status === 1 && prev?.apply_status !== 1) {
|
||||||
}
|
setWaitingSeconds(0);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
});
|
||||||
|
|
||||||
// 返回是否需要继续轮询(1-审核中 需要轮询)
|
// 返回是否需要继续轮询(1-审核中 需要轮询)
|
||||||
return res.Data.apply_status === 1;
|
return res.Data.apply_status === 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -486,12 +521,19 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
setCustomSettlementStatus(null);
|
setCustomSettlementStatus(null);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}, [client.id, selectedIds, allAddons, customSettlementStatus]);
|
}, [client.id, currentAddItemId]);
|
||||||
|
|
||||||
// 当选中加项变化时,获取审批状态
|
// 当选中加项变化时,获取审批状态
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentSelectedItems = allAddons.filter(item => selectedIds.has(item.id || item.name));
|
// 切换选中项时,先清零状态,避免错误回显旧数据
|
||||||
if (currentSelectedItems.length > 0) {
|
setCustomSettlementStatus(null);
|
||||||
|
setCustomSettlementType(1);
|
||||||
|
setCustomDiscountRatio(null);
|
||||||
|
setCustomFinalPrice(0);
|
||||||
|
setCustomApplyReason('');
|
||||||
|
lastFetchStatusTimeRef.current = 0; // 强制立即发起新请求
|
||||||
|
|
||||||
|
if (currentAddItemId) {
|
||||||
fetchCustomSettlementStatus().then((shouldPoll) => {
|
fetchCustomSettlementStatus().then((shouldPoll) => {
|
||||||
// 如果需要轮询(审核中),开始轮询
|
// 如果需要轮询(审核中),开始轮询
|
||||||
if (shouldPoll) {
|
if (shouldPoll) {
|
||||||
@@ -501,10 +543,9 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setCustomSettlementStatus(null);
|
|
||||||
stopCustomSettlementPolling();
|
stopCustomSettlementPolling();
|
||||||
}
|
}
|
||||||
}, [selectedIds, client.id, allAddons, fetchCustomSettlementStatus]);
|
}, [currentAddItemId, client.id]); // 移除 fetchCustomSettlementStatus 依赖,避免由于状态更新导致的死循环
|
||||||
|
|
||||||
// 开始轮询自定义结算审批状态
|
// 开始轮询自定义结算审批状态
|
||||||
const startCustomSettlementPolling = useCallback(() => {
|
const startCustomSettlementPolling = useCallback(() => {
|
||||||
@@ -975,6 +1016,10 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isApprovedOrRejected =
|
||||||
|
(customSettlementStatus?.apply_status === 3 || customSettlementStatus?.apply_status === 4) &&
|
||||||
|
customSettlementStatus?.add_item_id === currentAddItemId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='space-y-4'>
|
<div className='space-y-4'>
|
||||||
{/* 标题和说明 */}
|
{/* 标题和说明 */}
|
||||||
@@ -1157,10 +1202,12 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
<div className='flex flex-col items-end gap-2 relative'>
|
<div className='flex flex-col items-end gap-2 relative'>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setShowCustomSettlementModal(true)}
|
onClick={() => setShowCustomSettlementModal(true)}
|
||||||
className=
|
className='px-3 py-1.5 text-xs text-white bg-blue-600'
|
||||||
'px-3 py-1.5 text-xs text-white bg-blue-600'
|
|
||||||
>
|
>
|
||||||
{!customSettlementStatus || !customSettlementStatus.apply_status || customSettlementStatus.apply_status === 1
|
{!customSettlementStatus ||
|
||||||
|
!customSettlementStatus.apply_status ||
|
||||||
|
customSettlementStatus.apply_status === 1 ||
|
||||||
|
customSettlementStatus.add_item_id !== currentAddItemId
|
||||||
? '申请自定义结算'
|
? '申请自定义结算'
|
||||||
: customSettlementStatus.apply_status === 3
|
: customSettlementStatus.apply_status === 3
|
||||||
? '自定义结算(已通过)'
|
? '自定义结算(已通过)'
|
||||||
@@ -1377,24 +1424,28 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
<div className='flex gap-3'>
|
<div className='flex gap-3'>
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
|
disabled={isApprovedOrRejected}
|
||||||
onClick={() => setCustomSettlementType(1)}
|
onClick={() => setCustomSettlementType(1)}
|
||||||
className={cls(
|
className={cls(
|
||||||
'flex-1 px-4 py-2 rounded-lg border text-sm transition-colors',
|
'flex-1 px-4 py-2 rounded-lg border text-sm transition-colors',
|
||||||
customSettlementType === 1
|
customSettlementType === 1
|
||||||
? 'bg-blue-50 border-blue-500 text-blue-700 font-medium'
|
? 'bg-blue-50 border-blue-500 text-blue-700 font-medium'
|
||||||
: 'bg-white border-gray-300 text-gray-700 hover:border-gray-400'
|
: 'bg-white border-gray-300 text-gray-700 hover:border-gray-400',
|
||||||
|
isApprovedOrRejected && 'opacity-70 cursor-not-allowed'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
按比例折扣
|
按比例折扣
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
|
disabled={isApprovedOrRejected}
|
||||||
onClick={() => setCustomSettlementType(2)}
|
onClick={() => setCustomSettlementType(2)}
|
||||||
className={cls(
|
className={cls(
|
||||||
'flex-1 px-4 py-2 rounded-lg border text-sm transition-colors',
|
'flex-1 px-4 py-2 rounded-lg border text-sm transition-colors',
|
||||||
customSettlementType === 2
|
customSettlementType === 2
|
||||||
? 'bg-blue-50 border-blue-500 text-blue-700 font-medium'
|
? 'bg-blue-50 border-blue-500 text-blue-700 font-medium'
|
||||||
: 'bg-white border-gray-300 text-gray-700 hover:border-gray-400'
|
: 'bg-white border-gray-300 text-gray-700 hover:border-gray-400',
|
||||||
|
isApprovedOrRejected && 'opacity-70 cursor-not-allowed'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
自定义结算价
|
自定义结算价
|
||||||
@@ -1417,6 +1468,7 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
min='0'
|
min='0'
|
||||||
max='100'
|
max='100'
|
||||||
step='1'
|
step='1'
|
||||||
|
disabled={isApprovedOrRejected}
|
||||||
value={customDiscountRatio ?? ''}
|
value={customDiscountRatio ?? ''}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const raw = e.target.value;
|
const raw = e.target.value;
|
||||||
@@ -1449,6 +1501,7 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
type='number'
|
type='number'
|
||||||
min='0'
|
min='0'
|
||||||
step='0.01'
|
step='0.01'
|
||||||
|
disabled={isApprovedOrRejected}
|
||||||
value={customFinalPrice || ''}
|
value={customFinalPrice || ''}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const val = Number(e.target.value);
|
const val = Number(e.target.value);
|
||||||
@@ -1467,10 +1520,14 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
<label className='text-sm text-gray-700 font-medium'>申请理由 *</label>
|
<label className='text-sm text-gray-700 font-medium'>申请理由 *</label>
|
||||||
<textarea
|
<textarea
|
||||||
value={customApplyReason}
|
value={customApplyReason}
|
||||||
|
disabled={isApprovedOrRejected}
|
||||||
onChange={(e) => setCustomApplyReason(e.target.value)}
|
onChange={(e) => setCustomApplyReason(e.target.value)}
|
||||||
placeholder='请输入申请理由'
|
placeholder='请输入申请理由'
|
||||||
rows={3}
|
rows={3}
|
||||||
className='w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 resize-none'
|
className={cls(
|
||||||
|
'w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 resize-none',
|
||||||
|
isApprovedOrRejected && 'bg-gray-50 opacity-70 cursor-not-allowed'
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1480,20 +1537,22 @@ export const ExamAddonPanel = ({ client, onGoToSign }: ExamAddonPanelProps) => {
|
|||||||
onClick={() => setShowCustomSettlementModal(false)}
|
onClick={() => setShowCustomSettlementModal(false)}
|
||||||
className='flex-1 px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700'
|
className='flex-1 px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700'
|
||||||
>
|
>
|
||||||
取消
|
{isApprovedOrRejected ? '关闭' : '取消'}
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={handleSubmitCustomSettlement}
|
|
||||||
disabled={customSettlementLoading || !customApplyReason.trim()}
|
|
||||||
className={cls(
|
|
||||||
'flex-1 px-4 py-2 text-white font-medium',
|
|
||||||
customSettlementLoading || !customApplyReason.trim()
|
|
||||||
? 'bg-gray-400 cursor-not-allowed'
|
|
||||||
: 'bg-blue-600 hover:bg-blue-700'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{customSettlementLoading ? '提交中...' : '提交申请'}
|
|
||||||
</Button>
|
</Button>
|
||||||
|
{!isApprovedOrRejected && (
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmitCustomSettlement}
|
||||||
|
disabled={customSettlementLoading || !customApplyReason.trim()}
|
||||||
|
className={cls(
|
||||||
|
'flex-1 px-4 py-2 text-white font-medium',
|
||||||
|
customSettlementLoading || !customApplyReason.trim()
|
||||||
|
? 'bg-gray-400 cursor-not-allowed'
|
||||||
|
: 'bg-blue-600 hover:bg-blue-700'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{customSettlementLoading ? '提交中...' : '提交申请'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user