fix: 카운트 5초 쓰로틀 복원 및 targetId 중복 제거 수정
문제: - incremental count가 매 메시지마다 스토어 갱신하여 범례 실시간 변동 - targetId 중복 제거 없이 개별 장비별로 카운트되어 수치 과다 수정: - incremental count 제거, 5초 주기 fullRecount 방식으로 복원 - updateCountsThrottled: 타임아웃 체크 + calculateCounts 통합 (5초 주기) - calculateCounts: targetId 중복 제거 포함 정확한 카운트 계산 - mergeFeatures에서는 features/darkSignalIds만 갱신, 카운트는 5초마다 - 필터 변경/삭제 시에는 recalculateCounts로 즉시 재계산 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
부모
08518c7c33
커밋
c4e40a0cef
@ -96,8 +96,6 @@ function isAnyEquipmentActive(ship) {
|
|||||||
// 타임아웃 체크 쓰로틀 간격
|
// 타임아웃 체크 쓰로틀 간격
|
||||||
// 참조: mda-react-front/src/common/deck.ts (271-331)
|
// 참조: mda-react-front/src/common/deck.ts (271-331)
|
||||||
// =====================
|
// =====================
|
||||||
const TIMEOUT_CHECK_INTERVAL_MS = 5000; // 5초
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 초기 선박 종류별 카운트
|
* 초기 선박 종류별 카운트
|
||||||
*/
|
*/
|
||||||
@ -113,144 +111,76 @@ const initialKindCounts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// Incremental 카운트 레지스트리 (스토어 외부)
|
// 카운트 쓰로틀링 (5초 주기)
|
||||||
|
// 참조: mda-react-front/src/common/deck.ts (271-331)
|
||||||
// =====================
|
// =====================
|
||||||
//
|
const COUNT_THROTTLE_MS = 5000; // 5초
|
||||||
// 기존 방식: 5초마다 features 전체 O(n) 순회하며 카운트 재계산
|
|
||||||
// 최적화: 변경된 선박만 카운트 증감 O(batch), 5초 주기는 타임아웃 체크에만 사용
|
/** 마지막 카운트 계산 시간 */
|
||||||
//
|
let lastCountTime = 0;
|
||||||
// - categories: 각 featureId가 마지막으로 기여한 카운트 카테고리
|
|
||||||
// 'dark' = 다크시그널 카운트, signalKindCode = 선종 카운트, null = 카운트 미포함
|
|
||||||
// - kindCounts: 선종별 누적 카운트 (incremental 유지)
|
|
||||||
// - darkSignalCount: 다크시그널 누적 카운트
|
|
||||||
// =====================
|
|
||||||
const countRegistry = {
|
|
||||||
categories: new Map(), // featureId → 'dark' | signalKindCode | null
|
|
||||||
kindCounts: { ...initialKindCounts },
|
|
||||||
darkSignalCount: 0,
|
|
||||||
totalCount: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 마지막 타임아웃 체크 시간 */
|
/** 마지막 타임아웃 체크 시간 */
|
||||||
let lastTimeoutCheckTime = 0;
|
let lastTimeoutCheckTime = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 선박 1건의 카운트 카테고리 판정
|
* 전체 카운트 계산 (targetId 중복 제거 포함)
|
||||||
|
*
|
||||||
* 처리 순서 (메인 프로젝트 동일):
|
* 처리 순서 (메인 프로젝트 동일):
|
||||||
* ① darkSignalIds.has → 'dark'
|
* ① darkSignalIds.has → darkCount++
|
||||||
* ② 단독 레이더 → null (카운트 제외)
|
* ② 단독 레이더 → 카운트 제외
|
||||||
* ⑤ !isAnyEquipmentActive → 'dark'
|
* ⑤ !isAnyEquipmentActive → darkCount++
|
||||||
* ⑥ isPriority 필터 + 선종/신호원/국적 필터 → signalKindCode | null
|
* ⑥ isPriority 필터 + 선종/신호원/국적 필터 → kindCounts++
|
||||||
|
* + targetId 기준 중복 제거
|
||||||
*
|
*
|
||||||
* ※ ②③④ 타임아웃 판정은 processTimeoutsThrottled에서 별도 처리
|
|
||||||
*
|
|
||||||
* @param {Object} ship - 선박 데이터
|
|
||||||
* @param {string} featureId
|
|
||||||
* @param {Set} darkSignalIds
|
|
||||||
* @param {boolean} isIntegrate
|
|
||||||
* @param {Object} kindVisibility
|
|
||||||
* @param {Object} sourceVisibility
|
|
||||||
* @param {Object} nationalVisibility
|
|
||||||
* @returns {string|null} 'dark' | signalKindCode | null
|
|
||||||
*/
|
|
||||||
function resolveShipCategory(ship, featureId, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility) {
|
|
||||||
if (darkSignalIds.has(featureId)) return 'dark';
|
|
||||||
if (ship.signalSourceCode === SIGNAL_SOURCE_RADAR && !ship.integrate) return null;
|
|
||||||
if (!isAnyEquipmentActive(ship)) return 'dark';
|
|
||||||
if (isIntegrate && ship.integrate && !ship.isPriority) return null;
|
|
||||||
if (!kindVisibility[ship.signalKindCode]) return null;
|
|
||||||
if (!sourceVisibility[ship.signalSourceCode]) return null;
|
|
||||||
const mapped = mapNationalCode(ship.nationalCode);
|
|
||||||
if (!nationalVisibility[mapped]) return null;
|
|
||||||
return ship.signalKindCode || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 단일 featureId의 카운트 증감 (delta)
|
|
||||||
* @param {string} featureId
|
|
||||||
* @param {string|null} newCategory - 새 카테고리
|
|
||||||
*/
|
|
||||||
function updateSingleCount(featureId, newCategory) {
|
|
||||||
const oldCategory = countRegistry.categories.get(featureId) || null;
|
|
||||||
if (oldCategory === newCategory) return;
|
|
||||||
|
|
||||||
// 이전 카테고리 카운트 감소
|
|
||||||
if (oldCategory === 'dark') {
|
|
||||||
countRegistry.darkSignalCount--;
|
|
||||||
} else if (oldCategory && countRegistry.kindCounts[oldCategory] !== undefined) {
|
|
||||||
countRegistry.kindCounts[oldCategory]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 새 카테고리 카운트 증가
|
|
||||||
if (newCategory === 'dark') {
|
|
||||||
countRegistry.darkSignalCount++;
|
|
||||||
} else if (newCategory && countRegistry.kindCounts[newCategory] !== undefined) {
|
|
||||||
countRegistry.kindCounts[newCategory]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newCategory) {
|
|
||||||
countRegistry.categories.set(featureId, newCategory);
|
|
||||||
} else {
|
|
||||||
countRegistry.categories.delete(featureId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* featureId를 카운트에서 제거
|
|
||||||
* @param {string} featureId
|
|
||||||
*/
|
|
||||||
function removeFromCount(featureId) {
|
|
||||||
updateSingleCount(featureId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* countRegistry의 totalCount 재계산
|
|
||||||
*/
|
|
||||||
function recalcTotal() {
|
|
||||||
countRegistry.totalCount = Object.values(countRegistry.kindCounts).reduce((a, b) => a + b, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 전체 카운트 재계산 (필터 변경, 통합모드 전환 시)
|
|
||||||
* targetId 중복 제거 포함
|
|
||||||
* @param {Map} features
|
* @param {Map} features
|
||||||
* @param {Set} darkSignalIds
|
* @param {Set} darkSignalIds
|
||||||
* @param {boolean} isIntegrate
|
* @param {boolean} isIntegrate
|
||||||
* @param {Object} kindVisibility
|
* @param {Object} kindVisibility
|
||||||
* @param {Object} sourceVisibility
|
* @param {Object} sourceVisibility
|
||||||
* @param {Object} nationalVisibility
|
* @param {Object} nationalVisibility
|
||||||
|
* @returns {{ kindCounts: Object, darkSignalCount: number, totalCount: number }}
|
||||||
*/
|
*/
|
||||||
function fullRecount(features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility) {
|
function calculateCounts(features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility) {
|
||||||
// 레지스트리 초기화
|
const kindCounts = { ...initialKindCounts };
|
||||||
countRegistry.categories.clear();
|
let darkSignalCount = 0;
|
||||||
Object.keys(countRegistry.kindCounts).forEach(k => { countRegistry.kindCounts[k] = 0; });
|
|
||||||
countRegistry.darkSignalCount = 0;
|
|
||||||
|
|
||||||
const seenTargetIds = new Set();
|
const seenTargetIds = new Set();
|
||||||
|
|
||||||
features.forEach((ship, featureId) => {
|
features.forEach((ship, featureId) => {
|
||||||
let category = resolveShipCategory(ship, featureId, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility);
|
// ① 다크시그널
|
||||||
|
if (darkSignalIds.has(featureId)) {
|
||||||
// targetId 중복 제거 (다크시그널은 개별 카운트이므로 제외)
|
darkSignalCount++;
|
||||||
if (category && category !== 'dark' && ship.targetId) {
|
return;
|
||||||
if (seenTargetIds.has(ship.targetId)) {
|
|
||||||
category = null;
|
|
||||||
} else {
|
|
||||||
seenTargetIds.add(ship.targetId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category === 'dark') {
|
// ② 단독 레이더 → 카운트 제외
|
||||||
countRegistry.darkSignalCount++;
|
if (ship.signalSourceCode === SIGNAL_SOURCE_RADAR && !ship.integrate) return;
|
||||||
countRegistry.categories.set(featureId, category);
|
|
||||||
} else if (category && countRegistry.kindCounts[category] !== undefined) {
|
// ⑤ 모든 장비 비활성 → 다크시그널
|
||||||
countRegistry.kindCounts[category]++;
|
if (!isAnyEquipmentActive(ship)) {
|
||||||
countRegistry.categories.set(featureId, category);
|
darkSignalCount++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⑥ 통합 모드: isPriority가 아니면 카운트 제외
|
||||||
|
if (isIntegrate && ship.integrate && !ship.isPriority) return;
|
||||||
|
|
||||||
|
// 필터 적용
|
||||||
|
if (!kindVisibility[ship.signalKindCode]) return;
|
||||||
|
if (!sourceVisibility[ship.signalSourceCode]) return;
|
||||||
|
const mapped = mapNationalCode(ship.nationalCode);
|
||||||
|
if (!nationalVisibility[mapped]) return;
|
||||||
|
|
||||||
|
// targetId 중복 제거
|
||||||
|
if (ship.targetId && seenTargetIds.has(ship.targetId)) return;
|
||||||
|
if (ship.targetId) seenTargetIds.add(ship.targetId);
|
||||||
|
|
||||||
|
if (ship.signalKindCode && kindCounts[ship.signalKindCode] !== undefined) {
|
||||||
|
kindCounts[ship.signalKindCode]++;
|
||||||
}
|
}
|
||||||
// null → categories에 저장하지 않음
|
|
||||||
});
|
});
|
||||||
|
|
||||||
recalcTotal();
|
const totalCount = Object.values(kindCounts).reduce((a, b) => a + b, 0);
|
||||||
|
return { kindCounts, darkSignalCount, totalCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -391,13 +321,11 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
* @param {Array} ships - 선박 데이터 배열
|
* @param {Array} ships - 선박 데이터 배열
|
||||||
*/
|
*/
|
||||||
mergeFeatures: (ships) => {
|
mergeFeatures: (ships) => {
|
||||||
// ※ 성능 최적화 #1: Map/Set을 직접 mutate (O(n) 전체 복사 제거)
|
// ※ 성능 최적화: Map/Set을 직접 mutate (O(n) 전체 복사 제거)
|
||||||
// ※ 성능 최적화 #2: Incremental count (변경된 선박만 카운트 증감)
|
// Zustand 변경 감지는 featuresVersion 카운터로 트리거
|
||||||
const state = get();
|
const state = get();
|
||||||
const { features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility } = state;
|
const { features, darkSignalIds } = state;
|
||||||
let darkChanged = false;
|
let darkChanged = false;
|
||||||
const deletedIds = [];
|
|
||||||
const changedIds = [];
|
|
||||||
|
|
||||||
ships.forEach((ship) => {
|
ships.forEach((ship) => {
|
||||||
const featureId = ship.featureId;
|
const featureId = ship.featureId;
|
||||||
@ -414,7 +342,6 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
if (!ship.lost && !hasActive) {
|
if (!ship.lost && !hasActive) {
|
||||||
features.delete(featureId);
|
features.delete(featureId);
|
||||||
if (darkSignalIds.delete(featureId)) darkChanged = true;
|
if (darkSignalIds.delete(featureId)) darkChanged = true;
|
||||||
deletedIds.push(featureId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +356,6 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
features.set(featureId, { ...ship, receivedTimestamp: parseReceivedTime(ship.receivedTime) });
|
features.set(featureId, { ...ship, receivedTimestamp: parseReceivedTime(ship.receivedTime) });
|
||||||
changedIds.push(featureId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 버전 카운터 증가
|
// 버전 카운터 증가
|
||||||
@ -438,52 +364,35 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
...(darkChanged ? { darkSignalVersion: s.darkSignalVersion + 1 } : {}),
|
...(darkChanged ? { darkSignalVersion: s.darkSignalVersion + 1 } : {}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Incremental count: 삭제된 선박은 카운트에서 제거, 변경된 선박은 카테고리 재판정
|
// 타임아웃 체크 + 카운트 갱신 (5초 쓰로틀)
|
||||||
deletedIds.forEach(fid => removeFromCount(fid));
|
get().updateCountsThrottled();
|
||||||
changedIds.forEach(fid => {
|
|
||||||
const ship = features.get(fid);
|
|
||||||
if (!ship) return;
|
|
||||||
const category = resolveShipCategory(ship, fid, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility);
|
|
||||||
updateSingleCount(fid, category);
|
|
||||||
});
|
|
||||||
recalcTotal();
|
|
||||||
|
|
||||||
set({
|
|
||||||
kindCounts: { ...countRegistry.kindCounts },
|
|
||||||
totalCount: countRegistry.totalCount,
|
|
||||||
darkSignalCount: countRegistry.darkSignalCount,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 타임아웃 체크 (5초 주기)
|
|
||||||
get().processTimeoutsThrottled();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 타임아웃 체크 (5초 주기)
|
* 쓰로틀 카운트 업데이트 (5초 주기)
|
||||||
* features 전체를 순회하여 타임아웃된 선박을 삭제/다크시그널 전환
|
* 타임아웃 체크 + 카운트 재계산을 5초마다 수행
|
||||||
* 카운트는 영향받는 선박만 incremental 업데이트
|
* 참조: mda-react-front/src/common/deck.ts - updateLayerData()
|
||||||
*
|
*
|
||||||
* 처리 순서 (메인 프로젝트 동일):
|
* 타임아웃 처리 순서 (메인 프로젝트 동일):
|
||||||
* ② 레이더(000005)+비통합 → timeout? delete
|
* ② 레이더(000005)+비통합 → timeout? delete
|
||||||
* ③ LOST=0 + INSHORE timeout → delete
|
* ③ LOST=0 + INSHORE timeout → delete
|
||||||
* ④ LOST=1 + OFFSHORE timeout → darkSignal 전환
|
* ④ LOST=1 + OFFSHORE timeout → darkSignal 전환
|
||||||
* ⑤ !isAnyEquipmentActive → darkSignal 전환
|
* ⑤ !isAnyEquipmentActive → darkSignal 전환
|
||||||
*/
|
*/
|
||||||
processTimeoutsThrottled: () => {
|
updateCountsThrottled: () => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (now - lastTimeoutCheckTime < TIMEOUT_CHECK_INTERVAL_MS) return;
|
if (now - lastCountTime < COUNT_THROTTLE_MS) return;
|
||||||
lastTimeoutCheckTime = now;
|
lastCountTime = now;
|
||||||
|
|
||||||
|
// === 타임아웃 체크 ===
|
||||||
const state = get();
|
const state = get();
|
||||||
const { features, darkSignalIds } = state;
|
const { features, darkSignalIds } = state;
|
||||||
const newDarkIds = [];
|
const newDarkIds = [];
|
||||||
const deleteIds = [];
|
const deleteIds = [];
|
||||||
|
|
||||||
features.forEach((ship, featureId) => {
|
features.forEach((ship, featureId) => {
|
||||||
// 이미 다크시그널 → 타임아웃 체크 불필요
|
|
||||||
if (darkSignalIds.has(featureId)) return;
|
if (darkSignalIds.has(featureId)) return;
|
||||||
|
|
||||||
// ② 단독 레이더(비통합) → 타임아웃이면 삭제
|
|
||||||
if (ship.signalSourceCode === SIGNAL_SOURCE_RADAR && !ship.integrate) {
|
if (ship.signalSourceCode === SIGNAL_SOURCE_RADAR && !ship.integrate) {
|
||||||
if (now - ship.receivedTimestamp > RADAR_TIMEOUT_MS) deleteIds.push(featureId);
|
if (now - ship.receivedTimestamp > RADAR_TIMEOUT_MS) deleteIds.push(featureId);
|
||||||
return;
|
return;
|
||||||
@ -491,60 +400,58 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
|
|
||||||
const elapsed = now - ship.receivedTimestamp;
|
const elapsed = now - ship.receivedTimestamp;
|
||||||
|
|
||||||
// ③ 영해안 (LOST≠1) + INSHORE 타임아웃 → 삭제
|
|
||||||
if (!ship.lost && elapsed > INSHORE_TIMEOUT_MS) {
|
if (!ship.lost && elapsed > INSHORE_TIMEOUT_MS) {
|
||||||
deleteIds.push(featureId);
|
deleteIds.push(featureId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ④ 영해밖 (LOST=1) + OFFSHORE 타임아웃 → 다크시그널 전환
|
|
||||||
if (ship.lost && elapsed > OFFSHORE_TIMEOUT_MS) {
|
if (ship.lost && elapsed > OFFSHORE_TIMEOUT_MS) {
|
||||||
newDarkIds.push(featureId);
|
newDarkIds.push(featureId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ⑤ 모든 장비 비활성 → 즉시 다크시그널 전환
|
|
||||||
if (!isAnyEquipmentActive(ship)) {
|
if (!isAnyEquipmentActive(ship)) {
|
||||||
newDarkIds.push(featureId);
|
newDarkIds.push(featureId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newDarkIds.length === 0 && deleteIds.length === 0) return;
|
// 타임아웃된 선박 처리
|
||||||
|
|
||||||
// features/darkSignalIds 직접 mutate
|
|
||||||
newDarkIds.forEach(fid => darkSignalIds.add(fid));
|
newDarkIds.forEach(fid => darkSignalIds.add(fid));
|
||||||
deleteIds.forEach(fid => {
|
deleteIds.forEach(fid => {
|
||||||
features.delete(fid);
|
features.delete(fid);
|
||||||
darkSignalIds.delete(fid);
|
darkSignalIds.delete(fid);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Incremental count: 영향받는 선박만 카운트 조정
|
// === 카운트 계산 (targetId 중복 제거 포함) ===
|
||||||
deleteIds.forEach(fid => removeFromCount(fid));
|
const { isIntegrate, kindVisibility, sourceVisibility, nationalVisibility } = get();
|
||||||
newDarkIds.forEach(fid => updateSingleCount(fid, 'dark'));
|
const counts = calculateCounts(features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility);
|
||||||
recalcTotal();
|
|
||||||
|
const hasTimeoutChanges = newDarkIds.length > 0 || deleteIds.length > 0;
|
||||||
|
|
||||||
set((s) => ({
|
set((s) => ({
|
||||||
featuresVersion: s.featuresVersion + 1,
|
...(hasTimeoutChanges ? {
|
||||||
darkSignalVersion: s.darkSignalVersion + 1,
|
featuresVersion: s.featuresVersion + 1,
|
||||||
kindCounts: { ...countRegistry.kindCounts },
|
darkSignalVersion: s.darkSignalVersion + 1,
|
||||||
totalCount: countRegistry.totalCount,
|
} : {}),
|
||||||
darkSignalCount: countRegistry.darkSignalCount,
|
kindCounts: counts.kindCounts,
|
||||||
|
totalCount: counts.totalCount,
|
||||||
|
darkSignalCount: counts.darkSignalCount,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 카운트 전체 재계산 (필터 변경, 통합모드 전환 시)
|
* 카운트 즉시 재계산 (필터 변경, 통합모드 전환 시)
|
||||||
* targetId 중복 제거 포함 전체 O(n) 순회
|
* targetId 중복 제거 포함 전체 O(n) 순회
|
||||||
*/
|
*/
|
||||||
recalculateCounts: () => {
|
recalculateCounts: () => {
|
||||||
const state = get();
|
const state = get();
|
||||||
const { features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility } = state;
|
const { features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility } = state;
|
||||||
fullRecount(features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility);
|
const counts = calculateCounts(features, darkSignalIds, isIntegrate, kindVisibility, sourceVisibility, nationalVisibility);
|
||||||
|
|
||||||
set({
|
set({
|
||||||
kindCounts: { ...countRegistry.kindCounts },
|
kindCounts: counts.kindCounts,
|
||||||
totalCount: countRegistry.totalCount,
|
totalCount: counts.totalCount,
|
||||||
darkSignalCount: countRegistry.darkSignalCount,
|
darkSignalCount: counts.darkSignalCount,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -571,14 +478,8 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
selectedShipId: s.selectedShipId === featureId ? null : s.selectedShipId,
|
selectedShipId: s.selectedShipId === featureId ? null : s.selectedShipId,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Incremental count: 삭제된 선박 카운트 제거
|
// 즉시 카운트 재계산
|
||||||
removeFromCount(featureId);
|
get().recalculateCounts();
|
||||||
recalcTotal();
|
|
||||||
set({
|
|
||||||
kindCounts: { ...countRegistry.kindCounts },
|
|
||||||
totalCount: countRegistry.totalCount,
|
|
||||||
darkSignalCount: countRegistry.darkSignalCount,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -599,14 +500,8 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
selectedShipId: featureIds.includes(s.selectedShipId) ? null : s.selectedShipId,
|
selectedShipId: featureIds.includes(s.selectedShipId) ? null : s.selectedShipId,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Incremental count: 삭제된 선박들 카운트 제거
|
// 즉시 카운트 재계산
|
||||||
featureIds.forEach(fid => removeFromCount(fid));
|
get().recalculateCounts();
|
||||||
recalcTotal();
|
|
||||||
set({
|
|
||||||
kindCounts: { ...countRegistry.kindCounts },
|
|
||||||
totalCount: countRegistry.totalCount,
|
|
||||||
darkSignalCount: countRegistry.darkSignalCount,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -672,21 +567,16 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
*/
|
*/
|
||||||
clearDarkSignals: () => {
|
clearDarkSignals: () => {
|
||||||
const state = get();
|
const state = get();
|
||||||
// Incremental count: 각 다크시그널 선박 카운트 제거
|
|
||||||
state.darkSignalIds.forEach((fid) => {
|
state.darkSignalIds.forEach((fid) => {
|
||||||
removeFromCount(fid);
|
|
||||||
state.features.delete(fid);
|
state.features.delete(fid);
|
||||||
});
|
});
|
||||||
state.darkSignalIds.clear();
|
state.darkSignalIds.clear();
|
||||||
recalcTotal();
|
|
||||||
|
|
||||||
set((s) => ({
|
set((s) => ({
|
||||||
featuresVersion: s.featuresVersion + 1,
|
featuresVersion: s.featuresVersion + 1,
|
||||||
darkSignalVersion: s.darkSignalVersion + 1,
|
darkSignalVersion: s.darkSignalVersion + 1,
|
||||||
kindCounts: { ...countRegistry.kindCounts },
|
|
||||||
totalCount: countRegistry.totalCount,
|
|
||||||
darkSignalCount: countRegistry.darkSignalCount,
|
|
||||||
}));
|
}));
|
||||||
|
get().recalculateCounts();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -940,12 +830,6 @@ const useShipStore = create(subscribeWithSelector((set, get) => ({
|
|||||||
* 모든 선박 데이터 초기화
|
* 모든 선박 데이터 초기화
|
||||||
*/
|
*/
|
||||||
clearFeatures: () => {
|
clearFeatures: () => {
|
||||||
// countRegistry 초기화
|
|
||||||
countRegistry.categories.clear();
|
|
||||||
Object.keys(countRegistry.kindCounts).forEach(k => { countRegistry.kindCounts[k] = 0; });
|
|
||||||
countRegistry.darkSignalCount = 0;
|
|
||||||
countRegistry.totalCount = 0;
|
|
||||||
|
|
||||||
set((s) => ({
|
set((s) => ({
|
||||||
features: new Map(),
|
features: new Map(),
|
||||||
featuresVersion: s.featuresVersion + 1,
|
featuresVersion: s.featuresVersion + 1,
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user