전투시스템 중지 처리

This commit is contained in:
2025-02-20 11:16:34 +09:00
parent 6760219734
commit c6dac677f6
5 changed files with 173 additions and 55 deletions

View File

@@ -5,6 +5,7 @@ export const TYPE_REGISTRY = 'regist';
export const TYPE_MODIFY = 'modify';
export const NONE = 'NONE';
export const ONE_MINUTE_MS = 60000;
export const ONE_MINUTE_SECOND = 60;
export const AUCTION_MIN_MINUTE_TIME = 15; // 15분
export { INITIAL_PAGE_SIZE, INITIAL_CURRENT_PAGE, INITIAL_PAGE_LIMIT };

View File

@@ -114,6 +114,8 @@ export const battleEventStatusType = {
wait: "WAIT",
register: "REGISTER",
end: "END",
stop: "STOP",
fail: "FAIL",
cancel: "CANCEL",
running: "RUNNING",
}

View File

@@ -6,31 +6,22 @@ import Loading from '../../common/Loading';
import {
Title,
BtnWrapper,
SearchBarAlert, SelectInput, InputLabel, DatePickerWrapper,
SearchBarAlert, SelectInput,
} from '../../../styles/Components';
import {
FormHelperText,
FormInput,
FormLabel,
FormTextArea,
FormTextAreaWrapper,
MessageWrapper,
FormRowGroup,
NoticeInputRow2,
NoticeInputItem2,
BoxWrapper,
FormStatusBar,
FormStatusLabel,
FormStatusWarning,
FormButtonContainer,
StyledSelectInput, TimeSeparator, TimeContainer,
} from '../../../styles/ModuleComponents';
import { HourList, MinuteList, modalTypes } from '../../../assets/data';
import { DynamicModal, Modal, DateTimeRangePicker, SingleDatePicker, SingleTimePicker } from '../../common';
import { LandAuctionModify, LandAuctionSingleRegist } from '../../../apis';
import { modalTypes } from '../../../assets/data';
import { DynamicModal, Modal, SingleDatePicker, SingleTimePicker } from '../../common';
import { NONE, TYPE_MODIFY, TYPE_REGISTRY } from '../../../assets/data/adminConstants';
import { landAuctionStatus, landAuctionStatusType, languageType, CurrencyType } from '../../../assets/data';
import { useModal } from '../../../utils/hook';
import { convertKTCDate } from '../../../utils';
import {
@@ -39,10 +30,9 @@ import {
battleEventStatus,
battleRepeatType,
} from '../../../assets/data/options';
import DatePickerComponent from '../../common/Date/DatePickerComponent';
import { BattleEventModify, BattleEventSingleRegist } from '../../../apis/Battle';
import { battleEventStatusType } from '../../../assets/data/types';
import { result } from 'lodash';
import { isValidDayRange } from '../../../utils/date';
const BattleEventModal = ({ modalType, detailView, handleDetailView, content, setDetailData, configData, rewardData }) => {
const { t } = useTranslation();
@@ -105,6 +95,17 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
const newDate = new Date(date);
if(resultData.repeat_type !== NONE && resultData.event_end_dt){
const endDate = new Date(resultData.event_end_dt);
const startDay = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate());
const endDay = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
if (endDay <= startDay) {
setAlertMsg(t('BATTLE_EVENT_MODAL_START_DIFF_END_WARNING'));
return;
}
}
setResultData(prev => ({
...prev,
event_start_dt: newDate
@@ -134,9 +135,9 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
// 종료 날짜 변경 핸들러
const handleEndDateChange = (date) => {
if (!date || !resultData.start_dt) return;
if (!date || !resultData.event_start_dt) return;
const startDate = new Date(resultData.start_dt);
const startDate = new Date(resultData.event_start_dt);
const endDate = new Date(date);
// 일자만 비교하기 위해 년/월/일만 추출
@@ -144,22 +145,27 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
const endDay = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
if (endDay <= startDay) {
setAlertMsg('종료일은 시작일보다 하루 이후여야 합니다.');
setAlertMsg(t('BATTLE_EVENT_MODAL_START_DIFF_END_WARNING'));
return;
}
const newDate = new Date(date);
newDate.setHours(23, 59, 59, 0);
setResultData(prev => ({
...prev,
event_end_dt: newDate
event_end_dt: endDate
}));
};
const handleConfigChange = (e) => {
const config = configData.find(data => data.id === e.target.value);
setResultData({ ...resultData, config_id: config.id, round_time: config.round_time });
const config = configData.find(data => String(data.id) === String(e.target.value));
if (config) {
setResultData({
...resultData,
config_id: config.id,
round_time: config.round_time
});
} else {
console.warn('Config not found for value:', e.target.value);
}
}
const handleReset = () => {
@@ -174,18 +180,20 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
if (!checkCondition()) return;
const minAllowedTime = new Date(new Date().getTime() + 10 * 60000);
if (resultData.event_start_dt < minAllowedTime) {
setAlertMsg(t('BATTLE_EVENT_MADEL_START_DT_WARNING'));
const startDt = resultData.event_start_dt;
const endDt = resultData.event_end_dt;
if (startDt < minAllowedTime) {
setAlertMsg(t('BATTLE_EVENT_MODAL_START_DT_WARNING'));
return;
}
if(resultData.repeat_type !== 'NONE' && resultData.event_start_dt >= resultData.event_end_dt) {
setAlertMsg(t('LAND_AUCTION_MADEL_AUCTION_DIFF_AUCTION'))
if(resultData.repeat_type !== 'NONE' && !isValidDayRange(startDt, endDt)) {
setAlertMsg(t('BATTLE_EVENT_MODAL_START_DIFF_END_WARNING'))
return;
}
//화면에 머물면서 상태는 안바꼈을 경우가 있기에 시작시간 지났을경우 차단
if (modalType === TYPE_MODIFY && resultData.event_start_dt < new Date()) {
setAlertMsg(t('LAND_AUCTION_MADEL_MODIFY_START'));
if (modalType === TYPE_MODIFY && startDt < new Date()) {
setAlertMsg(t('BATTLE_EVENT_MODAL_START_DT_WARNING'));
return;
}
@@ -212,8 +220,6 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
handleModalClose('registConfirm');
if(data.result === "SUCCESS") {
handleModalView('registComplete');
}else if(data.result === "ERROR_AUCTION_STATUS_IMPOSSIBLE"){
setAlertMsg(t('LAND_AUCTION_ERROR_MODIFY_STATUS'));
}else{
setAlertMsg(t('UPDATE_FAIL'));
}
@@ -227,8 +233,8 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
handleModalClose('registConfirm');
if(data.result === "SUCCESS") {
handleModalView('registComplete');
}else if(data.result === "ERROR_LAND_AUCTION_IMPOSSIBLE"){
setAlertMsg(t('LAND_AUCTION_ERROR_PROGRESS'));
}else if(data.result === "ERROR_BATTLE_EVENT_TIME_OVER"){
setAlertMsg(t('BATTLE_EVENT_MODAL_TIME_CHECK_WARNING'));
}else{
setAlertMsg(t('REGIST_FAIL'));
}
@@ -380,7 +386,7 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
현재상태: {battleEventStatus.find(data => data.value === content?.status)?.name || "등록"}
</FormStatusLabel>
<FormStatusWarning>
{isView('registry') ? '' : t('LAND_AUCTION_MODAL_STATUS_WARNING')}
{isView('registry') ? '' : t('BATTLE_EVENT_MODAL_STATUS_WARNING')}
</FormStatusWarning>
</FormStatusBar>
<FormButtonContainer $gap="5px">
@@ -415,7 +421,7 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
<DynamicModal
modalType={modalTypes.confirmOkCancel}
view={modalState.registConfirmModal}
modalText={isView('modify') ? t('LAND_UPDATE_CONFIRM') : t('LAND_REGIST_CONFIRM')}
modalText={isView('modify') ? t('BATTLE_EVENT_UPDATE_CONFIRM') : t('BATTLE_EVENT_REGIST_CONFIRM')}
handleSubmit={() => handleSubmit('registConfirm')}
handleCancel={() => handleModalClose('registConfirm')}
/>

View File

@@ -10,6 +10,7 @@ const resources = {
REGIST_COMPLTE: "등록이 완료되었습니다.",
REGIST_FAIL: '등록에 실패하였습니다. 잠시 후 다시 한번 진행해 주세요.',
UPDATE_FAIL: '수정에 실패하였습니다. 잠시 후 다시 한번 진행해 주세요.',
STOP_FAIL: '중단에 실패하였습니다. 잠시 후 다시 한번 진행해 주세요.',
DELETE_FAIL: '삭제에 실패하였습니다. 잠시 후 다시 한번 진행해 주세요.',
API_FAIL: '처리 중 오류가 발생하였습니다. 잠시 후 다시 한번 진행해 주세요. 오류가 지속될 경우, 담당자에게 문의해주세요.',
USER_MAIL_DEL_CONFIRM: '해당 우편을 삭제하시겠습니까?',
@@ -20,6 +21,7 @@ const resources = {
CANCEL_COMPLETED: '취소가 완료되었습니다.',
DEL_CONFIRM: "해당 아이템을 삭제하시겠습니까?",
DEL_COMPLETE: '삭제가 완료되었습니다.',
STOP_COMPLETE: '중단이 완료되었습니다.',
DEL_ITEM_COMPLETE: '아이템 삭제가 완료되었습니다.',
REQUIRED_VALUE_CHECK: '필수값을 입력해주세요.',
UPDATE_COMPLETED: '수정이 완료되었습니다.',
@@ -78,7 +80,16 @@ const resources = {
CHARGE_FINISH_FAIL: '충전 처리가 불가능합니다. 이미 충전이 완료되었거나, 관리자에 의해 요청 건에 대한 취소(반려) 처리된 것입니다. 해당 요청건에 대한 진행 상태를 다시 확인해 주세요.',
SEARCH_LIMIT_FAIL: '인출 가능 수량 조회에 대한 요청 중 오류가 발생하였습니다. 잠시 후 다시 한번 진행해 주세요. 오류가 지속될 경우, 담당자에게 문의해주세요.',
//전투시스템
BATTLE_EVENT_MADEL_START_DT_WARNING: "시작 시간은 현재 시간으로부터 10분 이후부터 가능합니다.",
BATTLE_EVENT_MODAL_START_DT_WARNING: "시작 시간은 현재 시간으로부터 10분 이후부터 가능합니다.",
BATTLE_EVENT_MODAL_START_DIFF_END_WARNING :"종료일은 시작일보다 하루 이후여야 합니다.",
BATTLE_EVENT_MODAL_TIME_CHECK_WARNING :"해당 시간에 속하는 이벤트가 존재합니다.",
BATTLE_EVENT_REGIST_CONFIRM: "랜드 경매를 등록하시겠습니까?",
BATTLE_EVENT_UPDATE_CONFIRM: "랜드 경매를 수정하시겠습니까?",
BATTLE_EVENT_SELECT_DELETE: "선택된 이벤트를 삭제하시겠습니까?",
BATTLE_EVENT_SELECT_STOP: "선택된 이벤트를 중단하시겠습니까?",
BATTLE_EVENT_STOP_5MINUTES_DATE_WARNING: "이벤트 시작 5분 전에는 중단할 수 없습니다.",
BATTLE_EVENT_STATUS_RUNNING_WARNING: "이벤트 진행중에는 중단할 수 없습니다.",
BATTLE_EVENT_MODAL_STATUS_WARNING: "이벤트가 진행중에는 변경이 불가합니다.",
//파일명칭
FILE_INDEX_USER_CONTENT: 'Caliverse_User_Index.xlsx',
FILE_CALIUM_REQUEST: 'Caliverse_Calium_Request.xlsx',

View File

@@ -6,7 +6,7 @@ import 'react-datepicker/dist/react-datepicker.css';
import {
BattleConfigView,
BattleEventDelete,
BattleEventDetailView,
BattleEventDetailView, BattleEventStop,
BattleEventView,
BattleRewardView,
} from '../../apis/Battle';
@@ -28,7 +28,7 @@ import {
Pagination,
ViewTableInfo, ExcelDownButton,
} from '../../components/common';
import { convertKTC, timeDiffMinute } from '../../utils';
import { convertKTC, convertKTCDate, convertUTC, timeDiffMinute } from '../../utils';
import { BattleEventModal, LandAuctionModal, LandAuctionSearchBar } from '../../components/ServiceManage';
import { INITIAL_PAGE_SIZE, INITIAL_PAGE_LIMIT } from '../../assets/data/adminConstants';
import { useDataFetch, useModal, useTable, withAuth } from '../../utils/hook';
@@ -38,7 +38,8 @@ import { battleEventStatus, battleRepeatType } from '../../assets/data/options';
import BattleEventSearchBar, {
useBattleEventSearch,
} from '../../components/ServiceManage/searchBar/BattleEventSearchBar';
import { getTimeOnly } from '../../utils/date';
import { getDateOnly, getTimeOnly, secondToMinutes } from '../../utils/date';
import { battleEventStatusType } from '../../assets/data/types';
const BattleEvent = () => {
const token = sessionStorage.getItem('token');
@@ -53,6 +54,8 @@ const BattleEvent = () => {
handleModalView,
handleModalClose
} = useModal({
stopConfirm: 'hidden',
stopComplete: 'hidden',
detail: 'hidden',
deleteConfirm: 'hidden',
deleteComplete: 'hidden'
@@ -85,6 +88,41 @@ const BattleEvent = () => {
data: battleRewardData
} = useDataFetch(() => BattleRewardView(token), [token]);
const endTime = (start_dt, operation_time) =>{
const startDate = new Date(start_dt);
startDate.setSeconds(startDate.getSeconds() + operation_time);
return startDate;
}
const isStopMinutes = (time) => {
const givenDate = new Date(time);
const currentDate = convertUTC(new Date());
// 시간만 비교하기 위해 년,월,일을 동일하게 설정
givenDate.setFullYear(currentDate.getFullYear());
givenDate.setMonth(currentDate.getMonth());
givenDate.setDate(currentDate.getDate());
// 두 시간의 차이를 밀리초로 계산
const timeDifference = currentDate.getTime() - givenDate.getTime();
// 밀리초로 변환
const fiveMinutesInMs = 5 * 60 * 1000;
return timeDifference < 0 && Math.abs(timeDifference) <= fiveMinutesInMs;
}
const isRunningTime = (time, operation_time) =>{
const startDate = new Date(time);
const endDate = new Date(startDate.getTime() + (operation_time * 1000));
const currentDate = convertUTC(new Date());
return currentDate >= startDate && currentDate <= endDate;
}
const handleModalSubmit = async (type, param = null) => {
switch (type) {
case "regist":
@@ -112,6 +150,42 @@ const BattleEvent = () => {
return;
}
handleModalView('deleteConfirm');
break;
case "stop":
const select_item = selectedRows[0];
if(select_item.status === battleEventStatusType.running){
setAlertMsg(t('BATTLE_EVENT_STATUS_RUNNING_WARNING'));
return;
}
console.log(select_item)
const isStopTimeCheck = isStopMinutes(select_item.event_start_dt);
if(isStopTimeCheck){
setAlertMsg(t('BATTLE_EVENT_STOP_5MINUTES_DATE_WARNING'));
return;
}
if(isRunningTime(select_item.event_start_dt, select_item.event_operation_time)){
setAlertMsg(t('BATTLE_EVENT_STATUS_RUNNING_WARNING'));
return;
}
handleModalView('stopConfirm');
break;
case "stopConfirm":
const stop_item = selectedRows[0];
await BattleEventStop(token, stop_item.id, stop_item).then(data => {
handleModalClose('stopConfirm');
if(data.result === "SUCCESS") {
handleModalView('stopComplete');
}else if(data.result === "ERROR_BATTLE_EVENT_STATUS_START_IMPOSSIBLE"){
setAlertMsg(t('BATTLE_EVENT_STATUS_RUNNING_WARNING'));
}else{
setAlertMsg(t('STOP_FAIL'));
}
}).catch(reason => {
setAlertMsg(t('API_FAIL'));
});
break;
case "deleteConfirm":
let list = [];
@@ -149,6 +223,10 @@ const BattleEvent = () => {
handleModalClose('deleteComplete');
window.location.reload();
break;
case "stopComplete":
handleModalClose('stopComplete');
window.location.reload();
break;
case "warning":
setAlertMsg('')
break;
@@ -175,8 +253,11 @@ const BattleEvent = () => {
</FormWrapper>
<ViewTableInfo total={dataList?.total} total_all={dataList?.total_all} handleOrderBy={handleOrderByChange} handlePageSize={handlePageSizeChange}>
<ExcelDownButton tableRef={tableRef} fileName={t('FILE_BATTLE_EVENT')} />
{/*{userInfo.auth_list?.some(auth => auth.id === authType.battleEventDelete) && (*/}
{/* <Button theme={selectedRows.length === 0 ? 'disable' : 'line'} text="이벤트 삭제" handleClick={() => handleModalSubmit('delete')} />*/}
{/*)}*/}
{userInfo.auth_list?.some(auth => auth.id === authType.battleEventDelete) && (
<Button theme={selectedRows.length === 0 ? 'disable' : 'line'} text="이벤트 중단" handleClick={() => handleModalSubmit('delete')} />
<Button theme={selectedRows.length === 0 ? 'disable' : 'line'} text="이벤트 중단" handleClick={() => handleModalSubmit('stop')} />
)}
{userInfo.auth_list?.some(auth => auth.id === authType.battleEventUpdate) && (
<Button
@@ -194,17 +275,18 @@ const BattleEvent = () => {
<tr>
<th width="40"></th>
<th width="90">그룹</th>
<th width="60">이벤트 ID</th>
<th width="150">이벤트명</th>
<th width="70">이벤트 ID</th>
<th width="200">이벤트명</th>
<th width="80">반복</th>
<th width="120">이벤트 시작시간</th>
<th width="120">이벤트 종료시간</th>
<th width="100">이벤트 시작시간(KST)</th>
<th width="100">이벤트 종료시간(KST)</th>
<th width="90">이벤트 상태</th>
<th width="90">라운드 시간</th>
<th width="80">라운드 </th>
<th width="80">핫타임</th>
<th width="200">기간 시작일</th>
<th width="200">기간 종료일</th>
<th width="90">배정포드</th>
<th width="70">라운드 </th>
<th width="70">핫타임</th>
<th width="100">기간 시작일(KST)</th>
<th width="100">기간 종료일(KST)</th>
<th width="100">확인 / 수정</th>
<th width="150">히스토리</th>
</tr>
@@ -218,25 +300,26 @@ const BattleEvent = () => {
checked={isRowSelected(battle.id)} />
</td>
<td>{battle.group_id}</td>
<td>{battle.id}</td>
<td>{battle.event_id}</td>
<td>{battle.event_name}</td>
<StatusWapper>
<StatusLabel $status={battle.repeat_type}>
{battleRepeatType.find(data => data.value === battle.repeat_type).name}
</StatusLabel>
</StatusWapper>
<td>{getTimeOnly(battle.event_start_dt)}</td>
<td>{battle.end_time}</td>
<td>{getTimeOnly(convertKTCDate(battle.event_start_dt))}</td>
<td>{getTimeOnly(endTime(convertKTCDate(battle.event_start_dt), battle.event_operation_time))}</td>
<StatusWapper>
<StatusLabel $status={battle.status}>
{battleEventStatus.find(data => data.value === battle.status).name}
</StatusLabel>
</StatusWapper>
<td>{battle.round_time}</td>
<td>{secondToMinutes(battle.round_time)}</td>
<td>{battle.reward_group_id}</td>
<td>{battle.round_count}</td>
<td>{battle.hot_time}</td>
<td>{convertKTC(battle.event_start_dt)}</td>
<td>{convertKTC(battle.event_end_dt)}</td>
<td>{getDateOnly(convertKTCDate(battle.event_start_dt))}</td>
<td>{getDateOnly(convertKTCDate(battle.event_end_dt))}</td>
<td>
<Button theme="line" text="상세보기"
handleClick={e => handleModalSubmit('detail', battle.id)} />
@@ -253,13 +336,28 @@ const BattleEvent = () => {
{/*상세*/}
<BattleEventModal modalType={modalType} detailView={modalState.detailModal} handleDetailView={() => handleModalClose('detail')} content={detailData} setDetailData={setDetailData} configData={battleConfigData} rewardData={battleRewardData} />
{/*중단 확인*/}
<DynamicModal
modalType={modalTypes.confirmOkCancel}
view={modalState.stopConfirmModal}
handleCancel={() => handleModalClose('stopConfirm')}
handleSubmit={() => handleModalSubmit('stopConfirm')}
modalText={t('BATTLE_EVENT_SELECT_STOP')}
/>
{/*중단 완료*/}
<DynamicModal
modalType={modalTypes.completed}
view={modalState.stopCompleteModal}
handleSubmit={() => handleModalSubmit('stopComplete')}
modalText={t('STOP_COMPLETE')}
/>
{/*삭제 확인*/}
<DynamicModal
modalType={modalTypes.confirmOkCancel}
view={modalState.deleteConfirmModal}
handleCancel={() => handleModalClose('deleteConfirm')}
handleSubmit={() => handleModalSubmit('deleteConfirm')}
modalText={t('LAND_AUCTION_SELECT_DELETE')}
modalText={t('BATTLE_EVENT_SELECT_DELETE')}
/>
{/*삭제 완료*/}
<DynamicModal