3달간 수정 사항

This commit is contained in:
comicgum
2026-09-04 23:52:28 +09:00
parent d26eb50875
commit 4187407e96
110 changed files with 4439 additions and 2456 deletions
@@ -54,12 +54,12 @@ public class JwtProvider {
/*
public String createAccessToken(Long gid, String user_id, String nick_name, Long permission, Long biz_group_id) {
public String createAccessToken(Long gid, String user_id, String name, Long permission, Long biz_group_id) {
Date now = new Date();
return Jwts.builder()
.setSubject(gid.toString())
.claim("user_id", user_id)
.claim("nick_name", nick_name)
.claim("name", name)
.claim("permission", permission)
.claim("biz_group_id", biz_group_id)
.setIssuedAt(now)
@@ -13,6 +13,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartFile;
//import static org.mockito.Answers.values;
import java.io.File;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
@@ -146,7 +148,8 @@ public class _AG {
if (qeuryResult == null || qeuryResult.size() == 0)
return 0L;
return (Long)qeuryResult.get(0).get(strColName);
//return (Long)qeuryResult.get(0).get(strColName);
return (Long)qeuryResult.get(0).values().iterator().next();
}
static public String getIpAddr(HttpServletRequest request) {
@@ -188,7 +191,7 @@ public class _AG {
//JWT Auth
static public boolean isSkipAuthUri(String uri) {
if (uri.compareTo("/api/miss-slot.do") == 0 ||
if (uri.compareTo("/api/miss-column_no.do") == 0 ||
uri.compareTo("/api/terminal-state.do") == 0 ||
uri.compareTo("/api/sign-in.do") == 0 ||
uri.compareTo("/api/sval2.do") == 0 ||
@@ -203,17 +206,17 @@ public class _AG {
UserInfo principal = new UserInfo(
Long.parseLong(claims.getSubject()),
claims.get("user_id", String.class),
claims.get("nick_name", String.class),
claims.get("name", String.class),
claims.get("permission", Number.class),
claims.get("biz_group_id", Number.class)
);
return principal;
}
static public Map<String, Object> createUserInfoMap(String user_id, String nick_name, Long permission, Long biz_group_id) {
static public Map<String, Object> createUserInfoMap(String user_id, String name, Long permission, Long biz_group_id) {
Map<String, Object> map = new HashMap<>();
map.put("user_id", user_id);
map.put("nick_name", nick_name);
map.put("name", name);
map.put("permission", permission);
map.put("biz_group_id", biz_group_id);
return map;
@@ -233,8 +236,8 @@ public class _AG {
// 사업자번호 검증
static public boolean isValidBusinessNumber(String input) {
//return true; //TestCode
return true;
/*
String digits = input.replaceAll("\\D", "");
if (digits.length() != 10) {
return false;
@@ -252,5 +255,6 @@ public class _AG {
int checkDigit = (10 - (sum % 10)) % 10;
return checkDigit == Character.getNumericValue(digits.charAt(9));
*/
}
}
@@ -12,4 +12,5 @@ public class CtErrorCode {
static public final int INVALID_USER = -9;
static public final int ALREADY_EXIST = -11;
static public final int THIRDPARTY_ERROR = -12;
static public final int PERMISSION_DENIED = -13;
}
@@ -0,0 +1,48 @@
package com.handong.smartservice.component;
public class Permission {
static public final Long PERM_ALL = 0xffffffffL; // 4294967295
static public final Long PERM_GROUP = 0x2L;
static public final Long PERM_TID = 0x4L;
static public final Long PERM_CANCEL = 0x8L;
static public Boolean hasGroup(Long permission) {
return (permission & PERM_GROUP) == PERM_GROUP;
}
static public Boolean hasUid1(Long permission) {
return (permission & PERM_TID) == PERM_TID;
}
static public Boolean hasCancel(Long permission) {
return (permission & PERM_CANCEL) == PERM_CANCEL;
}
private Long value = 0x0L;
public Long get() {
return value;
}
public void setGroup(Boolean perm_group) {
if (perm_group)
value |= PERM_GROUP;
else
value &= ~PERM_GROUP;
}
public void setUid1(Boolean perm_uid1) {
if (perm_uid1)
value |= PERM_TID;
else
value &= ~PERM_TID;
}
public void setCancel(Boolean perm_cancel) {
if (perm_cancel)
value |= PERM_CANCEL;
else
value &= ~PERM_CANCEL;
}
}
@@ -1,5 +1,7 @@
package com.handong.smartservice.component;
import org.springframework.security.core.context.SecurityContextHolder;
public class UserInfo {
private final Long gid;
@@ -8,10 +10,14 @@ public class UserInfo {
private final Long permission;
private final Long bizGroupId;
public UserInfo(Long gid, String user_id, String nick_name, Number permission, Number bizGroupId) {
static public UserInfo getCurr() {
return (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
public UserInfo(Long gid, String user_id, String name, Number permission, Number bizGroupId) {
this.gid = gid;
this.userId = user_id;
this.nickName = nick_name;
this.nickName = name;
this.permission = permission != null ? permission.longValue() : 0L;
this.bizGroupId = bizGroupId != null ? bizGroupId.longValue() : 0L;
}
@@ -51,12 +51,13 @@ class AccountController {
Boolean is_excel = _AG.toBoolean(body.get("is_excel"));
Boolean is_group_access = _AG.toBoolean(body.get("is_group_access"));
String nick_name = body.get("nick_name");
String name = body.get("name");
String phone = body.get("phone");
String user_id = body.get("user_id");
String email = body.get("email");
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
Map<String, Object> mapResult = accountService.getAccountList(offset, limit, date_start, date_end, is_excel, is_group_access, user_id, email, nick_name, biz_group_id);
Map<String, Object> mapResult = accountService.getAccountList(offset, limit, date_start, date_end, is_excel, is_group_access, user_id, email, name, phone, biz_group_id);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
@@ -66,7 +67,7 @@ class AccountController {
}
String[] arrHeader = {"등록일", "그룹", "아이디", "닉네임", "이메일", "상태"};
String[] arrColumn = {"reg_time", "biz_group_name", "user_id", "nick_name", "email", "state"};
String[] arrColumn = {"reg_time", "biz_group_name", "user_id", "name", "email", "state"};
CtExcelMaker.makeExcelResponse(request, response, "계정목록", arrHeader, arrColumn, list, null);
return null;
@@ -83,17 +84,21 @@ class AccountController {
String user_id = body.get("user_id");
String user_pw = body.get("user_pw");
String email = body.get("email");
String nick_name = body.get("nick_name");
String name = body.get("name");
String phone = body.get("phone");
Long state = _AG.toLong(body.get("state"));
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
Long new_biz_group_id = _AG.toLong(body.get("new_biz_group_id"));
Boolean perm_group = _AG.toBoolean(body.get("perm_group"));
Boolean perm_uid1 = _AG.toBoolean(body.get("perm_uid1"));
Boolean perm_cancel = _AG.toBoolean(body.get("perm_cancel"));
if (user_id == null || user_id.isEmpty()) {
result.setErrCode(ErrorCode.INVALID_PARAMETER);
return result;
}
result = accountService.addOrModifyAccount(isModify, gid, user_id, user_pw, email, nick_name, state, biz_group_id, new_biz_group_id);
result = accountService.addOrModifyAccount(isModify, gid, user_id, user_pw, email, name, phone, state, biz_group_id, new_biz_group_id, perm_group, perm_uid1, perm_cancel);
return result;
}
@@ -69,7 +69,7 @@ class AuthController {
Long gid = (Long)mapAccount.get("gid");
logger.info("gid: " + gid);
String nick_name = (String)mapAccount.get("nick_name");
String name = (String)mapAccount.get("name");
Long permission = (Long)mapAccount.get("permission");
Long biz_group_id = (Long)mapAccount.get("biz_group_id");
String encPw = (String)mapAccount.get("user_pw");
@@ -83,8 +83,8 @@ class AuthController {
return result;
}
//mapAccount.put("sval1", jwtProvider.createAccessToken(gid, user_id, nick_name, permission, biz_group_id));
mapAccount.put("sval1", jwtProvider.createAccessToken(gid, _AG.createUserInfoMap(user_id, nick_name, permission, biz_group_id)));
//mapAccount.put("sval1", jwtProvider.createAccessToken(gid, user_id, name, permission, biz_group_id));
mapAccount.put("sval1", jwtProvider.createAccessToken(gid, _AG.createUserInfoMap(user_id, name, permission, biz_group_id)));
String refreshToken = jwtProvider.createRefreshToken(gid);
/*
@@ -109,11 +109,11 @@ class AuthController {
@RequestMapping(value = "/sign-out.do", method = RequestMethod.POST)
public CtResponse signOut(HttpServletRequest request, HttpServletResponse response,
@RequestBody Map<String, String> body, Authentication authentication) {
@RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
Long gid = _AG.toLong(body.get("gid"));
UserInfo userInfo = (UserInfo)authentication.getPrincipal();
UserInfo userInfo = UserInfo.getCurr();
CtResponse result = new CtResponse();
if (gid != userInfo.getGid()) {
@@ -156,11 +156,11 @@ class AuthController {
}
String user_id = (String)mapAccount.get("user_id");
String nick_name = (String)mapAccount.get("user_id");
String name = (String)mapAccount.get("user_id");
Long permission = (Long)mapAccount.get("permission");
Long biz_group_id = (Long)mapAccount.get("biz_group_id");
//String newAccessToken = jwtProvider.createAccessToken(gid, user_id, nick_name, permission, biz_group_id);
String newAccessToken = jwtProvider.createAccessToken(gid, _AG.createUserInfoMap(user_id, nick_name, permission, biz_group_id));
//String newAccessToken = jwtProvider.createAccessToken(gid, user_id, name, permission, biz_group_id);
String newAccessToken = jwtProvider.createAccessToken(gid, _AG.createUserInfoMap(user_id, name, permission, biz_group_id));
mapAccount.put("sval1", newAccessToken);
@@ -10,6 +10,8 @@ import org.springframework.web.bind.annotation.*;
import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.ErrorCode;
import com.handong.smartservice.component.Permission;
import com.handong.smartservice.component.UserInfo;
import com.handong.smartservice.mapper.BizGroupMapper;
import com.handong.smartservice.service.BizGroupService;
@@ -68,6 +70,12 @@ class BizGroupController {
public CtResponse addOrModifyBizGroup(boolean isModify, HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
CtResponse result = new CtResponse();
UserInfo userInfo = UserInfo.getCurr();
if (Permission.hasGroup(userInfo.getPermission()) == false) {
result.setErrCode(ErrorCode.PERMISSION_DENIED);
return result;
}
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
Long pid = _AG.toLong(body.get("pid"));
Long top_group_id = _AG.toLong(body.get("top_group_id"));
@@ -116,10 +124,17 @@ class BizGroupController {
@RequestMapping(value = "/remove-biz-group.do", method = RequestMethod.POST)
public CtResponse removeBizGroup(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
String ids = body.get("ids");
CtResponse result = new CtResponse();
CtResponse result = bizGroupService.removeBizGroup(ids);
return result;
UserInfo userInfo = UserInfo.getCurr();
if (Permission.hasGroup(userInfo.getPermission()) == false) {
result.setErrCode(ErrorCode.PERMISSION_DENIED);
return result;
}
String ids = body.get("ids");
return bizGroupService.removeBizGroup(ids);
}
@@ -49,11 +49,13 @@ class DeviceController {
Boolean is_group_access = _AG.toBoolean(body.get("is_group_access"));
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
String name = body.get("name");
String name = body.get("device_name");
String uid1 = body.get("uid1");
String conn_state = body.get("conn_state");
String date_start = body.get("date_start");
String date_end = body.get("date_end");
Map<String, Object> mapResult = deviceService.getDeviceList(is_excel, offset, limit, is_group_access, biz_group_id, name, date_start, date_end);
Map<String, Object> mapResult = deviceService.getDeviceList(is_excel, offset, limit, is_group_access, biz_group_id, name, uid1, conn_state, date_start, date_end);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
@@ -1,6 +1,7 @@
package com.handong.smartservice.controller.api;
import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtExcelMaker;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.ErrorCode;
import com.handong.smartservice.service.ErrorHistoryService;
@@ -13,6 +14,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@@ -44,9 +46,20 @@ class ErrorHistoryController {
String date_end = body.get("date_end");
String uid1 = body.get("uid1");
Long uid1_type = _AG.toLong(body.get("uid1_type"));
String slot = body.get("slot");
String column_no = body.get("column_no");
Map<String, Object> mapResult = errorHistoryService.getErrorHistoryList(is_excel, offset, limit, date_start, date_end, uid1, uid1_type, slot);
Map<String, Object> mapResult = errorHistoryService.getErrorHistoryList(is_excel, offset, limit, date_start, date_end, uid1, uid1_type, column_no);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
String[] arrHeader = {"발생일시", "단말기 TID", "벤더", "컬럼번호"};
String[] arrColumn = {"reg_time", "uid1", "uid1_type", "column_no"};
CtExcelMaker.makeExcelResponse(request, response, "기기에러내역", arrHeader, arrColumn, list, null);
return null;
}
result.put("result", mapResult);
return result;
}
@@ -64,17 +77,17 @@ class ErrorHistoryController {
return result;
}
@RequestMapping(value = "/miss-slot.do", method = RequestMethod.POST)
public CtResponse missSlot(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
@RequestMapping(value = "/miss-column.do", method = RequestMethod.POST)
public CtResponse missColumn(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
String uid1 = body.get("uid1");
Long uid1_type = _AG.toLong(body.get("uid1_type"));
String slot = body.get("slot");
String column_no = body.get("column_no");
Map<String, Object> mapResult = errorHistoryService.missSlot(uid1, uid1_type, slot);
Map<String, Object> mapResult = errorHistoryService.missColumn(uid1, uid1_type, column_no);
result.put("result", mapResult);
return result;
}
@@ -0,0 +1,148 @@
package com.handong.smartservice.controller.api;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtExcelMaker;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.service.GamderService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
//TempCode - 겜더 화면 확인용. 응답은 GamderService의 하드코딩 데이터다.
@RestController
@RequestMapping("/api")
class GamderController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final GamderService gamderService;
public GamderController(GamderService gamderService) {
this.gamderService = gamderService;
}
// 단말기 단가설정 //////////////////////////////////////////////////////////
//
@RequestMapping(value = "/get-device-price.do", method = RequestMethod.POST)
public CtResponse getDevicePrice(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
Long device_id = _AG.toLong(body.get("device_id"));
result.put("result", gamderService.getDevicePriceList(device_id));
return result;
}
// prices가 배열이라 Map<String, Object>로 받는다.
@RequestMapping(value = "/manage-device-price.do", method = RequestMethod.POST)
public CtResponse manageDevicePrice(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, Object> body) {
logger.info("req: " + request.getRequestURI());
Object objDeviceId = body.get("device_id");
Long device_id = _AG.toLong(objDeviceId == null ? "" : String.valueOf(objDeviceId));
List<Object> prices = (List<Object>)body.get("prices");
return gamderService.manageDevicePrice(device_id, prices);
}
@RequestMapping(value = "/pay-device-service.do", method = RequestMethod.POST)
public CtResponse payDeviceService(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
Long device_id = _AG.toLong(body.get("device_id"));
Long service_pulse = _AG.toLong(body.get("service_pulse"));
String memo = _AG.safeStr(body.get("memo"));
return gamderService.payDeviceService(device_id, service_pulse, memo);
}
// 경품 //////////////////////////////////////////////////////////////////
//
@RequestMapping(value = "/get-prize.do", method = RequestMethod.POST)
public CtResponse getPrize(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
Boolean is_excel = _AG.toBoolean(body.get("is_excel"));
Long offset = _AG.toLong(body.get("offset"));
Long limit = _AG.toLong(body.get("limit"));
if (limit > 100)
limit = 100L;
String device_name = body.get("device_name");
String store_code = body.get("store_code");
Long state = _AG.toLong(body.get("state"));
String date_start = body.get("date_start");
String date_end = body.get("date_end");
Map<String, Object> mapResult = gamderService.getPrizeList(is_excel, offset, limit, device_name, store_code, state, date_start, date_end);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
String[] arrHeader = {"당첨일시", "매장코드", "기기코드", "기기이름", "경품 출구", "단가 이름", "금액", "상태"};
String[] arrColumn = {"reg_time", "store_code", "machine_code", "device_name", "exit_no", "price_name", "amount", "state"};
CtExcelMaker.makeExcelResponse(request, response, "경품당첨내역", arrHeader, arrColumn, list, null);
return null;
}
result.put("result", mapResult);
return result;
}
@RequestMapping(value = "/cancel-prize.do", method = RequestMethod.POST)
public CtResponse cancelPrize(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
String prize_id = _AG.safeStr(body.get("prize_id"));
return gamderService.cancelPrize(prize_id);
}
// 버튼 색상 //////////////////////////////////////////////////////////////
//
@RequestMapping(value = "/get-button-color.do", method = RequestMethod.POST)
public CtResponse getButtonColor(HttpServletRequest request, HttpServletResponse response) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
result.put("result", gamderService.getButtonColorList());
return result;
}
// colors가 배열이라 Map<String, Object>로 받는다.
@RequestMapping(value = "/manage-button-color.do", method = RequestMethod.POST)
public CtResponse manageButtonColor(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, Object> body) {
logger.info("req: " + request.getRequestURI());
List<Object> colors = (List<Object>)body.get("colors");
return gamderService.manageButtonColor(colors);
}
@RequestMapping(value = "/apply-button-color.do", method = RequestMethod.POST)
public CtResponse applyButtonColor(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
Long seq = _AG.toLong(body.get("seq"));
Long button_color = _AG.toLong(body.get("button_color"));
return gamderService.applyButtonColor(seq, button_color);
}
}
@@ -129,7 +129,7 @@ class GoodsController {
CtResponse result = new CtResponse();
Long device_id = _AG.toLong(body.get("device_id"));
String slot = body.get("slot");
String column_no = body.get("column_no");
Long goods_id = _AG.toLong(body.get("goods_id"));
if (device_id == 0) {
@@ -137,7 +137,7 @@ class GoodsController {
return result;
}
Map<String, Object> mapResult = goodsService.getDeviceGoodsList(device_id, slot, goods_id);
Map<String, Object> mapResult = goodsService.getDeviceGoodsList(device_id, column_no, goods_id);
result.put("result", mapResult);
return result;
}
@@ -51,13 +51,14 @@ class SalesController {
String date_start = body.get("date_start");
String date_end = body.get("date_end");
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
Boolean query_uid1 = _AG.toBoolean(body.get("query_uid1"));
String uid1 = body.get("uid1");
String device_name = body.get("device_name");
Long approval_type = _AG.toLong(body.get("approval_type"));
Long date_type = _AG.toLong(body.get("date_type"));
Map<String, Object> mapResult = salesService.getSalesList(is_excel, offset, limit, is_group_access, biz_group_id, date_start, date_end,
uid1, device_name, approval_type, date_type);
query_uid1, uid1, device_name, approval_type, date_type);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
@@ -11,6 +11,7 @@ import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtExcelMaker;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.ErrorCode;
import com.handong.smartservice.component.UserInfo;
import com.handong.smartservice.service.TerminalService;
import jakarta.servlet.http.HttpServletRequest;
@@ -35,6 +36,19 @@ class TerminalController {
this.terminalService = terminalService;
}
@RequestMapping(value = "/list-uid1.do", method = RequestMethod.POST)
public CtResponse listUid1(HttpServletRequest request, HttpServletResponse response, @RequestBody(required = false) Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
UserInfo userInfo = UserInfo.getCurr();
Map<String, Object> mapResult = terminalService.listUid1(0L, 1000L, userInfo.getBizGroupId());
result.put("result", mapResult);
return result;
}
@RequestMapping(value = "/get-terminal.do", method = RequestMethod.POST)
public CtResponse getTerminalList(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
@@ -52,6 +52,7 @@ class TransactionController {
String date_start = body.get("date_start");
String date_end = body.get("date_end");
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
String device_name = body.get("device_name");
String uid1 = body.get("uid1");
Long uid1_type = _AG.toLong(body.get("uid1_type"));
String type = body.get("type");
@@ -59,12 +60,12 @@ class TransactionController {
String approval = body.get("approval");
String pay_name = body.get("pay_name");
String pay_vendor = body.get("pay_vendor");
String slot = body.get("slot");
String column_no = body.get("column_no");
String code = body.get("code");
String goods_name = body.get("goods_name");
Map<String, Object> mapResult = transactionService.getTransactionList(is_excel, offset, limit, is_group_access, biz_group_id, date_start, date_end,
uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, slot, code, goods_name);
device_name, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, column_no, code, goods_name);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
@@ -74,7 +75,7 @@ class TransactionController {
}
String[] arrHeader = {"거래시간", "단말기 TID", "금액", "결제유형", "승인번호", "컬럼번호", "상품코드", "상품명", "결제서비스업체"};
String[] arrColumn = {"order_time", "uid1", "amount", "type", "approval", "slot", "code", "goods_name", "pay_vendor"};
String[] arrColumn = {"order_time", "uid1", "amount", "type", "approval", "column_no", "code", "goods_name", "pay_vendor"};
CtExcelMaker.makeExcelResponse(request, response, "거래내역목록", arrHeader, arrColumn, list, null);
return null;
@@ -105,12 +106,12 @@ class TransactionController {
String approval = body.get("approval");
String pay_name = body.get("pay_name");
String pay_vendor = body.get("pay_vendor");
String slot = body.get("slot");
String column_no = body.get("column_no");
String code = body.get("code");
String goods_name = body.get("goods_name");
Map<String, Object> mapResult = transactionService.getUndefinedTransactionList(is_excel, offset, limit, date_start, date_end,
uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, slot, code, goods_name);
uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, column_no, code, goods_name);
result.put("result", mapResult);
return result;
}
@@ -130,7 +131,7 @@ class TransactionController {
"approval": "33",
"pay_name": " HANA",
"pay_vendor": "HANA",
"slot": "01"
"column_no": "01"
}'
*/
@@ -143,18 +144,18 @@ class TransactionController {
String approval = body.get("approval");
String pay_name = body.get("pay_name");
String pay_vendor = body.get("pay_vendor");
String slot = body.get("slot");
String column_no = body.get("column_no");
//String code = body.get("code");
//String goods_name = body.get("goods_name");
String pay_unique_num = body.get("pay_unique_num");
String pay_order_time = body.get("pay_order_time");
if (uid1 == null || uid1_type == null || type == null || amount == null || slot == null) {
if (uid1 == null || uid1_type == null || type == null || amount == null || column_no == null) {
result.setErrCode(ErrorCode.INVALID_PARAMETER);
return result;
}
result = transactionService.addTransaction(uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, slot, pay_unique_num, pay_order_time);
result = transactionService.addTransaction(uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, column_no, pay_unique_num, pay_order_time);
return result;
}
}
@@ -10,14 +10,14 @@ import java.util.Map;
public interface AccountMapper {
List<Map<String, Object>> selectAccount(Boolean isCount, Boolean is_excel, Long offset, Long limit,
String date_start, String date_end, Long gid, String user_id, String email, String nick_name, Long biz_group_id);
String date_start, String date_end, Long gid, String user_id, String email, String name, String phone, Long biz_group_id);
List<Map<String, Object>> selectAccount2(Boolean isCount, Long offset, Long limit,
String date_start, String date_end, Boolean is_excel, Long gid, String user_id, String email, String nick_name, Long biz_group_id);
String date_start, String date_end, Boolean is_excel, Long gid, String user_id, String email, String name, String phone, Long biz_group_id);
int insertAccount(Map<String, Object> params);
int updateAccount(Long gid, String user_pw, String nick_name, String email, Long state, Long biz_group_id);
int updateAccount(Long gid, String user_pw, String name, String phone, String email, Long state, Long biz_group_id, Long permission);
int changeState(List<Long> ids, int state);
}
@@ -10,10 +10,10 @@ import java.util.Map;
@Mapper
public interface DeviceMapper {
List<Map<String, Object>> selectDevice(Boolean isCount, boolean is_excel, Long offset, Long limit, Boolean is_group_access,
Long biz_group_id, String name, String date_start, String date_end);
Long biz_group_id, String name, String uid1, String conn_state, String date_start, String date_end);
List<Map<String, Object>> selectDevice2(Boolean isCount, boolean is_excel, Long offset, Long limit,
Long biz_group_id, String name, String date_start, String date_end);
Long biz_group_id, String name, String uid1, String conn_state, String date_start, String date_end);
Map<String, Object> selectDeviceById(Long device_id);
@@ -9,9 +9,9 @@ import java.util.Map;
@Mapper
public interface ErrorHistoryMapper {
List<Map<String, Object>> selectErrorHistory(Boolean isCount, Boolean is_excel, Long offset, Long limit,
String date_start, String date_end, String uid1, Long uid1_type, String slot);
String date_start, String date_end, String uid1, Long uid1_type, String column_no);
List<Map<String, Object>> selectErrorHistoryByState(Long state);
int insertErrorHistory(String uid1, Long uid1_type, String slot);
int insertErrorHistory(String uid1, Long uid1_type, String column_no);
}
@@ -16,7 +16,7 @@ public interface GoodsMapper {
Map<String, Object> selectExistGoods(Long biz_group_id, String code, String name);
Map<String, Object> selectGoodsByUid1(String uid1, Long uid1_type, String slot);
Map<String, Object> selectGoodsByUid1(String uid1, Long uid1_type, String column_no);
int insertGoods(Map<String, Object> params);
@@ -25,10 +25,10 @@ public interface GoodsMapper {
int deleteGoods(List<Long> ids);
//
List<Map<String, Object>> selectDeviceGoods(Long device_id, String slot, Long goods_id);
List<Map<String, Object>> selectDeviceGoods(Long device_id, String column_no, Long goods_id);
int insertDeviceGoods(Long device_id, List<Map<String, String>> device_goods);
int updateDeviceGoodsPlusInventory(String approval);
int updateDeviceGoodsMinusInventory(Long device_id, String slot);
int updateDeviceGoodsMinusInventory(Long device_id, String column_no);
int deleteDeviceGoods(Long device_id, List<Map<String, String>> device_goods);
List<Map<String, Object>> selectGoodsTemplateByBizGroupId(Long biz_group_id);
@@ -10,6 +10,8 @@ import java.util.Map;
@Mapper
public interface TerminalMapper {
List<Map<String, Object>> selectUid1(Long offset, Long limit, Long biz_group_id);
List<Map<String, Object>> selectTerminal(Boolean isCount, Boolean is_excel, Long offset, Long limit, Boolean is_group_access,
Long biz_group_id, String name, Long state, String date_start, String date_end);
@@ -1,7 +1,6 @@
package com.handong.smartservice.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
@@ -10,18 +9,20 @@ import java.util.Map;
public interface TransactionMapper {
List<Map<String, Object>> selectTransaction(Boolean isCount, Boolean is_excel, Long offset, Long limit, Boolean is_group_access,
Long biz_group_id, String date_start, String date_end, String uid1, Long uid1_type, String type, Long amount,
String approval, String pay_name, String pay_vendor, String slot, String code, String goods_name);
Long biz_group_id, String date_start, String date_end, String device_name, String uid1, Long uid1_type, String type, Long amount,
String approval, String pay_name, String pay_vendor, String column_no, String code, String goods_name);
List<Map<String, Object>> selectTransactionBizGroup0(Boolean isCount, Boolean is_excel, Long offset, Long limit,
String date_start, String date_end, String uid1, Long uid1_type, String type, Long amount, String approval,
String pay_name, String pay_vendor, String slot, String code, String goods_name);
String date_start, String date_end, String device_name, String uid1, Long uid1_type, String type, Long amount, String approval,
String pay_name, String pay_vendor, String column_no, String code, String goods_name);
List<Map<String, Object>> selectTransaction2(Boolean isCount, Boolean is_excel, Long offset, Long limit, Boolean is_group_access,
Long biz_group_id, String date_start, String date_end, String uid1);
List<Map<String, Object>> selectTransaction3(Boolean isCount, Boolean is_excel, Long offset, Long limit, Boolean is_group_access,
Long biz_group_id, String date_start, String date_end, String uid1, String device_name, Long approval_type, Long date_type);
Long biz_group_id, String date_start, String date_end, Boolean query_uid1, String uid1, String device_name, Long approval_type, Long date_type);
Map<String, Object> selectTransactionSum(Boolean is_group_access, Long biz_group_id, String date_start, String date_end);
int insertTransaction(Map<String, Object> params);
}
@@ -1,5 +1,8 @@
package com.handong.smartservice.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -10,6 +13,7 @@ import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.DbLogger;
import com.handong.smartservice.component.ErrorCode;
import com.handong.smartservice.component.Permission;
import com.handong.smartservice.component.UserInfo;
import org.springframework.security.core.Authentication;
@@ -22,6 +26,8 @@ import com.handong.smartservice.mapper.AccountMapper;
@Service
public class AccountService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final AccountMapper accountMapper;
private final PasswordEncoder passwordEncoder;
@@ -38,7 +44,7 @@ public class AccountService {
}
List<Map<String, Object>> listMap = (List<Map<String, Object>>)accountMapper.selectAccount(false, false, 0L, 1L,
null, null, gid, user_id, null, null, 0L);
null, null, gid, user_id, null, null, null, 0L);
if (listMap.size() == 0)
result.put("result", null);
@@ -48,26 +54,28 @@ public class AccountService {
return result;
}
public Map<String, Object> getAccountList(Long offset, Long limit, String date_start, String date_end, Boolean is_excel, Boolean is_group_access, String user_id, String email, String nick_name, Long biz_group_id) {
public Map<String, Object> getAccountList(Long offset, Long limit, String date_start, String date_end, Boolean is_excel, Boolean is_group_access, String user_id, String email, String name, String phone, Long biz_group_id) {
Map<String, Object> mapResult = new HashMap<>();
//if (is_group_access) {
List<Map<String, Object>> listMap = (List<Map<String, Object>>)accountMapper.selectAccount2(false, offset, limit,
date_start, date_end, is_excel, 0L, user_id, email, nick_name, biz_group_id);
date_start, date_end, is_excel, 0L, user_id, email, name, phone, biz_group_id);
mapResult.put("list", listMap);
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", accountMapper.selectAccount2(true, offset, limit,
date_start, date_end, is_excel, 0L, user_id, email, nick_name, biz_group_id));
date_start, date_end, is_excel, 0L, user_id, email, name, phone, biz_group_id));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
return mapResult;
}
public CtResponse addOrModifyAccount(boolean isModify, Long gid, String user_id, String user_pw, String email, String nick_name, Long state, Long biz_group_id, Long new_biz_group_id) {
public CtResponse addOrModifyAccount(boolean isModify, Long gid, String user_id, String user_pw, String email, String name, String phone,Long state,
Long biz_group_id, Long new_biz_group_id, Boolean perm_group, Boolean perm_uid1, Boolean perm_cancel) {
CtResponse result = new CtResponse();
UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserInfo userInfo = UserInfo.getCurr();
String enc_pw = passwordEncoder.encode(user_pw);
@@ -80,8 +88,14 @@ public class AccountService {
return result;
}
//accountMapper.updateAccount(gid, user_pw, nick_name, email, state, biz_group_id);
accountMapper.updateAccount(gid, enc_pw, nick_name, email, state, biz_group_id);
Permission permission = new Permission();
permission.setGroup(perm_group);
permission.setUid1(perm_uid1);
permission.setCancel(perm_cancel);
//logger.debug("[TRACE1], permission = {}", permission.get());
//accountMapper.updateAccount(gid, user_pw, name, email, state, biz_group_id);
accountMapper.updateAccount(gid, enc_pw, name, phone, email, state, biz_group_id, permission.get());
DbLogger.insert(2L, "계정정보 수정", userInfo.getGid());
}
else {
@@ -94,15 +108,21 @@ public class AccountService {
params.put("user_id", user_id);
//params.put("user_pw", user_pw);
params.put("user_pw", enc_pw);
params.put("nick_name", nick_name);
params.put("name", name);
params.put("phone", phone);
params.put("email", email);
params.put("state", state);
params.put("biz_group_id", biz_group_id);
if (biz_group_id == 667) //TempCode
params.put("permission", 1L);
else
params.put("permission", 2L);
params.put("permission", Permission.PERM_ALL);
else {
Permission permission = new Permission();
permission.setGroup(perm_group);
permission.setUid1(perm_uid1);
permission.setCancel(perm_cancel);
params.put("permission", permission.get());
}
if (accountMapper.insertAccount(params) == 0) {
result.setErrCode(ErrorCode.INVALID_PARAMETER);
@@ -20,7 +20,9 @@ import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.DbLogger;
import com.handong.smartservice.component.ErrorCode;
import com.handong.smartservice.component.Permission;
import com.handong.smartservice.component.RcTreeBizGroup;
import com.handong.smartservice.component.UserInfo;
import com.handong.smartservice.mapper.BizGroupMapper;
import com.handong.smartservice.mapper.OperatingHistoryMapper;
@@ -41,7 +41,8 @@ public class DeviceService {
this.deviceMapper = deviceMapper;
}
public Map<String, Object> getDeviceList(Boolean is_excel, Long offset, Long limit, Boolean is_group_access, Long biz_group_id, String name, String date_start, String date_end) {
public Map<String, Object> getDeviceList(Boolean is_excel, Long offset, Long limit, Boolean is_group_access, Long biz_group_id,
String name, String uid1, String conn_state, String date_start, String date_end) {
Map<String, Object> mapResult = new HashMap<>();
//OldVer
@@ -53,26 +54,27 @@ public class DeviceService {
// biz_group_id = (Long)listForTopId.get(0).get("biz_group_id");
// }
//}
if (is_group_access) {
List<Map<String, Object>> listMap = (List<Map<String, Object>>)deviceMapper.selectDevice(false, is_excel, offset, limit, is_group_access,
biz_group_id, name, date_start, date_end);
biz_group_id, name, uid1, conn_state, date_start, date_end);
mapResult.put("list", listMap);
if (is_excel == false) {
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", deviceMapper.selectDevice(true, is_excel, offset, limit, is_group_access,
biz_group_id, name, date_start, date_end));
biz_group_id, name, uid1, conn_state, date_start, date_end));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
}
}
else {
List<Map<String, Object>> listMap = (List<Map<String, Object>>)deviceMapper.selectDevice2(false, is_excel, offset, limit,
biz_group_id, name, date_start, date_end);
biz_group_id, name, uid1, conn_state, date_start, date_end);
mapResult.put("list", listMap);
if (is_excel == false) {
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", deviceMapper.selectDevice2(true, is_excel, offset, limit,
biz_group_id, name, date_start, date_end));
biz_group_id, name, uid1, conn_state, date_start, date_end));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
}
@@ -84,7 +86,7 @@ public class DeviceService {
public CtResponse addOrModifyDevice(boolean isModify, Long biz_group_id, Long new_biz_group_id, Long device_id, Long terminal_id, String name, String uid1, String manager_name) {
CtResponse result = new CtResponse();
UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserInfo userInfo = UserInfo.getCurr();
if (isModify) {
if (device_id == 0) {
@@ -154,7 +156,7 @@ public class DeviceService {
}
DbLogger.insert(2L, "무인기기 추가, 기기명: " + name + "TID: " + uid1, userInfo.getGid());
Long new_device_id = _AG.toLong((BigInteger)params.get("device_id"));
Long new_device_id = _AG.toLong((BigInteger)params.get("device_id"));
if (deviceMapper.insertDeviceBizGroup(biz_group_id, new_device_id) == 0) {
result.setErrCode(ErrorCode.INVALID_PARAMETER);
@@ -172,7 +174,7 @@ public class DeviceService {
public CtResponse removeDevice(Long biz_group_id, Long device_id) {
CtResponse result = new CtResponse();
UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserInfo userInfo = UserInfo.getCurr();
//terminalMapper.updateTerminalRemoveDevice(device_id);
Map<String, Object> mapTerminal = terminalMapper.selectTerminalByDeviceId(device_id);
@@ -10,8 +10,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -29,34 +33,73 @@ public class ErrorHistoryService {
}
public Map<String, Object> getErrorHistoryList(Boolean is_excel, Long offset, Long limit, String date_start, String date_end,
String uid1, Long uid1_type, String slot) {
String uid1, Long uid1_type, String column_no) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> listMap = (List<Map<String, Object>>)errorHistoryMapper.selectErrorHistory(false, is_excel, offset, limit,
date_start, date_end, uid1, uid1_type, slot);
mapResult.put("list", listMap);
date_start, date_end, uid1, uid1_type, column_no);
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", errorHistoryMapper.selectErrorHistory(true, is_excel, offset, limit,
date_start, date_end, uid1, uid1_type, slot));
date_start, date_end, uid1, uid1_type, column_no));
//TempCode - 실제 데이터가 없을 때만 화면 확인용 하드코딩 데이터를 내려준다. 삭제해도 동작에 문제 없음.
if (listMap == null || listMap.isEmpty()) {
listMap = makeSampleErrorHistory();
totalCount = (long)listMap.size();
int from = (int)Math.min(offset == null ? 0 : offset, listMap.size());
int to = (int)Math.min(from + (limit == null ? 20 : limit), listMap.size());
if (is_excel == false)
listMap = new ArrayList<>(listMap.subList(from, to));
}
//
mapResult.put("list", listMap);
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
return mapResult;
}
//TempCode - 화면 확인용 샘플. 프론트의 convertDateTime2()가 파싱하도록 ISO 형식으로 내려준다.
private static final DateTimeFormatter TEMP_DT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
private List<Map<String, Object>> makeSampleErrorHistory() {
String[] arrUid1 = { "1234567", "1234568", "2345671", "2345672" };
List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < 27; i++) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("error_history_id", 5000 + i);
m.put("reg_time", LocalDateTime.now().minusMinutes(i * 53L + 7).format(TEMP_DT));
m.put("uid1", arrUid1[i % arrUid1.length]);
m.put("uid1_type", (i % 2) + 1);
m.put("column_no", String.format("%02d", (i % 12) + 1));
list.add(m);
}
return list;
}
public Map<String, Object> getMiss(Long state) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> listMap = errorHistoryMapper.selectErrorHistoryByState(1L);
//TempCode - 실제 데이터가 없을 때만 화면 확인용 하드코딩 데이터를 내려준다. 삭제해도 동작에 문제 없음.
if (listMap == null || listMap.isEmpty())
listMap = new ArrayList<>(makeSampleErrorHistory().subList(0, 6));
//
mapResult.put("list", listMap);
return mapResult;
}
public CtResponse missSlot(String uid1, Long uid1_type, String slot) {
public CtResponse missColumn(String uid1, Long uid1_type, String column_no) {
CtResponse result = new CtResponse();
errorHistoryMapper.insertErrorHistory(uid1, uid1_type, slot);
DbLogger.insert(1L, "물품 미투출 TID: " + uid1 + ", 컬럼번호: " + slot, 2L);
errorHistoryMapper.insertErrorHistory(uid1, uid1_type, column_no);
DbLogger.insert(1L, "물품 미투출 TID: " + uid1 + ", 컬럼번호: " + column_no, 2L);
return result;
}
@@ -0,0 +1,210 @@
package com.handong.smartservice.service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.handong.smartservice.component.CtResponse;
//TempCode - 겜더 화면 확인용 하드코딩 데이터. DB 연동 시 이 클래스 전체를 실제 mapper 호출로 교체한다.
@Service
public class GamderService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final DateTimeFormatter DT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
// 프론트의 convertDateTime2()가 new Date(str)로 파싱하므로 ISO 형식으로 내려준다.
private static String ago(int minutes) {
return LocalDateTime.now().minusMinutes(minutes).format(DT);
}
// 단말기 단가설정 //////////////////////////////////////////////////////////
//
private static Map<String, Object> price(int seq, int pay_type, int amount, int in_pulse, int out_pulse,
boolean use_service, int service_pulse, String price_name, int button_color,
int check_time, int pulse_interval) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("seq", seq);
m.put("pay_type", pay_type);
m.put("amount", amount);
m.put("in_pulse", in_pulse);
m.put("out_pulse", out_pulse);
m.put("use_service", use_service);
m.put("service_pulse", service_pulse);
m.put("price_name", price_name);
m.put("button_color", button_color);
m.put("check_time", check_time);
m.put("pulse_interval", pulse_interval);
return m;
}
public Map<String, Object> getDevicePriceList(Long device_id) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> list = new ArrayList<>();
// 코인(1) / 지폐(2) / 카드(3)
list.add(price(1, 1, 500, 1, 0, false, 0, "코인 500", 1, 0, 0));
list.add(price(2, 1, 1000, 2, 0, false, 0, "코인 1000", 1, 0, 0));
list.add(price(3, 2, 5000, 5, 0, true, 1, "지폐 5000", 1, 150, 80));
list.add(price(4, 2, 10000, 10, 0, true, 2, "지폐 10000", 1, 150, 80));
list.add(price(5, 3, 1000, 0, 2, false, 0, "카드 1000", 7, 0, 0));
list.add(price(6, 3, 5000, 0, 10, true, 1, "카드 5000", 5, 0, 0));
list.add(price(7, 3, 10000, 0, 20, true, 3, "카드 10000", 8, 200, 100));
mapResult.put("list", list);
return mapResult;
}
public CtResponse manageDevicePrice(Long device_id, List<Object> prices) {
logger.info("manageDevicePrice, device_id: {}, count: {}", device_id, prices == null ? 0 : prices.size());
return new CtResponse();
}
public CtResponse payDeviceService(Long device_id, Long service_pulse, String memo) {
logger.info("payDeviceService, device_id: {}, service_pulse: {}, memo: {}", device_id, service_pulse, memo);
return new CtResponse();
}
// 경품 //////////////////////////////////////////////////////////////////
//
private static final int PRIZE_STATE_WIN = 1;
private static final int PRIZE_STATE_CANCEL = 2;
private static final String[] PRIZE_DEVICE_NAMES = {
"인형뽑기 1호기", "인형뽑기 2호기", "펀치머신", "레이싱 게임기", "농구 게임기", "메달 게임기",
};
private static final String[] PRIZE_PRICE_NAMES = {
"카드 1000", "카드 5000", "지폐 5000", "코인 1000",
};
// 조회 조건과 무관하게 같은 목록을 만들어 두고 페이징만 적용한다.
private List<Map<String, Object>> makePrizeList() {
List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < 23; i++) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("prize_id", String.valueOf(1000 + i));
m.put("reg_time", ago(i * 37 + 5));
m.put("store_code", "0001");
m.put("machine_code", String.format("%04d", (i % 6) + 1));
m.put("device_name", PRIZE_DEVICE_NAMES[i % PRIZE_DEVICE_NAMES.length]);
m.put("exit_no", (i % 3) + 1);
m.put("price_name", PRIZE_PRICE_NAMES[i % PRIZE_PRICE_NAMES.length]);
m.put("amount", ((i % 5) + 1) * 1000);
// 5번째마다 취소 건을 섞어 상태 표시를 확인할 수 있게 한다.
m.put("state", (i % 5 == 4) ? PRIZE_STATE_CANCEL : PRIZE_STATE_WIN);
list.add(m);
}
return list;
}
public Map<String, Object> getPrizeList(Boolean is_excel, Long offset, Long limit, String device_name,
String store_code, Long state, String date_start, String date_end) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> all = makePrizeList();
// 상태 조건만 실제로 걸러준다. (나머지 조건은 하드코딩 데이터라 무시)
if (state != null && state != 0) {
List<Map<String, Object>> filtered = new ArrayList<>();
for (Map<String, Object> m : all) {
if (((Integer)m.get("state")).longValue() == state)
filtered.add(m);
}
all = filtered;
}
long totalWin = 0, totalAmount = 0, cancelCount = 0, cancelAmount = 0;
for (Map<String, Object> m : all) {
int amount = (Integer)m.get("amount");
if ((Integer)m.get("state") == PRIZE_STATE_CANCEL) {
cancelCount++;
cancelAmount += amount;
}
else {
totalWin++;
totalAmount += amount;
}
}
Map<String, Object> sum = new LinkedHashMap<>();
sum.put("total_count", totalWin);
sum.put("total_amount", totalAmount);
sum.put("cancel_count", cancelCount);
sum.put("net_amount", totalAmount - cancelAmount);
mapResult.put("sum", sum);
// 엑셀은 페이징 없이 전체를 내린다. (기존 목록 API와 동일한 규칙)
List<Map<String, Object>> list;
if (is_excel) {
list = all;
}
else {
int from = (int)Math.min(offset == null ? 0 : offset, all.size());
int to = (int)Math.min(from + (limit == null ? 10 : limit), all.size());
list = new ArrayList<>(all.subList(from, to));
}
mapResult.put("list", list);
mapResult.put("totalCount", (long)all.size());
mapResult.put("offset", offset);
return mapResult;
}
public CtResponse cancelPrize(String prize_id) {
logger.info("cancelPrize, prize_id: {}", prize_id);
return new CtResponse();
}
// 버튼 색상 //////////////////////////////////////////////////////////////
//
private static Map<String, Object> color(String value, String label, String color) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("value", value);
m.put("label", label);
m.put("color", color);
return m;
}
public Map<String, Object> getButtonColorList() {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> list = new ArrayList<>();
list.add(color("1", "빨강", "#e02b20"));
list.add(color("2", "주황", "#f79009"));
list.add(color("3", "노랑", "#eaaa08"));
list.add(color("4", "연두", "#84cc16"));
list.add(color("5", "초록", "#12b76a"));
list.add(color("6", "청록", "#06aed4"));
list.add(color("7", "파랑", "#2e90fa"));
list.add(color("8", "남색", "#465fff"));
list.add(color("9", "보라", "#7a5af8"));
list.add(color("10", "분홍", "#ee46bc"));
mapResult.put("list", list);
return mapResult;
}
public CtResponse manageButtonColor(List<Object> colors) {
logger.info("manageButtonColor, count: {}", colors == null ? 0 : colors.size());
return new CtResponse();
}
public CtResponse applyButtonColor(Long seq, Long button_color) {
logger.info("applyButtonColor, seq: {}, button_color: {}", seq, button_color);
return new CtResponse();
}
}
@@ -68,7 +68,7 @@ public class GoodsService {
public CtResponse addOrModifyGoods(boolean isModify, Long biz_group_id, Long goods_id, String code, String name, Long price, Long inventory, String vendor) {
CtResponse result = new CtResponse();
UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserInfo userInfo = UserInfo.getCurr();
if (isModify) {
if (goods_id == 0) {
@@ -120,7 +120,7 @@ public class GoodsService {
}
//
public Map<String, Object> getDeviceGoodsList(Long device_id, String slot, Long goods_id) {
public Map<String, Object> getDeviceGoodsList(Long device_id, String column_no, Long goods_id) {
Map<String, Object> mapResult = new HashMap<>();
Map<String, Object> mapDevice = deviceMapper.selectDeviceById(device_id);
@@ -129,7 +129,7 @@ public class GoodsService {
List<Map<String, Object>> listMap = (List<Map<String, Object>>)goodsMapper.selectGoodsByDevice(false, device_id);
mapResult.put("goods_list", listMap);
List<Map<String, Object>> listMap2 = (List<Map<String, Object>>)goodsMapper.selectDeviceGoods(device_id, slot, goods_id);
List<Map<String, Object>> listMap2 = (List<Map<String, Object>>)goodsMapper.selectDeviceGoods(device_id, column_no, goods_id);
mapResult.put("device_goods_list", listMap2);
if (listMap.size() > 0) {
@@ -143,7 +143,7 @@ public class GoodsService {
public CtResponse addDeviceGoods(Long device_id, List<Map<String, String>> device_goods) {
CtResponse result = new CtResponse();
UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserInfo userInfo = UserInfo.getCurr();
if (goodsMapper.insertDeviceGoods(device_id, device_goods) == 0) {
result.setErrCode(ErrorCode.QUERY_ERROR);
@@ -155,7 +155,7 @@ public class GoodsService {
public CtResponse deleteDeviceGoods(Long device_id, List<Map<String, String>> device_goods) {
CtResponse result = new CtResponse();
UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserInfo userInfo = UserInfo.getCurr();
//for (Map<String, Object> item : device_goods) {
// item.put("device_id", device_id);
@@ -192,7 +192,7 @@ public class GoodsService {
Map<String, Object> element = new HashMap<>();
element.put("goods_template_element_id", item.get("goods_template_element_id"));
element.put("slot", item.get("slot"));
element.put("column_no", item.get("column_no"));
element.put("goods_id", item.get("goods_id"));
element.put("inventory", item.get("inventory"));
element.put("idx", item.get("idx"));
@@ -25,17 +25,23 @@ import com.handong.smartservice.mapper.GoodsMapper;
public class SalesService {
private final TransactionMapper transactionMapper;
/*
private final BizGroupMapper bizGroupMapper;
public SalesService(TransactionMapper transactionMapper, BizGroupMapper bizGroupMapper) {
this.transactionMapper = transactionMapper;
this.bizGroupMapper = bizGroupMapper;
}
*/
public SalesService(TransactionMapper transactionMapper) {
this.transactionMapper = transactionMapper;
}
public Map<String, Object> getSalesList(Boolean is_excel, Long offset, Long limit, Boolean is_group_access, Long biz_group_id, String date_start, String date_end,
String uid1, String device_name, Long approval_type, Long date_type) {
Boolean query_uid1, String uid1, String device_name, Long approval_type, Long date_type) {
Map<String, Object> mapResult = new HashMap<>();
/*
if (is_group_access == false) {
List<Map<String, Object>> listForTopId = bizGroupMapper.selectBizGroup(biz_group_id, false, 0L, 1L, null, null, null, null, null, null, null);
if (listForTopId != null && listForTopId.size() > 0) {
@@ -44,13 +50,18 @@ public class SalesService {
biz_group_id = (Long)listForTopId.get(0).get("biz_group_id");
}
}
*/
Map<String, Object> mapSum = (Map<String, Object>)transactionMapper.selectTransactionSum(is_group_access,
biz_group_id, date_start, date_end);
mapResult.put("sum", mapSum);
List<Map<String, Object>> listMap = (List<Map<String, Object>>)transactionMapper.selectTransaction3(false, is_excel, offset, limit, is_group_access,
biz_group_id, date_start, date_end, uid1, device_name, approval_type, date_type);
biz_group_id, date_start, date_end, query_uid1, uid1, device_name, approval_type, date_type);
mapResult.put("list", listMap);
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", transactionMapper.selectTransaction3(true, is_excel, offset, limit, is_group_access,
biz_group_id, date_start, date_end, uid1, device_name, approval_type, date_type));
biz_group_id, date_start, date_end, query_uid1, uid1, device_name, approval_type, date_type));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
return mapResult;
@@ -42,6 +42,15 @@ public class TerminalService {
this.bizGroupMapper = bizGroupMapper;
}
public Map<String, Object> listUid1(Long offset, Long limit, Long biz_group_id) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> listMap = (List<Map<String, Object>>)terminalMapper.selectUid1(offset, limit, biz_group_id);
mapResult.put("list", listMap);
return mapResult;
}
public Map<String, Object> getTerminalList(Boolean is_excel, Long offset, Long limit, Boolean is_group_access, Long biz_group_id, Long state, String date_start, String date_end) {
Map<String, Object> mapResult = new HashMap<>();
@@ -38,7 +38,7 @@ public class TransactionService {
}
public Map<String, Object> getTransactionList(Boolean is_excel, Long offset, Long limit, Boolean is_group_access, Long biz_group_id, String date_start, String date_end,
String uid1, Long uid1_type, String type, Long amount, String approval, String pay_name, String pay_vendor, String slot, String code, String goods_name) {
String device_name, String uid1, Long uid1_type, String type, Long amount, String approval, String pay_name, String pay_vendor, String column_no, String code, String goods_name) {
Map<String, Object> mapResult = new HashMap<>();
/*
@@ -53,32 +53,32 @@ public class TransactionService {
*/
List<Map<String, Object>> listMap = (List<Map<String, Object>>)transactionMapper.selectTransaction(false, is_excel, offset, limit, is_group_access,
biz_group_id, date_start, date_end, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, slot, code, goods_name);
biz_group_id, date_start, date_end, device_name, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, column_no, code, goods_name);
mapResult.put("list", listMap);
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", transactionMapper.selectTransaction(true, is_excel, offset, limit, is_group_access,
biz_group_id, date_start, date_end, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, slot, code, goods_name));
biz_group_id, date_start, date_end, device_name, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, column_no, code, goods_name));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
return mapResult;
}
public Map<String, Object> getUndefinedTransactionList(Boolean is_excel, Long offset, Long limit, String date_start, String date_end,
String uid1, Long uid1_type, String type, Long amount, String approval, String pay_name, String pay_vendor, String slot, String code, String goods_name) {
String uid1, Long uid1_type, String type, Long amount, String approval, String pay_name, String pay_vendor, String column_no, String code, String goods_name) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> listMap = (List<Map<String, Object>>)transactionMapper.selectTransactionBizGroup0(
false, is_excel, offset, limit, date_start, date_end, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, slot, code, goods_name);
false, is_excel, offset, limit, date_start, date_end, null, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, column_no, code, goods_name);
mapResult.put("list", listMap);
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", transactionMapper.selectTransactionBizGroup0(
true, is_excel, offset, limit, date_start, date_end, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, slot, code, goods_name));
true, is_excel, offset, limit, date_start, date_end, null, uid1, uid1_type, type, amount, approval, pay_name, pay_vendor, column_no, code, goods_name));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
return mapResult;
}
public CtResponse addTransaction(String uid1, Long uid1_type, String type, Long amount, String approval, String pay_name, String pay_vendor, String slot, String pay_unique_num, String pay_order_time) {
public CtResponse addTransaction(String uid1, Long uid1_type, String type, Long amount, String approval, String pay_name, String pay_vendor, String column_no, String pay_unique_num, String pay_order_time) {
CtResponse result = new CtResponse();
Long biz_group_id = 0L;
Long device_id = 0L;
@@ -99,8 +99,8 @@ public class TransactionService {
}
}
//select uid1, uid1_type -> device_id ->device_goods (slot) -> goods_id
Map<String, Object> goods = goodsMapper.selectGoodsByUid1(uid1, uid1_type, slot);
//select uid1, uid1_type -> device_id ->device_goods (column_no) -> goods_id
Map<String, Object> goods = goodsMapper.selectGoodsByUid1(uid1, uid1_type, column_no);
if (goods != null) {
device_id = (Long)goods.get("device_id");
}
@@ -115,7 +115,7 @@ public class TransactionService {
params.put("pay_unique_num", pay_unique_num);
params.put("pay_name", pay_name);
params.put("pay_vendor", pay_vendor);
params.put("slot", slot);
params.put("column_no", column_no);
params.put("biz_group_id", biz_group_id);
params.put("device_id", device_id);
@@ -127,7 +127,7 @@ public class TransactionService {
params.put("code", goods.get("code"));
params.put("price", goods.get("price"));
goodsMapper.updateDeviceGoodsMinusInventory((Long)goods.get("device_id"), slot);
goodsMapper.updateDeviceGoodsMinusInventory((Long)goods.get("device_id"), column_no);
}
transactionMapper.insertTransaction(params);
@@ -6,37 +6,40 @@
<select id="selectAccount" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
AC.gid, AC.user_id, AC.reg_time, AC.user_pw, AC.biz_group_id, AC.user_pw_time, AC.nick_name, AC.email, AC.state, AC.permission
AC.gid, AC.user_id, AC.reg_time, AC.user_pw, AC.biz_group_id, AC.user_pw_time, AC.name, AC.phone, AC.email, AC.state, AC.permission
</otherwise>
</choose>
FROM account AS AC
WHERE state != 2
<if test="biz_group_id != 0">
<if test='biz_group_id != 0'>
AND AC.biz_group_id = #{biz_group_id}
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(AC.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(AC.reg_time) &lt;= #{date_end}
</if>
<if test="gid != 0">
<if test='gid != 0'>
AND AC.gid = #{gid}
</if>
<if test="user_id != null and user_id != ''">
<if test='user_id != null and user_id != ""'>
AND AC.user_id = #{user_id}
</if>
<if test="email != null and email != ''">
<if test='email != null and email != ""'>
AND AC.email like CONCAT(#{email}, '%')
</if>
<if test="nick_name != null and nick_name != ''">
AND AC.nick_name like CONCAT(#{nick_name}, '%')
<if test='name != null and name != ""'>
AND AC.name like CONCAT(#{name}, '%')
</if>
<if test="isCount == false and is_excel == false">
<if test='phone != null and phone != ""'>
AND AC.phone like CONCAT(#{phone}, '%')
</if>
<if test='isCount == false and is_excel == false'>
ORDER BY gid DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -61,35 +64,38 @@
)
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
AC.gid, AC.user_id, AC.reg_time, AC.user_pw, AC.biz_group_id, GT.name AS biz_group_name, AC.user_pw_time, AC.nick_name, AC.email, AC.state, AC.permission
AC.gid, AC.user_id, AC.reg_time, AC.user_pw, AC.biz_group_id, GT.name AS biz_group_name, AC.user_pw_time, AC.name, AC.phone, AC.email, AC.state, AC.permission
</otherwise>
</choose>
FROM account AS AC
JOIN group_tree GT ON GT.biz_group_id = AC.biz_group_id
WHERE state != 2
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(AC.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(AC.reg_time) &lt;= #{date_end}
</if>
<if test="gid != 0">
<if test='gid != 0'>
AND AC.gid = #{gid}
</if>
<if test="user_id != null and user_id != ''">
<if test='user_id != null and user_id != ""'>
AND AC.user_id = #{user_id}
</if>
<if test="email != null and email != ''">
AND AC.email like CONCAT(#{email}, '%')
<if test='email != null and email != ""'>
AND AC.email like CONCAT('%', #{email}, '%')
</if>
<if test="nick_name != null and nick_name != ''">
AND AC.nick_name like CONCAT(#{nick_name}, '%')
<if test='name != null and name != ""'>
AND AC.name like CONCAT('%', #{name}, '%')
</if>
<if test="isCount == false and is_excel == false">
<if test='phone != null and phone != ""'>
AND AC.phone like CONCAT(#{phone}, '%')
</if>
<if test='isCount == false and is_excel == false'>
ORDER BY gid DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -98,37 +104,41 @@
INSERT INTO account
<trim prefix="(" suffix=")" suffixOverrides=",">
user_id, user_pw,
<if test="nick_name != null and nick_name != ''">nick_name,</if>
<if test="email != null and email != ''">email,</if>
<if test="state != 0">state,</if>
<if test="biz_group_id != 0">biz_group_id,</if>
<if test="permission != 0">permission,</if>
<if test='name != null and name != ""'>name,</if>
<if test='phone != null and phone != ""'>phone,</if>
<if test='email != null and email != ""'>email,</if>
<if test='state != 0'>state,</if>
<if test='biz_group_id != 0'>biz_group_id,</if>
<if test='permission != 0'>permission,</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{user_id}, #{user_pw},
<if test="nick_name != null and nick_name != ''">#{nick_name},</if>
<if test="email != null and email != ''">#{email},</if>
<if test="state != 0">#{state},</if>
<if test="biz_group_id != 0">#{biz_group_id},</if>
<if test="permission != 0">#{permission},</if>
<if test='name != null and name != ""'>#{name},</if>
<if test='phone != null and phone != ""'>#{phone},</if>
<if test='email != null and email != ""'>#{email},</if>
<if test='state != 0'>#{state},</if>
<if test='biz_group_id != 0'>#{biz_group_id},</if>
<if test='permission != 0'>#{permission},</if>
</trim>
</insert>
<update id="updateAccount">
UPDATE account
<set>
<if test="user_pw != null and user_pw != ''">user_pw = #{user_pw},</if>
<if test="nick_name != null and nick_name != ''">nick_name = #{nick_name},</if>
<if test="email != null and email != ''">email = #{email},</if>
<if test="state != 0">state = #{state},</if>
<if test="biz_group_id != 0">biz_group_id = #{biz_group_id},</if>
<if test='user_pw != null and user_pw != ""'>user_pw = #{user_pw},</if>
<if test='name != null and name != ""'>name = #{name},</if>
<if test='phone != null and phone != ""'>phone = #{phone},</if>
<if test='email != null and email != ""'>email = #{email},</if>
<if test='state != 0'>state = #{state},</if>
<if test='biz_group_id != 0'>biz_group_id = #{biz_group_id},</if>
<if test='permission != 0'>permission = #{permission}</if>
</set>
WHERE gid = #{gid}
</update>
<update id="changeState">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE account
SET state=#{state}
WHERE gid IN
@@ -6,7 +6,7 @@
<select id="selectBizGroup" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -15,31 +15,28 @@
</choose>
FROM biz_group AS BG
WHERE state != 2
<if test="name != null and name != ''">
AND name like CONCAT(#{name}, '%')
</if>
<if test="biz_group_id != 0">
<if test='biz_group_id != 0'>
AND biz_group_id = #{biz_group_id}
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(reg_time) &lt;= #{date_end}
</if>
<if test="name != null and name != ''">
AND name like CONCAT(#{name}, '%')
<if test='name != null and name != ""'>
AND name like CONCAT('%', #{name}, '%')
</if>
<if test="biz_reg_num != null and biz_reg_num != ''">
AND biz_reg_num like CONCAT(#{biz_reg_num}, '%')
<if test='biz_reg_num != null and biz_reg_num != ""'>
AND biz_reg_num like CONCAT('%', #{biz_reg_num}, '%')
</if>
<if test="email != null and email != ''">
AND email like CONCAT(#{email}, '%')
<if test='email != null and email != ""'>
AND email like CONCAT('%', #{email}, '%')
</if>
<if test="phone != null and phone != ''">
AND phone like CONCAT(#{phone}, '%')
<if test='phone != null and phone != ""'>
AND phone like CONCAT('%', #{phone}, '%')
</if>
<if test="address != null and address != ''">
AND address like CONCAT(#{address}, '%')
<if test='address != null and address != ""'>
AND address like CONCAT('%', #{address}, '%')
</if>
<if test="isCount == false">
<if test='isCount == false'>
ORDER BY biz_group_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -48,7 +45,7 @@
SELECT biz_group_id
FROM biz_group
WHERE state != 2 AND biz_reg_num = #{biz_reg_num}
<if test="biz_group_id != 0">
<if test='biz_group_id != 0'>
AND biz_group_id != #{biz_group_id}
</if>
LIMIT 1
@@ -77,38 +74,38 @@
<insert id="insertBizGroup" parameterType="map" useGeneratedKeys="true" keyProperty="biz_group_id">
INSERT INTO biz_group
<choose>
<when test="pid == 0">
<when test='pid == 0'>
<trim prefix="(" suffix=")" suffixOverrides=",">
name, biz_reg_num, gid
<if test="email != null and email != ''">, email</if>
<if test="phone != null and phone != ''">, phone</if>
<if test="ceo != null and ceo != ''">, ceo</if>
<if test="address != null and address != ''">, address</if>
<if test='email != null and email != ""'>, email</if>
<if test='phone != null and phone != ""'>, phone</if>
<if test='ceo != null and ceo != ""'>, ceo</if>
<if test='address != null and address != ""'>, address</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{name}, #{biz_reg_num}, #{gid}
<if test="email != null and email != ''">, #{email}</if>
<if test="phone != null and phone != ''">, #{phone}</if>
<if test="ceo != null and ceo != ''">, #{ceo}</if>
<if test="address != null and address != ''">, #{address}</if>
<if test='email != null and email != ""'>, #{email}</if>
<if test='phone != null and phone != ""'>, #{phone}</if>
<if test='ceo != null and ceo != ""'>, #{ceo}</if>
<if test='address != null and address != ""'>, #{address}</if>
</trim>
</when>
<otherwise>
<trim prefix="(" suffix=")" suffixOverrides=",">
top_group_id, pid, name, biz_reg_num, gid
<if test="email != null and email != ''">, email</if>
<if test="phone != null and phone != ''">, phone</if>
<if test="ceo != null and ceo != ''">, ceo</if>
<if test="address != null and address != ''">, address</if>
<if test='email != null and email != ""'>, email</if>
<if test='phone != null and phone != ""'>, phone</if>
<if test='ceo != null and ceo != ""'>, ceo</if>
<if test='address != null and address != ""'>, address</if>
</trim>
SELECT
COALESCE(TGI.top_group_id, #{pid}) AS top_group_id,
#{pid}, #{name}, #{biz_reg_num}, #{gid}
<if test="email != null and email != ''">, #{email}</if>
<if test="phone != null and phone != ''">, #{phone}</if>
<if test="ceo != null and ceo != ''">, #{ceo}</if>
<if test="address != null and address != ''">, #{address}</if>
<if test='email != null and email != ""'>, #{email}</if>
<if test='phone != null and phone != ""'>, #{phone}</if>
<if test='ceo != null and ceo != ""'>, #{ceo}</if>
<if test='address != null and address != ""'>, #{address}</if>
FROM (
SELECT top_group_id
FROM biz_group
@@ -122,19 +119,19 @@
<update id="updateBizGroup">
UPDATE biz_group
<set>
<if test="name != null and name != ''">name = #{name},</if>
<if test="biz_reg_num != null and biz_reg_num != ''">biz_reg_num = #{biz_reg_num},</if>
<if test="email != null and email != ''">email = #{email},</if>
<if test="phone != null and phone != ''">phone = #{phone},</if>
<if test="ceo != null and ceo != ''">ceo = #{ceo},</if>
<if test="address != null and address != ''">address = #{address},</if>
<if test="pid != 0">pid = #{pid},</if>
<if test='name != null and name != ""'>name = #{name},</if>
<if test='biz_reg_num != null and biz_reg_num != ""'>biz_reg_num = #{biz_reg_num},</if>
<if test='email != null and email != ""'>email = #{email},</if>
<if test='phone != null and phone != ""'>phone = #{phone},</if>
<if test='ceo != null and ceo != ""'>ceo = #{ceo},</if>
<if test='address != null and address != ""'>address = #{address},</if>
<if test='pid != 0'>pid = #{pid},</if>
</set>
WHERE biz_group_id = #{biz_group_id}
</update>
<update id="changeStateBizGroup">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE biz_group
SET state = #{state}
WHERE biz_group_id IN
@@ -145,7 +142,7 @@
</update>
<!--
<delete id="deleteBizGroup">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
DELETE FROM biz_group
WHERE biz_group_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
@@ -158,7 +155,7 @@
<update id="changePidBizGroup">
UPDATE biz_group
<choose>
<when test="new_pid != null">
<when test='new_pid != null'>
SET pid = #{new_pid}
</when>
<otherwise>
@@ -172,7 +169,7 @@
</update>
<update id="changeState">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE biz_group
SET state = #{state}
WHERE biz_group_id IN
@@ -235,27 +232,27 @@
) AS hasChildren
FROM biz_group BG
WHERE BG.state != 2 AND BG.pid is null
<if test="top_group_id != 0">
<if test='top_group_id != 0'>
AND (BG.biz_group_id = #{top_group_id} OR BG.top_group_id = #{top_group_id})
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(BG.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(BG.reg_time) &lt;= #{date_end}
</if>
<if test="name != null and name != ''">
AND BG.name like CONCAT(#{name}, '%')
<if test='name != null and name != ""'>
AND BG.name like CONCAT('%', #{name}, '%')
</if>
<if test="biz_reg_num != null and biz_reg_num != ''">
AND BG.biz_reg_num like CONCAT(#{biz_reg_num}, '%')
<if test='biz_reg_num != null and biz_reg_num != ""'>
AND BG.biz_reg_num like CONCAT('%', #{biz_reg_num}, '%')
</if>
</select>
<select id="selectBizGroupChildTree" resultType="map">
SELECT
<choose>
<when test="queryAll == true">
<when test='queryAll == true'>
BG.biz_group_id, BG.top_group_id, BG.reg_time, BG.name, BG.biz_reg_num, BG.email, BG.phone, BG.ceo, BG.address,
</when>
<otherwise>
@@ -270,20 +267,20 @@
) AS hasChildren
FROM biz_group BG
WHERE BG.state != 2 AND BG.pid = #{pid}
<if test="top_group_id != 0">
<if test='top_group_id != 0'>
AND BG.top_group_id = #{top_group_id}
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(BG.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(BG.reg_time) &lt;= #{date_end}
</if>
<if test="name != null and name != ''">
AND BG.name like CONCAT(#{name}, '%')
<if test='name != null and name != ""'>
AND BG.name like CONCAT('%', #{name}, '%')
</if>
<if test="biz_reg_num != null and biz_reg_num != ''">
AND BG.biz_reg_num like CONCAT(#{biz_reg_num}, '%')
<if test='biz_reg_num != null and biz_reg_num != ""'>
AND BG.biz_reg_num like CONCAT('%', #{biz_reg_num}, '%')
</if>
</select>
@@ -291,7 +288,7 @@
WITH RECURSIVE group_tree AS (
SELECT
<choose>
<when test="queryAll == true">
<when test='queryAll == true'>
BG.biz_group_id, BG.pid, BG.top_group_id, BG.reg_time, BG.name, BG.biz_reg_num, BG.email, BG.phone, BG.ceo, BG.address,
</when>
<otherwise>
@@ -306,24 +303,24 @@
) AS hasChildren
FROM biz_group BG
WHERE BG.state != 2
<if test="biz_group_id != 0">
<if test='biz_group_id != 0'>
AND BG.biz_group_id = #{biz_group_id}
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(BG.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(BG.reg_time) &lt;= #{date_end}
</if>
<if test="name != null and name != ''">
AND BG.name like CONCAT(#{name}, '%')
<if test='name != null and name != ""'>
AND BG.name like CONCAT('%', #{name}, '%')
</if>
<if test="biz_reg_num != null and biz_reg_num != ''">
AND BG.biz_reg_num like CONCAT(#{biz_reg_num}, '%')
<if test='biz_reg_num != null and biz_reg_num != ""'>
AND BG.biz_reg_num like CONCAT('%', #{biz_reg_num}, '%')
</if>
<choose>
<when test="biz_group_id != 0">
<when test='biz_group_id != 0'>
UNION ALL
</when>
<otherwise>
@@ -333,7 +330,7 @@
SELECT
<choose>
<when test="queryAll == true">
<when test='queryAll == true'>
BG.biz_group_id, BG.pid, BG.top_group_id, BG.reg_time, BG.name, BG.biz_reg_num, BG.email, BG.phone, BG.ceo, BG.address,
</when>
<otherwise>
@@ -7,7 +7,7 @@
<select id="selectDevice" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -19,26 +19,26 @@
JOIN biz_group AS BG ON BG.biz_group_id = DBG.biz_group_id
LEFT JOIN terminal AS T ON T.device_id = D.device_id
WHERE D.state != 2 AND ( BG.biz_group_id = #{biz_group_id}
<if test="is_group_access == false">
<if test='is_group_access == false'>
OR BG.top_group_id = #{biz_group_id}
</if>
)
<if test="name != null and name != ''">
<if test='name != null and name != ""'>
AND D.name = #{name}
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(D.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(D.reg_time) &lt;= #{date_end}
</if>
<if test="isCount == false and is_excel == false">
<if test='isCount == false and is_excel == false'>
ORDER BY D.device_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
-->
<select id="selectDevice" resultType="map">
<if test="is_group_access == false">
<if test='is_group_access == false'>
WITH target_group AS (
WITH RECURSIVE group_tree AS (
SELECT
@@ -62,7 +62,7 @@
</if>
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -75,23 +75,32 @@
LEFT JOIN terminal AS T ON T.device_id = D.device_id
WHERE D.state != 2 AND
<choose>
<when test="is_group_access == false">
<when test='is_group_access == false'>
DBG.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</when>
<otherwise>
DBG.biz_group_id = #{biz_group_id}
</otherwise>
</choose>
<if test="name != null and name != ''">
AND D.name = #{name}
<if test='name != null and name != ""'>
AND D.name like CONCAT('%', #{name}, '%')
</if>
<if test="date_start != null and date_start != ''">
<if test='uid1 != null and uid1 != ""'>
AND T.uid1 = #{uid1}
</if>
<if test='conn_state != null and conn_state == "1"'>
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time &lt;= T.disconnect_time
</if>
<if test='conn_state != null and conn_state == "4"'>
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time &gt; T.disconnect_time
</if>
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(D.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(D.reg_time) &lt;= #{date_end}
</if>
<if test="isCount == false and is_excel == false">
<if test='isCount == false and is_excel == false'>
ORDER BY D.device_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -116,7 +125,7 @@
)
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -128,16 +137,25 @@
JOIN group_tree GT ON DBG.biz_group_id = GT.biz_group_id
LEFT JOIN terminal AS T ON T.device_id = D.device_id
WHERE D.state != 2
<if test="name != null and name != ''">
AND D.name = #{name}
<if test='name != null and name != ""'>
AND D.name like CONCAT('%', #{name}, '%')
</if>
<if test="date_start != null and date_start != ''">
<if test='uid1 != null and uid1 != ""'>
AND T.uid1 = #{uid1}
</if>
<if test='conn_state != null and conn_state == "1"'>
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time &gt;= T.disconnect_time
</if>
<if test='conn_state != null and conn_state == "4"'>
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time &lt; T.disconnect_time
</if>
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(D.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(D.reg_time) &lt;= #{date_end}
</if>
<if test="isCount == false and is_excel == false">
<if test='isCount == false and is_excel == false'>
ORDER BY D.device_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -185,38 +203,35 @@
device_id, name, uid1
FROM device
WHERE state != 2
<if test="device_id != 0">
<if test='device_id != 0'>
AND device_id != #{device_id}
</if>
<if test="name != null and name != ''">
<if test='name != null and name != ""'>
AND name = #{name}
</if>
LIMIT 1
</select>
<insert id="insertDevice"
parameterType="map"
useGeneratedKeys="true"
keyProperty="device_id">
<insert id="insertDevice" parameterType="map" useGeneratedKeys="true" keyProperty="device_id">
INSERT INTO device
<trim prefix="(" suffix=")" suffixOverrides=",">
name, gid, state,
<if test="manager_name != null and manager_name != ''">manager_name,</if>
<if test='manager_name != null and manager_name != ""'>manager_name,</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{name}, #{gid}, #{state},
<if test="manager_name != null and manager_name != ''">#{manager_name},</if>
<if test='manager_name != null and manager_name != ""'>#{manager_name},</if>
</trim>
</insert>
<update id="updateDevice">
UPDATE device
<set>
<if test="name != null and name != ''">name = #{name},</if>
<if test="uid1 != null and uid1 != ''">uid1 = #{uid1},</if>
<if test="manager_name != null and manager_name != ''">manager_name = #{manager_name},</if>
<if test="gid != null and gid != ''">gid = #{gid},</if>
<if test='name != null and name != ""'>name = #{name},</if>
<if test='uid1 != null and uid1 != ""'>uid1 = #{uid1},</if>
<if test='manager_name != null and manager_name != ""'>manager_name = #{manager_name},</if>
<if test='gid != null and gid != ""'>gid = #{gid},</if>
</set>
WHERE device_id = #{device_id}
</update>
@@ -232,7 +247,7 @@
</update>
<update id="changeStateDevice">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE device
SET state = #{state}
WHERE device_id IN
@@ -244,7 +259,7 @@
<delete id="deleteDevice">
<!--
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
DELETE FROM device
WHERE device_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
@@ -6,32 +6,32 @@
<select id="selectErrorHistory" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
EH.error_history_id, EH.reg_time, EH.uid1, EH.uid1_type, EH.slot
EH.error_history_id, EH.reg_time, EH.uid1, EH.uid1_type, EH.column_no
</otherwise>
</choose>
FROM error_history EH
WHERE 1=1
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(EH.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(EH.reg_time) &lt;= #{date_end}
</if>
<if test="uid1 != null and uid1 != ''">
AND EH.uid1 like CONCAT('%', #{uid1}, '%')
<if test='uid1 != null and uid1 != ""'>
AND EH.uid1 = #{uid1}
</if>
<if test="isCount == false and is_excel == false">
<if test='isCount == false and is_excel == false'>
ORDER BY EH.error_history_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
<select id="selectErrorHistoryByState" resultType="map">
SELECT
EH.error_history_id, EH.reg_time, EH.uid1, EH.uid1_type, EH.slot
EH.error_history_id, EH.reg_time, EH.uid1, EH.uid1_type, EH.column_no
FROM error_history EH
WHERE EH.state = #{state}
</select>
@@ -39,11 +39,11 @@
<insert id="insertErrorHistory">
INSERT INTO error_history
<trim prefix="(" suffix=")" suffixOverrides=",">
uid1, uid1_type, slot,
uid1, uid1_type, column_no,
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{uid1}, #{uid1_type}, #{slot},
#{uid1}, #{uid1_type}, #{column_no},
</trim>
</insert>
@@ -6,7 +6,7 @@
<select id="selectGoods" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -16,29 +16,29 @@
FROM goods AS G
JOIN biz_group AS BG ON BG.biz_group_id = G.biz_group_id
WHERE G.state != 2 AND ( BG.biz_group_id = #{biz_group_id}
<if test="is_group_access == false">
<if test='is_group_access == false'>
OR BG.top_group_id = #{biz_group_id}
</if>
)
<if test="code != null and code != ''">
<if test='code != null and code != ""'>
AND G.code = #{code}
</if>
<if test="name != null and name != ''">
AND G.name = #{name}
<if test='name != null and name != ""'>
AND G.name like CONCAT('%', #{name}, '%')
</if>
<if test="state != 0">
<if test='state != 0'>
AND G.state = #{state}
</if>
<if test="vendor != null and vendor != ''">
<if test='vendor != null and vendor != ""'>
AND G.vendor = #{vendor}
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(G.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(G.reg_time) &lt;= #{date_end}
</if>
<if test="isCount == false and is_excel == false">
<if test='isCount == false and is_excel == false'>
ORDER BY G.goods_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -74,7 +74,7 @@
ON BG.biz_group_id = G.biz_group_id
WHERE G.state != 2 AND (
BG.biz_group_id = (SELECT biz_group_id FROM target_group)
<if test="is_group_access == false">
<if test='is_group_access == false'>
OR BG.top_group_id = (SELECT biz_group_id FROM target_group)
</if>
)
@@ -117,14 +117,14 @@
SELECT goods_id
FROM goods
WHERE 1=1
<if test="biz_group_id != 0">
<if test='biz_group_id != 0'>
AND biz_group_id = #{biz_group_id}
</if>
AND ( false
<if test="code != null and code != ''">
<if test='code != null and code != ""'>
OR code = #{code}
</if>
<if test="name != null and name != ''">
<if test='name != null and name != ""'>
OR name = #{name}
</if>
)
@@ -145,7 +145,7 @@
G.vendor,
G.opt,
DG.device_id,
DG.slot,
DG.column_no,
DG.price AS device_goods_price,
DG.inventory AS device_goods_inventory
FROM terminal AS T
@@ -154,7 +154,7 @@
JOIN goods AS G ON G.goods_id = DG.goods_id
WHERE T.uid1 = #{uid1}
AND T.type = #{uid1_type}
AND DG.slot = #{slot}
AND DG.column_no = #{column_no}
AND T.state != 2
AND D.state != 2
AND G.state != 2
@@ -165,30 +165,30 @@
INSERT INTO goods
<trim prefix="(" suffix=")" suffixOverrides=",">
biz_group_id, code, name, price, inventory, gid,
<if test="vendor != null and vendor != ''">vendor,</if>
<if test='vendor != null and vendor != ""'>vendor,</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{biz_group_id}, #{code}, #{name}, #{price}, #{inventory}, #{gid},
<if test="vendor != null and vendor != ''">#{vendor},</if>
<if test='vendor != null and vendor != ""'>#{vendor},</if>
</trim>
</insert>
<update id="updateGoods">
UPDATE goods
<set>
<if test="code != null and code != ''">code = #{code},</if>
<if test="name != null and name != ''">name = #{name},</if>
<if test="price != null">price = #{price},</if>
<if test="inventory != null">inventory = #{inventory},</if>
<if test="vendor != null and vendor != ''">vendor = #{vendor},</if>
<if test="gid != 0">gid = #{gid},</if>
<if test='code != null and code != ""'>code = #{code},</if>
<if test='name != null and name != ""'>name = #{name},</if>
<if test='price != null'>price = #{price},</if>
<if test='inventory != null'>inventory = #{inventory},</if>
<if test='vendor != null and vendor != ""'>vendor = #{vendor},</if>
<if test='gid != 0'>gid = #{gid},</if>
</set>
WHERE goods_id = #{goods_id}
</update>
<delete id="deleteGoods">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
DELETE FROM goods
WHERE goods_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
@@ -199,21 +199,21 @@
<select id="selectDeviceGoods" resultType="map">
SELECT
DG.device_id, DG.slot, G.goods_id, DG.idx, DG.inventory, G.reg_time, G.name, G.code, G.price, G.vendor, G.state, DG.inventory_max, DG.inventory_alarm
DG.device_id, DG.column_no, G.goods_id, DG.idx, DG.inventory, G.reg_time, G.name, G.code, G.price, G.vendor, G.state, DG.inventory_max, DG.inventory_alarm
FROM goods AS G
JOIN device_goods AS DG ON DG.goods_id = G.goods_id
WHERE G.state != 2 AND DG.device_id = #{device_id}
ORDER BY DG.slot ASC
ORDER BY DG.column_no ASC
</select>
<insert id="insertDeviceGoods">
<if test="device_goods != null and device_goods.size > 0">
<if test='device_goods != null and device_goods.size > 0'>
INSERT INTO device_goods (
device_id, slot, goods_id, price, inventory, idx, inventory_max, inventory_alarm
device_id, column_no, goods_id, price, inventory, idx, inventory_max, inventory_alarm
) VALUES
<foreach collection="device_goods" item="item" separator=",">
(
#{device_id}, #{item.slot}, #{item.goods_id}, #{item.price}, #{item.inventory}, #{item.idx}, #{item.inventory_max}, #{item.inventory_alarm}
#{device_id}, #{item.column_no}, #{item.goods_id}, #{item.price}, #{item.inventory}, #{item.idx}, #{item.inventory_max}, #{item.inventory_alarm}
)
</foreach>
</if>
@@ -223,7 +223,7 @@
UPDATE device_goods dg
JOIN transactions t
ON dg.device_id = t.device_id
AND dg.slot = t.slot
AND dg.column_no = t.column_no
SET dg.inventory = dg.inventory + 1
WHERE t.approval = #{approval}
</update>
@@ -233,16 +233,16 @@
<set>
inventory = inventory - 1
</set>
WHERE device_id = #{device_id} AND slot = #{slot}
WHERE device_id = #{device_id} AND column_no = #{column_no}
</update>
<update id="updateDeviceGoodsInventory">
<choose>
<when test="type == 'D4'">
<when test='type == "D4"'>
UPDATE device_goods dg
JOIN transactions t
ON dg.device_id = t.device_id
AND dg.slot = t.slot
AND dg.column_no = t.column_no
SET dg.inventory = dg.inventory + 1
WHERE t.approval = #{approval}
</when>
@@ -251,17 +251,17 @@
<set>
inventory = inventory - 1
</set>
WHERE device_id = #{device_id} AND slot = #{slot}
WHERE device_id = #{device_id} AND column_no = #{column_no}
</otherwise>
</choose>
</update>
<delete id="deleteDeviceGoods">
<if test="device_goods != null and device_goods.size > 0">
<if test='device_goods != null and device_goods.size > 0'>
DELETE FROM device_goods
WHERE device_id = #{device_id} AND slot IN
WHERE device_id = #{device_id} AND column_no IN
<foreach collection="device_goods" item="item" open="(" separator="," close=")">
#{item.slot}
#{item.column_no}
</foreach>
</if>
</delete>
@@ -269,7 +269,7 @@
<select id="selectGoodsTemplateByBizGroupId" resultType="map">
SELECT
GTE.goods_template_element_id,
GTE.slot,
GTE.column_no,
GTE.goods_id,
GTE.inventory,
GTE.inventory_max,
@@ -291,7 +291,7 @@
<select id="selectGoodsTemplateById" resultType="map">
SELECT
GTE.goods_template_element_id,
GTE.slot,
GTE.column_no,
GTE.goods_id,
GTE.inventory,
GTE.inventory_max,
@@ -326,13 +326,13 @@
</insert>
<insert id="insertGoodsTemplateElements">
<if test="goods_template_elements != null and goods_template_elements.size > 0">
<if test='goods_template_elements != null and goods_template_elements.size > 0'>
INSERT INTO goods_template_element (
slot, goods_id, inventory, goods_template_id,idx,inventory_max,inventory_alarm
column_no, goods_id, inventory, goods_template_id,idx,inventory_max,inventory_alarm
) VALUES
<foreach collection="goods_template_elements" item="item" separator=",">
(
#{item.slot}, #{item.goods_id}, #{item.inventory}, #{goods_template_id}, #{item.idx}, #{item.inventory_max}, #{item.inventory_alarm}
#{item.column_no}, #{item.goods_id}, #{item.inventory}, #{goods_template_id}, #{item.idx}, #{item.inventory_max}, #{item.inventory_alarm}
)
</foreach>
</if>
@@ -341,7 +341,7 @@
<update id="updateGoodsTemplate">
UPDATE goods_template
<set>
<if test="name != null and name != ''">name = #{name},</if>
<if test='name != null and name != ""'>name = #{name},</if>
</set>
WHERE goods_template_id = #{goods_template_id}
</update>
@@ -6,7 +6,7 @@
<select id="selectLocation" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -15,22 +15,22 @@
</choose>
FROM location AS BG
WHERE state != 2
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(reg_time) &lt;= #{date_end}
</if>
<if test="name != null and name != ''">
AND name like CONCAT(#{name}, '%')
<if test='name != null and name != ""'>
AND name like CONCAT('%', #{name}, '%')
</if>
<if test="description != null and description != ''">
AND description like CONCAT(#{description}, '%')
<if test='description != null and description != ""'>
AND description like CONCAT('%', #{description}, '%')
</if>
<if test="address != null and address != ''">
AND address like CONCAT(#{address}, '%')
<if test='address != null and address != ""'>
AND address like CONCAT('%', #{address}, '%')
</if>
<if test="isCount == false">
<if test='isCount == false'>
ORDER BY location_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -49,32 +49,32 @@
INSERT INTO location
<trim prefix="(" suffix=")" suffixOverrides=",">
name, gid,
<if test="description != null and description != ''">description,</if>
<if test="address != null and address != ''">address,</if>
<if test="pid != 0">pid,</if>
<if test='description != null and description != ""'>description,</if>
<if test='address != null and address != ""'>address,</if>
<if test='pid != 0'>pid,</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{name}, #{gid},
<if test="description != null and description != ''">#{description},</if>
<if test="address != null and address != ''">#{address},</if>
<if test="pid != 0">#{pid},</if>
<if test='description != null and description != ""'>#{description},</if>
<if test='address != null and address != ""'>#{address},</if>
<if test='pid != 0'>#{pid},</if>
</trim>
</insert>
<update id="updateLocation">
UPDATE location
<set>
<if test="name != null and name != ''">name = #{name},</if>
<if test="description != null and description != ''">description = #{description},</if>
<if test="address != null and address != ''">address = #{address},</if>
<if test="pid != 0">pid = #{pid},</if>
<if test='name != null and name != ""'>name = #{name},</if>
<if test='description != null and description != ""'>description = #{description},</if>
<if test='address != null and address != ""'>address = #{address},</if>
<if test='pid != 0'>pid = #{pid},</if>
</set>
WHERE location_id = #{location_id}
</update>
<update id="changeStateLocation">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE location
SET state = #{state}
WHERE location_id IN
@@ -87,7 +87,7 @@
<update id="changePidLocation">
UPDATE location
<choose>
<when test="new_pid != null">
<when test='new_pid != null'>
SET pid = #{new_pid}
</when>
<otherwise>
@@ -101,7 +101,7 @@
</update>
<update id="changeState">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE location
SET state=#{state}
WHERE location_id IN
@@ -160,22 +160,22 @@
SELECT location_id, reg_time, name, description, address
FROM location
WHERE state != 2
<if test="(name == null || name == '') and (description == null || description == '')">
<if test='(name == null || name == "") and (description == null || description == "")'>
AND pid is null
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(reg_time) &lt;= #{date_end}
</if>
<if test="name != null and name != ''">
<if test='name != null and name != ""'>
AND name like CONCAT(#{name}, '%')
</if>
<if test="description != null and description != ''">
<if test='description != null and description != ""'>
AND description like CONCAT(#{description}, '%')
</if>
<if test="address != null and address != ''">
<if test='address != null and address != ""'>
AND address like CONCAT(#{address}, '%')
</if>
</select>
@@ -183,7 +183,7 @@
<select id="selectLocationChildTree" resultType="map">
SELECT
<choose>
<when test="queryAll == true">
<when test='queryAll == true'>
location_id, reg_time, name, description, address
</when>
<otherwise>
@@ -192,19 +192,19 @@
</choose>
FROM location
WHERE state != 2 AND pid = #{pid}
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(reg_time) &lt;= #{date_end}
</if>
<if test="name != null and name != ''">
<if test='name != null and name != ""'>
AND name like CONCAT(#{name}, '%')
</if>
<if test="description != null and description != ''">
<if test='description != null and description != ""'>
AND description like CONCAT(#{description}, '%')
</if>
<if test="address != null and address != ''">
<if test='address != null and address != ""'>
AND address like CONCAT(#{address}, '%')
</if>
</select>
@@ -12,7 +12,7 @@
<select id="selectNotice" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -21,19 +21,19 @@
</choose>
FROM notice AS RB
WHERE state != 2
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(reg_time) &lt;= #{date_end}
</if>
<if test="title != null and title != ''">
<if test='title != null and title != ""'>
AND title like CONCAT(#{title}, '%')
</if>
<if test="content != null and content != ''">
<if test='content != null and content != ""'>
AND content like CONCAT(#{content}, '%')
</if>
<if test="isCount == false">
<if test='isCount == false'>
ORDER BY notice_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -52,14 +52,14 @@
<update id="updateNotice">
UPDATE notice
<set>
<if test="title != null and title != ''">title = #{title},</if>
<if test="content != null and content != ''">content = #{content},</if>
<if test='title != null and title != ""'>title = #{title},</if>
<if test='content != null and content != ""'>content = #{content},</if>
</set>
WHERE notice_id = #{notice_id}
</update>
<update id="changeStateNotice">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE notice
SET state = #{state}
WHERE notice_id IN
@@ -70,7 +70,7 @@
</update>
<!--
<delete id="deleteNotice">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
DELETE FROM resource_board
WHERE resource_board_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
@@ -6,26 +6,26 @@
<select id="selectOperatingHistory" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
OH.operating_history_id, OH.reg_time, OH.type, OH.action, A.gid, A.user_id, A.nick_name
OH.operating_history_id, OH.reg_time, OH.type, OH.action, A.gid, A.user_id, A.name
</otherwise>
</choose>
FROM operating_history OH
JOIN account A ON A.gid = OH.gid
WHERE 1=1
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(OH.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(OH.reg_time) &lt;= #{date_end}
</if>
<if test="action != null and action != ''">
<if test='action != null and action != ""'>
AND OH.action like CONCAT('%', #{action}, '%')
</if>
<if test="isCount == false and is_excel == false">
<if test='isCount == false and is_excel == false'>
ORDER BY OH.operating_history_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -6,24 +6,24 @@
<sql id="ordersWhere">
<where>
AND o.state != 2
<if test="param.order_id != null and param.order_id != ''">
<if test='param.order_id != null and param.order_id != ""'>
AND o.order_id = #{param.order_id}
</if>
<if test="param.biz_group_name != null and param.biz_group_name != ''">
<if test='param.biz_group_name != null and param.biz_group_name != ""'>
AND b.name LIKE CONCAT('%', #{param.biz_group_name}, '%')
</if>
<if test="param.name != null and param.name != ''">
<if test='param.name != null and param.name != ""'>
AND CONCAT(a.last_name, a.first_name)
LIKE CONCAT('%', #{param.name}, '%')
</if>
<if test="param.date_start != null and param.date_start != ''">
<if test='param.date_start != null and param.date_start != ""'>
AND o.reg_time &gt;= #{param.date_start}
</if>
<if test="param.date_end != null and param.date_end != ''">
<if test='param.date_end != null and param.date_end != ""'>
AND o.reg_time &lt;= #{param.date_end}
</if>
</where>
@@ -31,7 +31,7 @@
<select id="selectOrders" parameterType="map" resultType="map">
<choose>
<when test="isCount == true">
<when test='isCount == true'>
SELECT
o.*,
CONCAT(a.last_name, a.first_name) AS submitter,
@@ -60,69 +60,69 @@
INSERT INTO orders
<trim prefix="(" suffix=")" suffixOverrides=",">
biz_group_id,
<if test="state != null and state != ''">state,</if>
<if test="is_doc_accept != null">is_doc_accept,</if>
<if test="is_tid != null">is_tid,</if>
<if test="is_card != null">is_card,</if>
<if test="is_samchip != null">is_samchip,</if>
<if test="is_comm_open != null">is_comm_open,</if>
<if test="is_shipping != null">is_shipping,</if>
<if test="is_tested != null">is_tested,</if>
<if test="is_parcel != null">is_parcel,</if>
<if test="order_time != null and order_time != ''">order_time,</if>
<if test="goods_list_id != null and goods_list_id != ''">goods_list_id,</if>
<if test="delivery_address != null and delivery_address != ''">delivery_address,</if>
<if test="delivery_recv_name != null and delivery_recv_name != ''">delivery_recv_name,</if>
<if test="delivery_recv_phone != null and delivery_recv_phone != ''">delivery_recv_phone,</if>
<if test="delivery_invoice_no != null and delivery_invoice_no != ''">delivery_invoice_no,</if>
<if test="delivery_company != null and delivery_company != ''">delivery_company,</if>
<if test="delivery_req_time != null and delivery_req_time != ''">delivery_req_time,</if>
<if test="gid != null and gid != ''">gid</if>
<if test='state != null and state != ""'>state,</if>
<if test='is_doc_accept != null'>is_doc_accept,</if>
<if test='is_tid != null'>is_tid,</if>
<if test='is_card != null'>is_card,</if>
<if test='is_samchip != null'>is_samchip,</if>
<if test='is_comm_open != null'>is_comm_open,</if>
<if test='is_shipping != null'>is_shipping,</if>
<if test='is_tested != null'>is_tested,</if>
<if test='is_parcel != null'>is_parcel,</if>
<if test='order_time != null and order_time != ""'>order_time,</if>
<if test='goods_list_id != null and goods_list_id != ""'>goods_list_id,</if>
<if test='delivery_address != null and delivery_address != ""'>delivery_address,</if>
<if test='delivery_recv_name != null and delivery_recv_name != ""'>delivery_recv_name,</if>
<if test='delivery_recv_phone != null and delivery_recv_phone != ""'>delivery_recv_phone,</if>
<if test='delivery_invoice_no != null and delivery_invoice_no != ""'>delivery_invoice_no,</if>
<if test='delivery_company != null and delivery_company != ""'>delivery_company,</if>
<if test='delivery_req_time != null and delivery_req_time != ""'>delivery_req_time,</if>
<if test='gid != null and gid != ""'>gid</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{biz_group_id},
<if test="state != null and state != ''">#{state},</if>
<if test="is_doc_accept != null">#{is_doc_accept},</if>
<if test="is_tid != null">#{is_tid},</if>
<if test="is_card != null">#{is_card},</if>
<if test="is_samchip != null">#{is_samchip},</if>
<if test="is_comm_open != null">#{is_comm_open},</if>
<if test="is_shipping != null">#{is_shipping},</if>
<if test="is_tested != null">#{is_tested},</if>
<if test="is_parcel != null">#{is_parcel},</if>
<if test="order_time != null and order_time != ''">#{order_time},</if>
<if test="goods_list_id != null and goods_list_id != ''">#{goods_list_id},</if>
<if test="delivery_address != null and delivery_address != ''">#{delivery_address},</if>
<if test="delivery_recv_name != null and delivery_recv_name != ''">#{delivery_recv_name},</if>
<if test="delivery_recv_phone != null and delivery_recv_phone != ''">#{delivery_recv_phone},</if>
<if test="delivery_invoice_no != null and delivery_invoice_no != ''">#{delivery_invoice_no},</if>
<if test="delivery_company != null and delivery_company != ''">#{delivery_company},</if>
<if test="delivery_req_time != null and delivery_req_time != ''">#{delivery_req_time},</if>
<if test="gid != null and gid != ''">#{gid}</if>
<if test='state != null and state != ""'>#{state},</if>
<if test='is_doc_accept != null'>#{is_doc_accept},</if>
<if test='is_tid != null'>#{is_tid},</if>
<if test='is_card != null'>#{is_card},</if>
<if test='is_samchip != null'>#{is_samchip},</if>
<if test='is_comm_open != null'>#{is_comm_open},</if>
<if test='is_shipping != null'>#{is_shipping},</if>
<if test='is_tested != null'>#{is_tested},</if>
<if test='is_parcel != null'>#{is_parcel},</if>
<if test='order_time != null and order_time != ""'>#{order_time},</if>
<if test='goods_list_id != null and goods_list_id != ""'>#{goods_list_id},</if>
<if test='delivery_address != null and delivery_address != ""'>#{delivery_address},</if>
<if test='delivery_recv_name != null and delivery_recv_name != ""'>#{delivery_recv_name},</if>
<if test='delivery_recv_phone != null and delivery_recv_phone != ""'>#{delivery_recv_phone},</if>
<if test='delivery_invoice_no != null and delivery_invoice_no != ""'>#{delivery_invoice_no},</if>
<if test='delivery_company != null and delivery_company != ""'>#{delivery_company},</if>
<if test='delivery_req_time != null and delivery_req_time != ""'>#{delivery_req_time},</if>
<if test='gid != null and gid != ""'>#{gid}</if>
</trim>
</insert>
<update id="updateOrders" parameterType="map">
UPDATE orders
<set>
<if test="biz_group_id != null and biz_group_id != ''">biz_group_id = #{biz_group_id},</if>
<if test="state != null and state != ''">state = #{state},</if>
<if test="is_doc_accept != null">is_doc_accept = #{is_doc_accept},</if>
<if test="is_tid != null">is_tid = #{is_tid},</if>
<if test="is_card != null">is_card = #{is_card},</if>
<if test="is_samchip != null">is_samchip = #{is_samchip},</if>
<if test="is_comm_open != null">is_comm_open = #{is_comm_open},</if>
<if test="is_shipping != null">is_shipping = #{is_shipping},</if>
<if test="is_tested != null">is_tested = #{is_tested},</if>
<if test="is_parcel != null">is_parcel = #{is_parcel},</if>
<if test="goods_list_id != null and goods_list_id != ''">goods_list_id = #{goods_list_id},</if>
<if test="delivery_address != null and delivery_address != ''">delivery_address = #{delivery_address},</if>
<if test="delivery_recv_name != null and delivery_recv_name != ''">delivery_recv_name = #{delivery_recv_name},</if>
<if test="delivery_recv_phone != null and delivery_recv_phone != ''">delivery_recv_phone = #{delivery_recv_phone},</if>
<if test="delivery_invoice_no != null and delivery_invoice_no != ''">delivery_invoice_no = #{delivery_invoice_no},</if>
<if test="delivery_company != null and delivery_company != ''">delivery_company = #{delivery_company},</if>
<!-- <if test="delivery_req_time != null and delivery_req_time != ''">delivery_req_time = #{delivery_req_time},</if> -->
<if test='biz_group_id != null and biz_group_id != ""'>biz_group_id = #{biz_group_id},</if>
<if test='state != null and state != ""'>state = #{state},</if>
<if test='is_doc_accept != null'>is_doc_accept = #{is_doc_accept},</if>
<if test='is_tid != null'>is_tid = #{is_tid},</if>
<if test='is_card != null'>is_card = #{is_card},</if>
<if test='is_samchip != null'>is_samchip = #{is_samchip},</if>
<if test='is_comm_open != null'>is_comm_open = #{is_comm_open},</if>
<if test='is_shipping != null'>is_shipping = #{is_shipping},</if>
<if test='is_tested != null'>is_tested = #{is_tested},</if>
<if test='is_parcel != null'>is_parcel = #{is_parcel},</if>
<if test='goods_list_id != null and goods_list_id != ""'>goods_list_id = #{goods_list_id},</if>
<if test='delivery_address != null and delivery_address != ""'>delivery_address = #{delivery_address},</if>
<if test='delivery_recv_name != null and delivery_recv_name != ""'>delivery_recv_name = #{delivery_recv_name},</if>
<if test='delivery_recv_phone != null and delivery_recv_phone != ""'>delivery_recv_phone = #{delivery_recv_phone},</if>
<if test='delivery_invoice_no != null and delivery_invoice_no != ""'>delivery_invoice_no = #{delivery_invoice_no},</if>
<if test='delivery_company != null and delivery_company != ""'>delivery_company = #{delivery_company},</if>
<!-- <if test='delivery_req_time != null and delivery_req_time != ""'>delivery_req_time = #{delivery_req_time},</if> -->
</set>
WHERE order_id = #{order_id}
</update>
@@ -12,7 +12,7 @@
<select id="selectResourceBoard" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -21,19 +21,19 @@
</choose>
FROM resource_board AS RB
WHERE state != 2
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(reg_time) &lt;= #{date_end}
</if>
<if test="title != null and title != ''">
<if test='title != null and title != ""'>
AND title like CONCAT(#{title}, '%')
</if>
<if test="content != null and content != ''">
<if test='content != null and content != ""'>
AND content like CONCAT(#{content}, '%')
</if>
<if test="isCount == false">
<if test='isCount == false'>
ORDER BY resource_board_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -52,14 +52,14 @@
<update id="updateResourceBoard">
UPDATE resource_board
<set>
<if test="title != null and title != ''">title = #{title},</if>
<if test="content != null and content != ''">content = #{content},</if>
<if test='title != null and title != ""'>title = #{title},</if>
<if test='content != null and content != ""'>content = #{content},</if>
</set>
WHERE resource_board_id = #{resource_board_id}
</update>
<update id="changeStateResourceBoard">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE resource_board
SET state = #{state}
WHERE resource_board_id IN
@@ -70,7 +70,7 @@
</update>
<!--
<delete id="deleteResourceBoard">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
DELETE FROM resource_board
WHERE resource_board_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
@@ -3,10 +3,39 @@
<mapper namespace="com.handong.smartservice.mapper.TerminalMapper">
<select id="selectUid1" resultType="map">
WITH target_group AS (
WITH RECURSIVE group_tree AS (
SELECT
BG1.biz_group_id,
1 AS depth
FROM biz_group BG1
WHERE BG1.state != 2 AND BG1.biz_group_id = #{biz_group_id}
UNION ALL
SELECT
BG2.biz_group_id,
GT.depth + 1
FROM biz_group BG2
INNER JOIN group_tree GT ON BG2.pid = GT.biz_group_id
WHERE BG2.state != 2 AND GT.depth &lt; 10
)
SELECT biz_group_id
FROM group_tree
)
SELECT T.name, T.uid1
FROM terminal AS T
JOIN terminal_biz_group AS TBG ON TBG.terminal_id = T.terminal_id
JOIN biz_group AS BG ON BG.biz_group_id = TBG.biz_group_id
WHERE T.state != 2 AND TBG.biz_group_id IN ( SELECT biz_group_id FROM target_group )
ORDER BY T.uid1 ASC LIMIT #{limit} OFFSET #{offset}
</select>
<select id="selectTerminal" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -17,23 +46,23 @@
JOIN terminal_biz_group AS TBG ON TBG.terminal_id = T.terminal_id
JOIN biz_group AS BG ON BG.biz_group_id = TBG.biz_group_id
WHERE T.state != 2 AND ( BG.biz_group_id = #{biz_group_id}
<if test="is_group_access == false">
<if test='is_group_access == false'>
OR BG.top_group_id = #{biz_group_id}
</if>
)
<if test="name != null and name != ''">
<if test='name != null and name != ""'>
AND T.name = #{name}
</if>
<if test="state != 0">
<if test='state != 0'>
AND T.state = #{state}
</if>
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(T.reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(T.reg_time) &lt;= #{date_end}
</if>
<if test="isCount == false and is_excel == false">
<if test='isCount == false and is_excel == false'>
ORDER BY T.terminal_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -66,14 +95,14 @@
FROM terminal
WHERE state != 2
AND ( false
<if test="name != null and name != ''">
<if test='name != null and name != ""'>
OR name = #{name}
</if>
<if test="uid1 != null and uid1 != ''">
<if test='uid1 != null and uid1 != ""'>
OR uid1 = #{uid1}
</if>
)
<if test="type != 0">
<if test='type != 0'>
AND type = #{type}
</if>
LIMIT 1
@@ -83,29 +112,29 @@
INSERT INTO terminal
<trim prefix="(" suffix=")" suffixOverrides=",">
name, uid1, gid,
<if test="state != null and state != 0">state,</if>
<if test="type != null and type != 0">type,</if>
<if test="manager_name != null and manager_name != ''">manager_name,</if>
<if test="device_id != null and device_id != 0">device_id,</if>
<if test='state != null and state != 0'>state,</if>
<if test='type != null and type != 0'>type,</if>
<if test='manager_name != null and manager_name != ""'>manager_name,</if>
<if test='device_id != null and device_id != 0'>device_id,</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{name}, #{uid1}, #{gid},
<if test="state != null and state != 0">#{state},</if>
<if test="type != null and type != 0">#{type},</if>
<if test="manager_name != null and manager_name != ''">#{manager_name},</if>
<if test="device_id != null and device_id != 0">#{device_id},</if>
<if test='state != null and state != 0'>#{state},</if>
<if test='type != null and type != 0'>#{type},</if>
<if test='manager_name != null and manager_name != ""'>#{manager_name},</if>
<if test='device_id != null and device_id != 0'>#{device_id},</if>
</trim>
</insert>
<update id="updateTerminal">
UPDATE terminal
<set>
<if test="name != null and name != ''">name = #{name},</if>
<if test="uid1 != null and uid1 != ''">uid1 = #{uid1},</if>
<if test="type != 0">type = #{type},</if>
<if test="manager_name != null and manager_name != ''">manager_name = #{manager_name},</if>
<if test="gid != 0">gid = #{gid},</if>
<if test='name != null and name != ""'>name = #{name},</if>
<if test='uid1 != null and uid1 != ""'>uid1 = #{uid1},</if>
<if test='type != 0'>type = #{type},</if>
<if test='manager_name != null and manager_name != ""'>manager_name = #{manager_name},</if>
<if test='gid != 0'>gid = #{gid},</if>
</set>
WHERE terminal_id = #{terminal_id}
</update>
@@ -127,7 +156,7 @@
</update>
<update id="changeStateTerminals">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE terminal
SET state = #{state}
WHERE terminal_id IN
@@ -139,7 +168,7 @@
<delete id="deleteTerminal">
<!--
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
DELETE FROM terminal
WHERE terminal_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
@@ -187,10 +216,10 @@
<update id="terminalState">
UPDATE terminal
<set>
<if test="state == 1">
<if test='state == 1'>
connect_time = NOW(),
</if>
<if test="state == 2">
<if test='state == 2'>
disconnect_time = NOW(),
</if>
</set>
@@ -7,11 +7,11 @@
<select id="selectTransaction" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
T.reg_time, T.order_time, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.slot, T.code, T.goods_name, T.pay_unique_num, T.order_time
T.reg_time, T.order_time, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.column_no, T.code, T.goods_name, T.pay_unique_num, T.order_time
</otherwise>
</choose>
FROM transactions AS T
@@ -19,23 +19,23 @@
JOIN terminal_biz_group TBG ON TBG.terminal_id = T2.terminal_id
JOIN biz_group AS BG ON BG.biz_group_id = TBG.biz_group_id
WHERE ( TBG.biz_group_id = #{biz_group_id}
<if test="is_group_access == false">
<if test='is_group_access == false'>
OR BG.top_group_id = #{biz_group_id}
</if>
)
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(T.reg_time) &lt;= #{date_end}
</if>
<if test="uid1 != null and uid1 != ''">
<if test='uid1 != null and uid1 != ""'>
AND T.uid1 = #{uid1}
</if>
<if test="isCount == false">
<if test='isCount == false'>
ORDER BY T.transaction_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
-->
<select id="selectTransaction" resultType="map">
<if test="is_group_access == false">
<if test='is_group_access == false'>
WITH target_group AS (
WITH RECURSIVE group_tree AS (
SELECT
@@ -59,35 +59,38 @@
</if>
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
T.reg_time, T.order_time, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.slot, T.code, T.goods_name, T.pay_unique_num, T.order_time
T.reg_time, T.order_time, D.name AS device_name, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.column_no, T.code, T.goods_name, T.pay_unique_num, T.order_time
</otherwise>
</choose>
FROM transactions AS T
JOIN device D ON T.device_id = D.device_id
WHERE
<choose>
<when test="is_group_access == false">
<when test='is_group_access == false'>
T.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</when>
<otherwise>
T.biz_group_id = #{biz_group_id}
</otherwise>
</choose>
<if test="date_start != null and date_start != ''">AND #{date_start} &lt;= DATE(T.reg_time)</if>
<if test="date_end != null and date_end != ''">AND DATE(T.reg_time) &lt;= #{date_end}</if>
<if test="uid1 != null and uid1 != ''">AND T.uid1 = #{uid1}</if>
<if test="uid1_type != null and uid1_type != 0">AND T.uid1_type = #{uid1_type}</if>
<if test="type != null and type != ''">AND T.type = #{type}</if>
<if test="amount != null and amount != 0">AND T.amount = #{amount}</if>
<if test="approval != null and approval != ''">AND T.approval = #{approval}</if>
<if test="slot != null and slot != ''">AND T.slot = #{slot}</if>
<if test="code != null and code != ''">AND T.code = #{code}</if>
<if test="goods_name != null and goods_name != ''">AND T.goods_name = #{goods_name}</if>
<if test="pay_vendor != null and pay_vendor != ''">AND T.pay_vendor = #{pay_vendor}</if>
<if test="isCount == false and is_excel == false">
<if test='date_start != null and date_start != ""'>AND #{date_start} &lt;= DATE(T.reg_time)</if>
<if test='date_end != null and date_end != ""'>AND DATE(T.reg_time) &lt;= #{date_end}</if>
<if test='device_name != null and device_name != ""'>AND D.name like CONCAT('%', #{device_name}, '%')</if>
<if test='uid1 != null and uid1 != ""'>AND T.uid1 = #{uid1}</if>
<if test='uid1_type != null and uid1_type != 0'>AND T.uid1_type = #{uid1_type}</if>
<if test='type != null and type != ""'>AND T.type = #{type}</if>
<if test='amount != null and amount != 0'>AND T.amount = #{amount}</if>
<if test='approval != null and approval != ""'>AND T.approval = #{approval}</if>
<if test='column_no != null and column_no != ""'>AND T.column_no = #{column_no}</if>
<if test='code != null and code != ""'>AND T.code = #{code}</if>
<if test='goods_name != null and goods_name != ""'>AND T.goods_name like CONCAT('%', #{goods_name}, '%')</if>
<if test='pay_name != null and pay_name != ""'>AND T.pay_name like CONCAT('%', #{pay_name}, '%')</if>
<if test='pay_vendor != null and pay_vendor != ""'>AND T.pay_vendor like CONCAT('%', #{pay_vendor}, '%')</if>
<if test='isCount == false and is_excel == false'>
ORDER BY T.transaction_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -95,30 +98,31 @@
<select id="selectTransactionBizGroup0" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
T.reg_time, T.order_time, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.slot, T.code, T.goods_name, T.pay_unique_num, T.order_time
T.reg_time, T.order_time, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.column_no, T.code, T.goods_name, T.pay_unique_num, T.order_time
</otherwise>
</choose>
FROM transactions AS T
WHERE biz_group_id = 0
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(T.reg_time) &lt;= #{date_end}
</if>
<if test="date_start != null and date_start != ''">AND #{date_start} &lt;= DATE(T.reg_time)</if>
<if test="date_end != null and date_end != ''">AND DATE(T.reg_time) &lt;= #{date_end}</if>
<if test="uid1 != null and uid1 != ''">AND T.uid1 = #{uid1}</if>
<if test="uid1_type != null and uid1_type != 0">AND T.uid1_type = #{uid1_type}</if>
<if test="type != null and type != ''">AND T.type = #{type}</if>
<if test="amount != null and amount != 0">AND T.amount = #{amount}</if>
<if test="approval != null and approval != ''">AND T.approval = #{approval}</if>
<if test="slot != null and slot != ''">AND T.slot = #{slot}</if>
<if test="code != null and code != ''">AND T.code = #{code}</if>
<if test="goods_name != null and goods_name != ''">AND T.goods_name = #{goods_name}</if>
<if test="pay_vendor != null and pay_vendor != ''">AND T.pay_vendor = #{pay_vendor}</if>
<if test="isCount == false and is_excel == false">
<if test='date_start != null and date_start != ""'>AND #{date_start} &lt;= DATE(T.reg_time)</if>
<if test='date_end != null and date_end != ""'>AND DATE(T.reg_time) &lt;= #{date_end}</if>
<if test='uid1 != null and uid1 != ""'>AND T.uid1 = #{uid1}</if>
<if test='uid1_type != null and uid1_type != 0'>AND T.uid1_type = #{uid1_type}</if>
<if test='type != null and type != ""'>AND T.type = #{type}</if>
<if test='amount != null and amount != 0'>AND T.amount = #{amount}</if>
<if test='approval != null and approval != ""'>AND T.approval = #{approval}</if>
<if test='column_no != null and column_no != ""'>AND T.column_no = #{column_no}</if>
<if test='code != null and code != ""'>AND T.code = #{code}</if>
<if test='goods_name != null and goods_name != ""'>AND T.goods_name like CONCAT('%', #{goods_name}, '%')</if>
<if test='pay_name != null and pay_name != ""'>AND T.pay_name like CONCAT('%', #{pay_name}, '%')</if>
<if test='pay_vendor != null and pay_vendor != ""'>AND T.pay_vendor like CONCAT('%', #{pay_vendor}, '%')</if>
<if test='isCount == false and is_excel == false'>
ORDER BY T.transaction_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -127,7 +131,7 @@
<select id="selectTransaction3" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -152,24 +156,170 @@
JOIN device_biz_group DBG ON DBG.device_id = D.device_id
JOIN biz_group AS BG ON BG.biz_group_id = DBG.biz_group_id
WHERE ( DBG.biz_group_id = #{biz_group_id}
<if test="is_group_access == false">
<if test='is_group_access == false'>
OR BG.top_group_id = #{biz_group_id}
</if>
)
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(T.reg_time) &lt;= #{date_end}
</if>
<if test="uid1 != null and uid1 != ''">
<if test='uid1 != null and uid1 != ""'>
AND TER.uid1 = #{uid1}
</if>
GROUP BY DATE_FORMAT(STR_TO_DATE(T.order_time, '%y%m%d%H%i%s'), '%Y-%m-%d'), D.name, TER.uid1
<if test="isCount == false">
<if test='isCount == false'>
ORDER BY date, D.name;
</if>
</select>
-->
<select id="selectTransaction3" resultType="map">
<if test="is_group_access == false">
<if test='is_group_access == false'>
WITH target_group AS (
WITH RECURSIVE group_tree AS (
SELECT
BG1.biz_group_id,
1 AS depth
FROM biz_group BG1
WHERE BG1.state != 2 AND BG1.biz_group_id = #{biz_group_id}
UNION ALL
SELECT
BG2.biz_group_id,
GT.depth + 1
FROM biz_group BG2
INNER JOIN group_tree GT ON BG2.pid = GT.biz_group_id
WHERE BG2.state != 2 AND GT.depth &lt; 10
)
SELECT biz_group_id
FROM group_tree
)
</if>
<choose>
<when test='isCount == true'>
SELECT COUNT(*) AS total_count
FROM (
SELECT 1
</when>
<otherwise>
SELECT
<choose>
<when test='date_type == 2'>DATE_FORMAT(T.reg_time, '%Y-%m')</when>
<otherwise>DATE_FORMAT(T.reg_time, '%Y-%m-%d')</otherwise>
</choose> AS date,
<if test='query_uid1 == true'>
D.name AS device_name, T.uid1 AS uid1,
</if>
/* 카드 */
COUNT(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('D1','D4','I1','I4')</when>
<when test='approval_type == 1'>T.type IN ('D1','I1')</when>
<when test='approval_type == 2'>T.type IN ('D4','I4')</when>
</choose>
THEN 1 END) AS card_count,
SUM(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('D1','D4','I1','I4')</when>
<when test='approval_type == 1'>T.type IN ('D1','I1')</when>
<when test='approval_type == 2'>T.type IN ('D4','I4')</when>
</choose>
THEN T.amount ELSE 0 END) AS card_amount,
/* 현금 */
COUNT(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('B1','B4')</when>
<when test='approval_type == 1'>T.type IN ('B1')</when>
<when test='approval_type == 2'>T.type IN ('B4')</when>
</choose>
THEN 1 END) AS cash_count,
SUM(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('B1','B4')</when>
<when test='approval_type == 1'>T.type IN ('B1')</when>
<when test='approval_type == 2'>T.type IN ('B4')</when>
</choose>
THEN T.amount ELSE 0 END) AS cash_amount,
/* T머니 */
COUNT(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('TM1','TM4')</when>
<when test='approval_type == 1'>T.type IN ('TM1')</when>
<when test='approval_type == 2'>T.type IN ('TM4')</when>
</choose>
THEN 1 END) AS tmoney_count,
SUM(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('TM1','TM4')</when>
<when test='approval_type == 1'>T.type IN ('TM1')</when>
<when test='approval_type == 2'>T.type IN ('TM4')</when>
</choose>
THEN T.amount ELSE 0 END) AS tmoney_amount,
/* 캐시비 */
COUNT(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('EB1','EB4')</when>
<when test='approval_type == 1'>T.type IN ('EB1')</when>
<when test='approval_type == 2'>T.type IN ('EB4')</when>
</choose>
THEN 1 END) AS cbee_count,
SUM(CASE WHEN
<choose>
<when test='approval_type == 0'>T.type IN ('EB1','EB4')</when>
<when test='approval_type == 1'>T.type IN ('EB1')</when>
<when test='approval_type == 2'>T.type IN ('EB4')</when>
</choose>
THEN T.amount ELSE 0 END) AS cbee_amount,
/* 합계 */
(
SUM(CASE WHEN T.type IN ('D1','D4','I1','I4') THEN T.amount ELSE 0 END) +
SUM(CASE WHEN T.type IN ('B1','B4') THEN T.amount ELSE 0 END) +
SUM(CASE WHEN T.type IN ('TM1','TM4') THEN T.amount ELSE 0 END) +
SUM(CASE WHEN T.type IN ('EB1','EB4') THEN T.amount ELSE 0 END)
) AS total
</otherwise>
</choose>
FROM transactions AS T
JOIN device D ON D.device_id = T.device_id
WHERE
<choose>
<when test='is_group_access == false'>
T.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</when>
<otherwise>
T.biz_group_id = #{biz_group_id}
</otherwise>
</choose>
<if test='date_start != null and date_start != ""'>AND #{date_start} &lt;= DATE(T.reg_time)</if>
<if test='date_end != null and date_end != ""'>AND DATE(T.reg_time) &lt;= #{date_end}</if>
<if test='device_name != null and device_name != ""'>AND D.name like CONCAT('%', #{device_name}, '%')</if>
<if test='uid1 != null and uid1 != ""'>AND T.uid1 = #{uid1}</if>
GROUP BY
<choose>
<when test='date_type == 2'>DATE_FORMAT(T.reg_time, '%Y-%m')</when>
<otherwise>DATE_FORMAT(T.reg_time, '%Y-%m-%d')</otherwise>
</choose>
<if test='query_uid1 == true'>, D.name, T.uid1</if>
<choose>
<when test='isCount == true'>
HAVING COUNT(CASE WHEN T.type IN ('D1','D4','I1','I4','B1','B4','TM1','TM4','EB1','EB4') THEN 1 END) != 0
) AS counted
</when>
<otherwise>
<if test='isCount == false and is_excel == false'>
HAVING card_count != 0 OR cash_count != 0 OR tmoney_count != 0 OR cbee_count != 0
ORDER BY date DESC LIMIT #{limit} OFFSET #{offset}
</if>
</otherwise>
</choose>
</select>
<select id="selectTransactionSum" resultType="map">
<if test='is_group_access == false'>
WITH target_group AS (
WITH RECURSIVE group_tree AS (
SELECT
@@ -192,162 +342,84 @@
)
</if>
SELECT
<choose>
<when test="date_type == 2">DATE_FORMAT(T.reg_time, '%Y-%m')</when>
<otherwise>DATE_FORMAT(T.reg_time, '%Y-%m-%d')</otherwise>
</choose> AS date,
D.name AS device_name,
T.uid1 AS uid1,
/* 카드 */
COUNT(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('D1','D4','I1','I4')</when>
<when test="approval_type == 1">T.type IN ('D1','I1')</when>
<when test="approval_type == 2">T.type IN ('D4','I4')</when>
</choose>
THEN 1 END) AS card_count,
SUM(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('D1','D4','I1','I4')</when>
<when test="approval_type == 1">T.type IN ('D1','I1')</when>
<when test="approval_type == 2">T.type IN ('D4','I4')</when>
</choose>
THEN T.amount ELSE 0 END) AS card_amount,
SUM(T.type IN ('D1','D4','I1','I4')) AS card_count,
IFNULL(SUM(CASE WHEN T.type IN ('D1','D4','I1','I4') THEN T.amount ELSE 0 END), 0) AS card_amount,
/* 현금 */
COUNT(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('B1','B4')</when>
<when test="approval_type == 1">T.type IN ('B1')</when>
<when test="approval_type == 2">T.type IN ('B4')</when>
</choose>
THEN 1 END) AS cash_count,
SUM(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('B1','B4')</when>
<when test="approval_type == 1">T.type IN ('B1')</when>
<when test="approval_type == 2">T.type IN ('B4')</when>
</choose>
THEN T.amount ELSE 0 END) AS cash_amount,
SUM(T.type IN ('B1','B4')) AS cash_count,
IFNULL(SUM(CASE WHEN T.type IN ('B1','B4') THEN T.amount ELSE 0 END), 0) AS cash_amount,
/* T머니 */
COUNT(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('TM1','TM4')</when>
<when test="approval_type == 1">T.type IN ('TM1')</when>
<when test="approval_type == 2">T.type IN ('TM4')</when>
</choose>
THEN 1 END) AS tmoney_count,
SUM(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('TM1','TM4')</when>
<when test="approval_type == 1">T.type IN ('TM1')</when>
<when test="approval_type == 2">T.type IN ('TM4')</when>
</choose>
THEN T.amount ELSE 0 END) AS tmoney_amount,
SUM(T.type IN ('TM1','TM4')) AS tmoney_count,
IFNULL(SUM(CASE WHEN T.type IN ('TM1','TM4') THEN T.amount ELSE 0 END), 0) AS tmoney_amount,
/* 캐시비 */
COUNT(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('EB1','EB4')</when>
<when test="approval_type == 1">T.type IN ('EB1')</when>
<when test="approval_type == 2">T.type IN ('EB4')</when>
</choose>
THEN 1 END) AS cbee_count,
SUM(CASE
WHEN
<choose>
<when test="approval_type == 0">T.type IN ('EB1','EB4')</when>
<when test="approval_type == 1">T.type IN ('EB1')</when>
<when test="approval_type == 2">T.type IN ('EB4')</when>
</choose>
THEN T.amount ELSE 0 END) AS cbee_amount,
SUM(T.type IN ('EB1','EB4')) AS cbee_count,
IFNULL(SUM(CASE WHEN T.type IN ('EB1','EB4') THEN T.amount ELSE 0 END), 0) AS cbee_amount,
/* 합계 */
(
SUM(CASE WHEN T.type IN ('D1','D4','I1','I4') THEN T.amount ELSE 0 END) +
SUM(CASE WHEN T.type IN ('B1','B4') THEN T.amount ELSE 0 END) +
SUM(CASE WHEN T.type IN ('TM1','TM4') THEN T.amount ELSE 0 END) +
SUM(CASE WHEN T.type IN ('EB1','EB4') THEN T.amount ELSE 0 END)
IFNULL(SUM(CASE WHEN T.type IN ('D1','D4','I1','I4') THEN T.amount ELSE 0 END), 0) +
IFNULL(SUM(CASE WHEN T.type IN ('B1','B4') THEN T.amount ELSE 0 END), 0) +
IFNULL(SUM(CASE WHEN T.type IN ('TM1','TM4') THEN T.amount ELSE 0 END), 0) +
IFNULL(SUM(CASE WHEN T.type IN ('EB1','EB4') THEN T.amount ELSE 0 END), 0)
) AS total
FROM transactions AS T
JOIN device D ON D.device_id = T.device_id
WHERE
<choose>
<when test="is_group_access == false">
<when test='is_group_access == false'>
T.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</when>
<otherwise>
T.biz_group_id = #{biz_group_id}
</otherwise>
</choose>
<if test="date_start != null and date_start != ''">AND #{date_start} &lt;= DATE(T.reg_time)</if>
<if test="date_end != null and date_end != ''">AND DATE(T.reg_time) &lt;= #{date_end}</if>
GROUP BY
<choose>
<when test="date_type == 2">DATE_FORMAT(T.reg_time, '%Y-%m')</when>
<otherwise>DATE_FORMAT(T.reg_time, '%Y-%m-%d')</otherwise>
</choose>,
D.name,
T.uid1
<if test='date_start != null and date_start != ""'>AND #{date_start} &lt;= DATE(T.reg_time)</if>
<if test='date_end != null and date_end != ""'>AND DATE(T.reg_time) &lt;= #{date_end}</if>
HAVING card_count != 0 OR cash_count != 0 OR tmoney_count != 0 OR cbee_count != 0
ORDER BY
date DESC
</select>
<insert id="insertTransaction">
INSERT INTO transactions
<trim prefix="(" suffix=")" suffixOverrides=",">
reg_time, process,
<if test="biz_group_id != null">biz_group_id,</if>
<if test="device_id != null">device_id,</if>
<if test="uid1 != null and uid1 != ''">uid1,</if>
<if test="uid1_type != null and uid1_type != 0">uid1_type,</if>
<if test="order_time != null and order_time != ''">order_time,</if>
<if test="type != null and type != ''">type,</if>
<if test="amount != null and amount != 0">amount,</if>
<if test="approval != null and approval != ''">approval,</if>
<if test="pay_unique_num != null and pay_unique_num != ''">pay_unique_num,</if>
<if test="slot != null and slot != ''">slot,</if>
<if test="code != null and code != ''">code,</if>
<if test="goods_name != null and goods_name != ''">goods_name,</if>
<if test="price != null and price != 0">price,</if>
<if test="pay_name != null and pay_name != ''">pay_name,</if>
<if test="pay_vendor != null and pay_vendor != ''">pay_vendor</if>
<if test='biz_group_id != null'>biz_group_id,</if>
<if test='device_id != null'>device_id,</if>
<if test='uid1 != null and uid1 != ""'>uid1,</if>
<if test='uid1_type != null and uid1_type != 0'>uid1_type,</if>
<if test='order_time != null and order_time != ""'>order_time,</if>
<if test='type != null and type != ""'>type,</if>
<if test='amount != null and amount != 0'>amount,</if>
<if test='approval != null and approval != ""'>approval,</if>
<if test='pay_unique_num != null and pay_unique_num != ""'>pay_unique_num,</if>
<if test='column_no != null and column_no != ""'>column_no,</if>
<if test='code != null and code != ""'>code,</if>
<if test='goods_name != null and goods_name != ""'>goods_name,</if>
<if test='price != null and price != 0'>price,</if>
<if test='pay_name != null and pay_name != ""'>pay_name,</if>
<if test='pay_vendor != null and pay_vendor != ""'>pay_vendor</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
NOW(), 1,
<if test="biz_group_id != null">#{biz_group_id},</if>
<if test="device_id != null">#{device_id},</if>
<if test="uid1 != null and uid1 != ''">#{uid1},</if>
<if test="uid1_type != null and uid1_type != 0">#{uid1_type},</if>
<if test="order_time != null and order_time != ''">#{order_time},</if>
<if test="type != null and type != ''">#{type},</if>
<if test="amount != null and amount != 0">#{amount},</if>
<if test="approval != null and approval != ''">#{approval},</if>
<if test="pay_unique_num != null and pay_unique_num != ''">#{pay_unique_num},</if>
<if test="slot != null and slot != ''">#{slot},</if>
<if test="code != null and code != ''">#{code},</if>
<if test="goods_name != null and goods_name != ''">#{goods_name},</if>
<if test="price != null and price != 0">#{price},</if>
<if test="pay_name != null and pay_name != ''">#{pay_name},</if>
<if test="pay_vendor != null and pay_vendor != ''">#{pay_vendor}</if>
<if test='biz_group_id != null'>#{biz_group_id},</if>
<if test='device_id != null'>#{device_id},</if>
<if test='uid1 != null and uid1 != ""'>#{uid1},</if>
<if test='uid1_type != null and uid1_type != 0'>#{uid1_type},</if>
<if test='order_time != null and order_time != ""'>#{order_time},</if>
<if test='type != null and type != ""'>#{type},</if>
<if test='amount != null and amount != 0'>#{amount},</if>
<if test='approval != null and approval != ""'>#{approval},</if>
<if test='pay_unique_num != null and pay_unique_num != ""'>#{pay_unique_num},</if>
<if test='column_no != null and column_no != ""'>#{column_no},</if>
<if test='code != null and code != ""'>#{code},</if>
<if test='goods_name != null and goods_name != ""'>#{goods_name},</if>
<if test='price != null and price != 0'>#{price},</if>
<if test='pay_name != null and pay_name != ""'>#{pay_name},</if>
<if test='pay_vendor != null and pay_vendor != ""'>#{pay_vendor}</if>
</trim>
</insert>
</mapper>
@@ -12,7 +12,7 @@
<select id="selectVoc" resultType="map">
SELECT
<choose>
<when test="isCount == true">
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
@@ -21,19 +21,19 @@
</choose>
FROM voc AS RB
WHERE state != 2
<if test="date_start != null and date_start != ''">
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(reg_time)
</if>
<if test="date_end != null and date_end != ''">
<if test='date_end != null and date_end != ""'>
AND DATE(reg_time) &lt;= #{date_end}
</if>
<if test="title != null and title != ''">
<if test='title != null and title != ""'>
AND title like CONCAT(#{title}, '%')
</if>
<if test="content != null and content != ''">
<if test='content != null and content != ""'>
AND content like CONCAT(#{content}, '%')
</if>
<if test="isCount == false">
<if test='isCount == false'>
ORDER BY voc_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -52,14 +52,14 @@
<update id="updateVoc">
UPDATE voc
<set>
<if test="title != null and title != ''">title = #{title},</if>
<if test="content != null and content != ''">content = #{content},</if>
<if test='title != null and title != ""'>title = #{title},</if>
<if test='content != null and content != ""'>content = #{content},</if>
</set>
WHERE voc_id = #{voc_id}
</update>
<update id="changeStateVoc">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
UPDATE voc
SET state = #{state}
WHERE voc_id IN
@@ -70,7 +70,7 @@
</update>
<!--
<delete id="deleteVoc">
<if test="ids != null and ids.size > 0">
<if test='ids != null and ids.size > 0'>
DELETE FROM voc
WHERE voc IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
+476 -485
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -24,10 +24,13 @@
"axios": "^1.6.0",
"express": "^5.1.0",
"flatpickr": "^4.6.13",
"headlessui": "^0.0.0",
"html-to-image": "^1.11.13",
"http-proxy-middleware": "^3.0.5",
"jwt-decode": "^4.0.0",
"morgan": "^1.10.1",
"next": "^15.5.6",
"pretendard": "^1.3.9",
"rc-tree": "^5.13.1",
"react": "^19.0.0",
"react-apexcharts": "^1.7.0",
@@ -47,6 +50,7 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react-transition-group": "^4.4.12",
"baseline-browser-mapping": "^2.10.40",
"eslint": "^9",
"eslint-config-next": "15.1.3",
"postcss": "^8",
@@ -11,7 +11,7 @@ import Badge from "@/components/ui/badge/Badge";
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime2, convertDateTime3, postFileDownload, useAuthStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime2, convertDateTime3, postFileDownload, todayYMD, useAuthStore } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyAccountModal, { AccountModalProps } from './AddModifyAccountModal';
@@ -19,10 +19,12 @@ import { useMultiState } from "@/hooks/useMultiState";
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, addNodeByKey, deleteNodeByKey } from "@/components/CtTree";
import { reqBizGroupTree2 } from "@/app/(admin)/biz-group/BizGroupContent";
import Select from "@/components/form/Select2";
import PageCountSelector from "@/components/PageCountSelector";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -33,6 +35,8 @@ export default function Account() {
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
@@ -45,12 +49,14 @@ export default function Account() {
const [ user_id, setUserId ] = useState<string>("");
const [ email, setEmail ] = useState<string>("");
const [ nick_name, setNickName ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>();
const [ date_end, setDateEnd ] = useState<string>();
// modal
const { isOpen, openModal, closeModal } = useModal();
const modalData = useMultiState<AccountModalProps>({biz_group_name: "", isModify: false, gid: "", biz_group_id: "", user_id: "", user_pw: "", nick_name: "", email: "", state: "1"});
const modalData = useMultiState<AccountModalProps>({ biz_group_name: "", isModify: false,
gid: "", biz_group_id: "", user_id: "", user_pw: "", name: "", phone: "", email: "", state: "1",
perm_group: true, perm_uid1: true, perm_cancel: true, perm_account: true });
//function part
//
@@ -84,6 +90,13 @@ export default function Account() {
setTableData([]);
return;
}
resp.data.result.list.forEach((item: any) => {
item.perm_group = (item.permission & 0x2) === 0x2;
item.perm_uid1 = (item.permission & 0x4) === 0x4;
item.perm_cancel = (item.permission & 0x8) === 0x8;
});
setTableTotalCount(resp.data.result.totalCount);
setTableData(resp.data.result.list);
}
@@ -117,17 +130,17 @@ export default function Account() {
// event processing part
//
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -157,7 +170,7 @@ export default function Account() {
const node = findNodeByKey(treeData, selectedTreeKeys[0]);
modalData.setAll({biz_group_name: node.name, biz_reg_num: node.biz_reg_num,
isModify: false, gid: "", user_id: "", user_pw: "", nick_name: "", email: "", state: "1", biz_group_id: node.key});
isModify: false, gid: "", user_id: "", user_pw: "", name: "", phone: "", email: "", state: "1", biz_group_id: node.key});
openModal();
};
@@ -210,18 +223,25 @@ export default function Account() {
title: "등록일",
key: "reg_time" ,
renderItem: (item:any) => convertDateTime3(item.reg_time),
viewMobile: true,
},
{
title: "그룹",
key: "biz_group_name",
viewMobile: true,
},
{
title: "아이디",
key: "user_id",
viewMobile: true,
},
{
title: "닉네임",
key: "nick_name",
title: "이름",
key: "name",
},
{
title: "휴대폰번호",
key: "phone",
},
{
title: "이메일",
@@ -270,11 +290,11 @@ export default function Account() {
<div className="flex-1 space-y-6">
{/*<div className="hidden sm:block h-[86px]"></div>*/}
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="그룹(사업자명)" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="조회할 그룹(사업자명) 입력하세요." value={name} onChange={(e) => setName(e.target.value)}
<WithLabel label="그룹(사업자)명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 그룹(사업자)명 입력하세요." value={name} onChange={(e) => setName(e.target.value)}
onKeyDown={(e) => {if (e.key === "Enter") handleClickGroupSearch()}} />
</WithLabel>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 사업자번호를 입력하세요." value={biz_reg_num} onChange={(e) => setBizRegNum(e.target.value)}
onKeyDown={(e) => {if (e.key === "Enter") handleClickGroupSearch()}} />
</WithLabel>
@@ -304,28 +324,30 @@ export default function Account() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="아이디" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="아이디" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 아이디를 입력하세요." value={user_id} onChange={(e) => setUserId(e.target.value)} />
</WithLabel>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="email" placeholder="조회할 이메일을 입력하세요." value={email} onChange={(e) => setEmail(e.target.value)} />
</WithLabel>
<WithLabel label="닉네임" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="닉네임" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 닉네임을 입력하세요." value={nick_name} onChange={(e) => setNickName(e.target.value)} />
</WithLabel>
</div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -336,6 +358,10 @@ export default function Account() {
</div>
</div>
<div className="flex items-center justify-end gap-5">
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
<CtTable1 columns={columns} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
onClickPageChange={handlePageChange} />
@@ -5,7 +5,8 @@ import Label from '@/components/form/Label2';
import Input from '@/components/form/input/InputField2';
import Select from '@/components/form/Select2';
import { useMultiState } from "@/hooks/useMultiState";
import api from '@/lib/_AG';
import api, { useAuthStore } from '@/lib/_AG';
import Checkbox from "@/components/form/input/Checkbox";
@@ -18,9 +19,14 @@ export interface AccountModalProps {
biz_group_id: string;
user_id: string;
user_pw: string;
nick_name: string;
name: string;
phone: string;
email: string;
state: string;
perm_group: boolean;
perm_uid1: boolean;
perm_cancel: boolean;
perm_account: boolean;
}
@@ -32,7 +38,11 @@ interface AddModifyAccountModalProps {
}
export default function AddModifyAccountModal({ multiState, onOk, isOpen, closeModal }: AddModifyAccountModalProps) {
const tokenPayload = useAuthStore((s) => s.tokenPayload); //Bruce, JWT
const [ user_pw_confirm, setUserPwConfirm ] = useState<string>("");
const handleClickAddOrModify = () => {
if (multiState.values.user_id == "") {
alert("계정 아이디를 입력하셔야 합니다.");
@@ -42,6 +52,22 @@ export default function AddModifyAccountModal({ multiState, onOk, isOpen, closeM
alert("계정 비밀번호를 입력하셔야 합니다.");
return;
}
else if (user_pw_confirm == "") {
alert("비밀번호 확인을 입력하셔야 합니다.");
return;
}
else if (multiState.values.user_pw !== user_pw_confirm) {
alert("비밀번호 확인이 일치하지 않습니다.");
return;
}
else if (multiState.values.name == "") {
alert("이름 입력하셔야 합니다.");
return;
}
else if (multiState.values.phone == "") {
alert("휴대폰 번호를 입력하셔야 합니다.");
return;
}
if (multiState.values.isModify) {
api.post('/api/modify-account.do', multiState.values).then((resp) => {
@@ -87,7 +113,7 @@ export default function AddModifyAccountModal({ multiState, onOk, isOpen, closeM
>
<div>
<Label></Label>
<Input type="text" value={multiState.values.biz_group_name + "(" + multiState.values.biz_reg_num + ")"} disabled />
<Input type="text" value={multiState.values.biz_group_name + (multiState.values.biz_reg_num ? `(${multiState.values.biz_reg_num})` : "")} disabled />
</div>
<div>
<Label redPoint></Label>
@@ -95,16 +121,33 @@ export default function AddModifyAccountModal({ multiState, onOk, isOpen, closeM
</div>
<div>
<Label redPoint></Label>
<Input type="password" value={multiState.values.user_pw} onChange={(e) => multiState.set("user_pw", e.target.value)} />
<Input type="password" defaultValue="" onChange={(e) => multiState.set("user_pw", e.target.value)} />
</div>
<div>
<Label></Label>
<Input type="text" value={multiState.values.nick_name} onChange={(e) => multiState.set("nick_name", e.target.value)} />
<Label redPoint> </Label>
<Input type="password" value={user_pw_confirm} onChange={(e) => setUserPwConfirm(e.target.value)} />
</div>
<div>
<Label redPoint></Label>
<Input type="text" value={multiState.values.name} onChange={(e) => multiState.set("name", e.target.value)} />
</div>
<div>
<Label redPoint></Label>
<Input type="text" value={multiState.values.phone} onChange={(e) => multiState.set("phone", e.target.value)} />
</div>
<div>
<Label></Label>
<Input type="email" value={multiState.values.email} onChange={(e) => multiState.set("email", e.target.value)} />
</div>
<div>
<Label> </Label>
<div className="flex items-center gap-5">
<Checkbox checked={multiState.values.perm_group} onChange={(value) => multiState.set("perm_group", value)} label="그룹변경" />
<Checkbox checked={multiState.values.perm_uid1} onChange={(value) => multiState.set("perm_uid1", value)} label="TID변경" />
<Checkbox checked={multiState.values.perm_cancel} onChange={(value) => multiState.set("perm_cancel", value)} label="카드승인취소" />
<Checkbox checked={multiState.values.perm_account} onChange={(value) => multiState.set("perm_account", value)} label="계정관리" />
</div>
</div>
<div>
<Label></Label>
<Select
@@ -113,7 +156,7 @@ export default function AddModifyAccountModal({ multiState, onOk, isOpen, closeM
{ label: "정상", value: "1" },
{ label: "정지", value: "4" },
]}
defaultValue={multiState.values.state} onChange={(value) => multiState.set("state", value)}
defaultValue={multiState.values.state} onChange={(e) => multiState.set("state", e.target.value)}
className="dark:bg-dark-900" />
</div>
</CtModal>
@@ -4,7 +4,7 @@ import Label from '@/components/form/Label2';
import Input from '@/components/form/input/InputField2';
import CtModal from "@/components/CtModal";
import { useMultiState } from "@/hooks/useMultiState";
import api, { formatBusinessNumber } from '@/lib/_AG';
import api, { formatBusinessNumber, isValidBusinessNumber } from '@/lib/_AG';
export interface BizGroupModalProps {
@@ -30,13 +30,17 @@ export default function AddModifyBizGroupModal({ multiState, onOk, isOpen, close
const handleClickAddOrModify = () => {
if (multiState.values.name == "") {
alert("그룹(사업자명)을 입력하셔야 합니다.");
alert("그룹(사업자)명을 입력하셔야 합니다.");
return;
}
//else if (multiState.values.biz_reg_num == "") {
// alert("사업자등록번호를 입력하셔야 합니다.");
// return;
//}
if (multiState.values.biz_reg_num != "" && !isValidBusinessNumber(multiState.values.biz_reg_num)) {
if (!confirm("잘못된 형식의 사업자등록번호입니다. 그래도 등록하시겠습니까?"))
return;
}
if (multiState.values.isModify) {
api.post('/api/modify-biz-group.do', multiState.values).then((resp) => {
@@ -96,7 +100,7 @@ export default function AddModifyBizGroupModal({ multiState, onOk, isOpen, close
className="max-w-[700px] p-6 lg:p-10"
>
<div>
<Label redPoint>()</Label>
<Label redPoint>()</Label>
<Input type="text" value={multiState.values.name} onChange={(e) => multiState.set("name", e.target.value)} />
</div>
<div>
@@ -9,7 +9,7 @@ import Input from '@/components/form/input/InputField2';
import DatePicker from '@/components/form/date-picker2';
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime3, formatBusinessNumber, useAuthStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, formatBusinessNumber, isValidBusinessNumber, todayYMD, useAuthStore } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyBizGroupModal, { BizGroupModalProps } from './AddModifyBizGroupModal';
@@ -19,7 +19,7 @@ import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParent
import { tree } from "next/dist/build/templates/app-page";
import { useRouter } from "next/router";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
// api component
@@ -126,22 +126,22 @@ export default function BizGroupContent({
}: BizGroupContentProps) {
const tokenPayload = useAuthStore((s) => s.tokenPayload); //Bruce, JWT
const {isOpen, openModal, closeModal} = useModal();
const { isOpen, openModal, closeModal } = useModal();
// tree part
const [treeData, setTreeData] = useState<CtTreeNode[]>(preloadTreeData ? preloadTreeData : []);
const [selectedTreeKeys, setSelectedTreeKeys] = useState<Key[]>(preloadTreeData ? [preloadTreeData[0].key as string] : []);
const [expandedTreeKeys, setExpandedTreeKeys] = useState<Key[]>(preloadTreeData ? getAllNodeKeys(preloadTreeData) : []);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>(preloadTreeData ? preloadTreeData : []);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>(preloadTreeData ? [preloadTreeData[0].key as string] : []);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>(preloadTreeData ? getAllNodeKeys(preloadTreeData) : []);
// search fields
const [name, setName] = useState<string>("");
const [biz_reg_num, setBizRegNum] = useState<string>("");
const [date_start, setDateStart] = useState<string>("");
const [date_end, setDateEnd] = useState<string>("");
const [ name, setName ] = useState<string>("");
const [ biz_reg_num, setBizRegNum ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>();
const [ date_end, setDateEnd ] = useState<string>();
//
// form fields
const [formInfo, setFormInfo] = useState({name: "", biz_reg_num: "", email: "", phone: "", ceo: "", address: ""});
const [ formInfo, setFormInfo ] = useState({name: "", biz_reg_num: "", email: "", phone: "", ceo: "", address: ""});
const handleChangeFormInfo = (field: string, value?: string | number) => { setFormInfo(prev => ({ ...prev, [field]: value ?? "" })); };
// modal values
@@ -175,13 +175,17 @@ export default function BizGroupContent({
function reqModifyBizGroup(biz_group_id: Key) {
if (formInfo.name == "") {
alert("그룹(사업자명)을 입력하셔야 합니다.");
alert("그룹(사업자)명을 입력하셔야 합니다.");
return;
}
//else if (formInfo.biz_reg_num == "") {
// alert("사업자등록번호를 입력하셔야 합니다.");
// return;
//}
if (formInfo.biz_reg_num != "" && !isValidBusinessNumber(formInfo.biz_reg_num)) {
if (!confirm("잘못된 형식의 사업자등록번호입니다. 그래도 등록하시겠습니까?"))
return;
}
const params = {
biz_group_id: biz_group_id,
@@ -233,17 +237,17 @@ export default function BizGroupContent({
}
const handleClickSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -339,11 +343,11 @@ export default function BizGroupContent({
<ComponentCard title={title} titleIcon={titleIcon}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="그룹(사업자명)" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="조회할 그룹(사업자명)을 입력하세요." value={name} onChange={(e) => setName(e.target.value)}
<WithLabel label="그룹(사업자)명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 그룹(사업자)명을 입력하세요." value={name} onChange={(e) => setName(e.target.value)}
onKeyDown={(e) => {if (e.key === "Enter") handleClickSearch()}} />
</WithLabel>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 사업자번호를 입력하세요." value={biz_reg_num} onChange={(e) => handleChangeBizRegNum(e.target.value)}
onKeyDown={(e) => {if (e.key === "Enter") handleClickSearch()}} />
</WithLabel>
@@ -353,17 +357,19 @@ export default function BizGroupContent({
</div>
{/*
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -399,9 +405,9 @@ export default function BizGroupContent({
</div>
</ComponentCard>
<div className="w-[380px]">
<div className="flex-1 space-y-6">
<div className="flex-1 space-y-4">
<div>
<Label>()</Label>
<Label>()</Label>
<Input type="text" value={formInfo.name} onChange={(e) => handleChangeFormInfo("name", e.target.value)} />
</div>
<div>
@@ -30,7 +30,7 @@ export default function AddModifyBizGroupModal({ multiState, onOk, isOpen, close
const handleClickAddOrModify = () => {
if (multiState.values.name == "") {
alert("그룹(사업자명)을 입력하셔야 합니다.");
alert("그룹(사업자)명을 입력하셔야 합니다.");
return;
}
//else if (multiState.values.biz_reg_num == "") {
@@ -80,7 +80,7 @@ export default function AddModifyBizGroupModal({ multiState, onOk, isOpen, close
className="max-w-[700px] p-6 lg:p-10"
>
<div>
<Label redPoint>()</Label>
<Label redPoint>()</Label>
<Input type="text" value={multiState.values.name} onChange={(e) => multiState.set("name", e.target.value)} />
</div>
<div>
@@ -10,17 +10,19 @@ import DatePicker from '@/components/form/date-picker2';
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime3 } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, todayYMD } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyBizGroupModal, { BizGroupModalProps } from './AddModifyBizGroupModal';
import { useMultiState } from "@/hooks/useMultiState";
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, deleteNodeByKey } from "@/components/CtTree";
import Select from "@/components/form/Select2";
import PageCountSelector from "@/components/PageCountSelector";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -29,6 +31,8 @@ export default function BizGroup() {
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
@@ -196,7 +200,7 @@ export default function BizGroup() {
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time)
},
{
title: "그룹(사업자명)",
title: "그룹(사업자)명",
key: "name",
},
{
@@ -257,36 +261,38 @@ export default function BizGroup() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="그룹(사업자명)" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="조회할 그룹(사업자명)을 입력하세요." value={name} onChange={(e) => setName(e.target.value)} />
<WithLabel label="그룹(사업자)명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 그룹(사업자)명을 입력하세요." value={name} onChange={(e) => setName(e.target.value)} />
</WithLabel>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 사업자번호를 입력하세요." value={biz_reg_num} onChange={(e) => setBizRegNum(e.target.value)} />
</WithLabel>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 이메일를 입력하세요." value={email} onChange={(e) => setEmail(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="전화번호" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="전화번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 전화번호를 입력하세요." value={phone} onChange={(e) => setPhone(e.target.value)} />
</WithLabel>
<WithLabel label="주소" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="주소" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 주소를 입력하세요." value={address} onChange={(e) => setAddress(e.target.value)} />
</WithLabel>
</div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -295,25 +301,28 @@ export default function BizGroup() {
<Button size="sm" variant="primary" onClick={handleClickSearch}></Button>
</div>
</div>
<div className="grid grid-cols-1 gap-3">
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
</div>
<div className="flex flex-col sm:flex-row gap-2">
<ComponentCard title='조직 계층도'>
<div className="min-w-[310px] w-full h-[330px] overflow-auto">
<CtTree
treeData={treeData}
selectedKeys={selectedTreeKeys}
setSelectedKeys={setSelectedTreeKeys}
expandedKeys={expandedTreeKeys}
setExpandedKeys={setExpandedTreeKeys}
onClickExpanded={handleClickTreeExpanded}
/>
</div>
<div className="flex items-center gap-5">
<Button size="sm" variant="primary" startIcon={<PlusIcon />} onClick={handleClickAdd}> <br></br> </Button>
<Button size="sm" variant="primary" startIcon={<TrashBinIcon />} onClick={handleClickDelete}><br></br></Button>
</div>
</ComponentCard>
<ComponentCard title='조직 계층도'>
<div className="min-w-[310px] w-full h-[330px] overflow-auto">
<CtTree
treeData={treeData}
selectedKeys={selectedTreeKeys}
setSelectedKeys={setSelectedTreeKeys}
expandedKeys={expandedTreeKeys}
setExpandedKeys={setExpandedTreeKeys}
onClickExpanded={handleClickTreeExpanded}
/>
</div>
<div className="flex items-center gap-5">
<Button size="sm" variant="primary" startIcon={<PlusIcon />} onClick={handleClickAdd}> <br></br> </Button>
<Button size="sm" variant="primary" startIcon={<TrashBinIcon />} onClick={handleClickDelete}><br></br></Button>
</div>
</ComponentCard>
<div className="flex-1">
<CtTable1 columns={columns} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
@@ -5,7 +5,8 @@ import Label from '@/components/form/Label2';
import Input from '@/components/form/input/InputField2';
import Select from '@/components/form/Select2';
import { useMultiState } from "@/hooks/useMultiState";
import api from '@/lib/_AG';
import api, { useAuthStore } from '@/lib/_AG';
import Checkbox from "@/components/form/input/Checkbox";
@@ -19,9 +20,14 @@ export interface CustomerAccountModalProps {
new_biz_group_id: string;
user_id: string;
user_pw: string;
nick_name: string;
name: string;
phone: string;
email: string;
state: string;
perm_group: boolean;
perm_uid1: boolean;
perm_cancel: boolean;
perm_account: boolean;
}
@@ -33,6 +39,10 @@ interface AddModifyCustomerAccountModalProps {
}
export default function AddModifyCustomerAccountModal({ multiState, onOk, isOpen, closeModal }: AddModifyCustomerAccountModalProps) {
const tokenPayload = useAuthStore((s) => s.tokenPayload); //Bruce, JWT
const [ user_pw_confirm, setUserPwConfirm ] = useState<string>("");
const handleClickAddOrModify = () => {
if (multiState.values.user_id == "") {
@@ -43,6 +53,22 @@ export default function AddModifyCustomerAccountModal({ multiState, onOk, isOpen
alert("계정 비밀번호를 입력하셔야 합니다.");
return;
}
else if (user_pw_confirm == "") {
alert("비밀번호 확인을 입력하셔야 합니다.");
return;
}
else if (multiState.values.user_pw !== user_pw_confirm) {
alert("비밀번호 확인이 일치하지 않습니다.");
return;
}
else if (multiState.values.name == "") {
alert("이름 입력하셔야 합니다.");
return;
}
else if (multiState.values.phone == "") {
alert("휴대폰 번호를 입력하셔야 합니다.");
return;
}
const { biz_group_name, biz_reg_num, ...params } = multiState.values;
@@ -90,24 +116,43 @@ export default function AddModifyCustomerAccountModal({ multiState, onOk, isOpen
>
<div>
<Label></Label>
<Input type="text" value={multiState.values.biz_group_name + "(" + multiState.values.biz_reg_num + ")"} disabled />
<Input type="text" value={multiState.values.biz_group_name + (multiState.values.biz_reg_num ? `(${multiState.values.biz_reg_num})` : "")} disabled />
</div>
<div>
<Label redPoint></Label>
<Input type="text" value={multiState.values.user_id} onChange={(e) => multiState.set("user_id", e.target.value)} disabled={multiState.values.isModify ? true : false} />
</div>
{ !multiState.values.isModify || (multiState.values.isModify && tokenPayload?.user_id === multiState.values.user_id) ? <>
<div>
<Label redPoint></Label>
<Input type="password" value={multiState.values.user_pw} onChange={(e) => multiState.set("user_pw", e.target.value)} />
<Input type="password" defaultValue="" onChange={(e) => multiState.set("user_pw", e.target.value)} />
</div>
<div>
<Label></Label>
<Input type="text" value={multiState.values.nick_name} onChange={(e) => multiState.set("nick_name", e.target.value)} />
<Label redPoint> </Label>
<Input type="password" value={user_pw_confirm} onChange={(e) => setUserPwConfirm(e.target.value)} />
</div>
</> : <></>}
<div>
<Label redPoint></Label>
<Input type="text" value={multiState.values.name} onChange={(e) => multiState.set("name", e.target.value)} />
</div>
<div>
<Label redPoint></Label>
<Input type="text" value={multiState.values.phone} onChange={(e) => multiState.set("phone", e.target.value)} />
</div>
<div>
<Label></Label>
<Input type="email" value={multiState.values.email} onChange={(e) => multiState.set("email", e.target.value)} />
</div>
<div>
<Label> </Label>
<div className="flex items-center gap-5">
<Checkbox checked={multiState.values.perm_group} onChange={(value) => multiState.set("perm_group", value)} label="그룹변경" />
<Checkbox checked={multiState.values.perm_uid1} onChange={(value) => multiState.set("perm_uid1", value)} label="TID변경" />
<Checkbox checked={multiState.values.perm_cancel} onChange={(value) => multiState.set("perm_cancel", value)} label="카드승인취소" />
<Checkbox checked={multiState.values.perm_account} onChange={(value) => multiState.set("perm_account", value)} label="계정관리" />
</div>
</div>
<div>
<Label></Label>
<Select
@@ -116,7 +161,7 @@ export default function AddModifyCustomerAccountModal({ multiState, onOk, isOpen
{ label: "정상", value: "1" },
{ label: "정지", value: "4" },
]}
defaultValue={multiState.values.state} onChange={(value) => multiState.set("state", value)}
defaultValue={multiState.values.state} onChange={(e) => multiState.set("state", e.target.value)}
className="dark:bg-dark-900" />
</div>
</CtModal>
@@ -1,10 +1,10 @@
"use client"
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
import ComponentCard from '@/components/common/ComponentCard2';
import BizGroupPanel from "@/components/common/BizGroupPanel";
import BizGroupPanel from "@/components/BizGroupPanel";
import CtTable1 from '@/components/tables/CtTable1';
import Button from '@/components/ui/button/Button2';
import { DocsIcon, TableIcon, PlusIcon, TrashBinIcon, PencilIcon } from "@/icons";
import { DocsIcon, TableIcon, PlusIcon, TrashBinIcon, PencilIcon, FilterIcon } from "@/icons";
import WithLabel from '@/components/form/WithLabel';
import Input from '@/components/form/input/InputField2';
import DatePicker from '@/components/form/date-picker2';
@@ -12,7 +12,7 @@ import Badge from "@/components/ui/badge/Badge";
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { useAuthStore, convertDateTime2, convertDateTime3, useUiLoadingStore, postFileDownload } from '@/lib/_AG';
import api, { useAuthStore, convertDateTime2, convertDateTime3, useUiLoadingStore, postFileDownload, todayYMD, addDaysYMD } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyCustomerAccountModal, { CustomerAccountModalProps } from './AddModifyCustomerAccountModal';
@@ -21,10 +21,14 @@ import CtTree, { CtTreeNode, findNodeByKey, findRootNodeByKey, treeToList } from
import { reqBizGroupTree2, reqBizGroupTree3 } from "../biz-group/BizGroupContent";
import Checkbox from "@/components/form/input/Checkbox";
import ManageBizGroupModal from "../biz-group/ManageBizGroupModal";
import CtDrawer from "@/components/CtDrawer";
import CtSelectedTextField from "@/components/CtSelectedText";
import Select from "@/components/form/Select2";
import PageCountSelector from "@/components/PageCountSelector";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -37,11 +41,13 @@ export default function CustomerAccount() {
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
// group search fields
const [ name, setName ] = useState<string>("");
@@ -54,10 +60,23 @@ export default function CustomerAccount() {
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
const [ isMobileMode, setIsMobileMode ] = useState<boolean>(false);
const [ isSearchFieldOpen, setIsSearchFieldOpen ] = useState<boolean>(false);
const [ listSelectedText, setListSelectedText ] = useState<string[]>([]);
const changeListSelectedText = (index: number, text: string) => {
setListSelectedText(prev => {
const copy = [...prev];
copy[index] = text;
return copy;
});
}
// modal
const { isOpen, openModal, closeModal } = useModal();
const modalData = useMultiState<CustomerAccountModalProps>({biz_group_name: "", biz_reg_num: "", isModify: false, gid: "", biz_group_id: "", new_biz_group_id: "", user_id: "", user_pw: "", nick_name: "", email: "", state: "1" });
const modalData = useMultiState<CustomerAccountModalProps>({ biz_group_name: "", biz_reg_num: "", isModify: false,
gid: "", biz_group_id: "", new_biz_group_id: "", user_id: "", user_pw: "", name: "", phone: "", email: "", state: "1",
perm_group: true, perm_uid1: true, perm_cancel: true, perm_account: true });
const { isOpen: isOpenManageBizGroup, openModal: openModalManageBizGroup, closeModal: closeModalManageBizGroup } = useModal();
@@ -95,6 +114,13 @@ export default function CustomerAccount() {
setTableData([]);
return;
}
resp.data.result.list.forEach((item: any) => {
item.perm_group = (item.permission & 0x2) === 0x2;
item.perm_uid1 = (item.permission & 0x4) === 0x4;
item.perm_cancel = (item.permission & 0x8) === 0x8;
});
setTableTotalCount(resp.data.result.totalCount);
setTableData(resp.data.result.list);
}
@@ -134,22 +160,22 @@ export default function CustomerAccount() {
const handleManageBizGroupModalClose = () => {
closeModalManageBizGroup();
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
reqAccountList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
reqAccountList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
};
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -157,7 +183,7 @@ export default function CustomerAccount() {
}
else {
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
//reqAccountList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
//reqAccountList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
reqAccountList(false, String(resp.data.result.tree[0].key), isGroupAccess);
});
}
@@ -182,7 +208,7 @@ export default function CustomerAccount() {
const handleClickGroupAccess = (value: boolean) => {
setGroupAccess(value);
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (selectedTreeKeys.length <= 0) {
return;
}
@@ -225,7 +251,8 @@ export default function CustomerAccount() {
new_biz_group_id: "",
user_id: "",
user_pw: "",
nick_name: "",
name: "",
phone: "",
email: "",
state: "1"
});
@@ -264,6 +291,20 @@ export default function CustomerAccount() {
reqAccountList(false, selectedTreeKeys[0] as string, isGroupAccess);
}
//
const handleChangeUserId = (e: React.ChangeEvent<HTMLInputElement>) => {
setUserId(e.target.value);
changeListSelectedText(0, e.target.value);
}
const handleChangeEmail = (e: React.ChangeEvent<HTMLInputElement>) => {
setEmail(e.target.value);
changeListSelectedText(1, e.target.value);
}
const handleChangeNickName = (e: React.ChangeEvent<HTMLInputElement>) => {
setNickName(e.target.value);
changeListSelectedText(2, e.target.value);
}
useEffect(() => {
@@ -276,14 +317,14 @@ export default function CustomerAccount() {
if (tokenPayload == undefined)
return;
if (tokenPayload?.permission == 1)
if (tokenPayload?.permission == 0xffffffff)
return;
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
setGroupAccess(tokenPayload?.permission == 1);
setTreeOpen(tokenPayload?.permission == 1);
setGroupAccess(tokenPayload?.permission == 0xffffffff);
setTreeOpen(tokenPayload?.permission == 0xffffffff);
reqAccountList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
reqAccountList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
}, [tokenPayload]);
@@ -293,18 +334,25 @@ export default function CustomerAccount() {
title: "등록일",
key: "reg_time" ,
renderItem: (item:any) => convertDateTime3(item.reg_time),
viewMobile: true,
},
{
title: "그룹",
key: "biz_group_name",
viewMobile: true,
},
{
title: "아이디",
key: "user_id",
viewMobile: true,
},
{
title: "닉네임",
key: "nick_name",
title: "이름",
key: "name",
},
{
title: "휴대폰번호",
key: "phone",
},
{
title: "이메일",
@@ -359,7 +407,7 @@ export default function CustomerAccount() {
onClickSearch={handleClickGroupSearch}
onClickManage={handleClickGroupManage}
isDisabled={isLoadingGlobal}
searchLabelWidth={SEARCH_LABEL_WIDTH}
searchLabelWidth={SEARCH_LABEL_WIDTH_PX}
>
<CtTree
treeData={treeData}
@@ -374,46 +422,55 @@ export default function CustomerAccount() {
<ComponentCard title="계정 목록 조회" titleIcon={<TableIcon />}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="아이디" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="조회할 아이디를 입력하세요." value={user_id} onChange={(e) => setUserId(e.target.value)} />
</WithLabel>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="조회할 이메일을 입력하세요." value={email} onChange={(e) => setEmail(e.target.value)} />
</WithLabel>
<WithLabel label="닉네임" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="조회할 닉네임을 입력하세요." value={nick_name} onChange={(e) => setNickName(e.target.value)} />
</WithLabel>
<CtDrawer title="상세 조회" isMobileMode={isMobileMode} setIsMobileMode={setIsMobileMode} isSearchFieldOpen={isSearchFieldOpen} setIsSearchFieldOpen={setIsSearchFieldOpen}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="아이디" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 아이디를 입력하세요." value={user_id} onChange={handleChangeUserId} />
</WithLabel>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 이메일을 입력하세요." value={email} onChange={handleChangeEmail} />
</WithLabel>
<WithLabel label="닉네임" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 닉네임을 입력하세요." value={nick_name} onChange={handleChangeNickName} />
</WithLabel>
</div>
</div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
/>
</div>
</WithLabel>
<div className="flex items-center gap-3">
<Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} />
<span className="block font-normal text-gray-700 text-theme-sm dark:text-gray-400">
</span>
</div>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</CtDrawer>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
{ isMobileMode && <Button size="sm" variant="outline" startIcon={<FilterIcon />} onClick={() => setIsSearchFieldOpen(true)}></Button> }
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</div>
</div>
<div className="flex items-center justify-end gap-5">
{ isTreeOpen && <Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} label="그룹단위로 조회" /> }
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
{ isMobileMode &&
<CtSelectedTextField label={"필터:"} listText={listSelectedText} setListText={setListSelectedText}></CtSelectedTextField>
}
<CtTable1 columns={columns} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
onClickPageChange={handlePageChange} />
@@ -165,7 +165,7 @@ export default function AddModifyDeviceModal({ multiState, onOk, isOpen, closeMo
placeholder="선택하세요"
defaultValue={multiState.values.biz_group_id}
options={multiState.values.optBizGroup}
onChange={(value) => {multiState.set("new_biz_group_id", value)}}
onChange={(e) => {multiState.set("new_biz_group_id", e.target.value)}}
className="dark:bg-dark-900" />
</div>
<div>
@@ -178,7 +178,7 @@ export default function AddModifyDeviceModal({ multiState, onOk, isOpen, closeMo
placeholder="선택하세요"
defaultValue={multiState.values.optTid.length > 0 ? multiState.values.optTid[0].value : undefined}
options={multiState.values.optTid}
onChange={(value) => {multiState.set("terminal_id", value)}}
onChange={(e) => {multiState.set("terminal_id", e.target.value)}}
className="dark:bg-dark-900" />
</div>
<div>
@@ -1,10 +1,10 @@
"use client"
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
import ComponentCard from '@/components/common/ComponentCard2';
import BizGroupPanel from "@/components/common/BizGroupPanel";
import BizGroupPanel from "@/components/BizGroupPanel";
import CtTable1 from '@/components/tables/CtTable1';
import Button from '@/components/ui/button/Button2';
import { DocsIcon, PlusIcon, TrashBinIcon, TableIcon, BoxCubeIcon, PencilIcon } from "@/icons";
import { DocsIcon, PlusIcon, TrashBinIcon, TableIcon, BoxCubeIcon, PencilIcon, FilterIcon } from "@/icons";
import WithLabel from '@/components/form/WithLabel';
import Input from '@/components/form/input/InputField2';
import Select from '@/components/form/Select2';
@@ -15,7 +15,7 @@ import Badge from "@/components/ui/badge/Badge";
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import { useRouter } from "next/navigation";
import api, { useAuthStore, postFileDownload, convertDateTime3, useUiLoadingStore } from '@/lib/_AG';
import api, { useAuthStore, postFileDownload, convertDateTime3, useUiLoadingStore, todayYMD, addDaysYMD } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyDeviceModal, { DeviceModalProps } from './AddModifyDeviceModal';
@@ -26,10 +26,14 @@ import { useMultiState } from "@/hooks/useMultiState";
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, treeToList, addNodeByKey, deleteNodeByKey, findRootNodeByKey } from "@/components/CtTree";
import { reqBizGroupTree2, reqBizGroupTree3 } from "@/app/(admin)/biz-group/BizGroupContent";
import ManageBizGroupModal from "../biz-group/ManageBizGroupModal";
import CtDrawer from "@/components/CtDrawer";
import CtSelectedTextField from "@/components/CtSelectedText";
import PageCountSelector from "@/components/PageCountSelector";
import InputSelectField from "@/components/form/input/InputSelectField";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -41,23 +45,41 @@ export default function Device() {
const [ tableData, setTableData ] = useState<any[]>([]);
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
// group search fields
const [ name, setName ] = useState<string>("");
const [ biz_reg_num, setBizRegNum ] = useState<string>("");
// device search fields
const [ device_name, setDeivceName ] = useState<string>("");
const [ uid1, setUid1 ] = useState<string>("");
const [ list_uid1, setListUid1 ] = useState<{label: string; value: string}[]>([]);
const [ conn_state, setConnState ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
const [ listIdleTerminal, setListIdelTerminal ] = useState([]);
const [ listGoods, setListGoods ] = useState([]);
const isLoadingGlobal = useUiLoadingStore((s) => s.isLoading);
const [ isMobileMode, setIsMobileMode ] = useState<boolean>(false);
const [ isSearchFieldOpen, setIsSearchFieldOpen ] = useState<boolean>(false);
const [ listSelectedText, setListSelectedText ] = useState<string[]>([]);
const changeListSelectedText = (index: number, text: string) => {
setListSelectedText(prev => {
const copy = [...prev];
copy[index] = text;
return copy;
});
}
// modal
const { isOpen, openModal, closeModal } = useModal();
@@ -75,6 +97,27 @@ export default function Device() {
// function part
//
function reqUid1List() {
api.post('/api/list-uid1.do').then((resp) => {
console.log(resp);
if (resp.data.errCode == 0) {
if (resp.data.result.list.length == 0) {
setListUid1([]);
return;
}
setListUid1(
resp.data.result.list.map((item: { uid1: string; name: string }) => ({
label: item.uid1 + (item.name !== "" ? " (" + item.name + ")" : ""),
value: item.uid1,
}))
);
}
})
.catch((err) => console.error(err))
}
function reqDeviceList(is_excel: boolean, biz_group_id: string, groupAccess: boolean) {
if (!biz_group_id)
return;
@@ -85,6 +128,9 @@ export default function Device() {
offset: tableOffset,
limit: COUNT_PER_PAGE,
biz_group_id: biz_group_id,
device_name: device_name,
uid1: uid1,
conn_state: conn_state,
date_start: date_start,
date_end: date_end,
}
@@ -224,22 +270,22 @@ export default function Device() {
const handleManageBizGroupModalClose = () => {
closeModalManageBizGroup();
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
reqDeviceList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
reqDeviceList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
};
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -248,7 +294,9 @@ export default function Device() {
}
else {
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
//reqDeviceList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
reqUid1List();
//reqDeviceList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
reqDeviceList(false, String(resp.data.result.tree[0].key), isGroupAccess);
});
}
@@ -274,7 +322,7 @@ export default function Device() {
const handleClickGroupAccess = (value: boolean) => {
setGroupAccess(value);
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (selectedTreeKeys.length <= 0) {
return;
}
@@ -461,18 +509,36 @@ export default function Device() {
};
//
const handleChangeDeivceName = (e: React.ChangeEvent<HTMLInputElement>) => {
setDeivceName(e.target.value);
changeListSelectedText(0, e.target.value);
}
const handleChangeUid1 = (e: React.ChangeEvent<HTMLInputElement>) => {
setUid1(e.target.value);
changeListSelectedText(1, e.target.value);
}
const handleChangeConnState = (e: React.ChangeEvent<HTMLSelectElement>) => {
setConnState(e.target.value);
changeListSelectedText(2, e.target.options[e.target.selectedIndex].text);
}
//
useEffect(() => {
if (tokenPayload == undefined)
return;
if (tokenPayload?.permission == 1)
if (tokenPayload?.permission == 0xffffffff)
return;
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
setGroupAccess(tokenPayload?.permission == 1);
setTreeOpen(tokenPayload?.permission == 1);
reqUid1List();
reqDeviceList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
setGroupAccess(tokenPayload?.permission == 0xffffffff);
setTreeOpen(tokenPayload?.permission == 0xffffffff);
reqDeviceList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
}, [tokenPayload]);
@@ -487,7 +553,8 @@ export default function Device() {
{
title: "등록일",
key: "reg_time",
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time)
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time),
viewMobile: true,
},
{
title: "그룹",
@@ -500,9 +567,8 @@ export default function Device() {
{
title: "단말기 TID",
key: "uid1",
renderItem: (item: any, row: number) => {
return item.uid1 ? (item.uid1 + " (" + (item.type == 1 ? "KICC" : "NICE") +")") : ""
}
renderItem: (item: any, row: number) => item.uid1 ? (item.uid1 + " (" + (item.type == 1 ? "KICC" : "NICE") +")") : "",
viewMobile: true,
},
{
title: "상태",
@@ -528,6 +594,7 @@ export default function Device() {
</Badge>
);
},
viewMobile: true,
},
{
title: "가동시간",
@@ -594,7 +661,7 @@ export default function Device() {
onClickSearch={handleClickGroupSearch}
onClickManage={handleClickGroupManage}
isDisabled={isLoadingGlobal}
searchLabelWidth={SEARCH_LABEL_WIDTH}
searchLabelWidth={SEARCH_LABEL_WIDTH_PX}
>
<CtTree
treeData={treeData}
@@ -608,39 +675,65 @@ export default function Device() {
</BizGroupPanel>
<ComponentCard title="무인기기 목록" titleIcon={<TableIcon />} >
<div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
/>
</div>
</WithLabel>
<div className="flex items-center gap-3">
{ isTreeOpen && <>
<Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} />
<span className="block font-normal text-gray-700 text-theme-sm dark:text-gray-400">
</span>
</>}
</div>
<div className="flex items-center justify-end gap-5">
{/*<Button size="sm" variant="primary" startIcon={<PlusIcon />} onClick={handleClickTemplateManage}>템플릿 관리</Button>*/}
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
<CtDrawer title="상세 조회" isMobileMode={isMobileMode} setIsMobileMode={setIsMobileMode} isSearchFieldOpen={isSearchFieldOpen} setIsSearchFieldOpen={setIsSearchFieldOpen}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="무인기기명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="무인기기명을 입력하세요." value={device_name} onChange={handleChangeDeivceName} />
</WithLabel>
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH_PX}>
<InputSelectField type="text" placeholder="TID를 입력하세요." value={uid1} options={list_uid1} onChange={handleChangeUid1} />
</WithLabel>
<WithLabel label="상태" label_width={SEARCH_LABEL_WIDTH_PX}>
<Select
//placeholder="선택하세요"
options={[
{ label: "전체", value: "" },
{ label: "가동중", value: "1" },
{ label: "장애", value: "4" },
]}
defaultValue={conn_state} onChange={handleChangeConnState}
className="dark:bg-dark-900" />
</WithLabel>
</div>
</div>
</CtDrawer>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
<div className="flex items-center justify-end gap-5">
{/*<Button size="sm" variant="primary" startIcon={<PlusIcon />} onClick={handleClickTemplateManage}>템플릿 관리</Button>*/}
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
{ isMobileMode && <Button size="sm" variant="outline" startIcon={<FilterIcon />} onClick={() => setIsSearchFieldOpen(true)}></Button> }
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</div>
</div>
<div className="flex items-center justify-end gap-5">
{ isTreeOpen && <Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} label="그룹단위로 조회" /> }
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
{ isMobileMode &&
<CtSelectedTextField label={"필터:"} listText={listSelectedText} setListText={setListSelectedText}></CtSelectedTextField>
}
<CtTable1 columns={columns} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
onClickPageChange={handlePageChange} />
@@ -11,7 +11,7 @@ import { PlusIcon, TrashBinIcon } from "@/icons";
interface DeviceGooodsItem {
slot: string;
column_no: string;
goods_id: number;
price?: number;
inventory?: number;
@@ -40,23 +40,23 @@ export default function ManageGoodsModal({ multiState, onOk, isOpen, closeModal
function computeGoods(modal: GoodsModalProps): GoodsModalProps {
// 1 & 2. 우선 slot이 빈 문자열("")이 아닌 아이템들만 추출 (1차 필터링)
const filteredPrev = modal.prev_device_goods.filter(item => item.slot !== "");
const filteredNew = modal.new_device_goods.filter(item => item.slot !== "");
const filteredPrev = modal.prev_device_goods.filter(item => item.column_no !== "");
const filteredNew = modal.new_device_goods.filter(item => item.column_no !== "");
// 3. slot이 같으면서 goods_id까지 같은 아이템은 양쪽에서 제거
// 즉, "상대방 배열에 나랑 똑같은(slot & goods_id) 애가 없는" 것들만 남깁니다.
// 즉, "상대방 배열에 나랑 똑같은(column_no & goods_id) 애가 없는" 것들만 남깁니다.
// device_goods 정제
const final_device_goods = filteredPrev.filter(prevItem =>
!filteredNew.find(newItem =>
newItem.slot === prevItem.slot && newItem.goods_id === prevItem.goods_id
newItem.column_no === prevItem.column_no && newItem.goods_id === prevItem.goods_id
)
);
// new_device_goods 정제
const final_new_device_goods = filteredNew.filter(newItem =>
!filteredPrev.find(prevItem =>
prevItem.slot === newItem.slot && prevItem.goods_id === newItem.goods_id
prevItem.column_no === newItem.column_no && prevItem.goods_id === newItem.goods_id
)
);
@@ -118,7 +118,7 @@ export default function ManageGoodsModal({ multiState, onOk, isOpen, closeModal
return;
}
const newItem: DeviceGooodsItem = { slot: "", goods_id: parseInt(multiState.values.optGoodsList[0].value) }
const newItem: DeviceGooodsItem = { column_no: "", goods_id: parseInt(multiState.values.optGoodsList[0].value) }
const newArray: DeviceGooodsItem[] = [...multiState.values.new_device_goods, newItem];
multiState.set("new_device_goods", newArray);
@@ -133,7 +133,7 @@ export default function ManageGoodsModal({ multiState, onOk, isOpen, closeModal
const handleChangeSlot = (index: number, newValue: string) => {
const newArray: DeviceGooodsItem[] = [...multiState.values.new_device_goods];
newArray[index].slot = newValue;
newArray[index].column_no = newValue;
multiState.set("new_device_goods", newArray);
};
@@ -165,7 +165,7 @@ export default function ManageGoodsModal({ multiState, onOk, isOpen, closeModal
>
<div>
<Label></Label>
<Input type="text" value={multiState.values.biz_group_name + "(" + multiState.values.biz_reg_num + ")"} disabled />
<Input type="text" value={multiState.values.biz_group_name + (multiState.values.biz_reg_num ? `(${multiState.values.biz_reg_num})` : "")} disabled />
</div>
<div>
<Label> </Label>
@@ -176,14 +176,14 @@ export default function ManageGoodsModal({ multiState, onOk, isOpen, closeModal
<Label> {index + 1}</Label>
<div className="flex gap-2">
<div className={"w-34"}>
<Input type="text" placeholder="컬럼번호2" value={multiState.values.new_device_goods[index].slot} onChange={(e) => handleChangeSlot(index, e.target.value)} />
<Input type="text" placeholder="컬럼번호2" value={multiState.values.new_device_goods[index].column_no} onChange={(e) => handleChangeSlot(index, e.target.value)} />
</div>
<div className="flex-1">
<Select
placeholder="상품을 선택하세요"
options={multiState.values.optGoodsList}
defaultValue={String(multiState.values.new_device_goods[index].goods_id)}
onChange={(value) => handleChangeGoods(index, value)}
onChange={(e) => handleChangeGoods(index, e.target.value)}
className="dark:bg-dark-900" />
</div>
<div className={"w-34"}>
@@ -10,7 +10,7 @@ import Button from "@/components/ui/button/Button2";
import { PlusIcon, TrashBinIcon } from "@/icons";
interface TemplateElement {
slot: string;
column_no: string;
goods_id: number;
inventory?: number;
}
@@ -59,7 +59,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
const template = templateMap.get(templateId)!;
template.elements.push({
slot: item.slot,
column_no: item.column_no,
goods_id: item.goods_id,
inventory: item.inventory
});
@@ -129,7 +129,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
}
// slot이 빈 문자열인 항목 필터링
const validElements = currentElements.filter(item => item.slot !== "");
const validElements = currentElements.filter(item => item.column_no !== "");
if (validElements.length === 0) {
alert("컬럼번호를 입력한 상품이 없습니다.");
@@ -139,7 +139,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
const params = {
biz_group_id: multiState.values.biz_group_id,
goods_template_elements: validElements.map(item => ({
slot: item.slot,
column_no: item.column_no,
goods_id: item.goods_id,
inventory: item.inventory || null
}))
@@ -174,7 +174,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
}
// slot이 빈 문자열인 항목 필터링
const validElements = currentElements.filter(item => item.slot !== "");
const validElements = currentElements.filter(item => item.column_no !== "");
if (validElements.length === 0) {
alert("컬럼번호를 입력한 상품이 없습니다.");
@@ -185,7 +185,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
goods_template_id: selectedTemplateId,
goods_template_name: templateName || undefined,
goods_template_elements: validElements.map(item => ({
slot: item.slot,
column_no: item.column_no,
goods_id: item.goods_id,
inventory: item.inventory || null
}))
@@ -241,7 +241,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
}
const newItem: TemplateElement = {
slot: "",
column_no: "",
goods_id: parseInt(multiState.values.optGoodsList[0].value)
};
setCurrentElements([...currentElements, newItem]);
@@ -254,7 +254,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
const handleChangeSlot = (index: number, newValue: string) => {
const newArray = [...currentElements];
newArray[index].slot = newValue;
newArray[index].column_no = newValue;
setCurrentElements(newArray);
};
@@ -297,12 +297,12 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
<>
<div className="space-y-2 mb-4">
{templates.length === 0 ? (
<div className="text-center py-4 text-gray-500"> 릿 .</div>
<div className="text-center py-4 text-gray-500 dark:text-gray-400"> 릿 .</div>
) : (
templates.map((template) => (
<div
key={template.goods_template_id}
className="flex items-center justify-between p-3 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer"
className="flex items-center justify-between p-3 border border-gray-200 dark:border-gray-800 rounded-lg hover:bg-gray-50 dark:hover:bg-white/5 cursor-pointer"
onClick={() => handleClickEdit(template)}
>
<span className="flex-1">{template.template_name}</span>
@@ -349,7 +349,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
<Input
type="text"
placeholder="컬럼번호"
value={item.slot}
value={item.column_no}
onChange={(e) => handleChangeSlot(index, e.target.value)}
/>
</div>
@@ -358,7 +358,7 @@ export default function ManageTemplateModal({ multiState, onOk, isOpen, closeMod
placeholder="상품을 선택하세요"
options={multiState.values.optGoodsList}
defaultValue={String(item.goods_id)}
onChange={(value) => handleChangeGoods(index, value)}
onChange={(e) => handleChangeGoods(index, e.target.value)}
className="dark:bg-dark-900"
/>
</div>
@@ -22,7 +22,7 @@ import DeviceGoodsList from '@/components/DeviceGoodsItem';
interface DeviceGooodsItem {
slot: string;
column_no: string;
goods_id: number;
price?: number;
inventory?: number;
@@ -41,7 +41,7 @@ interface GoodsTemplateItem {
goods_template_elements: Array<{
goods_template_element_id: number;
goods_id: number;
slot: string;
column_no: string;
inventory: number;
inventory_max?: number;
inventory_alarm?: number;
@@ -50,18 +50,18 @@ interface GoodsTemplateItem {
}
function makeParams(device_id: string, prev_device_goods: DeviceGooodsItem[], new_device_goods: DeviceGooodsItem[], isSaveTemplate: boolean, templateName: string, biz_group_id: string | undefined, inventorySetValue: { inventory: number; inventory_max: number; inventory_alarm: number } ) {
const filteredPrev = prev_device_goods.filter(item => item.slot !== "" && item.goods_id !== 0);
const filteredNew = new_device_goods.filter(item => item.slot !== "" && item.goods_id !== 0);
const filteredPrev = prev_device_goods.filter(item => item.column_no !== "" && item.goods_id !== 0);
const filteredNew = new_device_goods.filter(item => item.column_no !== "" && item.goods_id !== 0);
const final_device_goods = filteredPrev.filter(prevItem =>
!filteredNew.find(newItem =>
newItem.slot === prevItem.slot && newItem.goods_id === prevItem.goods_id && newItem.inventory === prevItem.inventory && newItem.inventory_max === prevItem.inventory_max && newItem.inventory_alarm === prevItem.inventory_alarm
newItem.column_no === prevItem.column_no && newItem.goods_id === prevItem.goods_id && newItem.inventory === prevItem.inventory && newItem.inventory_max === prevItem.inventory_max && newItem.inventory_alarm === prevItem.inventory_alarm
)
);
const final_new_device_goods = filteredNew.filter(newItem =>
!filteredPrev.find(prevItem =>
prevItem.slot === newItem.slot && prevItem.goods_id === newItem.goods_id && newItem.inventory === prevItem.inventory && newItem.inventory_max === prevItem.inventory_max && newItem.inventory_alarm === prevItem.inventory_alarm
prevItem.column_no === newItem.column_no && prevItem.goods_id === newItem.goods_id && newItem.inventory === prevItem.inventory && newItem.inventory_max === prevItem.inventory_max && newItem.inventory_alarm === prevItem.inventory_alarm
)
);
@@ -108,7 +108,7 @@ export default function ManageGoods() {
const [ optGoodsList, setOptGoodsList ] = useState<any>([]);
const [ prev_device_goods, setPrev_device_goods ] = useState<any[]>([]);
const [ new_device_goods, setNew_device_goods ] = useState<any[]>(Array.from({ length: 30 }, (_, i) => ({ idx: i + 1, slot: String(i + 1).padStart(2, "0"), goods_id: 0, inventory: 0, inventory_max: 0, inventory_alarm: 0 })));
const [ new_device_goods, setNew_device_goods ] = useState<any[]>(Array.from({ length: 30 }, (_, i) => ({ idx: i + 1, column_no: String(i + 1).padStart(2, "0"), goods_id: 0, inventory: 0, inventory_max: 0, inventory_alarm: 0 })));
const [ isSaveTemplate, setIsSaveTemplate ] = useState<boolean>(false);
const [ isModalOpen, setIsModalOpen ] = useState<boolean>(false);
@@ -183,7 +183,7 @@ export default function ManageGoods() {
const handleChangeSlot = (index: number, newValue: string) => {
const newArray: DeviceGooodsItem[] = [...new_device_goods];
newArray[index].slot = newValue;
newArray[index].column_no = newValue;
setNew_device_goods(newArray);
};
@@ -221,8 +221,8 @@ export default function ManageGoods() {
};
const handleClickAdd = () => {
//const newItem: DeviceGooodsItem = { slot: "", goods_id: parseInt(optGoodsList[0].value) }
const newItem: DeviceGooodsItem = { slot: "", goods_id: 0 }
//const newItem: DeviceGooodsItem = { column_no: "", goods_id: parseInt(optGoodsList[0].value) }
const newItem: DeviceGooodsItem = { column_no: "", goods_id: 0 }
const newArray: DeviceGooodsItem[] = [...new_device_goods, newItem];
setNew_device_goods(newArray);
@@ -274,7 +274,7 @@ export default function ManageGoods() {
// 기존 값을 모두 비우고 초기 상태로 리셋
const resetGoods = Array.from({ length: 30 }, (_, i) => ({
idx: i + 1,
slot: String(i + 1).padStart(2, "0"),
column_no: String(i + 1).padStart(2, "0"),
goods_id: 0,
inventory: 0
}));
@@ -284,7 +284,7 @@ export default function ManageGoods() {
// 템플릿의 goods_template_elements를 DeviceGooodsItem 형태로 변환
const mappedGoods: DeviceGooodsItem[] = goodsTemplate.goods_template_elements.map((element) => ({
slot: element.slot,
column_no: element.column_no,
goods_id: Number(element.goods_id),
inventory: element.inventory,
inventory_max: element.inventory_max,
@@ -317,7 +317,7 @@ export default function ManageGoods() {
<div className="grid grid-cols-1 gap-3 sm:grid-cols-5">
<div>
<Label></Label>
<Input type="text" value={biz_group_name + "(" + biz_reg_num + ")"} disabled />
<Input type="text" value={biz_group_name + (biz_reg_num ? "(" + biz_reg_num + ")" : "")} disabled />
</div>
<div>
<Label> </Label>
@@ -14,9 +14,10 @@ import Select from '@/components/form/Select2';
import React from "react";
import { useState } from 'react';
import { useRouter } from "next/navigation";
import { addDaysYMD, todayYMD } from "@/lib/_AG";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -255,25 +256,27 @@ export default function FAQ() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="제목을 입력하세요." value={title} onChange={(e) => setTitle(e.target.value)} />
</WithLabel>
<WithLabel label="카테고리" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="카테고리" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="카테고리" value={category} onChange={(e) => setCategory(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -317,7 +320,7 @@ export default function FAQ() {
placeholder="카테고리를 선택하세요."
options={FAQ_CATEGORY_OPTIONS}
defaultValue={newCategory || ""}
onChange={(value) => setNewCategory(value)}
onChange={(e) => setNewCategory(e.target.value)}
className="dark:bg-dark-900"
/>
</div>
@@ -1,7 +1,7 @@
"use client"
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
import ComponentCard from '@/components/common/ComponentCard2';
import BizGroupPanel from "@/components/common/BizGroupPanel";
import BizGroupPanel from "@/components/BizGroupPanel";
import CtTable1 from '@/components/tables/CtTable1';
import Button from '@/components/ui/button/Button2';
import { DocsIcon, PlusIcon, TrashBinIcon, TableIcon, PencilIcon } from "@/icons";
@@ -15,17 +15,18 @@ import Badge from "@/components/ui/badge/Badge";
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import { useRouter } from "next/navigation";
import api, { convertDateTime3, getUrlParam, postFileDownload, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, getUrlParam, postFileDownload, todayYMD, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import { useMultiState } from "@/hooks/useMultiState";
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, addNodeByKey, deleteNodeByKey, findRootNodeByKey } from "@/components/CtTree";
import { reqBizGroupTree2, reqBizGroupTree3 } from "@/app/(admin)/biz-group/BizGroupContent";
import PageCountSelector from "@/components/PageCountSelector";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -37,12 +38,14 @@ export default function GoodsTemplate() {
const [ tableData, setTableData ] = useState<any[]>([]);
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
// group search fields
const [ name, setName] = useState<string>("");
@@ -50,8 +53,8 @@ export default function GoodsTemplate() {
// template search fields
const [ templateName, setTemplateName] = useState<string>("");
const [ date_start, setDateStart] = useState<string>("");
const [ date_end, setDateEnd] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
// function part
@@ -122,17 +125,17 @@ export default function GoodsTemplate() {
//
// tree part //////////
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -164,7 +167,7 @@ export default function GoodsTemplate() {
const handleClickGroupAccess = (value: boolean) => {
setGroupAccess(value);
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (selectedTreeKeys.length <= 0) {
return;
}
@@ -225,12 +228,12 @@ export default function GoodsTemplate() {
if (tokenPayload == undefined)
return;
if (tokenPayload?.permission == 1)
if (tokenPayload?.permission == 0xffffffff)
return;
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
setGroupAccess(tokenPayload?.permission == 1);
setTreeOpen(tokenPayload?.permission == 1);
setGroupAccess(tokenPayload?.permission == 0xffffffff);
setTreeOpen(tokenPayload?.permission == 0xffffffff);
reqGoodsTemplateList(false, String(resp.data.result.tree[0].key), isGroupAccess);
});
@@ -247,11 +250,13 @@ export default function GoodsTemplate() {
{
title: "등록일",
key: "reg_time",
renderItem: (item: any, row: number) => convertDateTime3(item.template_reg_time)
renderItem: (item: any, row: number) => convertDateTime3(item.template_reg_time),
viewMobile: true,
},
{
title: "템플릿명",
key: "template_name",
viewMobile: true,
},
{
title: "설정",
@@ -292,7 +297,7 @@ export default function GoodsTemplate() {
onChangeBizRegNum={setBizRegNum}
onClickSearch={handleClickGroupSearch}
isDisabled={isLoadingGlobal}
searchLabelWidth={SEARCH_LABEL_WIDTH}
searchLabelWidth={SEARCH_LABEL_WIDTH_PX}
>
<CtTree
treeData={treeData}
@@ -306,42 +311,38 @@ export default function GoodsTemplate() {
</BizGroupPanel>
<ComponentCard title="상품 사전설정 목록" titleIcon={<TableIcon />}>
<div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
/>
</div>
</WithLabel>
<div className="flex items-center gap-3">
{ isTreeOpen && <>
<Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} />
<span className="block font-normal text-gray-700 text-theme-sm dark:text-gray-400">
</span>
</>}
</div>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</div>
</div>
<div className="flex items-center justify-end gap-5">
{ isTreeOpen && <Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} label="그룹단위로 조회" /> }
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
<CtTable1 columns={columns} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
onClickPageChange={handlePageChange} />
<div>
<Button size="sm" variant="primary" startIcon={<PlusIcon />} onClick={handleClickAdd} disabled={isLoadingGlobal}> </Button>
</div>
@@ -13,7 +13,7 @@ import { useRouter, useParams, useSearchParams } from "next/navigation";
import api, { convertDateTime2, useAuthStore } from '@/lib/_AG';
interface DeviceGooodsItem {
slot: string;
column_no: string;
goods_id: number;
inventory?: number;
inventory_max?: number;
@@ -36,7 +36,7 @@ export default function GoodsTemplateEdit() {
const router = useRouter();
const tokenPayload = useAuthStore((s) => s.tokenPayload);
const [deviceGoods, setDeviceGoods] = useState<DeviceGooodsItem[]>(Array.from({ length: 30 }, (_, i) => ({ idx: i + 1, slot: String(i + 1).padStart(2, "0"), goods_id: 0, inventory: 0, inventory_max: 0, inventory_alarm: 0 })));
const [deviceGoods, setDeviceGoods] = useState<DeviceGooodsItem[]>(Array.from({ length: 30 }, (_, i) => ({ idx: i + 1, column_no: String(i + 1).padStart(2, "0"), goods_id: 0, inventory: 0, inventory_max: 0, inventory_alarm: 0 })));
const [optGoodsList, setOptGoodsList] = useState<{ label: string; value: string; }[]>([]);
const [goodsTemplate, setGoodsTemplate] = useState<GoodsTemplateData | null>(null);
const [inventorySetValue, setInventorySetValue] = useState<{ inventory: number; inventory_max: number; inventory_alarm: number }>({ inventory: 0, inventory_max: 0, inventory_alarm: 0 });
@@ -105,7 +105,7 @@ export default function GoodsTemplateEdit() {
const handleChangeSlot = (index: number, value: string) => {
const newGoods = [...deviceGoods];
newGoods[index].slot = value;
newGoods[index].column_no = value;
setDeviceGoods(newGoods);
};
@@ -138,8 +138,8 @@ export default function GoodsTemplateEdit() {
};
const handleClickAdd = () => {
//const newItem: DeviceGooodsItem = { slot: "", goods_id: parseInt(optGoodsList[0].value) }
const newItem: DeviceGooodsItem = { slot: "", goods_id: 0 }
//const newItem: DeviceGooodsItem = { column_no: "", goods_id: parseInt(optGoodsList[0].value) }
const newItem: DeviceGooodsItem = { column_no: "", goods_id: 0 }
const newArray: DeviceGooodsItem[] = [...deviceGoods, newItem];
setDeviceGoods(newArray);
@@ -152,7 +152,7 @@ export default function GoodsTemplateEdit() {
}
const validGoods = deviceGoods.filter(item =>
item.slot && item.goods_id && item.inventory != null && item.inventory > 0
item.column_no && item.goods_id && item.inventory != null && item.inventory > 0
);
if (validGoods.length === 0) {
@@ -169,7 +169,7 @@ export default function GoodsTemplateEdit() {
inventory_alarm: inventorySetValue.inventory_alarm
},
goods_template_elements: validGoods.map(item => ({
slot: item.slot,
column_no: item.column_no,
goods_id: item.goods_id,
inventory: item.inventory,
idx: item.idx,
@@ -118,7 +118,7 @@ export default function AddModifyGoodsModal({ multiState, onOk, isOpen, closeMod
>
<div>
<Label></Label>
<Input type="text" value={multiState.values.biz_group_name + "(" + multiState.values.biz_reg_num + ")"} disabled />
<Input type="text" value={multiState.values.biz_group_name + (multiState.values.biz_reg_num ? `(${multiState.values.biz_reg_num})` : "")} disabled />
</div>
<div>
<div className="flex items-center gap-3">
@@ -1,7 +1,7 @@
"use client"
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
import ComponentCard from '@/components/common/ComponentCard2';
import BizGroupPanel from "@/components/common/BizGroupPanel";
import BizGroupPanel from "@/components/BizGroupPanel";
import CtTable1 from '@/components/tables/CtTable1';
import Button from '@/components/ui/button/Button2';
import { DocsIcon, PlusIcon, TrashBinIcon, TableIcon, PencilIcon } from "@/icons";
@@ -15,7 +15,7 @@ import Badge from "@/components/ui/badge/Badge";
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import { useRouter } from "next/navigation";
import api, { convertDateTime3, getUrlParam, postFileDownload, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, getUrlParam, postFileDownload, todayYMD, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyGoodsModal, { GoodsModalProps } from './AddModifyGoodsModal';
@@ -23,10 +23,11 @@ import { useMultiState } from "@/hooks/useMultiState";
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, addNodeByKey, deleteNodeByKey, findRootNodeByKey } from "@/components/CtTree";
import { reqBizGroupTree2, reqBizGroupTree3 } from "@/app/(admin)/biz-group/BizGroupContent";
import PageCountSelector from "@/components/PageCountSelector";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -38,20 +39,22 @@ export default function Goods() {
const [ tableData, setTableData ] = useState<any[]>([]);
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
// group search fields
const [ name, setName] = useState<string>("");
const [ biz_reg_num, setBizRegNum] = useState<string>("");
// goods search fields
const [ date_start, setDateStart] = useState<string>("");
const [ date_end, setDateEnd] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
// modal
const { isOpen, openModal, closeModal } = useModal();
@@ -129,17 +132,17 @@ export default function Goods() {
//
// tree part //////////
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -172,7 +175,7 @@ export default function Goods() {
const handleClickGroupAccess = (value: boolean) => {
setGroupAccess(value);
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (selectedTreeKeys.length <= 0) {
return;
}
@@ -259,14 +262,14 @@ export default function Goods() {
if (tokenPayload == undefined)
return;
if (tokenPayload?.permission == 1)
if (tokenPayload?.permission == 0xffffffff)
return;
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
setGroupAccess(tokenPayload?.permission == 1);
setTreeOpen(tokenPayload?.permission == 1);
setGroupAccess(tokenPayload?.permission == 0xffffffff);
setTreeOpen(tokenPayload?.permission == 0xffffffff);
reqGoodsList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
reqGoodsList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
}, [tokenPayload]);
@@ -281,7 +284,8 @@ export default function Goods() {
{
title: "등록일",
key: "reg_time",
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time)
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time),
viewMobile: true,
},
{
title: "사업자",
@@ -290,10 +294,12 @@ export default function Goods() {
{
title: "상품코드",
key: "code",
viewMobile: true,
},
{
title: "상품명",
key: "name",
viewMobile: true,
},
/*
{
@@ -345,7 +351,7 @@ export default function Goods() {
onChangeBizRegNum={setBizRegNum}
onClickSearch={handleClickGroupSearch}
isDisabled={isLoadingGlobal}
searchLabelWidth={SEARCH_LABEL_WIDTH}
searchLabelWidth={SEARCH_LABEL_WIDTH_PX}
>
<CtTree
treeData={treeData}
@@ -359,37 +365,36 @@ export default function Goods() {
</BizGroupPanel>
<ComponentCard title="상품 목록" titleIcon={<TableIcon />}>
<div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
/>
</div>
</WithLabel>
<div className="flex items-center gap-3">
{ isTreeOpen && <>
<Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} />
<span className="block font-normal text-gray-700 text-theme-sm dark:text-gray-400">
</span>
</>}
</div>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</div>
</div>
<div className="flex items-center justify-end gap-5">
{ isTreeOpen && <Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} label="그룹단위로 조회" /> }
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
<CtTable1 columns={columns} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
onClickPageChange={handlePageChange} />
@@ -27,7 +27,7 @@ export default function AddModifyLocationModal({ multiState, onOk, isOpen, close
const handleClickAddOrModify = () => {
if (multiState.values.name == "") {
alert("그룹(사업자명)을 입력하셔야 합니다.");
alert("그룹(사업자)명을 입력하셔야 합니다.");
return;
}
@@ -9,7 +9,7 @@ import Input from '@/components/form/input/InputField2';
import DatePicker from '@/components/form/date-picker2';
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime3 } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, todayYMD } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyLocationModal, { LocationModalProps } from "./AddModifyLocationModal";
@@ -17,7 +17,7 @@ import { useMultiState } from "@/hooks/useMultiState";
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, addNodeByKey, changeNodeByKey, deleteNodeByKey } from "@/components/CtTree";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
export default function Location() {
@@ -32,8 +32,8 @@ export default function Location() {
const [ name, setName] = useState<string>("");
const [ description, setDescription] = useState<string>("");
const [ address, setAddress] = useState<string>("");
const [ date_start, setDateStart] = useState<string>("");
const [ date_end, setDateEnd] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
//
// form fields
@@ -237,15 +237,15 @@ export default function Location() {
<ComponentCard title="위치정보 조회" titleIcon={<TableIcon />}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="위치명" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="위치명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 위치명을 입력하세요." value={name} onChange={(e) => setName(e.target.value)}
onKeyDown={(e) => {if (e.key === "Enter") handleClickSearch()}} />
</WithLabel>
<WithLabel label="설명" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="설명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 설명를 입력하세요." value={description} onChange={(e) => setDescription(e.target.value)}
onKeyDown={(e) => {if (e.key === "Enter") handleClickSearch()}} />
</WithLabel>
<WithLabel label="주소" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="주소" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 주소를 입력하세요." value={address} onChange={(e) => setAddress(e.target.value)}
onKeyDown={(e) => {if (e.key === "Enter") handleClickSearch()}} />
</WithLabel>
@@ -10,10 +10,10 @@ import DatePicker from '@/components/form/date-picker2';
import React from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime, convertDateTime2, convertDateTime3, convertDateTime6, postFileDownload, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime, convertDateTime2, convertDateTime3, convertDateTime6, postFileDownload, todayYMD, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -97,12 +97,14 @@ export default function Logging() {
{
title: "날짜",
key: "reg_time",
renderItem: (item: any, row: number) => convertDateTime2(item.reg_time)
renderItem: (item: any, row: number) => convertDateTime2(item.reg_time),
viewMobile: true,
},
{
title: "유형",
key: "type",
renderItem: (item : any) => ( item.type === 1 ? "system" : "operating")
renderItem: (item : any) => ( item.type === 1 ? "system" : "operating"),
viewMobile: true,
},
{
title: "작업 내용",
@@ -123,7 +125,7 @@ export default function Logging() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="작업내용 검색어" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="작업내용 검색어" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input
type="text"
placeholder="작업내용 검색어를 입력하세요."
@@ -131,7 +133,7 @@ export default function Logging() {
onChange={(e) => setAction(e.target.value)}
/>
</WithLabel>
<WithLabel label="작업자 아이디" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="작업자 아이디" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input
type="text"
placeholder="조회할 작업자 아이디를 입력하세요."
@@ -141,17 +143,19 @@ export default function Logging() {
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -11,14 +11,14 @@ import DatePicker from '@/components/form/date-picker2';
import React from "react";
import { useEffect, useState } from 'react';
import { useRouter } from "next/navigation";
import api, { convertDateTime3 } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, todayYMD } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyNoticeModal, {NoticeModalProps} from './AddModifyNoticeModal';
import { useMultiState } from "@/hooks/useMultiState";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -132,7 +132,8 @@ export default function Notice() {
{
title: "날짜",
key: "reg_time",
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time)
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time),
viewMobile: true,
},
{
title: "홈화면 시작일",
@@ -152,6 +153,7 @@ export default function Notice() {
{
title: "제목",
key: "title",
viewMobile: true,
},
{
title: "작성자",
@@ -168,33 +170,27 @@ export default function Notice() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="제목을 입력하세요." value={title} onChange={(e) => setTitle(e.target.value)} />
</WithLabel>
<WithLabel label="작성자 아이디" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="작성자 아이디" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 작성자 아이디를 입력하세요." value={uid1} onChange={(e) => setUid1(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
// onChange={(dates, currentDateString) => {
// // Handle your logic
// console.log({ dates, currentDateString });
// }}
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
// onChange={(dates, currentDateString) => {
// // Handle your logic
// console.log({ dates, currentDateString });
// }}
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -28,7 +28,7 @@ export default function AddModifyResourceBoardModal({ multiState, onOk, isOpen,
const handleClickAddOrModify = () => {
if (multiState.values.user_id == "") {
alert("그룹(사업자명)을 입력하셔야 합니다.");
alert("그룹(사업자)명을 입력하셔야 합니다.");
return;
}
//else if (multiState.values.user_pw == "") {
@@ -11,14 +11,14 @@ import DatePicker from '@/components/form/date-picker2';
import React from "react";
import { useEffect, useState } from 'react';
import { useRouter } from "next/navigation";
import api, { convertDateTime3 } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, todayYMD } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyResourceBoardModal, {ResourceBoardModalProps} from './AddModifyResourceBoardModal';
import { useMultiState } from "@/hooks/useMultiState";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -143,7 +143,7 @@ export default function ResourceBoard() {
}
if (multiState.values.title == "") {
alert("그룹(사업자명)을 입력하셔야 합니다.");
alert("그룹(사업자)명을 입력하셔야 합니다.");
return;
}
@@ -207,25 +207,27 @@ export default function ResourceBoard() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="제목을 입력하세요." value={title} onChange={(e) => setTitle(e.target.value)} />
</WithLabel>
<WithLabel label="작성자 아이디" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="작성자 아이디" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 작성자 아이디를 입력하세요." value={uid1} onChange={(e) => setUid1(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -1,25 +1,30 @@
"use client"
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
import ComponentCard from '@/components/common/ComponentCard2';
import BizGroupPanel from "@/components/common/BizGroupPanel";
import BizGroupPanel from "@/components/BizGroupPanel";
import CtTable1 from '@/components/tables/CtTable1';
import Button from '@/components/ui/button/Button2';
import { DocsIcon, PlusIcon, TableIcon, ChevronDownIcon } from "@/icons";
import { DocsIcon, PlusIcon, TableIcon, ChevronDownIcon, FilterIcon } from "@/icons";
import WithLabel from '@/components/form/WithLabel';
import Input from '@/components/form/input/InputField2';
import DatePicker from '@/components/form/date-picker2';
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime3, postFileDownload, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import api, { convertDateTime3, postFileDownload, todayYMD, addDaysYMD, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import CtTree, { CtTreeNode, findNodeByKey, findRootNodeByKey, getAllNodeKeys } from "@/components/CtTree";
import { reqBizGroupTree2, reqBizGroupTree3 } from "../biz-group/BizGroupContent";
import Checkbox from "@/components/form/input/Checkbox";
import Select from "@/components/form/Select2";
import CtDrawer from "@/components/CtDrawer";
import CtSelectedTextField from "@/components/CtSelectedText";
import PageCountSelector from "@/components/PageCountSelector";
import InputSelectField from "@/components/form/input/InputSelectField";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -27,15 +32,18 @@ export default function Sales() {
const tokenPayload = useAuthStore((s) => s.tokenPayload); //Bruce, JWT
const isLoadingGlobal = useUiLoadingStore((s) => s.isLoading);
const [ sumData, setSumData ] = useState<any[]>([]);
const [ tableData, setTableData ] = useState<any[]>([]);
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
// group search fields
const [ name, setName ] = useState<string>("");
@@ -43,18 +51,60 @@ export default function Sales() {
//search fields
const [ device_name, setDeivceName ] = useState<string>("");
const [ query_uid1, setQueryUid1 ] = useState<boolean>(false);
const [ uid1, setUid1 ] = useState<string>("");
const [ list_uid1, setListUid1 ] = useState<{label: string; value: string}[]>([]);
const [ approval_type, setApprovalType ] = useState<string>("0");
const [ date_type, setDateType ] = useState<string>("1");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>(addDaysYMD(-7));
const [ date_end, setDateEnd ] = useState<string>(todayYMD());
const [ isMobileMode, setIsMobileMode ] = useState<boolean>(false);
const [ isSearchFieldOpen, setIsSearchFieldOpen ] = useState<boolean>(false);
const [ listSelectedText, setListSelectedText ] = useState<string[]>(["일별집계"]);
const changeListSelectedText = (index: number, text: string) => {
setListSelectedText(prev => {
const copy = [...prev];
copy[index] = text;
return copy;
});
}
const [ show_query_uid1, setShowQueryUid1 ] = useState<boolean>(false);
// function part
//
function reqUid1List() {
api.post('/api/list-uid1.do').then((resp) => {
if (resp.data.errCode == 0) {
if (resp.data.result.list.length == 0) {
setListUid1([]);
return;
}
setListUid1(
resp.data.result.list.map((item: { uid1: string; name: string }) => ({
label: item.uid1 + (item.name !== "" ? " (" + item.name + ")" : ""),
value: item.uid1,
}))
);
}
})
.catch((err) => console.error(err))
}
function reqSalesList(is_excel: boolean, biz_group_id: string, groupAccess: boolean) {
if (!biz_group_id)
return;
if (!groupAccess) {
const root = findRootNodeByKey(treeData, biz_group_id);
if (root)
biz_group_id = root.key;
}
const params = {
is_group_access: groupAccess,
is_excel: is_excel,
@@ -62,6 +112,7 @@ export default function Sales() {
limit: COUNT_PER_PAGE,
biz_group_id: biz_group_id,
device_name: device_name,
query_uid1: query_uid1,
uid1: uid1,
approval_type: approval_type,
date_type: date_type,
@@ -81,11 +132,15 @@ export default function Sales() {
if (resp.data.result.list.length == 0) {
alert("조회 결과가 없습니다.");
setTableData([]);
setSumData([]);
return;
}
setShowQueryUid1(query_uid1);
setTableTotalCount(resp.data.result.totalCount);
setTableData(resp.data.result.list);
setSumData(resp.data.result.sum);
}
else {
alert("일시적으로 사용할 수 없습니다 : " + resp.data.errCode);
@@ -99,17 +154,26 @@ export default function Sales() {
//
// tree part //////////
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
/*
console.log("tokenPayload?.permission 11: ", tokenPayload?.permission);
if (tokenPayload?.permission == 0xffffffff)
console.log("tokenPayload?.permission 0xffffffff");
else
console.log("tokenPayload?.permission else......");*/
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -117,7 +181,9 @@ export default function Sales() {
}
else {
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
//reqSalesList(false, String(tokenPayload?.biz_group_id), tokenPayload?.permission == 1);
reqUid1List();
//reqSalesList(false, String(tokenPayload?.biz_group_id), tokenPayload?.permission == 0xffffffff);
reqSalesList(false, String(tokenPayload?.biz_group_id), isGroupAccess);
});
}
@@ -143,7 +209,7 @@ export default function Sales() {
const handleClickGroupAccess = (value: boolean) => {
setGroupAccess(value);
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (selectedTreeKeys.length <= 0) {
return;
}
@@ -181,19 +247,43 @@ export default function Sales() {
//
const handleChangeDateType = (e: React.ChangeEvent<HTMLSelectElement>) => {
setDateType(e.target.value);
changeListSelectedText(0, e.target.options[e.target.selectedIndex].text);
}
const handleChangeApprovalType = (e: React.ChangeEvent<HTMLSelectElement>) => {
setApprovalType(e.target.value);
changeListSelectedText(1, e.target.options[e.target.selectedIndex].text);
}
const handleChangeDeivceName = (e: React.ChangeEvent<HTMLInputElement>) => {
setDeivceName(e.target.value);
changeListSelectedText(2, e.target.value);
}
const handleChangeUid1 = (e: React.ChangeEvent<HTMLInputElement>) => {
setUid1(e.target.value);
changeListSelectedText(3, e.target.value);
}
//
useEffect(() => {
if (tokenPayload == undefined)
return;
if (tokenPayload?.permission == 1)
if (tokenPayload?.permission == 0xffffffff)
return;
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
setGroupAccess(tokenPayload?.permission == 1);
setTreeOpen(tokenPayload?.permission == 1);
reqUid1List();
reqSalesList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
setGroupAccess(tokenPayload?.permission == 0xffffffff);
setTreeOpen(tokenPayload?.permission == 0xffffffff);
reqSalesList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
}, [tokenPayload]);
useEffect(() => {
@@ -205,6 +295,7 @@ export default function Sales() {
{
title: "날짜",
key: "date",
viewMobile: true,
},
/*
{
@@ -215,14 +306,18 @@ export default function Sales() {
{
title: "무인기기명",
key: "device_name",
viewMobile: show_query_uid1,
hidden: !show_query_uid1,
},
{
title: "단말기TID",
key: "uid1",
hidden: !show_query_uid1,
},
{
title: "카드건수",
key: "card_count",
renderItem: (item : any) => (item.card_count.toLocaleString("ko-KR"))
},
{
title: "카드금액",
@@ -232,6 +327,7 @@ export default function Sales() {
{
title: "현금건수",
key: "cash_count",
renderItem: (item : any) => (item.cash_count.toLocaleString("ko-KR"))
},
{
title: "현금금액",
@@ -240,6 +336,7 @@ export default function Sales() {
},{
title: "T머니건수",
key: "tmoney_count",
renderItem: (item : any) => (item.tmoney_count.toLocaleString("ko-KR"))
},
{
title: "T머니금액",
@@ -248,6 +345,7 @@ export default function Sales() {
},{
title: "캐시비건수",
key: "cbee_count",
renderItem: (item : any) => (item.cbee_count.toLocaleString("ko-KR"))
},
{
title: "캐시비금액",
@@ -257,10 +355,59 @@ export default function Sales() {
{
title: "합계",
key: "total",
renderItem: (item : any) => (item.total.toLocaleString("ko-KR") + "원")
renderItem: (item : any) => (item.total.toLocaleString("ko-KR") + "원"),
viewMobile: true,
}
];
const sumColumns = [
{
title: "카드건수",
key: "card_count",
renderItem: (item : any) => (item.card_count.toLocaleString("ko-KR"))
},
{
title: "카드금액",
key: "card_amount",
renderItem: (item : any) => (item.card_amount.toLocaleString("ko-KR") + "원")
},
{
title: "현금건수",
key: "cash_count",
renderItem: (item : any) => (item.cash_count.toLocaleString("ko-KR"))
},
{
title: "현금금액",
key: "cash_amount",
renderItem: (item : any) => (item.cash_amount.toLocaleString("ko-KR") + "원")
},{
title: "T머니건수",
key: "tmoney_count",
renderItem: (item : any) => (item.tmoney_count.toLocaleString("ko-KR"))
},
{
title: "T머니금액",
key: "tmoney_amount",
renderItem: (item : any) => (item.tmoney_amount.toLocaleString("ko-KR") + "원")
},{
title: "캐시비건수",
key: "cbee_count",
renderItem: (item : any) => (item.cbee_count.toLocaleString("ko-KR"))
},
{
title: "캐시비금액",
key: "cbee_amount",
renderItem: (item : any) => (item.cbee_amount.toLocaleString("ko-KR") + "원")
},
{
title: "합계",
key: "total",
renderItem: (item : any) => (item.total.toLocaleString("ko-KR") + "원"),
}
];
const options = ["Option 1", "abcdefg", "Optio333333"];
return (
<div>
<PageBreadcrumb pageTitle1="매출 및 통계" pageTitle2="매출집계" />
@@ -276,7 +423,7 @@ export default function Sales() {
onChangeBizRegNum={setBizRegNum}
onClickSearch={handleClickGroupSearch}
isDisabled={isLoadingGlobal}
searchLabelWidth={SEARCH_LABEL_WIDTH}
searchLabelWidth={SEARCH_LABEL_WIDTH_PX}
>
<CtTree
treeData={treeData}
@@ -288,72 +435,86 @@ export default function Sales() {
onClickExpanded={handleClickTreeExpanded}
/>
</BizGroupPanel>
<ComponentCard title="매출 집계" titleIcon={<TableIcon />}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="일별/월별" label_width={SEARCH_LABEL_WIDTH}>
<Select
placeholder="선택하세요"
options={[
{ label: "일별집계", value: "1" },
{ label: "월별집계", value: "2" },
]}
defaultValue={date_type} onChange={(value) => setDateType(value)}
className="dark:bg-dark-900" />
</WithLabel>
<WithLabel label="승인/취소" label_width={SEARCH_LABEL_WIDTH}>
<Select
placeholder="선택하세요"
options={[
{ label: "전체", value: "0" },
{ label: "승인", value: "1" },
{ label: "취소", value: "2" },
]}
defaultValue={approval_type} onChange={(value) => setApprovalType(value)}
className="dark:bg-dark-900" />
</WithLabel>
<WithLabel label="무인기기명" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="승인번호를 입력하세요." value={device_name} onChange={(e) => setDeivceName(e.target.value)} />
</WithLabel>
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="금액을 입력하세요." value={uid1} onChange={(e) => setUid1(e.target.value)} />
</WithLabel>
</div>
<div className="space-y-3">
<CtDrawer title="상세 조회" isMobileMode={isMobileMode} setIsMobileMode={setIsMobileMode} isSearchFieldOpen={isSearchFieldOpen} setIsSearchFieldOpen={setIsSearchFieldOpen}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="일별/월별" label_width={SEARCH_LABEL_WIDTH_PX}>
<Select
//placeholder="선택하세요"
options={[
{ label: "일별집계", value: "1" },
{ label: "월별집계", value: "2" },
]}
defaultValue={date_type} onChange={handleChangeDateType}
className="dark:bg-dark-900" />
</WithLabel>
<WithLabel label="승인/취소" label_width={SEARCH_LABEL_WIDTH_PX}>
<Select
//placeholder="선택하세요"
options={[
{ label: "전체", value: "0" },
{ label: "승인", value: "1" },
{ label: "취소", value: "2" },
]}
defaultValue={approval_type} onChange={handleChangeApprovalType}
className="dark:bg-dark-900" />
</WithLabel>
<WithLabel label="무인기기명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="무인기기명을 입력하세요." value={device_name} onChange={handleChangeDeivceName} />
</WithLabel>
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH_PX}>
<InputSelectField type="text" placeholder="TID를 입력하세요." value={uid1} options={list_uid1} onChange={handleChangeUid1} />
</WithLabel>
</div>
</div>
</CtDrawer>
{/*<div className="space-y-3">*/}
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
<div className="flex items-center gap-3">
{ isTreeOpen && <>
<Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} />
<span className="block font-normal text-gray-700 text-theme-sm dark:text-gray-400">
</span>
</>}
<div className="flex items-center gap-5">
<Checkbox checked={query_uid1} onChange={(value) => setQueryUid1(value)} label="TID" />
</div>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
{ isMobileMode && <Button size="sm" variant="outline" startIcon={<FilterIcon />} onClick={() => setIsSearchFieldOpen(true)}></Button> }
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</div>
</div>
{/*</div>*/}
<div className="flex items-center justify-end gap-5">
{ isTreeOpen && <Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} label="그룹단위로 조회" /> }
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
<CtTable1 columns={columns} bodyData={tableData}
{ isMobileMode &&
<CtSelectedTextField label={"필터:"} listText={listSelectedText} setListText={setListSelectedText}></CtSelectedTextField>
}
<CtTable1 columns={columns} sumColumns={sumColumns} sumData={sumData} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
onClickPageChange={handlePageChange} />
</ComponentCard>
</div>
@@ -54,9 +54,11 @@ export default function AddModifyTerminalModal({ multiState, onOk, isOpen, close
multiState.set("uid1", value);
if (isAutoName) {
multiState.set("name", multiState.values.biz_group_name as string);
//multiState.set("name", multiState.values.biz_group_name + "-" + value); //...
//multiState.set("name", prefix + "-" + value); //...
multiState.set("name", prefix); //...
//multiState.set("name", prefix); //...
}
};
@@ -64,7 +66,7 @@ export default function AddModifyTerminalModal({ multiState, onOk, isOpen, close
setPrefix(randomUppercase(7)); //...
if (multiState.values.name == "") {
alert("그룹(사업자명)을 입력하셔야 합니다.");
alert("그룹(사업자)명을 입력하셔야 합니다.");
return;
}
@@ -133,7 +135,7 @@ export default function AddModifyTerminalModal({ multiState, onOk, isOpen, close
>
<div>
<Label></Label>
<Input type="text" value={multiState.values.biz_group_name + "(" + multiState.values.biz_reg_num + ")"} disabled />
<Input type="text" value={multiState.values.biz_group_name + (multiState.values.biz_reg_num ? `(${multiState.values.biz_reg_num})` : "")} disabled />
</div>
<div>
<div className="flex items-center gap-3">
@@ -160,7 +162,7 @@ export default function AddModifyTerminalModal({ multiState, onOk, isOpen, close
{ label: "NICE", value: "2" }
]}
defaultValue={multiState.values.type}
onChange={(value) => {setOptTerminalType(value)}}
onChange={(e) => {setOptTerminalType(e.target.value)}}
className="dark:bg-dark-900" />
</div>
{ multiState.values.isModify == false ? <>
@@ -173,7 +175,7 @@ export default function AddModifyTerminalModal({ multiState, onOk, isOpen, close
{ label: "카드단말기 교체용으로 추가", value: "2" }
]}
defaultValue={multiState.values.addType}
onChange={(value) => {setOptAddType(value)}}
onChange={(e) => {setOptAddType(e.target.value)}}
className="dark:bg-dark-900" />
</div>
</>
@@ -1,10 +1,10 @@
"use client"
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
import ComponentCard from '@/components/common/ComponentCard2';
import BizGroupPanel from "@/components/common/BizGroupPanel";
import BizGroupPanel from "@/components/BizGroupPanel";
import CtTable1 from '@/components/tables/CtTable1';
import Button from '@/components/ui/button/Button2';
import { DocsIcon, PlusIcon, TrashBinIcon, TableIcon, PencilIcon } from "@/icons";
import { DocsIcon, PlusIcon, TrashBinIcon, TableIcon, PencilIcon, FilterIcon } from "@/icons";
import WithLabel from '@/components/form/WithLabel';
import Input from '@/components/form/input/InputField2';
import Select from '@/components/form/Select2';
@@ -15,7 +15,7 @@ import Badge from "@/components/ui/badge/Badge";
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import { useRouter } from "next/navigation";
import api, { convertDateTime3, getUrlParam, postFileDownload, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, getUrlParam, postFileDownload, todayYMD, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyTerminalModal, { TerminalModalProps } from './AddModifyTerminalModal';
@@ -23,10 +23,13 @@ import { useMultiState } from "@/hooks/useMultiState";
import CtTree, { CtTreeNode, expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, addNodeByKey, deleteNodeByKey, findRootNodeByKey } from "@/components/CtTree";
import { reqBizGroupTree2, reqBizGroupTree3 } from "@/app/(admin)/biz-group/BizGroupContent";
import PageCountSelector from "@/components/PageCountSelector";
import CtDrawer from "@/components/CtDrawer";
import InputSelectField from "@/components/form/input/InputSelectField";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -38,28 +41,68 @@ export default function Terminal() {
const [ tableData, setTableData ] = useState<any[]>([]);
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
// group search fields
const [ name, setName] = useState<string>("");
const [ biz_reg_num, setBizRegNum] = useState<string>("");
// terminal search fields
const [ date_start, setDateStart] = useState<string>("");
const [ date_end, setDateEnd] = useState<string>("");
const [ group_name, setGroupName] = useState<string>("");
const [ device_name, setDeviceName ] = useState<string>("");
const [ uid1, setUid1 ] = useState<string>("");
const [ list_uid1, setListUid1 ] = useState<{label: string; value: string}[]>([]);
const [ state, setState ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
// modal
const { isOpen, openModal, closeModal } = useModal();
const modalData = useMultiState<TerminalModalProps>({biz_group_name: "", biz_reg_num: "", isModify: false, addType: "1", terminal_id: "", biz_group_id: "", name: "", uid1: "", type: "" });
const [ isMobileMode, setIsMobileMode ] = useState<boolean>(false);
const [ isSearchFieldOpen, setIsSearchFieldOpen ] = useState<boolean>(false);
const [ listSelectedText, setListSelectedText ] = useState<string[]>([]);
const changeListSelectedText = (index: number, text: string) => {
setListSelectedText(prev => {
const copy = [...prev];
copy[index] = text;
return copy;
});
}
// function part
//
function reqUid1List() {
api.post('/api/list-uid1.do').then((resp) => {
console.log(resp);
if (resp.data.errCode == 0) {
if (resp.data.result.list.length == 0) {
setListUid1([]);
return;
}
setListUid1(
resp.data.result.list.map((item: { uid1: string; name: string }) => ({
label: item.uid1 + (item.name !== "" ? " (" + item.name + ")" : ""),
value: item.uid1,
}))
);
}
})
.catch((err) => console.error(err))
}
function reqTerminalList(is_excel: boolean, biz_group_id: string, groupAccess: boolean) {
if (!biz_group_id)
return;
@@ -124,17 +167,17 @@ export default function Terminal() {
//
// tree part //////////
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -163,7 +206,7 @@ export default function Terminal() {
const handleClickGroupAccess = (value: boolean) => {
setGroupAccess(value);
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (selectedTreeKeys.length <= 0) {
return;
}
@@ -247,19 +290,40 @@ export default function Terminal() {
reqTerminalList(false, selectedTreeKeys[0] as string, isGroupAccess);
};
//
const handleChangeGroupName = (e: React.ChangeEvent<HTMLInputElement>) => {
setGroupName(e.target.value);
changeListSelectedText(1, e.target.value);
}
const handleChangeDeviceName = (e: React.ChangeEvent<HTMLInputElement>) => {
setDeviceName(e.target.value);
changeListSelectedText(0, e.target.value);
}
const handleChangeUid1 = (e: React.ChangeEvent<HTMLInputElement>) => {
setUid1(e.target.value);
changeListSelectedText(0, e.target.value);
}
const handleChangeState = (e: React.ChangeEvent<HTMLSelectElement>) => {
setState(e.target.value);
changeListSelectedText(2, e.target.options[e.target.selectedIndex].text);
}
useEffect(() => {
if (tokenPayload == undefined)
return;
if (tokenPayload?.permission == 1)
if (tokenPayload?.permission == 0xffffffff)
return;
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
setGroupAccess(tokenPayload?.permission == 1);
setTreeOpen(tokenPayload?.permission == 1);
reqUid1List();
reqTerminalList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
setGroupAccess(tokenPayload?.permission == 0xffffffff);
setTreeOpen(tokenPayload?.permission == 0xffffffff);
reqTerminalList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
}, [tokenPayload]);
@@ -274,11 +338,13 @@ export default function Terminal() {
{
title: "등록일",
key: "reg_time",
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time)
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time),
viewMobile: true,
},
{
title: "사업자",
key: "biz_group_name",
viewMobile: true,
},
{
title: "기기명",
@@ -287,7 +353,8 @@ export default function Terminal() {
{
title: "단말기 TID",
key: "uid1",
renderItem: (item: any, row: number) => (item.uid1 + " (" + (item.type == 1 ? "KICC" : "NICE") +")")
renderItem: (item: any, row: number) => (item.uid1 + " (" + (item.type == 1 ? "KICC" : "NICE") +")"),
viewMobile: true,
},
{
title: "무인기기 장착 여부",
@@ -335,7 +402,7 @@ export default function Terminal() {
onChangeBizRegNum={setBizRegNum}
onClickSearch={handleClickGroupSearch}
isDisabled={isLoadingGlobal}
searchLabelWidth={SEARCH_LABEL_WIDTH}
searchLabelWidth={SEARCH_LABEL_WIDTH_PX}
>
<CtTree
treeData={treeData}
@@ -349,33 +416,61 @@ export default function Terminal() {
</BizGroupPanel>
<ComponentCard title="카드단말기 목록" titleIcon={<TableIcon />}>
<div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
/>
</div>
</WithLabel>
<div className="flex items-center gap-3">
<Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} />
<span className="block font-normal text-gray-700 text-theme-sm dark:text-gray-400">
</span>
</div>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
<CtDrawer title="상세 조회" isMobileMode={isMobileMode} setIsMobileMode={setIsMobileMode} isSearchFieldOpen={isSearchFieldOpen} setIsSearchFieldOpen={setIsSearchFieldOpen}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="그룹명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="그룹명 입력하세요." value={group_name} onChange={handleChangeGroupName} />
</WithLabel>
<WithLabel label="무인기기명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="무인기기명을 입력하세요." value={device_name} onChange={handleChangeDeviceName} />
</WithLabel>
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH_PX}>
<InputSelectField type="text" placeholder="TID를 입력하세요." value={uid1} options={list_uid1} onChange={handleChangeUid1} />
</WithLabel>
<WithLabel label="기기장착여부" label_width={SEARCH_LABEL_WIDTH_PX}>
<Select
placeholder="전체"
options={[
{ label: "장착중", value: "1" },
{ label: "단말기만", value: "2" },
]}
defaultValue={state} onChange={handleChangeState}
className="dark:bg-dark-900" />
</WithLabel>
</div>
</div>
</CtDrawer>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
{ isMobileMode && <Button size="sm" variant="outline" startIcon={<FilterIcon />} onClick={() => setIsSearchFieldOpen(true)}></Button> }
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</div>
</div>
<div className="flex items-center justify-end gap-5">
{ isTreeOpen && <Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} label="그룹단위로 조회" /> }
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
<CtTable1 columns={columns} bodyData={tableData}
@@ -0,0 +1,150 @@
"use client";
import React, { useState, useRef, useEffect } from "react";
import CtModal from "@/components/CtModal";
import { useMultiState } from "@/hooks/useMultiState";
import api, { convertDateTime6 } from '@/lib/_AG';
import { toPng } from 'html-to-image';
import Button from "@/components/ui/button/Button2";
import { DocsIcon, DownloadIcon } from "@/icons";
export interface ReceiptModalProps {
order_time: string;
goods_name: string;
amount: number;
pay_name: string;
approval: string;
biz_group_name: string;
biz_reg_num: string;
ceo: string;
phone: string;
address: string;
}
interface ViewReceiptModalProps {
multiState: ReturnType<typeof useMultiState<ReceiptModalProps>>;
onOk: () => void;
isOpen: boolean;
closeModal: () => void;
}
export default function ReceiptModal({ multiState, onOk, isOpen, closeModal }: ViewReceiptModalProps) {
const tax = multiState.values.amount / 10;
const price = multiState.values.amount - tax;
const elementRef = useRef<HTMLDivElement>(null);
const handleDownload = async () => {
if (elementRef.current === null) {
return;
}
try {
const dataUrl = await toPng(elementRef.current, { cacheBust: true });
const link = document.createElement('a');
link.download = 'my-custom-image.png';
link.href = dataUrl;
link.click();
} catch (error) {
console.error('이미지 다운로드 중 오류 발생:', error);
}
};
return (
<CtModal
isOpen={isOpen}
closeModal={closeModal}
className="max-w-[500px] p-6 lg:p-10"
>
<div className="p-5" ref={elementRef}>
<div className="receipt w-[80mm] bg-white text-gray-900 px-5 py-5 mx-auto border border-gray-300 shadow-md text-[13px] leading-relaxed">
<h2 className="text-center text-lg font-bold mb-1">[]</h2>
<div className="text-center text-[11px] mb-5">
: {multiState.values.biz_group_name}<br />
: {multiState.values.address}<br />
: {multiState.values.biz_reg_num} | : {multiState.values.ceo}<br />
TEL: {multiState.values.phone}<br />
{convertDateTime6(multiState.values.order_time)}
</div>
<div className="border-t border-dashed border-black my-2.5" />
<table className="w-full border-collapse">
<thead>
<tr>
<th className="border-b border-black text-left pb-1"></th>
<th className="border-b border-black text-center pb-1"></th>
<th className="border-b border-black text-right pb-1"></th>
</tr>
</thead>
<tbody>
<tr>
<td className="py-1">{multiState.values.goods_name ? multiState.values.goods_name : "물품"}</td>
<td className="py-1 text-center">1</td>
<td className="py-1 text-right"> {multiState.values.amount.toLocaleString("ko-KR")}</td>
</tr>
</tbody>
</table>
<div className="border-t border-dashed border-black my-2.5" />
<table className="w-full border-collapse">
<tbody>
<tr>
<td className="py-1"> ( 1)</td>
<td className="py-1 text-right text-[15px] font-bold border-t-2 border-b-2 border-black"> {price.toLocaleString("ko-KR")}</td>
</tr>
<tr>
<td className="py-1">(10%)</td>
<td className="py-1 text-right"> {tax}</td>
</tr>
<tr>
<td className="py-1 text-[15px] font-bold border-t-2 border-b-2 border-black"> </td>
<td className="py-1 text-right text-[15px] font-bold border-t-2 border-b-2 border-black"> {multiState.values.amount.toLocaleString("ko-KR")}</td>
</tr>
</tbody>
</table>
<div className="border-t border-dashed border-black my-2.5" />
<table className="w-full border-collapse">
<tbody>
<tr>
<td className="py-1">결제수단: 신용카드 ()</td>
<td className="py-1 text-right"></td>
</tr>
{/*<tr>
<td className="py-1">카드번호: 1234-****-****-1234</td>
<td className="py-1 text-right"></td>
</tr>*/}
<tr>
<td className="py-1">: {multiState.values.pay_name}</td>
<td className="py-1 text-right"></td>
</tr>
<tr>
<td className="py-1">: {multiState.values.approval}</td>
<td className="py-1 text-right"></td>
</tr>
</tbody>
</table>
<div className="border-t border-dashed border-black my-2.5" />
<div className="text-center mt-5 text-[11px]">
- . -<br />
( )
</div>
</div>
</div>
<div className="flex items-center justify-center gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={() => window.print()}></Button>
<Button size="sm" variant="outline" startIcon={<DownloadIcon />} onClick={handleDownload}></Button>
</div>
</CtModal>
);
};
@@ -1,27 +1,34 @@
"use client"
import PageBreadcrumb from "@/components/common/PageBreadCrumb2";
import ComponentCard from '@/components/common/ComponentCard2';
import BizGroupPanel from "@/components/common/BizGroupPanel";
import BizGroupPanel from "@/components/BizGroupPanel";
import CtTable1 from '@/components/tables/CtTable1';
import Button from '@/components/ui/button/Button2';
import { DocsIcon, TableIcon, PlusIcon, TrashBinIcon, InfoIcon } from "@/icons";
import { DocsIcon, TableIcon, PlusIcon, TrashBinIcon, InfoIcon, FilterIcon } from "@/icons";
import WithLabel from '@/components/form/WithLabel';
import Input from '@/components/form/input/InputField2';
import DatePicker from '@/components/form/date-picker2';
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime3, convertDateTime4, convertDateTime6, postFileDownload, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, convertDateTime4, convertDateTime6, postFileDownload, todayYMD, useAuthStore, useUiLoadingStore } from '@/lib/_AG';
import api2 from '@/lib/_AG';
import CtTree, { CtTreeNode, findNodeByKey, findRootNodeByKey } from "@/components/CtTree";
import { reqBizGroupTree2, reqBizGroupTree3 } from "../biz-group/BizGroupContent";
import Checkbox from "@/components/form/input/Checkbox";
import Badge from "@/components/ui/badge/Badge";
import Select from "@/components/form/Select2";
import CtSelectedTextField from "@/components/CtSelectedText";
import CtDrawer from "@/components/CtDrawer";
import { useModal } from "@/hooks/useModal";
import { useMultiState } from "@/hooks/useMultiState";
import ReceiptModal, { ReceiptModalProps } from "./ReceiptModal";
import PageCountSelector from "@/components/PageCountSelector";
import InputSelectField from "@/components/form/input/InputSelectField";
const SEARCH_LABEL_WIDTH = 24;
const COUNT_PER_PAGE = 10;
const SEARCH_LABEL_WIDTH_PX = 80;
//const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -29,35 +36,75 @@ export default function Transactions() {
const tokenPayload = useAuthStore((s) => s.tokenPayload); //Bruce, JWT
const isLoadingGlobal = useUiLoadingStore((s) => s.isLoading);
const [ sumData, setSumData ] = useState<any[]>([]);
const [ tableData, setTableData ] = useState<any[]>([]);
const [ tableOffset, setTableOffset ] = useState<number>(0);
const [ tableTotalCount, setTableTotalCount ] = useState<number>(0);
const [ COUNT_PER_PAGE, setCOUNT_PER_PAGE ] = useState<number>(20);
const [ treeData, setTreeData ] = useState<CtTreeNode[]>([]);
const [ selectedTreeKeys, setSelectedTreeKeys ] = useState<Key[]>([]);
const [ expandedTreeKeys, setExpandedTreeKeys ] = useState<Key[]>([]);
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 1); //TempCode
const [ isGroupAccess, setGroupAccess ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
const [ isTreeOpen, setTreeOpen ] = useState(tokenPayload?.permission == 0xffffffff); //TempCode
// group search fields
const [ name, setName ] = useState<string>("");
const [ biz_reg_num, setBizRegNum ] = useState<string>("");
//search fields
const [ device_name, setDeviceName ] = useState<string>("");
const [ uid1, setUid1 ] = useState<string>("");
const [ list_uid1, setListUid1 ] = useState<{label: string; value: string}[]>([]);
const [ amount, setAmount ] = useState<string>("");
const [ type, setType ] = useState<string>("");
const [ approval, setApproval ] = useState<string>("");
const [ slot, setSlot ] = useState<string>("");
const [ column_no, setSlot ] = useState<string>("");
const [ code, setCode ] = useState<string>("");
const [ goods_name, setGoodsName ] = useState<string>("");
const [ pay_vendor, setPayVendor ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
const [ pay_name, setPayName ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>(addDaysYMD(-7));
const [ date_end, setDateEnd ] = useState<string>(todayYMD());
const { isOpen, openModal, closeModal } = useModal();
const modalData = useMultiState<ReceiptModalProps>({order_time: "", goods_name: "", amount: 0, pay_name: "", approval: "", biz_group_name: "", biz_reg_num: "", ceo: "", phone: "", address: ""});
const [ isMobileMode, setIsMobileMode ] = useState<boolean>(false);
const [ isSearchFieldOpen, setIsSearchFieldOpen ] = useState<boolean>(false);
const [ listSelectedText, setListSelectedText ] = useState<string[]>([]);
const changeListSelectedText = (index: number, text: string) => {
setListSelectedText(prev => {
const copy = [...prev];
copy[index] = text;
return copy;
});
}
//function part
//
function reqUid1List() {
api.post('/api/list-uid1.do').then((resp) => {
console.log(resp);
if (resp.data.errCode == 0) {
if (resp.data.result.list.length == 0) {
setListUid1([]);
return;
}
setListUid1(
resp.data.result.list.map((item: { uid1: string; name: string }) => ({
label: item.uid1 + (item.name !== "" ? " (" + item.name + ")" : ""),
value: item.uid1,
}))
);
}
})
.catch((err) => console.error(err))
}
function reqTransactionList(is_excel: boolean, biz_group_id: string, groupAccess: boolean) {
if (!biz_group_id)
return;
@@ -67,14 +114,15 @@ export default function Transactions() {
is_excel: is_excel,
offset: tableOffset,
limit: COUNT_PER_PAGE,
device_name: device_name,
uid1: uid1,
amount: amount,
type: type,
approval: approval,
slot: slot,
column_no: column_no,
code: code,
goods_name: goods_name,
pay_vendor: pay_vendor,
pay_name: pay_name,
date_start: date_start,
date_end: date_end,
biz_group_id: biz_group_id,
@@ -110,17 +158,17 @@ export default function Transactions() {
//
// tree part //////////
const handleClickGroupSearch = () => {
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (name == "" && biz_reg_num == "") {
alert("그룹(사업자명) 또는 사업자등록번호를 입력하셔야 합니다.");
alert("그룹(사업자)명 또는 사업자등록번호를 입력하셔야 합니다.");
return;
}
if (name != "" && name.length < 3) {
alert("그룹(사업자명)글자 이상 입력해야 합니다.");
if (name != "" && name.length < 2) {
alert("그룹(사업자)명은 글자 이상 입력해야 합니다.");
return;
}
if (biz_reg_num != "" && biz_reg_num.length < 3) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
if (biz_reg_num != "" && biz_reg_num.length < 2) {
alert("사업자등록번호는 글자 이상 입력해야 합니다.");
return;
}
@@ -128,7 +176,9 @@ export default function Transactions() {
}
else {
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
//reqTransactionList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
reqUid1List();
//reqTransactionList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
reqTransactionList(false, String(resp.data.result.tree[0].key), isGroupAccess);
});
}
@@ -154,7 +204,7 @@ export default function Transactions() {
const handleClickGroupAccess = (value: boolean) => {
setGroupAccess(value);
if (tokenPayload?.permission == 1) {
if (tokenPayload?.permission == 0xffffffff) {
if (selectedTreeKeys.length <= 0) {
return;
}
@@ -189,7 +239,25 @@ export default function Transactions() {
setTableOffset((page - 1) * COUNT_PER_PAGE);
};
const handleRowClickReceipt = (row: number) => {
const node = findRootNodeByKey(treeData, String(tokenPayload?.biz_group_id));
modalData.setAll({...tableData[row],
biz_group_name: node.name,
biz_reg_num: node.biz_reg_num,
ceo: node.ceo,
phone: node.phone,
address: node.address,
});
openModal();
};
const handleRowClickDelete = (row: number) => {
const permission = tokenPayload?.permission ?? 0;
if ((permission & 0x8) !== 0x8) {
alert("권한이 없습니다.");
return;
}
if (tableData[row].type != "D1" && tableData[row].type != "I1" &&
tableData[row].type != "TM1" && tableData[row].type != "EB1") {
alert("이미 취소 처리된 항목입니다.");
@@ -221,21 +289,72 @@ export default function Transactions() {
});
}
};
//
const handleModalOk = () => {
closeModal();
}
//
const handleChangeDeviceName = (e: React.ChangeEvent<HTMLInputElement>) => {
setDeviceName(e.target.value);
changeListSelectedText(0, e.target.value);
}
const handleChangeUid1 = (e: React.ChangeEvent<HTMLInputElement>) => {
setUid1(e.target.value);
changeListSelectedText(0, e.target.value);
}
const handleChangeAmount = (e: React.ChangeEvent<HTMLInputElement>) => {
setAmount(e.target.value);
changeListSelectedText(1, e.target.value);
}
const handleChangeType = (e: React.ChangeEvent<HTMLSelectElement>) => {
setType(e.target.value);
changeListSelectedText(2, e.target.options[e.target.selectedIndex].text);
}
const handleChangeApproval = (e: React.ChangeEvent<HTMLInputElement>) => {
setApproval(e.target.value);
changeListSelectedText(3, e.target.value);
}
const handleChangeSlot = (e: React.ChangeEvent<HTMLInputElement>) => {
setSlot(e.target.value);
changeListSelectedText(4, e.target.value);
}
const handleChangeCode = (e: React.ChangeEvent<HTMLInputElement>) => {
setCode(e.target.value);
changeListSelectedText(5, e.target.value);
}
const handleChangeGoodsName = (e: React.ChangeEvent<HTMLInputElement>) => {
setGoodsName(e.target.value);
changeListSelectedText(6, e.target.value);
}
const handleChangePayName = (e: React.ChangeEvent<HTMLInputElement>) => {
setPayName(e.target.value);
changeListSelectedText(7, e.target.value);
}
useEffect(() => {
if (tokenPayload == undefined)
return;
if (tokenPayload?.permission == 1)
if (tokenPayload?.permission == 0xffffffff)
return;
reqBizGroupTree3(String(tokenPayload?.biz_group_id), setTreeData, setSelectedTreeKeys, setExpandedTreeKeys, (resp: any) => {
setGroupAccess(tokenPayload?.permission == 1);
setTreeOpen(tokenPayload?.permission == 1);
reqUid1List();
reqTransactionList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 1);
setGroupAccess(tokenPayload?.permission == 0xffffffff);
setTreeOpen(tokenPayload?.permission == 0xffffffff);
reqTransactionList(false, String(resp.data.result.tree[0].key), tokenPayload?.permission == 0xffffffff);
});
}, [tokenPayload]);
@@ -255,22 +374,23 @@ export default function Transactions() {
{
title: "거래시간",
key: "order_time",
renderItem: (item: any, row: number) => convertDateTime6(item.order_time)
renderItem: (item: any, row: number) => convertDateTime6(item.order_time),
viewMobile: true,
},
/*
{
title: "무인기기명",
key: "device_name",
},
*/
{
title: "단말기 TID",
key: "uid1",
viewMobile: true,
},
{
title: "금액",
key: "amount",
renderItem: (item : any) => (item.amount.toLocaleString("ko-KR") + "원")
renderItem: (item : any) => (item.amount.toLocaleString("ko-KR") + "원"),
viewMobile: true,
},
{
title: "결제유형",
@@ -304,7 +424,7 @@ export default function Transactions() {
},
{
title: "컬럼번호",
key: "slot",
key: "column_no",
},
{
title: "상품코드",
@@ -315,31 +435,61 @@ export default function Transactions() {
key: "goods_name",
},
{
title: "결제서비스업체",
key: "pay_vendor",
title: "결제카드",
key: "pay_name",
renderItem: (item : any) => (
item.type === "TM1" ? "티머니" :
item.type === "TM4" ? "티머니" :
item.type === "EB1" ? "캐시비" :
item.type === "EB4" ? "캐시비" :
item.pay_vendor
item.pay_name
)
},
{
title: "영수증",
key: "_",
renderItem: (item: any, row: number) => (
item.type == "D1" ?
<div>
<DocsIcon
className="cursor-pointer hover:fill-error-500 dark:hover:fill-error-500 fill-gray-700 dark:fill-gray-400"
onClick={() => {handleRowClickReceipt(row)}} />
</div>
: ""
),
},
{
title: "취소요청",
key: "_",
renderItem: (item: any, row: number) => (
item.type == "D1" ?
<div>
/*<div>
<InfoIcon
className="cursor-pointer hover:fill-error-500 dark:hover:fill-error-500 fill-gray-700 dark:fill-gray-400"
onClick={() => {handleRowClickDelete(row)}} />
</div>
<Badge size="sm" color={"error"} ></Badge>
<div className="px-4 py-1.5 text-start text-theme-xs text-gray-600 dark:text-gray-400 transition-colors">
<span className="inline-flex items-center py-0.5 justify-center gap-1 rounded-full font-medium text-theme-xs bg-error-50 text-error-600 dark:bg-error-500/15 dark:text-error-500"></span>
</div>*/
<button className="inline-flex items-center px-1 py-0.5 justify-center gap-1 rounded font-medium text-theme-xs bg-error-50 text-error-600 dark:bg-error-500/15 dark:text-error-500"
onClick={() => {handleRowClickDelete(row)}}>
</button>
: ""
),
},
];
const sumColumns = [
{
title: "결제 금액 합계",
key: "amount",
renderItem: (item : any) => (item.amount.toLocaleString("ko-KR") + "원"),
viewMobile: true,
},
];
return (
<div>
<PageBreadcrumb pageTitle1="매출 및 통계" pageTitle2="거래내역 조회" />
@@ -355,7 +505,7 @@ export default function Transactions() {
onChangeBizRegNum={setBizRegNum}
onClickSearch={handleClickGroupSearch}
isDisabled={isLoadingGlobal}
searchLabelWidth={SEARCH_LABEL_WIDTH}
searchLabelWidth={SEARCH_LABEL_WIDTH_PX}
>
<CtTree
treeData={treeData}
@@ -369,83 +519,96 @@ export default function Transactions() {
</BizGroupPanel>
<ComponentCard title="거래내역 목록" titleIcon={<TableIcon />}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="단말기 TID를 입력하세요." value={uid1} onChange={(e) => setUid1(e.target.value)} />
</WithLabel>
<WithLabel label="금액" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="금액을 입력하세요." value={amount} onChange={(e) => setAmount(e.target.value)} />
</WithLabel>
<WithLabel label="결제유형" label_width={SEARCH_LABEL_WIDTH}>
<Select
placeholder="선택하세요"
options={[
{ label: "신용승인", value: "D1" },
{ label: "신용취소", value: "D4" },
{ label: "페이승인", value: "I1" },
{ label: "페이취소", value: "I4" },
{ label: "현금", value: "B1" },
{ label: "티머니승인", value: "TM1" },
{ label: "캐니비승인", value: "EB1" },
]}
defaultValue={type} onChange={(value) => setType(value)}
className="dark:bg-dark-900" />
</WithLabel>
<WithLabel label="승인번호" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="승인번호를 입력하세요." value={approval} onChange={(e) => setApproval(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="컬럼번호" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="컬럼번호를 입력하세요." value={slot} onChange={(e) => setSlot(e.target.value)} />
</WithLabel>
<WithLabel label="상품코드" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="상품코드를 입력하세요." value={code} onChange={(e) => setCode(e.target.value)} />
</WithLabel>
<WithLabel label="상품명" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="상품명을 입력하세요." value={goods_name} onChange={(e) => setGoodsName(e.target.value)} />
</WithLabel>
<WithLabel label="결제업체" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="결제업체를 입력하세요." value={pay_vendor} onChange={(e) => setPayVendor(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
/>
</div>
</WithLabel>
<div className="flex items-center gap-3">
{ isTreeOpen && <>
<Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} />
<span className="block font-normal text-gray-700 text-theme-sm dark:text-gray-400">
</span>
</>}
<CtDrawer title="상세 조회" isMobileMode={isMobileMode} setIsMobileMode={setIsMobileMode} isSearchFieldOpen={isSearchFieldOpen} setIsSearchFieldOpen={setIsSearchFieldOpen}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-5">
<WithLabel label="무인기기명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="무인기기명을 입력하세요." value={device_name} onChange={handleChangeDeviceName} />
</WithLabel>
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH_PX}>
<InputSelectField type="text" placeholder="TID를 입력하세요." value={uid1} options={list_uid1} onChange={handleChangeUid1} />
</WithLabel>
<WithLabel label="금액" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="number" placeholder="금액을 입력하세요." value={amount} onChange={handleChangeAmount} />
</WithLabel>
<WithLabel label="결제유형" label_width={SEARCH_LABEL_WIDTH_PX}>
<Select
placeholder="전체"
options={[
{ label: "신용승인", value: "D1" },
{ label: "신용취소", value: "D4" },
{ label: "페이승인", value: "I1" },
{ label: "페이취소", value: "I4" },
{ label: "현금", value: "B1" },
{ label: "티머니승인", value: "TM1" },
{ label: "캐니비승인", value: "EB1" },
]}
defaultValue={type} onChange={handleChangeType}
className="dark:bg-dark-900" />
</WithLabel>
<WithLabel label="승인번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="승인번호를 입력하세요." value={approval} onChange={handleChangeApproval} />
</WithLabel>
</div>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="컬럼번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="컬럼번호를 입력하세요." value={column_no} onChange={handleChangeSlot} />
</WithLabel>
<WithLabel label="상품코드" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="상품코드를 입력하세요." value={code} onChange={handleChangeCode} />
</WithLabel>
<WithLabel label="상품명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="상품명을 입력하세요." value={goods_name} onChange={handleChangeGoodsName} />
</WithLabel>
<WithLabel label="결제카드" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="결제업체를 입력하세요." value={pay_name} onChange={handleChangePayName} />
</WithLabel>
</div>
</div>
</CtDrawer>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
<div className="flex items-center justify-end gap-5">
<Button size="sm" variant="outline" startIcon={<DocsIcon />} onClick={handleClickDownload}> </Button>
{ isMobileMode && <Button size="sm" variant="outline" startIcon={<FilterIcon />} onClick={() => setIsSearchFieldOpen(true)}></Button> }
<Button size="sm" variant="primary" onClick={handleClickSearch} disabled={isLoadingGlobal}></Button>
</div>
</div>
<CtTable1 columns={columns} bodyData={tableData}
<div className="flex items-center justify-end gap-5">
{ isTreeOpen && <Checkbox checked={isGroupAccess} onChange={(value) => handleClickGroupAccess(value)} label="그룹단위로 조회" /> }
<PageCountSelector defaultValue={COUNT_PER_PAGE.toString()} onChange={(e) => setCOUNT_PER_PAGE(parseInt(e.target.value))} />
</div>
{ isMobileMode &&
<CtSelectedTextField label={"필터:"} listText={listSelectedText} setListText={setListSelectedText}></CtSelectedTextField>
}
<CtTable1 columns={columns} sumColumns={sumColumns} sumData={sumData} bodyData={tableData}
offset={tableOffset} totalCount={tableTotalCount} countPerPage={COUNT_PER_PAGE} pageNumCount={PAGE_NUM_COUNT}
onClickPageChange={handlePageChange} />
</ComponentCard>
<ReceiptModal multiState={modalData} onOk={handleModalOk} isOpen={isOpen} closeModal={closeModal} />
</div>
</div>
);
@@ -10,7 +10,7 @@ import DatePicker from '@/components/form/date-picker2';
import React, { Key } from "react";
import { useEffect, useState } from 'react';
import api, { convertDateTime3, convertDateTime4, convertDateTime6, useAuthStore } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, convertDateTime4, convertDateTime6, todayYMD, useAuthStore } from '@/lib/_AG';
import api2 from '@/lib/_AG';
import CtTree, { CtTreeNode, findNodeByKey } from "@/components/CtTree";
import { reqBizGroupTree2, reqBizGroupTree3 } from "../biz-group/BizGroupContent";
@@ -19,7 +19,7 @@ import Badge from "@/components/ui/badge/Badge";
import Select from "@/components/form/Select2";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -36,10 +36,10 @@ export default function UndefinedTransactions() {
const [ amount, setAmount ] = useState<string>("");
const [ type, setType ] = useState<string>("");
const [ approval, setApproval ] = useState<string>("");
const [ slot, setSlot ] = useState<string>("");
const [ column_no, setSlot ] = useState<string>("");
const [ code, setCode ] = useState<string>("");
const [ goods_name, setGoodsName ] = useState<string>("");
const [ pay_vendor, setPayVendor ] = useState<string>("");
const [ pay_name, setPayName ] = useState<string>("");
const [ date_start, setDateStart ] = useState<string>("");
const [ date_end, setDateEnd ] = useState<string>("");
@@ -54,10 +54,10 @@ export default function UndefinedTransactions() {
amount: amount,
type: type,
approval: approval,
slot: slot,
column_no: column_no,
code: code,
goods_name: goods_name,
pay_vendor: pay_vendor,
pay_name: pay_name,
date_start: date_start,
date_end: date_end,
}
@@ -152,7 +152,8 @@ export default function UndefinedTransactions() {
{
title: "거래시간",
key: "order_time",
renderItem: (item: any, row: number) => convertDateTime6(item.order_time)
renderItem: (item: any, row: number) => convertDateTime6(item.order_time),
viewMobile: true,
},
/*
{
@@ -163,11 +164,13 @@ export default function UndefinedTransactions() {
{
title: "단말기 TID",
key: "uid1",
viewMobile: true,
},
{
title: "금액",
key: "amount",
renderItem: (item : any) => (item.amount.toLocaleString("ko-KR") + "원")
renderItem: (item : any) => (item.amount.toLocaleString("ko-KR") + "원"),
viewMobile: true,
},
{
title: "결제유형",
@@ -200,7 +203,7 @@ export default function UndefinedTransactions() {
},
{
title: "컬럼번호",
key: "slot",
key: "column_no",
},
{
title: "상품코드",
@@ -211,14 +214,14 @@ export default function UndefinedTransactions() {
key: "goods_name",
},
{
title: "결제서비스업체",
key: "pay_vendor",
title: "결제카드",
key: "pay_name",
renderItem: (item : any) => (
item.type === "TM1" ? "티머니" :
item.type === "TM4" ? "티머니" :
item.type === "EB1" ? "캐시비" :
item.type === "EB4" ? "캐시비" :
item.pay_vendor
item.pay_name
)
},
{
@@ -245,13 +248,13 @@ export default function UndefinedTransactions() {
<ComponentCard title="거래내역 목록" titleIcon={<TableIcon />}>
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="단말기 TID" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="단말기 TID를 입력하세요." value={uid1} onChange={(e) => setUid1(e.target.value)} />
</WithLabel>
<WithLabel label="금액" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="금액" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="금액을 입력하세요." value={amount} onChange={(e) => setAmount(e.target.value)} />
</WithLabel>
<WithLabel label="결제유형" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="결제유형" label_width={SEARCH_LABEL_WIDTH_PX}>
<Select
placeholder="선택하세요"
options={[
@@ -263,39 +266,41 @@ export default function UndefinedTransactions() {
{ label: "티머니승인", value: "TM1" },
{ label: "캐니비승인", value: "EB1" },
]}
defaultValue={type} onChange={(value) => setType(value)}
defaultValue={type} onChange={(e) => setType(e.target.value)}
className="dark:bg-dark-900" />
</WithLabel>
<WithLabel label="승인번호" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="승인번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="승인번호를 입력하세요." value={approval} onChange={(e) => setApproval(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-4">
<WithLabel label="컬럼번호" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="컬럼번호를 입력하세요." value={slot} onChange={(e) => setSlot(e.target.value)} />
<WithLabel label="컬럼번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="컬럼번호를 입력하세요." value={column_no} onChange={(e) => setSlot(e.target.value)} />
</WithLabel>
<WithLabel label="상품코드" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="상품코드" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="상품코드를 입력하세요." value={code} onChange={(e) => setCode(e.target.value)} />
</WithLabel>
<WithLabel label="상품명" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="상품명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="상품명을 입력하세요." value={goods_name} onChange={(e) => setGoodsName(e.target.value)} />
</WithLabel>
<WithLabel label="결제업체" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="결제업체를 입력하세요." value={pay_vendor} onChange={(e) => setPayVendor(e.target.value)} />
<WithLabel label="결제업체" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="결제카드를 입력하세요." value={pay_name} onChange={(e) => setPayName(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -12,14 +12,14 @@ import Badge from "@/components/ui/badge/Badge";
import React from "react";
import { useEffect, useState } from 'react';
import { useRouter } from "next/navigation";
import api, { convertDateTime3 } from '@/lib/_AG';
import api, { addDaysYMD, convertDateTime3, todayYMD } from '@/lib/_AG';
import { useModal } from "@/hooks/useModal";
import AddModifyVocModal, {VocModalProps} from './AddModifyVocModal';
import { useMultiState } from "@/hooks/useMultiState";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -115,7 +115,8 @@ export default function Voc() {
{
title: "등록일",
key: "reg_time",
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time)
renderItem: (item: any, row: number) => convertDateTime3(item.reg_time),
viewMobile: true,
},
{
title: "수정일",
@@ -132,6 +133,7 @@ export default function Voc() {
{
title: "제목",
key: "title",
viewMobile: true,
},
{
title: "고객명",
@@ -182,28 +184,30 @@ export default function Voc() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="제목" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="제목을 입력하세요." value={title} onChange={(e) => setTitle(e.target.value)} />
</WithLabel>
<WithLabel label="고객명" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="고객명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 고객명을 입력하세요." value={name} onChange={(e) => setName(e.target.value)} />
</WithLabel>
<WithLabel label="작성자 아이디" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="작성자 아이디" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 작성자 아이디를 입력하세요." value={uid1} onChange={(e) => setUid1(e.target.value)} />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
onChange={(dates, currentDateString) => { setDateStart(currentDateString); }}
defaultDate={date_start}
/>
<DatePicker
id="date_end-picker"
placeholder="조회 종료일"
onChange={(dates, currentDateString) => { setDateEnd(currentDateString); }}
defaultDate={date_end}
/>
</div>
</WithLabel>
@@ -11,7 +11,7 @@ import { useForm } from 'react-hook-form';
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -18,7 +18,7 @@ import { useModal } from "@/hooks/useModal";
import AddTest2ViewModal from './AddTest2ViewModal';
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -128,8 +128,8 @@ export default function Test2View() {
{ value: "error", label: "장애" },
];
const handleSelectChange = (value: string) => {
console.log("Selected value:", value);
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
console.log("Selected value:", e.target.value);
};
const handlePageChange = (page: number) => {
@@ -19,7 +19,7 @@ import AddTest2ViewModal from './AddTest2ViewModal';
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -123,8 +123,8 @@ export default function DeviceStatus() {
const { isOpen, openModal, closeModal } = useModal();
const handleSelectChange = (value: string) => {
console.log("Selected value:", value);
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
console.log("Selected value:", e.target.value);
};
const handlePageChange = (page: number) => {
@@ -41,7 +41,7 @@ export default function AddModifyGroupModal({ isOpen, openModal, closeModal }: A
<div className="mt-8"></div>
<div className="space-y-6">
<div>
<Label>()</Label>
<Label>()</Label>
<Input type="text" />
</div>
<div>
@@ -18,7 +18,7 @@ import AddModifyGroupModal from './AddModifyGroupModal';
import CtTree, { expandAndSelectTreeNode, getAllNodeKeys, findParentKeys, findNodeByKey, deleteNodeByKey } from "@/components/CtTree";
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
const COUNT_PER_PAGE = 10;
const PAGE_NUM_COUNT = 5;
@@ -30,7 +30,7 @@ const columns = [
key: "reg_time" ,
},
{
title: "그룹(사업자명)",
title: "그룹(사업자)명",
key: "name",
},
{
@@ -298,7 +298,7 @@ export default function BizGroup() {
};
const SEARCH_LABEL_WIDTH = 24;
const SEARCH_LABEL_WIDTH_PX = 80;
return (
<div>
@@ -309,27 +309,27 @@ export default function BizGroup() {
<div className="space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="그룹(사업자명)" label_width={SEARCH_LABEL_WIDTH}>
<Input type="text" placeholder="조회할 그룹(사업자명)을 입력하세요." />
<WithLabel label="그룹(사업자)명" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 그룹(사업자)명을 입력하세요." />
</WithLabel>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="사업자번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 사업자번호를 입력하세요." />
</WithLabel>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="이메일" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 이메일를 입력하세요." />
</WithLabel>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<WithLabel label="전화번호" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="전화번호" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 전화번호를 입력하세요." />
</WithLabel>
<WithLabel label="주소" label_width={SEARCH_LABEL_WIDTH}>
<WithLabel label="주소" label_width={SEARCH_LABEL_WIDTH_PX}>
<Input type="text" placeholder="조회할 주소를 입력하세요." />
</WithLabel>
</div>
<div className="space-y-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={SEARCH_LABEL_WIDTH}>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="등록일" label_width={50}>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-2">
<DatePicker
id="date_start-picker"
placeholder="조회 시작일"
+5 -1
View File
@@ -16,7 +16,11 @@
--breakpoint-lg: 1024px;
--breakpoint-xl: 1280px;
--breakpoint-2xl: 1536px;
--text-sm--line-height: 18px;
--text-base: 14px;
*/
--text-sm: 13px;
--breakpoint-*: initial;
--breakpoint-2xsm: 640px;
@@ -200,7 +204,7 @@
cursor: pointer;
}
body {
@apply relative font-normal font-outfit z-1 bg-gray-50;
@apply relative font-normal font-outfit z-1 bg-gray-50 dark:bg-gray-900;
}
}
+13 -6
View File
@@ -1,13 +1,20 @@
import { Outfit } from 'next/font/google';
//import { Outfit } from 'next/font/google';
import localFont from 'next/font/local';
import './globals.css';
import { SidebarProvider } from '@/context/SidebarContext';
import { ThemeProvider } from '@/context/ThemeContext';
import CustomAlertProvider from '@/components/common/CustomAlertProvider';
const outfit = Outfit({
subsets: ["latin"],
});
//const outfit = Outfit({
// subsets: ["latin"],
//});
const pretendard = localFont({
src: '../../public/fonts/PretendardVariable.woff2',
display: 'swap',
weight: '45 920',
})
export default function RootLayout({
children,
@@ -15,8 +22,8 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${outfit.className} dark:bg-gray-900`}>
<html lang="ko" className={pretendard.className}>
<body>
<ThemeProvider>
<SidebarProvider>
<CustomAlertProvider>{children}</CustomAlertProvider>
@@ -47,12 +47,13 @@ export default function BizGroupPanel({
>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<ComponentCard>
<div className="flex-1 space-y-6">
<div className="flex-1 space-y-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<WithLabel label="그룹(사업자명)" label_width={searchLabelWidth}>
{/*<WithLabel label="그룹(사업자)명" label_width={searchLabelWidth}>*/}
<WithLabel label="그룹(사업자)명" label_width={90}>
<Input
type="text"
placeholder="조회할 그룹(사업자명) 입력하세요."
placeholder="조회할 그룹(사업자)명 입력하세요."
value={name}
onChange={(e) => onChangeName(e.target.value)}
onKeyDown={(e) => {
@@ -0,0 +1,62 @@
import React, { useEffect, useState } from "react";
import { TableIcon } from "@/icons/index";
interface CtDrawerProps {
title?: string;
isMobileMode: boolean;
setIsMobileMode: React.Dispatch<React.SetStateAction<boolean>>;
isSearchFieldOpen: boolean;
setIsSearchFieldOpen: React.Dispatch<React.SetStateAction<boolean>>;
children: React.ReactNode;
}
const CtDrawer: React.FC<CtDrawerProps> = ({
title,
isMobileMode,
setIsMobileMode,
isSearchFieldOpen,
setIsSearchFieldOpen,
children,
}) => {
useEffect(() => {
const handleResize = () => {
setIsMobileMode(window.innerWidth < 768);
//console.log("isMobileMode = ", isMobileMode);
};
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
if (!isMobileMode)
return children;
//if (isSearchFieldOpen)
return (<>
{/*<div className="fixed inset-0 bg-black/30 bg-opacity-50 z-100000 transition-opacity" aria-hidden="true" />
<div className="fixed inset-y-0 right-0 w-90 bg-white shadow-lg p-4 z-100001 transition-transform duration-300 overflow-y-auto overscroll-contain md:hidden">*/}
<div
className={`fixed inset-0 bg-black/30 z-100000 transition-opacity duration-300 ease-in-out
${isSearchFieldOpen ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}
aria-hidden="true"
onClick={() => setIsSearchFieldOpen(false)}
/>
<div
className={`fixed inset-y-0 right-0 w-90 bg-white dark:bg-gray-900 shadow-lg p-4 z-100001 transition-transform duration-300 ease-in-out overflow-y-auto overscroll-contain md:hidden
${isSearchFieldOpen ? 'translate-x-0' : 'translate-x-full'}`}
>
<div className="flex justify-between">
<span className="text-lg font-semibold text-gray-800 dark:text-white/90">{title}</span>
<button onClick={() => setIsSearchFieldOpen(false)} className="w-6 h-6 border border-gray-400 dark:border-gray-700 rounded flex items-center justify-center text-gray-600 dark:text-gray-400"></button>
</div>
<div className="border-b border-gray-300 dark:border-gray-800 mt-2 mb-4"></div>
{children}
</div>
</>);
//return "";
};
export default CtDrawer;
@@ -6,7 +6,7 @@ import Input from '@/components/form/input/InputField2';
interface CtModalProps {
title: string,
title?: string,
description?: string,
children: ReactNode;
okBtnText?: string;
@@ -28,7 +28,7 @@ export default function CtModal({ title, description, children, okBtnText, onCli
<div className="flex flex-col px-2 overflow-y-auto custom-scrollbar">
<div>
<h5 className="mb-2 font-semibold text-gray-800 modal-title text-theme-xl dark:text-white/90 lg:text-2xl">
{title}
{title ? title : ""}
</h5>
<p className="text-sm text-gray-500 dark:text-gray-400">
{description}
@@ -0,0 +1,79 @@
import React, { useEffect, useState } from "react";
import Label from "./form/Label2";
const CtSelectedText = ({
text,
remove,
} : {
text: string;
remove?: () => void;
}) => {
return (
<div className="group flex items-center justify-center rounded-full border-[0.7px] border-transparent bg-gray-100 py-1 pl-2.5 pr-2 text-sm text-gray-800 hover:border-gray-200 dark:bg-gray-800 dark:text-white/90 dark:hover:border-gray-800">
<span className="flex-initial max-w-full">{text}</span>
<div className="flex flex-row-reverse flex-auto">
{remove &&
<div className="pl-2 text-gray-500 cursor-pointer group-hover:text-gray-400 dark:text-gray-400"
onClick={() => remove()}>
<svg
className="fill-current"
role="button"
width="14"
height="14"
viewBox="0 0 14 14"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.40717 4.46881C3.11428 4.17591 3.11428 3.70104 3.40717 3.40815C3.70006 3.11525 4.17494 3.11525 4.46783 3.40815L6.99943 5.93975L9.53095 3.40822C9.82385 3.11533 10.2987 3.11533 10.5916 3.40822C10.8845 3.70112 10.8845 4.17599 10.5916 4.46888L8.06009 7.00041L10.5916 9.53193C10.8845 9.82482 10.8845 10.2997 10.5916 10.5926C10.2987 10.8855 9.82385 10.8855 9.53095 10.5926L6.99943 8.06107L4.46783 10.5927C4.17494 10.8856 3.70006 10.8856 3.40717 10.5927C3.11428 10.2998 3.11428 9.8249 3.40717 9.53201L5.93877 7.00041L3.40717 4.46881Z"
/>
</svg>
</div>
}
</div>
</div>
);
}
const CtSelectedTextField = ({
label,
listText,
setListText,
} : {
label?: string;
listText: string[];
setListText?: React.Dispatch<React.SetStateAction<string[]>>;
}) => {
if (label)
return (
<div className="flex gap-2">
<div style={{ width: "36px" }}>
<Label className="translate-y-1 text-right">{label}</Label>
</div>
<div className="flex-1">
<div className="flex flex-wrap flex-auto gap-2">
{ listText.map((text, index) => (
text !== "" && <CtSelectedText key={index} text={text}></CtSelectedText>
))}
</div>
</div>
</div>
);
return (
<div className="flex flex-wrap flex-auto gap-2">
{ listText.map((text, index) => (
text !== "" && <CtSelectedText key={index} text={text}></CtSelectedText>
))}
</div>
);
}
export default CtSelectedTextField;
@@ -248,7 +248,7 @@ export default function CtTree({ treeData, selectedKeys, setSelectedKeys, onClic
useEffect(() => {
const handleGlobalClick = (event: any) => {
if (event.target.matches('.rc-tree-treenode')) {
console.log("event.target = ", event.target)
//console.log("event.target = ", event.target)
setSelectedKeys([]);
}
@@ -260,7 +260,7 @@ export default function CtTree({ treeData, selectedKeys, setSelectedKeys, onClic
const switcherIcon = (nodeProps: any) => {
console.log("nodeProps = ", nodeProps);
//console.log("nodeProps = ", nodeProps);
//const hasChildren = nodeProps?.data?.children && nodeProps.data.children.length > 0;
//if (hasChildren == undefined || hasChildren == null) return null;
if (nodeProps.isLeaf) return null;
@@ -284,7 +284,7 @@ export default function CtTree({ treeData, selectedKeys, setSelectedKeys, onClic
{loading && (
<div className="absolute inset-0 flex items-center justify-center bg-white/50 dark:bg-gray-900/40">
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300">
<span className="h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-brand-500"></span>
<span className="h-4 w-4 animate-spin rounded-full border-2 border-gray-300 dark:border-gray-700 border-t-brand-500 dark:border-t-brand-500"></span>
...
</div>
</div>
@@ -6,9 +6,10 @@ import Select from '@/components/form/Select2';
import Button from "./ui/button/Button2";
import WithLabel from "./form/WithLabel";
import { PlusIcon } from "@/icons";
import InputSelectField from "./form/input/InputSelectField";
interface DeviceGoodsItem {
slot: string;
column_no: string;
goods_id: number;
price?: number;
inventory?: number;
@@ -156,18 +157,20 @@ export default function DeviceGoodsList({
<Input
type="text"
placeholder="컬럼번호2"
value={item.slot}
value={item.column_no}
onChange={(e) => onSlotChange(index, e.target.value)}
/>
</div>
<div className="w-50">
<Select
{/*<Select
placeholder="상품을 선택하세요"
options={optGoodsList}
defaultValue={item.goods_id == 0 ? "" : String(item.goods_id)}
onChange={(value) => onGoodsChange(index, value)}
onChange={(e) => onGoodsChange(index, e.target.value)}
className="dark:bg-dark-900"
/>
/>*/}
<InputSelectField type="text" placeholder="상품을 선택하세요." value={item.goods_id == 0 ? "" : optGoodsList.find(opt => opt.value === String(item.goods_id))?.label}
options={optGoodsList} selectLabel={true} onChange={(e) => onGoodsChange(index, e.target.value)} />
</div>
<div className={"w-24"}>
<Input
@@ -0,0 +1,28 @@
import React from "react";
import Select from "./form/Select2";
interface PageCountSelectorProps {
defaultValue?: string;
onChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
}
const PageCountSelector: React.FC<PageCountSelectorProps> = ({
defaultValue,
onChange,
}) => {
return (
<div className="flex items-center justify-end">
<Select
options={[
{ label: "20개씩 보기", value: "20" },
{ label: "30개씩 보기", value: "30" },
{ label: "40개씩 보기", value: "40" },
{ label: "50개씩 보기", value: "50" },
]}
defaultValue={defaultValue} onChange={onChange} className="dark:bg-dark-900" />
</div>
);
};
export default PageCountSelector;
@@ -27,7 +27,7 @@ const ComponentCard: React.FC<ComponentCardProps> = ({
>
{/* Card Header */}
{ title &&
<div className="px-6 py-3 flex items-center">
<div className="px-4 py-3 flex items-center">
<div className="flex items-center gap-1">
<h3 className="flex text-base font-medium text-gray-800 dark:text-white/90">
<span className="inline-flex gap-2 mr-5">{titleIcon}{title}</span>
@@ -41,7 +41,7 @@ const ComponentCard: React.FC<ComponentCardProps> = ({
{topUi}
{ setOpen &&
<button onClick={() => setOpen(!isOpen)}
className="ml-5 flex h-10 w-10 items-center justify-center rounded-full bg-gray-100 duration-200 ease-linear dark:bg-white/[0.03] text-gray-800 dark:text-white/90 rotate-180">
className="ml-3 flex h-8 w-8 items-center justify-center rounded-full bg-gray-100 duration-200 ease-linear dark:bg-white/[0.03] text-gray-800 dark:text-white/90 rotate-180">
<svg className={`stroke-current transform transition-transform duration-300 ease-in-out ${isOpen ? "rotate-0" : "rotate-180"}`}
width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.75 8.875L12 15.125L18.25 8.875" stroke="" strokeWidth="2" strokeLinecap="round" ></path>
@@ -52,13 +52,19 @@ const ComponentCard: React.FC<ComponentCardProps> = ({
}
{/* Card Body */}
{ (isOpen === undefined || isOpen === true) && React.Children.map(children, (item, index) => {
return (
<div key={index} className="p-4 border-t border-gray-100 dark:border-gray-800 sm:p-6">
<div className="space-y-6">{item}</div>
{ //(isOpen === undefined || isOpen === true) && React.Children.map(children, (item, index) => {
/*(isOpen === undefined || isOpen === true) && React.Children.toArray(children).filter(Boolean).map((item, index) => {
return (
<div key={index} className="p-4 border-t border-gray-100 dark:border-gray-800 sm:p-6">
<div className="space-y-6">{item}</div>
</div>
)
})*/
(isOpen === undefined || isOpen === true) &&
<div className="p-4 border-t border-gray-100 dark:border-gray-800 sm:p-6 space-y-3">
{children}
</div>
)
})}
}
</div>
);
};
@@ -0,0 +1,130 @@
import React, { useState } from "react";
interface Option {
value: string;
text: string;
selected: boolean;
}
interface InputSelectProps {
label: string;
options: Option[];
defaultSelected?: string[];
onChange?: (selected: string[]) => void;
disabled?: boolean;
}
const InputSelect: React.FC<InputSelectProps> = ({
label,
options,
defaultSelected = [],
onChange,
disabled = false,
}) => {
const [selectedOptions, setSelectedOptions] =
useState<string[]>(defaultSelected);
const [isOpen, setIsOpen] = useState(false);
const toggleDropdown = () => {
if (disabled) return;
setIsOpen((prev) => !prev);
};
const handleSelect = (optionValue: string) => {
const newSelectedOptions = selectedOptions.includes(optionValue)
? selectedOptions.filter((value) => value !== optionValue)
: [...selectedOptions, optionValue];
setSelectedOptions(newSelectedOptions);
if (onChange) onChange(newSelectedOptions);
};
const removeOption = (index: number, value: string) => {
const newSelectedOptions = selectedOptions.filter((opt) => opt !== value);
setSelectedOptions(newSelectedOptions);
if (onChange) onChange(newSelectedOptions);
};
const selectedValuesText = selectedOptions.map(
(value) => options.find((option) => option.value === value)?.text || ""
);
return (
<div className="w-full">
<label className="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
{label}
</label>
<div className="relative z-20 inline-block w-full">
<div className="relative flex flex-col items-center">
<div onClick={toggleDropdown} className="w-full">
<div className="mb-2 flex h-11 rounded-lg border border-gray-300 py-1.5 pl-3 pr-3 shadow-theme-xs outline-hidden transition focus:border-brand-300 focus:shadow-focus-ring dark:border-gray-700 dark:bg-gray-900 dark:focus:border-brand-300">
<div className="flex flex-wrap flex-auto gap-2">
<input
placeholder="Select option"
className="w-full h-full p-1 pr-2 text-sm bg-transparent border-0 outline-hidden appearance-none placeholder:text-gray-800 focus:border-0 focus:outline-hidden focus:ring-0 dark:placeholder:text-white/90"
/>
</div>
<div className="flex items-center py-1 pl-1 pr-1 w-7">
<button
type="button"
onClick={toggleDropdown}
className="w-5 h-5 text-gray-700 outline-hidden cursor-pointer focus:outline-hidden dark:text-gray-400"
>
<svg
className={`stroke-current ${isOpen ? "rotate-180" : ""}`}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.79175 7.39551L10.0001 12.6038L15.2084 7.39551"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
</div>
</div>
</div>
{isOpen && (
<div
className="absolute left-0 z-40 w-full overflow-y-auto bg-white rounded-lg shadow-sm top-full max-h-select dark:bg-gray-900"
onClick={(e) => e.stopPropagation()}
>
<div className="flex flex-col">
{options.map((option, index) => (
<div key={index}>
<div
className={`hover:bg-primary/5 w-full cursor-pointer rounded-t border-b border-gray-200 dark:border-gray-800`}
onClick={() => handleSelect(option.value)}
>
<div
className={`relative flex w-full items-center p-2 pl-2 ${
selectedOptions.includes(option.value)
? "bg-primary/10"
: ""
}`}
>
<div className="mx-2 leading-6 text-gray-800 dark:text-white/90">
{option.text}
</div>
</div>
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
);
};
export default InputSelect;
@@ -9,14 +9,16 @@ interface Option {
interface SelectProps {
options: Option[];
placeholder?: string;
onChange: (value: string) => void;
//onChange: (value: string) => void;
onChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
className?: string;
defaultValue?: string;
}
const Select: React.FC<SelectProps> = ({
options,
placeholder = "Select an option",
//placeholder = "Select an option",
placeholder,
onChange,
className = "",
defaultValue = "",
@@ -27,7 +29,8 @@ const Select: React.FC<SelectProps> = ({
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
setSelectedValue(value);
onChange(value); // Trigger parent handler
//onChange(value); // Trigger parent handler
onChange(e); // Trigger parent handler
};
@@ -40,7 +43,7 @@ const Select: React.FC<SelectProps> = ({
<div className="relative">
<select
className={`h-11 w-full appearance-none rounded-lg border border-gray-300 px-4 py-2.5 pr-11 text-sm shadow-theme-xs placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 ${
className={`h-10 w-full appearance-none rounded-lg border border-gray-300 px-2 py-1.5 pr-11 text-sm shadow-theme-xs placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 ${
selectedValue
? "text-gray-800 dark:text-white/90"
: "text-gray-400 dark:text-gray-400"
@@ -49,6 +52,7 @@ const Select: React.FC<SelectProps> = ({
onChange={handleChange}
>
{/* Placeholder option */}
{ placeholder &&
<option
value=""
//disabled
@@ -56,6 +60,7 @@ const Select: React.FC<SelectProps> = ({
>
{placeholder}
</option>
}
{/* Map over options */}
{options.map((option) => (
<option
@@ -12,7 +12,10 @@ export default function WithLabel({
}) {
return (
<div className="flex gap-2">
<Label className={`w-${label_width} translate-y-3 text-right`}>{label}</Label>
{/*<Label className={`w-${label_width} translate-y-3 text-right`}>{label}</Label>*/}
<div style={{ width: `${label_width}px` }}>
<Label className="translate-y-3 text-right">{label}</Label>
</div>
<div className="flex-1">
{children}
</div>
@@ -52,7 +52,7 @@ export default function DatePicker({
<input
id={id}
placeholder={placeholder}
className="h-11 w-full rounded-lg border appearance-none px-4 py-2.5 text-sm shadow-theme-xs placeholder:text-gray-400 focus:outline-hidden focus:ring-3 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 bg-transparent text-gray-800 border-gray-300 focus:border-brand-300 focus:ring-brand-500/20 dark:border-gray-700 dark:focus:border-brand-800"
className="h-10 w-full rounded-lg border appearance-none px-3 py-1.5 text-sm shadow-theme-xs placeholder:text-gray-400 focus:outline-hidden focus:ring-3 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 bg-transparent text-gray-800 border-gray-300 focus:border-brand-300 focus:ring-brand-500/20 dark:border-gray-700 dark:focus:border-brand-800"
/>
<span className="absolute text-gray-500 -translate-y-1/2 pointer-events-none right-3 top-1/2 dark:text-gray-400">
@@ -19,7 +19,8 @@ const Checkbox: React.FC<CheckboxProps> = ({
}) => {
return (
<label
className={`flex items-center space-x-3 group cursor-pointer ${
//Bruce className={`flex items-center space-x-3 group cursor-pointer ${
className={`flex items-center space-x-2 group cursor-pointer ${
disabled ? "cursor-not-allowed opacity-60" : ""
}`}
>
@@ -38,7 +38,7 @@ const Input: FC<InputProps> = ({
hint,
}) => {
// Determine input styles based on state (disabled, success, error)
let inputClasses = `h-11 w-full rounded-lg border appearance-none px-4 py-2.5 text-sm shadow-theme-xs placeholder:text-gray-400 focus:outline-hidden focus:ring-3 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 ${className}`;
let inputClasses = `h-10 w-full rounded-lg border appearance-none px-2 py-1.5 text-sm shadow-theme-xs placeholder:text-gray-400 focus:outline-hidden focus:ring-3 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 ${className}`;
// Add styles for the different states
if (disabled) {
@@ -0,0 +1,262 @@
import React, { FC, useState, useEffect, useRef } from "react";
interface Option {
value: string;
label: string;
}
interface InputSelectFieldProps {
type?: "text" | "number" | "email" | "password" | "date" | "time" | string;
id?: string;
name?: string;
placeholder?: string;
defaultValue?: string | number;
value?: string | number;
options: Option[];
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
className?: string;
min?: string;
max?: string;
step?: number;
selectLabel?: boolean;
disableKeyboard?: boolean;
disabled?: boolean;
success?: boolean;
error?: boolean;
hint?: string;
}
const InputSelectField: FC<InputSelectFieldProps> = ({
type = "text",
id,
name,
placeholder,
defaultValue,
value,
options,
onChange,
onKeyDown,
className = "",
min,
max,
step,
selectLabel = false,
disableKeyboard = false,
disabled = false,
success = false,
error = false,
hint,
}) => {
const [isOpen, setIsOpen] = useState(false);
const [highlightedIndex, setHighlightedIndex] = useState(-1);
const [inputText, setInputText] = useState<string>(
String(value ?? defaultValue ?? "")
);
const wrapperRef = useRef<HTMLDivElement>(null);
const filteredOptions = options.filter((option) =>
disableKeyboard ? option : option.value.toLowerCase().includes(inputText.toLowerCase())
);
const toggleDropdown = () => {
if (disabled)
return;
setIsOpen((prev) => !prev);
setHighlightedIndex(filteredOptions.length === 1 ? 0 : -1);
};
const fireChange = (optionValue: string) => {
if (onChange) {
onChange({
target: { value: optionValue },
currentTarget: { value: optionValue },
nativeEvent: new Event('change'),
bubbles: true,
cancelable: false,
defaultPrevented: false,
eventPhase: 0,
isTrusted: true,
preventDefault: () => {},
isDefaultPrevented: () => false,
stopPropagation: () => {},
isPropagationStopped: () => false,
persist: () => {},
timeStamp: Date.now(),
type: 'change'
} as React.ChangeEvent<HTMLInputElement>);
}
};
const handleSelect = (optionValue: string) => {
setInputText(optionValue);
fireChange(optionValue);
setIsOpen(false);
setHighlightedIndex(-1);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputText(e.target.value);
setIsOpen(true);
setHighlightedIndex(-1);
onChange?.(e);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
onKeyDown?.(e);
if (disabled) return;
switch (e.key) {
case "ArrowDown":
e.preventDefault();
if (!isOpen) {
setIsOpen(true);
setHighlightedIndex(0);
} else if (filteredOptions.length > 1) {
setHighlightedIndex((prev) => (prev + 1) % filteredOptions.length);
}
break;
case "ArrowUp":
e.preventDefault();
if (!isOpen) {
setIsOpen(true);
setHighlightedIndex(filteredOptions.length - 1);
} else if (filteredOptions.length > 1) {
setHighlightedIndex(
(prev) => (prev - 1 + filteredOptions.length) % filteredOptions.length
);
}
break;
case "Enter":
e.preventDefault();
if (filteredOptions.length === 1) {
handleSelect(filteredOptions[0].value);
} else if (
isOpen &&
highlightedIndex >= 0 &&
highlightedIndex < filteredOptions.length
) {
handleSelect(filteredOptions[highlightedIndex].value);
}
break;
case "Escape":
setIsOpen(false);
setHighlightedIndex(-1);
break;
//case "ArrowLeft":
//case "ArrowRight":
//case "Delete":
//case "Backspace":
break;
default:
if (disableKeyboard) {
e.preventDefault();
return;
}
break;
}
};
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) {
setIsOpen(false);
setHighlightedIndex(-1);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
useEffect(() => {
if (value !== undefined) {
setInputText(String(value));
}
}, [value]);
let inputClasses = `h-10 w-full rounded-lg border appearance-none px-2 py-1.5 text-sm shadow-theme-xs placeholder:text-gray-400 focus:outline-hidden focus:ring-3 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800 ${className}`;
if (disabled) {
inputClasses += ` text-gray-500 border-gray-300 cursor-not-allowed bg-gray-100 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-700`;
} else if (error) {
inputClasses += ` text-error-800 border-error-500 focus:ring-3 focus:ring-error-500/10 dark:text-error-400 dark:border-error-500`;
} else if (success) {
inputClasses += ` text-success-500 border-success-400 focus:ring-success-500/10 focus:border-success-300 dark:text-success-400 dark:border-success-500`;
} else {
inputClasses += ` bg-transparent text-gray-800 border-gray-300 focus:border-brand-300 focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:focus:border-brand-800`;
}
return (
<div className="relative" ref={wrapperRef}>
<input
type={type}
id={id}
name={name}
placeholder={placeholder}
value={inputText}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
onClick={toggleDropdown}
min={min}
max={max}
step={step}
disabled={disabled}
className={inputClasses}
/>
{hint && (
<p
className={`mt-1.5 text-xs ${
error ? "text-error-500" : success ? "text-success-500" : "text-gray-500"
}`}
>
{hint}
</p>
)}
{isOpen && filteredOptions.length > 0 && (
<div
className="absolute left-0 z-40 w-full overflow-y-auto bg-white rounded-lg shadow-sm top-full max-h-70 dark:bg-gray-900"
onClick={(e) => e.stopPropagation()}
>
<div className="flex flex-col">
{filteredOptions.map((option, index) => (
<div key={index}>
<div
className={`w-full cursor-pointer rounded-t border-b border-gray-200 dark:border-gray-800 ${
index === highlightedIndex
? "bg-slate-100 dark:bg-gray-800"
: "hover:bg-slate-50 dark:hover:bg-white/5"
}`}
onMouseEnter={() => setHighlightedIndex(index)}
onClick={() => handleSelect(selectLabel ? option.label : option.value)}
>
<div className={`relative flex w-full items-center p-2 pl-1`}>
<div className="mx-2 leading-6 text-xs text-gray-800 dark:text-white/90">
{option.label}
</div>
</div>
</div>
</div>
))}
</div>
</div>
)}
</div>
);
};
export default InputSelectField;

Some files were not shown because too many files have changed in this diff Show More