모달 스크롤 추가
detailGrid 수정 전투이벤트, 랜드경매, 이벤트, 메일 상세 수정 랜드경매 예약종료일 제거
This commit is contained in:
@@ -1,131 +0,0 @@
|
|||||||
{
|
|
||||||
"baseUrl": "/api/v1/users",
|
|
||||||
"endpoints": {
|
|
||||||
"UserView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/find-users",
|
|
||||||
"dataPath": "data.data.result",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["search_type", "search_key"]
|
|
||||||
},
|
|
||||||
"UserInfoView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/basicinfo",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserChangeNickName": {
|
|
||||||
"method": "PUT",
|
|
||||||
"url": "/api/v1/users/change-nickname",
|
|
||||||
"dataPath": null,
|
|
||||||
"paramFormat": "body",
|
|
||||||
"paramMapping": ["guid", "nickname"]
|
|
||||||
},
|
|
||||||
"UserChangeAdminLevel": {
|
|
||||||
"method": "PUT",
|
|
||||||
"url": "/api/v1/users/change-level",
|
|
||||||
"dataPath": null,
|
|
||||||
"paramFormat": "body",
|
|
||||||
"paramMapping": ["guid", "level"]
|
|
||||||
},
|
|
||||||
"UserKick": {
|
|
||||||
"method": "PUT",
|
|
||||||
"url": "/api/v1/users/user-kick",
|
|
||||||
"dataPath": "data",
|
|
||||||
"paramFormat": "body",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserAvatarView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/avatarinfo",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserClothView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/clothinfo",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserToolView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/toolslot",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserInventoryView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/inventory",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserInventoryItemDelete": {
|
|
||||||
"method": "DELETE",
|
|
||||||
"url": "/api/v1/users/inventory/delete/item",
|
|
||||||
"dataPath": "data",
|
|
||||||
"paramFormat": "body",
|
|
||||||
"paramMapping": ["guid", "inventory_id"]
|
|
||||||
},
|
|
||||||
"UserTattooView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/tattoo",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserQuestView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/quest",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserFriendListView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/friendlist",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
},
|
|
||||||
"UserMailView": {
|
|
||||||
"method": "POST",
|
|
||||||
"url": "/api/v1/users/mail",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "body",
|
|
||||||
"paramMapping": ["guid", "page", "limit"]
|
|
||||||
},
|
|
||||||
"UserMailDelete": {
|
|
||||||
"method": "DELETE",
|
|
||||||
"url": "/api/v1/users/mail/delete",
|
|
||||||
"dataPath": "data",
|
|
||||||
"paramFormat": "body",
|
|
||||||
"paramMapping": ["mail_id"]
|
|
||||||
},
|
|
||||||
"UserMailItemDelete": {
|
|
||||||
"method": "DELETE",
|
|
||||||
"url": "/api/v1/users/mail/delete/item",
|
|
||||||
"dataPath": "data",
|
|
||||||
"paramFormat": "body",
|
|
||||||
"paramMapping": ["mail_id", "item_id"]
|
|
||||||
},
|
|
||||||
"UserMailDetailView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/mail/:id",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "path",
|
|
||||||
"paramMapping": ["id"]
|
|
||||||
},
|
|
||||||
"UserMyhomeView": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "/api/v1/users/myhome",
|
|
||||||
"dataPath": "data.data",
|
|
||||||
"paramFormat": "query",
|
|
||||||
"paramMapping": ["guid"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,7 @@ import styled from 'styled-components';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { AnimatedTabs } from '../index';
|
import { AnimatedTabs } from '../index';
|
||||||
const { RangePicker } = DatePicker;
|
const { RangePicker } = DatePicker;
|
||||||
|
const { TextArea } = Input;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 위치 지정 가능한 그리드 형태 상세 정보 표시 컴포넌트
|
* 위치 지정 가능한 그리드 형태 상세 정보 표시 컴포넌트
|
||||||
@@ -51,12 +52,15 @@ const DetailGrid = ({ items, formData, onChange, disabled = false, columns = 4 }
|
|||||||
handler,
|
handler,
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
|
step,
|
||||||
format,
|
format,
|
||||||
required,
|
required,
|
||||||
showTime,
|
showTime,
|
||||||
tabItems,
|
tabItems,
|
||||||
activeKey,
|
activeKey,
|
||||||
onTabChange
|
onTabChange,
|
||||||
|
maxLength,
|
||||||
|
rows: textareaRows
|
||||||
} = item;
|
} = item;
|
||||||
|
|
||||||
// 현재 값 가져오기 (formData에서 또는 항목에서)
|
// 현재 값 가져오기 (formData에서 또는 항목에서)
|
||||||
@@ -85,10 +89,35 @@ const DetailGrid = ({ items, formData, onChange, disabled = false, columns = 4 }
|
|||||||
value={currentValue}
|
value={currentValue}
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
|
step={step || 1}
|
||||||
onChange={(value) => onChange(key, value, handler)}
|
onChange={(value) => onChange(key, value, handler)}
|
||||||
placeholder={placeholder || `${label} 입력`}
|
placeholder={placeholder || `${label} 입력`}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
|
case 'display':
|
||||||
|
return <Input
|
||||||
|
{...commonProps}
|
||||||
|
value={currentValue || ''}
|
||||||
|
readOnly
|
||||||
|
style={{
|
||||||
|
...commonProps.style,
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
cursor: 'default'
|
||||||
|
}}
|
||||||
|
placeholder={placeholder || ''}
|
||||||
|
/>;
|
||||||
|
|
||||||
|
case 'textarea':
|
||||||
|
return <TextArea
|
||||||
|
{...commonProps}
|
||||||
|
value={currentValue || ''}
|
||||||
|
onChange={(e) => onChange(key, e.target.value, handler)}
|
||||||
|
placeholder={placeholder}
|
||||||
|
maxLength={maxLength}
|
||||||
|
rows={textareaRows || 4}
|
||||||
|
showCount={!!maxLength}
|
||||||
|
/>;
|
||||||
|
|
||||||
case 'select':
|
case 'select':
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
@@ -99,7 +128,7 @@ const DetailGrid = ({ items, formData, onChange, disabled = false, columns = 4 }
|
|||||||
>
|
>
|
||||||
{options && options.map((option) => (
|
{options && options.map((option) => (
|
||||||
<Select.Option key={option.value} value={option.value}>
|
<Select.Option key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.name}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
@@ -131,12 +160,25 @@ const DetailGrid = ({ items, formData, onChange, disabled = false, columns = 4 }
|
|||||||
currentValue.end ? dayjs(currentValue.end) : null
|
currentValue.end ? dayjs(currentValue.end) : null
|
||||||
] : null)}
|
] : null)}
|
||||||
format={format || 'YYYY-MM-DD HH:mm:ss'}
|
format={format || 'YYYY-MM-DD HH:mm:ss'}
|
||||||
onChange={(dates, dateStrings) => {
|
onChange={(dates) => {
|
||||||
if (dates) {
|
if (dates && dates.length === 2) {
|
||||||
// 두 개의 별도 필드에 각각 업데이트
|
// 두 개의 별도 필드에 각각 업데이트
|
||||||
if (item.keys) {
|
if (item.keys) {
|
||||||
onChange(item.keys.start, dates[0], handler);
|
// 두 개의 onChange를 순차적으로 호출하는 대신
|
||||||
onChange(item.keys.end, dates[1], handler);
|
// 한 번에 두 필드를 모두 업데이트하는 방식으로 변경
|
||||||
|
const updatedData = {
|
||||||
|
...formData,
|
||||||
|
[item.keys.start]: dates[0],
|
||||||
|
[item.keys.end]: dates[1]
|
||||||
|
};
|
||||||
|
|
||||||
|
// handler가 있으면 handler 실행, 없으면 직접 onChange 호출
|
||||||
|
if (handler) {
|
||||||
|
handler(dates, key, updatedData);
|
||||||
|
} else {
|
||||||
|
// onChange를 통해 전체 업데이트된 데이터를 전달
|
||||||
|
onChange('dateRange_update', updatedData, null);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 기존 방식 지원 (하위 호환성)
|
// 기존 방식 지원 (하위 호환성)
|
||||||
onChange(key, {
|
onChange(key, {
|
||||||
@@ -147,8 +189,17 @@ const DetailGrid = ({ items, formData, onChange, disabled = false, columns = 4 }
|
|||||||
} else {
|
} else {
|
||||||
// 두 필드 모두 비우기
|
// 두 필드 모두 비우기
|
||||||
if (item.keys) {
|
if (item.keys) {
|
||||||
onChange(item.keys.start, null, handler);
|
const updatedData = {
|
||||||
onChange(item.keys.end, null, handler);
|
...formData,
|
||||||
|
[item.keys.start]: null,
|
||||||
|
[item.keys.end]: null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (handler) {
|
||||||
|
handler(null, key, updatedData);
|
||||||
|
} else {
|
||||||
|
onChange('dateRange_update', updatedData, null);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
onChange(key, { start: null, end: null }, handler);
|
onChange(key, { start: null, end: null }, handler);
|
||||||
}
|
}
|
||||||
@@ -204,8 +255,17 @@ const DetailGrid = ({ items, formData, onChange, disabled = false, columns = 4 }
|
|||||||
case 'custom':
|
case 'custom':
|
||||||
return item.render ? item.render(formData, onChange) : null;
|
return item.render ? item.render(formData, onChange) : null;
|
||||||
|
|
||||||
|
case 'label':
|
||||||
default:
|
default:
|
||||||
return <div>{currentValue}</div>;
|
return <div style={{
|
||||||
|
padding: '4px 11px',
|
||||||
|
minHeight: '32px',
|
||||||
|
lineHeight: '24px',
|
||||||
|
fontSize: '15px',
|
||||||
|
color: currentValue ? '#000' : '#bfbfbf'
|
||||||
|
}}>
|
||||||
|
{currentValue || placeholder || ''}
|
||||||
|
</div>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,24 +22,36 @@ const DetailLayout = ({
|
|||||||
}) => {
|
}) => {
|
||||||
// 값 변경 핸들러
|
// 값 변경 핸들러
|
||||||
const handleChange = (key, value, handler) => {
|
const handleChange = (key, value, handler) => {
|
||||||
// 핸들러가 있으면 핸들러 실행
|
let updatedFormData = { ...formData };
|
||||||
if (handler) {
|
|
||||||
handler(value, key, formData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// dateRange 전용 업데이트 처리
|
||||||
|
if (key === 'dateRange_update') {
|
||||||
|
updatedFormData = value; // value가 이미 완전히 업데이트된 객체
|
||||||
|
}
|
||||||
// 키가 점 표기법이면 중첩 객체 업데이트
|
// 키가 점 표기법이면 중첩 객체 업데이트
|
||||||
if (key.includes('.')) {
|
else if (key.includes('.')) {
|
||||||
const [parentKey, childKey] = key.split('.');
|
const [parentKey, childKey] = key.split('.');
|
||||||
onChange({
|
updatedFormData = {
|
||||||
...formData,
|
...formData,
|
||||||
[parentKey]: {
|
[parentKey]: {
|
||||||
...formData[parentKey],
|
...formData[parentKey],
|
||||||
[childKey]: value
|
[childKey]: value
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
} else {
|
} else {
|
||||||
// 일반 키는 직접 업데이트
|
// 일반 키는 직접 업데이트
|
||||||
onChange({ ...formData, [key]: value });
|
updatedFormData = {
|
||||||
|
...formData,
|
||||||
|
[key]: value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 핸들러가 있으면 핸들러 실행 (업데이트된 데이터를 전달)
|
||||||
|
if (handler) {
|
||||||
|
handler(value, key, updatedFormData);
|
||||||
|
} else {
|
||||||
|
// 핸들러가 없으면 직접 onChange 호출
|
||||||
|
onChange(updatedFormData);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
import * as XLSX from 'xlsx-js-style';
|
|
||||||
import { ExcelDownButton } from '../../../styles/ModuleComponents';
|
|
||||||
|
|
||||||
const ExcelDownloadButton = ({ tableRef, fileName = 'download.xlsx', sheetName = 'Sheet1' }) => {
|
|
||||||
const isNumeric = (value) => {
|
|
||||||
// 숫자 또는 숫자 문자열인지 확인
|
|
||||||
return !isNaN(value) && !isNaN(parseFloat(value));
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadExcel = () => {
|
|
||||||
try {
|
|
||||||
if (!tableRef.current) return;
|
|
||||||
|
|
||||||
const tableElement = tableRef.current;
|
|
||||||
const headerRows = tableElement.getElementsByTagName('thead')[0].getElementsByTagName('tr');
|
|
||||||
const bodyRows = tableElement.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
|
|
||||||
|
|
||||||
// 헤더 데이터 추출
|
|
||||||
const headers = Array.from(headerRows[0].cells).map(cell => cell.textContent);
|
|
||||||
|
|
||||||
// 바디 데이터 추출 및 숫자 타입 처리
|
|
||||||
const bodyData = Array.from(bodyRows).map(row =>
|
|
||||||
Array.from(row.cells).map(cell => {
|
|
||||||
const value = cell.textContent;
|
|
||||||
return isNumeric(value) ? parseFloat(value) : value;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// 워크북 생성
|
|
||||||
const wb = XLSX.utils.book_new();
|
|
||||||
|
|
||||||
// 테두리 스타일 정의
|
|
||||||
const borderStyle = {
|
|
||||||
style: "thin",
|
|
||||||
color: { rgb: "000000" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// 스타일 정의
|
|
||||||
const centerStyle = {
|
|
||||||
font: {
|
|
||||||
name: "맑은 고딕",
|
|
||||||
sz: 11
|
|
||||||
},
|
|
||||||
alignment: {
|
|
||||||
horizontal: 'right',
|
|
||||||
vertical: 'right'
|
|
||||||
},
|
|
||||||
border: {
|
|
||||||
top: borderStyle,
|
|
||||||
bottom: borderStyle,
|
|
||||||
left: borderStyle,
|
|
||||||
right: borderStyle
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const headerStyle = {
|
|
||||||
alignment: {
|
|
||||||
horizontal: 'center',
|
|
||||||
vertical: 'center'
|
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
fgColor: { rgb: "d9e1f2" },
|
|
||||||
patternType: "solid"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 데이터에 스타일 적용
|
|
||||||
const wsData = [
|
|
||||||
// 헤더 행
|
|
||||||
headers.map(h => ({
|
|
||||||
v: h,
|
|
||||||
s: headerStyle
|
|
||||||
})),
|
|
||||||
// 데이터 행들
|
|
||||||
...bodyData.map(row =>
|
|
||||||
row.map(cell => ({
|
|
||||||
v: cell,
|
|
||||||
s: centerStyle
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
// 워크시트 생성
|
|
||||||
const ws = XLSX.utils.aoa_to_sheet(wsData);
|
|
||||||
|
|
||||||
// 열 너비 설정 (최소 8, 최대 50)
|
|
||||||
ws['!cols'] = headers.map((_, index) => {
|
|
||||||
const maxLength = Math.max(
|
|
||||||
headers[index].length * 2,
|
|
||||||
...bodyData.map(row => String(row[index] || '').length * 1.2)
|
|
||||||
);
|
|
||||||
return { wch: Math.max(8, Math.min(50, maxLength)) };
|
|
||||||
});
|
|
||||||
|
|
||||||
// 워크시트를 워크북에 추가
|
|
||||||
XLSX.utils.book_append_sheet(wb, ws, sheetName);
|
|
||||||
|
|
||||||
// 엑셀 파일 다운로드
|
|
||||||
XLSX.writeFile(wb, fileName);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Excel download failed:', error);
|
|
||||||
alert('엑셀 다운로드 중 오류가 발생했습니다.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ExcelDownButton onClick={downloadExcel}>
|
|
||||||
엑셀 다운로드
|
|
||||||
</ExcelDownButton>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ExcelDownloadButton;
|
|
||||||
@@ -38,6 +38,8 @@ const ModalBg = styled(motion.div)`
|
|||||||
min-width: 1080px;
|
min-width: 1080px;
|
||||||
display: ${props => (props.$view === 'hidden' ? 'none' : 'block')};
|
display: ${props => (props.$view === 'hidden' ? 'none' : 'block')};
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ModalContainer = styled.div`
|
const ModalContainer = styled.div`
|
||||||
@@ -52,9 +54,18 @@ const ModalWrapper = styled(motion.div)`
|
|||||||
min-width: ${props => props.min || 'auto'};
|
min-width: ${props => props.min || 'auto'};
|
||||||
padding: ${props => props.$padding || '30px'};
|
padding: ${props => props.$padding || '30px'};
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
max-height: 90%;
|
max-height: calc(100vh - 40px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
|
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
/*모바일*/
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
min-width: unset;
|
||||||
|
max-width: calc(100vw - 20px);
|
||||||
|
max-height: calc(100vh - 20px);
|
||||||
|
padding: ${props => props.$padding || '20px'};
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Modal = ({ children, $padding, min, $view, $bgcolor }) => {
|
const Modal = ({ children, $padding, min, $view, $bgcolor }) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, Fragment, useEffect } from 'react';
|
import React, { useState, Fragment, useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Button from '../common/button/Button';
|
import Button from '../common/button/Button';
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
FormStatusWarning,
|
FormStatusWarning,
|
||||||
FormButtonContainer,
|
FormButtonContainer,
|
||||||
} from '../../styles/ModuleComponents';
|
} from '../../styles/ModuleComponents';
|
||||||
import { Modal, SingleDatePicker, SingleTimePicker } from '../common';
|
import { DetailLayout, Modal, SingleDatePicker, SingleTimePicker } from '../common';
|
||||||
import { NONE, TYPE_MODIFY, TYPE_REGISTRY } from '../../assets/data/adminConstants';
|
import { NONE, TYPE_MODIFY, TYPE_REGISTRY } from '../../assets/data/adminConstants';
|
||||||
import { convertKTCDate } from '../../utils';
|
import { convertKTCDate } from '../../utils';
|
||||||
import {
|
import {
|
||||||
@@ -64,16 +64,6 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
}
|
}
|
||||||
}, [modalType, content]);
|
}, [modalType, content]);
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if(modalType === TYPE_REGISTRY && configData?.length > 0){
|
|
||||||
// setResultData(prev => ({
|
|
||||||
// ...prev,
|
|
||||||
// round_count: configData[0].default_round_count,
|
|
||||||
// round_time: configData[0].round_time
|
|
||||||
// }));
|
|
||||||
// }
|
|
||||||
// }, [modalType, configData]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (checkCondition()) {
|
if (checkCondition()) {
|
||||||
setIsNullValue(false);
|
setIsNullValue(false);
|
||||||
@@ -82,104 +72,12 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
}
|
}
|
||||||
}, [resultData]);
|
}, [resultData]);
|
||||||
|
|
||||||
// 시작 날짜 변경 핸들러
|
const opGameMode = useMemo(() => {
|
||||||
const handleStartDateChange = (date) => {
|
return gameModeData?.map(item => ({
|
||||||
if (!date) return;
|
value: item.id,
|
||||||
|
name: `${item.desc}(${item.id})`
|
||||||
const newDate = new Date(date);
|
})) || [];
|
||||||
|
}, [gameModeData]);
|
||||||
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) {
|
|
||||||
showToast('DATE_START_DIFF_END_WARNING', {type: alertTypes.warning});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setResultData(prev => ({
|
|
||||||
...prev,
|
|
||||||
event_start_dt: newDate
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
// 시작 시간 변경 핸들러
|
|
||||||
const handleStartTimeChange = (time) => {
|
|
||||||
if (!time) return;
|
|
||||||
|
|
||||||
const newDateTime = resultData.event_start_dt
|
|
||||||
? new Date(resultData.event_start_dt)
|
|
||||||
: new Date();
|
|
||||||
|
|
||||||
newDateTime.setHours(
|
|
||||||
time.getHours(),
|
|
||||||
time.getMinutes(),
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
setResultData(prev => ({
|
|
||||||
...prev,
|
|
||||||
event_start_dt: newDateTime
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEndTimeChange = (time) => {
|
|
||||||
if (!time) return;
|
|
||||||
|
|
||||||
const newDateTime = resultData.event_end_time
|
|
||||||
? new Date(resultData.event_end_time)
|
|
||||||
: new Date();
|
|
||||||
|
|
||||||
newDateTime.setHours(
|
|
||||||
time.getHours(),
|
|
||||||
time.getMinutes(),
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
setResultData(prev => ({
|
|
||||||
...prev,
|
|
||||||
event_end_time: newDateTime
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
// 종료 날짜 변경 핸들러
|
|
||||||
const handleEndDateChange = (date) => {
|
|
||||||
if (!date || !resultData.event_start_dt) return;
|
|
||||||
|
|
||||||
const startDate = new Date(resultData.event_start_dt);
|
|
||||||
const endDate = new Date(date);
|
|
||||||
|
|
||||||
// 일자만 비교하기 위해 년/월/일만 추출
|
|
||||||
const startDay = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
||||||
const endDay = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
||||||
|
|
||||||
if (endDay <= startDay) {
|
|
||||||
showToast('DATE_START_DIFF_END_WARNING', {type: alertTypes.warning});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setResultData(prev => ({
|
|
||||||
...prev,
|
|
||||||
event_end_dt: endDate
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleConfigChange = (e) => {
|
|
||||||
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 {
|
|
||||||
showToast('Config not found for value:', e.target.value, {type: alertTypes.warning});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setDetailData({});
|
setDetailData({});
|
||||||
@@ -282,6 +180,7 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
return (
|
return (
|
||||||
resultData.event_start_dt !== ''
|
resultData.event_start_dt !== ''
|
||||||
&& resultData.group_id !== ''
|
&& resultData.group_id !== ''
|
||||||
|
&& resultData.game_mode_id > 0
|
||||||
&& resultData.event_name !== ''
|
&& resultData.event_name !== ''
|
||||||
&& (resultData.repeat_type === 'NONE' || (resultData.repeat_type !== 'NONE' && resultData.event_end_dt !== ''))
|
&& (resultData.repeat_type === 'NONE' || (resultData.repeat_type !== 'NONE' && resultData.event_end_dt !== ''))
|
||||||
);
|
);
|
||||||
@@ -310,122 +209,115 @@ const BattleEventModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const itemGroups = [
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
row: 0,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'text',
|
||||||
|
key: 'group_id',
|
||||||
|
label: '그룹 ID',
|
||||||
|
disabled: !isView('group'),
|
||||||
|
width: '150px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 0,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'text',
|
||||||
|
key: 'event_name',
|
||||||
|
label: '이벤트명',
|
||||||
|
disabled: !isView('name'),
|
||||||
|
width: '250px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 1,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'date',
|
||||||
|
key: 'event_start_dt',
|
||||||
|
label: '시작일시',
|
||||||
|
disabled: !isView('start_dt'),
|
||||||
|
format: 'YYYY-MM-DD HH:mm',
|
||||||
|
width: '200px',
|
||||||
|
showTime: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 1,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'number',
|
||||||
|
key: 'event_operation_time',
|
||||||
|
label: '진행시간(분)',
|
||||||
|
disabled: !isView('operation_time'),
|
||||||
|
width: '100px',
|
||||||
|
min: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 3,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'select',
|
||||||
|
key: 'repeat_type',
|
||||||
|
label: '반복',
|
||||||
|
disabled: !isView('repeat'),
|
||||||
|
width: '150px',
|
||||||
|
options: battleRepeatType
|
||||||
|
},
|
||||||
|
...(resultData?.repeat_type !== 'NONE' ? [{
|
||||||
|
row: 3,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'date',
|
||||||
|
key: 'event_end_dt',
|
||||||
|
label: '종료일',
|
||||||
|
disabled: !isView('end_dt'),
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
width: '200px'
|
||||||
|
}] : []),
|
||||||
|
{
|
||||||
|
row: 4,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'select',
|
||||||
|
key: 'game_mode_id',
|
||||||
|
label: '게임 모드',
|
||||||
|
disabled: !isView('mode'),
|
||||||
|
width: '150px',
|
||||||
|
options: opGameMode
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 4,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'select',
|
||||||
|
key: 'hot_time',
|
||||||
|
label: '핫타임',
|
||||||
|
disabled: !isView('hot'),
|
||||||
|
width: '150px',
|
||||||
|
options: battleEventHotTime.map(value => ({
|
||||||
|
value: value,
|
||||||
|
name: `${value}배`
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal min="760px" $view={detailView}>
|
<Modal min="760px" $view={detailView}>
|
||||||
<Title $align="center">{isView('registry') ? "전투시스템 이벤트 등록" : isView('modify') ? "전투시스템 이벤트 수정" : "전투시스템 이벤트 상세"}</Title>
|
<Title $align="center">{isView('registry') ? "전투시스템 이벤트 등록" : isView('modify') ? "전투시스템 이벤트 수정" : "전투시스템 이벤트 상세"}</Title>
|
||||||
<MessageWrapper>
|
<DetailLayout
|
||||||
<FormRowGroup>
|
itemGroups={itemGroups}
|
||||||
<FormLabel>그룹 ID</FormLabel>
|
formData={resultData}
|
||||||
<FormInput
|
onChange={setResultData}
|
||||||
type="text"
|
disabled={false}
|
||||||
disabled={!isView('group')}
|
columnCount={4}
|
||||||
width='150px'
|
/>
|
||||||
value={resultData?.group_id}
|
|
||||||
onChange={e => setResultData({ ...resultData, group_id: e.target.value })}
|
|
||||||
/>
|
|
||||||
<FormLabel>이벤트명</FormLabel>
|
|
||||||
<FormInput
|
|
||||||
type="text"
|
|
||||||
disabled={!isView('name')}
|
|
||||||
width='300px'
|
|
||||||
value={resultData?.event_name}
|
|
||||||
onChange={e => setResultData({ ...resultData, event_name: e.target.value })}
|
|
||||||
/>
|
|
||||||
</FormRowGroup>
|
|
||||||
<FormRowGroup>
|
|
||||||
<SingleDatePicker
|
|
||||||
label="시작일자"
|
|
||||||
disabled={!isView('start_dt')}
|
|
||||||
dateLabel="시작 일자"
|
|
||||||
onDateChange={handleStartDateChange}
|
|
||||||
selectedDate={resultData?.event_start_dt}
|
|
||||||
/>
|
|
||||||
</FormRowGroup>
|
|
||||||
<FormRowGroup>
|
|
||||||
<SingleTimePicker
|
|
||||||
label="시작시간"
|
|
||||||
disabled={!isView('start_dt')}
|
|
||||||
selectedTime={resultData?.event_start_dt}
|
|
||||||
onTimeChange={handleStartTimeChange}
|
|
||||||
/>
|
|
||||||
<FormLabel>진행시간(분)</FormLabel>
|
|
||||||
<FormInput
|
|
||||||
type="number"
|
|
||||||
disabled={!isView('operation_time')}
|
|
||||||
width='100px'
|
|
||||||
min={10}
|
|
||||||
value={resultData?.event_operation_time}
|
|
||||||
onChange={e => setResultData({ ...resultData, event_operation_time: e.target.value })}
|
|
||||||
/>
|
|
||||||
</FormRowGroup>
|
|
||||||
<FormRowGroup>
|
|
||||||
<FormLabel>반복</FormLabel>
|
|
||||||
<SelectInput value={resultData?.repeat_type} onChange={e => setResultData({ ...resultData, repeat_type: e.target.value })} disabled={!isView('repeat')} width="150px">
|
|
||||||
{battleRepeatType.map((data, index) => (
|
|
||||||
<option key={index} value={data.value}>
|
|
||||||
{data.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
{resultData?.repeat_type !== 'NONE' &&
|
|
||||||
<SingleDatePicker
|
|
||||||
label="종료일자"
|
|
||||||
disabled={!isView('end_dt')}
|
|
||||||
dateLabel="종료 일자"
|
|
||||||
onDateChange={handleEndDateChange}
|
|
||||||
selectedDate={resultData?.event_end_dt}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</FormRowGroup>
|
|
||||||
{/*<FormRowGroup>*/}
|
|
||||||
{/* <FormLabel>라운드 시간</FormLabel>*/}
|
|
||||||
{/* <SelectInput value={resultData.config_id} onChange={handleConfigChange} disabled={!isView('config')} width="200px">*/}
|
|
||||||
{/* {configData && configData?.map((data, index) => (*/}
|
|
||||||
{/* <option key={index} value={data.id}>*/}
|
|
||||||
{/* {data.desc}({data.id})*/}
|
|
||||||
{/* </option>*/}
|
|
||||||
{/* ))}*/}
|
|
||||||
{/* </SelectInput>*/}
|
|
||||||
{/* <FormLabel>라운드 수</FormLabel>*/}
|
|
||||||
{/* <SelectInput value={resultData.round_count} onChange={e => setResultData({ ...resultData, round_count: e.target.value })} disabled={!isView('round')} width="100px">*/}
|
|
||||||
{/* {battleEventRoundCount.map((data, index) => (*/}
|
|
||||||
{/* <option key={index} value={data}>*/}
|
|
||||||
{/* {data}*/}
|
|
||||||
{/* </option>*/}
|
|
||||||
{/* ))}*/}
|
|
||||||
{/* </SelectInput>*/}
|
|
||||||
{/*</FormRowGroup>*/}
|
|
||||||
<FormRowGroup>
|
|
||||||
{/*<FormLabel>배정 포드</FormLabel>*/}
|
|
||||||
{/*<SelectInput value={resultData.reward_group_id} onChange={e => setResultData({ ...resultData, reward_group_id: e.target.value })} disabled={!isView('reward')} width="200px">*/}
|
|
||||||
{/* {rewardData && rewardData?.map((data, index) => (*/}
|
|
||||||
{/* <option key={index} value={data.group_id}>*/}
|
|
||||||
{/* {data.desc}({data.group_id})*/}
|
|
||||||
{/* </option>*/}
|
|
||||||
{/* ))}*/}
|
|
||||||
{/*</SelectInput>*/}
|
|
||||||
<FormLabel>게임 모드</FormLabel>
|
|
||||||
<SelectInput value={resultData.game_mode_id} onChange={e => setResultData({ ...resultData, game_mode_id: e.target.value })} disabled={!isView('mode')} width="200px">
|
|
||||||
{gameModeData && gameModeData?.map((data, index) => (
|
|
||||||
<option key={index} value={data.id}>
|
|
||||||
{data.desc}({data.id})
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
<FormLabel>핫타임</FormLabel>
|
|
||||||
<SelectInput value={resultData.hot_time} onChange={e => setResultData({ ...resultData, hot_time: e.target.value })} disabled={!isView('hot')} width="100px">
|
|
||||||
{battleEventHotTime.map((data, index) => (
|
|
||||||
<option key={index} value={data}>
|
|
||||||
{data}배
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
</FormRowGroup>
|
|
||||||
|
|
||||||
{!isView() && isNullValue && <SearchBarAlert $marginTop="25px" $align="right">{t('REQUIRED_VALUE_CHECK')}</SearchBarAlert>}
|
{!isView() && isNullValue && <SearchBarAlert $marginTop="25px" $align="right">{t('REQUIRED_VALUE_CHECK')}</SearchBarAlert>}
|
||||||
</MessageWrapper>
|
|
||||||
|
|
||||||
<BtnWrapper $gap="10px" $marginTop="10px">
|
<BtnWrapper $gap="10px" $marginTop="10px">
|
||||||
<FormStatusBar>
|
<FormStatusBar>
|
||||||
<FormStatusLabel>
|
<FormStatusLabel>
|
||||||
@@ -482,7 +374,7 @@ export const initData = {
|
|||||||
reward_group_id: 1,
|
reward_group_id: 1,
|
||||||
round_count: 1,
|
round_count: 1,
|
||||||
hot_time: 1,
|
hot_time: 1,
|
||||||
game_mode_id: 1,
|
game_mode_id: '',
|
||||||
event_start_dt: '',
|
event_start_dt: '',
|
||||||
event_end_dt: '',
|
event_end_dt: '',
|
||||||
event_operation_time: 10
|
event_operation_time: 10
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, useEffect, Fragment } from 'react';
|
import { useState, useEffect, Fragment } from 'react';
|
||||||
|
|
||||||
import { Title, SelectInput, BtnWrapper, TextInput, Label, InputLabel, Textarea, SearchBarAlert } from '../../styles/Components';
|
import { Input, Button as AntButton, Select, Alert, Space, Card, Row, Col } from 'antd';
|
||||||
|
import { Title, BtnWrapper } from '../../styles/Components';
|
||||||
import Button from '../common/button/Button';
|
import Button from '../common/button/Button';
|
||||||
import Modal from '../common/modal/Modal';
|
import Modal from '../common/modal/Modal';
|
||||||
import { EventIsItem, EventModify } from '../../apis';
|
import { EventIsItem, EventModify } from '../../apis';
|
||||||
@@ -10,16 +11,13 @@ import { useRecoilValue } from 'recoil';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { authType, benItems, commonStatus, currencyItemCode } from '../../assets/data';
|
import { authType, benItems, commonStatus, currencyItemCode } from '../../assets/data';
|
||||||
import {
|
import {
|
||||||
AppendRegistBox, AppendRegistTable, AreaBtnClose,
|
DetailRegistInfo, DetailState
|
||||||
BtnDelete, DetailInputItem, DetailInputRow,
|
|
||||||
DetailModalWrapper, RegistGroup, DetailRegistInfo, DetailState,
|
|
||||||
Item, ItemList, LangArea
|
|
||||||
} from '../../styles/ModuleComponents';
|
} from '../../styles/ModuleComponents';
|
||||||
import { convertKTC, combineDateTime, timeDiffMinute, convertKTCDate } from '../../utils';
|
import { convertKTC, timeDiffMinute, convertKTCDate } from '../../utils';
|
||||||
import DateTimeInput from '../common/input/DateTimeInput';
|
|
||||||
import { useLoading } from '../../context/LoadingProvider';
|
import { useLoading } from '../../context/LoadingProvider';
|
||||||
import { useAlert } from '../../context/AlertProvider';
|
import { useAlert } from '../../context/AlertProvider';
|
||||||
import { alertTypes } from '../../assets/data/types';
|
import { alertTypes } from '../../assets/data/types';
|
||||||
|
import { DetailLayout } from '../common';
|
||||||
|
|
||||||
const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData }) => {
|
const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData }) => {
|
||||||
const userInfo = useRecoilValue(authList);
|
const userInfo = useRecoilValue(authList);
|
||||||
@@ -31,21 +29,14 @@ const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData
|
|||||||
const id = content && content.id;
|
const id = content && content.id;
|
||||||
const updateAuth = userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.eventUpdate);
|
const updateAuth = userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.eventUpdate);
|
||||||
|
|
||||||
const [time, setTime] = useState({
|
const [activeLanguage, setActiveLanguage] = useState('KO');
|
||||||
start_hour: '00',
|
|
||||||
start_min: '00',
|
|
||||||
end_hour: '00',
|
|
||||||
end_min: '00',
|
|
||||||
}); //시간 정보
|
|
||||||
|
|
||||||
const [item, setItem] = useState('');
|
const [item, setItem] = useState('');
|
||||||
const [itemCount, setItemCount] = useState('');
|
const [itemCount, setItemCount] = useState(1);
|
||||||
const [resource, setResource] = useState('19010001');
|
const [resource, setResource] = useState('19010001');
|
||||||
const [resourceCount, setResourceCount] = useState('');
|
const [resourceCount, setResourceCount] = useState(1);
|
||||||
|
|
||||||
const [resultData, setResultData] = useState({});
|
const [resultData, setResultData] = useState({});
|
||||||
|
|
||||||
const [isNullValue, setIsNullValue] = useState(false);
|
|
||||||
// 과거 판단
|
// 과거 판단
|
||||||
const [isPast, setIsPast] = useState(false);
|
const [isPast, setIsPast] = useState(false);
|
||||||
const [isChanged, setIsChanged] = useState(false);
|
const [isChanged, setIsChanged] = useState(false);
|
||||||
@@ -65,13 +56,8 @@ const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData
|
|||||||
event_type: content.event_type,
|
event_type: content.event_type,
|
||||||
mail_list: content.mail_list,
|
mail_list: content.mail_list,
|
||||||
item_list: content.item_list,
|
item_list: content.item_list,
|
||||||
});
|
status: content.status,
|
||||||
|
delete_desc: content.delete_desc
|
||||||
setTime({ ...time,
|
|
||||||
start_hour: String(start_dt_KTC.getHours()).padStart(2, '0'),
|
|
||||||
start_min: String(start_dt_KTC.getMinutes()).padStart(2, '0'),
|
|
||||||
end_hour: String(end_dt_KTC.getHours()).padStart(2, '0'),
|
|
||||||
end_min: String(end_dt_KTC.getMinutes()).padStart(2, '0')
|
|
||||||
});
|
});
|
||||||
|
|
||||||
start_dt_KTC < (new Date) ? setIsPast(true) : setIsPast(false);
|
start_dt_KTC < (new Date) ? setIsPast(true) : setIsPast(false);
|
||||||
@@ -90,29 +76,97 @@ const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData
|
|||||||
}
|
}
|
||||||
}, [updateAuth, isPast]);
|
}, [updateAuth, isPast]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (conditionCheck()) {
|
|
||||||
setIsNullValue(false);
|
|
||||||
} else {
|
|
||||||
setIsNullValue(true);
|
|
||||||
}
|
|
||||||
}, [resultData]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setItemCheckMsg('');
|
setItemCheckMsg('');
|
||||||
}, [item]);
|
}, [item]);
|
||||||
|
|
||||||
// 아이템 수량 숫자 체크
|
const getLanguageTabItems = () => {
|
||||||
const handleItemCount = e => {
|
return resultData.mail_list?.map(mail => ({
|
||||||
if (e.target.value === '0' || e.target.value === '-0') {
|
key: mail.language,
|
||||||
setItemCount('1');
|
label: mail.language,
|
||||||
e.target.value = '1';
|
children: (
|
||||||
} else if (e.target.value < 0) {
|
<div style={{ padding: '10px', minHeight: '400px', height: 'auto' }}>
|
||||||
let plusNum = Math.abs(e.target.value);
|
<Row gutter={[16, 24]}>
|
||||||
setItemCount(plusNum);
|
<Col span={24}>
|
||||||
} else {
|
<div>
|
||||||
setItemCount(e.target.value);
|
<label style={{
|
||||||
|
display: 'block',
|
||||||
|
marginBottom: '8px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: 'rgba(0, 0, 0, 0.85)',
|
||||||
|
fontSize: '14px'
|
||||||
|
}}>
|
||||||
|
제목 <span style={{ color: '#ff4d4f' }}>*</span>
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
value={mail.title || ''}
|
||||||
|
placeholder="우편 제목을 입력하세요"
|
||||||
|
maxLength={30}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
onChange={(e) => updateMailData(mail.language, 'title', e.target.value.trimStart())}
|
||||||
|
showCount
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<div>
|
||||||
|
<label style={{
|
||||||
|
display: 'block',
|
||||||
|
marginBottom: '8px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: 'rgba(0, 0, 0, 0.85)',
|
||||||
|
fontSize: '14px'
|
||||||
|
}}>
|
||||||
|
내용 <span style={{ color: '#ff4d4f' }}>*</span>
|
||||||
|
</label>
|
||||||
|
<Input.TextArea
|
||||||
|
value={mail.content || ''}
|
||||||
|
placeholder="우편 내용을 입력하세요"
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
rows={8}
|
||||||
|
maxLength={2000}
|
||||||
|
showCount
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 2000) return;
|
||||||
|
updateMailData(mail.language, 'content', e.target.value.trimStart());
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
resize: 'vertical',
|
||||||
|
minHeight: '200px',
|
||||||
|
maxHeight: '400px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
closable: resultData.mail_list?.length > 1 && !isReadOnly, // 마지막 하나가 아니고 읽기전용이 아닐 때만 삭제 가능
|
||||||
|
})) || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateMailData = (language, field, value) => {
|
||||||
|
const updatedMailList = resultData.mail_list.map(mail =>
|
||||||
|
mail.language === language
|
||||||
|
? { ...mail, [field]: value }
|
||||||
|
: mail
|
||||||
|
);
|
||||||
|
setResultData({ ...resultData, mail_list: updatedMailList });
|
||||||
|
setIsChanged(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabClose = (targetKey) => {
|
||||||
|
if (resultData.mail_list.length <= 1) return;
|
||||||
|
|
||||||
|
const filterList = resultData.mail_list.filter(el => el.language !== targetKey);
|
||||||
|
setResultData({ ...resultData, mail_list: filterList });
|
||||||
|
|
||||||
|
// 삭제된 탭이 현재 활성 탭이었다면 첫 번째 탭으로 변경
|
||||||
|
if (activeLanguage === targetKey) {
|
||||||
|
setActiveLanguage(filterList[0]?.language || 'KO');
|
||||||
}
|
}
|
||||||
|
setIsChanged(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 아이템 추가
|
// 아이템 추가
|
||||||
@@ -152,19 +206,6 @@ const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData
|
|||||||
setResultData({ ...resultData, item_list: filterList });
|
setResultData({ ...resultData, item_list: filterList });
|
||||||
};
|
};
|
||||||
|
|
||||||
// 자원 수량 숫자 체크
|
|
||||||
const handleResourceCount = e => {
|
|
||||||
if (e.target.value === '0' || e.target.value === '-0') {
|
|
||||||
setResourceCount('1');
|
|
||||||
e.target.value = '1';
|
|
||||||
} else if (e.target.value < 0) {
|
|
||||||
let plusNum = Math.abs(e.target.value);
|
|
||||||
setResourceCount(plusNum);
|
|
||||||
} else {
|
|
||||||
setResourceCount(e.target.value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 자원 추가
|
// 자원 추가
|
||||||
const handleResourceList = (e) => {
|
const handleResourceList = (e) => {
|
||||||
if(resource.length === 0 || resourceCount.length === 0) return;
|
if(resource.length === 0 || resourceCount.length === 0) return;
|
||||||
@@ -186,45 +227,9 @@ const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData
|
|||||||
setResourceCount('');
|
setResourceCount('');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 입력창 삭제
|
|
||||||
const onLangDelete = language => {
|
|
||||||
let filterList = resultData.mail_list && resultData.mail_list.filter(el => el.language !== language);
|
|
||||||
|
|
||||||
if (filterList.length === 1) setBtnValidation(true);
|
|
||||||
|
|
||||||
setIsChanged(true);
|
|
||||||
setResultData({ ...resultData, mail_list: filterList });
|
|
||||||
};
|
|
||||||
|
|
||||||
// 날짜 처리
|
|
||||||
const handleDateChange = (data, type) => {
|
|
||||||
const date = new Date(data);
|
|
||||||
setResultData({
|
|
||||||
...resultData,
|
|
||||||
[`${type}_dt`]: combineDateTime(date, time[`${type}_hour`], time[`${type}_min`]),
|
|
||||||
});
|
|
||||||
setIsChanged(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 시간 처리
|
|
||||||
const handleTimeChange = (e, type) => {
|
|
||||||
const { id, value } = e.target;
|
|
||||||
const newTime = { ...time, [`${type}_${id}`]: value };
|
|
||||||
setTime(newTime);
|
|
||||||
|
|
||||||
const date = resultData[`${type}_dt`] ? new Date(resultData[`${type}_dt`]) : new Date();
|
|
||||||
|
|
||||||
setResultData({
|
|
||||||
...resultData,
|
|
||||||
[`${type}_dt`]: combineDateTime(date, newTime[`${type}_hour`], newTime[`${type}_min`]),
|
|
||||||
});
|
|
||||||
setIsChanged(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 확인 버튼 후 다 초기화
|
// 확인 버튼 후 다 초기화
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setBtnValidation(false);
|
setBtnValidation(false);
|
||||||
setIsNullValue(false);
|
|
||||||
setIsChanged(false);
|
setIsChanged(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -281,6 +286,197 @@ const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 아이템 목록 렌더링 컴포넌트
|
||||||
|
const renderItemList = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{resultData.item_list && resultData.item_list.length > 0 && (
|
||||||
|
<Space wrap>
|
||||||
|
{resultData.item_list.map((data, index) => (
|
||||||
|
<Card
|
||||||
|
key={index}
|
||||||
|
title={data.item_name}
|
||||||
|
size="small"
|
||||||
|
extra={
|
||||||
|
!isReadOnly && (
|
||||||
|
<AntButton
|
||||||
|
type="text"
|
||||||
|
danger
|
||||||
|
size="small"
|
||||||
|
onClick={() => onItemRemove(index)}
|
||||||
|
>
|
||||||
|
X
|
||||||
|
</AntButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
style={{ minWidth: '150px' }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div>{data.item}</div>
|
||||||
|
<div>수량: {data.item_cnt}</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 아이템 추가 컴포넌트
|
||||||
|
const renderItemAdd = () => {
|
||||||
|
return (
|
||||||
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
|
<Input
|
||||||
|
placeholder="Item Meta id 입력"
|
||||||
|
value={item}
|
||||||
|
onChange={(e) => setItem(e.target.value.trimStart())}
|
||||||
|
disabled={isReadOnly}
|
||||||
|
style={{ width: '200px' }}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder="수량"
|
||||||
|
value={itemCount}
|
||||||
|
onChange={(e) => setItemCount(e.target.value)}
|
||||||
|
disabled={isReadOnly}
|
||||||
|
style={{ width: '120px' }}
|
||||||
|
min={1}
|
||||||
|
/>
|
||||||
|
<AntButton
|
||||||
|
type="primary"
|
||||||
|
onClick={handleItemList}
|
||||||
|
disabled={itemCount.length === 0 || item.length === 0 || isReadOnly}
|
||||||
|
>
|
||||||
|
추가
|
||||||
|
</AntButton>
|
||||||
|
</Space.Compact>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 자원 추가 컴포넌트
|
||||||
|
const renderResourceAdd = () => {
|
||||||
|
return (
|
||||||
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
|
<Select
|
||||||
|
value={resource}
|
||||||
|
onChange={setResource}
|
||||||
|
disabled={isReadOnly}
|
||||||
|
style={{ width: '200px' }}
|
||||||
|
placeholder="자원 선택"
|
||||||
|
>
|
||||||
|
{currencyItemCode.map((data, index) => (
|
||||||
|
<Select.Option key={index} value={data.value}>
|
||||||
|
{data.name}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder="수량"
|
||||||
|
value={resourceCount}
|
||||||
|
disabled={isReadOnly}
|
||||||
|
onChange={(e) => setResourceCount(e.target.value)}
|
||||||
|
style={{ width: '120px' }}
|
||||||
|
min={1}
|
||||||
|
/>
|
||||||
|
<AntButton
|
||||||
|
type="primary"
|
||||||
|
onClick={handleResourceList}
|
||||||
|
disabled={resourceCount.length === 0 || resource.length === 0 || isReadOnly}
|
||||||
|
>
|
||||||
|
추가
|
||||||
|
</AntButton>
|
||||||
|
</Space.Compact>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemGroups = [
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
row: 0,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'dateRange',
|
||||||
|
keys: {
|
||||||
|
start: 'start_dt',
|
||||||
|
end: 'end_dt'
|
||||||
|
},
|
||||||
|
label: '이벤트 기간',
|
||||||
|
disabled: isReadOnly,
|
||||||
|
format: 'YYYY-MM-DD HH:mm',
|
||||||
|
showTime: true,
|
||||||
|
startLabel: '시작 일시',
|
||||||
|
endLabel: '종료 일시'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 0,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 1,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'status',
|
||||||
|
label: '이벤트 상태',
|
||||||
|
render: () => detailState(resultData.status)
|
||||||
|
},
|
||||||
|
...(resultData.status === commonStatus.delete ? [{
|
||||||
|
row: 0,
|
||||||
|
col: 3,
|
||||||
|
colSpan: 1,
|
||||||
|
type: 'display',
|
||||||
|
key: 'delete_desc',
|
||||||
|
label: '삭제 사유',
|
||||||
|
value: resultData.delete_desc || ''
|
||||||
|
}] : [{
|
||||||
|
row: 0,
|
||||||
|
col: 3,
|
||||||
|
colSpan: 1,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'empty_space',
|
||||||
|
label: '',
|
||||||
|
render: () => <div></div>
|
||||||
|
}]),
|
||||||
|
{
|
||||||
|
row: 1,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'tab',
|
||||||
|
key: 'language_tabs',
|
||||||
|
tabItems: getLanguageTabItems(),
|
||||||
|
activeKey: activeLanguage,
|
||||||
|
onTabChange: setActiveLanguage,
|
||||||
|
onTabClose: handleTabClose
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 2,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'item_add',
|
||||||
|
label: '아이템 추가',
|
||||||
|
render: renderItemAdd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 3,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'resource_add',
|
||||||
|
label: '자원 추가',
|
||||||
|
render: renderResourceAdd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 4,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'item_list',
|
||||||
|
render: renderItemList
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal min="960px" $view={detailView}>
|
<Modal min="960px" $view={detailView}>
|
||||||
@@ -297,201 +493,22 @@ const EventDetailModal = ({ detailView, handleDetailView, content, setDetailData
|
|||||||
)}
|
)}
|
||||||
</DetailRegistInfo>
|
</DetailRegistInfo>
|
||||||
}
|
}
|
||||||
<DetailModalWrapper>
|
|
||||||
{content &&
|
|
||||||
<RegistGroup>
|
|
||||||
<DetailInputRow>
|
|
||||||
<DateTimeInput
|
|
||||||
title="이벤트 기간"
|
|
||||||
dateName="시작 일자"
|
|
||||||
selectedDate={convertKTCDate(content.start_dt)}
|
|
||||||
handleSelectedDate={data => handleDateChange(data, 'start')}
|
|
||||||
onChange={e => handleTimeChange(e, 'start')}
|
|
||||||
|
|
||||||
/>
|
<DetailLayout
|
||||||
<DateTimeInput
|
itemGroups={itemGroups}
|
||||||
dateName="종료 일자"
|
formData={resultData}
|
||||||
selectedDate={convertKTCDate(content.end_dt)}
|
onChange={setResultData}
|
||||||
handleSelectedDate={data => handleDateChange(data, 'end')}
|
disabled={false}
|
||||||
onChange={e => handleTimeChange(e, 'end')}
|
columnCount={4}
|
||||||
/>
|
/>
|
||||||
</DetailInputRow>
|
|
||||||
<DetailInputRow>
|
|
||||||
<DetailInputItem>
|
|
||||||
<InputLabel>이벤트 상태</InputLabel>
|
|
||||||
<div>{detailState(content.status)}</div>
|
|
||||||
</DetailInputItem>
|
|
||||||
{content.status === commonStatus.delete &&
|
|
||||||
<DetailInputItem>
|
|
||||||
<InputLabel>삭제 사유</InputLabel>
|
|
||||||
<div>{content.delete_desc}</div>
|
|
||||||
</DetailInputItem>
|
|
||||||
}
|
|
||||||
</DetailInputRow>
|
|
||||||
|
|
||||||
</RegistGroup>
|
{itemCheckMsg && (
|
||||||
}
|
<Alert
|
||||||
{resultData.mail_list &&
|
message={itemCheckMsg}
|
||||||
resultData.mail_list.map(data => {
|
type="error"
|
||||||
return (
|
style={{ marginTop: '8px', width: '300px' }}
|
||||||
<Fragment key={data.language}>
|
/>
|
||||||
<AppendRegistBox>
|
)}
|
||||||
<LangArea>
|
|
||||||
언어 : {data.language}
|
|
||||||
{btnValidation === false && !isReadOnly ? (
|
|
||||||
<AreaBtnClose
|
|
||||||
onClick={e => {
|
|
||||||
e.preventDefault();
|
|
||||||
onLangDelete(data.language);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<AreaBtnClose opacity="10%" />
|
|
||||||
)}
|
|
||||||
</LangArea>
|
|
||||||
<AppendRegistTable>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th width="120">
|
|
||||||
<Label>제목</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<DetailInputItem>
|
|
||||||
<TextInput
|
|
||||||
placeholder="우편 제목 입력"
|
|
||||||
maxLength="30"
|
|
||||||
id={data.language}
|
|
||||||
value={data.title}
|
|
||||||
readOnly={isReadOnly}
|
|
||||||
onChange={e => {
|
|
||||||
let list = [...resultData.mail_list];
|
|
||||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
|
||||||
list[findIndex].title = e.target.value.trimStart();
|
|
||||||
|
|
||||||
setResultData({ ...resultData, mail_list: list });
|
|
||||||
setIsChanged(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</DetailInputItem>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<Label>내용</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<Textarea
|
|
||||||
value={data.content}
|
|
||||||
readOnly={isReadOnly}
|
|
||||||
id={data.language}
|
|
||||||
onChange={e => {
|
|
||||||
if (e.target.value.length > 2000) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let list = [...resultData.mail_list];
|
|
||||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
|
||||||
list[findIndex].content = e.target.value.trimStart();
|
|
||||||
|
|
||||||
setResultData({ ...resultData, mail_list: list });
|
|
||||||
setIsChanged(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</AppendRegistTable>
|
|
||||||
</AppendRegistBox>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<AppendRegistBox>
|
|
||||||
<AppendRegistTable>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th width="120">
|
|
||||||
<Label>아이템 첨부</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<DetailInputItem>
|
|
||||||
<TextInput
|
|
||||||
placeholder="Item Meta id 입력"
|
|
||||||
value={item}
|
|
||||||
onChange={e => {
|
|
||||||
let list = [];
|
|
||||||
list = e.target.value.trimStart();
|
|
||||||
setItem(list);
|
|
||||||
}}
|
|
||||||
disabled={isReadOnly}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder="수량"
|
|
||||||
value={itemCount}
|
|
||||||
type="number"
|
|
||||||
onChange={e => handleItemCount(e)}
|
|
||||||
width="90px"
|
|
||||||
disabled={isReadOnly}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
text="추가"
|
|
||||||
theme={itemCount.length === 0 || item.length === 0 ? 'disable' : 'search'}
|
|
||||||
handleClick={handleItemList}
|
|
||||||
/>
|
|
||||||
{itemCheckMsg && <SearchBarAlert>{itemCheckMsg}</SearchBarAlert>}
|
|
||||||
</DetailInputItem>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th width="120">
|
|
||||||
<Label>자원 첨부</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<DetailInputItem>
|
|
||||||
<SelectInput onChange={e => setResource(e.target.value)} value={resource} disabled={isReadOnly}>
|
|
||||||
{currencyItemCode.map((data, index) => (
|
|
||||||
<option key={index} value={data.value}>
|
|
||||||
{data.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
<TextInput
|
|
||||||
placeholder="수량"
|
|
||||||
type="number"
|
|
||||||
value={resourceCount}
|
|
||||||
disabled={isReadOnly}
|
|
||||||
onChange={e => handleResourceCount(e)}
|
|
||||||
width="200px"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
text="추가"
|
|
||||||
theme={resourceCount.length === 0 || resource.length === 0 ? 'disable' : 'search'}
|
|
||||||
handleClick={handleResourceList}
|
|
||||||
width="100px"
|
|
||||||
height="35px"
|
|
||||||
errorMessage={isReadOnly} />
|
|
||||||
</DetailInputItem>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{resultData.item_list && (
|
|
||||||
<ItemList>
|
|
||||||
{resultData.item_list.map((data, index) => {
|
|
||||||
return (
|
|
||||||
<Item key={index}>
|
|
||||||
<span>
|
|
||||||
{data.item_name}[{data.item}] ({data.item_cnt})
|
|
||||||
</span>
|
|
||||||
{!isReadOnly && <BtnDelete onClick={() => onItemRemove(index)}></BtnDelete>}
|
|
||||||
</Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ItemList>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</AppendRegistTable>
|
|
||||||
</AppendRegistBox>
|
|
||||||
</DetailModalWrapper>
|
|
||||||
<BtnWrapper $justify="flex-end" $gap="10px" $paddingTop="20px">
|
<BtnWrapper $justify="flex-end" $gap="10px" $paddingTop="20px">
|
||||||
<Button
|
<Button
|
||||||
text="확인"
|
text="확인"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, Fragment, useEffect } from 'react';
|
import React, { useState, Fragment, useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Button from '../common/button/Button';
|
import Button from '../common/button/Button';
|
||||||
import Loading from '../common/Loading';
|
import Loading from '../common/Loading';
|
||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
NoticeInputItem2, BoxWrapper, FormStatusBar, FormStatusLabel, FormStatusWarning, FormButtonContainer,
|
NoticeInputItem2, BoxWrapper, FormStatusBar, FormStatusLabel, FormStatusWarning, FormButtonContainer,
|
||||||
} from '../../styles/ModuleComponents';
|
} from '../../styles/ModuleComponents';
|
||||||
import { modalTypes } from '../../assets/data';
|
import { modalTypes } from '../../assets/data';
|
||||||
import {DynamicModal, Modal, DateTimeRangePicker} from '../common';
|
import { DynamicModal, Modal, DateTimeRangePicker, DetailLayout } from '../common';
|
||||||
import { LandAuctionModify, LandAuctionSingleRegist } from '../../apis';
|
import { LandAuctionModify, LandAuctionSingleRegist } from '../../apis';
|
||||||
import {
|
import {
|
||||||
AUCTION_MIN_MINUTE_TIME,
|
AUCTION_MIN_MINUTE_TIME,
|
||||||
@@ -36,6 +36,7 @@ import { convertKTCDate } from '../../utils';
|
|||||||
import { msToMinutes } from '../../utils/date';
|
import { msToMinutes } from '../../utils/date';
|
||||||
import { useAlert } from '../../context/AlertProvider';
|
import { useAlert } from '../../context/AlertProvider';
|
||||||
import { alertTypes } from '../../assets/data/types';
|
import { alertTypes } from '../../assets/data/types';
|
||||||
|
import { battleEventHotTime, battleRepeatType } from '../../assets/data/options';
|
||||||
|
|
||||||
const LandAuctionModal = ({ modalType, detailView, handleDetailView, content, setDetailData, landData, buildingData }) => {
|
const LandAuctionModal = ({ modalType, detailView, handleDetailView, content, setDetailData, landData, buildingData }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -62,7 +63,6 @@ const LandAuctionModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
currency_type: content.currency_type,
|
currency_type: content.currency_type,
|
||||||
start_price: content.start_price,
|
start_price: content.start_price,
|
||||||
resv_start_dt: convertKTCDate(content.resv_start_dt),
|
resv_start_dt: convertKTCDate(content.resv_start_dt),
|
||||||
resv_end_dt: convertKTCDate(content.resv_end_dt),
|
|
||||||
auction_start_dt: convertKTCDate(content.auction_start_dt),
|
auction_start_dt: convertKTCDate(content.auction_start_dt),
|
||||||
auction_end_dt: convertKTCDate(content.auction_end_dt),
|
auction_end_dt: convertKTCDate(content.auction_end_dt),
|
||||||
});
|
});
|
||||||
@@ -85,52 +85,26 @@ const LandAuctionModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
}
|
}
|
||||||
}, [resetDateTime]);
|
}, [resetDateTime]);
|
||||||
|
|
||||||
// 입력 수량 처리
|
const opLand = useMemo(() => {
|
||||||
const handleCount = e => {
|
return landData?.map(item => ({
|
||||||
const regex = /^\d*\.?\d{0,2}$/;
|
value: item.id,
|
||||||
if (!regex.test(e.target.value) && e.target.value !== '-') {
|
name: `${item.name}(${item.id})`
|
||||||
return;
|
})) || [];
|
||||||
}
|
}, [landData]);
|
||||||
|
|
||||||
let count = 0;
|
const handleLand = (value, key, currentFormData) => {
|
||||||
if (e.target.value === '-0') {
|
let land_id = value;
|
||||||
count = 1;
|
|
||||||
} else if (e.target.value < 0) {
|
|
||||||
let plusNum = Math.abs(e.target.value);
|
|
||||||
count = plusNum;
|
|
||||||
} else{
|
|
||||||
count = e.target.value;
|
|
||||||
}
|
|
||||||
setResultData((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
start_price: count,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleReservationChange = {
|
|
||||||
start: (date) => {
|
|
||||||
setResultData(prev => ({ ...prev, resv_start_dt: date }));
|
|
||||||
},
|
|
||||||
end: (date) => {
|
|
||||||
setResultData(prev => ({ ...prev, resv_end_dt: date }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAuctionChange = {
|
|
||||||
start: (date) => {
|
|
||||||
setResultData(prev => ({ ...prev, auction_start_dt: date }));
|
|
||||||
},
|
|
||||||
end: (date) => {
|
|
||||||
setResultData(prev => ({ ...prev, auction_end_dt: date }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLand = e => {
|
|
||||||
const land_id = e.target.value;
|
|
||||||
const land = landData.find(land => land.id === parseInt(land_id));
|
const land = landData.find(land => land.id === parseInt(land_id));
|
||||||
const instance = buildingData.find(building => building.id === parseInt(land.buildingId))?.socket;
|
const instance = buildingData.find(building => building.id === parseInt(land.buildingId))?.socket;
|
||||||
setSelectLand(land);
|
setSelectLand(land);
|
||||||
setResultData({ ...resultData, land_id: land_id, land_name: land.name, land_size: land.size, land_socket: instance });
|
const updatedData = {
|
||||||
|
...currentFormData,
|
||||||
|
land_name: land.name,
|
||||||
|
land_size: land.size,
|
||||||
|
land_socket: instance
|
||||||
|
};
|
||||||
|
setResultData(updatedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
@@ -236,7 +210,7 @@ const LandAuctionModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
|
|
||||||
const isView = (label) => {
|
const isView = (label) => {
|
||||||
switch (label) {
|
switch (label) {
|
||||||
case "recv":
|
case "resv":
|
||||||
return modalType === TYPE_REGISTRY || (modalType === TYPE_MODIFY && content?.status === landAuctionStatusType.wait);
|
return modalType === TYPE_REGISTRY || (modalType === TYPE_MODIFY && content?.status === landAuctionStatusType.wait);
|
||||||
case "auction":
|
case "auction":
|
||||||
case "price":
|
case "price":
|
||||||
@@ -256,95 +230,117 @@ const LandAuctionModal = ({ modalType, detailView, handleDetailView, content, se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const itemGroups = [
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
row: 0,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'select',
|
||||||
|
key: 'land_id',
|
||||||
|
label: '랜드선택',
|
||||||
|
disabled: !isView('registry'),
|
||||||
|
width: '400px',
|
||||||
|
options: opLand,
|
||||||
|
handler: handleLand
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 1,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'display',
|
||||||
|
key: 'land_name',
|
||||||
|
label: '랜드 이름',
|
||||||
|
width: '400px',
|
||||||
|
placeholder: '랜드를 선택하세요'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 2,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'display',
|
||||||
|
key: 'land_size',
|
||||||
|
label: '랜드 크기',
|
||||||
|
placeholder: '랜드를 선택하세요',
|
||||||
|
width: '200px'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 2,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'display',
|
||||||
|
key: 'land_socket',
|
||||||
|
label: '인스턴스 수',
|
||||||
|
placeholder: '랜드를 선택하세요',
|
||||||
|
width: '200px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 3,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'select',
|
||||||
|
key: 'currency_type',
|
||||||
|
label: '입찰재화',
|
||||||
|
disabled: true,
|
||||||
|
width: '200px',
|
||||||
|
options: CurrencyType
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 3,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'number',
|
||||||
|
key: 'start_price',
|
||||||
|
label: '입찰시작가',
|
||||||
|
disabled: !isView('price'),
|
||||||
|
width: '200px',
|
||||||
|
min: 0,
|
||||||
|
step: 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 4,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'date',
|
||||||
|
key: 'resv_start_dt',
|
||||||
|
label: '예약시작일',
|
||||||
|
disabled: !isView('resv'),
|
||||||
|
width: '200px',
|
||||||
|
format: 'YYYY-MM-DD HH:mm',
|
||||||
|
showTime: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 5,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'dateRange',
|
||||||
|
keys: {
|
||||||
|
start: 'auction_start_dt',
|
||||||
|
end: 'auction_end_dt'
|
||||||
|
},
|
||||||
|
label: '경매기간',
|
||||||
|
disabled: !isView('auction'),
|
||||||
|
width: '400px',
|
||||||
|
format: 'YYYY-MM-DD HH:mm',
|
||||||
|
showTime: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal min="760px" $view={detailView}>
|
<Modal min="760px" $view={detailView}>
|
||||||
<Title $align="center">{isView('registry') ? "랜드 경매 등록" : isView('modify') ? "랜드 경매 수정" : "랜드 경매 상세"}</Title>
|
<Title $align="center">{isView('registry') ? "랜드 경매 등록" : isView('modify') ? "랜드 경매 수정" : "랜드 경매 상세"}</Title>
|
||||||
<MessageWrapper>
|
<DetailLayout
|
||||||
<FormRowGroup>
|
itemGroups={itemGroups}
|
||||||
<FormLabel>랜드선택</FormLabel>
|
formData={resultData}
|
||||||
<SelectInput value={resultData.land_id} onChange={e => handleLand(e)} disabled={!isView('registry')} width="400px">
|
onChange={setResultData}
|
||||||
{landData && landData.map((data, index) => (
|
disabled={false}
|
||||||
<option key={index} value={data.id}>
|
columnCount={4}
|
||||||
{data.name}({data.id})
|
/>
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
</FormRowGroup>
|
|
||||||
<FormRowGroup>
|
|
||||||
<FormLabel>랜드 이름</FormLabel>
|
|
||||||
<FormInput
|
|
||||||
type="text"
|
|
||||||
disabled={true}
|
|
||||||
width='400px'
|
|
||||||
value={resultData?.land_name}
|
|
||||||
/>
|
|
||||||
</FormRowGroup>
|
|
||||||
<FormRowGroup>
|
|
||||||
<FormLabel>랜드 크기</FormLabel>
|
|
||||||
<FormInput
|
|
||||||
type="text"
|
|
||||||
disabled={true}
|
|
||||||
width='200px'
|
|
||||||
value={resultData?.land_size}
|
|
||||||
/>
|
|
||||||
<FormLabel>인스턴스 수</FormLabel>
|
|
||||||
<FormInput
|
|
||||||
type="text"
|
|
||||||
disabled={true}
|
|
||||||
width='200px'
|
|
||||||
value={resultData?.land_socket}
|
|
||||||
/>
|
|
||||||
</FormRowGroup>
|
|
||||||
|
|
||||||
<FormRowGroup>
|
|
||||||
<FormLabel>입찰 재화</FormLabel>
|
|
||||||
<SelectInput value={resultData.currency_type} width='200px' disabled={true} >
|
|
||||||
{CurrencyType.map((data, index) => (
|
|
||||||
<option key={index} value={data.value}>
|
|
||||||
{data.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
<FormLabel>입찰시작가</FormLabel>
|
|
||||||
<FormInput
|
|
||||||
type="number"
|
|
||||||
name="price"
|
|
||||||
value={resultData.start_price}
|
|
||||||
step={"0.01"}
|
|
||||||
min={0}
|
|
||||||
width='200px'
|
|
||||||
disabled={!isView('price')}
|
|
||||||
onChange={e => handleCount(e)}
|
|
||||||
/>
|
|
||||||
</FormRowGroup>
|
|
||||||
<DateTimeRangePicker
|
|
||||||
label="예약기간"
|
|
||||||
startDate={resultData.resv_start_dt}
|
|
||||||
endDate={resultData.resv_end_dt}
|
|
||||||
onStartDateChange={handleReservationChange.start}
|
|
||||||
onEndDateChange={handleReservationChange.end}
|
|
||||||
pastDate={new Date()}
|
|
||||||
disabled={!isView('recv')}
|
|
||||||
startLabel="시작 일자"
|
|
||||||
endLabel="종료 일자"
|
|
||||||
reset={resetDateTime}
|
|
||||||
/>
|
|
||||||
<DateTimeRangePicker
|
|
||||||
label="경매기간"
|
|
||||||
startDate={resultData.auction_start_dt}
|
|
||||||
endDate={resultData.auction_end_dt}
|
|
||||||
onStartDateChange={handleAuctionChange.start}
|
|
||||||
onEndDateChange={handleAuctionChange.end}
|
|
||||||
pastDate={new Date()}
|
|
||||||
disabled={!isView('auction')}
|
|
||||||
startLabel="시작 일자"
|
|
||||||
endLabel="종료 일자"
|
|
||||||
reset={resetDateTime}
|
|
||||||
/>
|
|
||||||
{!isView() && isNullValue && <SearchBarAlert $marginTop="25px" $align="right">{t('REQUIRED_VALUE_CHECK')}</SearchBarAlert>}
|
{!isView() && isNullValue && <SearchBarAlert $marginTop="25px" $align="right">{t('REQUIRED_VALUE_CHECK')}</SearchBarAlert>}
|
||||||
</MessageWrapper>
|
|
||||||
|
|
||||||
<BtnWrapper $gap="10px" $marginTop="10px">
|
<BtnWrapper $gap="10px" $marginTop="10px">
|
||||||
<FormStatusBar>
|
<FormStatusBar>
|
||||||
<FormStatusLabel>
|
<FormStatusLabel>
|
||||||
@@ -401,7 +397,6 @@ export const initData = {
|
|||||||
currency_type: 'Calium',
|
currency_type: 'Calium',
|
||||||
start_price: 0,
|
start_price: 0,
|
||||||
resv_start_dt: '',
|
resv_start_dt: '',
|
||||||
resv_end_dt: '',
|
|
||||||
auction_start_dt: '',
|
auction_start_dt: '',
|
||||||
auction_end_dt: ''
|
auction_end_dt: ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,21 @@ import { styled } from 'styled-components';
|
|||||||
import RadioInput from '../common/input/Radio';
|
import RadioInput from '../common/input/Radio';
|
||||||
import React, { useState, useEffect, Fragment } from 'react';
|
import React, { useState, useEffect, Fragment } from 'react';
|
||||||
import CheckBox from '../common/input/CheckBox';
|
import CheckBox from '../common/input/CheckBox';
|
||||||
|
import {
|
||||||
|
Input,
|
||||||
|
Button as AntButton,
|
||||||
|
Select,
|
||||||
|
Alert,
|
||||||
|
Space,
|
||||||
|
Card,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Checkbox,
|
||||||
|
Radio,
|
||||||
|
DatePicker,
|
||||||
|
TimePicker
|
||||||
|
} from 'antd';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import { Title, SelectInput, BtnWrapper, TextInput, Label, InputLabel, DatePickerWrapper, Textarea} from '../../styles/Components';
|
import { Title, SelectInput, BtnWrapper, TextInput, Label, InputLabel, DatePickerWrapper, Textarea} from '../../styles/Components';
|
||||||
import Button from '../common/button/Button';
|
import Button from '../common/button/Button';
|
||||||
@@ -32,6 +47,7 @@ import { useLoading } from '../../context/LoadingProvider';
|
|||||||
import { alertTypes, currencyCodeTypes } from '../../assets/data/types';
|
import { alertTypes, currencyCodeTypes } from '../../assets/data/types';
|
||||||
import { userType2 } from '../../assets/data/options';
|
import { userType2 } from '../../assets/data/options';
|
||||||
import { STORAGE_MAIL_COPY } from '../../assets/data/adminConstants';
|
import { STORAGE_MAIL_COPY } from '../../assets/data/adminConstants';
|
||||||
|
import { DetailLayout } from '../common';
|
||||||
|
|
||||||
const MailDetailModal = ({ detailView, handleDetailView, content }) => {
|
const MailDetailModal = ({ detailView, handleDetailView, content }) => {
|
||||||
const userInfo = useRecoilValue(authList);
|
const userInfo = useRecoilValue(authList);
|
||||||
@@ -46,10 +62,11 @@ const MailDetailModal = ({ detailView, handleDetailView, content }) => {
|
|||||||
const [sendHour, setSendHour] = useState('00');
|
const [sendHour, setSendHour] = useState('00');
|
||||||
const [sendMin, setSendMin] = useState('00');
|
const [sendMin, setSendMin] = useState('00');
|
||||||
|
|
||||||
|
const [activeLanguage, setActiveLanguage] = useState('KO');
|
||||||
const [item, setItem] = useState('');
|
const [item, setItem] = useState('');
|
||||||
const [itemCount, setItemCount] = useState('');
|
const [itemCount, setItemCount] = useState(1);
|
||||||
const [resource, setResource] = useState(currencyCodeTypes.gold);
|
const [resource, setResource] = useState(currencyCodeTypes.gold);
|
||||||
const [resourceCount, setResourceCount] = useState('');
|
const [resourceCount, setResourceCount] = useState(1);
|
||||||
|
|
||||||
const [resultData, setResultData] = useState({
|
const [resultData, setResultData] = useState({
|
||||||
is_reserve: false,
|
is_reserve: false,
|
||||||
@@ -94,6 +111,7 @@ const MailDetailModal = ({ detailView, handleDetailView, content }) => {
|
|||||||
mail_list: content.mail_list,
|
mail_list: content.mail_list,
|
||||||
item_list: content.item_list,
|
item_list: content.item_list,
|
||||||
guid: content.target,
|
guid: content.target,
|
||||||
|
send_status: content.send_status,
|
||||||
file_name: content.receive_type === 'MULTIPLE' ? content.target : null
|
file_name: content.receive_type === 'MULTIPLE' ? content.target : null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,6 +140,136 @@ const MailDetailModal = ({ detailView, handleDetailView, content }) => {
|
|||||||
}
|
}
|
||||||
},[updateAuth, content, resultData])
|
},[updateAuth, content, resultData])
|
||||||
|
|
||||||
|
// 발송 상태 렌더링
|
||||||
|
const renderSendStatus = () => {
|
||||||
|
const status = resultData.send_status;
|
||||||
|
let color = '';
|
||||||
|
let text = '';
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 'WAIT':
|
||||||
|
color = '#FAAD14';
|
||||||
|
text = '대기';
|
||||||
|
break;
|
||||||
|
case 'FINISH':
|
||||||
|
color = '#52c41a';
|
||||||
|
text = '완료';
|
||||||
|
break;
|
||||||
|
case 'FAIL':
|
||||||
|
color = '#ff4d4f';
|
||||||
|
text = '실패';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
color = '#d9d9d9';
|
||||||
|
text = status || '알 수 없음';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
padding: '2px 8px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
backgroundColor: color,
|
||||||
|
color: 'white',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: '500'
|
||||||
|
}}>
|
||||||
|
{text}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 탭 항목 생성
|
||||||
|
const getLanguageTabItems = () => {
|
||||||
|
return resultData.mail_list?.map(mail => ({
|
||||||
|
key: mail.language,
|
||||||
|
label: mail.language,
|
||||||
|
children: (
|
||||||
|
<div style={{ padding: '10px', minHeight: '400px', height: 'auto' }}>
|
||||||
|
<Row gutter={[16, 24]}>
|
||||||
|
<Col span={24}>
|
||||||
|
<div>
|
||||||
|
<label style={{
|
||||||
|
display: 'block',
|
||||||
|
marginBottom: '8px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: 'rgba(0, 0, 0, 0.85)',
|
||||||
|
fontSize: '14px'
|
||||||
|
}}>
|
||||||
|
제목 <span style={{ color: '#ff4d4f' }}>*</span>
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
value={mail.title || ''}
|
||||||
|
placeholder="우편 제목을 입력하세요"
|
||||||
|
maxLength={30}
|
||||||
|
readOnly={isView}
|
||||||
|
onChange={(e) => updateMailData(mail.language, 'title', e.target.value.trimStart())}
|
||||||
|
showCount
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<div>
|
||||||
|
<label style={{
|
||||||
|
display: 'block',
|
||||||
|
marginBottom: '8px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: 'rgba(0, 0, 0, 0.85)',
|
||||||
|
fontSize: '14px'
|
||||||
|
}}>
|
||||||
|
내용 <span style={{ color: '#ff4d4f' }}>*</span>
|
||||||
|
</label>
|
||||||
|
<Input.TextArea
|
||||||
|
value={mail.content || ''}
|
||||||
|
placeholder="우편 내용을 입력하세요"
|
||||||
|
readOnly={isView}
|
||||||
|
rows={6}
|
||||||
|
maxLength={2000}
|
||||||
|
showCount
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 2000) return;
|
||||||
|
updateMailData(mail.language, 'content', e.target.value.trimStart());
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
resize: 'vertical',
|
||||||
|
minHeight: '200px',
|
||||||
|
maxHeight: '400px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
closable: resultData.mail_list?.length > 1 && !isView,
|
||||||
|
})) || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 메일 데이터 업데이트
|
||||||
|
const updateMailData = (language, field, value) => {
|
||||||
|
const updatedMailList = resultData.mail_list.map(mail =>
|
||||||
|
mail.language === language
|
||||||
|
? { ...mail, [field]: value }
|
||||||
|
: mail
|
||||||
|
);
|
||||||
|
setResultData({ ...resultData, mail_list: updatedMailList });
|
||||||
|
setIsChanged(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 탭 삭제 핸들러
|
||||||
|
const handleTabClose = (targetKey) => {
|
||||||
|
if (resultData.mail_list.length <= 1) return;
|
||||||
|
|
||||||
|
const filterList = resultData.mail_list.filter(el => el.language !== targetKey);
|
||||||
|
setResultData({ ...resultData, mail_list: filterList });
|
||||||
|
|
||||||
|
if (activeLanguage === targetKey) {
|
||||||
|
setActiveLanguage(filterList[0]?.language || 'KO');
|
||||||
|
}
|
||||||
|
setIsChanged(true);
|
||||||
|
};
|
||||||
|
|
||||||
// 아이템 수량 숫자 체크
|
// 아이템 수량 숫자 체크
|
||||||
const handleItemCount = e => {
|
const handleItemCount = e => {
|
||||||
if (e.target.value === '0' || e.target.value === '-0') {
|
if (e.target.value === '0' || e.target.value === '-0') {
|
||||||
@@ -338,12 +486,282 @@ const MailDetailModal = ({ detailView, handleDetailView, content }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDateTimeChange = (datetime) => {
|
||||||
|
setResultData({ ...resultData, send_dt: datetime.toDate() });
|
||||||
|
setIsChanged(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 아이템 목록 렌더링
|
||||||
|
const renderItemList = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{resultData.item_list && resultData.item_list.length > 0 ? (
|
||||||
|
<Space wrap>
|
||||||
|
{resultData.item_list.map((data, index) => (
|
||||||
|
<Card
|
||||||
|
key={index}
|
||||||
|
title={data.item_name}
|
||||||
|
size="small"
|
||||||
|
extra={
|
||||||
|
!isView && (
|
||||||
|
<AntButton
|
||||||
|
type="text"
|
||||||
|
danger
|
||||||
|
size="small"
|
||||||
|
onClick={() => onItemRemove(index)}
|
||||||
|
>
|
||||||
|
X
|
||||||
|
</AntButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
style={{ minWidth: '150px' }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div>{data.item}</div>
|
||||||
|
<div>수량: {data.item_cnt}</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
) : (
|
||||||
|
<Alert message="등록된 아이템이 없습니다." type="info" showIcon />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 아이템 추가 컴포넌트
|
||||||
|
const renderItemAdd = () => {
|
||||||
|
return (
|
||||||
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
|
<Input
|
||||||
|
placeholder="Item Meta id 입력"
|
||||||
|
value={item}
|
||||||
|
onChange={(e) => setItem(e.target.value.trimStart())}
|
||||||
|
disabled={isView}
|
||||||
|
style={{ width: '200px' }}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder="수량"
|
||||||
|
value={itemCount}
|
||||||
|
onChange={(e) => setItemCount(e.target.value)}
|
||||||
|
disabled={isView}
|
||||||
|
style={{ width: '120px' }}
|
||||||
|
min={1}
|
||||||
|
/>
|
||||||
|
<AntButton
|
||||||
|
type="primary"
|
||||||
|
onClick={handleItemList}
|
||||||
|
disabled={itemCount.length === 0 || item.length === 0 || isView}
|
||||||
|
>
|
||||||
|
추가
|
||||||
|
</AntButton>
|
||||||
|
</Space.Compact>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 자원 추가 컴포넌트
|
||||||
|
const renderResourceAdd = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Space.Compact style={{ width: '100%', marginBottom: '8px' }}>
|
||||||
|
<Select
|
||||||
|
value={resource}
|
||||||
|
onChange={setResource}
|
||||||
|
disabled={isView}
|
||||||
|
style={{ width: '200px' }}
|
||||||
|
placeholder="자원 선택"
|
||||||
|
>
|
||||||
|
{currencyItemCode.map((data, index) => (
|
||||||
|
<Select.Option key={index} value={data.value}>
|
||||||
|
{data.name}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder="수량"
|
||||||
|
value={resourceCount}
|
||||||
|
disabled={isView}
|
||||||
|
onChange={(e) => setResourceCount(e.target.value)}
|
||||||
|
style={{ width: '120px' }}
|
||||||
|
min={1}
|
||||||
|
/>
|
||||||
|
<AntButton
|
||||||
|
type="primary"
|
||||||
|
onClick={handleResourceList}
|
||||||
|
disabled={resourceCount.length === 0 || resource.length === 0 || isView}
|
||||||
|
>
|
||||||
|
추가
|
||||||
|
</AntButton>
|
||||||
|
</Space.Compact>
|
||||||
|
{resource === currencyCodeTypes.calium && (
|
||||||
|
<div style={{ fontSize: '12px', color: '#666' }}>
|
||||||
|
잔여 수량: {caliumTotalData}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 수신대상 렌더링
|
||||||
|
const renderReceiver = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }}>
|
||||||
|
<div>
|
||||||
|
<Radio.Group value={resultData.receive_type} disabled>
|
||||||
|
<Space direction="vertical">
|
||||||
|
<Radio value="SINGLE">
|
||||||
|
단일: {resultData.receive_type === 'SINGLE' ? resultData.guid : ''}
|
||||||
|
</Radio>
|
||||||
|
<Radio value="MULTIPLE">
|
||||||
|
복수: {resultData.receive_type === 'MULTIPLE' ? excelFile : ''}
|
||||||
|
</Radio>
|
||||||
|
</Space>
|
||||||
|
</Radio.Group>
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemGroups = [
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
row: 0,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 1,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'is_reserve',
|
||||||
|
render: () => (
|
||||||
|
<Checkbox
|
||||||
|
checked={resultData.is_reserve}
|
||||||
|
disabled
|
||||||
|
onChange={(e) => {
|
||||||
|
setResultData({ ...resultData, is_reserve: e.target.checked });
|
||||||
|
setIsChanged(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
예약 발송
|
||||||
|
</Checkbox>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
...(resultData.is_reserve ? [{
|
||||||
|
row: 0,
|
||||||
|
col: 1,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'send_dt',
|
||||||
|
label: '발송 시간',
|
||||||
|
render: () => (
|
||||||
|
<DatePicker
|
||||||
|
showTime
|
||||||
|
allowClear={false}
|
||||||
|
value={resultData.send_dt ? dayjs(resultData.send_dt) : null}
|
||||||
|
onChange={handleDateTimeChange}
|
||||||
|
disabled={!content?.is_reserve || isView}
|
||||||
|
format="YYYY-MM-DD HH:mm"
|
||||||
|
style={{ width: '200px' }}
|
||||||
|
disabledDate={(current) => current && current < dayjs().startOf('day')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}] : []),
|
||||||
|
{
|
||||||
|
row: 1,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 1,
|
||||||
|
type: 'select',
|
||||||
|
key: 'mail_type',
|
||||||
|
label: '우편 타입',
|
||||||
|
value: resultData.mail_type,
|
||||||
|
disabled: isView,
|
||||||
|
options: [
|
||||||
|
{ value: 'SELECT', name: '타입 선택' },
|
||||||
|
...mailType.filter(data => data.value !== 'ALL')
|
||||||
|
],
|
||||||
|
handler: (value) => {
|
||||||
|
setResultData({ ...resultData, mail_type: value });
|
||||||
|
setIsChanged(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 1,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 1,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'send_status',
|
||||||
|
label: '발송상태',
|
||||||
|
render: renderSendStatus
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 2,
|
||||||
|
col: 1,
|
||||||
|
colSpan: 1,
|
||||||
|
type: 'select',
|
||||||
|
key: 'user_type',
|
||||||
|
label: '수신대상 타입',
|
||||||
|
value: resultData.user_type,
|
||||||
|
disabled: true,
|
||||||
|
options: userType2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 2,
|
||||||
|
col: 2,
|
||||||
|
colSpan: 2,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'receiver',
|
||||||
|
label: '수신대상',
|
||||||
|
render: renderReceiver
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 3,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'tab',
|
||||||
|
key: 'language_tabs',
|
||||||
|
tabItems: getLanguageTabItems(),
|
||||||
|
activeKey: activeLanguage,
|
||||||
|
onTabChange: setActiveLanguage,
|
||||||
|
onTabClose: handleTabClose
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 4,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'item_add',
|
||||||
|
label: '아이템 추가',
|
||||||
|
render: renderItemAdd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 5,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'resource_add',
|
||||||
|
label: '자원 추가',
|
||||||
|
render: renderResourceAdd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
row: 6,
|
||||||
|
col: 0,
|
||||||
|
colSpan: 4,
|
||||||
|
type: 'custom',
|
||||||
|
key: 'item_list',
|
||||||
|
render: renderItemList
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal min="960px" $view={detailView}>
|
<Modal min="960px" $view={detailView}>
|
||||||
<Title $align="center">우편 상세 정보</Title>
|
<Title $align="center">우편 상세 정보</Title>
|
||||||
{content && <>
|
{content && <RegistInfo>
|
||||||
<RegistInfo>
|
|
||||||
<span>등록자 : {content.create_by}</span>
|
<span>등록자 : {content.create_by}</span>
|
||||||
<span>등록일 : {convertKTC(content.create_dt, false)}</span>
|
<span>등록일 : {convertKTC(content.create_dt, false)}</span>
|
||||||
{typeof content.update_by !== 'undefined' && (
|
{typeof content.update_by !== 'undefined' && (
|
||||||
@@ -352,321 +770,14 @@ const MailDetailModal = ({ detailView, handleDetailView, content }) => {
|
|||||||
<span>수정일 : {convertKTC(content.update_dt, false)}</span>
|
<span>수정일 : {convertKTC(content.update_dt, false)}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</RegistInfo>
|
</RegistInfo>}
|
||||||
<ModalWrapper>
|
<DetailLayout
|
||||||
<RegistGroup>
|
itemGroups={itemGroups}
|
||||||
<InputRow>
|
formData={resultData}
|
||||||
<CheckBox
|
onChange={setResultData}
|
||||||
label="예약 발송"
|
disabled={false}
|
||||||
id="reserve"
|
columnCount={4}
|
||||||
checked={resultData && resultData.is_reserve}
|
/>
|
||||||
setData={e => {
|
|
||||||
setResultData({ ...resultData, is_reserve: e.target.checked });
|
|
||||||
setIsChanged(true);
|
|
||||||
}}
|
|
||||||
disabled={(content.is_reserve === false) || isView}
|
|
||||||
/>
|
|
||||||
{content.is_reserve === false ? (
|
|
||||||
<></>
|
|
||||||
) : (
|
|
||||||
resultData.is_reserve === true && (
|
|
||||||
<InputItem>
|
|
||||||
<InputLabel>발송 시간</InputLabel>
|
|
||||||
<InputGroup>
|
|
||||||
<DatePickerWrapper>
|
|
||||||
<DatePickerComponent
|
|
||||||
readOnly={(content.is_reserve === false) || isView}
|
|
||||||
name={initialData.send_dt}
|
|
||||||
selectedDate={resultData ? resultData.send_dt : initialData.send_dt}
|
|
||||||
handleSelectedDate={data => handleSelectedDate(data)}
|
|
||||||
pastDate={new Date()}
|
|
||||||
/>
|
|
||||||
</DatePickerWrapper>
|
|
||||||
<SelectInput
|
|
||||||
onChange={e => handleSendTime(e)}
|
|
||||||
id="hour"
|
|
||||||
disabled={(content.is_reserve === false) || isView}
|
|
||||||
value={
|
|
||||||
resultData && String(new Date(resultData.send_dt).getHours()) < 10
|
|
||||||
? '0' + String(new Date(resultData.send_dt).getHours())
|
|
||||||
: resultData && String(new Date(resultData.send_dt).getHours())
|
|
||||||
}>
|
|
||||||
{HourList.map(hour => (
|
|
||||||
<option value={hour} key={hour}>
|
|
||||||
{hour}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
<SelectInput
|
|
||||||
onChange={e => {
|
|
||||||
handleSendTime(e);
|
|
||||||
setIsChanged(true);
|
|
||||||
}}
|
|
||||||
id="min"
|
|
||||||
disabled={(content.is_reserve === false) || isView}
|
|
||||||
value={
|
|
||||||
resultData && String(new Date(resultData.send_dt).getMinutes()) < 10
|
|
||||||
? '0' + String(new Date(resultData.send_dt).getMinutes())
|
|
||||||
: resultData && String(new Date(resultData.send_dt).getMinutes())
|
|
||||||
}>
|
|
||||||
{MinuteList.map(min => (
|
|
||||||
<option value={min} key={min}>
|
|
||||||
{min}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
</InputGroup>
|
|
||||||
</InputItem>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
<InputItem>
|
|
||||||
<InputLabel>우편 타입</InputLabel>
|
|
||||||
<SelectInput
|
|
||||||
onChange={e => {
|
|
||||||
setResultData({ ...resultData, mail_type: e.target.value });
|
|
||||||
setIsChanged(true);
|
|
||||||
}}
|
|
||||||
value={resultData.mail_type}
|
|
||||||
disabled={isView}>
|
|
||||||
<option value="SELECT">타입 선택</option>
|
|
||||||
{mailType.filter(data => data.value !== 'ALL').map((data, index) => (
|
|
||||||
<option key={index} value={data.value}>
|
|
||||||
{data.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
</InputItem>
|
|
||||||
<InputItem>
|
|
||||||
<InputLabel>발송상태</InputLabel>
|
|
||||||
<div>
|
|
||||||
{initialData.send_status === 'WAIT' && <MailState>대기</MailState>}
|
|
||||||
{initialData.send_status === 'FINISH' && <MailState result="success">완료</MailState>}
|
|
||||||
{initialData.send_status === 'FAIL' && <MailState result="fail">실패</MailState>}
|
|
||||||
</div>
|
|
||||||
</InputItem>
|
|
||||||
</InputRow>
|
|
||||||
<MailReceiver>
|
|
||||||
<InputItem>
|
|
||||||
<InputLabel>수신대상</InputLabel>
|
|
||||||
<InputItem>
|
|
||||||
<SelectInput onChange={e => setResultData({ ...resultData, user_type: e.target.value })}
|
|
||||||
value={resultData.user_type}
|
|
||||||
disabled={true}>
|
|
||||||
{userType2.map((data, index) => (
|
|
||||||
<option key={index} value={data.value}>
|
|
||||||
{data.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
</InputItem>
|
|
||||||
<div>
|
|
||||||
<InputGroup>
|
|
||||||
<RadioInput
|
|
||||||
label="단일"
|
|
||||||
id="SINGLE"
|
|
||||||
name="receiver"
|
|
||||||
value="SINGLE"
|
|
||||||
disabled={true}
|
|
||||||
fontWeight="600"
|
|
||||||
checked={resultData.receive_type === 'SINGLE'}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
disabled={true}
|
|
||||||
value={resultData.receive_type === 'SINGLE' && resultData.guid !== '' ? resultData.guid : ''}
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
<InputGroup>
|
|
||||||
<RadioInput
|
|
||||||
label="복수"
|
|
||||||
id="MULTIPLE"
|
|
||||||
name="receiver"
|
|
||||||
value="MULTIPLE"
|
|
||||||
fontWeight="600"
|
|
||||||
disabled={true}
|
|
||||||
/>
|
|
||||||
<MailRegistUploadBtn
|
|
||||||
disabled={true}
|
|
||||||
setResultData={setResultData}
|
|
||||||
resultData={resultData}
|
|
||||||
setExcelFile={setExcelFile}
|
|
||||||
handleDetailDelete={() => {}}
|
|
||||||
disabledBtn={true}
|
|
||||||
excelName={excelFile}
|
|
||||||
setExcelName={setExcelFile}
|
|
||||||
downloadData={downloadData}
|
|
||||||
status={initialData.send_status}
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
</div>
|
|
||||||
</InputItem>
|
|
||||||
</MailReceiver>
|
|
||||||
</RegistGroup>
|
|
||||||
{resultData.mail_list &&
|
|
||||||
resultData?.mail_list?.map(data => {
|
|
||||||
return (
|
|
||||||
<Fragment key={data.language}>
|
|
||||||
<MailRegistBox>
|
|
||||||
<LangArea>
|
|
||||||
언어 : {data.language}
|
|
||||||
{btnValidation === false ? (
|
|
||||||
<BtnClose
|
|
||||||
disabled={true}
|
|
||||||
onClick={e => {
|
|
||||||
e.preventDefault();
|
|
||||||
onLangDelete(data.language);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<BtnClose opacity="10%" />
|
|
||||||
)}
|
|
||||||
</LangArea>
|
|
||||||
<MailRegistTable>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th width="120">
|
|
||||||
<Label>제목</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<InputItem>
|
|
||||||
<TextInput
|
|
||||||
placeholder="우편 제목 입력"
|
|
||||||
maxLength="30"
|
|
||||||
id={data.language}
|
|
||||||
value={data.title}
|
|
||||||
readOnly={(content.is_reserve === false) || isView}
|
|
||||||
onChange={e => {
|
|
||||||
let list = [...resultData.mail_list];
|
|
||||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
|
||||||
list[findIndex].title = e.target.value.trimStart();
|
|
||||||
|
|
||||||
setResultData({ ...resultData, mail_list: list });
|
|
||||||
setIsChanged(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</InputItem>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<Label>내용</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<Textarea
|
|
||||||
value={data.content}
|
|
||||||
readOnly={isView}
|
|
||||||
id={data.language}
|
|
||||||
onChange={e => {
|
|
||||||
if (e.target.value.length > 2000) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let list = [...resultData.mail_list];
|
|
||||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
|
||||||
list[findIndex].content = e.target.value.trimStart();
|
|
||||||
|
|
||||||
setResultData({ ...resultData, mail_list: list });
|
|
||||||
setIsChanged(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</MailRegistTable>
|
|
||||||
</MailRegistBox>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<MailRegistBox>
|
|
||||||
<MailRegistTable>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th width="120">
|
|
||||||
<Label>아이템 첨부</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<InputItem>
|
|
||||||
<TextInput
|
|
||||||
placeholder="Item Meta id 입력"
|
|
||||||
value={item}
|
|
||||||
onChange={e => {
|
|
||||||
let list = [];
|
|
||||||
list = e.target.value.trimStart();
|
|
||||||
setItem(list);
|
|
||||||
}}
|
|
||||||
disabled={isView}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder="수량"
|
|
||||||
value={itemCount}
|
|
||||||
type="number"
|
|
||||||
onChange={e => handleItemCount(e)}
|
|
||||||
width="90px"
|
|
||||||
disabled={isView}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
text="추가"
|
|
||||||
theme={itemCount.length === 0 || item.length === 0 ? 'disable' : 'search'}
|
|
||||||
disabled={isView}
|
|
||||||
handleClick={handleItemList}
|
|
||||||
/>
|
|
||||||
</InputItem>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th width="120">
|
|
||||||
<Label>자원 첨부</Label>
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<InputItem>
|
|
||||||
<SelectInput onChange={e => setResource(e.target.value)} value={resource} disabled={isView}>
|
|
||||||
{currencyItemCode.map((data, index) => (
|
|
||||||
<option key={index} value={data.value}>
|
|
||||||
{data.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</SelectInput>
|
|
||||||
<TextInput
|
|
||||||
placeholder="수량"
|
|
||||||
type="number"
|
|
||||||
value={resourceCount}
|
|
||||||
disabled={isView}
|
|
||||||
onChange={e => handleResourceCount(e)}
|
|
||||||
width="200px"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
text="추가"
|
|
||||||
theme={resourceCount.length === 0 || resource.length === 0 ? 'disable' : 'search'}
|
|
||||||
disabled={isView}
|
|
||||||
handleClick={handleResourceList}
|
|
||||||
width="100px"
|
|
||||||
height="35px"
|
|
||||||
/>
|
|
||||||
{resource === currencyCodeTypes.calium &&
|
|
||||||
<Label>(잔여 수량: {caliumTotalData})</Label>}
|
|
||||||
</InputItem>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{resultData.item_list && (
|
|
||||||
<ItemList>
|
|
||||||
{resultData.item_list.map((data, index) => {
|
|
||||||
return (
|
|
||||||
<Item key={index}>
|
|
||||||
<span>
|
|
||||||
{data.item_name}[{data.item}] ({data.item_cnt})
|
|
||||||
</span>
|
|
||||||
{!isView && <BtnDelete onClick={() => onItemRemove(index)}></BtnDelete>}
|
|
||||||
</Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ItemList>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</MailRegistTable>
|
|
||||||
</MailRegistBox>
|
|
||||||
</ModalWrapper>
|
|
||||||
</>}
|
|
||||||
<BtnWrapper $justify="flex-end" $gap="10px" $paddingTop="20px">
|
<BtnWrapper $justify="flex-end" $gap="10px" $paddingTop="20px">
|
||||||
<Button
|
<Button
|
||||||
text="확인"
|
text="확인"
|
||||||
|
|||||||
@@ -205,7 +205,6 @@ const LandAuction = () => {
|
|||||||
{/*<th width="100">경매 재화</th>*/}
|
{/*<th width="100">경매 재화</th>*/}
|
||||||
<th width="90">경매 시작가</th>
|
<th width="90">경매 시작가</th>
|
||||||
<th width="200">예약 시작일</th>
|
<th width="200">예약 시작일</th>
|
||||||
<th width="200">예약 종료일</th>
|
|
||||||
<th width="200">경매 시작일</th>
|
<th width="200">경매 시작일</th>
|
||||||
<th width="200">경매 종료일</th>
|
<th width="200">경매 종료일</th>
|
||||||
<th width="200">낙찰 정산일</th>
|
<th width="200">낙찰 정산일</th>
|
||||||
@@ -236,7 +235,6 @@ const LandAuction = () => {
|
|||||||
{/*<td>{auction.currency_type}</td>*/}
|
{/*<td>{auction.currency_type}</td>*/}
|
||||||
<td>{auction.start_price}</td>
|
<td>{auction.start_price}</td>
|
||||||
<td>{convertKTC(auction.resv_start_dt)}</td>
|
<td>{convertKTC(auction.resv_start_dt)}</td>
|
||||||
<td>{convertKTC(auction.resv_end_dt)}</td>
|
|
||||||
<td>{convertKTC(auction.auction_start_dt)}</td>
|
<td>{convertKTC(auction.auction_start_dt)}</td>
|
||||||
<td>{convertKTC(auction.auction_end_dt)}</td>
|
<td>{convertKTC(auction.auction_end_dt)}</td>
|
||||||
<td>{convertKTC(auction.close_end_dt)}</td>
|
<td>{convertKTC(auction.close_end_dt)}</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user