Compare commits
74 Commits
4bc8b34c26
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| b801552839 | |||
| 3169055646 | |||
| 5d2e1918d1 | |||
| 4407fdc6b6 | |||
| b01c5cd410 | |||
| 63b3704e89 | |||
| f78a4912a6 | |||
| e25bcdc86e | |||
| 5143b45610 | |||
| f4b629df52 | |||
| 2ba8594e6b | |||
| d3470e3d03 | |||
| 99943c0b19 | |||
| 26114c9a9b | |||
| 952701f68b | |||
| 7041d4a649 | |||
| 7fa9abcad4 | |||
| 943b146496 | |||
| 88585c1b24 | |||
| 991462c0d7 | |||
| bab594918e | |||
| c4099c0cf0 | |||
| 0d8fb7b327 | |||
| d4db33bcf0 | |||
| 38dac99278 | |||
| 28094e1c48 | |||
| 67c048a11d | |||
| f6a0319701 | |||
| 0368bf77e7 | |||
| b2b579ead1 | |||
| 495243a1a3 | |||
| 7993f37e26 | |||
| 93a7c087e1 | |||
| 38fa323db6 | |||
| 6f9f0307ac | |||
| dc7934d906 | |||
| 9d06246aba | |||
| 1532793cc1 | |||
| 64bf449de7 | |||
| 9be5bb388a | |||
| d219a128bc | |||
| ce2f3db35c | |||
| b5efab7755 | |||
| 1cc20b65e2 | |||
| 0b85232969 | |||
| 4291d7976c | |||
| 065c081a85 | |||
| fa290b64ec | |||
| f8d5b2197d | |||
| 3e5c3f0167 | |||
| 826459f304 | |||
| d2ac5b338e | |||
| 1598fa93b6 | |||
| 24eb59d937 | |||
| a74376108a | |||
| 80a3c0ab8a | |||
| f290f0dbf0 | |||
| 9221a06a8e | |||
| 2c693b2503 | |||
| 73f8448b24 | |||
| ffdfad1223 | |||
| 8bd7e8325d | |||
| daf4c62aa7 | |||
| a333f55f81 | |||
| 894eb17fd8 | |||
| cddd8e6333 | |||
| a0087a1e29 | |||
| f2d7c87f38 | |||
| 5d9b6871fb | |||
| 3efd663f0d | |||
| 04adce4aaf | |||
| 2330bbc393 | |||
| 2b2cec3d10 | |||
| 24e09a65bc |
@@ -3,6 +3,10 @@ server {
|
||||
listen [::]:8080;
|
||||
server_name localhost;
|
||||
|
||||
client_max_body_size 100M;
|
||||
client_body_timeout 300s;
|
||||
client_header_timeout 300s;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/admintool;
|
||||
index index.html index.htm;
|
||||
@@ -16,6 +20,11 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
@@ -3,6 +3,10 @@ server {
|
||||
listen [::]:8080;
|
||||
server_name localhost;
|
||||
|
||||
client_max_body_size 100M;
|
||||
client_body_timeout 300s;
|
||||
client_header_timeout 300s;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/admintool;
|
||||
index index.html index.htm;
|
||||
@@ -16,6 +20,11 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
@@ -3,6 +3,10 @@ server {
|
||||
listen [::]:8080;
|
||||
server_name localhost;
|
||||
|
||||
client_max_body_size 100M;
|
||||
client_body_timeout 300s;
|
||||
client_header_timeout 300s;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/admintool;
|
||||
index index.html index.htm;
|
||||
@@ -11,11 +15,16 @@ server {
|
||||
|
||||
# api reverse proxy
|
||||
location /api/ {
|
||||
proxy_pass http://172.40.129.180:23450;
|
||||
proxy_pass http://172.24.128.231:23450;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
@@ -3,6 +3,10 @@ server {
|
||||
listen [::]:8080;
|
||||
server_name localhost;
|
||||
|
||||
client_max_body_size 100M;
|
||||
client_body_timeout 300s;
|
||||
client_header_timeout 300s;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/admintool;
|
||||
index index.html index.htm;
|
||||
@@ -16,6 +20,11 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
1744
package-lock.json
generated
1744
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,17 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.6.1",
|
||||
"@hookform/resolvers": "^3.2.0",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^13.0.0",
|
||||
"@testing-library/user-event": "^13.2.1",
|
||||
"antd": "^5.26.1",
|
||||
"axios": "^1.4.0",
|
||||
"date-fns": "^2.30.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"dotenv-cli": "^7.4.2",
|
||||
"framer-motion": "^12.19.1",
|
||||
"i18next": "^23.15.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.2.0",
|
||||
|
||||
16
src/App.js
16
src/App.js
@@ -5,16 +5,22 @@ import GlobalStyles from './styles/GlobalStyles';
|
||||
import RouteInfo from './RouteInfo';
|
||||
|
||||
import './i18n';
|
||||
import { AlertProvider } from './context/AlertProvider';
|
||||
import { LoadingProvider } from './context/LoadingProvider';
|
||||
|
||||
function App() {
|
||||
const isToken = sessionStorage.getItem('token') ? true : false;
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<GlobalStyles />
|
||||
<ControllLink>{isToken ? <Link to="/main" /> : <Link to="/fail" />}</ControllLink>
|
||||
<RouteInfo />
|
||||
</BrowserRouter>
|
||||
<AlertProvider>
|
||||
<LoadingProvider>
|
||||
<BrowserRouter>
|
||||
<GlobalStyles />
|
||||
<ControllLink>{isToken ? <Link to="/main" /> : <Link to="/fail" />}</ControllLink>
|
||||
<RouteInfo />
|
||||
</BrowserRouter>
|
||||
</LoadingProvider>
|
||||
</AlertProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,24 +9,33 @@ import {
|
||||
AdminView,
|
||||
AuthSetting,
|
||||
AuthSettingUpdate,
|
||||
CaliumRequest,
|
||||
CaliumRequest, DataInitView,
|
||||
LogView,
|
||||
} from './pages/UserManage';
|
||||
import { EconomicIndex, UserIndex } from './pages/IndexManage';
|
||||
import { LandView, CryptView, GameLogView, UserView } from './pages/DataManage';
|
||||
import {
|
||||
LandInfoView,
|
||||
GameLogView,
|
||||
UserView,
|
||||
BusinessLogView,
|
||||
MetaItemView,
|
||||
RankManage,
|
||||
MetaCraftingView,
|
||||
} from './pages/DataManage';
|
||||
import {
|
||||
Board,
|
||||
Event,
|
||||
EventRegist,
|
||||
RewardEvent,
|
||||
RewardEventRegist,
|
||||
Items,
|
||||
Mail,
|
||||
MailRegist,
|
||||
ReportList,
|
||||
UserBlock,
|
||||
UserBlockRegist,
|
||||
WhiteList,
|
||||
LandAuction,
|
||||
BattleEvent
|
||||
BattleEvent,
|
||||
MenuBanner, MenuBannerRegist, Ranking,
|
||||
Event
|
||||
} from './pages/ServiceManage';
|
||||
|
||||
const RouteInfo = () => {
|
||||
@@ -49,6 +58,7 @@ const RouteInfo = () => {
|
||||
<Route path="authsetting" element={<AuthSetting />} />
|
||||
<Route path="authsetting/:id" element={<AuthSettingUpdate />} />
|
||||
<Route path="caliumrequest" element={<CaliumRequest />} />
|
||||
<Route path="datainit" element={<DataInitView />} />
|
||||
</Route>
|
||||
<Route path="/indexmanage">
|
||||
<Route path="userindex" element={<UserIndex />} />
|
||||
@@ -56,23 +66,29 @@ const RouteInfo = () => {
|
||||
</Route>
|
||||
<Route path="/datamanage">
|
||||
<Route path="userview" element={<UserView />} />
|
||||
<Route path="landview" element={<LandView />} />
|
||||
<Route path="landview" element={<LandInfoView />} />
|
||||
<Route path="gamelogview" element={<GameLogView />} />
|
||||
<Route path="cryptview" element={<CryptView />} />
|
||||
<Route path="businesslogview" element={<BusinessLogView />} />
|
||||
<Route path="itemdictionary" element={<MetaItemView />} />
|
||||
<Route path="craftdictionary" element={<MetaCraftingView />} />
|
||||
<Route path="rankmanage" element={<RankManage />} />
|
||||
</Route>
|
||||
<Route path="/servicemanage">
|
||||
<Route path="board" element={<Board />} />
|
||||
<Route path="whitelist" element={<WhiteList />} />
|
||||
<Route path="mail" element={<Mail />} />
|
||||
<Route path="mail/mailregist" element={<MailRegist />} />
|
||||
<Route path="userblock" element={<UserBlock />} />
|
||||
<Route path="userblock/userblockregist" element={<UserBlockRegist />} />
|
||||
<Route path="reportlist" element={<ReportList />} />
|
||||
<Route path="items" element={<Items />} />
|
||||
<Route path="event" element={<Event />} />
|
||||
<Route path="event/eventregist" element={<EventRegist />} />
|
||||
<Route path="rewardevent" element={<RewardEvent />} />
|
||||
<Route path="rewardevent/eventregist" element={<RewardEventRegist />} />
|
||||
<Route path="landauction" element={<LandAuction />} />
|
||||
<Route path="battleevent" element={<BattleEvent />} />
|
||||
<Route path="menubanner" element={<MenuBanner />} />
|
||||
<Route path="menubanner/menubannerregist" element={<MenuBannerRegist />} />
|
||||
<Route path="ranking" element={<Ranking />} />
|
||||
<Route path="event" element={<Event />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
@@ -130,3 +130,20 @@ export const BattleRewardView = async (token) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const GameModeView = async (token) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/battle/game-mode/list`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data.game_mode_list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameModeView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -52,7 +52,7 @@ export const BlackListDelete = async (token, params) => {
|
||||
data: { list: params },
|
||||
});
|
||||
|
||||
return res;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('BlackListDelete', e);
|
||||
@@ -67,7 +67,7 @@ export const BlackListRegist = async (token, params) => {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('BlacklistRegist', e);
|
||||
|
||||
32
src/apis/Data.js
Normal file
32
src/apis/Data.js
Normal file
@@ -0,0 +1,32 @@
|
||||
//사용자 관리 - 데이터 api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
|
||||
export const InitData = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post('/api/v1/data/init-data', params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('InitData Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const InitHistoryList = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/data/init-list`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('InitHistoryList Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
95
src/apis/Dictionary.js
Normal file
95
src/apis/Dictionary.js
Normal file
@@ -0,0 +1,95 @@
|
||||
//운영 정보 관리 - 백과사전 api 연결
|
||||
|
||||
import { Axios, responseFileDownload } from '../utils';
|
||||
|
||||
// 아이템 백과사전 조회
|
||||
export const getItemDictionaryList = async (token, searchType, searchData, largeType, smallType, brand, gender, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/dictionary/item/list?search_type=${searchType}&search_data=${searchData}
|
||||
&large_type=${largeType}&small_type=${smallType}&brand=${brand}&gender=${gender}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getItemDictionaryList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const ItemDictionaryExport = async (token, params) => {
|
||||
try {
|
||||
await Axios.get(`/api/v1/dictionary/item/excel-export?search_type=${params.search_type}&search_data=${params.search_data}
|
||||
&large_type=${params.large_type}&small_type=${params.small_type}&brand=${params.brand}&gender=${params.gender}
|
||||
&lang=${params.lang}&task_id=${params.taskId}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob'
|
||||
}).then(response => {
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: 'itemDictionary'
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('ItemDictionaryExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getCraftingDictionaryList = async (token, searchType, searchData, smallType, recipeType, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/dictionary/craft/list?search_type=${searchType}&search_data=${searchData}
|
||||
&small_type=${smallType}&recipe_type=${recipeType}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getCraftingDictionaryList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const CraftingDictionaryExport = async (token, params) => {
|
||||
try {
|
||||
await Axios.get(`/api/v1/dictionary/craft/excel-export?search_type=${params.search_type}&search_data=${params.search_data}
|
||||
&small_type=${params.small_type}&recipe_type=${params.recipe_type}
|
||||
&lang=${params.lang}&task_id=${params.taskId}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob'
|
||||
}).then(response => {
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: 'craftingDictionary'
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('CraftingDictionaryExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const BrandView = async (token) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/dictionary/brand/list`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data.brand_list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('BrandView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,13 +1,13 @@
|
||||
//운영서비스 관리 - 이벤트 api 연결
|
||||
//운영서비스 관리 - 통합 이벤트 api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
// 이벤트 리스트 조회
|
||||
export const EventView = async (token, title, content, status, startDate, endDate, order, size, currentPage) => {
|
||||
export const EventView = async (token, searchData, status, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/event/list?title=${title}&content=${content}&status=${status}&start_dt=${startDate}&end_dt=${endDate}&orderby=${order}&page_no=${currentPage}
|
||||
&page_size=${size}`,
|
||||
`/api/v1/world-event/list?search_data=${searchData}&status=${status}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
@@ -24,11 +24,11 @@ export const EventView = async (token, title, content, status, startDate, endDat
|
||||
// 이벤트 상세보기
|
||||
export const EventDetailView = async (token, id) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/event/detail/${id}`, {
|
||||
const res = await Axios.get(`/api/v1/world-event/detail/${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data.detail;
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('EventDetailView Error', e);
|
||||
@@ -39,11 +39,11 @@ export const EventDetailView = async (token, id) => {
|
||||
// 이벤트 등록
|
||||
export const EventSingleRegist = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/event`, params, {
|
||||
const res = await Axios.post(`/api/v1/world-event`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('EventSingleRegist Error', e);
|
||||
@@ -51,14 +51,14 @@ export const EventSingleRegist = async (token, params) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 우편 수정
|
||||
// 이벤트 수정
|
||||
export const EventModify = async (token, id, params) => {
|
||||
try {
|
||||
const res = await Axios.put(`/api/v1/event/${id}`, params, {
|
||||
const res = await Axios.put(`/api/v1/world-event/${id}`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data.list;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('EventModify Error', e);
|
||||
@@ -66,15 +66,14 @@ export const EventModify = async (token, id, params) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 우편 삭제
|
||||
export const EventDelete = async (token, params, id) => {
|
||||
// 이벤트 삭제
|
||||
export const EventDelete = async (token, id) => {
|
||||
try {
|
||||
const res = await Axios.delete(`/api/v1/event/delete`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
data: { list: params },
|
||||
const res = await Axios.delete(`/api/v1/world-event/delete?id=${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
});
|
||||
|
||||
return res.data.data.list;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('EventDelete Error', e);
|
||||
@@ -82,17 +81,20 @@ export const EventDelete = async (token, params, id) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 이벤트 우편 아이템 확인
|
||||
export const EventIsItem = async (token, params) => {
|
||||
// 이벤트 메타데이터 조회
|
||||
export const EventActionView = async (token) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/event/item`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
const res = await Axios.get(
|
||||
`/api/v1/dictionary/event-action/list`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res;
|
||||
return res.data.data.event_action_list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('EventIsItem Error', e);
|
||||
throw new Error('EventActionView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
//사용자 관리 - 로그조회 api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
export const LogViewList = async (token, searchType, searchKey, historyType, startDt, endDt, orderBy, size, currentPage) => {
|
||||
@@ -13,7 +12,7 @@ export const LogViewList = async (token, searchType, searchKey, historyType, sta
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('LogViewList Error', e);
|
||||
@@ -34,3 +33,21 @@ export const LogviewDetail = async (token, id) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const LogHistory = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/history/change-list`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if(res.data.result === 'ERROR'){
|
||||
throw new Error('LogHistory Error', res.data.data.message);
|
||||
}
|
||||
|
||||
return res.data.data.list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('LogHistory Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -36,6 +36,19 @@ export const userTotalIndex = async token => {
|
||||
}
|
||||
};
|
||||
|
||||
export const dashboardCaliumIndex = async token => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/dashboard/calium/converter`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('dashboardCaliumIndex', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 유저 지표 다운로드
|
||||
export const userIndexExport = async (token, filename, sendDate, endDate) => {
|
||||
try {
|
||||
@@ -62,10 +75,14 @@ export const userIndexExport = async (token, filename, sendDate, endDate) => {
|
||||
};
|
||||
|
||||
// Retention
|
||||
export const RetentionIndexView = async (token, start_dt, end_dt) => {
|
||||
export const RetentionIndexView = async (token, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/retention/list?start_dt=${start_dt}&end_dt=${end_dt}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
const res = await Axios.get(`/api/v1/indicators/retention/list?start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
});
|
||||
|
||||
return res.data.data;
|
||||
@@ -183,10 +200,10 @@ export const PlaytimeIndexExport = async (token, filename, sendDate, endDate) =>
|
||||
|
||||
// 2. 경제 지표
|
||||
|
||||
// 재화 조회 (currency)
|
||||
export const CurrencyIndexView = async (token, start_dt, end_dt, currency_type) => {
|
||||
// 재화 획득 조회
|
||||
export const CurrencyAcquireIndexView = async (token, start_dt, end_dt, currencyType, deltaType) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/currency/use?start_dt=${start_dt}&end_dt=${end_dt}¤cy_type=${currency_type}`, {
|
||||
const res = await Axios.get(`/api/v1/indicators/currency/list?start_dt=${start_dt}&end_dt=${end_dt}¤cy_type=${currencyType}&delta_type=${deltaType}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
@@ -198,75 +215,10 @@ export const CurrencyIndexView = async (token, start_dt, end_dt, currency_type)
|
||||
}
|
||||
};
|
||||
|
||||
// 재화 지표 다운로드
|
||||
export const CurrencyIndexExport = async (token, filename, sendDate, endDate, currencyType) => {
|
||||
try {
|
||||
await Axios.get(`/api/v1/indicators/currency/excel-down?file=${filename}&start_dt=${sendDate}&end_dt=${endDate}¤cy_type=${currencyType}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
}).then(response => {
|
||||
const href = URL.createObjectURL(response.data);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = href;
|
||||
link.setAttribute('download', `${filename}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('CurrencyIndexExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// VBP
|
||||
export const VbpIndexView = async (token, start_dt, end_dt) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/currency/vbp?start_dt=${start_dt}&end_dt=${end_dt}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('VbpIndexView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// VBP 다운로드
|
||||
export const VBPIndexExport = async (token, filename, sendDate, endDate) => {
|
||||
try {
|
||||
await Axios.get(`/api/v1/indicators/currency/excel-down?file=${filename}&start_dt=${sendDate}&end_dt=${endDate}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
}).then(response => {
|
||||
const href = URL.createObjectURL(response.data);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = href;
|
||||
link.setAttribute('download', `${filename}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('VBPIndexExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Item
|
||||
export const ItemIndexView = async (token, start_dt, end_dt) => {
|
||||
export const ItemIndexView = async (token, start_dt, end_dt, itemId, deltaType) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/currency/item?start_dt=${start_dt}&end_dt=${end_dt}`, {
|
||||
const res = await Axios.get(`/api/v1/indicators/item/list?start_dt=${start_dt}&end_dt=${end_dt}&item_id=${itemId}&delta_type=${deltaType}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
@@ -278,27 +230,17 @@ export const ItemIndexView = async (token, start_dt, end_dt) => {
|
||||
}
|
||||
};
|
||||
|
||||
// Item 다운로드
|
||||
export const ItemIndexExport = async (token, filename, sendDate, endDate) => {
|
||||
// Assets
|
||||
export const AssetsIndexView = async (token, start_dt, end_dt, itemId, deltaType) => {
|
||||
try {
|
||||
await Axios.get(`/api/v1/indicators/currency/excel-down?file=${filename}&start_dt=${sendDate}&end_dt=${endDate}`, {
|
||||
const res = await Axios.get(`/api/v1/indicators/assets/list?start_dt=${start_dt}&end_dt=${end_dt}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
}).then(response => {
|
||||
const href = URL.createObjectURL(response.data);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = href;
|
||||
link.setAttribute('download', `${filename}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
});
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('ItemIndexExport Error', e);
|
||||
throw new Error('AssetsIndexView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -321,136 +263,3 @@ export const InstanceIndexView = async (token, data, start_dt, end_dt) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Instance 다운로드
|
||||
export const InstanceIndexExport = async (token, filename, data, sendDate, endDate) => {
|
||||
try {
|
||||
await Axios.get(
|
||||
`/api/v1/indicators/currency/excel-down?file=${filename}&search_key=${data ? data : ''}
|
||||
&start_dt=${sendDate}&end_dt=${endDate}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
},
|
||||
).then(response => {
|
||||
const href = URL.createObjectURL(response.data);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = href;
|
||||
link.setAttribute('download', `${filename}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('InstanceIndexExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Clothes
|
||||
export const ClothesIndexView = async (token, data, start_dt, end_dt) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/currency/clothes?search_key=${data ? data : ''}&start_dt=${start_dt}&end_dt=${end_dt}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('ClothesIndexView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Clothes 다운로드
|
||||
export const ClothesIndexExport = async (token, filename, data, sendDate, endDate) => {
|
||||
try {
|
||||
await Axios.get(
|
||||
`/api/v1/indicators/currency/excel-down?file=${filename}&search_key=${data ? data : ''}
|
||||
&start_dt=${sendDate}&end_dt=${endDate}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
},
|
||||
).then(response => {
|
||||
const href = URL.createObjectURL(response.data);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = href;
|
||||
link.setAttribute('download', `${filename}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('ClothesIndexExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// DAU
|
||||
export const DailyActiveUserView = async (token, start_dt, end_dt) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/dau/list?start_dt=${start_dt}&end_dt=${end_dt}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data.dau_list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('DailyActiveUserView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// DAU 다운로드
|
||||
export const DailyActiveUserExport = async (token, filename, sendDate, endDate) => {
|
||||
try {
|
||||
await Axios.get(`/api/v1/indicators/dau/excel-down?file=${filename}&start_dt=${sendDate}&end_dt=${endDate}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
}).then(response => {
|
||||
const href = URL.createObjectURL(response.data);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = href;
|
||||
link.setAttribute('download', `${filename}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('PlaytimeIndexExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Daily Medal
|
||||
export const DailyMedalView = async (token, start_dt, end_dt) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/indicators/daily-medal/list?start_dt=${start_dt}&end_dt=${end_dt}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data.daily_medal_list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('DailyMedalView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2,26 +2,31 @@
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
//아이템 리스트 조회
|
||||
export const ItemListView = async (token, searchType, data, status, restore, order, size, currentPage) => {
|
||||
export const ItemListAPI = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/items/list?search_type=${searchType ? searchType : ''}
|
||||
&search_key=${data ? data : ''}
|
||||
&orderby=${order}
|
||||
&page_no=${currentPage}
|
||||
&page_size=${size}
|
||||
`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
// console.log(res.data.data);
|
||||
const res = await Axios.post(`/api/v1/items/list`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
|
||||
throw new Error('ItemAPI Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const ItemDeleteAPI = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.delete(`/api/v1/items/delete`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
data: params,
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('ItemDelete Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -21,6 +21,24 @@ export const LandAuctionView = async (token, landType, landData, userType, userD
|
||||
}
|
||||
};
|
||||
|
||||
export const LandInfoData = async (token, landType, landData, landSize, category, status, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/land/info?land_type=${landType}&land_data=${landData}&land_size=${landSize}&category=${category}&status=${status}&start_dt=${startDate}&end_dt=${endDate}&orderby=${order}&page_no=${currentPage}
|
||||
&page_size=${size}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('LandInfoData Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 랜드 경매 상세보기
|
||||
export const LandAuctionDetailView = async (token, id) => {
|
||||
try {
|
||||
@@ -51,6 +69,21 @@ export const LandAuctionSingleRegist = async (token, params) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 랜드 소유권 변경 등록
|
||||
export const LandOwnedChangesRegist = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/land/change`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('LandAuctionSingleRegist Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 랜드 경매 수정
|
||||
export const LandAuctionModify = async (token, id, params) => {
|
||||
try {
|
||||
@@ -66,6 +99,21 @@ export const LandAuctionModify = async (token, id, params) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 랜드 소유권 변경 수정
|
||||
export const LandOwnedChangesModify = async (token, id, params) => {
|
||||
try {
|
||||
const res = await Axios.put(`/api/v1/land/change/${id}`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('LandAuctionModify Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 랜드 경매 삭제
|
||||
export const LandAuctionDelete = async (token, params, id) => {
|
||||
try {
|
||||
@@ -82,6 +130,22 @@ export const LandAuctionDelete = async (token, params, id) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 랜드 소유권 변경 예약 삭제
|
||||
export const LandOwnerChangesDelete = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.delete(`/api/v1/land/change/delete`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
data: params,
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('LandAuctionDelete Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const LandView = async (token) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
|
||||
313
src/apis/Log.js
Normal file
313
src/apis/Log.js
Normal file
@@ -0,0 +1,313 @@
|
||||
//운영 정보 관리 - 로그 api 연결
|
||||
|
||||
import { Axios, responseFileDownload } from '../utils';
|
||||
|
||||
// 비즈니스 로그 조회
|
||||
export const BusinessLogList = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/log/generic/list`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
timeout: 600000
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('BusinessLogList Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const BusinessLogExport = async (token, params) => {
|
||||
try {
|
||||
await Axios.post(`/api/v1/log/generic/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob'
|
||||
}).then(response => {
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: 'businessLog'
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('BusinessLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getExcelProgress = async (token, taskId) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/progress/${taskId}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Progress API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getCurrencyList = async (token, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/currency/list?start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getCurrencyList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const GameCurrencyLogExport = async (token, params, fileName) => {
|
||||
try {
|
||||
await Axios.post(`/api/v1/log/currency/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
}).then(response => {
|
||||
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: fileName
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameCurrencyLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getCurrencyDetailList = async (token, searchType, searchData, tranId, logAction, currencyType, amountDeltaType, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/currency/detail/list?search_type=${searchType}&search_data=${searchData}&tran_id=${tranId}
|
||||
&log_action=${logAction}¤cy_type=${currencyType}&amount_delta_type=${amountDeltaType}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getCurrencyDetailList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const GameCurrencyDetailLogExport = async (token, params, fileName) => {
|
||||
try {
|
||||
await Axios.post(`/api/v1/log/currency/detail/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
}).then(response => {
|
||||
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: fileName
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameCurrencyDetailLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getItemDetailList = async (token, searchType, searchData, itemId, tranId, logAction, itemLargeType, itemSmallType, countDeltaType, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/item/detail/list?search_type=${searchType}&search_data=${searchData}&tran_id=${tranId}&item_id=${itemId}
|
||||
&log_action=${logAction}&item_large_type=${itemLargeType}&item_small_type=${itemSmallType}&count_delta_type=${countDeltaType}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getItemDetailList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const GameItemDetailLogExport = async (token, params, fileName) => {
|
||||
try {
|
||||
await Axios.post(`/api/v1/log/item/detail/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
}).then(response => {
|
||||
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: fileName
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameItemDetailLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getCurrencyItemList = async (token, searchType, searchData, tranId, logAction, currencyType, amountDeltaType, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/currency-item/list?search_type=${searchType}&search_data=${searchData}&tran_id=${tranId}
|
||||
&log_action=${logAction}¤cy_type=${currencyType}&amount_delta_type=${amountDeltaType}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getItemDetailList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const GameCurrencyItemLogExport = async (token, params, fileName) => {
|
||||
try {
|
||||
|
||||
await Axios.post(`/api/v1/log/currency-item/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
}).then(response => {
|
||||
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: fileName
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameCurrencyItemLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserCreateList = async (token, searchType, searchData, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/user/create/list?search_type=${searchType}&search_data=${searchData}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getUserCreateList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserLoginDetailList = async (token, searchType, searchData, tranId, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/user/login/list?search_type=${searchType}&search_data=${searchData}&tran_id=${tranId}
|
||||
&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getUserLoginDetailList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const GameUserCreateLogExport = async (token, params, fileName) => {
|
||||
try {
|
||||
await Axios.post(`/api/v1/log/user/create/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
}).then(response => {
|
||||
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: fileName
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameUserCreateLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const GameUserLoginLogExport = async (token, params, fileName) => {
|
||||
try {
|
||||
await Axios.post(`/api/v1/log/user/login/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
}).then(response => {
|
||||
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: fileName
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameUserLoginLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserSnapshotList = async (token, searchType, searchData, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const response = await Axios.get(`/api/v1/log/user/snapshot/list?search_type=${searchType}&search_data=${searchData}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('getUserSnapshotList API error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const GameUserSnapshotLogExport = async (token, params, fileName) => {
|
||||
try {
|
||||
await Axios.post(`/api/v1/log/user/snapshot/excel-export`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
}).then(response => {
|
||||
|
||||
responseFileDownload(response, {
|
||||
defaultFileName: fileName
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('GameUserSnapshotLogExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -72,7 +72,7 @@ export const MailModify = async (token, id, params) => {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data.list;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MailModify Error', e);
|
||||
@@ -88,7 +88,7 @@ export const MailDelete = async (token, params, id) => {
|
||||
data: { list: params },
|
||||
});
|
||||
|
||||
return res.data.data.list;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MailDelete Error', e);
|
||||
@@ -147,7 +147,7 @@ export const MailIsItem = async (token, params) => {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MailItemCheck Error', e);
|
||||
|
||||
113
src/apis/Menu.js
Normal file
113
src/apis/Menu.js
Normal file
@@ -0,0 +1,113 @@
|
||||
//운영서비스 관리 - 메뉴배너 api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
// 리스트 조회
|
||||
export const MenuBannerView = async (token, searchData, status, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/menu/banner/list?search_data=${searchData}&status=${status}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MenuBannerView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 상세보기
|
||||
export const MenuBannerDetailView = async (token, id) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/menu/banner/detail/${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MenuBannerDetailView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 등록
|
||||
export const MenuBannerSingleRegist = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/menu/banner`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MenuBannerSingleRegist Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 수정
|
||||
export const MenuBannerModify = async (token, id, params) => {
|
||||
try {
|
||||
const res = await Axios.put(`/api/v1/menu/banner/${id}`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MenuBannerModify Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제
|
||||
export const MenuBannerDelete = async (token, id) => {
|
||||
try {
|
||||
const res = await Axios.delete(`/api/v1/menu/banner/delete?id=${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MenuBannerDelete Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const MenuImageUpload = async (token, file) => {
|
||||
const exelFile = new FormData();
|
||||
exelFile.append('file', file);
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/menu/image-upload`, exelFile, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MenuImageUpload', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const MenuImageDelete = async (token, filename) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/menu/image-delete?file=${filename}`, {
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
});
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('MenuImageDelete', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
21
src/apis/OpenAI.js
Normal file
21
src/apis/OpenAI.js
Normal file
@@ -0,0 +1,21 @@
|
||||
//AI api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
|
||||
export const AnalyzeAI = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post('/api/v1/ai/analyze', params, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('analyzeAI Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
99
src/apis/Rank.js
Normal file
99
src/apis/Rank.js
Normal file
@@ -0,0 +1,99 @@
|
||||
//운영서비스 관리 - 랭킹 스케줄 api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
// 리스트 조회
|
||||
export const RankingScheduleView = async (token, title, content, status, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/rank/schedule/list?title=${title}&content=${content}&status=${status}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RankingScheduleView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 전투시스템 상세보기
|
||||
export const RankingScheduleDetailView = async (token, id) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/rank/schedule/detail/${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RankingScheduleDetailView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 랭킹스케줄 등록
|
||||
export const RankingScheduleSingleRegist = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/rank/schedule`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RankingScheduleSingleRegist Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 랭킹스케줄 수정
|
||||
export const RankingScheduleModify = async (token, id, params) => {
|
||||
try {
|
||||
const res = await Axios.put(`/api/v1/rank/schedule/${id}`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RankingScheduleModify Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 랭킹스케줄 삭제
|
||||
export const RankingScheduleDelete = async (token, id) => {
|
||||
try {
|
||||
const res = await Axios.delete(`/api/v1/rank/schedule/delete?id=${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RankingScheduleDelete Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const RankingDataView = async (token) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/dictionary/ranking/list`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data.ranking_list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RankingDataView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
98
src/apis/RewardEvent.js
Normal file
98
src/apis/RewardEvent.js
Normal file
@@ -0,0 +1,98 @@
|
||||
//운영서비스 관리 - 이벤트 api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
// 이벤트 리스트 조회
|
||||
export const RewardEventView = async (token, title, content, status, startDate, endDate, order, size, currentPage) => {
|
||||
try {
|
||||
const res = await Axios.get(
|
||||
`/api/v1/event/list?title=${title}&content=${content}&status=${status}&start_dt=${startDate}&end_dt=${endDate}
|
||||
&orderby=${order}&page_no=${currentPage}&page_size=${size}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
|
||||
return res.data.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RewardEventView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 이벤트 상세보기
|
||||
export const RewardEventDetailView = async (token, id) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/event/detail/${id}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data.detail;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RewardEventDetailView Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 이벤트 등록
|
||||
export const RewardEventSingleRegist = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/event`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RewardEventSingleRegist Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 우편 수정
|
||||
export const RewardEventModify = async (token, id, params) => {
|
||||
try {
|
||||
const res = await Axios.put(`/api/v1/event/${id}`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RewardEventModify Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 우편 삭제
|
||||
export const RewardEventDelete = async (token, params, id) => {
|
||||
try {
|
||||
const res = await Axios.delete(`/api/v1/event/delete`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
data: { list: params },
|
||||
});
|
||||
|
||||
return res.data.data.list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('RewardEventDelete Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 이벤트 우편 아이템 확인
|
||||
export const EventIsItem = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/event/item`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('EventIsItem Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -12,7 +12,7 @@ export const UserView = async (token, searchType, searchKey) => {
|
||||
{ headers: { Authorization: `Bearer ${token}` } },
|
||||
);
|
||||
|
||||
return res.data.data.result;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('UserView Error', e);
|
||||
@@ -42,7 +42,7 @@ export const UserChangeNickName = async (token, params) => {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res;
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('UserChangeNickName Error', e);
|
||||
@@ -65,6 +65,20 @@ export const UserChangeAdminLevel = async (token, params) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const UserKick = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.put('/api/v1/users/user-kick', params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('UserKick Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 아바타 조회
|
||||
export const UserAvatarView = async (token, guid) => {
|
||||
try {
|
||||
@@ -171,6 +185,21 @@ export const UserQuestView = async (token, guid) => {
|
||||
}
|
||||
};
|
||||
|
||||
//퀘스트 테스크 완료
|
||||
export const UserQuestTaskComplete = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/users/quest/task`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('UserQuestTaskComplete Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 친구목록 조회
|
||||
export const UserFriendListView = async (token, guid) => {
|
||||
try {
|
||||
@@ -187,9 +216,9 @@ export const UserFriendListView = async (token, guid) => {
|
||||
};
|
||||
|
||||
// 우편 조회
|
||||
export const UserMailView = async (token, guid, option) => {
|
||||
export const UserMailView = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/users/mail?guid=${guid}&type=${option}`, {
|
||||
const res = await Axios.post(`/api/v1/users/mail`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
//운영서비스 관리 - 화이트 리스트 api 연결
|
||||
|
||||
import { Axios } from '../utils';
|
||||
|
||||
export const WhiteListData = async token => {
|
||||
try {
|
||||
const res = await Axios.get(`/api/v1/white-list/list`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
return res.data.data.list;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('whiteList Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 선택 삭제
|
||||
export const WhiteListDelete = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.delete(`/api/v1/white-list`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
data: { list: params },
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('WhiteListDelete', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 선택 승인
|
||||
export const WhiteListAllow = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.patch(
|
||||
`/api/v1/white-list`,
|
||||
{ list: params },
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('WhiteListAllow', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 화이트 리스트 등록 (단일)
|
||||
export const WhiteListRegist = async (token, params) => {
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/white-list`, params, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('WhiteListRegist', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 화이트리스트 엑셀 업로더
|
||||
export const WhiteListExelUpload = async (token, file) => {
|
||||
const exelFile = new FormData();
|
||||
exelFile.append('file', file);
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/white-list/excel-upload`, exelFile, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('WhiteListExelUpload', e);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 화이트 리스트 등록(복수) -> 등록하는 것임
|
||||
export const WhiteListMultiRegsit = async (token, file) => {
|
||||
const exelFile = new FormData();
|
||||
exelFile.append('file', file);
|
||||
try {
|
||||
const res = await Axios.post(`/api/v1/white-list/multiPost`, exelFile, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
throw new Error('WhiteListMultiRegsit', e);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
export const WhiteListExport = async (token, fileName) => {
|
||||
try{
|
||||
await Axios.get(`/api/v1/white-list/excelDownLoad`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'blob',
|
||||
}).then(response => {
|
||||
const href = URL.createObjectURL(response.data);
|
||||
|
||||
const link = document.createElement('a');
|
||||
const fileName = 'Caliverse_whitelist.xlsx';
|
||||
link.href = href;
|
||||
link.setAttribute('download', `${fileName}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
})
|
||||
|
||||
}catch(e) {
|
||||
if(e instanceof Error) {
|
||||
throw new Error('WhiteListExport Error', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,14 +1,42 @@
|
||||
import { createAPIModule } from '../utils/apiService';
|
||||
|
||||
import * as APIConfigs from '../assets/data/apis'
|
||||
|
||||
export * from './Admin';
|
||||
export * from './Auth';
|
||||
export * from './Group';
|
||||
export * from './History';
|
||||
export * from './Mail';
|
||||
export * from './Notice';
|
||||
export * from './WhiteList';
|
||||
export * from './BlackList';
|
||||
export * from './Users';
|
||||
export * from './Indicators';
|
||||
export * from './Item';
|
||||
export * from './Event';
|
||||
export * from './RewardEvent';
|
||||
export * from './Calium';
|
||||
export * from './Land';
|
||||
export * from './Menu';
|
||||
// export * from './OpenAI';
|
||||
export * from './Log';
|
||||
export * from './Data';
|
||||
export * from './Dictionary';
|
||||
export * from './Rank';
|
||||
export * from './Event';
|
||||
|
||||
const apiModules = {};
|
||||
const allApis = {};
|
||||
|
||||
// 각 API 설정에 대해 모듈 생성
|
||||
Object.entries(APIConfigs).forEach(([configName, config]) => {
|
||||
const moduleName = configName.replace(/API$/, ''); // "userAPI" -> "user"
|
||||
apiModules[moduleName] = createAPIModule(config);
|
||||
|
||||
// 모든 API 함수 추출해서 allApis에 복사
|
||||
Object.entries(apiModules[moduleName]).forEach(([fnName, fn]) => {
|
||||
allApis[fnName] = fn;
|
||||
});
|
||||
});
|
||||
|
||||
export const Modules = apiModules;
|
||||
|
||||
// export const ItemAPI = createAPIModule(itemAPIConfig);
|
||||
@@ -7,5 +7,14 @@ export const NONE = 'NONE';
|
||||
export const ONE_MINUTE_MS = 60000;
|
||||
export const ONE_MINUTE_SECOND = 60;
|
||||
export const AUCTION_MIN_MINUTE_TIME = 15; // 15분
|
||||
export const IMAGE_MAX_SIZE = 5242880;
|
||||
export const STORAGE_MAIL_COPY = 'copyMailData';
|
||||
export const STORAGE_BUSINESS_LOG_SEARCH = 'businessLogSearchParam';
|
||||
export const STORAGE_GAME_LOG_CURRENCY_SEARCH = 'gameLogCurrencySearchParam';
|
||||
export const STORAGE_GAME_LOG_ITEM_SEARCH = 'gameLogItemSearchParam';
|
||||
export const STORAGE_GAME_LOG_USER_CREATE_SEARCH = 'gameLogUserCreateSearchParam';
|
||||
export const STORAGE_GAME_LOG_USER_LOGIN_SEARCH = 'gameLogUserLoginSearchParam';
|
||||
export const LOG_ACTION_FAIL_CALIUM_ECHO = 'FailCaliumEchoSystem';
|
||||
export const BATTLE_EVENT_OPERATION_TIME_WAIT_SECONDS = 300;
|
||||
|
||||
export { INITIAL_PAGE_SIZE, INITIAL_CURRENT_PAGE, INITIAL_PAGE_LIMIT };
|
||||
|
||||
18
src/assets/data/apis/eventAPI.json
Normal file
18
src/assets/data/apis/eventAPI.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"baseUrl": "/api/v1/world-event",
|
||||
"endpoints": {
|
||||
"EventView": {
|
||||
"method": "GET",
|
||||
"url": "/list",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "query"
|
||||
},
|
||||
"EventDetailView": {
|
||||
"method": "GET",
|
||||
"url": "/detail/:id",
|
||||
"dataPath": "data.data",
|
||||
"paramFormat": "query",
|
||||
"paramMapping": ["id"]
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/assets/data/apis/historyAPI.json
Normal file
18
src/assets/data/apis/historyAPI.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"baseUrl": "/api/v1/history",
|
||||
"endpoints": {
|
||||
"LogViewList": {
|
||||
"method": "GET",
|
||||
"url": "/list",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "query"
|
||||
},
|
||||
"LogviewDetail": {
|
||||
"method": "GET",
|
||||
"url": "/detail/:id",
|
||||
"dataPath": "data.data",
|
||||
"paramFormat": "query",
|
||||
"paramMapping": ["id"]
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/assets/data/apis/index.js
Normal file
15
src/assets/data/apis/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import itemAPI from './itemAPI.json';
|
||||
import menuBannerAPI from './menuBannerAPI.json';
|
||||
import historyAPI from './historyAPI.json';
|
||||
import eventAPI from './eventAPI.json';
|
||||
import rankingAPI from './rankingAPI.json';
|
||||
import metaCraftingAPI from './metaCraftingAPI.json';
|
||||
|
||||
export {
|
||||
itemAPI,
|
||||
menuBannerAPI,
|
||||
historyAPI,
|
||||
eventAPI,
|
||||
rankingAPI,
|
||||
metaCraftingAPI
|
||||
};
|
||||
17
src/assets/data/apis/itemAPI.json
Normal file
17
src/assets/data/apis/itemAPI.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"baseUrl": "/api/v1/items",
|
||||
"endpoints": {
|
||||
"ItemList": {
|
||||
"method": "POST",
|
||||
"url": "/list",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "body"
|
||||
},
|
||||
"ItemDelete": {
|
||||
"method": "DELETE",
|
||||
"url": "/delete",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "body"
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/assets/data/apis/menuBannerAPI.json
Normal file
48
src/assets/data/apis/menuBannerAPI.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"baseUrl": "/api/v1/menu",
|
||||
"endpoints": {
|
||||
"MenuBannerView": {
|
||||
"method": "GET",
|
||||
"url": "/banner/list",
|
||||
"dataPath": "data.data",
|
||||
"paramFormat": "query"
|
||||
},
|
||||
"MenuBannerDetailView": {
|
||||
"method": "GET",
|
||||
"url": "/banner/detail/:id",
|
||||
"dataPath": "data.data",
|
||||
"paramFormat": "query",
|
||||
"paramMapping": ["id"]
|
||||
},
|
||||
"MenuBannerSingleRegist": {
|
||||
"method": "POST",
|
||||
"url": "/banner",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "body"
|
||||
},
|
||||
"MenuBannerModify": {
|
||||
"method": "PUT",
|
||||
"url": "/banner/:id",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "body"
|
||||
},
|
||||
"MenuBannerDelete": {
|
||||
"method": "DELETE",
|
||||
"url": "/banner/delete",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "body"
|
||||
},
|
||||
"MenuImageUpload": {
|
||||
"method": "POST",
|
||||
"url": "/image-upload",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "body"
|
||||
},
|
||||
"MenuImageDelete": {
|
||||
"method": "DELETE",
|
||||
"url": "/image-delete",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "body"
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/assets/data/apis/metaCraftingAPI.json
Normal file
11
src/assets/data/apis/metaCraftingAPI.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"baseUrl": "/api/v1/dictionary/craft",
|
||||
"endpoints": {
|
||||
"getCraftingDictionaryList": {
|
||||
"method": "GET",
|
||||
"url": "/list",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "query"
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/assets/data/apis/rankingAPI.json
Normal file
18
src/assets/data/apis/rankingAPI.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"baseUrl": "/api/v1/rank/schedule",
|
||||
"endpoints": {
|
||||
"RankingScheduleView": {
|
||||
"method": "GET",
|
||||
"url": "/list",
|
||||
"dataPath": "data",
|
||||
"paramFormat": "query"
|
||||
},
|
||||
"RankingScheduleDetailView": {
|
||||
"method": "GET",
|
||||
"url": "/detail/:id",
|
||||
"dataPath": "data.data",
|
||||
"paramFormat": "query",
|
||||
"paramMapping": ["id"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,14 @@ export const benItems = [
|
||||
"19010005"
|
||||
];
|
||||
|
||||
export const historyBenField = [
|
||||
"create_by",
|
||||
"create_dt",
|
||||
"update_by",
|
||||
"update_dt",
|
||||
"id"
|
||||
]
|
||||
|
||||
export const HourList = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'];
|
||||
|
||||
export const MinuteList = [
|
||||
@@ -24,17 +32,45 @@ export const caliumRequestInitData = {
|
||||
content: '',
|
||||
}
|
||||
|
||||
export const ORDER_OPTIONS = {
|
||||
asc: [
|
||||
{ value: 'ASC', label: '오름차순' },
|
||||
{ value: 'DESC', label: '내림차순' }
|
||||
],
|
||||
desc: [
|
||||
{ value: 'DESC', label: '내림차순' },
|
||||
{ value: 'ASC', label: '오름차순' }
|
||||
],
|
||||
};
|
||||
|
||||
export const PAGE_SIZE_OPTIONS = {
|
||||
default: [
|
||||
{ value: '50', label: '50개' },
|
||||
{ value: '100', label: '100개' }
|
||||
],
|
||||
B: [
|
||||
{ value: '500', label: '500개' },
|
||||
{ value: '1000', label: '1000개' },
|
||||
{ value: '5000', label: '5000개' },
|
||||
{ value: '10000', label: '10000개' }
|
||||
],
|
||||
};
|
||||
|
||||
export const STATUS_STYLES = {
|
||||
COMPLETE: {
|
||||
background: '#58AB62',
|
||||
color: 'white'
|
||||
},
|
||||
EXPIRATION: {
|
||||
background: '#58AB62',
|
||||
color: 'white'
|
||||
},
|
||||
WAIT: {
|
||||
background: '#DEBB46',
|
||||
background: '#FAAD14',
|
||||
color: 'black'
|
||||
},
|
||||
FAIL: {
|
||||
background: '#D33B27',
|
||||
background: '#ff4d4f',
|
||||
color: 'white'
|
||||
},
|
||||
FINISH: {
|
||||
@@ -42,11 +78,11 @@ export const STATUS_STYLES = {
|
||||
color: 'black'
|
||||
},
|
||||
REJECT: {
|
||||
background: '#D33B27',
|
||||
background: '#ff4d4f',
|
||||
color: 'white'
|
||||
},
|
||||
CANCEL: {
|
||||
background: '#D33B27',
|
||||
background: '#ff4d4f',
|
||||
color: 'white'
|
||||
},
|
||||
RESV_START: {
|
||||
@@ -57,6 +93,10 @@ export const STATUS_STYLES = {
|
||||
background: '#4287f5',
|
||||
color: 'white'
|
||||
},
|
||||
INPROGRESS: {
|
||||
background: '#4287f5',
|
||||
color: 'white'
|
||||
},
|
||||
AUCTION_END: {
|
||||
background: '#A37FB8',
|
||||
color: 'white'
|
||||
@@ -66,15 +106,115 @@ export const STATUS_STYLES = {
|
||||
color: 'white'
|
||||
},
|
||||
REGISTER: {
|
||||
background: '#DEBB46',
|
||||
background: '#FAAD14',
|
||||
color: 'black'
|
||||
},
|
||||
STOP: {
|
||||
background: '#FFB59B',
|
||||
color: 'white'
|
||||
},
|
||||
DELETE: {
|
||||
background: '#FFB59B',
|
||||
color: 'white'
|
||||
},
|
||||
RUNNING: {
|
||||
background: '#4287f5',
|
||||
color: 'white'
|
||||
},
|
||||
};
|
||||
|
||||
export const FieldLabels = {
|
||||
// DynamoDB 필드
|
||||
'attribFieldName': '속성 명',
|
||||
'pk': '파티션 키',
|
||||
'sk': '정렬 키',
|
||||
'DocType': '문서 타입',
|
||||
'CreatedDateTime': '생성 일시',
|
||||
'UpdatedDateTime': '수정 일시',
|
||||
'DeletedDateTime': '삭제 일시',
|
||||
'RestoredDateTime': '복원 일시',
|
||||
'INSERT': '등록',
|
||||
'UPDATE': '수정',
|
||||
'DELETE': '삭제',
|
||||
|
||||
//기본
|
||||
'id': 'ID',
|
||||
'userId': '사용자 ID',
|
||||
'userIP': '사용자 IP',
|
||||
'timestamp': '타임스탬프',
|
||||
'message': '메시지',
|
||||
'tranId': '트랜잭션 ID',
|
||||
'group_id': '그룹 ID',
|
||||
'update_dt': '수정 일시',
|
||||
'updateDt': '수정 일시',
|
||||
'update_by': '수정자',
|
||||
'create_dt': '생성 일시',
|
||||
'createDt': '생성 일시',
|
||||
'create_by': '생성자',
|
||||
'status': '상태',
|
||||
'deleted': '삭제 여부',
|
||||
|
||||
// 이벤트 필드 관련
|
||||
'eventId': '이벤트 ID',
|
||||
'eventName': '이벤트 명',
|
||||
'repeatType': '반복 타입',
|
||||
'eventOperationTime': '운영 시간(초)',
|
||||
'eventStartDt': '시작 시간',
|
||||
'eventEndDt': '종료 시간',
|
||||
'roundTime': '라운드 시간(초)',
|
||||
'roundCount': '라운드 수',
|
||||
'hotTime': '핫타임',
|
||||
'configId': '설정 ID',
|
||||
'rewardGroupId': '보상 그룹 ID',
|
||||
'attrib_type': '속성 타입',
|
||||
'event_id': '이벤트 ID',
|
||||
'is_active': '활성화 여부',
|
||||
'start_day': '시작일',
|
||||
'start_hour': '시작 시간',
|
||||
'start_min': '시작 분',
|
||||
'end_date': '종료 일시',
|
||||
'instance_id': '인스턴스 ID',
|
||||
'once_period_type': '주기 타입',
|
||||
'day_of_week_type': '요일 타입',
|
||||
'ffa_config_data_id': 'FFA 설정 ID',
|
||||
'ffa_reward_group_id': 'FFA 보상 그룹 ID',
|
||||
'ffa_hot_time': 'FFA 핫타임',
|
||||
'round_count': '라운드 수',
|
||||
|
||||
//dictionary
|
||||
'max_count': '최대 보유 가능 수량',
|
||||
'stack_max_count': '최대 스택 가능 수량',
|
||||
'expire_type': '아이템 만료 타입',
|
||||
'expire_start_dt': '만료 시작 시간',
|
||||
'expire_end_dt': '만료 종료 시간',
|
||||
'expire_time_sec': '만료 시간 연장 여부',
|
||||
'user_tradable': '유저 간 거래 가능 여부',
|
||||
'system_tradable': '상점에서 판매 가능 여부',
|
||||
'throwable': '버리기 가능 여부',
|
||||
'cart_buy': '상점에서 구매 가능 여부',
|
||||
'rarity': '희귀도',
|
||||
'default_attrib': '기본 속성',
|
||||
'attrib_random_group': '랜덤 그룹',
|
||||
'item_set': '아이템 세트',
|
||||
'buff': '아이템 사용 시 획득 버프',
|
||||
'dress_slot_type': '착용 부위',
|
||||
'product_link': '제품 URL',
|
||||
'prop_small_type': '제작 아이템 그룹',
|
||||
'gacha_group_id': '랜덤박스 그룹 ID',
|
||||
'ugq_action': 'UGQ 사용 가능 여부',
|
||||
'linked_land': '연결된 랜드 ID',
|
||||
};
|
||||
|
||||
export const historyTables = {
|
||||
userBlock: 'black_list',
|
||||
landAuction: 'land_auction',
|
||||
landOwnerChange: 'land_ownership_changes',
|
||||
rewardEvent: 'event',
|
||||
mail: 'mail',
|
||||
notice: 'notice',
|
||||
battleEvent: 'battle_event',
|
||||
caliumRequest: 'calium_request',
|
||||
menuBanner: 'menu_banner',
|
||||
event: 'world_event',
|
||||
rankingSchedule: 'ranking_schedule',
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export {authType, ivenTabType, modalTypes, TabList, tattooSlot, commonStatus, ViewTitleCountType, landAuctionStatusType} from './types'
|
||||
export {authType, ivenTabType, modalTypes, tattooSlot, commonStatus, ViewTitleCountType, landAuctionStatusType} from './types'
|
||||
export {
|
||||
mailSendType,
|
||||
mailType,
|
||||
@@ -7,17 +7,27 @@ export {
|
||||
adminLevelType,
|
||||
logOption,
|
||||
eventStatus,
|
||||
wellType,
|
||||
currencyItemCode,
|
||||
blockStatus,
|
||||
blockSanctions,
|
||||
blockPeriod,
|
||||
blockType,
|
||||
caliumStatus,
|
||||
landSize,
|
||||
userSearchType,
|
||||
userType,
|
||||
landAuctionStatus,
|
||||
landSearchType,
|
||||
CurrencyType,
|
||||
languageType
|
||||
languageType,
|
||||
opLandCategoryType,
|
||||
opLandOwnedType,
|
||||
opSuccessType,
|
||||
opPickupType,
|
||||
opReadType,
|
||||
opYNType,
|
||||
opUserSessionType,
|
||||
opMailType,
|
||||
amountDeltaType,
|
||||
TabUserList
|
||||
} from './options'
|
||||
export {benItems, MinuteList, HourList, caliumRequestInitData, STATUS_STYLES, months} from './data'
|
||||
export {benItems, MinuteList, HourList, caliumRequestInitData, STATUS_STYLES, months, PAGE_SIZE_OPTIONS, ORDER_OPTIONS} from './data'
|
||||
@@ -1,4 +1,4 @@
|
||||
import { authType } from './types';
|
||||
import { adminAuthLevel, authType } from './types';
|
||||
|
||||
export const menuConfig = {
|
||||
usermanage: {
|
||||
@@ -11,13 +11,17 @@ export const menuConfig = {
|
||||
confirm: authType.adminSearchConfirm,
|
||||
update: authType.adminSearchUpdate,
|
||||
delete: authType.adminSearchDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
logview: {
|
||||
title: '사용 이력 조회',
|
||||
permissions: {
|
||||
read: authType.adminLogSearchRead
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
authsetting: {
|
||||
title: '권한 설정',
|
||||
@@ -25,14 +29,25 @@ export const menuConfig = {
|
||||
read: authType.authoritySettingRead,
|
||||
update: authType.authoritySettingUpdate,
|
||||
delete: authType.authoritySettingDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
caliumrequest: {
|
||||
title: '칼리움 요청',
|
||||
permissions: {
|
||||
read: authType.caliumRequestRead,
|
||||
update: authType.caliumRequestUpdate
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
datainit: {
|
||||
title: '데이터 초기화',
|
||||
permissions: {},
|
||||
view: false,
|
||||
test: true,
|
||||
authLevel: adminAuthLevel.MASTER
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -43,13 +58,17 @@ export const menuConfig = {
|
||||
title: '유저 지표',
|
||||
permissions: {
|
||||
read: authType.userIndicatorsRead
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
economicindex: {
|
||||
title: '경제 지표',
|
||||
permissions: {
|
||||
read: authType.economicIndicatorsRead
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -62,27 +81,59 @@ export const menuConfig = {
|
||||
read: authType.userSearchRead,
|
||||
update: authType.userSearchUpdate,
|
||||
delete: authType.userSearchDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
landview: {
|
||||
title: '랜드 조회',
|
||||
title: '랜드 정보 조회',
|
||||
permissions: {
|
||||
read: authType.landRead,
|
||||
update: authType.landUpdate,
|
||||
delete: authType.landDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
gamelogview: {
|
||||
title: '게임 로그 조회',
|
||||
permissions: {
|
||||
read: authType.gameLogRead
|
||||
}
|
||||
},
|
||||
view: false,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
cryptview: {
|
||||
title: '크립토 조회',
|
||||
businesslogview: {
|
||||
title: '비즈니스 로그 조회',
|
||||
permissions: {
|
||||
read: authType.cryptoRead
|
||||
}
|
||||
read: authType.businessLogRead
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
itemdictionary: {
|
||||
title: '아이템 백과사전 조회',
|
||||
permissions: {
|
||||
read: authType.itemDictionaryRead
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
craftdictionary: {
|
||||
title: '제작 아이템 조회',
|
||||
permissions: {
|
||||
read: authType.craftingDictionaryRead
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
rankmanage: {
|
||||
title: '랭킹 점수 관리',
|
||||
permissions: {
|
||||
read: authType.rankManagerRead
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -95,7 +146,9 @@ export const menuConfig = {
|
||||
read: authType.inGameRead,
|
||||
update: authType.inGameUpdate,
|
||||
delete: authType.inGameDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
mail: {
|
||||
title: '우편',
|
||||
@@ -103,7 +156,9 @@ export const menuConfig = {
|
||||
read: authType.mailRead,
|
||||
update: authType.mailUpdate,
|
||||
delete: authType.mailDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
userblock: {
|
||||
title: '이용자 제재',
|
||||
@@ -111,23 +166,29 @@ export const menuConfig = {
|
||||
read: authType.blackListRead,
|
||||
update: authType.blackListUpdate,
|
||||
delete: authType.blackListDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
reportlist: {
|
||||
title: '신고내역',
|
||||
permissions: {
|
||||
read: authType.reportRead,
|
||||
update: authType.reportUpdate,
|
||||
delete: authType.reportDelete
|
||||
}
|
||||
},
|
||||
event: {
|
||||
// reportlist: {
|
||||
// title: '신고내역',
|
||||
// permissions: {
|
||||
// read: authType.reportRead,
|
||||
// update: authType.reportUpdate,
|
||||
// delete: authType.reportDelete
|
||||
// },
|
||||
// view: true,
|
||||
// authLevel: adminAuthLevel.NONE
|
||||
// },
|
||||
rewardevent: {
|
||||
title: '보상 이벤트 관리',
|
||||
permissions: {
|
||||
read: authType.eventRead,
|
||||
update: authType.eventUpdate,
|
||||
delete: authType.eventDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
landauction: {
|
||||
title: '랜드 경매 관리',
|
||||
@@ -135,7 +196,9 @@ export const menuConfig = {
|
||||
read: authType.landAuctionRead,
|
||||
update: authType.landAuctionUpdate,
|
||||
delete: authType.landAuctionDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
battleevent: {
|
||||
title: '전투시스템 타입 스케줄러',
|
||||
@@ -143,7 +206,49 @@ export const menuConfig = {
|
||||
read: authType.battleEventRead,
|
||||
update: authType.battleEventUpdate,
|
||||
delete: authType.battleEventDelete
|
||||
}
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
items: {
|
||||
title: '아이템 관리',
|
||||
permissions: {
|
||||
read: authType.itemRead,
|
||||
update: authType.itemUpdate,
|
||||
delete: authType.itemDelete
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
menubanner: {
|
||||
title: '메뉴 배너 관리',
|
||||
permissions: {
|
||||
read: authType.menuBannerRead,
|
||||
update: authType.menuBannerUpdate,
|
||||
delete: authType.menuBannerDelete
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
ranking: {
|
||||
title: '랭킹 스케줄러',
|
||||
permissions: {
|
||||
read: authType.rankingRead,
|
||||
update: authType.rankingUpdate,
|
||||
delete: authType.rankingDelete
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
event: {
|
||||
title: '통합 이벤트 관리',
|
||||
permissions: {
|
||||
read: authType.worldEventRead,
|
||||
update: authType.worldEventUpdate,
|
||||
delete: authType.worldEventDelete
|
||||
},
|
||||
view: true,
|
||||
authLevel: adminAuthLevel.NONE
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
96
src/assets/data/pages/businessLogSearch.json
Normal file
96
src/assets/data/pages/businessLogSearch.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchType": "GUID",
|
||||
"searchData": "",
|
||||
"logAction": "None",
|
||||
"logDomain": "BASE",
|
||||
"tran_id": "",
|
||||
"startDate": "",
|
||||
"endDate": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 500,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "select",
|
||||
"id": "searchType",
|
||||
"optionsRef": "userSearchType2",
|
||||
"col": 1,
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchData",
|
||||
"placeholder": "대상 입력",
|
||||
"width": "300px",
|
||||
"col": 1,
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "조회 일자",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchContent",
|
||||
"label": "우편 내용",
|
||||
"placeholder": "우편 내용(공백으로 구분)",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "sendType",
|
||||
"label": "발송 방식",
|
||||
"optionsRef": "mailSendType",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "발송 상태",
|
||||
"optionsRef": "mailSendStatus",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "mailType",
|
||||
"label": "우편 타입",
|
||||
"optionsRef": "mailType",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "receiveType",
|
||||
"label": "수신 대상",
|
||||
"optionsRef": "mailReceiveType",
|
||||
"col": 2
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"functionName": "MailView",
|
||||
"loadOnMount": true,
|
||||
"paramsMapping": [
|
||||
"searchTitle",
|
||||
"searchContent",
|
||||
"sendType",
|
||||
"status",
|
||||
"mailType",
|
||||
"receiveType",
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"},
|
||||
"orderBy",
|
||||
"pageSize",
|
||||
"currentPage"
|
||||
],
|
||||
"pageField": "currentPage",
|
||||
"pageSizeField": "pageSize",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
53
src/assets/data/pages/caliumRequestSearch.json
Normal file
53
src/assets/data/pages/caliumRequestSearch.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchContent": "",
|
||||
"status": "ALL",
|
||||
"startDate": "",
|
||||
"endDate": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "등록 일자",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchContent",
|
||||
"label": "요청 내용",
|
||||
"placeholder": "요청 내용",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "요청 상태",
|
||||
"optionsRef": "caliumStatus",
|
||||
"col": 1
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"functionName": "CaliumRequestView",
|
||||
"loadOnMount": true,
|
||||
"paramsMapping": [
|
||||
"searchContent",
|
||||
"status",
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"},
|
||||
"orderBy",
|
||||
"pageSize",
|
||||
"currentPage"
|
||||
],
|
||||
"pageField": "currentPage",
|
||||
"pageSizeField": "pageSize",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
48
src/assets/data/pages/eventSearch.json
Normal file
48
src/assets/data/pages/eventSearch.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchData": "",
|
||||
"status": "ALL",
|
||||
"startDate": "",
|
||||
"endDate": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchData",
|
||||
"label": "제목",
|
||||
"placeholder": "제목 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "상태",
|
||||
"optionsRef": "opMenuBannerStatus",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "기간",
|
||||
"col": 1
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"endpointName": "EventView",
|
||||
"loadOnMount": true,
|
||||
"paramTransforms": [
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"}
|
||||
],
|
||||
"pageField": "page_no",
|
||||
"pageSizeField": "page_size",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
119
src/assets/data/pages/eventTable.json
Normal file
119
src/assets/data/pages/eventTable.json
Normal file
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"id": "eventTable",
|
||||
"selection": {
|
||||
"type": "single",
|
||||
"idField": "id"
|
||||
},
|
||||
"header": {
|
||||
"countType": "total",
|
||||
"orderType": "desc",
|
||||
"pageType": "default",
|
||||
"buttons": [
|
||||
{
|
||||
"id": "delete",
|
||||
"text": "선택 삭제",
|
||||
"theme": "line",
|
||||
"disableWhen": "noSelection",
|
||||
"requiredAuth": "worldEventDelete",
|
||||
"action": "delete"
|
||||
},
|
||||
{
|
||||
"id": "register",
|
||||
"text": "통합 이벤트 등록",
|
||||
"theme": "primary",
|
||||
"requiredAuth": "worldEventUpdate",
|
||||
"action": "regist"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"id": "checkbox",
|
||||
"type": "checkbox",
|
||||
"width": "40px",
|
||||
"title": ""
|
||||
},
|
||||
{
|
||||
"id": "row_num",
|
||||
"type": "text",
|
||||
"width": "70px",
|
||||
"title": "번호"
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"type": "status",
|
||||
"width": "120px",
|
||||
"title": "상태",
|
||||
"option_name": "opCommonStatus"
|
||||
},
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"title": "제목",
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"id": "personal_event_action_id",
|
||||
"type": "text",
|
||||
"width": "150px",
|
||||
"title": "개인제작 이벤트 모드"
|
||||
},
|
||||
{
|
||||
"id": "global_event_action_id",
|
||||
"type": "text",
|
||||
"width": "150px",
|
||||
"title": "기여도 이벤트 모드"
|
||||
},
|
||||
{
|
||||
"id": "max_point",
|
||||
"type": "text",
|
||||
"width": "150px",
|
||||
"title": "기여도 목표점수"
|
||||
},
|
||||
{
|
||||
"id": "start_dt",
|
||||
"type": "date",
|
||||
"width": "220px",
|
||||
"title": "시작일(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "end_dt",
|
||||
"type": "date",
|
||||
"width": "220px",
|
||||
"title": "종료일(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "detail",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "상세보기",
|
||||
"text": "상세보기",
|
||||
"action": {
|
||||
"type": "modal",
|
||||
"target": "detailModal",
|
||||
"dataParam": {
|
||||
"id": "id"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "history",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "히스토리",
|
||||
"text": "히스토리"
|
||||
}
|
||||
],
|
||||
"sort": {
|
||||
"defaultColumn": "row_num",
|
||||
"defaultDirection": "desc"
|
||||
}
|
||||
}
|
||||
59
src/assets/data/pages/historySearch.json
Normal file
59
src/assets/data/pages/historySearch.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchType": "ID",
|
||||
"searchData": "",
|
||||
"historyType": "",
|
||||
"startDate": "today",
|
||||
"endDate": "today",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "select",
|
||||
"id": "searchType",
|
||||
"label": "대상",
|
||||
"optionsRef": "adminUserType",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchData",
|
||||
"placeholder": "대상 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "historyType",
|
||||
"label": "이력종류",
|
||||
"optionsRef": "opHistoryType",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "기간",
|
||||
"col": 2,
|
||||
"width": "500px",
|
||||
"format": "YYYY-MM-DD HH:mm:ss",
|
||||
"showTime": true
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"endpointName": "LogViewList",
|
||||
"loadOnMount": true,
|
||||
"paramTransforms": [
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"}
|
||||
],
|
||||
"pageField": "page_no",
|
||||
"pageSizeField": "page_size",
|
||||
"orderField": "orderBy"
|
||||
},
|
||||
"paginationType": "front"
|
||||
}
|
||||
69
src/assets/data/pages/historyTable.json
Normal file
69
src/assets/data/pages/historyTable.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"id": "historyTable",
|
||||
"selection": {
|
||||
"type": "single",
|
||||
"idField": "id"
|
||||
},
|
||||
"header": {
|
||||
"countType": "total",
|
||||
"orderType": "desc",
|
||||
"pageType": "default",
|
||||
"buttons": []
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"id": "logTime",
|
||||
"type": "date",
|
||||
"width": "200px",
|
||||
"title": "일시(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "category",
|
||||
"type": "option",
|
||||
"width": "100px",
|
||||
"title": "로그종류",
|
||||
"option_name": "opLogCategory"
|
||||
},
|
||||
{
|
||||
"id": "action",
|
||||
"type": "option",
|
||||
"width": "150px",
|
||||
"title": "로그액션",
|
||||
"option_name": "opLogAction"
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"type": "option",
|
||||
"width": "100px",
|
||||
"title": "상태",
|
||||
"option_name": "opCommonStatus"
|
||||
},
|
||||
{
|
||||
"id": "worker",
|
||||
"type": "text",
|
||||
"width": "100px",
|
||||
"title": "작업자"
|
||||
},
|
||||
{
|
||||
"id": "message",
|
||||
"type": "text",
|
||||
"width": "100px",
|
||||
"title": "비고"
|
||||
},
|
||||
{
|
||||
"id": "detail",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "상세보기",
|
||||
"text": "상세보기"
|
||||
}
|
||||
],
|
||||
"sort": {
|
||||
"defaultColumn": "timestamp",
|
||||
"defaultDirection": "desc"
|
||||
}
|
||||
}
|
||||
39
src/assets/data/pages/itemSearch.json
Normal file
39
src/assets/data/pages/itemSearch.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchType": "GUID",
|
||||
"searchData": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1,
|
||||
"lastEvaluatedKey": null
|
||||
},
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "select",
|
||||
"id": "searchType",
|
||||
"label": "대상",
|
||||
"optionsRef": "userType",
|
||||
"col": 1,
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchData",
|
||||
"placeholder": "대상 입력",
|
||||
"width": "300px",
|
||||
"col": 1,
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"endpointName": "ItemList",
|
||||
"loadOnMount": false,
|
||||
"pageField": "page_no",
|
||||
"pageSizeField": "page_size",
|
||||
"orderField": "orderBy",
|
||||
"lastPageKeyField": "pageKey"
|
||||
},
|
||||
"paginationType": "dynamodb",
|
||||
"initSearch": false
|
||||
}
|
||||
90
src/assets/data/pages/itemTable.json
Normal file
90
src/assets/data/pages/itemTable.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"id": "itemTable",
|
||||
"selection": {
|
||||
"type": "single",
|
||||
"idField": "id"
|
||||
},
|
||||
"header": {
|
||||
"countType": "total",
|
||||
"orderType": "desc",
|
||||
"pageType": "default",
|
||||
"buttons": [
|
||||
{
|
||||
"id": "delete",
|
||||
"text": "선택 삭제",
|
||||
"theme": "line",
|
||||
"disableWhen": "noSelection",
|
||||
"requiredAuth": "itemDelete",
|
||||
"action": "delete"
|
||||
},
|
||||
{
|
||||
"id": "restore",
|
||||
"text": "아이템 복구",
|
||||
"theme": "line",
|
||||
"disableWhen": "disable",
|
||||
"requiredAuth": "itemDelete",
|
||||
"action": "restore"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"id": "checkbox",
|
||||
"type": "checkbox",
|
||||
"width": "40px",
|
||||
"title": ""
|
||||
},
|
||||
{
|
||||
"id": "item_name",
|
||||
"type": "text",
|
||||
"width": "20%",
|
||||
"title": "아이템명"
|
||||
},
|
||||
{
|
||||
"id": "item_id",
|
||||
"type": "text",
|
||||
"width": "20%",
|
||||
"title": "아이템 ID"
|
||||
},
|
||||
{
|
||||
"id": "count",
|
||||
"type": "text",
|
||||
"width": "80px",
|
||||
"title": "수량"
|
||||
},
|
||||
{
|
||||
"id": "item_type",
|
||||
"type": "option",
|
||||
"width": "120px",
|
||||
"title": "아이템 타입",
|
||||
"option_name": "opItemType"
|
||||
},
|
||||
{
|
||||
"id": "equip_type",
|
||||
"type": "option",
|
||||
"width": "80px",
|
||||
"title": "장착",
|
||||
"option_name": "opEquipType"
|
||||
},
|
||||
{
|
||||
"id": "equiped_pos",
|
||||
"type": "text",
|
||||
"width": "80px",
|
||||
"title": "슬롯"
|
||||
},
|
||||
{
|
||||
"id": "create_dt",
|
||||
"type": "date",
|
||||
"width": "100px",
|
||||
"title": "생성날짜(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
}
|
||||
],
|
||||
"sort": {
|
||||
"defaultColumn": "row_num",
|
||||
"defaultDirection": "desc"
|
||||
}
|
||||
}
|
||||
90
src/assets/data/pages/mailSearch.json
Normal file
90
src/assets/data/pages/mailSearch.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchTitle": "",
|
||||
"searchContent": "",
|
||||
"sendType": "ALL",
|
||||
"status": "ALL",
|
||||
"mailType": "ALL",
|
||||
"receiveType": "ALL",
|
||||
"startDate": "",
|
||||
"endDate": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchTitle",
|
||||
"label": "우편 제목",
|
||||
"placeholder": "제목 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "조회 일자",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchContent",
|
||||
"label": "우편 내용",
|
||||
"placeholder": "우편 내용(공백으로 구분)",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "sendType",
|
||||
"label": "발송 방식",
|
||||
"optionsRef": "mailSendType",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "발송 상태",
|
||||
"optionsRef": "mailSendStatus",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "mailType",
|
||||
"label": "우편 타입",
|
||||
"optionsRef": "mailType",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "receiveType",
|
||||
"label": "수신 대상",
|
||||
"optionsRef": "mailReceiveType",
|
||||
"col": 2
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"functionName": "MailView",
|
||||
"loadOnMount": true,
|
||||
"paramsMapping": [
|
||||
"searchTitle",
|
||||
"searchContent",
|
||||
"sendType",
|
||||
"status",
|
||||
"mailType",
|
||||
"receiveType",
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"},
|
||||
"orderBy",
|
||||
"pageSize",
|
||||
"currentPage"
|
||||
],
|
||||
"pageField": "currentPage",
|
||||
"pageSizeField": "pageSize",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
126
src/assets/data/pages/menuBanner.json
Normal file
126
src/assets/data/pages/menuBanner.json
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"pageId": "menuBanner",
|
||||
"title": "메뉴 배너 관리",
|
||||
"endpoint": "/api/v1/menu/banner",
|
||||
"permissions": ["battleEventRead", "battleEventUpdate", "battleEventDelete"],
|
||||
"layout": {
|
||||
"type": "standard",
|
||||
"components": ["search", "table", "pagination"]
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"id": "create",
|
||||
"label": "배너 등록",
|
||||
"type": "button",
|
||||
"theme": "primary",
|
||||
"permission": "battleEventUpdate",
|
||||
"action": {
|
||||
"type": "modal",
|
||||
"target": "createModal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "delete",
|
||||
"label": "선택 삭제",
|
||||
"type": "button",
|
||||
"theme": "line",
|
||||
"permission": "battleEventDelete",
|
||||
"requireSelection": true,
|
||||
"action": {
|
||||
"type": "modal",
|
||||
"target": "deleteConfirmModal"
|
||||
}
|
||||
}
|
||||
],
|
||||
"modals": {
|
||||
"createModal": {
|
||||
"id": "createModal",
|
||||
"type": "form",
|
||||
"title": "메뉴 배너 등록",
|
||||
"size": "medium",
|
||||
"schema": "menuBannerForm",
|
||||
"actions": [
|
||||
{
|
||||
"id": "cancel",
|
||||
"label": "취소",
|
||||
"type": "button",
|
||||
"theme": "line",
|
||||
"action": {
|
||||
"type": "close"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "submit",
|
||||
"label": "등록",
|
||||
"type": "button",
|
||||
"theme": "primary",
|
||||
"action": {
|
||||
"type": "api",
|
||||
"method": "POST",
|
||||
"endpoint": "/api/v1/menu/banner",
|
||||
"successAction": {
|
||||
"type": "close",
|
||||
"then": "refresh"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"detailModal": {
|
||||
"id": "detailModal",
|
||||
"type": "form",
|
||||
"title": "메뉴 배너 상세",
|
||||
"size": "medium",
|
||||
"schema": "menuBannerForm",
|
||||
"readOnly": true,
|
||||
"dataSource": {
|
||||
"type": "api",
|
||||
"endpoint": "/api/v1/menu/banner/detail/{id}"
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"id": "close",
|
||||
"label": "확인",
|
||||
"type": "button",
|
||||
"theme": "line",
|
||||
"action": {
|
||||
"type": "close"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"deleteConfirmModal": {
|
||||
"id": "deleteConfirmModal",
|
||||
"type": "confirm",
|
||||
"title": "배너 삭제",
|
||||
"message": "선택한 배너를 삭제하시겠습니까?",
|
||||
"actions": [
|
||||
{
|
||||
"id": "cancel",
|
||||
"label": "취소",
|
||||
"type": "button",
|
||||
"theme": "line",
|
||||
"action": {
|
||||
"type": "close"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "confirm",
|
||||
"label": "삭제",
|
||||
"type": "button",
|
||||
"theme": "primary",
|
||||
"action": {
|
||||
"type": "api",
|
||||
"method": "DELETE",
|
||||
"endpoint": "/api/v1/menu/banner/delete",
|
||||
"dataTransform": "selectedToRequestBody",
|
||||
"successAction": {
|
||||
"type": "close",
|
||||
"then": "refresh"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
176
src/assets/data/pages/menuBannerRegist.json
Normal file
176
src/assets/data/pages/menuBannerRegist.json
Normal file
@@ -0,0 +1,176 @@
|
||||
{
|
||||
"modal": {
|
||||
"titles": {
|
||||
"create": "메뉴배너 등록",
|
||||
"update": "메뉴배너 수정",
|
||||
"view": "메뉴배너 상세"
|
||||
},
|
||||
"grid": {
|
||||
"rows": 8,
|
||||
"columns": 12
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"id": "date_range",
|
||||
"type": "dateTimeRange",
|
||||
"label": "등록기간",
|
||||
"position": { "row": 0, "col": 0, "width": 12 },
|
||||
"startDateField": "start_dt",
|
||||
"endDateField": "end_dt",
|
||||
"startDateLabel": "시작일자",
|
||||
"endDateLabel": "종료일자",
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"]
|
||||
},
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"label": "배너 제목",
|
||||
"position": { "row": 1, "col": 0, "width": 6 },
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"],
|
||||
"width": "100%"
|
||||
},
|
||||
{
|
||||
"id": "image_ko",
|
||||
"type": "imageUpload",
|
||||
"label": "이미지 첨부 (KO)",
|
||||
"position": { "row": 2, "col": 0, "width": 12 },
|
||||
"language": "KO",
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"]
|
||||
},
|
||||
{
|
||||
"id": "image_en",
|
||||
"type": "imageUpload",
|
||||
"label": "이미지 첨부 (EN)",
|
||||
"position": { "row": 3, "col": 0, "width": 12 },
|
||||
"language": "EN",
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"]
|
||||
},
|
||||
{
|
||||
"id": "image_ja",
|
||||
"type": "imageUpload",
|
||||
"label": "이미지 첨부 (JA)",
|
||||
"position": { "row": 4, "col": 0, "width": 12 },
|
||||
"language": "JA",
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"]
|
||||
},
|
||||
{
|
||||
"id": "is_link",
|
||||
"type": "checkbox",
|
||||
"label": "이미지 링크 여부",
|
||||
"position": { "row": 5, "col": 0, "width": 12 },
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"]
|
||||
},
|
||||
{
|
||||
"id": "link_ko",
|
||||
"type": "textWithSuffix",
|
||||
"label": "웹 링크",
|
||||
"position": { "row": 6, "col": 0, "width": 12 },
|
||||
"suffix": "KO",
|
||||
"conditional": { "field": "is_link", "operator": "==", "value": true },
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"],
|
||||
"width": "100%"
|
||||
},
|
||||
{
|
||||
"id": "link_en",
|
||||
"type": "textWithSuffix",
|
||||
"label": "",
|
||||
"position": { "row": 7, "col": 0, "width": 12 },
|
||||
"suffix": "EN",
|
||||
"conditional": { "field": "is_link", "operator": "==", "value": true },
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"],
|
||||
"width": "100%"
|
||||
},
|
||||
{
|
||||
"id": "link_ja",
|
||||
"type": "textWithSuffix",
|
||||
"label": "",
|
||||
"position": { "row": 8, "col": 0, "width": 12 },
|
||||
"suffix": "JA",
|
||||
"conditional": { "field": "is_link", "operator": "==", "value": true },
|
||||
"validations": ["required"],
|
||||
"visibleOn": ["create", "update", "view"],
|
||||
"editableOn": ["create", "update"],
|
||||
"width": "100%"
|
||||
}
|
||||
],
|
||||
"actions": {
|
||||
"create": [
|
||||
{ "id": "cancel", "label": "취소", "theme": "line", "action": "cancel" },
|
||||
{ "id": "submit", "label": "등록", "theme": "primary", "action": "submit" }
|
||||
],
|
||||
"update": [
|
||||
{ "id": "cancel", "label": "취소", "theme": "line", "action": "cancel" },
|
||||
{ "id": "submit", "label": "수정", "theme": "primary", "action": "submit" }
|
||||
],
|
||||
"view": [
|
||||
{ "id": "cancel", "label": "취소", "theme": "line", "action": "cancel" },
|
||||
{ "id": "edit", "label": "수정", "theme": "primary", "action": "edit" }
|
||||
]
|
||||
},
|
||||
"validations": {
|
||||
"create": [
|
||||
{
|
||||
"condition": "start_dt < (new Date() + 60 * 60000)",
|
||||
"message": "EVENT_TIME_LIMIT_ADD"
|
||||
},
|
||||
{
|
||||
"condition": "end_dt <= start_dt",
|
||||
"message": "DATE_START_DIFF_END_WARNING"
|
||||
}
|
||||
],
|
||||
"update": [
|
||||
{
|
||||
"condition": "end_dt <= start_dt",
|
||||
"message": "DATE_START_DIFF_END_WARNING"
|
||||
}
|
||||
]
|
||||
},
|
||||
"api": {
|
||||
"create": {
|
||||
"endpoint": "MenuBannerSingleRegist",
|
||||
"errorMapping": {
|
||||
"ERROR_API_FAIL": "API_FAIL",
|
||||
"ERROR_REGIST_FAIL": "REGIST_FAIL"
|
||||
}
|
||||
},
|
||||
"update": {
|
||||
"endpoint": "MenuBannerUpdate",
|
||||
"errorMapping": {
|
||||
"ERROR_API_FAIL": "API_FAIL",
|
||||
"ERROR_UPDATE_FAIL": "UPDATE_FAIL"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"initData": {
|
||||
"title": "",
|
||||
"is_link": false,
|
||||
"start_dt": "",
|
||||
"end_dt": "",
|
||||
"image_list": [
|
||||
{ "language": "KO", "content": "" },
|
||||
{ "language": "EN", "content": "" },
|
||||
{ "language": "JA", "content": "" }
|
||||
],
|
||||
"link_list": [
|
||||
{ "language": "KO", "content": "" },
|
||||
{ "language": "EN", "content": "" },
|
||||
{ "language": "JA", "content": "" }
|
||||
]
|
||||
}
|
||||
}
|
||||
48
src/assets/data/pages/menuBannerSearch.json
Normal file
48
src/assets/data/pages/menuBannerSearch.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchData": "",
|
||||
"status": "ALL",
|
||||
"startDate": "",
|
||||
"endDate": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchData",
|
||||
"label": "제목",
|
||||
"placeholder": "제목 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "상태",
|
||||
"optionsRef": "opMenuBannerStatus",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "기간",
|
||||
"col": 1
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"endpointName": "MenuBannerView",
|
||||
"loadOnMount": true,
|
||||
"paramTransforms": [
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"}
|
||||
],
|
||||
"pageField": "page_no",
|
||||
"pageSizeField": "page_size",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
114
src/assets/data/pages/menuBannerTable.json
Normal file
114
src/assets/data/pages/menuBannerTable.json
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"id": "menuBannerTable",
|
||||
"selection": {
|
||||
"type": "single",
|
||||
"idField": "id"
|
||||
},
|
||||
"header": {
|
||||
"countType": "total",
|
||||
"orderType": "desc",
|
||||
"pageType": "default",
|
||||
"buttons": [
|
||||
{
|
||||
"id": "delete",
|
||||
"text": "선택 삭제",
|
||||
"theme": "line",
|
||||
"disableWhen": "noSelection",
|
||||
"requiredAuth": "menuBannerDelete",
|
||||
"action": "delete"
|
||||
},
|
||||
{
|
||||
"id": "register",
|
||||
"text": "이미지 등록",
|
||||
"theme": "primary",
|
||||
"requiredAuth": "menuBannerUpdate",
|
||||
"action": "navigate",
|
||||
"navigateTo": "/servicemanage/menubanner/menubannerregist"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"id": "checkbox",
|
||||
"type": "checkbox",
|
||||
"width": "40px",
|
||||
"title": ""
|
||||
},
|
||||
{
|
||||
"id": "row_num",
|
||||
"type": "text",
|
||||
"width": "70px",
|
||||
"title": "번호"
|
||||
},
|
||||
{
|
||||
"id": "order_id",
|
||||
"type": "text",
|
||||
"width": "70px",
|
||||
"title": "순서"
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"type": "status",
|
||||
"width": "100px",
|
||||
"title": "등록 상태",
|
||||
"option_name": "opMenuBannerStatus"
|
||||
},
|
||||
{
|
||||
"id": "start_dt",
|
||||
"type": "date",
|
||||
"width": "200px",
|
||||
"title": "시작일(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "end_dt",
|
||||
"type": "date",
|
||||
"width": "200px",
|
||||
"title": "종료일(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"title": "설명 제목"
|
||||
},
|
||||
{
|
||||
"id": "is_link",
|
||||
"type": "option",
|
||||
"width": "90px",
|
||||
"title": "링크여부",
|
||||
"option_name": "opYNType"
|
||||
},
|
||||
{
|
||||
"id": "detail",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "상세보기",
|
||||
"text": "상세보기",
|
||||
"action": {
|
||||
"type": "modal",
|
||||
"target": "detailModal",
|
||||
"dataParam": {
|
||||
"id": "id"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "history",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "히스토리",
|
||||
"text": "히스토리"
|
||||
}
|
||||
],
|
||||
"sort": {
|
||||
"defaultColumn": "row_num",
|
||||
"defaultDirection": "desc"
|
||||
}
|
||||
}
|
||||
49
src/assets/data/pages/metaCraftingSearch.json
Normal file
49
src/assets/data/pages/metaCraftingSearch.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"search_type": "ID",
|
||||
"search_data": "",
|
||||
"small_type": "ALL",
|
||||
"recipe_type": "ALL",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "select",
|
||||
"id": "search_type",
|
||||
"optionsRef": "itemSearchType",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "search_data",
|
||||
"placeholder": "아이템 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "small_type",
|
||||
"label": "제작 분류",
|
||||
"optionsRef": "opPropSmallType",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "recipe_type",
|
||||
"label": "레시피 필요 여부",
|
||||
"optionsRef": "opPropRecipeType",
|
||||
"col": 1
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"endpointName": "getCraftingDictionaryList",
|
||||
"loadOnMount": true,
|
||||
"pageField": "page_no",
|
||||
"pageSizeField": "page_size",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
48
src/assets/data/pages/rankingSearch.json
Normal file
48
src/assets/data/pages/rankingSearch.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchData": "",
|
||||
"status": "ALL",
|
||||
"startDate": "",
|
||||
"endDate": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchData",
|
||||
"label": "제목",
|
||||
"placeholder": "제목 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "상태",
|
||||
"optionsRef": "opMenuBannerStatus",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "기간",
|
||||
"col": 1
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"endpointName": "RankingScheduleView",
|
||||
"loadOnMount": true,
|
||||
"paramTransforms": [
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"}
|
||||
],
|
||||
"pageField": "page_no",
|
||||
"pageSizeField": "page_size",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
140
src/assets/data/pages/rankingTable.json
Normal file
140
src/assets/data/pages/rankingTable.json
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"id": "rankingTable",
|
||||
"selection": {
|
||||
"type": "single",
|
||||
"idField": "id"
|
||||
},
|
||||
"header": {
|
||||
"countType": "total",
|
||||
"orderType": "desc",
|
||||
"pageType": "default",
|
||||
"buttons": [
|
||||
{
|
||||
"id": "delete",
|
||||
"text": "선택 삭제",
|
||||
"theme": "line",
|
||||
"disableWhen": "noSelection",
|
||||
"requiredAuth": "rankingDelete",
|
||||
"action": "delete"
|
||||
},
|
||||
{
|
||||
"id": "register",
|
||||
"text": "랭킹 스케줄 등록",
|
||||
"theme": "primary",
|
||||
"requiredAuth": "rankingUpdate",
|
||||
"action": "regist"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"id": "checkbox",
|
||||
"type": "checkbox",
|
||||
"width": "40px",
|
||||
"title": ""
|
||||
},
|
||||
{
|
||||
"id": "row_num",
|
||||
"type": "text",
|
||||
"width": "70px",
|
||||
"title": "번호"
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"type": "status",
|
||||
"width": "100px",
|
||||
"title": "상태",
|
||||
"option_name": "opCommonStatus"
|
||||
},
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"title": "제목"
|
||||
},
|
||||
{
|
||||
"id": "meta_id",
|
||||
"type": "text",
|
||||
"title": "랭킹모드",
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"id": "event_action_id",
|
||||
"type": "text",
|
||||
"title": "이벤트 액션 그룹",
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"id": "start_dt",
|
||||
"type": "date",
|
||||
"width": "200px",
|
||||
"title": "시작일(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "end_dt",
|
||||
"type": "date",
|
||||
"width": "200px",
|
||||
"title": "종료일(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "base_dt",
|
||||
"type": "date",
|
||||
"width": "200px",
|
||||
"title": "기준일(KST)",
|
||||
"format": {
|
||||
"type": "function",
|
||||
"name": "convertKTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "refresh_interval",
|
||||
"type": "text",
|
||||
"width": "120px",
|
||||
"title": "새로고침 주기"
|
||||
},
|
||||
{
|
||||
"id": "initialization_interval",
|
||||
"type": "text",
|
||||
"width": "120px",
|
||||
"title": "초기화 주기"
|
||||
},
|
||||
{
|
||||
"id": "snapshot_interval",
|
||||
"type": "text",
|
||||
"width": "120px",
|
||||
"title": "스냅샷 주기"
|
||||
},
|
||||
{
|
||||
"id": "detail",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "상세보기",
|
||||
"text": "상세보기",
|
||||
"action": {
|
||||
"type": "modal",
|
||||
"target": "detailModal",
|
||||
"dataParam": {
|
||||
"id": "id"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "history",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "히스토리",
|
||||
"text": "히스토리"
|
||||
}
|
||||
],
|
||||
"sort": {
|
||||
"defaultColumn": "row_num",
|
||||
"defaultDirection": "desc"
|
||||
}
|
||||
}
|
||||
63
src/assets/data/pages/rewardEventSearch.json
Normal file
63
src/assets/data/pages/rewardEventSearch.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchTitle": "",
|
||||
"searchContent": "",
|
||||
"status": "ALL",
|
||||
"startDate": "",
|
||||
"endDate": "",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchTitle",
|
||||
"label": "우편 제목",
|
||||
"placeholder": "제목 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "period",
|
||||
"startDateId": "startDate",
|
||||
"endDateId": "endDate",
|
||||
"label": "조회 일자",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchContent",
|
||||
"label": "우편 내용",
|
||||
"placeholder": "우편 내용(공백으로 구분)",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "이벤트 상태",
|
||||
"optionsRef": "eventStatus",
|
||||
"col": 2
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"functionName": "RewardEventView",
|
||||
"loadOnMount": true,
|
||||
"paramsMapping": [
|
||||
"searchTitle",
|
||||
"searchContent",
|
||||
"status",
|
||||
{"param": "startDate", "transform": "toISOString"},
|
||||
{"param": "endDate", "transform": "toISOString"},
|
||||
"orderBy",
|
||||
"pageSize",
|
||||
"currentPage"
|
||||
],
|
||||
"pageField": "currentPage",
|
||||
"pageSizeField": "pageSize",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
78
src/assets/data/pages/userBlockSearch.json
Normal file
78
src/assets/data/pages/userBlockSearch.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"initialSearchParams": {
|
||||
"searchType": "GUID",
|
||||
"searchData": "",
|
||||
"email": "",
|
||||
"status": "ALL",
|
||||
"sanctions": "ALL",
|
||||
"period": "ALL",
|
||||
"orderBy": "DESC",
|
||||
"pageSize": 50,
|
||||
"currentPage": 1
|
||||
},
|
||||
|
||||
"searchFields": [
|
||||
{
|
||||
"type": "select",
|
||||
"id": "searchType",
|
||||
"label": "대상",
|
||||
"optionsRef": "userType",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "searchData",
|
||||
"placeholder": "대상 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "email",
|
||||
"label": "등록자",
|
||||
"placeholder": "이메일 입력",
|
||||
"width": "300px",
|
||||
"col": 1
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "status",
|
||||
"label": "상태",
|
||||
"optionsRef": "blockStatus",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "sanctions",
|
||||
"label": "제재 사유",
|
||||
"optionsRef": "blockSanctions",
|
||||
"col": 2
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"id": "period",
|
||||
"label": "제재 기간",
|
||||
"optionsRef": "blockPeriod",
|
||||
"col": 2
|
||||
}
|
||||
],
|
||||
|
||||
"apiInfo": {
|
||||
"functionName": "BlackListView",
|
||||
"loadOnMount": true,
|
||||
"paramsMapping": [
|
||||
"searchType",
|
||||
"searchData",
|
||||
"email",
|
||||
"status",
|
||||
"sanctions",
|
||||
"period",
|
||||
"orderBy",
|
||||
"pageSize",
|
||||
"currentPage"
|
||||
],
|
||||
"pageField": "currentPage",
|
||||
"pageSizeField": "pageSize",
|
||||
"orderField": "orderBy"
|
||||
}
|
||||
}
|
||||
102
src/assets/data/pages/userBlockTable.json
Normal file
102
src/assets/data/pages/userBlockTable.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"id": "userBlockTable",
|
||||
"selection": {
|
||||
"type": "single",
|
||||
"idField": "id"
|
||||
},
|
||||
"header": {
|
||||
"countType": "total",
|
||||
"orderType": "desc",
|
||||
"pageType": "default",
|
||||
"buttons": [
|
||||
{
|
||||
"id": "delete",
|
||||
"text": "선택 해지",
|
||||
"theme": "line",
|
||||
"disableWhen": "noSelection",
|
||||
"requiredAuth": "blackListDelete",
|
||||
"action": "delete"
|
||||
},
|
||||
{
|
||||
"id": "register",
|
||||
"text": "제재 등록",
|
||||
"theme": "primary",
|
||||
"requiredAuth": "blackListUpdate",
|
||||
"action": "navigate",
|
||||
"navigateTo": "/servicemanage/userblock/userblockregist"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"id": "checkbox",
|
||||
"type": "checkbox",
|
||||
"width": "40px",
|
||||
"title": ""
|
||||
},
|
||||
{
|
||||
"id": "row_num",
|
||||
"type": "text",
|
||||
"width": "80px",
|
||||
"title": "번호"
|
||||
},
|
||||
{
|
||||
"id": "guid",
|
||||
"type": "text",
|
||||
"width": "20%",
|
||||
"title": "GUID"
|
||||
},
|
||||
{
|
||||
"id": "nickname",
|
||||
"type": "text",
|
||||
"width": "20%",
|
||||
"title": "아바타명"
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"type": "status",
|
||||
"width": "100px",
|
||||
"title": "상태",
|
||||
"option_name": "blockStatus"
|
||||
},
|
||||
{
|
||||
"id": "period",
|
||||
"type": "option",
|
||||
"width": "100px",
|
||||
"title": "제재 기간",
|
||||
"option_name": "blockPeriod"
|
||||
},
|
||||
{
|
||||
"id": "sanctions",
|
||||
"type": "option",
|
||||
"width": "250px",
|
||||
"title": "제재 사유",
|
||||
"option_name": "blockSanctions"
|
||||
},
|
||||
{
|
||||
"id": "detail",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "상세보기",
|
||||
"text": "상세보기",
|
||||
"action": {
|
||||
"type": "modal",
|
||||
"target": "detailModal",
|
||||
"dataParam": {
|
||||
"id": "id"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "history",
|
||||
"type": "button",
|
||||
"width": "120px",
|
||||
"title": "히스토리",
|
||||
"text": "히스토리"
|
||||
}
|
||||
],
|
||||
"sort": {
|
||||
"defaultColumn": "row_num",
|
||||
"defaultDirection": "desc"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export const authType = {
|
||||
none: 0,
|
||||
adminSearchRead: 1,
|
||||
adminSearchConfirm: 2,
|
||||
adminSearchUpdate: 3,
|
||||
@@ -46,22 +47,43 @@ export const authType = {
|
||||
landDelete: 45,
|
||||
battleEventRead: 46,
|
||||
battleEventUpdate: 47,
|
||||
battleEventDelete: 48
|
||||
battleEventDelete: 48,
|
||||
businessLogRead: 49,
|
||||
menuBannerRead: 50,
|
||||
menuBannerUpdate: 51,
|
||||
menuBannerDelete: 52,
|
||||
itemDictionaryRead: 53,
|
||||
rankManagerRead: 54,
|
||||
rankManagerUpdate: 55,
|
||||
rankingRead: 56,
|
||||
rankingUpdate: 57,
|
||||
rankingDelete: 58,
|
||||
worldEventRead: 59,
|
||||
worldEventUpdate: 60,
|
||||
worldEventDelete: 61,
|
||||
craftingDictionaryRead: 62,
|
||||
|
||||
|
||||
levelReader: 999,
|
||||
levelMaster: 9999,
|
||||
levelDeveloper: 99999,
|
||||
};
|
||||
|
||||
export const TabList = [
|
||||
{ title: '기본정보' },
|
||||
{ title: '아바타' },
|
||||
{ title: '의상' },
|
||||
{ title: '도구' },
|
||||
{ title: '인벤토리' },
|
||||
{ title: '우편' },
|
||||
{ title: '마이홈' },
|
||||
{ title: '친구목록' },
|
||||
{ title: '타투' },
|
||||
{ title: '퀘스트' },
|
||||
// { title: '클레임' },
|
||||
];
|
||||
export const alertTypes = {
|
||||
info: 0,
|
||||
success: 1,
|
||||
warning: 2,
|
||||
error: 3,
|
||||
confirm: 4,
|
||||
confirmChildren: 5
|
||||
}
|
||||
|
||||
export const adminAuthLevel = {
|
||||
NONE: "None",
|
||||
READER: "Reader",
|
||||
MASTER: "Master",
|
||||
DEVELOPER: "Developer",
|
||||
}
|
||||
|
||||
export const ivenTabType = {
|
||||
CLOTH: "cloth",
|
||||
@@ -93,6 +115,13 @@ export const commonStatus = {
|
||||
delete: "DELETE",
|
||||
reject: "REJECT",
|
||||
complete: "COMPLETE",
|
||||
cancel: "CANCEL"
|
||||
}
|
||||
|
||||
export const customStatus = {
|
||||
inprogress: "INPROGRESS",
|
||||
expiration: "EXPIRATION",
|
||||
|
||||
}
|
||||
|
||||
export const ViewTitleCountType = {
|
||||
@@ -126,3 +155,9 @@ export const currencyCodeTypes = {
|
||||
ruby: "19010005",
|
||||
calium: "19010003"
|
||||
}
|
||||
|
||||
export const languageNames = {
|
||||
'Ko': '한국어',
|
||||
'En': '영어',
|
||||
'Ja': '일본어',
|
||||
};
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { useState } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import DatePicker, { registerLocale } from 'react-datepicker';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import { getMonth, getYear } from 'date-fns';
|
||||
import range from 'lodash/range';
|
||||
|
||||
import { TextInput, SelectInput, DatePickerWrapper, InputLabel, BtnWrapper } from '../../styles/Components';
|
||||
|
||||
const GoodsLogSearchBar = () => {
|
||||
const [startDate, setStartDate] = useState(new Date());
|
||||
const [endDate, setEndDate] = useState(new Date());
|
||||
const [selectData, setSelectData] = useState('default');
|
||||
const years = range(1990, getYear(new Date()) + 1, 1);
|
||||
const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
|
||||
|
||||
const handleChange = e => {
|
||||
setSelectData(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchbarStyle2>
|
||||
<SearchRow>
|
||||
<SearchItem>
|
||||
<InputLabel>조회 기간</InputLabel>
|
||||
<DatePickerWrapper>
|
||||
<InputGroup>
|
||||
<DatePicker
|
||||
selected={startDate}
|
||||
onChange={date => setStartDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="검색기간 선택"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
<span>~</span>
|
||||
<InputGroup>
|
||||
<DatePicker
|
||||
selected={endDate}
|
||||
onChange={date => setEndDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="검색기간 선택"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
minDate = {startDate}
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</DatePickerWrapper>
|
||||
</SearchItem>
|
||||
</SearchRow>
|
||||
<SearchRow>
|
||||
<SearchItem>
|
||||
<InputLabel>조회 대상</InputLabel>
|
||||
<TextInput type="text" placeholder="조회 대상 유저의 GUID를 입력하세요." width="600px" />
|
||||
</SearchItem>
|
||||
<BtnWrapper $gap="8px">
|
||||
<Button theme="reset" />
|
||||
<Button theme="gray" text="검색" />
|
||||
</BtnWrapper>
|
||||
</SearchRow>
|
||||
</SearchbarStyle2>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GoodsLogSearchBar;
|
||||
|
||||
const SearchbarStyle = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
font-size: 14px;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
margin-bottom: 40px;
|
||||
`;
|
||||
const SearchbarStyle2 = styled(SearchbarStyle)`
|
||||
flex-flow: column;
|
||||
gap: 20px;
|
||||
`;
|
||||
|
||||
const SearchRow = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
`;
|
||||
|
||||
const InputGroup = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
`;
|
||||
|
||||
const SearchItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-right: 50px;
|
||||
|
||||
${TextInput}, ${SelectInput} {
|
||||
height: 35px;
|
||||
}
|
||||
${TextInput} {
|
||||
padding: 0 10px;
|
||||
max-width: 400px;
|
||||
}
|
||||
`;
|
||||
168
src/components/DataManage/CurrencyItemLogContent.js
Normal file
168
src/components/DataManage/CurrencyItemLogContent.js
Normal file
@@ -0,0 +1,168 @@
|
||||
import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
CircularProgressWrapper,
|
||||
FormWrapper,
|
||||
TableStyle,
|
||||
TableWrapper,
|
||||
} from '../../styles/Components';
|
||||
import { amountDeltaType, CurrencyType } from '../../assets/data';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { CurrencyItemLogSearchBar, useCurrencyItemLogSearch } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import Pagination from '../common/Pagination/Pagination';
|
||||
import {
|
||||
INITIAL_PAGE_LIMIT,
|
||||
STORAGE_BUSINESS_LOG_SEARCH,
|
||||
STORAGE_GAME_LOG_CURRENCY_SEARCH,
|
||||
} from '../../assets/data/adminConstants';
|
||||
import ExcelExportButton from '../common/button/ExcelExportButton';
|
||||
import CircularProgress from '../common/CircularProgress';
|
||||
import { GameCurrencyItemLogExport } from '../../apis';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
|
||||
const CurrencyItemLogContent = ({ active }) => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
const [downloadState, setDownloadState] = useState({
|
||||
loading: false,
|
||||
progress: 0
|
||||
});
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
handleOrderByChange,
|
||||
handlePageSizeChange,
|
||||
updateSearchParams
|
||||
} = useCurrencyItemLogSearch(token, 500);
|
||||
|
||||
useEffect(() => {
|
||||
if(active) {
|
||||
// 세션 스토리지에서 복사된 메일 데이터 가져오기
|
||||
const paramsData = sessionStorage.getItem(STORAGE_GAME_LOG_CURRENCY_SEARCH);
|
||||
|
||||
if (paramsData) {
|
||||
const searchData = JSON.parse(paramsData);
|
||||
|
||||
handleSearch({
|
||||
start_dt: new Date(searchData.start_dt),
|
||||
end_dt: new Date(searchData.end_dt),
|
||||
search_data: searchData.guid
|
||||
});
|
||||
|
||||
// 사용 후 세션 스토리지 데이터 삭제
|
||||
sessionStorage.removeItem(STORAGE_GAME_LOG_CURRENCY_SEARCH);
|
||||
}
|
||||
}
|
||||
}, [active]);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
// { id: 'logDay', label: '일자', width: '120px' },
|
||||
{ id: 'logTime', label: '일시', width: '150px' },
|
||||
{ id: 'accountId', label: 'account ID', width: '80px' },
|
||||
{ id: 'userGuid', label: 'GUID', width: '200px' },
|
||||
{ id: 'userNickname', label: '아바타명', width: '150px' },
|
||||
{ id: 'tranId', label: '트랜잭션 ID', width: '200px' },
|
||||
{ id: 'action', label: '액션', width: '150px' },
|
||||
{ id: 'currencyType', label: '재화종류', width: '120px' },
|
||||
{ id: 'amountDeltaType', label: '증감유형', width: '120px' },
|
||||
{ id: 'deltaAmount', label: '수량', width: '80px' },
|
||||
// { id: 'deltaAmount', label: '수량원본', width: '120px' },
|
||||
{ id: 'currencyAmount', label: '잔량', width: '80px' },
|
||||
{ id: 'itemId', label: '아이템ID', width: '150px' },
|
||||
];
|
||||
}, []);
|
||||
|
||||
if(!active) return null;
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<CurrencyItemLogSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo orderType="asc" pageType="B" total={dataList?.total} total_all={dataList?.total_all}>
|
||||
<ExcelExportButton
|
||||
functionName="GameCurrencyItemLogExport"
|
||||
params={searchParams}
|
||||
fileName={t('FILE_GAME_LOG_CURRENCY_ITEM')}
|
||||
onLoadingChange={setDownloadState}
|
||||
dataSize={dataList?.total_all}
|
||||
/>
|
||||
{downloadState.loading && (
|
||||
<CircularProgressWrapper>
|
||||
<CircularProgress
|
||||
progress={downloadState.progress}
|
||||
size={36}
|
||||
progressColor="#4A90E2"
|
||||
/>
|
||||
</CircularProgressWrapper>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => (
|
||||
<th key={header.id} width={header.width}>{header.label}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.currency_item_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logTime}</td>
|
||||
<td>{item.accountId}</td>
|
||||
<td>{item.userGuid}</td>
|
||||
<td>{item.userNickname}</td>
|
||||
<td>{item.tranId}</td>
|
||||
<td>{item.action}</td>
|
||||
<td>{CurrencyType.find(data => data.value === item.currencyType)?.name}</td>
|
||||
<td>{amountDeltaType.find(data => data.value === item.amountDeltaType)?.name}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.deltaAmount)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.currencyAmount)}</td>
|
||||
<td>{item.itemIDs}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
{dataList?.currency_item_list &&
|
||||
<Pagination
|
||||
postsPerPage={searchParams.page_size}
|
||||
totalPosts={dataList?.total_all}
|
||||
setCurrentPage={handlePageChange}
|
||||
currentPage={searchParams.page_no}
|
||||
pageLimit={INITIAL_PAGE_LIMIT}
|
||||
/>
|
||||
}
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
export default CurrencyItemLogContent;
|
||||
166
src/components/DataManage/CurrencyLogContent.js
Normal file
166
src/components/DataManage/CurrencyLogContent.js
Normal file
@@ -0,0 +1,166 @@
|
||||
import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
CircularProgressWrapper,
|
||||
FormWrapper,
|
||||
TableStyle,
|
||||
TableWrapper,
|
||||
} from '../../styles/Components';
|
||||
import { amountDeltaType, CurrencyType } from '../../assets/data';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { CurrencyLogSearchBar, useCurrencyLogSearch } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import Pagination from '../common/Pagination/Pagination';
|
||||
import {
|
||||
INITIAL_PAGE_LIMIT,
|
||||
STORAGE_BUSINESS_LOG_SEARCH,
|
||||
STORAGE_GAME_LOG_CURRENCY_SEARCH,
|
||||
} from '../../assets/data/adminConstants';
|
||||
import ExcelExportButton from '../common/button/ExcelExportButton';
|
||||
import CircularProgress from '../common/CircularProgress';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
|
||||
const CurrencyLogContent = ({ active }) => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
const [downloadState, setDownloadState] = useState({
|
||||
loading: false,
|
||||
progress: 0
|
||||
});
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
handleOrderByChange,
|
||||
handlePageSizeChange,
|
||||
updateSearchParams
|
||||
} = useCurrencyLogSearch(token, 500);
|
||||
|
||||
useEffect(() => {
|
||||
if(active) {
|
||||
// 세션 스토리지에서 복사된 메일 데이터 가져오기
|
||||
const paramsData = sessionStorage.getItem(STORAGE_GAME_LOG_CURRENCY_SEARCH);
|
||||
|
||||
if (paramsData) {
|
||||
const searchData = JSON.parse(paramsData);
|
||||
|
||||
handleSearch({
|
||||
start_dt: new Date(searchData.start_dt),
|
||||
end_dt: new Date(searchData.end_dt),
|
||||
search_data: searchData.guid
|
||||
});
|
||||
|
||||
// 사용 후 세션 스토리지 데이터 삭제
|
||||
sessionStorage.removeItem(STORAGE_GAME_LOG_CURRENCY_SEARCH);
|
||||
}
|
||||
}
|
||||
}, [active]);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
// { id: 'logDay', label: '일자', width: '120px' },
|
||||
{ id: 'logTime', label: '일시', width: '120px' },
|
||||
{ id: 'accountId', label: 'account ID', width: '80px' },
|
||||
{ id: 'userGuid', label: 'GUID', width: '200px' },
|
||||
{ id: 'userNickname', label: '아바타명', width: '150px' },
|
||||
{ id: 'tranId', label: '트랜잭션 ID', width: '200px' },
|
||||
{ id: 'action', label: '액션', width: '150px' },
|
||||
{ id: 'currencyType', label: '재화종류', width: '120px' },
|
||||
{ id: 'amountDeltaType', label: '증감유형', width: '120px' },
|
||||
{ id: 'deltaAmount', label: '수량', width: '120px' },
|
||||
// { id: 'deltaAmount', label: '수량원본', width: '120px' },
|
||||
{ id: 'currencyAmount', label: '잔량', width: '120px' },
|
||||
];
|
||||
}, []);
|
||||
|
||||
if(!active) return null;
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<CurrencyLogSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo orderType="asc" pageType="B" total={dataList?.total} total_all={dataList?.total_all}>
|
||||
<ExcelExportButton
|
||||
functionName="GameCurrencyDetailLogExport"
|
||||
params={searchParams}
|
||||
fileName={t('FILE_GAME_LOG_CURRENCY')}
|
||||
onLoadingChange={setDownloadState}
|
||||
dataSize={dataList?.total_all}
|
||||
/>
|
||||
{downloadState.loading && (
|
||||
<CircularProgressWrapper>
|
||||
<CircularProgress
|
||||
progress={downloadState.progress}
|
||||
size={36}
|
||||
progressColor="#4A90E2"
|
||||
/>
|
||||
</CircularProgressWrapper>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => (
|
||||
<th key={header.id} width={header.width}>{header.label}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.currency_detail_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logTime}</td>
|
||||
<td>{item.accountId}</td>
|
||||
<td>{item.userGuid}</td>
|
||||
<td>{item.userNickname}</td>
|
||||
<td>{item.tranId}</td>
|
||||
<td>{item.action}</td>
|
||||
<td>{CurrencyType.find(data => data.value === item.currencyType)?.name}</td>
|
||||
<td>{amountDeltaType.find(data => data.value === item.amountDeltaType)?.name}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.deltaAmount)}</td>
|
||||
{/*<td>{item.deltaAmount}</td>*/}
|
||||
<td>{numberFormatter.formatCurrency(item.currencyAmount)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
{dataList?.currency_detail_list &&
|
||||
<Pagination
|
||||
postsPerPage={searchParams.page_size}
|
||||
totalPosts={dataList?.total_all}
|
||||
setCurrentPage={handlePageChange}
|
||||
currentPage={searchParams.page_no}
|
||||
pageLimit={INITIAL_PAGE_LIMIT}
|
||||
/>
|
||||
}
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
export default CurrencyLogContent;
|
||||
171
src/components/DataManage/ItemLogContent.js
Normal file
171
src/components/DataManage/ItemLogContent.js
Normal file
@@ -0,0 +1,171 @@
|
||||
import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
CircularProgressWrapper,
|
||||
FormWrapper,
|
||||
TableStyle,
|
||||
TableWrapper,
|
||||
} from '../../styles/Components';
|
||||
import { amountDeltaType, CurrencyType } from '../../assets/data';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { ItemLogSearchBar, useItemLogSearch } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import Pagination from '../common/Pagination/Pagination';
|
||||
import {
|
||||
INITIAL_PAGE_LIMIT,
|
||||
STORAGE_BUSINESS_LOG_SEARCH,
|
||||
STORAGE_GAME_LOG_CURRENCY_SEARCH, STORAGE_GAME_LOG_ITEM_SEARCH,
|
||||
} from '../../assets/data/adminConstants';
|
||||
import ExcelExportButton from '../common/button/ExcelExportButton';
|
||||
import CircularProgress from '../common/CircularProgress';
|
||||
import { countDeltaType, itemTypeLarge } from '../../assets/data/options';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
|
||||
const CurrencyLogContent = ({ active }) => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
const [downloadState, setDownloadState] = useState({
|
||||
loading: false,
|
||||
progress: 0
|
||||
});
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
handleOrderByChange,
|
||||
handlePageSizeChange,
|
||||
updateSearchParams
|
||||
} = useItemLogSearch(token, 500);
|
||||
|
||||
useEffect(() => {
|
||||
if(active) {
|
||||
// 세션 스토리지에서 복사된 메일 데이터 가져오기
|
||||
const paramsData = sessionStorage.getItem(STORAGE_GAME_LOG_ITEM_SEARCH);
|
||||
|
||||
if (paramsData) {
|
||||
const searchData = JSON.parse(paramsData);
|
||||
|
||||
handleSearch({
|
||||
start_dt: new Date(searchData.start_dt),
|
||||
end_dt: new Date(searchData.end_dt),
|
||||
search_data: searchData.guid
|
||||
});
|
||||
|
||||
// 사용 후 세션 스토리지 데이터 삭제
|
||||
sessionStorage.removeItem(STORAGE_GAME_LOG_ITEM_SEARCH);
|
||||
}
|
||||
}
|
||||
}, [active]);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
// { id: 'logDay', label: '일자', width: '120px' },
|
||||
{ id: 'logTime', label: '일시', width: '150px' },
|
||||
{ id: 'accountId', label: 'account ID', width: '80px' },
|
||||
{ id: 'userGuid', label: 'GUID', width: '200px' },
|
||||
{ id: 'userNickname', label: '아바타명', width: '150px' },
|
||||
{ id: 'tranId', label: '트랜잭션 ID', width: '200px' },
|
||||
{ id: 'action', label: '액션', width: '120px' },
|
||||
{ id: 'itemId', label: '아이템ID', width: '80px' },
|
||||
{ id: 'itemName', label: '아이템명', width: '150px' },
|
||||
{ id: 'itemTypeLarge', label: 'LargeType', width: '100px' },
|
||||
{ id: 'itemTypeSmall', label: 'SmallType', width: '100px' },
|
||||
{ id: 'countDeltaType', label: '증감유형', width: '80px' },
|
||||
{ id: 'deltaCount', label: '수량', width: '80px' },
|
||||
{ id: 'stackCount', label: '총량', width: '80px' },
|
||||
];
|
||||
}, []);
|
||||
|
||||
if(!active) return null;
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<ItemLogSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo orderType="asc" pageType="B" total={dataList?.total} total_all={dataList?.total_all}>
|
||||
<ExcelExportButton
|
||||
functionName="GameItemDetailLogExport"
|
||||
params={searchParams}
|
||||
fileName={t('FILE_GAME_LOG_ITEM')}
|
||||
onLoadingChange={setDownloadState}
|
||||
dataSize={dataList?.total_all}
|
||||
/>
|
||||
{downloadState.loading && (
|
||||
<CircularProgressWrapper>
|
||||
<CircularProgress
|
||||
progress={downloadState.progress}
|
||||
size={36}
|
||||
progressColor="#4A90E2"
|
||||
/>
|
||||
</CircularProgressWrapper>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => (
|
||||
<th key={header.id} width={header.width}>{header.label}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.item_detail_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logTime}</td>
|
||||
<td>{item.accountId}</td>
|
||||
<td>{item.userGuid}</td>
|
||||
<td>{item.userNickname}</td>
|
||||
<td>{item.tranId}</td>
|
||||
<td>{item.action}</td>
|
||||
<td>{item.itemId}</td>
|
||||
<td>{item.itemName}</td>
|
||||
<td>{itemTypeLarge.find(data => data.value === item.itemTypeLarge)?.name || item.itemTypeLarge}</td>
|
||||
<td>{item.itemTypeSmall}</td>
|
||||
<td>{countDeltaType.find(data => data.value === item.countDeltaType)?.name || item.countDeltaType}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.deltaCount)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.stackCount)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
{dataList?.item_detail_list &&
|
||||
<Pagination
|
||||
postsPerPage={searchParams.page_size}
|
||||
totalPosts={dataList?.total_all}
|
||||
setCurrentPage={handlePageChange}
|
||||
currentPage={searchParams.page_no}
|
||||
pageLimit={INITIAL_PAGE_LIMIT}
|
||||
/>
|
||||
}
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
export default CurrencyLogContent;
|
||||
@@ -1,219 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
import RadioInput from '../common/input/Radio';
|
||||
import Button from '../common/button/Button';
|
||||
|
||||
import DatePicker, { registerLocale } from 'react-datepicker';
|
||||
import { ko } from 'date-fns/esm/locale';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import { getMonth, getYear } from 'date-fns';
|
||||
import range from 'lodash/range';
|
||||
|
||||
import { TextInput, SelectInput, DatePickerWrapper, InputLabel, BtnWrapper } from '../../styles/Components';
|
||||
|
||||
const ItemLogSearchBar = () => {
|
||||
const [startDate, setStartDate] = useState(new Date());
|
||||
const [endDate, setEndDate] = useState(new Date());
|
||||
const [selectData, setSelectData] = useState('default');
|
||||
const years = range(1990, getYear(new Date()) + 1, 1);
|
||||
const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
|
||||
|
||||
const handleChange = e => {
|
||||
setSelectData(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchbarStyle2>
|
||||
<SearchRow>
|
||||
<RadioGroup>
|
||||
<RadioInput label="기본 조회" id="single" name="receiver" value="default" fontWeight="600" checked={selectData === 'default'} handleChange={handleChange} />
|
||||
<RadioInput label="아이템 소유자 추적" id="multi" name="receiver" value="item" fontWeight="600" checked={selectData === 'item'} handleChange={handleChange} />
|
||||
</RadioGroup>
|
||||
</SearchRow>
|
||||
<SearchRow>
|
||||
<SearchItem>
|
||||
<InputLabel>조회 기간</InputLabel>
|
||||
<DatePickerWrapper>
|
||||
<InputGroup>
|
||||
<DatePicker
|
||||
selected={startDate}
|
||||
onChange={date => setStartDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="검색기간 선택"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
<span>~</span>
|
||||
<InputGroup>
|
||||
<DatePicker
|
||||
selected={endDate}
|
||||
onChange={date => setEndDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="검색기간 선택"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
minDate = {startDate}
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</DatePickerWrapper>
|
||||
</SearchItem>
|
||||
</SearchRow>
|
||||
<SearchRow>
|
||||
{selectData === 'default' ? (
|
||||
<SearchItem>
|
||||
<InputLabel>조회 대상</InputLabel>
|
||||
<TextInput type="text" placeholder="조회 대상 유저의 GUID를 입력하세요." width="600px" />
|
||||
</SearchItem>
|
||||
) : (
|
||||
<SearchItem>
|
||||
<InputLabel>아이템 ID</InputLabel>
|
||||
<TextInput type="text" placeholder="아이템의 GUID를 입력하세요." width="600px" />
|
||||
</SearchItem>
|
||||
)}
|
||||
|
||||
<BtnWrapper $gap="8px">
|
||||
<Button theme="reset" />
|
||||
<Button theme="gray" text="검색" />
|
||||
</BtnWrapper>
|
||||
</SearchRow>
|
||||
</SearchbarStyle2>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ItemLogSearchBar;
|
||||
|
||||
const SearchbarStyle = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
font-size: 14px;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
margin-bottom: 40px;
|
||||
`;
|
||||
const SearchbarStyle2 = styled(SearchbarStyle)`
|
||||
flex-flow: column;
|
||||
gap: 20px;
|
||||
`;
|
||||
|
||||
const SearchRow = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
`;
|
||||
|
||||
const InputGroup = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
`;
|
||||
|
||||
const RadioGroup = styled(InputGroup)`
|
||||
gap: 30px;
|
||||
height: 35px;
|
||||
`;
|
||||
|
||||
const SearchItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-right: 50px;
|
||||
|
||||
${TextInput}, ${SelectInput} {
|
||||
height: 35px;
|
||||
}
|
||||
${TextInput} {
|
||||
padding: 0 10px;
|
||||
max-width: 400px;
|
||||
}
|
||||
`;
|
||||
@@ -2,16 +2,19 @@ import { styled } from 'styled-components';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { Title } from '../../styles/Components';
|
||||
import { TextInput, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import { TextInput, BtnWrapper } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import { UserChangeNickName } from '../../apis';
|
||||
import { alertTypes } from '../../assets/data/types';
|
||||
import { useAlert } from '../../context/AlertProvider';
|
||||
import { useLoading } from '../../context/LoadingProvider';
|
||||
|
||||
const NicknameChangeModal = ({ pwPop, handleClick, dataList }) => {
|
||||
const {showModal, showToast} = useAlert();
|
||||
const {withLoading} = useLoading();
|
||||
|
||||
let nickName = dataList.char_info && dataList.char_info.character_name;
|
||||
const [modifyModal, setModifyModal] = useState('hidden');
|
||||
const [completeModal, setCompleteModal] = useState('hidden');
|
||||
const [completeText, setCompleteText] = useState('');
|
||||
|
||||
const [resultData, setResultData] = useState({
|
||||
guid: '',
|
||||
@@ -20,42 +23,42 @@ const NicknameChangeModal = ({ pwPop, handleClick, dataList }) => {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setResultData({ ...resultData, guid: dataList.user_info && dataList.user_info.aid, nickname: dataList.char_info && dataList.char_info.character_name });
|
||||
setResultData({ ...resultData,
|
||||
guid: dataList.user_info && dataList.user_info.aid,
|
||||
nickname: dataList.char_info && dataList.char_info.character_name
|
||||
});
|
||||
}, [dataList]);
|
||||
|
||||
// 수정 모달창
|
||||
const handleModifyModal = () => {
|
||||
if (modifyModal === 'hidden') {
|
||||
setModifyModal('view');
|
||||
} else {
|
||||
setModifyModal('hidden');
|
||||
const handleSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
|
||||
case "nicknameChangeSubmit":
|
||||
showModal('NICKNAME_CHANGES_CONFIRM', {
|
||||
type: alertTypes.confirm,
|
||||
onConfirm: () => handleSubmit('nicknameChange')
|
||||
});
|
||||
break;
|
||||
|
||||
case "nicknameChange":
|
||||
const token = sessionStorage.getItem('token');
|
||||
|
||||
await withLoading(async () => {
|
||||
return await UserChangeNickName(token, resultData);
|
||||
}).then(data =>{
|
||||
console.log(data);
|
||||
if(data.result === 'ERROR'){
|
||||
showToast(data.data.message, {type: alertTypes.error});
|
||||
}else{
|
||||
showToast('NICKNAME_CHANGES_COMPLETE', {type: alertTypes.success});
|
||||
}
|
||||
}).catch(error => {
|
||||
showToast(error, {type: alertTypes.error});
|
||||
}).finally(() => {
|
||||
handleClick();
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// 완료 모달창
|
||||
const handleCompleteModal = () => {
|
||||
if (completeModal === 'hidden') {
|
||||
setCompleteModal('view');
|
||||
} else {
|
||||
setCompleteModal('hidden');
|
||||
|
||||
handleClick();
|
||||
completeText === '변경이 완료되었습니다.' && window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 수정
|
||||
const handleModifyNotice = async () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
|
||||
const message = await UserChangeNickName(token, resultData);
|
||||
|
||||
// console.log(message);
|
||||
message.data.data.message !== '수정 하였습니다.' ? setCompleteText('변경 닉네임이 이미 존재합니다.\n다시 시도해주세요.') : setCompleteText('변경이 완료되었습니다.');
|
||||
|
||||
handleCompleteModal();
|
||||
handleModifyModal();
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -82,29 +85,7 @@ const NicknameChangeModal = ({ pwPop, handleClick, dataList }) => {
|
||||
</PwSetTable>
|
||||
<BtnWrapper $justify="center" $gap="10px">
|
||||
<Button theme="line" text="취소" handleClick={handleClick} />
|
||||
<Button theme="primary" text="변경하기" handleClick={handleModifyModal} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={modifyModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleModifyModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">닉네임을 변경하시겠습니까?</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleModifyModal} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleModifyNotice} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{completeText}</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteModal} />
|
||||
<Button theme="primary" text="변경하기" handleClick={() => handleSubmit('nicknameChangeSubmit')} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
|
||||
@@ -5,15 +5,31 @@ import { BtnWrapper, TableStyle } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import { useEffect, useState, Fragment } from 'react';
|
||||
import { questStatus } from '../../assets/data/options';
|
||||
import { commonStatus } from '../../assets/data';
|
||||
import { useModal } from '../../hooks/hook';
|
||||
import { alertTypes } from '../../assets/data/types';
|
||||
import { useAlert } from '../../context/AlertProvider';
|
||||
|
||||
const QuestDetailModal = ({ detailPop, handleClick, detailQuest, handleQuestComplete }) => {
|
||||
const { showModal } = useAlert();
|
||||
|
||||
const QuestDetailModal = ({ detailPop, handleClick, detailQuest }) => {
|
||||
const [detailList, setDetailList] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
Array.isArray(detailQuest) && setDetailList(detailQuest)
|
||||
Array.isArray(detailQuest.detailQuest) && setDetailList(detailQuest.detailQuest)
|
||||
|
||||
}, [detailQuest])
|
||||
// const questlist = [{ taskNo: detailQuest.task_no, taskName: detailQuest.quest_name, counter: detailQuest.counter, state: detailQuest.status }];
|
||||
|
||||
const handleQuestCompleteConfirm = (data) => {
|
||||
const params = {...data, quest_key: detailQuest.quest_key}
|
||||
showModal('QUEST_TASK_COMPLETE_CONFIRM',{
|
||||
type: alertTypes.confirm,
|
||||
onConfirm: () => {
|
||||
handleQuestComplete(params);
|
||||
}
|
||||
});
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Modal $view={detailPop} min="480px">
|
||||
@@ -25,7 +41,8 @@ const QuestDetailModal = ({ detailPop, handleClick, detailQuest }) => {
|
||||
<th width="80">Task No</th>
|
||||
<th>Task Name</th>
|
||||
<th width="120">Counter</th>
|
||||
<th width="120">State</th>
|
||||
<th width="120">상태</th>
|
||||
<th width="120">완료처리</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -36,7 +53,10 @@ const QuestDetailModal = ({ detailPop, handleClick, detailQuest }) => {
|
||||
<td>{el.task_no}</td>
|
||||
<td>{el.quest_name}</td>
|
||||
<td>{el.counter}</td>
|
||||
<td>{el.status}</td>
|
||||
<td>{questStatus.find(data => data.value === el.status)?.name}</td>
|
||||
<td>
|
||||
{ el.status === commonStatus.running && <Button text="완료" theme="line" handleClick={() => handleQuestCompleteConfirm(el)} />}
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { useState } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import DatePicker, { registerLocale } from 'react-datepicker';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import { getMonth, getYear } from 'date-fns';
|
||||
import range from 'lodash/range';
|
||||
|
||||
import { TextInput, SelectInput, DatePickerWrapper, InputLabel, BtnWrapper } from '../../styles/Components';
|
||||
|
||||
const TradeLogSerchBar = () => {
|
||||
const [startDate, setStartDate] = useState(new Date());
|
||||
const [endDate, setEndDate] = useState(new Date());
|
||||
const [selectData, setSelectData] = useState('default');
|
||||
const years = range(1990, getYear(new Date()) + 1, 1);
|
||||
const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
|
||||
|
||||
const handleChange = e => {
|
||||
setSelectData(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchbarStyle2>
|
||||
<SearchRow>
|
||||
<SearchItem>
|
||||
<InputLabel>조회 기간</InputLabel>
|
||||
<DatePickerWrapper>
|
||||
<InputGroup>
|
||||
<DatePicker
|
||||
selected={startDate}
|
||||
onChange={date => setStartDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="검색기간 선택"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
<span>~</span>
|
||||
<InputGroup>
|
||||
<DatePicker
|
||||
selected={endDate}
|
||||
onChange={date => setEndDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="검색기간 선택"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
minDate = {startDate}
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
<SelectInput>
|
||||
<option value="">00</option>
|
||||
<option value="">01</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</DatePickerWrapper>
|
||||
</SearchItem>
|
||||
</SearchRow>
|
||||
<SearchRow>
|
||||
<SearchItem>
|
||||
<InputLabel>조회 대상</InputLabel>
|
||||
<TextInput type="text" placeholder="조회 대상 유저의 GUID를 입력하세요." width="600px" />
|
||||
</SearchItem>
|
||||
<BtnWrapper $gap="8px">
|
||||
<Button theme="reset" />
|
||||
<Button theme="gray" text="검색" />
|
||||
</BtnWrapper>
|
||||
</SearchRow>
|
||||
</SearchbarStyle2>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TradeLogSerchBar;
|
||||
|
||||
const SearchbarStyle = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
font-size: 14px;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
margin-bottom: 40px;
|
||||
`;
|
||||
const SearchbarStyle2 = styled(SearchbarStyle)`
|
||||
flex-flow: column;
|
||||
gap: 20px;
|
||||
`;
|
||||
|
||||
const SearchRow = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
`;
|
||||
|
||||
const InputGroup = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
`;
|
||||
|
||||
const SearchItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-right: 50px;
|
||||
|
||||
${TextInput}, ${SelectInput} {
|
||||
height: 35px;
|
||||
}
|
||||
${TextInput} {
|
||||
padding: 0 10px;
|
||||
max-width: 400px;
|
||||
}
|
||||
`;
|
||||
@@ -8,7 +8,9 @@ const UserAvatarInfo = ({ userInfo }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fetchData = async () => {
|
||||
|
||||
146
src/components/DataManage/UserCreateLogContent.js
Normal file
146
src/components/DataManage/UserCreateLogContent.js
Normal file
@@ -0,0 +1,146 @@
|
||||
import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
CircularProgressWrapper,
|
||||
FormWrapper,
|
||||
TableStyle,
|
||||
TableWrapper,
|
||||
} from '../../styles/Components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { useUserCreateLogSearch, UserCreateLogSearchBar } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import Pagination from '../common/Pagination/Pagination';
|
||||
import {
|
||||
INITIAL_PAGE_LIMIT,STORAGE_GAME_LOG_USER_CREATE_SEARCH,
|
||||
} from '../../assets/data/adminConstants';
|
||||
import ExcelExportButton from '../common/button/ExcelExportButton';
|
||||
import CircularProgress from '../common/CircularProgress';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
|
||||
const UserCreateLogContent = ({ active }) => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
const [downloadState, setDownloadState] = useState({
|
||||
loading: false,
|
||||
progress: 0
|
||||
});
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
updateSearchParams
|
||||
} = useUserCreateLogSearch(token, 500);
|
||||
|
||||
useEffect(() => {
|
||||
if(active) {
|
||||
// 세션 스토리지에서 복사된 메일 데이터 가져오기
|
||||
const paramsData = sessionStorage.getItem(STORAGE_GAME_LOG_USER_CREATE_SEARCH);
|
||||
|
||||
if (paramsData) {
|
||||
const searchData = JSON.parse(paramsData);
|
||||
|
||||
handleSearch({
|
||||
start_dt: new Date(searchData.start_dt),
|
||||
end_dt: new Date(searchData.end_dt),
|
||||
search_data: searchData.guid
|
||||
});
|
||||
|
||||
// 사용 후 세션 스토리지 데이터 삭제
|
||||
sessionStorage.removeItem(STORAGE_GAME_LOG_USER_CREATE_SEARCH);
|
||||
}
|
||||
}
|
||||
}, [active]);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '120px' },
|
||||
{ id: 'accountId', label: 'account ID', width: '80px' },
|
||||
{ id: 'userGuid', label: 'GUID', width: '200px' },
|
||||
{ id: 'userNickname', label: '아바타명', width: '150px' },
|
||||
{ id: 'createTime', label: '생성일시', width: '200px' },
|
||||
];
|
||||
}, []);
|
||||
|
||||
if(!active) return null;
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<UserCreateLogSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo orderType="asc" pageType="B" total={dataList?.total} total_all={dataList?.total_all}>
|
||||
<ExcelExportButton
|
||||
functionName="GameUserCreateLogExport"
|
||||
params={searchParams}
|
||||
fileName={t('FILE_GAME_LOG_USER_CREATE')}
|
||||
onLoadingChange={setDownloadState}
|
||||
dataSize={dataList?.total_all}
|
||||
/>
|
||||
{downloadState.loading && (
|
||||
<CircularProgressWrapper>
|
||||
<CircularProgress
|
||||
progress={downloadState.progress}
|
||||
size={36}
|
||||
progressColor="#4A90E2"
|
||||
/>
|
||||
</CircularProgressWrapper>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => (
|
||||
<th key={header.id} width={header.width}>{header.label}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.user_create_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logDay}</td>
|
||||
<td>{item.accountId}</td>
|
||||
<td>{item.userGuid}</td>
|
||||
<td>{item.userNickname}</td>
|
||||
<td>{item.createdTime}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
{dataList?.user_create_list &&
|
||||
<Pagination
|
||||
postsPerPage={searchParams.page_size}
|
||||
totalPosts={dataList?.total_all}
|
||||
setCurrentPage={handlePageChange}
|
||||
currentPage={searchParams.page_no}
|
||||
pageLimit={INITIAL_PAGE_LIMIT}
|
||||
/>
|
||||
}
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
export default UserCreateLogContent;
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import Profile from '../../assets/img/datamanage/img-profile.png';
|
||||
import NicknameChangeModal from '../../components/DataManage/NicknameChangeModal';
|
||||
import EditIcon from '../../assets/img/icon/icon-edit.png';
|
||||
import { UserChangeAdminLevel, UserInfoView } from '../../apis/Users';
|
||||
import { UserChangeAdminLevel, UserInfoView, UserKick } from '../../apis/Users';
|
||||
import { SelectInput } from '../../styles/Components';
|
||||
import { adminLevelType, authType, modalTypes } from '../../assets/data';
|
||||
import DynamicModal from '../common/modal/DynamicModal';
|
||||
@@ -16,53 +16,96 @@ import { convertKTC } from '../../utils';
|
||||
import { EditButton, ProfileWrapper, UserDefault, UserInfoTable } from '../../styles/ModuleComponents';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { UserInfoSkeleton } from '../Skeleton/UserInfoSkeleton';
|
||||
import { opUserSessionType } from '../../assets/data/options';
|
||||
import Button from '../common/button/Button';
|
||||
import { useModal } from '../../hooks/hook';
|
||||
import { InitData } from '../../apis/Data';
|
||||
import { useAlert } from '../../context/AlertProvider';
|
||||
import { useLoading } from '../../context/LoadingProvider';
|
||||
import { alertTypes } from '../../assets/data/types';
|
||||
|
||||
const UserDefaultInfo = ({ userInfo }) => {
|
||||
const { t } = useTranslation();
|
||||
const authInfo = useRecoilValue(authList);
|
||||
const token = sessionStorage.getItem('token');
|
||||
const {showModal, showToast} = useAlert();
|
||||
const {withLoading} = useLoading();
|
||||
|
||||
const [pwPop, setPwPop] = useState('hidden');
|
||||
const [gmModal, setGmModal] = useState('hidden');
|
||||
const {
|
||||
modalState,
|
||||
handleModalView,
|
||||
handleModalClose
|
||||
} = useModal({
|
||||
pwChange: 'hidden'
|
||||
});
|
||||
const [dataList, setDataList] = useState({});
|
||||
const [adminLevel, setAdminLevel] = useState('0');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const handleClick = () => {
|
||||
if (pwPop === 'hidden') setPwPop('view');
|
||||
else setPwPop('hidden');
|
||||
};
|
||||
const [authDelete, setAuthDelete] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
setAuthDelete(authInfo?.auth_list?.some(auth => auth.id === authType.userSearchDelete));
|
||||
}, [authInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, [userInfo]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
setLoading(true);
|
||||
await UserInfoView(token, userInfo.guid).then(data => {
|
||||
setDataList(data);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const handleGMChange = (e) =>{
|
||||
setAdminLevel(e.target.value);
|
||||
setGmModal('view');
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const handleSubmit = async (type, param = null) => {
|
||||
let params = {};
|
||||
params.guid = userInfo.guid;
|
||||
params.admin_level = adminLevel;
|
||||
|
||||
await UserChangeAdminLevel(token, params);
|
||||
switch (type) {
|
||||
case "gmLevelChangeSubmit":
|
||||
showModal('USER_GM_CHANGE', {
|
||||
type: alertTypes.confirm,
|
||||
onConfirm: () => handleSubmit('gmLevelChange', param)
|
||||
});
|
||||
break;
|
||||
|
||||
handleCancel();
|
||||
await fetchData();
|
||||
}
|
||||
case "userKickSubmit":
|
||||
showModal('USER_KICK_CONFIRM', {
|
||||
type: alertTypes.confirm,
|
||||
onConfirm: () => handleSubmit('userKick')
|
||||
});
|
||||
break;
|
||||
|
||||
const handleCancel = () => {
|
||||
setGmModal('hidden');
|
||||
case "gmLevelChange":
|
||||
params.guid = userInfo.guid;
|
||||
params.admin_level = param;
|
||||
|
||||
await withLoading(async () => {
|
||||
return await UserChangeAdminLevel(token, params);
|
||||
}).then(data =>{
|
||||
showToast('USER_GM_CHANGE_COMPLETE', {type: alertTypes.success});
|
||||
}).catch(error => {
|
||||
showToast(error, {type: alertTypes.error});
|
||||
}).finally(() => {
|
||||
fetchData();
|
||||
});
|
||||
break;
|
||||
|
||||
case "userKick":
|
||||
params.guid = userInfo.guid;
|
||||
await withLoading(async () => {
|
||||
return await UserKick(token, params);
|
||||
}).then((data) =>{
|
||||
showToast('USER_KICK_COMPLETE', {type: alertTypes.success});
|
||||
}).catch(error => {
|
||||
showToast(error, {type: alertTypes.error});
|
||||
}).finally(() => {
|
||||
fetchData();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -76,11 +119,11 @@ const UserDefaultInfo = ({ userInfo }) => {
|
||||
<UserInfoTable $maxwidth="530px">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>AID(GUID)</th>
|
||||
<th>GUID</th>
|
||||
<td>{dataList.user_info && dataList.user_info.aid}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>계정 ID</th>
|
||||
<th>Account ID</th>
|
||||
<td>{dataList.user_info && dataList.user_info.user_id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -88,12 +131,17 @@ const UserDefaultInfo = ({ userInfo }) => {
|
||||
<td>{dataList.user_info && dataList.user_info.nation}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>멤버십</th>
|
||||
<td>{dataList.user_info && dataList.user_info.membership}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>친구 추천코드</th>
|
||||
<td>{dataList.user_info && dataList.user_info.friend_code}</td>
|
||||
<th>접속상태</th>
|
||||
<StatusCell>{dataList.user_session !== undefined && opUserSessionType.find(session => session.value === dataList.user_session)?.name}
|
||||
{<Button
|
||||
theme={(dataList.user_session && authDelete) ? "line" : "disable"}
|
||||
id={"user_session"}
|
||||
name="kick"
|
||||
text="KICK"
|
||||
handleClick={() => handleSubmit('userKickSubmit')}
|
||||
disabled={(!authDelete || !dataList.user_session)}
|
||||
/>}
|
||||
</StatusCell>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>계정 생성일</th>
|
||||
@@ -103,10 +151,7 @@ const UserDefaultInfo = ({ userInfo }) => {
|
||||
</tr>
|
||||
<tr>
|
||||
<th>최근 접속일자</th>
|
||||
<td>
|
||||
{/*{dataList.user_info && String(new Date(new Date(dataList.user_info.access_dt).setHours(new Date(dataList.user_info.access_dt).getHours() + 9)).toLocaleString())}*/}
|
||||
{dataList.user_info && convertKTC(dataList.user_info.access_dt)}
|
||||
</td>
|
||||
<td>{dataList.user_info && convertKTC(dataList.user_info.access_dt)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>최근 종료일자</th>
|
||||
@@ -121,7 +166,9 @@ const UserDefaultInfo = ({ userInfo }) => {
|
||||
<tr>
|
||||
<th>GM권한</th>
|
||||
<td>
|
||||
<SelectInput value={dataList.user_info && dataList.user_info.admin_level} onChange={(e) => handleGMChange(e)} disabled={authInfo.auth_list && !authInfo.auth_list.some(auth => auth.id === authType.userSearchUpdate)} >
|
||||
<SelectInput value={dataList?.user_info?.admin_level}
|
||||
onChange={e => handleSubmit('gmLevelChangeSubmit', e.target.value)}
|
||||
disabled={authInfo.auth_list && !authInfo.auth_list.some(auth => auth.id === authType.userSearchUpdate)} >
|
||||
{adminLevelType.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{data.name}
|
||||
@@ -146,10 +193,10 @@ const UserDefaultInfo = ({ userInfo }) => {
|
||||
<td colSpan="3">
|
||||
{dataList.char_info && dataList.char_info.character_name}
|
||||
<EditButton
|
||||
hidden={true}
|
||||
// hidden={true}
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
handleClick();
|
||||
handleModalView('pwChange');
|
||||
}}></EditButton>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -172,15 +219,21 @@ const UserDefaultInfo = ({ userInfo }) => {
|
||||
</tbody>
|
||||
</UserInfoTable>
|
||||
</div>
|
||||
<NicknameChangeModal pwPop={pwPop} handleClick={handleClick} dataList={dataList} />
|
||||
<DynamicModal
|
||||
modalType={modalTypes.childOkCancel}
|
||||
view={gmModal}
|
||||
modalText={t('USER_GM_CHANGE')}
|
||||
handleCancel={handleCancel}
|
||||
handleSubmit={handleSubmit}
|
||||
/>
|
||||
<NicknameChangeModal
|
||||
pwPop={modalState.pwChangeModal}
|
||||
handleClick={() => {
|
||||
handleModalClose('pwChange');
|
||||
fetchData();
|
||||
}}
|
||||
dataList={dataList} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default UserDefaultInfo;
|
||||
|
||||
const StatusCell = styled.td`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
`;
|
||||
@@ -9,7 +9,9 @@ const UserDressInfo = ({ userInfo }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -91,12 +93,6 @@ const UserInfoTable = styled.table`
|
||||
font-size: 13px;
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
tr:first-child {
|
||||
th,
|
||||
td {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
th,
|
||||
td {
|
||||
height: 36px;
|
||||
|
||||
@@ -13,7 +13,9 @@ const UserFriendInfo = ({ userInfo }) => {
|
||||
const [dataList, setDataList] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fetchData = async () => {
|
||||
|
||||
@@ -12,10 +12,16 @@ import { useRecoilValue } from 'recoil';
|
||||
import { authList } from '../../store/authList';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { InfoSubTitle, UserDefaultTable, UserTableWrapper } from '../../styles/ModuleComponents';
|
||||
import { useAlert } from '../../context/AlertProvider';
|
||||
import { useLoading } from '../../context/LoadingProvider';
|
||||
import { convertKTC, timeDiffMinute } from '../../utils';
|
||||
import { alertTypes } from '../../assets/data/types';
|
||||
|
||||
const UserInventoryInfo = ({ userInfo }) => {
|
||||
const { t } = useTranslation();
|
||||
const authInfo = useRecoilValue(authList);
|
||||
const {showModal, showToast} = useAlert();
|
||||
const {withLoading} = useLoading();
|
||||
|
||||
const [dataList, setDataList] = useState();
|
||||
const [itemCount, setItemCount] = useState('');
|
||||
@@ -28,8 +34,10 @@ const UserInventoryInfo = ({ userInfo }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, [userInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
setAuthDelete(authInfo.auth_list.some(auth => auth.id === 35));
|
||||
@@ -152,6 +160,19 @@ const UserInventoryInfo = ({ userInfo }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleAction = async (action, item = null) => {
|
||||
switch (action) {
|
||||
case "delete":
|
||||
break;
|
||||
case "deleteConfirm":
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const ConfirmChild = () => {
|
||||
return(
|
||||
<InputItem>
|
||||
@@ -173,7 +194,7 @@ const UserInventoryInfo = ({ userInfo }) => {
|
||||
<th width="120">ID</th>
|
||||
<th width="50%">아이템</th>
|
||||
<th width="100">보유개수</th>
|
||||
<th width="60">삭제</th>
|
||||
{/*<th width="60">삭제</th>*/}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -184,9 +205,9 @@ const UserInventoryInfo = ({ userInfo }) => {
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
<td>{el.count}</td>
|
||||
<td>
|
||||
<Button theme={authDelete ? "line" : "disable"} id={el.item_guid} name="single" text="삭제" handleClick={e => {handleDeleteConfirmModal(el, type)}} disabled={!authDelete}/>
|
||||
</td>
|
||||
{/*<td>*/}
|
||||
{/* <Button theme={authDelete ? "line" : "disable"} id={el.item_guid} name="single" text="삭제" handleClick={e => {handleDeleteConfirmModal(el, type)}} disabled={!authDelete}/>*/}
|
||||
{/*</td>*/}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
@@ -225,136 +246,6 @@ const UserInventoryInfo = ({ userInfo }) => {
|
||||
modalText={t('DEL_COMPLETE')}
|
||||
handleComplete={handleDeleteComplete}
|
||||
/>
|
||||
{/* <InfoSubTitle>의상 탭</InfoSubTitle>
|
||||
<UserTableWrapper>
|
||||
<UserDefaultTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="80">no.</th>
|
||||
<th width="120">ID</th>
|
||||
<th width="50%">아이템</th>
|
||||
<th width="100">보유개수</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList &&
|
||||
dataList.inventory_list.cloth.map((el, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td>{idx + 1}</td>
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
<td>{el.count}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</UserDefaultTable>
|
||||
</UserTableWrapper>
|
||||
<InfoSubTitle>소품 탭</InfoSubTitle>
|
||||
<UserTableWrapper>
|
||||
<UserDefaultTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="80">no.</th>
|
||||
<th width="120">ID</th>
|
||||
<th width="50%">아이템</th>
|
||||
<th width="100">보유개수</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList &&
|
||||
dataList.inventory_list.prop.map((el, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td>{idx + 1}</td>
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
<td>{el.count}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</UserDefaultTable>
|
||||
</UserTableWrapper>
|
||||
<InfoSubTitle>미용 탭</InfoSubTitle>
|
||||
<UserTableWrapper>
|
||||
<UserDefaultTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="80">no.</th>
|
||||
<th width="120">ID</th>
|
||||
<th width="50%">아이템</th>
|
||||
<th width="100">보유개수</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList &&
|
||||
dataList.inventory_list.beauty.map((el, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td>{idx + 1}</td>
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
<td>{el.count}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</UserDefaultTable>
|
||||
</UserTableWrapper>
|
||||
<InfoSubTitle>타투 탭</InfoSubTitle>
|
||||
<UserTableWrapper>
|
||||
<UserDefaultTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="80">no.</th>
|
||||
<th width="120">ID</th>
|
||||
<th width="50%">아이템</th>
|
||||
<th width="100">보유개수</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList &&
|
||||
dataList.inventory_list.tattoo.map((el, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td>{idx + 1}</td>
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
<td>{el.count}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</UserDefaultTable>
|
||||
</UserTableWrapper>
|
||||
<InfoSubTitle>기타 탭</InfoSubTitle>
|
||||
<UserTableWrapper>
|
||||
<UserDefaultTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="80">슬롯 no.</th>
|
||||
<th width="320">ID</th>
|
||||
<th width="50%">아이템</th>
|
||||
<th width="100">보유개수</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList &&
|
||||
dataList.inventory_list.etc.map((el, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td>{idx + 1}</td>
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
<td>{el.count}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</UserDefaultTable>
|
||||
</UserTableWrapper> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
159
src/components/DataManage/UserLoginLogContent.js
Normal file
159
src/components/DataManage/UserLoginLogContent.js
Normal file
@@ -0,0 +1,159 @@
|
||||
import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
CircularProgressWrapper,
|
||||
FormWrapper,
|
||||
TableStyle,
|
||||
TableWrapper,
|
||||
} from '../../styles/Components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { useUserLoginLogSearch, UserLoginLogSearchBar } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import Pagination from '../common/Pagination/Pagination';
|
||||
import {
|
||||
INITIAL_PAGE_LIMIT, STORAGE_GAME_LOG_USER_LOGIN_SEARCH,
|
||||
} from '../../assets/data/adminConstants';
|
||||
import ExcelExportButton from '../common/button/ExcelExportButton';
|
||||
import CircularProgress from '../common/CircularProgress';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import { numberFormatter } from '../../utils';
|
||||
|
||||
const UserLoginLogContent = ({ active }) => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
const [downloadState, setDownloadState] = useState({
|
||||
loading: false,
|
||||
progress: 0
|
||||
});
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
handleOrderByChange,
|
||||
handlePageSizeChange,
|
||||
updateSearchParams
|
||||
} = useUserLoginLogSearch(token, 500);
|
||||
|
||||
useEffect(() => {
|
||||
if(active) {
|
||||
// 세션 스토리지에서 복사된 메일 데이터 가져오기
|
||||
const paramsData = sessionStorage.getItem(STORAGE_GAME_LOG_USER_LOGIN_SEARCH);
|
||||
|
||||
if (paramsData) {
|
||||
const searchData = JSON.parse(paramsData);
|
||||
|
||||
handleSearch({
|
||||
start_dt: new Date(searchData.start_dt),
|
||||
end_dt: new Date(searchData.end_dt),
|
||||
search_data: searchData.guid
|
||||
});
|
||||
|
||||
// 사용 후 세션 스토리지 데이터 삭제
|
||||
sessionStorage.removeItem(STORAGE_GAME_LOG_USER_LOGIN_SEARCH);
|
||||
}
|
||||
}
|
||||
}, [active]);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '100px' },
|
||||
{ id: 'accountId', label: 'account ID', width: '80px' },
|
||||
{ id: 'userGuid', label: 'GUID', width: '180px' },
|
||||
{ id: 'userNickname', label: '아바타명', width: '150px' },
|
||||
{ id: 'tranId', label: '트랜잭션 ID', width: '200px' },
|
||||
{ id: 'loginTime', label: '로그인시간', width: '150px' },
|
||||
{ id: 'logoutTime', label: '로그아웃시간', width: '120px' },
|
||||
{ id: 'serverType', label: '서버종류', width: '80px' },
|
||||
{ id: 'languageType', label: '언어', width: '80px' },
|
||||
{ id: 'playtime', label: '플레이시간(분)', width: '80px' },
|
||||
];
|
||||
}, []);
|
||||
|
||||
if(!active) return null;
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<UserLoginLogSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo orderType="asc" pageType="B" total={dataList?.total} total_all={dataList?.total_all}>
|
||||
<ExcelExportButton
|
||||
functionName="GameUserLoginLogExport"
|
||||
params={searchParams}
|
||||
fileName={t('FILE_GAME_LOG_USER_LOGIN')}
|
||||
onLoadingChange={setDownloadState}
|
||||
dataSize={dataList?.total_all}
|
||||
/>
|
||||
{downloadState.loading && (
|
||||
<CircularProgressWrapper>
|
||||
<CircularProgress
|
||||
progress={downloadState.progress}
|
||||
size={36}
|
||||
progressColor="#4A90E2"
|
||||
/>
|
||||
</CircularProgressWrapper>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => (
|
||||
<th key={header.id} width={header.width}>{header.label}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.user_login_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logDay}</td>
|
||||
<td>{item.accountId}</td>
|
||||
<td>{item.userGuid}</td>
|
||||
<td>{item.userNickname}</td>
|
||||
<td>{item.tranId}</td>
|
||||
<td>{item.loginTime}</td>
|
||||
<td>{item.logoutTime}</td>
|
||||
<td>{item.serverType}</td>
|
||||
<td>{item.languageType}</td>
|
||||
<td>{numberFormatter.formatSecondToMinuts(item.playtime)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
{dataList?.user_login_list &&
|
||||
<Pagination
|
||||
postsPerPage={searchParams.page_size}
|
||||
totalPosts={dataList?.total_all}
|
||||
setCurrentPage={handlePageChange}
|
||||
currentPage={searchParams.page_no}
|
||||
pageLimit={INITIAL_PAGE_LIMIT}
|
||||
/>
|
||||
}
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
export default UserLoginLogContent;
|
||||
@@ -1,108 +1,120 @@
|
||||
import { useState, Fragment, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useState, Fragment, useEffect, memo } from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import MailDetailModal from '../../components/DataManage/MailDetailModal';
|
||||
import { SelectInput, TextInput } from '../../styles/Components';
|
||||
import { UserMailDelete, UserMailItemDelete, UserMailView } from '../../apis';
|
||||
import ConfirmModal from '../common/modal/ConfirmModal';
|
||||
import CompletedModal from '../common/modal/CompletedModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import CustomConfirmModal from '../common/modal/CustomConfirmModal';
|
||||
import DynamicModal from '../common/modal/DynamicModal';
|
||||
import { authType, ivenTabType } from '../../assets/data';
|
||||
import { authType, ivenTabType, opMailType } from '../../assets/data';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { authList } from '../../store/authList';
|
||||
import { convertKTC } from '../../utils';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { opPickupType, opReadType, opYNType } from '../../assets/data/options';
|
||||
import { useDynamoDBPagination, useModal } from '../../hooks/hook';
|
||||
import { DynamoPagination } from '../common';
|
||||
import { useLoading } from '../../context/LoadingProvider';
|
||||
import { useAlert } from '../../context/AlertProvider';
|
||||
import { alertTypes } from '../../assets/data/types';
|
||||
|
||||
const ConfirmChild = memo(({ maxCount }) => {
|
||||
const { t } = useTranslation();
|
||||
const [localCount, setLocalCount] = useState('1');
|
||||
const {showToast} = useAlert();
|
||||
|
||||
const handleChange = (e) => {
|
||||
let value = e.target.value;
|
||||
|
||||
if (value === '0' || value === '-0') {
|
||||
value = '1';
|
||||
} else if (value < 0) {
|
||||
value = Math.abs(value).toString();
|
||||
} else if(Number(value) > maxCount) {
|
||||
showToast('DEL_COUNT_CHECK', {type: alertTypes.warning});
|
||||
value = maxCount.toString();
|
||||
}
|
||||
|
||||
setLocalCount(value);
|
||||
};
|
||||
|
||||
return(
|
||||
<InputItem>
|
||||
<p>{t('DEL_COUNT_CONFIRM', {count: maxCount})}</p>
|
||||
<TextInput
|
||||
id="user-mail-item-count-input"
|
||||
placeholder="수량"
|
||||
type="number"
|
||||
value={localCount}
|
||||
onChange={handleChange}
|
||||
width="200px"
|
||||
/>
|
||||
</InputItem>
|
||||
);
|
||||
});
|
||||
|
||||
const UserMailInfo = ({ userInfo }) => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const { t } = useTranslation();
|
||||
const authInfo = useRecoilValue(authList);
|
||||
const {withLoading} = useLoading();
|
||||
const {showModal, showToast} = useAlert();
|
||||
|
||||
//데이터 리스트
|
||||
const [dataList, setDataList] = useState([]);
|
||||
// 받은 우편, 보낸 우편
|
||||
const [option, setOption] = useState('RECEIVE');
|
||||
// 상세 정보
|
||||
const [detail, setDetail] = useState({ title: '', content: '', item_list: [], mail_guid: '' });
|
||||
const [deleteSelected, setDeleteSelected] = useState({});
|
||||
const [itemUpdateCount, setItemUpdateCount] = useState('1');
|
||||
const [authDelete, setAuthDelete] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [modalState, setModalState] = useState({
|
||||
detailModal: 'hidden',
|
||||
deleteItemModal: 'hidden',
|
||||
deleteSubmitModal: 'hidden',
|
||||
deleteCompleteModal: 'hidden',
|
||||
deleteItemCompleteModal: 'hidden'
|
||||
const {
|
||||
modalState,
|
||||
handleModalView,
|
||||
handleModalClose
|
||||
} = useModal({
|
||||
detail: 'hidden',
|
||||
deleteItem: 'hidden'
|
||||
});
|
||||
|
||||
// 받은 우편, 보낸 우편 option 에 따른 data fetch
|
||||
const fetchMailData = async (page, startKey) => {
|
||||
const params = {
|
||||
mail_type: option,
|
||||
guid: userInfo.guid,
|
||||
page_key: startKey
|
||||
};
|
||||
return await UserMailView(token, params);
|
||||
};
|
||||
|
||||
const {
|
||||
data: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
fetchPage,
|
||||
goToNextPage,
|
||||
goToPrevPage,
|
||||
resetPagination
|
||||
} = useDynamoDBPagination(fetchMailData);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(option);
|
||||
resetPagination();
|
||||
fetchPage(1);
|
||||
}, [option]);
|
||||
|
||||
useEffect(() => {
|
||||
setAuthDelete(authInfo.auth_list.some(auth => auth.id === authType.userSearchDelete));
|
||||
}, [authInfo]);
|
||||
|
||||
const fetchData = async option => {
|
||||
await UserMailView(token, userInfo.guid, option).then(data =>{
|
||||
setDataList(data);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
// 상세 모달 value 세팅
|
||||
const handleDetail = (title, content, itmeList, mail_guid) => {
|
||||
setDetail({ title: title, content: content, item_list: itmeList, mail_guid: mail_guid });
|
||||
};
|
||||
|
||||
// 우편 아이템 삭제 개수 처리
|
||||
const handleItemCount = e => {
|
||||
if (e.target.value === '0' || e.target.value === '-0') {
|
||||
setItemUpdateCount('1');
|
||||
e.target.value = '1';
|
||||
} else if (e.target.value < 0) {
|
||||
let plusNum = Math.abs(e.target.value);
|
||||
setItemUpdateCount(plusNum);
|
||||
} else if(e.target.value > deleteSelected.count){
|
||||
alert(t('DEL_COUNT_CHECK'));
|
||||
setItemUpdateCount(deleteSelected.count);
|
||||
} else {
|
||||
setItemUpdateCount(e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
const handleModalView = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'view',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleModalClose = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'hidden',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleModalSubmit = async (type, param = null) => {
|
||||
let params;
|
||||
let result;
|
||||
switch (type) {
|
||||
case "detail":
|
||||
handleModalView('deleteSubmit');
|
||||
break;
|
||||
case "deleteItem":
|
||||
setDeleteSelected(param);
|
||||
handleModalView('deleteItem');
|
||||
showModal('USER_MAIL_DEL_CONFIRM', {
|
||||
type: alertTypes.confirm,
|
||||
onConfirm: () => handleModalSubmit('deleteSubmit')
|
||||
});
|
||||
break;
|
||||
case "deleteSubmit":
|
||||
params = {}
|
||||
@@ -110,76 +122,89 @@ const UserMailInfo = ({ userInfo }) => {
|
||||
params.guid = userInfo.guid;
|
||||
params.mail_guid = detail.mail_guid;
|
||||
|
||||
result = await UserMailDelete(token, params);
|
||||
await withLoading(async () => {
|
||||
return await UserMailDelete(token, params);
|
||||
}).then(data => {
|
||||
if(data.result === "SUCCESS") {
|
||||
showToast('DEL_COMPLETE', {type: alertTypes.success});
|
||||
}else{
|
||||
showToast(data.data.message, {type: alertTypes.error});
|
||||
}
|
||||
}).catch(e => {
|
||||
showToast(e, {type: alertTypes.error});
|
||||
});
|
||||
|
||||
handleModalClose('deleteSubmit');
|
||||
handleModalView('deleteComplete');
|
||||
break;
|
||||
case "deleteItem":
|
||||
setDeleteSelected(param);
|
||||
handleModalView('deleteItem');
|
||||
break;
|
||||
case "deleteItemSubmit":
|
||||
//랜더링 문제로 dom에서 값을 찾아 가져온다.
|
||||
const inputElement = document.getElementById("user-mail-item-count-input");
|
||||
|
||||
if(inputElement === null) showToast('INPUT_VALUE_ERROR',{type: alertTypes.error});
|
||||
const count = inputElement.value;
|
||||
|
||||
params = {}
|
||||
params.type = option;
|
||||
params.guid = userInfo.guid;
|
||||
params.mail_guid = detail.mail_guid;
|
||||
params.item_id = deleteSelected.item_id;
|
||||
params.parrent_count = deleteSelected.count;
|
||||
params.count = itemUpdateCount;
|
||||
params.count = count;
|
||||
|
||||
result = await UserMailItemDelete(token, params);
|
||||
if(result.result === "SUCCESS"){
|
||||
if(deleteSelected.count <= itemUpdateCount){
|
||||
const item_idx = detail.item_list.findIndex(item => item.item_id === deleteSelected.item_id);
|
||||
if(item_idx >= 0) {
|
||||
detail.item_list.splice(item_idx, 1);
|
||||
await withLoading(async () => {
|
||||
return await UserMailItemDelete(token, params);
|
||||
}).then(data => {
|
||||
if(data.result === "SUCCESS") {
|
||||
if(deleteSelected.count <= count){
|
||||
const item_idx = detail.item_list.findIndex(item => item.item_id === params.item_id);
|
||||
if(item_idx >= 0) {
|
||||
detail.item_list.splice(item_idx, 1);
|
||||
}
|
||||
}else{
|
||||
deleteSelected.count = deleteSelected.count - count;
|
||||
}
|
||||
showToast('DEL_ITEM_COMPLETE', {type: alertTypes.success});
|
||||
}else{
|
||||
deleteSelected.count = deleteSelected.count - itemUpdateCount;
|
||||
showToast(data.data.message, {type: alertTypes.error});
|
||||
}
|
||||
}
|
||||
handleModalClose('deleteItem');
|
||||
handleModalView('deleteItemComplete');
|
||||
break;
|
||||
case "deleteComplete":
|
||||
handleModalClose('deleteComplete');
|
||||
handleModalClose('detail');
|
||||
// const idx = dataList.mail_list.findIndex(mail => mail.mail_guid === detail.mail_guid);
|
||||
// if(idx >= 0) {
|
||||
// dataList.mail_list.splice(idx, 1);
|
||||
// }
|
||||
fetchData(option);
|
||||
break;
|
||||
case "deleteItemComplete":
|
||||
handleModalClose('deleteItemComplete');
|
||||
}).catch(e => {
|
||||
showToast(e, {type: alertTypes.error});
|
||||
}).finally(() => {
|
||||
handleModalClose('deleteItem');
|
||||
fetchPage(pagination.currentPage);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const ConfirmChild = () => {
|
||||
return(
|
||||
<InputItem>
|
||||
<p>{t('DEL_COUNT_CONFIRM', {count: deleteSelected.count})}</p>
|
||||
<TextInput placeholder="수량" type="number" value={itemUpdateCount} onChange={e => handleItemCount(e)} width="200px" />
|
||||
</InputItem>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
loading ? <TableSkeleton count={10}/> :
|
||||
<>
|
||||
<SelectWrapper>
|
||||
<SelectContainer>
|
||||
<SelectInput
|
||||
value={option}
|
||||
onChange={e => {
|
||||
setOption(e.target.value);
|
||||
}}>
|
||||
<option value="RECEIVE">받은 우편</option>
|
||||
<option value="SEND">보낸 우편</option>
|
||||
{opMailType.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{data.name}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</SelectWrapper>
|
||||
|
||||
<DynamoPagination
|
||||
pagination={pagination}
|
||||
onNextPage={goToNextPage}
|
||||
onPrevPage={goToPrevPage}
|
||||
/>
|
||||
</SelectContainer>
|
||||
|
||||
{option === 'RECEIVE' && (
|
||||
<>
|
||||
{/* <CheckWrapper>
|
||||
<CheckBox id="viewDelReceiveMail" label="삭제 우편 보기" />
|
||||
</CheckWrapper> */}
|
||||
<UserTableWrapper>
|
||||
<UserDefaultTable>
|
||||
<thead>
|
||||
@@ -191,12 +216,10 @@ const UserMailInfo = ({ userInfo }) => {
|
||||
<th width="100">첨부 아이템</th>
|
||||
<th width="80">수령</th>
|
||||
<th width="80">시스템 우편</th>
|
||||
{/* <th width="170">수령 일자</th> */}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.mail_list &&
|
||||
dataList.mail_list.map((mail, idx) => {
|
||||
{dataList?.mail_list?.map((mail, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td>{convertKTC(mail.create_time)}</td>
|
||||
@@ -211,13 +234,10 @@ const UserMailInfo = ({ userInfo }) => {
|
||||
{mail.title}
|
||||
</MailLink>
|
||||
</td>
|
||||
<td>{mail.status === true ? '확인' : '미확인'}</td>
|
||||
<td>{mail.item_list.length > 0 ? 'Y' : 'N'}</td>
|
||||
<td>{mail.is_get_item === true ? '수령함' : '미수령함'}</td>
|
||||
<td>{mail.is_system_mail === true ? 'Y' : 'N'}</td>
|
||||
{/* <td>
|
||||
{mail.is_get_item_dt && String(new Date(new Date(mail.is_get_item_dt).setHours(new Date(mail.is_get_item_dt).getHours() + 9)).toLocaleString())}
|
||||
</td> */}
|
||||
<td>{opReadType.find(type => type.value === mail.status).name}</td>
|
||||
<td>{opYNType.find(type => type.value === (mail.item_list.length > 0)).name}</td>
|
||||
<td>{opPickupType.find(type => type.value === mail.is_get_item).name}</td>
|
||||
<td>{opYNType.find(type => type.value === mail.is_system_mail).name}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
@@ -228,9 +248,6 @@ const UserMailInfo = ({ userInfo }) => {
|
||||
)}
|
||||
{option === 'SEND' && (
|
||||
<>
|
||||
{/* <CheckWrapper>
|
||||
<CheckBox id="viewDelSendMail" label="삭제 우편 보기" />
|
||||
</CheckWrapper> */}
|
||||
<UserTableWrapper>
|
||||
<UserDefaultTable>
|
||||
<thead>
|
||||
@@ -242,7 +259,7 @@ const UserMailInfo = ({ userInfo }) => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.mail_list &&
|
||||
{dataList && dataList.mail_list &&
|
||||
dataList.mail_list.map((mail, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
@@ -267,6 +284,7 @@ const UserMailInfo = ({ userInfo }) => {
|
||||
</UserTableWrapper>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/*상세*/}
|
||||
<MailDetailModal
|
||||
mailModal={modalState.detailModal}
|
||||
@@ -277,32 +295,19 @@ const UserMailInfo = ({ userInfo }) => {
|
||||
handleItemDelete={(param) => handleModalSubmit('deleteItem', param)}
|
||||
authDelete={authDelete}
|
||||
/>
|
||||
{/*메일 삭제 모달*/}
|
||||
<ConfirmModal
|
||||
modalText={t('USER_MAIL_DEL_CONFIRM')}
|
||||
view={modalState.deleteSubmitModal}
|
||||
handleSubmit={() => handleModalSubmit('deleteSubmit')}
|
||||
handleCancel={() => handleModalClose('deleteSubmit')}
|
||||
handleClose={() => handleModalClose('deleteSubmit')}
|
||||
/>
|
||||
<CompletedModal
|
||||
view={modalState.deleteCompleteModal}
|
||||
modalText={t('DEL_COMPLETE')}
|
||||
handleComplete={() => handleModalSubmit('deleteComplete')}
|
||||
/>
|
||||
|
||||
{/*메일 아이템 삭제 모달*/}
|
||||
<CustomConfirmModal
|
||||
ChildView={ConfirmChild}
|
||||
ChildView={() => (
|
||||
<ConfirmChild
|
||||
maxCount={deleteSelected.count}
|
||||
/>
|
||||
)}
|
||||
view={modalState.deleteItemModal}
|
||||
handleSubmit={() => handleModalSubmit('deleteItemSubmit')}
|
||||
handleCancel={() => handleModalClose('deleteItem')}
|
||||
handleClose={() => handleModalClose('deleteItem')}
|
||||
/>
|
||||
<CompletedModal
|
||||
view={modalState.deleteItemCompleteModal}
|
||||
modalText={t('DEL_ITEM_COMPLETE')}
|
||||
handleComplete={() => handleModalSubmit('deleteItemComplete')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -365,22 +370,7 @@ const UserTableWrapper = styled.div`
|
||||
const MailLink = styled.div`
|
||||
color: #61a2d0;
|
||||
text-decoration: underline;
|
||||
`;
|
||||
|
||||
const SelectWrapper = styled.div`
|
||||
select {
|
||||
height: 30px;
|
||||
}
|
||||
margin-bottom: 10px;
|
||||
`;
|
||||
const CheckWrapper = styled.div`
|
||||
text-align: right;
|
||||
padding: 10px;
|
||||
margin-top: -40px;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const InputItem = styled.div`
|
||||
@@ -396,3 +386,14 @@ const InputItem = styled.div`
|
||||
padding: 10px 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const SelectContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
select {
|
||||
height: 30px;
|
||||
}
|
||||
`;
|
||||
@@ -1,31 +1,38 @@
|
||||
import styled from 'styled-components';
|
||||
import Button from '../common/button/Button';
|
||||
import { InfoSubTitle, UserDefaultTable, UserInfoTable, UserTableWrapper } from '../../styles/ModuleComponents';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { UserInventoryView, UserMyhomeView } from '../../apis';
|
||||
import { UserMyhomeView } from '../../apis';
|
||||
import { SelectInput } from '../../styles/Components';
|
||||
|
||||
const UserMyHomeInfo = ({ userInfo }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [dataList, setDataList] = useState();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [selectedHome, setSelectedHome] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fetchData = async () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
await UserMyhomeView(token, userInfo.guid).then(data => {
|
||||
setDataList(data.myhome_info);
|
||||
setDataList(data);
|
||||
if (data.myhome_info && data.myhome_info.length > 0) {
|
||||
setSelectedHome(data.myhome_info[0].myhome_guid);
|
||||
}
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const handleHomeChange = (e) => {
|
||||
setSelectedHome(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
loading ? <TableSkeleton count={15}/> :
|
||||
dataList &&
|
||||
@@ -34,7 +41,13 @@ const UserMyHomeInfo = ({ userInfo }) => {
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>마이 홈명</th>
|
||||
<td>{dataList.myhome_name}</td>
|
||||
<SelectInput onChange={handleHomeChange} value={selectedHome}>
|
||||
{dataList.myhome_info && dataList.myhome_info.map((data, index) => (
|
||||
<option key={index} value={data.myhome_guid}>
|
||||
{data.myhome_name}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</tr>
|
||||
</tbody>
|
||||
</UserInfoTable>
|
||||
@@ -49,15 +62,19 @@ const UserMyHomeInfo = ({ userInfo }) => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.prop_list && dataList.prop_list.map((el, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td>{idx + 1}</td>
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
{dataList.myhome_info.find(home => home.myhome_guid === selectedHome)?.prop_list?.map((el, idx) => (
|
||||
<tr key={idx}>
|
||||
<td>{idx + 1}</td>
|
||||
<td>{el.item_id}</td>
|
||||
<td>{el.item_name}</td>
|
||||
</tr>
|
||||
))}
|
||||
{(!dataList.myhome_info.find(home => home.myhome_guid === selectedHome)?.prop_list ||
|
||||
dataList.myhome_info.find(home => home.myhome_guid === selectedHome)?.prop_list.length === 0) && (
|
||||
<tr>
|
||||
<td colSpan="3" style={{textAlign: 'center'}}>{t('TABLE_DATA_NOT_FOUND')}</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</UserDefaultTable>
|
||||
</UserTableWrapper>
|
||||
|
||||
@@ -3,18 +3,27 @@ import { useState, useEffect, Fragment } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import QuestDetailModal from '../../components/DataManage/QuestDetailModal';
|
||||
import { UserQuestView } from '../../apis/Users';
|
||||
import { UserQuestTaskComplete, UserQuestView } from '../../apis/Users';
|
||||
import { convertKTC } from '../../utils';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { useAlert } from '../../context/AlertProvider';
|
||||
import { CaliumCharge } from '../../apis';
|
||||
import { alertTypes } from '../../assets/data/types';
|
||||
import { useLoading } from '../../context/LoadingProvider';
|
||||
import { questCompleteStatusType } from '../../assets/data/options';
|
||||
|
||||
const UserQuestInfo = ({ userInfo }) => {
|
||||
const [detailPop, setDetailPop] = useState('hidden');
|
||||
const [dataList, setDataList] = useState({});
|
||||
const [detailQuest, setDetailQuest] = useState({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { showModal, showToast } = useAlert();
|
||||
const { withLoading } = useLoading();
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fetchData = async () => {
|
||||
@@ -28,10 +37,30 @@ const UserQuestInfo = ({ userInfo }) => {
|
||||
const handleClick = data => {
|
||||
if (detailPop === 'hidden') {
|
||||
setDetailPop('view');
|
||||
setDetailQuest(data.detailQuest);
|
||||
setDetailQuest(data);
|
||||
} else setDetailPop('hidden');
|
||||
};
|
||||
|
||||
const handleQuestComplete = async data => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
await withLoading(async () => {
|
||||
const params = {...data, guid: userInfo.guid};
|
||||
return await UserQuestTaskComplete(token, params);
|
||||
}).then(data => {
|
||||
if (data.result === "SUCCESS") {
|
||||
showToast('QUEST_TASK_COMPLETE', { type: alertTypes.success });
|
||||
} else {
|
||||
showToast(data.data.message, { type: alertTypes.error });
|
||||
}
|
||||
}).catch(error => {
|
||||
showToast('API_FAIL', { type: alertTypes.error });
|
||||
}).finally(() => {
|
||||
handleClick();
|
||||
fetchData();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
loading ? <TableSkeleton /> :
|
||||
<>
|
||||
@@ -57,7 +86,7 @@ const UserQuestInfo = ({ userInfo }) => {
|
||||
<td>{el.quest_id}</td>
|
||||
<td>{el.quest_name}</td>
|
||||
<td>{el.quest_type}</td>
|
||||
<td>{el.status}</td>
|
||||
<td>{questCompleteStatusType.find(data => el.status === data.value).name || el.status}</td>
|
||||
<td>{convertKTC(el.quest_assign_time, false)}</td>
|
||||
<td>{convertKTC(el.quest_complete_time, false)}</td>
|
||||
<td>
|
||||
@@ -70,7 +99,7 @@ const UserQuestInfo = ({ userInfo }) => {
|
||||
</tbody>
|
||||
</QuestTable>
|
||||
</UserTableWrapper>
|
||||
<QuestDetailModal detailPop={detailPop} handleClick={handleClick} detailQuest={detailQuest} />
|
||||
<QuestDetailModal detailPop={detailPop} handleClick={handleClick} detailQuest={detailQuest} handleQuestComplete={handleQuestComplete} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { styled } from 'styled-components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { FormWrapper, InputLabel, TextInput, SelectInput, BtnWrapper } from '../../styles/Components';
|
||||
|
||||
const UserSearchBar = () => {
|
||||
return (
|
||||
<>
|
||||
<FormWrapper>
|
||||
<SearchbarStyle>
|
||||
<SearchItem>
|
||||
<InputLabel>유저 조회</InputLabel>
|
||||
<TextInput type="text" width="300px" placeholder="조회 대상 유저의 GUID를 입력하세요." />
|
||||
</SearchItem>
|
||||
<BtnWrapper $gap="8px">
|
||||
<Button theme="reset" />
|
||||
<Button
|
||||
theme="primary"
|
||||
text="검색"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</SearchbarStyle>
|
||||
</FormWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserSearchBar;
|
||||
|
||||
const SearchbarStyle = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
font-size: 14px;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
margin-bottom: 40px;
|
||||
`;
|
||||
const SearchItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-right: 50px;
|
||||
|
||||
${TextInput}, ${SelectInput} {
|
||||
height: 35px;
|
||||
}
|
||||
${TextInput} {
|
||||
padding: 0 10px;
|
||||
max-width: 400px;
|
||||
}
|
||||
`;
|
||||
153
src/components/DataManage/UserSnapshotLogContent.js
Normal file
153
src/components/DataManage/UserSnapshotLogContent.js
Normal file
@@ -0,0 +1,153 @@
|
||||
import React, { Fragment, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
CircularProgressWrapper,
|
||||
FormWrapper,
|
||||
TableStyle,
|
||||
TableWrapper,
|
||||
} from '../../styles/Components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { UserSnapshotLogSearchBar, useUserSnapshotLogSearch } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import Pagination from '../common/Pagination/Pagination';
|
||||
import {
|
||||
INITIAL_PAGE_LIMIT,
|
||||
} from '../../assets/data/adminConstants';
|
||||
import ExcelExportButton from '../common/button/ExcelExportButton';
|
||||
import CircularProgress from '../common/CircularProgress';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import { numberFormatter } from '../../utils';
|
||||
|
||||
const UserSnapshotLogContent = ({ active }) => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
const [downloadState, setDownloadState] = useState({
|
||||
loading: false,
|
||||
progress: 0
|
||||
});
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
updateSearchParams
|
||||
} = useUserSnapshotLogSearch(token, 500);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '80px' },
|
||||
{ id: 'accountId', label: 'account ID', width: '80px' },
|
||||
{ id: 'userGuid', label: 'GUID', width: '180px' },
|
||||
{ id: 'userNickname', label: '아바타명', width: '150px' },
|
||||
{ id: 'gold', label: '골드', width: '80px' },
|
||||
{ id: 'sapphire', label: '사파이어', width: '80px' },
|
||||
{ id: 'calium', label: '칼리움', width: '80px' },
|
||||
{ id: 'ruby', label: '루비', width: '80px' },
|
||||
{ id: 'item_13080002', label: '퀘스트 메달', width: '80px' },
|
||||
{ id: 'item_13080004', label: '보급품 메달', width: '80px' },
|
||||
{ id: 'item_13080005', label: '제작 메달', width: '80px' },
|
||||
{ id: 'item_13080006', label: '에테론 315 포드', width: '80px' },
|
||||
{ id: 'item_13080007', label: '에테론 316 포드', width: '80px' },
|
||||
{ id: 'item_13080008', label: '에테론 317 포드', width: '80px' },
|
||||
{ id: 'item_13080009', label: '에테론 318 포드', width: '80px' },
|
||||
{ id: 'item_11570001', label: '강화잉크', width: '80px' },
|
||||
{ id: 'item_11570002', label: '연성잉크', width: '80px' },
|
||||
{ id: 'lastLogoutTime', label: '마지막 로그아웃 일자', width: '150px' },
|
||||
];
|
||||
}, []);
|
||||
|
||||
if(!active) return null;
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<UserSnapshotLogSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo orderType="asc" pageType="B" total={dataList?.total} total_all={dataList?.total_all}>
|
||||
<ExcelExportButton
|
||||
functionName="GameUserSnapshotLogExport"
|
||||
params={searchParams}
|
||||
fileName={t('FILE_GAME_LOG_USER_SNAPSHOT')}
|
||||
onLoadingChange={setDownloadState}
|
||||
dataSize={dataList?.total_all}
|
||||
/>
|
||||
{downloadState.loading && (
|
||||
<CircularProgressWrapper>
|
||||
<CircularProgress
|
||||
progress={downloadState.progress}
|
||||
size={36}
|
||||
progressColor="#4A90E2"
|
||||
/>
|
||||
</CircularProgressWrapper>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => (
|
||||
<th key={header.id} width={header.width}>{header.label}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.snapshot_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logDay}</td>
|
||||
<td>{item.accountId}</td>
|
||||
<td>{item.userGuid}</td>
|
||||
<td>{item.userNickname}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.gold)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.sapphire)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.calium)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.ruby)}</td>
|
||||
<td>{item.item_13080002}</td>
|
||||
<td>{item.item_13080004}</td>
|
||||
<td>{item.item_13080005}</td>
|
||||
<td>{item.item_13080006}</td>
|
||||
<td>{item.item_13080007}</td>
|
||||
<td>{item.item_13080008}</td>
|
||||
<td>{item.item_13080009}</td>
|
||||
<td>{item.item_11570001}</td>
|
||||
<td>{item.item_11570002}</td>
|
||||
<td>{item.lastLogoutTime}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
{dataList?.snapshot_list &&
|
||||
<Pagination
|
||||
postsPerPage={searchParams.page_size}
|
||||
totalPosts={dataList?.total_all}
|
||||
setCurrentPage={handlePageChange}
|
||||
currentPage={searchParams.page_no}
|
||||
pageLimit={INITIAL_PAGE_LIMIT}
|
||||
/>
|
||||
}
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
export default UserSnapshotLogContent;
|
||||
@@ -4,12 +4,14 @@ import { useState, useEffect } from 'react';
|
||||
import { UserTattooView } from '../../apis/Users';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
|
||||
const UserTatttooInfo = ({ userInfo }) => {
|
||||
const UserTattooInfo = ({ userInfo }) => {
|
||||
const [dataList, setDataList] = useState();
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fetchData = async () => {
|
||||
@@ -60,7 +62,7 @@ const UserTatttooInfo = ({ userInfo }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default UserTatttooInfo;
|
||||
export default UserTattooInfo;
|
||||
|
||||
const UserDefaultTable = styled.table`
|
||||
border: 1px solid #e8eaec;
|
||||
|
||||
@@ -9,7 +9,9 @@ const UserToolInfo = ({ userInfo }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
if(userInfo && Object.keys(userInfo).length > 0) {
|
||||
fetchData();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,312 +1,279 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { styled } from 'styled-components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import React, { Fragment, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { CurrencyIndexExport, CurrencyIndexView } from '../../apis';
|
||||
import { SelectInput, TableStyle, TableInfo, ListOption, InputLabel } from '../../styles/Components';
|
||||
import {
|
||||
TableStyle,
|
||||
FormWrapper,
|
||||
TableWrapper, CircularProgressWrapper, TotalRow,
|
||||
} from '../../styles/Components';
|
||||
|
||||
import CreditSeacrhBar from '../../components/IndexManage/CreditSearchBar';
|
||||
import { uniqBy } from 'lodash';
|
||||
import { sumBy } from 'lodash';
|
||||
import { useCurrencyIndexSearch } from '../searchBar';
|
||||
import { Button, TopButton, ViewTableInfo } from '../common';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import {STORAGE_GAME_LOG_CURRENCY_SEARCH, } from '../../assets/data/adminConstants';
|
||||
import ExcelExportButton from '../common/button/ExcelExportButton';
|
||||
import CircularProgress from '../common/CircularProgress';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import CurrencyUserIndexSearchBar from '../searchBar/CurrencyUserIndexSearchBar';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
|
||||
const CreditContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date();
|
||||
const CURRENCY_LIST = [
|
||||
{ "key": "Gold", "name": "골드" },
|
||||
{ "key": "Sapphire", "name": "사파이어" },
|
||||
{ "key": "Calium", "name": "칼리움" },
|
||||
{ "key": "Onyxium", "name": "오닉시움" }
|
||||
];
|
||||
const navigate = useNavigate();
|
||||
const tableRef = useRef(null);
|
||||
const [downloadState, setDownloadState] = useState({
|
||||
loading: false,
|
||||
progress: 0
|
||||
});
|
||||
|
||||
const [sendDate, setSendDate] = useState(START_DATE);
|
||||
const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
const [currencyType, setCurrencyType] = useState('Gold');
|
||||
const [currencyText, setCurrencyText] = useState('골드');
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useCurrencyIndexSearch(token);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [routeData, setRouteData] = useState([]);
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
// 기본 컬럼 (rowSpan=2)
|
||||
{ id: 'logDay', label: '일자', width: '100px', rowSpan: 2 },
|
||||
{ id: 'accountId', label: 'account ID', width: '80px', rowSpan: 2 },
|
||||
{ id: 'userGuid', label: 'GUID', width: '200px', rowSpan: 2 },
|
||||
{ id: 'userNickname', label: '아바타명', width: '150px', rowSpan: 2 },
|
||||
|
||||
// 획득량 그룹 헤더 (첫 번째 행에만 표시)
|
||||
{ id: 'acquired', label: '획득', width: '400px', colSpan: 5, groupHeader: true },
|
||||
|
||||
// 획득량 컬럼 (두 번째 행에만 표시)
|
||||
{ id: 'sapphireAcquired', label: '사파이어', width: '80px', groupRow: true },
|
||||
{ id: 'goldAcquired', label: '골드', width: '80px', groupRow: true },
|
||||
{ id: 'caliumAcquired', label: '칼리움', width: '80px', groupRow: true },
|
||||
{ id: 'beamAcquired', label: 'BEAM', width: '80px', groupRow: true },
|
||||
{ id: 'rubyAcquired', label: '루비', width: '80px', groupRow: true },
|
||||
|
||||
// 소모량 그룹 헤더 (첫 번째 행에만 표시)
|
||||
{ id: 'consumed', label: '소모', width: '400px', colSpan: 5, groupHeader: true },
|
||||
|
||||
// 소모량 컬럼 (두 번째 행에만 표시)
|
||||
{ id: 'sapphireConsumed', label: '사파이어', width: '80px', groupRow: true },
|
||||
{ id: 'goldConsumed', label: '골드', width: '80px', groupRow: true },
|
||||
{ id: 'caliumConsumed', label: '칼리움', width: '80px', groupRow: true },
|
||||
{ id: 'beamConsumed', label: 'BEAM', width: '80px', groupRow: true },
|
||||
{ id: 'rubyConsumed', label: '루비', width: '80px', groupRow: true },
|
||||
|
||||
// 계 컬럼 (rowSpan=2)
|
||||
{ id: 'sapphireNet', label: '사파이어 계', width: '80px', rowSpan: 2 },
|
||||
{ id: 'goldNet', label: '골드 계', width: '80px', rowSpan: 2 },
|
||||
{ id: 'caliumNet', label: '칼리움 계', width: '80px', rowSpan: 2 },
|
||||
{ id: 'beamNet', label: 'BEAM 계', width: '80px', rowSpan: 2 },
|
||||
{ id: 'rubyNet', label: '루비 계', width: '80px', rowSpan: 2 },
|
||||
|
||||
// 기타 컬럼 (rowSpan=2)
|
||||
{ id: 'totalCurrencies', label: '활동 수', width: '80px', rowSpan: 2 },
|
||||
{ id: 'detail', label: '상세', width: '100px', rowSpan: 2 }
|
||||
];
|
||||
|
||||
}, []);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(sendDate, finishDate, currencyType);
|
||||
}, [currencyType]);
|
||||
const totals = useMemo(() => {
|
||||
if (!dataList?.currency_list?.length) return null;
|
||||
|
||||
const fetchData = async (startDate, endDate) => {
|
||||
const newStartDate = new Date(startDate);
|
||||
const newEndDate = new Date(endDate);
|
||||
return dataList.currency_list.reduce((acc, item) => {
|
||||
return {
|
||||
sapphireAcquired: (acc.sapphireAcquired || 0) + (item.sapphireAcquired || 0),
|
||||
sapphireConsumed: (acc.sapphireConsumed || 0) + (item.sapphireConsumed || 0),
|
||||
goldAcquired: (acc.goldAcquired || 0) + (item.goldAcquired || 0),
|
||||
goldConsumed: (acc.goldConsumed || 0) + (item.goldConsumed || 0),
|
||||
caliumAcquired: (acc.caliumAcquired || 0) + (item.caliumAcquired || 0),
|
||||
caliumConsumed: (acc.caliumConsumed || 0) + (item.caliumConsumed || 0),
|
||||
beamAcquired: (acc.beamAcquired || 0) + (item.beamAcquired || 0),
|
||||
beamConsumed: (acc.beamConsumed || 0) + (item.beamConsumed || 0),
|
||||
rubyAcquired: (acc.rubyAcquired || 0) + (item.rubyAcquired || 0),
|
||||
rubyConsumed: (acc.rubyConsumed || 0) + (item.rubyConsumed || 0),
|
||||
sapphireNet: (acc.sapphireNet || 0) + (item.sapphireNet || 0),
|
||||
goldNet: (acc.goldNet || 0) + (item.goldNet || 0),
|
||||
caliumNet: (acc.caliumNet || 0) + (item.caliumNet || 0),
|
||||
beamNet: (acc.beamNet || 0) + (item.beamNet || 0),
|
||||
rubyNet: (acc.rubyNet || 0) + (item.rubyNet || 0),
|
||||
totalCurrencies: (acc.totalCurrencies || 0) + (item.totalCurrencies || 0),
|
||||
};
|
||||
}, {});
|
||||
}, [dataList?.currency_list]);
|
||||
|
||||
const startDateToLocal =
|
||||
newStartDate.getFullYear() +
|
||||
'-' +
|
||||
(newStartDate.getMonth() + 1 < 9 ? '0' + (newStartDate.getMonth() + 1) : newStartDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(newStartDate.getDate() < 9 ? '0' + newStartDate.getDate() : newStartDate.getDate());
|
||||
const handleModalSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
case "detail":
|
||||
const params = {
|
||||
tab: "CURRENCY",
|
||||
start_dt: (() => {
|
||||
const date = new Date(param.logDay);
|
||||
return date;
|
||||
})(),
|
||||
end_dt: (() => {
|
||||
const date = new Date(param.logDay);
|
||||
date.setDate(date.getDate() + 1);
|
||||
return date;
|
||||
})(),
|
||||
guid: param.userGuid
|
||||
};
|
||||
|
||||
const endDateToLocal =
|
||||
newEndDate.getFullYear() +
|
||||
'-' +
|
||||
(newEndDate.getMonth() + 1 < 9 ? '0' + (newEndDate.getMonth() + 1) : newEndDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(newEndDate.getDate() < 9 ? '0' + newEndDate.getDate() : newEndDate.getDate());
|
||||
|
||||
setDataList(await CurrencyIndexView(token, startDateToLocal, endDateToLocal, currencyType));
|
||||
|
||||
|
||||
setSendDate(startDateToLocal);
|
||||
setFinishDate(endDateToLocal);
|
||||
setRoutArray(await CurrencyIndexView(token, startDateToLocal, endDateToLocal, currencyType));
|
||||
};
|
||||
|
||||
const handleCurrencyChange = e => {
|
||||
let value = e.target.value;
|
||||
setCurrencyType(value);
|
||||
CURRENCY_LIST.filter(data => data.key === value).map(data => {
|
||||
setCurrencyText(data.name);
|
||||
});
|
||||
};
|
||||
|
||||
//route data
|
||||
const setRoutArray = async (data) => {
|
||||
let routeArray = [];
|
||||
let routeAcqArr = [];
|
||||
let routeConArr = [];
|
||||
|
||||
//생산량 route
|
||||
data.list && data.list[0].daily_data.filter(routeData => routeData.delta_type === 'ACQUIRE').map(routeData => {
|
||||
routeData.data.map(routeData => {
|
||||
if(!routeAcqArr.includes(routeData.route) ){
|
||||
routeAcqArr.push(routeData.route);
|
||||
}
|
||||
})
|
||||
});
|
||||
routeArray.ACQUIRE = routeAcqArr;
|
||||
|
||||
//소진량 route
|
||||
data.list && data.list[0].daily_data.filter(routeData => routeData.delta_type === 'CONSUME').map(routeData => {
|
||||
routeData.data.map(routeData => {
|
||||
if(!routeConArr.includes(routeData.route) ){
|
||||
routeConArr.push(routeData.route);
|
||||
}
|
||||
})
|
||||
});
|
||||
routeArray.CONSUME = routeConArr;
|
||||
|
||||
setRouteData(routeArray);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_Credit_Index.xlsx';
|
||||
CurrencyIndexExport(token, fileName, sendDate, finishDate, currencyType);
|
||||
};
|
||||
// 복사한 데이터를 세션 스토리지에 저장
|
||||
sessionStorage.setItem(STORAGE_GAME_LOG_CURRENCY_SEARCH, JSON.stringify(params));
|
||||
navigate('/datamanage/gamelogview');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<CurrencyUserIndexSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo >
|
||||
<ExcelExportButton
|
||||
functionName="GameCurrencyLogExport"
|
||||
params={searchParams}
|
||||
fileName={t('FILE_CURRENCY_INDEX')}
|
||||
onLoadingChange={setDownloadState}
|
||||
dataSize={dataList?.length}
|
||||
/>
|
||||
{downloadState.loading && (
|
||||
<CircularProgressWrapper>
|
||||
<CircularProgress
|
||||
progress={downloadState.progress}
|
||||
size={36}
|
||||
progressColor="#4A90E2"
|
||||
/>
|
||||
</CircularProgressWrapper>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{/* 첫 번째 행 - 기본 컬럼 + 그룹 헤더 + rowSpan=2 컬럼 */}
|
||||
{tableHeaders.map(header => {
|
||||
if (header.groupRow) return null; // 두 번째 행의 컬럼은 첫 번째 행에서 건너뜀
|
||||
|
||||
<CreditSeacrhBar fetchData={fetchData} />
|
||||
<TableInfo2>
|
||||
<SelectInput onChange={handleCurrencyChange}>
|
||||
{CURRENCY_LIST.map((item, index) => (
|
||||
<option value={item.key} key={index}>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
<ListOption>
|
||||
<Button theme="line" text="엑셀 다운로드" handleClick={handleXlsxExport} />
|
||||
</ListOption>
|
||||
</TableInfo2>
|
||||
<TableWrapper>
|
||||
<EconomicTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan="2" className="text-center" width="300">
|
||||
Product
|
||||
</th>
|
||||
{dataList.list && uniqBy(dataList.list, 'date').map(data =>
|
||||
<th width="160" key={data.date}>{data.date}</th>
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
width={header.width}
|
||||
rowSpan={header.rowSpan}
|
||||
colSpan={header.colSpan}
|
||||
>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
<tr>
|
||||
{/* 두 번째 행 - 그룹 내 하위 컬럼만 */}
|
||||
{tableHeaders.map(header => {
|
||||
if (!header.groupRow) return null; // 첫 번째 행이나 rowSpan=2 컬럼은 두 번째 행에서 건너뜀
|
||||
|
||||
return (
|
||||
<th key={header.id} width={header.width}>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
{totals && (
|
||||
<TotalRow>
|
||||
<td colSpan="4">합계</td>
|
||||
{/* 획득 그룹 합계 */}
|
||||
<td>{numberFormatter.formatCurrency(totals.sapphireAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.goldAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.caliumAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.beamAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.rubyAcquired)}</td>
|
||||
|
||||
{/* 소모 그룹 합계 */}
|
||||
<td>{numberFormatter.formatCurrency(totals.sapphireConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.goldConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.caliumConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.beamConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.rubyConsumed)}</td>
|
||||
|
||||
{/* 계 합계 */}
|
||||
<td>{numberFormatter.formatCurrency(totals.sapphireNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.goldNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.caliumNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.beamNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(totals.rubyNet)}</td>
|
||||
|
||||
<td>{totals.totalCurrencies}</td>
|
||||
<td>-</td>
|
||||
</TotalRow>
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<TableTitle colSpan="2">(Total) {currencyText} 생산량</TableTitle>
|
||||
{dataList.list &&
|
||||
dataList.list.map((data) =>
|
||||
(data.total).filter(totalData => data.date === totalData.date && totalData.delta_type === 'ACQUIRE')
|
||||
.map((totalData, index) => (
|
||||
<TableData key={index}
|
||||
$state={totalData.dif !== "" && totalData.dif !== "Infinity" ? "danger" : ""}>
|
||||
{totalData.quantity}
|
||||
{
|
||||
totalData.dif !== "" && totalData.dif !== "Infinity"
|
||||
? (<span>({totalData.dif})</span>)
|
||||
: ("")
|
||||
}
|
||||
</TableData>
|
||||
)
|
||||
))
|
||||
}
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle colSpan="2">(Total) {currencyText} 소진량</TableTitle>
|
||||
{dataList.list &&
|
||||
dataList.list.map((data) =>
|
||||
(data.total).filter(totalData => data.date === totalData.date && totalData.delta_type === 'CONSUME')
|
||||
.map((totalData, index) => (
|
||||
<TableData key={index}
|
||||
$state={totalData.dif !== "" && totalData.dif !== "Infinity" ? "danger" : ""}>
|
||||
{totalData.quantity}
|
||||
{
|
||||
totalData.dif !== "" && totalData.dif !== "Infinity"
|
||||
? (<span>({totalData.dif})</span>)
|
||||
: ("")
|
||||
}
|
||||
</TableData>
|
||||
)
|
||||
))
|
||||
}
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle colSpan="2">(Total) {currencyText} 보유량</TableTitle>
|
||||
{dataList.list &&
|
||||
dataList.list.map((data, index) => (
|
||||
<TableData key={index}>
|
||||
{sumBy(
|
||||
data.total.filter(totalData => data.date === totalData.date && totalData.delta_type === 'ACQUIRE'),
|
||||
'quantity',
|
||||
) -
|
||||
sumBy(
|
||||
data.total.filter(totalData => data.date === totalData.date && totalData.delta_type === 'CONSUME'),
|
||||
'quantity',
|
||||
)}
|
||||
</TableData>
|
||||
))
|
||||
}
|
||||
</tr>
|
||||
{/* 획득 GET */}
|
||||
{
|
||||
routeData.ACQUIRE && routeData.ACQUIRE.map((route, index) => (
|
||||
<tr key={index}>
|
||||
<TableTitle>GET</TableTitle>
|
||||
<TableTitle>{route}</TableTitle>
|
||||
{dataList.list &&
|
||||
dataList.list.map((data) =>
|
||||
data.daily_data.filter(dailyData => data.date === dailyData.date && dailyData.delta_type === 'ACQUIRE')
|
||||
.map(dailyData => (dailyData.data).filter(routeData => data.date === routeData.date && routeData.route === route)
|
||||
.map((routeData, i) => (
|
||||
<TableData key={i} data={routeData.date}>{routeData.quantity}</TableData>
|
||||
)))
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
{/* 소진 USE CONSUME */}
|
||||
{
|
||||
routeData.CONSUME && routeData.CONSUME.map((route, index) => (
|
||||
<tr key={index}>
|
||||
<TableTitle>USE</TableTitle>
|
||||
<TableTitle>{route}</TableTitle>
|
||||
{dataList.list &&
|
||||
dataList.list.map((data) =>
|
||||
data.daily_data.filter(dailyData => data.date === dailyData.date && dailyData.delta_type === 'CONSUME')
|
||||
.map(dailyData => (dailyData.data).filter(routeData => data.date === routeData.date && routeData.route === route)
|
||||
.map((routeData, i) => (
|
||||
<TableData key={i} data={routeData.date}>{routeData.quantity}</TableData>
|
||||
)))
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</EconomicTable>
|
||||
</TableWrapper>
|
||||
</>
|
||||
{dataList?.currency_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
{/* 기본 정보 */}
|
||||
<td>{item.logDay}</td>
|
||||
<td>{item.accountId}</td>
|
||||
<td>{item.userGuid}</td>
|
||||
<td>{item.userNickname}</td>
|
||||
|
||||
{/* 획득 그룹 */}
|
||||
<td>{numberFormatter.formatCurrency(item.sapphireAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.goldAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.caliumAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.beamAcquired)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.rubyAcquired)}</td>
|
||||
|
||||
{/* 소모 그룹 */}
|
||||
<td>{numberFormatter.formatCurrency(item.sapphireConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.goldConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.caliumConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.beamConsumed)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.rubyConsumed)}</td>
|
||||
|
||||
{/* 계 */}
|
||||
<td>{numberFormatter.formatCurrency(item.sapphireNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.goldNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.caliumNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.beamNet)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.rubyNet)}</td>
|
||||
|
||||
<td>{item.totalCurrencies}</td>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기"
|
||||
handleClick={e => handleModalSubmit('detail', item)} />
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreditContent;
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
width: 100%;
|
||||
min-width: 680px;
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
${TableStyle} {
|
||||
width: 100%;
|
||||
min-width: 900px;
|
||||
th {
|
||||
&.cell-nru {
|
||||
background: #f0f0f0;
|
||||
border-left: 1px solid #aaa;
|
||||
border-right: 1px solid #aaa;
|
||||
}
|
||||
}
|
||||
td {
|
||||
&.blank {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
&.cell-nru {
|
||||
background: #fafafa;
|
||||
border-left: 1px solid #aaa;
|
||||
border-right: 1px solid #aaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const TableInfo2 = styled(TableInfo)`
|
||||
justify-content: space-between;
|
||||
${InputLabel} {
|
||||
font-size: 12px;
|
||||
}
|
||||
${SelectInput} {
|
||||
width: auto;
|
||||
min-width: 100px;
|
||||
height: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const TableDate = styled.th`
|
||||
color: ${props => (props.$state === 'danger' ? '#d60000' : '#2c2c2c')};
|
||||
`;
|
||||
|
||||
const TableData = styled.td`
|
||||
|
||||
background: ${props => (props.$state === 'danger' ? '#d60000' : props.$state === 'blank' ? '#F9F9F9' : 'transparent')};
|
||||
color: ${props => (props.$state === 'danger' ? '#fff' : '#2c2c2c')};
|
||||
`;
|
||||
|
||||
const perData = styled.span`
|
||||
display: ${props => (props.$view === 'hidden' ? 'none' : 'block')};
|
||||
`;
|
||||
|
||||
const TableTitle = styled.td`
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const EconomicTable = styled(TableStyle)`
|
||||
${TableData} {
|
||||
text-align: left;
|
||||
}
|
||||
tbody {
|
||||
tr:nth-child(1),
|
||||
tr:nth-child(2),
|
||||
tr:nth-child(3) {
|
||||
background: #f5fcff;
|
||||
}
|
||||
}
|
||||
`;
|
||||
126
src/components/IndexManage/CurrencyAcquireContent.js
Normal file
126
src/components/IndexManage/CurrencyAcquireContent.js
Normal file
@@ -0,0 +1,126 @@
|
||||
import React, { Fragment, useMemo, useRef } from 'react';
|
||||
|
||||
import {
|
||||
TableStyle,
|
||||
FormWrapper,
|
||||
TableWrapper, ListOption,
|
||||
} from '../../styles/Components';
|
||||
|
||||
import { useCurrencyAcquireIndexSearch, CurrencyAcquireIndexSearchBar } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import CSVDownloadButton from '../common/button/CsvDownButton';
|
||||
|
||||
const CurrencyAcquireContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useCurrencyAcquireIndexSearch(token);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '100px' },
|
||||
{ id: 'mail', label: '우편', width: '80px' },
|
||||
{ id: 'ShopSell', label: '상점 판매', width: '80px' },
|
||||
{ id: 'ShopPurchase', label: '상점 구매', width: '80px' },
|
||||
{ id: 'seasonPass', label: '시즌 패스', width: '80px' },
|
||||
{ id: 'claim', label: '클레임', width: '80px' },
|
||||
{ id: 'quest', label: '퀘스트', width: '80px' },
|
||||
{ id: 'ugq', label: 'UGQ', width: '80px' },
|
||||
{ id: 'battleObject', label: '보급품 상자', width: '80px' },
|
||||
{ id: 'randomBox', label: '랜덤박스', width: '80px' },
|
||||
{ id: 'landRent', label: '랜드 임대', width: '80px' },
|
||||
{ id: 'caliumExchange', label: '칼리움 교환소', width: '80px' },
|
||||
{ id: 'caliumConverter', label: '칼리움 컨버터', width: '80px' },
|
||||
{ id: 'beaconShop', label: '비컨 상점', width: '80px' },
|
||||
{ id: 'etc', label: '기타', width: '80px' },
|
||||
{ id: 'summary', label: '합계', width: '80px' },
|
||||
];
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<CurrencyAcquireIndexSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo >
|
||||
<ListOption>
|
||||
<CSVDownloadButton tableRef={tableRef} fileName={t('FILE_INDEX_CURRENCY_ACQUIRE')} />
|
||||
</ListOption>
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
width={header.width}
|
||||
colSpan={header.colSpan}
|
||||
>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{dataList?.currency_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logDay}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.MailTaken)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ShopSell)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ShopPurchase)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.SeasonPassTakeReward)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ClaimReward)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.QuestMainReward || 0) + (item.actionSummary.QuestTaskUpdate || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.UgqAbort)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.RewardProp)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ItemRandomBoxUse)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.GainLandProfit)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ConvertExchangeCalium)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ConvertCalium)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BeaconSell || 0) + (item.actionSummary.BeaconShopReceivePaymentForSales || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.MoneyChange)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.totalDeltaAmount)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default CurrencyAcquireContent;
|
||||
109
src/components/IndexManage/CurrencyAssetsContent.js
Normal file
109
src/components/IndexManage/CurrencyAssetsContent.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import React, { Fragment, useMemo, useRef } from 'react';
|
||||
|
||||
import {
|
||||
TableStyle,
|
||||
FormWrapper,
|
||||
TableWrapper, ListOption
|
||||
} from '../../styles/Components';
|
||||
|
||||
import {
|
||||
AssetsIndexSearchBar, useAssetsIndexSearch,
|
||||
} from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import CSVDownloadButton from '../common/button/CsvDownButton';
|
||||
import DailyDashBoard from './DailyCaliumDashBoard';
|
||||
|
||||
const CurrencyAssetsContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useAssetsIndexSearch(token);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '100px' },
|
||||
{ id: 'userCount', label: '유저수', width: '100px' },
|
||||
{ id: 'gold', label: '골드', width: '100px' },
|
||||
{ id: 'sapphire', label: '사파이어', width: '100px' },
|
||||
{ id: 'calium', label: '칼리움', width: '100px' },
|
||||
{ id: 'ruby', label: '루비', width: '100px' }
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<DailyDashBoard />
|
||||
<FormWrapper>
|
||||
<AssetsIndexSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo >
|
||||
<ListOption>
|
||||
<CSVDownloadButton tableRef={tableRef} fileName={t('FILE_INDEX_ASSETS_CURRENCY')} />
|
||||
</ListOption>
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
width={header.width}
|
||||
colSpan={header.colSpan}
|
||||
>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{dataList?.assets_list?.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{data.logDay}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.userCount)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.gold)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.sapphire)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.calium)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.ruby)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default CurrencyAssetsContent;
|
||||
128
src/components/IndexManage/CurrencyConsumeContent.js
Normal file
128
src/components/IndexManage/CurrencyConsumeContent.js
Normal file
@@ -0,0 +1,128 @@
|
||||
import React, { Fragment, useMemo, useRef } from 'react';
|
||||
|
||||
import {
|
||||
TableStyle,
|
||||
FormWrapper,
|
||||
TableWrapper, ListOption,
|
||||
} from '../../styles/Components';
|
||||
|
||||
import {
|
||||
useCurrencyConsumeIndexSearch, CurrencyConsumeIndexSearchBar,
|
||||
} from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import CSVDownloadButton from '../common/button/CsvDownButton';
|
||||
|
||||
const CurrencyConsumeContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useCurrencyConsumeIndexSearch(token);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '100px' },
|
||||
{ id: 'itemBuy', label: '아이템 구매', width: '80px' },
|
||||
{ id: 'ShopPurchase', label: '상점 구매', width: '80px' },
|
||||
{ id: 'ShopRePurchase', label: '상점 재구매', width: '80px' },
|
||||
{ id: 'beaconShop', label: '비컨상점', width: '80px' },
|
||||
{ id: 'beacon', label: '비컨', width: '80px' },
|
||||
{ id: 'taxi', label: '택시', width: '80px' },
|
||||
{ id: 'farming', label: '파밍', width: '80px' },
|
||||
{ id: 'seasonPass', label: '시즌 패스', width: '80px' },
|
||||
{ id: 'caliumExchange', label: '칼리움 교환소', width: '80px' },
|
||||
{ id: 'caliumConverter', label: '칼리움 컨버터', width: '80px' },
|
||||
{ id: 'rent', label: '랜드 렌탈', width: '80px' },
|
||||
{ id: 'landAuction', label: '랜드 경매', width: '80px' },
|
||||
{ id: 'ugq', label: 'UGQ', width: '80px' },
|
||||
{ id: 'etc', label: '기타', width: '80px' },
|
||||
{ id: 'summary', label: '합계', width: '80px' },
|
||||
];
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<CurrencyConsumeIndexSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo >
|
||||
<ListOption>
|
||||
<CSVDownloadButton tableRef={tableRef} fileName={t('FILE_INDEX_CURRENCY_CONSUME')} />
|
||||
</ListOption>
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
width={header.width}
|
||||
colSpan={header.colSpan}
|
||||
>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{dataList?.currency_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logDay}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ItemBuy)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ShopPurchase)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ShopRePurchase)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BeaconShopRegisterItem || 0) + (item.actionSummary.BeaconShopPurchaseItem || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BeaconCreate || 0) + (item.actionSummary.BeaconEdit || 0) + (item.actionSummary.BeaconAppearanceCustomize || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.TaxiMove)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.FarmingStart)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.SeasonPassBuyCharged)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ConvertExchangeCalium)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ConvertCalium)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.RentFloor)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.LandAuctionBid)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.UgqAssign)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.MoneyChange ||0) + (item.actionSummary.RenewalShopProducts ||0) + (item.actionSummary.CharacterAppearanceCustomize ||0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.totalDeltaAmount)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default CurrencyConsumeContent;
|
||||
@@ -1,110 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { TableStyle, TableInfo, ListOption, IndexTableWrap } from '../../styles/Components';
|
||||
import { DailySearchBar } from '../../components/IndexManage/index';
|
||||
import { DailyActiveUserExport, DailyActiveUserView } from '../../apis';
|
||||
|
||||
const PlayTimeContent = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date();
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [resultData, setResultData] = useState([]);
|
||||
|
||||
const [sendDate, setSendDate] = useState(START_DATE);
|
||||
const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(START_DATE, END_DATE);
|
||||
}, []);
|
||||
|
||||
// DAU 데이터
|
||||
const fetchData = async (startDate, endDate) => {
|
||||
const startDateToLocal =
|
||||
startDate.getFullYear() +
|
||||
'-' +
|
||||
(startDate.getMonth() + 1 < 9 ? '0' + (startDate.getMonth() + 1) : startDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(startDate.getDate() < 9 ? '0' + startDate.getDate() : startDate.getDate());
|
||||
|
||||
const endDateToLocal =
|
||||
endDate.getFullYear() +
|
||||
'-' +
|
||||
(endDate.getMonth() + 1 < 9 ? '0' + (endDate.getMonth() + 1) : endDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(endDate.getDate() < 9 ? '0' + endDate.getDate() : endDate.getDate());
|
||||
|
||||
// await DailyActiveUserView(token, startDateToLocal, endDateToLocal).then(data => {
|
||||
// console.log(data);
|
||||
// setDataList(data);
|
||||
// });
|
||||
|
||||
setSendDate(startDateToLocal);
|
||||
setFinishDate(endDateToLocal);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (send_dt, end_dt) => {
|
||||
fetchData(send_dt, end_dt);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_Dau.xlsx';
|
||||
DailyActiveUserExport(token, fileName, sendDate, finishDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DailySearchBar setResultData={setResultData} resultData={resultData} handleSearch={handleSearch} fetchData={fetchData} />
|
||||
<TableInfo>
|
||||
<ListOption>
|
||||
<Button theme="line" text="엑셀 다운로드" handleClick={handleXlsxExport} />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<IndexTableWrap>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowSpan="1" width="45">
|
||||
일자
|
||||
</th>
|
||||
<th colSpan="1" width="30">
|
||||
DAU
|
||||
</th>
|
||||
{/*<th colSpan="1" width="30">*/}
|
||||
{/* DALC*/}
|
||||
{/*</th>*/}
|
||||
<th colSpan="1" width="30">
|
||||
DGLC
|
||||
</th>
|
||||
{/*<th colSpan="1" width="30">*/}
|
||||
{/* MaxAU*/}
|
||||
{/*</th>*/}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
{dataList && (dataList || []).map((data, index) => (
|
||||
<tr key={index}>
|
||||
<td>{data.date}</td>
|
||||
<td>{data.dau}</td>
|
||||
{/*<td>{data.dalc}</td>*/}
|
||||
<td>{data.dglc}</td>
|
||||
{/*<td>{data.maxAu}</td>*/}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</IndexTableWrap>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlayTimeContent;
|
||||
|
||||
141
src/components/IndexManage/DailyCaliumDashBoard.js
Normal file
141
src/components/IndexManage/DailyCaliumDashBoard.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { dashboardCaliumIndex } from '../../apis';
|
||||
|
||||
import { styled } from 'styled-components';
|
||||
import TitleArrow from '../../assets/img/icon/icon-title.png';
|
||||
|
||||
const DailyDashBoard = () => {
|
||||
const [boardState, setBoardState] = useState('active');
|
||||
const [totalData, setTotalData] = useState([]);
|
||||
|
||||
const handleBoard = () => {
|
||||
if (boardState === 'active') {
|
||||
setBoardState('inactive');
|
||||
} else {
|
||||
setBoardState('active');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const fetchData = async () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
await dashboardCaliumIndex(token).then(data => {
|
||||
setTotalData(data.dashboard_calium);
|
||||
});
|
||||
};
|
||||
|
||||
const dashboardItems = [
|
||||
{
|
||||
title: '컨버터 칼리움 보유량',
|
||||
value: totalData.total_calium || 0
|
||||
},
|
||||
{
|
||||
title: '컨버터 변환 효율',
|
||||
value: `${totalData.converter_rate || 0}%`
|
||||
},
|
||||
{
|
||||
title: '인플레이션 가중치',
|
||||
value: `${totalData.inflation_rate || 0}%`
|
||||
},
|
||||
{
|
||||
title: '칼리움 누적 총량',
|
||||
value: totalData.cumulative_calium || 0
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<DailyBoardWrapper>
|
||||
{totalData &&
|
||||
<DailyBoard>
|
||||
<BoardTitle onClick={handleBoard} $state={boardState}>
|
||||
Daily Dashboard
|
||||
</BoardTitle>
|
||||
<BoardInfo $state={boardState}>
|
||||
<BoxWrapper>
|
||||
{dashboardItems?.map((item, index) => (
|
||||
<InfoItem key={index}>
|
||||
<InfoTitle>{item.title}</InfoTitle>
|
||||
<InfoValue>
|
||||
{item.value}
|
||||
</InfoValue>
|
||||
</InfoItem>
|
||||
))}
|
||||
</BoxWrapper>
|
||||
</BoardInfo>
|
||||
</DailyBoard>
|
||||
}
|
||||
</DailyBoardWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default DailyDashBoard;
|
||||
|
||||
const DailyBoardWrapper = styled.div`
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #000;
|
||||
`;
|
||||
|
||||
const DailyBoard = styled.div`
|
||||
background: #f6f6f6;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
`;
|
||||
|
||||
const BoardTitle = styled.div`
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
line-height: 52px;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
&:after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 11px;
|
||||
height: 52px;
|
||||
margin-left: 10px;
|
||||
background: url(${TitleArrow}) 50% 50% no-repeat;
|
||||
position: absolute;
|
||||
transform: ${props => (props.$state === 'active' ? 'rotate(0)' : 'rotate(180deg)')};
|
||||
}
|
||||
`;
|
||||
|
||||
const BoardInfo = styled.div`
|
||||
padding: 20px;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
display: ${props => (props.$state === 'active' ? 'block' : 'none')};
|
||||
`;
|
||||
|
||||
const BoxWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
`;
|
||||
|
||||
const InfoItem = styled.div`
|
||||
width: 18%;
|
||||
background: #fff;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-radius: 15px;
|
||||
`;
|
||||
|
||||
const InfoTitle = styled.div`
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const InfoValue = styled.div`
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 5px 0;
|
||||
gap: 5px 0;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
`;
|
||||
@@ -26,7 +26,6 @@ const DailyDashBoard = ({ content }) => {
|
||||
const fetchData = async () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
await userTotalIndex(token).then(data => {
|
||||
console.log(data);
|
||||
setTotalData(data.dashboard);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
|
||||
import Button from '../common/button/Button';
|
||||
|
||||
import { TableStyle, TableInfo, ListOption, IndexTableWrap } from '../../styles/Components';
|
||||
import { DailySearchBar } from './index';
|
||||
import { DailyMedalView } from '../../apis';
|
||||
|
||||
const DailyMedalContent = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date();
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [resultData, setResultData] = useState([]);
|
||||
|
||||
const [sendDate, setSendDate] = useState(START_DATE);
|
||||
const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(START_DATE, END_DATE);
|
||||
}, []);
|
||||
|
||||
const fetchData = async (startDate, endDate) => {
|
||||
const startDateToLocal =
|
||||
startDate.getFullYear() +
|
||||
'-' +
|
||||
(startDate.getMonth() + 1 < 9 ? '0' + (startDate.getMonth() + 1) : startDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(startDate.getDate() < 9 ? '0' + startDate.getDate() : startDate.getDate());
|
||||
|
||||
const endDateToLocal =
|
||||
endDate.getFullYear() +
|
||||
'-' +
|
||||
(endDate.getMonth() + 1 < 9 ? '0' + (endDate.getMonth() + 1) : endDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(endDate.getDate() < 9 ? '0' + endDate.getDate() : endDate.getDate());
|
||||
|
||||
setDataList(await DailyMedalView(token, startDateToLocal, endDateToLocal));
|
||||
|
||||
setSendDate(startDateToLocal);
|
||||
setFinishDate(endDateToLocal);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (send_dt, end_dt) => {
|
||||
fetchData(send_dt, end_dt);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_Daily_Medal.xlsx';
|
||||
//DailyActiveUserExport(token, fileName, sendDate, finishDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DailySearchBar setResultData={setResultData} resultData={resultData} handleSearch={handleSearch} fetchData={fetchData} />
|
||||
<TableInfo>
|
||||
<ListOption>
|
||||
<Button theme="line" text="엑셀 다운로드" handleClick={handleXlsxExport} />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<IndexTableWrap>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead >
|
||||
<tr>
|
||||
<th rowSpan="1" width="20">
|
||||
일자
|
||||
</th>
|
||||
<th colSpan="1" width="30">
|
||||
UserID
|
||||
</th>
|
||||
<th colSpan="1" width="30">
|
||||
닉네임
|
||||
</th>
|
||||
<th colSpan="1" width="30">
|
||||
Item ID
|
||||
</th>
|
||||
<th colSpan="1" width="30">
|
||||
획득량
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
{(dataList || []).map((data, index) => (
|
||||
<tr key={index}>
|
||||
<td>{data.date}</td>
|
||||
<td>{data.dau}</td>
|
||||
<td>{data.dalc}</td>
|
||||
<td>{data.dglc}</td>
|
||||
<td>{data.maxAu}</td>
|
||||
{Array.from({ length: 24 }, (_, i) => (
|
||||
<td key={i}>{data['h' + i]}</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</IndexTableWrap>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DailyMedalContent;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import DecoSearchBar from '../../components/IndexManage/DecoSearchBar';
|
||||
import DecoSearchBar from '../searchBar/DecoSearchBar';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { TableStyle, TableInfo, ListOption } from '../../styles/Components';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
|
||||
import { TableStyle, TableInfo, ListOption } from '../../styles/Components';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
import InstanceSearchBar from '../../components/IndexManage/InstanceSearchBar';
|
||||
import InstanceSearchBar from '../searchBar/InstanceSearchBar';
|
||||
import { InstanceIndexExport, InstanceIndexView } from '../../apis';
|
||||
|
||||
const InstanceContent = () => {
|
||||
|
||||
152
src/components/IndexManage/ItemAcquireContent.js
Normal file
152
src/components/IndexManage/ItemAcquireContent.js
Normal file
@@ -0,0 +1,152 @@
|
||||
import React, { Fragment, useMemo, useRef } from 'react';
|
||||
|
||||
import {
|
||||
TableStyle,
|
||||
FormWrapper,
|
||||
TableWrapper, ListOption, TextInput, TableInfoContent, Notice,
|
||||
} from '../../styles/Components';
|
||||
|
||||
import { ItemAcquireIndexSearchBar, useItemAcquireIndexSearch } from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import CSVDownloadButton from '../common/button/CsvDownButton';
|
||||
|
||||
const ItemAcquireContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useItemAcquireIndexSearch(token);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '100px' },
|
||||
{ id: 'mail', label: '우편', width: '80px' },
|
||||
{ id: 'shopPurchase', label: '상점 구매', width: '80px' },
|
||||
{ id: 'shopRePurchase', label: '상점 재구매', width: '80px' },
|
||||
{ id: 'itemBuy', label: '아이템 구매', width: '80px' },
|
||||
{ id: 'itemUse', label: '아이템 사용', width: '80px' },
|
||||
{ id: 'seasonPass', label: '시즌 패스', width: '80px' },
|
||||
{ id: 'claim', label: '클레임', width: '80px' },
|
||||
{ id: 'quest', label: '퀘스트', width: '80px' },
|
||||
{ id: 'ugq', label: 'UGQ', width: '80px' },
|
||||
{ id: 'battleObject', label: '배틀맵', width: '80px' },
|
||||
{ id: 'runRace', label: '런레이스', width: '80px' },
|
||||
{ id: 'prop', label: '보급품 상자', width: '80px' },
|
||||
{ id: 'randomBox', label: '랜덤박스', width: '80px' },
|
||||
{ id: 'beacon', label: '비컨', width: '80px' },
|
||||
{ id: 'beaconShop', label: '비컨 상점', width: '80px' },
|
||||
{ id: 'myHome', label: '마이홈', width: '80px' },
|
||||
{ id: 'craft', label: '크래프트', width: '80px' },
|
||||
{ id: 'etc', label: '기타', width: '80px' },
|
||||
{ id: 'summary', label: '합계', width: '80px' },
|
||||
];
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<ItemAcquireIndexSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo >
|
||||
{dataList?.item_list && dataList.item_list.length > 0 &&
|
||||
<TableInfoContent>
|
||||
<TextInput
|
||||
type="text"
|
||||
value={dataList.item_list[0].itemId}
|
||||
width="100px"
|
||||
readOnly
|
||||
/>
|
||||
<TextInput
|
||||
type="text"
|
||||
value={dataList.item_list[0].itemName}
|
||||
width="150px"
|
||||
readOnly
|
||||
/>
|
||||
<Notice $color='#F15F5F'>* 확인되지 않은 액션이 있을 수 있습니다</Notice>
|
||||
</TableInfoContent>
|
||||
}
|
||||
<ListOption>
|
||||
<CSVDownloadButton tableRef={tableRef} fileName={t('FILE_INDEX_ITEM_ACQUIRE')} />
|
||||
</ListOption>
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
width={header.width}
|
||||
colSpan={header.colSpan}
|
||||
>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{dataList?.item_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logDay}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.MailTaken)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ShopPurchase)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ShopRePurchase)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ItemBuy)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ItemUse)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.SeasonPassTakeReward)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ClaimReward)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.QuestMainReward || 0) + (item.actionSummary.QuestTaskUpdate || 0) + (item.actionSummary.QuestMainTask || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.UgqAbort)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BattleRoundStateUpdate || 0) + (item.actionSummary.BattlePodCombatOccupyReward || 0) + (item.actionSummary.BattleObjectInteraction || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.RunRaceFinishReward || 0) + (item.actionSummary.RunRaceRespawnReward || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.RewardProp)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ItemRandomBoxUse)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BeaconCreate || 0) + (item.actionSummary.BeaconEdit || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BeaconShopPurchaseItem || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.DeleteMyhome || 0) + (item.actionSummary.SaveMyhome || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.CraftFinish || 0) + (item.actionSummary.CraftStop || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.CheatCommandItem || 0) + (item.actionSummary.CharacterAppearanceUpdate || 0)
|
||||
+ (item.actionSummary.ItemTattooLevelUp || 0) + (item.actionSummary.UserCreate || 0) + (item.actionSummary.JoinInstance || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.totalDeltaCount)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ItemAcquireContent;
|
||||
119
src/components/IndexManage/ItemAssetsContent.js
Normal file
119
src/components/IndexManage/ItemAssetsContent.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import React, { Fragment, useMemo, useRef } from 'react';
|
||||
|
||||
import {
|
||||
TableStyle,
|
||||
FormWrapper,
|
||||
TableWrapper, ListOption
|
||||
} from '../../styles/Components';
|
||||
|
||||
import {
|
||||
AssetsIndexSearchBar, useAssetsIndexSearch,
|
||||
} from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import CSVDownloadButton from '../common/button/CsvDownButton';
|
||||
import DailyDashBoard from './DailyCaliumDashBoard';
|
||||
|
||||
const ItemAssetsContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useAssetsIndexSearch(token);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '100px' },
|
||||
{ id: 'userCount', label: '유저수', width: '100px' },
|
||||
{ id: 'item_13080002', label: '퀘스트 메달', width: '100px' },
|
||||
{ id: 'item_13080004', label: '보급품 메달', width: '100px' },
|
||||
{ id: 'item_13080005', label: '제작 메달', width: '100px' },
|
||||
{ id: 'item_13080006', label: '에테론 315 포드', width: '100px' },
|
||||
{ id: 'item_13080007', label: '에테론 316 포드', width: '100px' },
|
||||
{ id: 'item_13080008', label: '에테론 317 포드', width: '100px' },
|
||||
{ id: 'item_13080009', label: '에테론 318 포드', width: '100px' },
|
||||
{ id: 'item_11570001', label: '강화 잉크', width: '100px' },
|
||||
{ id: 'item_11570002', label: '연성 잉크', width: '100px' }
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<DailyDashBoard />
|
||||
<FormWrapper>
|
||||
<AssetsIndexSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo >
|
||||
<ListOption>
|
||||
<CSVDownloadButton tableRef={tableRef} fileName={t('FILE_INDEX_ASSETS_ITEM')} />
|
||||
</ListOption>
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
width={header.width}
|
||||
colSpan={header.colSpan}
|
||||
>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{dataList?.assets_list?.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{data.logDay}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.userCount)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_13080002)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_13080004)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_13080005)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_13080006)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_13080007)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_13080008)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_13080009)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_11570001)}</td>
|
||||
<td>{numberFormatter.formatCurrency(data.item_11570002)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ItemAssetsContent;
|
||||
143
src/components/IndexManage/ItemConsumeContent.js
Normal file
143
src/components/IndexManage/ItemConsumeContent.js
Normal file
@@ -0,0 +1,143 @@
|
||||
import React, { Fragment, useMemo, useRef } from 'react';
|
||||
|
||||
import {
|
||||
TableStyle,
|
||||
FormWrapper,
|
||||
TableWrapper, ListOption, TableInfoContent, TextInput, Label, Notice,
|
||||
} from '../../styles/Components';
|
||||
|
||||
import {
|
||||
ItemAcquireIndexSearchBar,
|
||||
ItemConsumeIndexSearchBar,
|
||||
useItemAcquireIndexSearch,
|
||||
useItemConsumeIndexSearch,
|
||||
} from '../searchBar';
|
||||
import { TopButton, ViewTableInfo } from '../common';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import CSVDownloadButton from '../common/button/CsvDownButton';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const ItemConsumeContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useItemConsumeIndexSearch(token);
|
||||
|
||||
const tableHeaders = useMemo(() => {
|
||||
return [
|
||||
{ id: 'logDay', label: '일자', width: '100px' },
|
||||
{ id: 'shopSell', label: '상점 판매', width: '80px' },
|
||||
{ id: 'itemUse', label: '아이템 사용', width: '80px' },
|
||||
{ id: 'beaconShop', label: '비컨상점', width: '80px' },
|
||||
{ id: 'beacon', label: '비컨', width: '80px' },
|
||||
{ id: 'quest', label: '퀘스트', width: '80px' },
|
||||
{ id: 'ugq', label: 'UGQ', width: '80px' },
|
||||
{ id: 'randomBox', label: '랜덤박스', width: '80px' },
|
||||
{ id: 'myHome', label: '마이홈', width: '80px' },
|
||||
{ id: 'craft', label: '크래프트', width: '80px' },
|
||||
{ id: 'etc', label: '기타', width: '80px' },
|
||||
{ id: 'summary', label: '합계', width: '80px' },
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AnimatedPageWrapper>
|
||||
<FormWrapper>
|
||||
<ItemConsumeIndexSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo >
|
||||
{dataList?.item_list && dataList.item_list.length > 0 &&
|
||||
<TableInfoContent>
|
||||
<TextInput
|
||||
type="text"
|
||||
value={dataList.item_list[0].itemId}
|
||||
width="100px"
|
||||
readOnly
|
||||
/>
|
||||
<TextInput
|
||||
type="text"
|
||||
value={dataList.item_list[0].itemName}
|
||||
width="300px"
|
||||
readOnly
|
||||
/>
|
||||
<Notice $color='#F15F5F'>* 확인되지 않은 액션이 있을 수 있습니다</Notice>
|
||||
</TableInfoContent>
|
||||
}
|
||||
<ListOption>
|
||||
<CSVDownloadButton tableRef={tableRef} fileName={t('FILE_INDEX_ITEM_CONSUME')} />
|
||||
</ListOption>
|
||||
</ViewTableInfo>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
{tableHeaders.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
width={header.width}
|
||||
colSpan={header.colSpan}
|
||||
>
|
||||
{header.label}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{dataList?.item_list?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{item.logDay}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ShopSell)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ItemUse)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BeaconShopRegisterItem || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.BeaconEdit || 0) + (item.actionSummary.BeaconCreate || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.QuestTaskUpdate || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.UgqAbort)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.actionSummary.ItemRandomBoxUse)}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.SaveMyhome || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency((item.actionSummary.CraftStart || 0))}</td>
|
||||
<td>{numberFormatter.formatCurrency(
|
||||
(item.actionSummary.SummonParty || 0) + (item.actionSummary.ItemDestroy || 0) + (item.actionSummary.CreatePartyInstance || 0) + (item.actionSummary.ItemTattooChangeAttribute || 0)
|
||||
+ (item.actionSummary.CheatCommandItem || 0) + (item.actionSummary.ItemDestoryByExpiration || 0) + (item.actionSummary.ItemDestroyByUser || 0) + (item.actionSummary.ItemTattooLevelUp || 0)
|
||||
)}</td>
|
||||
<td>{numberFormatter.formatCurrency(item.totalDeltaCount)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<TopButton />
|
||||
</>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ItemConsumeContent;
|
||||
@@ -5,7 +5,7 @@ import Button from '../../components/common/button/Button';
|
||||
|
||||
import { SelectInput, TableStyle, TableInfo, ListOption, InputLabel, InputGroup } from '../../styles/Components';
|
||||
|
||||
import ItemSearchBar from '../../components/IndexManage/ItemSearchBar';
|
||||
import ItemSearchBar from '../searchBar/ItemSearchBar';
|
||||
import { ItemIndexExport, ItemIndexView } from '../../apis';
|
||||
|
||||
const ItemContent = () => {
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { TableStyle, TableInfo, ListOption, IndexTableWrap } from '../../styles/Components';
|
||||
import { PlayTimeSearchBar } from '../../components/IndexManage/index';
|
||||
import { PlaytimeIndexExport, PlaytimeIndexView } from '../../apis';
|
||||
|
||||
const PlayTimeContent = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date();
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [resultData, setResultData] = useState([]);
|
||||
|
||||
const [sendDate, setSendDate] = useState(START_DATE);
|
||||
const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(START_DATE, END_DATE);
|
||||
}, []);
|
||||
|
||||
// 이용자 지표 데이터
|
||||
const fetchData = async (startDate, endDate) => {
|
||||
const startDateToLocal =
|
||||
startDate.getFullYear() +
|
||||
'-' +
|
||||
(startDate.getMonth() + 1 < 9 ? '0' + (startDate.getMonth() + 1) : startDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(startDate.getDate() < 9 ? '0' + startDate.getDate() : startDate.getDate());
|
||||
|
||||
const endDateToLocal =
|
||||
endDate.getFullYear() +
|
||||
'-' +
|
||||
(endDate.getMonth() + 1 < 9 ? '0' + (endDate.getMonth() + 1) : endDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(endDate.getDate() < 9 ? '0' + endDate.getDate() : endDate.getDate());
|
||||
|
||||
setDataList(await PlaytimeIndexView(token, startDateToLocal, endDateToLocal));
|
||||
|
||||
setSendDate(startDateToLocal);
|
||||
setFinishDate(endDateToLocal);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (send_dt, end_dt) => {
|
||||
fetchData(send_dt, end_dt);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_PlayTime_Index.xlsx';
|
||||
PlaytimeIndexExport(token, fileName, sendDate, finishDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<PlayTimeSearchBar setResultData={setResultData} resultData={resultData} handleSearch={handleSearch} fetchData={fetchData} />
|
||||
<TableInfo>
|
||||
<ListOption>
|
||||
<Button theme="line" text="엑셀 다운로드" handleClick={handleXlsxExport} />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<IndexTableWrap>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowSpan="2" width="140">
|
||||
일자
|
||||
</th>
|
||||
<th colSpan="4" width="520">
|
||||
유저수
|
||||
</th>
|
||||
<th rowSpan="2" width="160">
|
||||
총 누적 플레이타임(분)
|
||||
</th>
|
||||
<th rowSpan="2" width="160">
|
||||
1인당 평균 플레이타임(분)
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>30분 이내</th>
|
||||
<th>30분 ~ 1시간</th>
|
||||
<th>1시간 ~ 3시간</th>
|
||||
<th>3시간 이상</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.playtime &&
|
||||
dataList.playtime.map(time => (
|
||||
<tr key={time.date}>
|
||||
<td>{time.date}</td>
|
||||
{time.user_cnt.map((cnt, index) => (
|
||||
<td className="text-left" key={index}>
|
||||
{cnt}
|
||||
</td>
|
||||
))}
|
||||
<td className="text-left">{time.total_time}</td>
|
||||
<td className="text-left">{time.average_time}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</IndexTableWrap>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlayTimeContent;
|
||||
@@ -1,108 +1,76 @@
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
import React, { Fragment, useRef } from 'react';
|
||||
|
||||
import { TableStyle, TableInfo, ListOption, IndexTableWrap } from '../../styles/Components';
|
||||
import { RetentionSearchBar } from '../../components/IndexManage/index';
|
||||
import { RetentionIndexExport, RetentionIndexView } from '../../apis';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import { useRetentionSearch, RetentionSearchBar } from '../searchBar';
|
||||
import { TableSkeleton } from '../Skeleton/TableSkeleton';
|
||||
import { numberFormatter } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import CSVDownloadButton from '../common/button/CsvDownButton';
|
||||
|
||||
const RetentionContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const tableRef = useRef(null);
|
||||
const token = sessionStorage.getItem('token');
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(24, 0, 0, 0));
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [resultData, setResultData] = useState([]);
|
||||
const [retentionData, setRetention] = useState(1);
|
||||
const {
|
||||
searchParams,
|
||||
loading: dataLoading,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
updateSearchParams
|
||||
} = useRetentionSearch(token);
|
||||
|
||||
const [sendDate, setSendDate] = useState(START_DATE);
|
||||
const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
const [excelBtn, setExcelBtn] = useState(true); //true 시 비활성화
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(START_DATE, END_DATE);
|
||||
}, []);
|
||||
|
||||
// Retention 지표 데이터
|
||||
const fetchData = async (startDate, endDate) => {
|
||||
const startDateToLocal =
|
||||
startDate.getFullYear() +
|
||||
'-' +
|
||||
(startDate.getMonth() + 1 < 9 ? '0' + (startDate.getMonth() + 1) : startDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(startDate.getDate() < 9 ? '0' + startDate.getDate() : startDate.getDate());
|
||||
|
||||
const endDateToLocal =
|
||||
endDate.getFullYear() +
|
||||
'-' +
|
||||
(endDate.getMonth() + 1 < 9 ? '0' + (endDate.getMonth() + 1) : endDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(endDate.getDate() < 9 ? '0' + endDate.getDate() : endDate.getDate());
|
||||
|
||||
setDataList(await RetentionIndexView(token, startDateToLocal, endDateToLocal));
|
||||
|
||||
console.log(dataList);
|
||||
|
||||
setSendDate(startDateToLocal);
|
||||
setFinishDate(endDateToLocal);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (send_dt, end_dt) => {
|
||||
fetchData(send_dt, end_dt);
|
||||
setRetention(resultData.retention);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_Retention_Index.xlsx';
|
||||
|
||||
if(!excelBtn){
|
||||
RetentionIndexExport(token, fileName, sendDate, finishDate);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<RetentionSearchBar setResultData={setResultData} resultData={resultData}
|
||||
handleSearch={handleSearch} fetchData={fetchData} setRetention={setRetention} setExcelBtn={setExcelBtn} />
|
||||
<AnimatedPageWrapper>
|
||||
<RetentionSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
<TableInfo>
|
||||
<ListOption>
|
||||
<Button
|
||||
theme={excelBtn === true ? "disable" : "line"}
|
||||
text="엑셀 다운로드"
|
||||
disabled={handleXlsxExport}
|
||||
handleClick={handleXlsxExport} />
|
||||
<CSVDownloadButton tableRef={tableRef} fileName={t('FILE_INDEX_USER_RETENTION')} />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<IndexTableWrap>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
{/* <th width="100">국가</th> */}
|
||||
<th width="150">일자</th>
|
||||
<th className="cell-nru">NRU</th>
|
||||
{[...Array(Number(retentionData))].map((value, index) => {
|
||||
return <th key={index}>{`D+${index + 1}`}</th>;
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.retention &&
|
||||
dataList.retention.map(data => (
|
||||
<tr className="cell-nru-th" key={data.date}>
|
||||
<td>{data.date}</td>
|
||||
{data['d-day'].map((day, index) => (
|
||||
<td key={index}>{day.dif}</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</IndexTableWrap>
|
||||
</>
|
||||
{dataLoading ? <TableSkeleton width='100%' count={15} /> :
|
||||
<IndexTableWrap>
|
||||
<TableStyle ref={tableRef}>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>일자</th>
|
||||
<th>NRU</th>
|
||||
<th>D+1</th>
|
||||
<th>D+7</th>
|
||||
<th>D+30</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{data.logDay}</td>
|
||||
<td>{data.totalCreated}</td>
|
||||
<td>{numberFormatter.formatPercent(data.d1_rate)}</td>
|
||||
<td>{numberFormatter.formatPercent(data.d7_rate)}</td>
|
||||
<td>{numberFormatter.formatPercent(data.d30_rate)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</IndexTableWrap>
|
||||
}
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { styled } from 'styled-components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import DatePickerComponent from '../common/Date/DatePickerComponent';
|
||||
|
||||
import { FormWrapper, InputLabel, TextInput, SelectInput, BtnWrapper, InputGroup, DatePickerWrapper, AlertText } from '../../styles/Components';
|
||||
|
||||
const RetentionSearchBar = ({ resultData, setResultData, handleSearch, fetchData, setRetention, setExcelBtn }) => {
|
||||
// 초기 날짜 세팅
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(24, 0, 0, 0));
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const [period, setPeriod] = useState(0);
|
||||
|
||||
// resultData에 임의 날짜 넣어주기
|
||||
useEffect(() => {
|
||||
setResultData({
|
||||
send_dt: START_DATE,
|
||||
end_dt: '',
|
||||
retention: 0,
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 발송 날짜 세팅 로직
|
||||
const handleSelectedDate = data => {
|
||||
const sendDate = new Date(data);
|
||||
const resultSendData = new Date(sendDate.getFullYear(), sendDate.getMonth(), sendDate.getDate());
|
||||
|
||||
const resultEndDate = new Date(resultSendData);
|
||||
resultEndDate.setDate(resultEndDate.getDate() + Number(resultData.retention));
|
||||
|
||||
setResultData({ ...resultData, send_dt: resultSendData, end_dt: resultEndDate });
|
||||
};
|
||||
|
||||
// // 발송 날짜 세팅 로직
|
||||
// const handleEndDate = data => {
|
||||
// const endDate = new Date(data);
|
||||
// const resultSendData = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
||||
|
||||
// setResultData({ ...resultData, end_dt: resultSendData });
|
||||
// };
|
||||
|
||||
// Retention 세팅 로직
|
||||
const handleRetention = e => {
|
||||
const value = e.target.value;
|
||||
|
||||
const resultEndDate = new Date(resultData.send_dt);
|
||||
resultEndDate.setDate(resultEndDate.getDate() + Number(value));
|
||||
|
||||
setResultData({ ...resultData, end_dt: resultEndDate, retention: value });
|
||||
setPeriod(value);
|
||||
};
|
||||
|
||||
//Retention 범위 선택 후 disable 처리 로직
|
||||
const handleSearchBtn = e => {
|
||||
e.preventDefault();
|
||||
|
||||
if(period == 0) {
|
||||
setErrorMessage("필수값을 선택하세요.");
|
||||
return false;
|
||||
} else {
|
||||
setErrorMessage("");
|
||||
setExcelBtn(false); //활성화
|
||||
handleSearch(resultData.send_dt, resultData.end_dt);
|
||||
}
|
||||
}
|
||||
|
||||
const handleReset = e => {
|
||||
e.preventDefault();
|
||||
setResultData({ send_dt: START_DATE, end_dt: '', retention: 0 });
|
||||
setRetention(1);
|
||||
setErrorMessage("");
|
||||
setPeriod(1);
|
||||
setExcelBtn(true); //비활성화
|
||||
|
||||
fetchData(START_DATE, END_DATE);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormWrapper>
|
||||
<SearchbarStyle>
|
||||
<SearchItem>
|
||||
<InputLabel>집계 기준일</InputLabel>
|
||||
<InputGroup>
|
||||
<DatePickerWrapper>
|
||||
<DatePickerComponent
|
||||
name="시작 일자" selectedDate={resultData.send_dt}
|
||||
handleSelectedDate={data => handleSelectedDate(data)}
|
||||
maxDate={new Date()} />
|
||||
<span>~</span>
|
||||
<DatePickerComponent
|
||||
name="종료 일자"
|
||||
selectedDate={resultData.end_dt}
|
||||
maxDate={new Date()}
|
||||
readOnly={true}
|
||||
disabled={true}
|
||||
type="retention" />
|
||||
</DatePickerWrapper>
|
||||
</InputGroup>
|
||||
</SearchItem>
|
||||
<SearchItem>
|
||||
<InputLabel>Retention 범위</InputLabel>
|
||||
<SelectInput
|
||||
onChange={e => handleRetention(e)} value={resultData.retention}>
|
||||
<option value={0}>선택</option>
|
||||
<option value={1}>D+1</option>
|
||||
<option value={7}>D+7</option>
|
||||
<option value={30}>D+30</option>
|
||||
</SelectInput>
|
||||
</SearchItem>
|
||||
{/* 기획 보류 */}
|
||||
{/* <SearchItem>
|
||||
<InputLabel>조회 국가</InputLabel>
|
||||
<SelectInput>
|
||||
<option value="">ALL</option>
|
||||
<option value="">KR</option>
|
||||
<option value="">EN</option>
|
||||
<option value="">JP</option>
|
||||
<option value="">TH</option>
|
||||
</SelectInput>
|
||||
</SearchItem> */}
|
||||
<BtnWrapper $gap="8px">
|
||||
<Button theme="reset" handleClick={handleReset} />
|
||||
<Button
|
||||
theme="search"
|
||||
text="검색"
|
||||
handleClick={handleSearchBtn}
|
||||
/>
|
||||
<AlertText>{errorMessage}</AlertText>
|
||||
</BtnWrapper>
|
||||
</SearchbarStyle>
|
||||
</FormWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RetentionSearchBar;
|
||||
|
||||
const SearchbarStyle = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
font-size: 14px;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
margin-bottom: 40px;
|
||||
`;
|
||||
|
||||
const SearchItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-right: 50px;
|
||||
|
||||
${TextInput}, ${SelectInput} {
|
||||
height: 35px;
|
||||
}
|
||||
${TextInput} {
|
||||
padding: 0 10px;
|
||||
max-width: 400px;
|
||||
}
|
||||
`;
|
||||
@@ -1,90 +0,0 @@
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { TableStyle, TableInfo, ListOption, IndexTableWrap } from '../../styles/Components';
|
||||
import { SegmentSearchBar } from '../../components/IndexManage/index';
|
||||
import { SegmentIndexExport, SegmentIndexView } from '../../apis';
|
||||
|
||||
const SegmentContent = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const END_DATE = new Date();
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [resultData, setResultData] = useState([]);
|
||||
|
||||
const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(END_DATE);
|
||||
}, []);
|
||||
|
||||
// Retention 지표 데이터
|
||||
const fetchData = async endDate => {
|
||||
const endDateToLocal =
|
||||
endDate.getFullYear() +
|
||||
'-' +
|
||||
(endDate.getMonth() + 1 < 9 ? '0' + (endDate.getMonth() + 1) : endDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(endDate.getDate() < 9 ? '0' + endDate.getDate() : endDate.getDate());
|
||||
|
||||
setDataList(await SegmentIndexView(token, endDateToLocal));
|
||||
setFinishDate(endDateToLocal);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = end_dt => {
|
||||
fetchData(end_dt);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_Segment_Index.xlsx';
|
||||
SegmentIndexExport(token, fileName, finishDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SegmentSearchBar setResultData={setResultData} resultData={resultData} handleSearch={handleSearch} fetchData={fetchData} />
|
||||
<TableInfo>
|
||||
<ListOption>
|
||||
<Button theme="line" text="엑셀 다운로드" handleClick={handleXlsxExport} />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<IndexTableWrap>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan="1" width="200">
|
||||
{dataList && dataList.start_dt} ~ {dataList && dataList.end_dt}
|
||||
</th>
|
||||
<th colSpan="2" width="400">
|
||||
KIP
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
{/* <th>국가</th> */}
|
||||
<th>세그먼트 분류</th>
|
||||
<th>AU</th>
|
||||
<th>AU Percentage by User Segment (%)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList && dataList.segment &&
|
||||
dataList.segment.map((segment, index) => (
|
||||
<tr key={index}>
|
||||
{/* <td rowSpan="6">TH</td> */}
|
||||
<td>{segment.type}</td>
|
||||
<td>{segment.au}</td>
|
||||
<td>{segment.dif}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</IndexTableWrap>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SegmentContent;
|
||||
@@ -1,15 +1,14 @@
|
||||
import { Fragment, useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
import { TableStyle, TableInfo, ListOption, IndexTableWrap } from '../../styles/Components';
|
||||
import { DailyDashBoard } from '../../components/IndexManage/index';
|
||||
|
||||
import { Title, TableStyle, TableInfo, ListOption, IndexTableWrap } from '../../styles/Components';
|
||||
import { UserIndexSearchBar, DailyDashBoard } from '../../components/IndexManage/index';
|
||||
|
||||
import { userIndexView, userIndexExport } from '../../apis';
|
||||
import Loading from '../common/Loading';
|
||||
import { userIndexView } from '../../apis';
|
||||
import { ExcelDownButton } from '../common';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { formatStringDate } from '../../utils';
|
||||
import { AnimatedPageWrapper } from '../common/Layout';
|
||||
import { UserIndexSearchBar } from '../searchBar';
|
||||
|
||||
const UserContent = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
@@ -24,20 +23,6 @@ const UserContent = () => {
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [resultData, setResultData] = useState([]);
|
||||
|
||||
// const [sendDate, setSendDate] = useState(START_DATE);
|
||||
// const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
|
||||
const headers = [
|
||||
{key: 'date', label: '일자'},
|
||||
{key: 'nru', label: 'NRU'},
|
||||
{key: 'ugqCreate', label: '일자'},
|
||||
{key: 'dglc', label: '일자'},
|
||||
{key: 'dau', label: '일자'},
|
||||
{key: 'mcu', label: '일자'},
|
||||
{key: 'date', label: '일자'},
|
||||
{key: 'date', label: '일자'},
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(START_DATE, END_DATE);
|
||||
}, []);
|
||||
@@ -54,8 +39,6 @@ const UserContent = () => {
|
||||
setLoading(false);
|
||||
});
|
||||
|
||||
// setSendDate(startDateToLocal);
|
||||
// setFinishDate(endDateToLocal);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
@@ -63,14 +46,8 @@ const UserContent = () => {
|
||||
fetchData(send_dt, end_dt);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
// const handleXlsxExport = () => {
|
||||
// const fileName = 'Caliverse_User_Index.xlsx';
|
||||
// userIndexExport(token, fileName, sendDate, finishDate);
|
||||
// };
|
||||
|
||||
return (
|
||||
<>
|
||||
<AnimatedPageWrapper>
|
||||
<DailyDashBoard />
|
||||
<UserIndexSearchBar setResultData={setResultData} resultData={resultData} handleSearch={handleSearch} fetchData={fetchData} />
|
||||
<TableInfo>
|
||||
@@ -125,8 +102,7 @@ const UserContent = () => {
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</IndexTableWrap>
|
||||
{loading && <Loading/>}
|
||||
</>
|
||||
</AnimatedPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { TableStyle, TableInfo, ListOption } from '../../styles/Components';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
import VBPSearchBar from '../../components/IndexManage/VBPSearchBar';
|
||||
import { VBPIndexExport, VbpIndexView } from '../../apis';
|
||||
|
||||
const VBPContent = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date();
|
||||
|
||||
const [sendDate, setSendDate] = useState(START_DATE);
|
||||
const [finishDate, setFinishDate] = useState(END_DATE);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
useEffect(() => {
|
||||
fetchData(START_DATE, END_DATE);
|
||||
}, []);
|
||||
|
||||
// console.log(dataList);
|
||||
|
||||
const fetchData = async (startDate, endDate) => {
|
||||
const startDateToLocal =
|
||||
startDate.getFullYear() +
|
||||
'-' +
|
||||
(startDate.getMonth() + 1 < 9 ? '0' + (startDate.getMonth() + 1) : startDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(startDate.getDate() < 9 ? '0' + startDate.getDate() : startDate.getDate());
|
||||
|
||||
const endDateToLocal =
|
||||
endDate.getFullYear() +
|
||||
'-' +
|
||||
(endDate.getMonth() + 1 < 9 ? '0' + (endDate.getMonth() + 1) : endDate.getMonth() + 1) +
|
||||
'-' +
|
||||
(endDate.getDate() < 9 ? '0' + endDate.getDate() : endDate.getDate());
|
||||
|
||||
setDataList(await VbpIndexView(token, startDateToLocal, endDateToLocal));
|
||||
|
||||
setSendDate(startDateToLocal);
|
||||
setFinishDate(endDateToLocal);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_VBP_Index.xlsx';
|
||||
VBPIndexExport(token, fileName, sendDate, finishDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<VBPSearchBar fetchData={fetchData} />
|
||||
<TableInfo>
|
||||
<ListOption>
|
||||
<Button theme="line" text="엑셀 다운로드" handleClick={handleXlsxExport} />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableWrapper>
|
||||
<EconomicTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan="2" className="text-center" width="300">
|
||||
Product
|
||||
</th>
|
||||
<th width="160">2023-08-07</th>
|
||||
<th width="160">2023-08-08</th>
|
||||
<th width="160">2023-08-09</th>
|
||||
<th width="160">2023-08-10</th>
|
||||
<th width="160">2023-08-11</th>
|
||||
<th width="160">2023-08-12</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<TableTitle colSpan="2">(Total) VBP 생산량</TableTitle>
|
||||
<TableData>500000</TableData>
|
||||
<TableData>500000</TableData>
|
||||
<TableData>500000</TableData>
|
||||
<TableData>500000</TableData>
|
||||
<TableData>500000</TableData>
|
||||
<TableData>500000</TableData>
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle colSpan="2">(Total) VBP 소진량</TableTitle>
|
||||
<TableData>490000</TableData>
|
||||
<TableData>490000</TableData>
|
||||
<TableData>490000</TableData>
|
||||
<TableData>490000</TableData>
|
||||
<TableData>490000</TableData>
|
||||
<TableData>490000</TableData>
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle colSpan="2">(Total) VBP 보유량</TableTitle>
|
||||
<TableData>3.2M</TableData>
|
||||
<TableData>3.3M</TableData>
|
||||
<TableData>3.3M</TableData>
|
||||
<TableData>3.4M</TableData>
|
||||
<TableData>3.5M</TableData>
|
||||
<TableData>3.5M</TableData>
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle rowSpan="2">GET</TableTitle>
|
||||
<TableTitle>퀘스트 보상</TableTitle>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle>시즌패스 보상</TableTitle>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle rowSpan="2">USE</TableTitle>
|
||||
<TableTitle>퀘스트 보상</TableTitle>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
</tr>
|
||||
<tr>
|
||||
<TableTitle>시즌패스 보상</TableTitle>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
<TableData>150000</TableData>
|
||||
</tr>
|
||||
|
||||
{/* {mokupData.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{data.date}</td>
|
||||
<td>{data.name}</td>
|
||||
<td>{data.trader}</td>
|
||||
<td>{data.id}</td>
|
||||
<td>{data.key}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))} */}
|
||||
</tbody>
|
||||
</EconomicTable>
|
||||
</TableWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default VBPContent;
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
width: 100%;
|
||||
min-width: 680px;
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
${TableStyle} {
|
||||
width: 100%;
|
||||
min-width: 900px;
|
||||
th {
|
||||
&.cell-nru {
|
||||
background: #f0f0f0;
|
||||
border-left: 1px solid #aaa;
|
||||
border-right: 1px solid #aaa;
|
||||
}
|
||||
}
|
||||
td {
|
||||
&.blank {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
&.cell-nru {
|
||||
background: #fafafa;
|
||||
border-left: 1px solid #aaa;
|
||||
border-right: 1px solid #aaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const TableData = styled.td`
|
||||
background: ${props => (props.$state === 'danger' ? '#d60000' : props.$state === 'blank' ? '#F9F9F9' : 'transparent')};
|
||||
color: ${props => (props.$state === 'danger' ? '#fff' : '#2c2c2c')};
|
||||
`;
|
||||
|
||||
const TableTitle = styled.td`
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const EconomicTable = styled(TableStyle)`
|
||||
${TableData} {
|
||||
text-align: left;
|
||||
}
|
||||
tbody {
|
||||
tr:nth-child(1),
|
||||
tr:nth-child(2),
|
||||
tr:nth-child(3) {
|
||||
background: #f5fcff;
|
||||
}
|
||||
}
|
||||
`;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user