Compare commits
7
Commits
cac5f79a40
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd26c0c9b7 | ||
|
|
5ac3011085 | ||
|
|
055a2bed6d | ||
|
|
fa473e8728 | ||
|
|
eb9b91cb7c | ||
|
|
1de5589ef2 | ||
|
|
2e56108a3b |
@@ -12,7 +12,7 @@ public class ChgrResponseDto {
|
|||||||
private String chgrId;
|
private String chgrId;
|
||||||
private String chgrNm;
|
private String chgrNm;
|
||||||
private String speedTp;
|
private String speedTp;
|
||||||
private String chgrTp;
|
private String chgrType;
|
||||||
private double gpsXpos;
|
private double gpsXpos;
|
||||||
private double gpsYpos;
|
private double gpsYpos;
|
||||||
private String locInfo;
|
private String locInfo;
|
||||||
@@ -29,7 +29,7 @@ public class ChgrResponseDto {
|
|||||||
chgr.setStNm(this.stNm);
|
chgr.setStNm(this.stNm);
|
||||||
chgr.setChgrNm(this.chgrNm);
|
chgr.setChgrNm(this.chgrNm);
|
||||||
chgr.setSpeedTp(this.speedTp);
|
chgr.setSpeedTp(this.speedTp);
|
||||||
chgr.setChgrTp(this.chgrTp);
|
chgr.setChgrTp(this.chgrType);
|
||||||
return chgr;
|
return chgr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ public class ChgrHist extends BaseStEntity {
|
|||||||
@Column(name = "CHGR_ID", nullable = false)
|
@Column(name = "CHGR_ID", nullable = false)
|
||||||
private String chgrId; // 충전기 id
|
private String chgrId; // 충전기 id
|
||||||
|
|
||||||
|
@Column(name = "CH_ID")
|
||||||
|
private Integer chId;
|
||||||
|
|
||||||
@Column(name = "ST_ID", nullable = false)
|
@Column(name = "ST_ID", nullable = false)
|
||||||
private String stId; // 충전소 id
|
private String stId; // 충전소 id
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public class ChgrHistController extends BaseController<ChgrHist,Integer,ChgrHist
|
|||||||
|
|
||||||
@GetMapping("list")
|
@GetMapping("list")
|
||||||
public String list() throws IllegalAccessException {
|
public String list() throws IllegalAccessException {
|
||||||
|
chgrHistService.getChgrHist();
|
||||||
return path+"list";
|
return path+"list";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ import org.springframework.stereotype.Repository;
|
|||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface ChgrHistRepository extends BaseRecStRepository<ChgrHist,Integer> {
|
public interface ChgrHistRepository extends BaseRecStRepository<ChgrHist,Integer> {
|
||||||
|
boolean existsByChgrIdAndChIdAndRechgEDt(String chgrId, Integer chId,String rechgEDt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public class ChgrHistResponseDto {
|
|||||||
chgrHist.setRechgAmt(this.rechgAmt);
|
chgrHist.setRechgAmt(this.rechgAmt);
|
||||||
chgrHist.setPayFnsh(this.payFnsh);
|
chgrHist.setPayFnsh(this.payFnsh);
|
||||||
chgrHist.setRechGwh(this.rechgWh);
|
chgrHist.setRechGwh(this.rechgWh);
|
||||||
|
chgrHist.setChId(this.chId);
|
||||||
return chgrHist;
|
return chgrHist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ public class ChgrHistService extends BaseService<ChgrHist, Integer, ChgrHistRepo
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Scheduled(cron = "0 */10 * * * *")
|
@Scheduled(cron = "0 */10 * * * *")
|
||||||
public void getChgrHist() throws IllegalAccessException {
|
public void getChgrHist() {
|
||||||
|
|
||||||
String startDt = LocalDate.now().toString();
|
String startDt = LocalDate.now().toString();
|
||||||
ApiResponse<List<ChgrHistResponseDto>> response = apiClient.fetchChgrHist(startDt, "50");
|
ApiResponse<List<ChgrHistResponseDto>> response = apiClient.fetchChgrHist(startDt, "50");
|
||||||
@@ -50,15 +50,18 @@ public class ChgrHistService extends BaseService<ChgrHist, Integer, ChgrHistRepo
|
|||||||
.map(ChgrHistResponseDto::toEntity)
|
.map(ChgrHistResponseDto::toEntity)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
int insertCount = 0;
|
||||||
for (ChgrHist h : entityList) {
|
for (ChgrHist h : entityList) {
|
||||||
Integer id = BaseService.getId(h);
|
|
||||||
|
|
||||||
if (id != null && super.repository.existsById(id)) {
|
boolean isExist = ((ChgrHistRepository) super.repository).existsByChgrIdAndChIdAndRechgEDt(h.getChgrId(), h.getChId(),h.getRechgEDt());
|
||||||
super.update(h);
|
|
||||||
} else {
|
if (!isExist) {
|
||||||
super.insert(h);
|
super.insert(h);
|
||||||
|
insertCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("충전이력 수집 완료: API 응답 {}건 중 신규 저장 {}건", entityList.size(), insertCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class ProviderController extends BaseController<Provider, String, Provide
|
|||||||
|
|
||||||
@GetMapping("list")
|
@GetMapping("list")
|
||||||
public String list() {
|
public String list() {
|
||||||
|
providerService.getProviders();
|
||||||
return path + "list";
|
return path + "list";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,8 +79,13 @@ public class ProviderService extends BaseService<Provider, String, ProviderRepos
|
|||||||
@Override
|
@Override
|
||||||
protected Specification<Provider> getSpecification(Provider srch) {
|
protected Specification<Provider> getSpecification(Provider srch) {
|
||||||
if (srch == null) return null;
|
if (srch == null) return null;
|
||||||
|
|
||||||
Specification<Provider> rst = null;
|
Specification<Provider> rst = null;
|
||||||
rst = addWhere(rst, srch.getProviderNm(), ProviderSpecification.providerNm(srch.getProviderNm()));
|
rst = addWhere(rst, srch.getProviderNm(), ProviderSpecification.providerNm(srch.getProviderNm()));
|
||||||
|
rst = addWhere(rst, srch.getBizTaxId(), ProviderSpecification.bizTaxId(srch.getBizTaxId()));
|
||||||
|
rst = addWhere(rst, srch.getCeo(), ProviderSpecification.ceo(srch.getCeo()));
|
||||||
|
rst = addWhere(rst, srch.getTel(), ProviderSpecification.tel(srch.getTel()));
|
||||||
|
rst = addWhere(rst, srch.getFax(), ProviderSpecification.fax(srch.getFax()));
|
||||||
return rst;
|
return rst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,28 @@
|
|||||||
package net.jwsi.jcms.vpp.provider;
|
package net.jwsi.jcms.vpp.provider;
|
||||||
|
|
||||||
|
import net.jwsi.jcms.utils.StrUtil;
|
||||||
|
import net.jwsi.jcms.vpp.rechgingList.RechgingList;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
|
||||||
public class ProviderSpecification {
|
public class ProviderSpecification {
|
||||||
|
|
||||||
public static Specification<Provider> providerNm(String providerNm) {
|
public static Specification<Provider> providerNm(String providerNm) {
|
||||||
return (root, query, criteriaBuilder) -> criteriaBuilder.like(root.get("providerNm"), "%"+providerNm+"%");
|
return (root, query, cb) -> cb.like(root.get("providerNm"), StrUtil.sqlLikeParam(providerNm));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Specification<Provider> bizTaxId(String bizTaxId) {
|
||||||
|
return (root, query, cb) -> cb.like(root.get("bizTaxId"), StrUtil.sqlLikeParam(bizTaxId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Specification<Provider> ceo(String ceo) {
|
||||||
|
return (root, query, cb) -> cb.like(root.get("ceo"), StrUtil.sqlLikeParam(ceo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Specification<Provider> tel(String tel) {
|
||||||
|
return (root, query, cb) -> cb.like(root.get("tel"), StrUtil.sqlLikeParam(tel));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Specification<Provider> fax(String fax) {
|
||||||
|
return (root, query, cb) -> cb.like(root.get("fax"), StrUtil.sqlLikeParam(fax));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public class RatePlanResponseDto {
|
|||||||
chargerRatePlan.setChargerCd(chargerDto.getChargerCd());
|
chargerRatePlan.setChargerCd(chargerDto.getChargerCd());
|
||||||
chargerRatePlan.setApplyStartDate(chargerDto.getApplyStartDate());
|
chargerRatePlan.setApplyStartDate(chargerDto.getApplyStartDate());
|
||||||
chargerRatePlan.setApplyEndDate(chargerDto.getApplyEndDate());
|
chargerRatePlan.setApplyEndDate(chargerDto.getApplyEndDate());
|
||||||
|
chargerRatePlan.setIsActive(chargerDto.getIsActive());
|
||||||
|
|
||||||
chargerRatePlanList.add(chargerRatePlan);
|
chargerRatePlanList.add(chargerRatePlan);
|
||||||
}
|
}
|
||||||
@@ -110,5 +111,6 @@ public class RatePlanResponseDto {
|
|||||||
private String chargerCd;
|
private String chargerCd;
|
||||||
private String applyStartDate;
|
private String applyStartDate;
|
||||||
private String applyEndDate;
|
private String applyEndDate;
|
||||||
|
private String isActive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,8 +48,32 @@ public class RatePlanService extends BaseService<RatePlan, Integer, RatePlanRepo
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<RatePlanResponseDto> dtoList = response.getData();
|
List<RatePlanResponseDto> dtoList = response.getData();
|
||||||
if (dtoList == null || dtoList.isEmpty()) {
|
if (dtoList == null) {
|
||||||
log.info("가져온 요금제 데이터가 없습니다.");
|
dtoList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
Set<Integer> validApiIds = dtoList.stream()
|
||||||
|
.map(RatePlanResponseDto::getRatePlanId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
List<RatePlan> localRatePlans = ratePlanRepository.findAll();
|
||||||
|
|
||||||
|
int deleteCount = 0;
|
||||||
|
for (RatePlan localPlan : localRatePlans) {
|
||||||
|
if (!validApiIds.contains(localPlan.getRatePlanId())) {
|
||||||
|
Integer idToDelete = localPlan.getRatePlanId();
|
||||||
|
|
||||||
|
ratePlanDetailTimeRepository.deleteByRatePlanId(idToDelete);
|
||||||
|
chargerRatePlanRepository.deleteByRatePlanId(idToDelete);
|
||||||
|
|
||||||
|
ratePlanRepository.deleteById(idToDelete);
|
||||||
|
|
||||||
|
deleteCount++;
|
||||||
|
log.info("운영 DB에서 삭제된 요금제를 로컬 DB에서 제거했습니다. - ID: {}", idToDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dtoList.isEmpty()) {
|
||||||
|
log.info("가져온 요금제 데이터가 없습니다. (로컬 동기화 및 삭제 완료. 삭제 건수: {})", deleteCount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +128,8 @@ public class RatePlanService extends BaseService<RatePlan, Integer, RatePlanRepo
|
|||||||
chargerRatePlanRepository.saveAll(allChargerRatePlans);
|
chargerRatePlanRepository.saveAll(allChargerRatePlans);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("요금제 동기화 완료: 마스터 {}건, 상세단가 {}건, 충전기매핑 {}건",
|
log.info("요금제 동기화 완료: 마스터 추가/수정 {}건, 삭제 {}건, 상세단가 {}건, 충전기매핑 {}건",
|
||||||
ratePlanEntities.size(), allDetailTimes.size(), allChargerRatePlans.size());
|
ratePlanEntities.size(), deleteCount, allDetailTimes.size(), allChargerRatePlans.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public RatePlanResponseDto getRatePlanDetail(Integer ratePlanId) {
|
public RatePlanResponseDto getRatePlanDetail(Integer ratePlanId) {
|
||||||
@@ -151,6 +175,7 @@ public class RatePlanService extends BaseService<RatePlan, Integer, RatePlanRepo
|
|||||||
cpDto.setChargerCd(cp.getChargerCd());
|
cpDto.setChargerCd(cp.getChargerCd());
|
||||||
cpDto.setApplyStartDate(cp.getApplyStartDate());
|
cpDto.setApplyStartDate(cp.getApplyStartDate());
|
||||||
cpDto.setApplyEndDate(cp.getApplyEndDate());
|
cpDto.setApplyEndDate(cp.getApplyEndDate());
|
||||||
|
cpDto.setIsActive(cp.getIsActive());
|
||||||
return cpDto;
|
return cpDto;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class RechgingListService extends BaseService<RechgingList, Long, Rechgin
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Scheduled(cron = "0 0 0 * * *")
|
@Scheduled(cron = "0 0/15 * * * *")
|
||||||
public void getRechgingList() {
|
public void getRechgingList() {
|
||||||
ApiResponse<List<RechgingListDto>> response = apiClient.fetchRechgingList();
|
ApiResponse<List<RechgingListDto>> response = apiClient.fetchRechgingList();
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ public class RechgingListService extends BaseService<RechgingList, Long, Rechgin
|
|||||||
rst = addWhere(rst, srch.getMemAuthInputNo(), RechgingListSpecification.memAuthInputNo(srch.getMemAuthInputNo()));
|
rst = addWhere(rst, srch.getMemAuthInputNo(), RechgingListSpecification.memAuthInputNo(srch.getMemAuthInputNo()));
|
||||||
rst = addWhere(rst, srch.getCreditPPayTrxNo(), RechgingListSpecification.creditPPayTrxNo(srch.getCreditPPayTrxNo()));
|
rst = addWhere(rst, srch.getCreditPPayTrxNo(), RechgingListSpecification.creditPPayTrxNo(srch.getCreditPPayTrxNo()));
|
||||||
rst = addWhere(rst, srch.getCreditPPayTrxDt(), RechgingListSpecification.creditPPayTrxDt(srch.getCreditPPayTrxDt()));
|
rst = addWhere(rst, srch.getCreditPPayTrxDt(), RechgingListSpecification.creditPPayTrxDt(srch.getCreditPPayTrxDt()));
|
||||||
rst = addWhere(rst, srch.getRechgSdt(), RechgingListSpecification.rechgSdt(srch.getRechgSdt()));
|
rst = addWhere(rst, srch.getRechgSdt(), RechgingListSpecification.rechgSdtBetween(srch.getRechgSdt()));
|
||||||
rst = addWhere(rst, srch.getPayType(), RechgingListSpecification.payType(srch.getPayType()));
|
rst = addWhere(rst, srch.getPayType(), RechgingListSpecification.payType(srch.getPayType()));
|
||||||
return rst;
|
return rst;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.jwsi.jcms.vpp.rechgingList;
|
|||||||
import net.jwsi.jcms.base.BaseSpecification;
|
import net.jwsi.jcms.base.BaseSpecification;
|
||||||
import net.jwsi.jcms.utils.StrUtil;
|
import net.jwsi.jcms.utils.StrUtil;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
public class RechgingListSpecification extends BaseSpecification {
|
public class RechgingListSpecification extends BaseSpecification {
|
||||||
|
|
||||||
@@ -34,10 +35,22 @@ public class RechgingListSpecification extends BaseSpecification {
|
|||||||
return (root, query, cb) -> cb.like(root.get("creditPPayTrxDt"), StrUtil.sqlLikeParam(creditPPayTrxDt));
|
return (root, query, cb) -> cb.like(root.get("creditPPayTrxDt"), StrUtil.sqlLikeParam(creditPPayTrxDt));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Specification<RechgingList> rechgSdt(String rechgSdt) {
|
public static Specification<RechgingList> rechgSdtBetween(String rechgSdt) {
|
||||||
return (root, query, cb) -> cb.like(root.get("rechgSdt"), StrUtil.sqlLikeParam(rechgSdt));
|
return (root, query, cb) -> {
|
||||||
|
// 날짜 파라미터가 없으면 검색 조건에서 제외 (null 반환)
|
||||||
|
if (!StringUtils.hasText(rechgSdt)) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 예: "2026-07-31" -> "2026-07-31 00:00:00" ~ "2026-07-31 23:59:59"
|
||||||
|
String startDateTime = rechgSdt.trim() + " 00:00:00";
|
||||||
|
String endDateTime = rechgSdt.trim() + " 23:59:59";
|
||||||
|
|
||||||
|
return cb.between(root.get("rechgSdt"), startDateTime, endDateTime);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Specification<RechgingList> payType(String payType) {
|
public static Specification<RechgingList> payType(String payType) {
|
||||||
return (root, query, cb) -> cb.like(root.get("payType"), StrUtil.sqlLikeParam(payType));
|
return (root, query, cb) -> cb.like(root.get("payType"), StrUtil.sqlLikeParam(payType));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ spring:
|
|||||||
datasource:
|
datasource:
|
||||||
jcms-db:
|
jcms-db:
|
||||||
driver-class-name: org.mariadb.jdbc.Driver
|
driver-class-name: org.mariadb.jdbc.Driver
|
||||||
jdbc-url: jdbc:mariadb://localhost:3306/jcmsdb
|
jdbc-url: jdbc:mariadb://192.168.62.37:3306/jcmsdb
|
||||||
username: root
|
username: root
|
||||||
password: jcms
|
password: jcms
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ spring:
|
|||||||
datasource:
|
datasource:
|
||||||
jcms-db:
|
jcms-db:
|
||||||
driver-class-name: org.mariadb.jdbc.Driver
|
driver-class-name: org.mariadb.jdbc.Driver
|
||||||
jdbc-url: jdbc:mariadb://192.168.62.37:33068/jcms
|
jdbc-url: jdbc:mariadb://dev.jinwoosi.co.kr:33091/jcms
|
||||||
username: jcms
|
username: jcms
|
||||||
password: ENC(nqt7VLhtxqwiJcQQw9ncNg==)
|
password: jw3593
|
||||||
jpa:
|
jpa:
|
||||||
entity-packages: net.jwsi.jcms
|
entity-packages: net.jwsi.jcms
|
||||||
show-sql: false
|
show-sql: false
|
||||||
|
|||||||
@@ -60,15 +60,18 @@
|
|||||||
if (strUtil.isNotEmpty($('#rechgEDtLike').val())) {d.rechgEDt = $('#rechgEDtLike').val();}
|
if (strUtil.isNotEmpty($('#rechgEDtLike').val())) {d.rechgEDt = $('#rechgEDtLike').val();}
|
||||||
if (strUtil.isNotEmpty($('#rechgTimeLike').val())) {d.rechgTime = $('#rechgTimeLike').val();}
|
if (strUtil.isNotEmpty($('#rechgTimeLike').val())) {d.rechgTime = $('#rechgTimeLike').val();}
|
||||||
if (strUtil.isNotEmpty($('#payFnshLike').val())) {d.payFnsh = $('#payFnshLike').val();}
|
if (strUtil.isNotEmpty($('#payFnshLike').val())) {d.payFnsh = $('#payFnshLike').val();}
|
||||||
|
if (strUtil.isNotEmpty($('#chIdLike').val())) {d.chId = $('#chIdLike').val();}
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
order: [[0, 'desc']],
|
order: [[5, 'desc']],
|
||||||
columns: [
|
columns: [
|
||||||
{title: "충전소 아이디", name: "ST_ID", data: "stId", className, orderable: false},
|
{title: "충전소 아이디", name: "ST_ID", data: "stId", className, orderable: false},
|
||||||
{title: "충전기 아이디", name: "CHGR_ID", data: "chgrId", className, orderable: false},
|
{title: "충전기 아이디", name: "CHGR_ID", data: "chgrId", className, orderable: false},
|
||||||
{title: "결제구분", name: "PAY_TP", data: "payTp", className, orderable: false},
|
{title: "결제구분", name: "PAY_TP", data: "payTp", className, orderable: false},
|
||||||
{title: "충전기타입 코드", name: "CHGR_TP", data: "plugTp", className, orderable: false},
|
{title: "채널", name: "CH_ID", data: "chId", className, orderable: false},
|
||||||
|
{title: "충전기타입 코드", name: "PLUG_TP", data: "plugTp", className, orderable: false},
|
||||||
{title: "충전 시작일시", name: "RECHG_S_DT", data: "rechgSDt", className, orderable: false},
|
{title: "충전 시작일시", name: "RECHG_S_DT", data: "rechgSDt", className, orderable: false},
|
||||||
{title: "충전 종료일시", name: "RECHG_E_DT", data: "rechgEDt", className, orderable: false},
|
{title: "충전 종료일시", name: "RECHG_E_DT", data: "rechgEDt", className, orderable: false},
|
||||||
{title: "충전시간", name: "RECHG_TIME", data: "rechgTime", className, orderable: false},
|
{title: "충전시간", name: "RECHG_TIME", data: "rechgTime", className, orderable: false},
|
||||||
@@ -134,6 +137,17 @@
|
|||||||
minLen: 0,
|
minLen: 0,
|
||||||
maxLen: 50,
|
maxLen: 50,
|
||||||
}),
|
}),
|
||||||
|
new ModalInput({
|
||||||
|
inputType: ModalInputType.text,
|
||||||
|
inputId: "chId",
|
||||||
|
inputName: "chId",
|
||||||
|
inputLabel: "채널",
|
||||||
|
inputPlaceholder: "채널",
|
||||||
|
isReq: false,
|
||||||
|
isEnable: true,
|
||||||
|
minLen: 0,
|
||||||
|
maxLen: 50,
|
||||||
|
}),
|
||||||
new ModalInput({
|
new ModalInput({
|
||||||
inputType: ModalInputType.textarea,
|
inputType: ModalInputType.textarea,
|
||||||
inputId: "payTp",
|
inputId: "payTp",
|
||||||
|
|||||||
@@ -57,61 +57,44 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#ratePlanDetailScrollArea {
|
#ratePlanDetailScrollArea { max-height: 65vh; overflow-y: auto; overflow-x: hidden; padding-right: 5px; }
|
||||||
max-height: 65vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
padding-right: 5px;
|
|
||||||
}
|
|
||||||
#ratePlanDetailScrollArea::-webkit-scrollbar { width: 6px; }
|
#ratePlanDetailScrollArea::-webkit-scrollbar { width: 6px; }
|
||||||
#ratePlanDetailScrollArea::-webkit-scrollbar-track { background: #f5f5f5; border-radius: 3px; }
|
#ratePlanDetailScrollArea::-webkit-scrollbar-track { background: #f5f5f5; border-radius: 3px; }
|
||||||
#ratePlanDetailScrollArea::-webkit-scrollbar-thumb { background: #d0d0d0; border-radius: 3px; }
|
#ratePlanDetailScrollArea::-webkit-scrollbar-thumb { background: #d0d0d0; border-radius: 3px; }
|
||||||
#ratePlanDetailScrollArea::-webkit-scrollbar-thumb:hover { background: #b5b5b5; }
|
#ratePlanDetailScrollArea::-webkit-scrollbar-thumb:hover { background: #b5b5b5; }
|
||||||
|
|
||||||
.custom-card { border: 1px solid #e5e5e5; border-radius: 0.25rem; margin-bottom: 1rem; background-color: #fff; }
|
.custom-card { border: 1px solid #e5e5e5; border-radius: 0.25rem; margin-bottom: 1rem; background-color: #fff; }
|
||||||
.custom-card-header { color: #333; font-weight: 600; font-size: 0.88rem; padding: 0.6rem 1rem; border-bottom: 1px solid #e5e5e5; background-color: #fafafa; }
|
.custom-card-header { color: #333; font-weight: 600; font-size: 0.88rem; padding: 0.6rem 1rem; border-bottom: 1px solid #e5e5e5; background-color: #fafafa; }
|
||||||
.custom-card-body { padding: 0.75rem 1rem; }
|
.custom-card-body { padding: 0.75rem 1rem; }
|
||||||
|
|
||||||
.info-table th, .info-table td { padding: 0.2rem 0.4rem !important; font-size: 0.85rem; color: #444; }
|
.info-table th, .info-table td { padding: 0.2rem 0.4rem !important; font-size: 0.85rem; color: #444; }
|
||||||
.info-table th { font-weight: 600; width: 110px; color: #222; white-space: nowrap; }
|
.info-table th { font-weight: 600; width: 110px; color: #222; white-space: nowrap; }
|
||||||
.info-table td { width: 100%; }
|
.info-table td { width: 100%; }
|
||||||
|
|
||||||
.price-table { font-size: 0.85rem; border-color: #e5e5e5; }
|
.price-table { font-size: 0.85rem; border-color: #e5e5e5; }
|
||||||
.price-table th, .price-table td { border-color: #e5e5e5; padding: 0.5rem; }
|
.price-table th, .price-table td { border-color: #e5e5e5; padding: 0.5rem; }
|
||||||
.price-table thead th { border-bottom-width: 1px; font-weight: 600; color: #555; }
|
.price-table thead th { border-bottom-width: 1px; font-weight: 600; color: #555; }
|
||||||
.price-table thead th:first-child { color: #222; }
|
.price-table thead th:first-child { color: #222; }
|
||||||
|
|
||||||
.val-price { color: #222; font-weight: 700; }
|
.val-price { color: #222; font-weight: 700; }
|
||||||
.val-unit { color: #999; font-size: 0.8rem; }
|
.val-unit { color: #999; font-size: 0.8rem; }
|
||||||
|
|
||||||
.charger-item { border: 1px solid #e5e5e5; border-radius: 0.35rem; padding: 0.6rem; background-color: #fff; height: 100%; }
|
.charger-item { border: 1px solid #e5e5e5; border-radius: 0.35rem; padding: 0.6rem; background-color: #fff; height: 100%; }
|
||||||
.charger-cd { font-size: 0.9rem; font-weight: bold; color: #222; margin-bottom: 0.1rem; }
|
.charger-cd { font-size: 0.9rem; font-weight: bold; color: #222; margin-bottom: 0.1rem; }
|
||||||
.charger-dt { font-size: 0.75rem; color: #aaa; margin-bottom: 0.4rem; }
|
.charger-dt { font-size: 0.75rem; color: #aaa; margin-bottom: 0.4rem; }
|
||||||
|
|
||||||
.badge-square { background-color: #f0f0f0; color: #333; border: 1px solid #d8d8d8; padding: 0.15rem 0.4rem; font-size: 0.7rem; border-radius: 2px; font-weight: 500; }
|
.badge-square { background-color: #f0f0f0; color: #333; border: 1px solid #d8d8d8; padding: 0.15rem 0.4rem; font-size: 0.7rem; border-radius: 2px; font-weight: 500; }
|
||||||
.badge-square.active { background-color: #eef1fb; color: #3b5bdb; border-color: #d6dcf5; }
|
.badge-square.active { background-color: #eef1fb; color: #3b5bdb; border-color: #d6dcf5; }
|
||||||
|
|
||||||
.approval-ok { color: #333; font-weight: 600; }
|
.approval-ok { color: #333; font-weight: 600; }
|
||||||
.approval-ok i { color: #3b5bdb; }
|
.approval-ok i { color: #3b5bdb; }
|
||||||
|
|
||||||
.season-tabs { display: flex; border-bottom: 1px solid #e5e5e5; margin-bottom: 0.75rem; }
|
.season-tabs { display: flex; border-bottom: 1px solid #e5e5e5; margin-bottom: 0.75rem; }
|
||||||
.season-tab-btn { flex: 1; text-align: center; padding: 0.5rem 0; cursor: pointer; font-size: 0.85rem; color: #666; border-bottom: 2px solid transparent; background: none; border-top:none; border-left:none; border-right:none; }
|
.season-tab-btn { flex: 1; text-align: center; padding: 0.5rem 0; cursor: pointer; font-size: 0.85rem; color: #666; border-bottom: 2px solid transparent; background: none; border-top:none; border-left:none; border-right:none; }
|
||||||
.season-tab-btn.active { color: #3b5bdb; font-weight: 600; border-bottom-color: #3b5bdb; }
|
.season-tab-btn.active { color: #3b5bdb; font-weight: 600; border-bottom-color: #3b5bdb; }
|
||||||
|
|
||||||
.time-mode-toggle { display: flex; border: 1px solid #e5e5e5; border-radius: 0.25rem; overflow: hidden; margin-bottom: 0.75rem; }
|
.time-mode-toggle { display: flex; border: 1px solid #e5e5e5; border-radius: 0.25rem; overflow: hidden; margin-bottom: 0.75rem; }
|
||||||
.time-mode-btn { flex: 1; text-align: center; padding: 0.4rem 0; cursor: pointer; font-size: 0.82rem; color: #666; background: #fafafa; }
|
.time-mode-btn { flex: 1; text-align: center; padding: 0.4rem 0; cursor: pointer; font-size: 0.82rem; color: #666; background: #fafafa; }
|
||||||
.time-mode-btn.active { background: #3b5bdb; color: #fff; font-weight: 600; }
|
.time-mode-btn.active { background: #3b5bdb; color: #fff; font-weight: 600; }
|
||||||
|
|
||||||
.basic-price-row { display: flex; align-items: center; justify-content: space-between; padding: 0.5rem 0; border-bottom: 1px solid #f2f2f2; }
|
.basic-price-row { display: flex; align-items: center; justify-content: space-between; padding: 0.5rem 0; border-bottom: 1px solid #f2f2f2; }
|
||||||
.basic-price-row:last-child { border-bottom: none; }
|
.basic-price-row:last-child { border-bottom: none; }
|
||||||
.basic-price-label { font-size: 0.85rem; color: #333; }
|
.basic-price-label { font-size: 0.85rem; color: #333; }
|
||||||
.basic-price-input { width: 140px; text-align: right; }
|
.basic-price-input { width: 140px; text-align: right; }
|
||||||
|
|
||||||
.detail-price-row { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 0; border-bottom: 1px solid #f5f5f5; }
|
.detail-price-row { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 0; border-bottom: 1px solid #f5f5f5; }
|
||||||
.detail-price-label { font-size: 0.82rem; color: #444; }
|
.detail-price-label { font-size: 0.82rem; color: #444; }
|
||||||
.detail-price-input { width: 140px; text-align: right; }
|
.detail-price-input { width: 140px; text-align: right; }
|
||||||
.detail-scroll { max-height: 260px; overflow-y: auto; padding-right: 4px; }
|
.detail-scroll { max-height: 260px; overflow-y: auto; padding-right: 4px; }
|
||||||
|
|
||||||
.charger-search-list { max-height: 260px; overflow-y: auto; border: 1px solid #eee; border-radius: 0.25rem; padding: 0.4rem; }
|
.charger-search-list { max-height: 260px; overflow-y: auto; border: 1px solid #eee; border-radius: 0.25rem; padding: 0.4rem; }
|
||||||
.charger-check-item { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.5rem; border: 1px solid #eee; border-radius: 0.3rem; margin-bottom: 0.4rem; background:#fff; }
|
.charger-check-item { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.5rem; border: 1px solid #eee; border-radius: 0.3rem; margin-bottom: 0.4rem; background:#fff; }
|
||||||
.charger-check-item label { margin: 0; font-size: 0.82rem; }
|
.charger-check-item label { margin: 0; font-size: 0.82rem; }
|
||||||
@@ -144,22 +127,15 @@
|
|||||||
columns: [
|
columns: [
|
||||||
{title: "요금제 ID", name: "RATE_PLAN_ID", data: "ratePlanId", className, orderable:false, width: "80px"},
|
{title: "요금제 ID", name: "RATE_PLAN_ID", data: "ratePlanId", className, orderable:false, width: "80px"},
|
||||||
{title: "요금제명", name: "RATE_PLAN_NAME", data: "ratePlanName", orderable:false, className: "dt-head-center dt-body-left"},
|
{title: "요금제명", name: "RATE_PLAN_NAME", data: "ratePlanName", orderable:false, className: "dt-head-center dt-body-left"},
|
||||||
{title: "요금제 구분", name: "RATE_PLAN_TYPE", data: "ratePlanType", orderable:false, className,
|
{title: "요금제 구분", name: "RATE_PLAN_TYPE", data: "ratePlanType", orderable:false, className, render: (data) => data === 'time' ? '계시별 요금제' : data},
|
||||||
render: (data) => data === 'time' ? '계시별 요금제' : data
|
|
||||||
},
|
|
||||||
{title: "적용 시작일", name: "APPLY_START_DATE", data: "applyStartDate", orderable:false, className, width: "120px"},
|
{title: "적용 시작일", name: "APPLY_START_DATE", data: "applyStartDate", orderable:false, className, width: "120px"},
|
||||||
{title: "적용 종료일", name: "APPLY_END_DATE", data: "applyEndDate", orderable:false, className, width: "120px"},
|
{title: "적용 종료일", name: "APPLY_END_DATE", data: "applyEndDate", orderable:false, className, width: "120px"},
|
||||||
{title: "승인 상태", name: "APPROVAL_STATUS", data: "approvalStatus", orderable:false, className, width: "100px",
|
{title: "승인 상태", name: "APPROVAL_STATUS", data: "approvalStatus", orderable:false, className, width: "100px", render: (data) => data === 'approved' ? '<span class="text-success fw-bold"><i class="bi bi-check-lg"></i> 승인완료</span>' : '<span class="text-secondary">대기중</span>'},
|
||||||
render: (data) => data === 'approved' ? '<span class="text-success fw-bold"><i class="bi bi-check-lg"></i> 승인완료</span>' : '<span class="text-secondary">대기중</span>'
|
{title: "활성화", name: "IS_ACTIVE", data: "isActive", orderable:false, className, width: "80px", render: (data) => {
|
||||||
},
|
let val = String(data || '').toLowerCase();
|
||||||
{title: "활성화", name: "IS_ACTIVE", data: "isActive", orderable:false, className, width: "80px",
|
return (val === 'true' || val === 'y') ? '<span class="text-primary fw-bold">활성</span>' : '<span class="text-secondary">비활성</span>';
|
||||||
render: (data) => data === "true" || data === 'Y' ? '<span class="text-primary fw-bold">활성</span>' : '<span class="text-secondary">비활성</span>'
|
}},
|
||||||
},
|
{title: "기능", orderable:false, width:"120px", render: (data, type, row) => mkRowDataFunctions({ratePlanId: row['ratePlanId']}, row['ratePlanName'], true, true, true)}
|
||||||
{title: "기능", orderable:false, width:"120px",
|
|
||||||
render: (data, type, row) => {
|
|
||||||
return mkRowDataFunctions({ratePlanId: row['ratePlanId']}, row['ratePlanName'], true, true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
allCheck: false,
|
allCheck: false,
|
||||||
}
|
}
|
||||||
@@ -173,9 +149,6 @@
|
|||||||
const modalWidth = 780;
|
const modalWidth = 780;
|
||||||
const labelWidth = '1px';
|
const labelWidth = '1px';
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 💡 조회 모드 (VIEW)
|
|
||||||
// ==========================================
|
|
||||||
if(mode === ModalMode.VIEW || mode === ModalMode.VIEW_ONLY) {
|
if(mode === ModalMode.VIEW || mode === ModalMode.VIEW_ONLY) {
|
||||||
let viewInputArray = [
|
let viewInputArray = [
|
||||||
new ModalInput({
|
new ModalInput({
|
||||||
@@ -198,7 +171,6 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="custom-card">
|
<div class="custom-card">
|
||||||
<div class="custom-card-header">승인 정보</div>
|
<div class="custom-card-header">승인 정보</div>
|
||||||
<div class="custom-card-body">
|
<div class="custom-card-body">
|
||||||
@@ -207,16 +179,12 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="custom-card">
|
<div class="custom-card">
|
||||||
<div class="custom-card-header">시간대별 단가 설정</div>
|
<div class="custom-card-header">시간대별 단가 설정</div>
|
||||||
<div class="custom-card-body p-0" id="v_priceTableArea"></div>
|
<div class="custom-card-body p-0" id="v_priceTableArea"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="custom-card mb-1">
|
<div class="custom-card mb-1">
|
||||||
<div class="custom-card-header" style="border-bottom: 1px solid #e5e5e5;">
|
<div class="custom-card-header" style="border-bottom: 1px solid #e5e5e5;">적용 충전기 목록 (<span id="v_chargerCount">0</span>개)</div>
|
||||||
적용 충전기 목록 (<span id="v_chargerCount">0</span>개)
|
|
||||||
</div>
|
|
||||||
<div class="custom-card-body pt-3 pb-2" style="background-color: #fcfcfc;">
|
<div class="custom-card-body pt-3 pb-2" style="background-color: #fcfcfc;">
|
||||||
<div class="row g-2" id="v_chargerListArea"></div>
|
<div class="row g-2" id="v_chargerListArea"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -245,7 +213,10 @@
|
|||||||
$('#v_ratePlanType').text(data.ratePlanType === 'time' ? '계시별 요금제' : data.ratePlanType);
|
$('#v_ratePlanType').text(data.ratePlanType === 'time' ? '계시별 요금제' : data.ratePlanType);
|
||||||
$('#v_seasonType').text(data.seasonType === 'season' ? '계절별' : '연중');
|
$('#v_seasonType').text(data.seasonType === 'season' ? '계절별' : '연중');
|
||||||
$('#v_applyDate').text(`${data.applyStartDate || ''} ~ ${data.applyEndDate || ''}`);
|
$('#v_applyDate').text(`${data.applyStartDate || ''} ~ ${data.applyEndDate || ''}`);
|
||||||
$('#v_isActive').text((data.isActive === "true" || data.isActive === 'Y' || data.active === true) ? '활성화' : '비활성');
|
|
||||||
|
let mainActiveVal = String(data.isActive || data.active || '').toLowerCase();
|
||||||
|
$('#v_isActive').text((mainActiveVal === 'true' || mainActiveVal === 'y') ? '활성화' : '비활성');
|
||||||
|
|
||||||
$('#v_description').text(data.description || '-');
|
$('#v_description').text(data.description || '-');
|
||||||
|
|
||||||
if(data.approvalStatus === 'approved') {
|
if(data.approvalStatus === 'approved') {
|
||||||
@@ -259,7 +230,8 @@
|
|||||||
if (data.chargerList && data.chargerList.length > 0) {
|
if (data.chargerList && data.chargerList.length > 0) {
|
||||||
$('#v_chargerCount').text(data.chargerList.length);
|
$('#v_chargerCount').text(data.chargerList.length);
|
||||||
let chargerHtml = data.chargerList.map(c => {
|
let chargerHtml = data.chargerList.map(c => {
|
||||||
let isActive = (c.isActive === true || c.active === true || c.isActive === 'Y');
|
let isActiveVal = String(c.isActive || c.active || '').toLowerCase();
|
||||||
|
let isActive = (isActiveVal === 'true' || isActiveVal === 'y');
|
||||||
let badgeClass = isActive ? 'badge-square active' : 'badge-square';
|
let badgeClass = isActive ? 'badge-square active' : 'badge-square';
|
||||||
let badgeText = isActive ? '적용중' : '중지';
|
let badgeText = isActive ? '적용중' : '중지';
|
||||||
return `
|
return `
|
||||||
@@ -280,10 +252,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 💡 등록 모드 (REGISTER)
|
|
||||||
// ==========================================
|
|
||||||
else if(mode === ModalMode.REGISTER) {
|
else if(mode === ModalMode.REGISTER) {
|
||||||
let registerInputArray = [
|
let registerInputArray = [
|
||||||
new ModalInput({
|
new ModalInput({
|
||||||
@@ -310,7 +278,6 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="custom-card">
|
<div class="custom-card">
|
||||||
<div class="custom-card-header">계시별 단가 설정</div>
|
<div class="custom-card-header">계시별 단가 설정</div>
|
||||||
<div class="custom-card-body">
|
<div class="custom-card-body">
|
||||||
@@ -318,7 +285,6 @@
|
|||||||
<div id="i_pricePanelsArea"></div>
|
<div id="i_pricePanelsArea"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="custom-card mb-1">
|
<div class="custom-card mb-1">
|
||||||
<div class="custom-card-header">적용할 충전기 선택</div>
|
<div class="custom-card-header">적용할 충전기 선택</div>
|
||||||
<div class="custom-card-body">
|
<div class="custom-card-body">
|
||||||
@@ -344,18 +310,14 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
newModal(new ModalInfo({modalTitle: "새 단가 정책 생성", inputArray: registerInputArray, modalWidth: modalWidth}), mode, 'main', {
|
newModal(new ModalInfo({modalTitle: "새 단가 정책 생성", inputArray: registerInputArray, modalWidth: modalWidth}), mode, 'main', {
|
||||||
// 🚨 insertUrl을 제거하여 프레임워크 폼 전송 방지
|
|
||||||
labelWidth: '1px',
|
labelWidth: '1px',
|
||||||
callInit: function() {
|
callInit: function() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
initRegisterForm();
|
initRegisterForm();
|
||||||
|
|
||||||
// 프레임워크 저장 버튼 이벤트 가로채기
|
|
||||||
$('.modal-footer button[name="approve"]').off('click').on('click', function(e) {
|
$('.modal-footer button[name="approve"]').off('click').on('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
if(confirm("등록하시겠습니까?")) {
|
if(confirm("등록하시겠습니까?")) {
|
||||||
submitRegisterForm();
|
submitRegisterForm();
|
||||||
}
|
}
|
||||||
@@ -370,8 +332,7 @@
|
|||||||
let activeSeason = null;
|
let activeSeason = null;
|
||||||
|
|
||||||
function getSeasons() {
|
function getSeasons() {
|
||||||
const seasonType = $('#i_seasonType').val();
|
return $('#i_seasonType').val() === 'season' ? ['spring','summer','fall','winter'] : ['all_year'];
|
||||||
return seasonType === 'season' ? ['spring','summer','fall','winter'] : ['all_year'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPriceStateFor(seasonKey) {
|
function initPriceStateFor(seasonKey) {
|
||||||
@@ -387,7 +348,6 @@
|
|||||||
$('#i_seasonType').off('change').on('change', renderSeasonTabsAndPanel);
|
$('#i_seasonType').off('change').on('change', renderSeasonTabsAndPanel);
|
||||||
renderSeasonTabsAndPanel();
|
renderSeasonTabsAndPanel();
|
||||||
loadChargerList();
|
loadChargerList();
|
||||||
|
|
||||||
$('#i_chargerSearch, #i_chargerFilter').off('input change').on('input change', filterChargerList);
|
$('#i_chargerSearch, #i_chargerFilter').off('input change').on('input change', filterChargerList);
|
||||||
$('#i_chargerAll').off('change').on('change', function() {
|
$('#i_chargerAll').off('change').on('change', function() {
|
||||||
$('#i_chargerListArea .charger-check-cb:visible').prop('checked', $(this).is(':checked'));
|
$('#i_chargerListArea .charger-check-cb:visible').prop('checked', $(this).is(':checked'));
|
||||||
@@ -399,7 +359,6 @@
|
|||||||
const seasons = getSeasons();
|
const seasons = getSeasons();
|
||||||
seasons.forEach(initPriceStateFor);
|
seasons.forEach(initPriceStateFor);
|
||||||
activeSeason = seasons[0];
|
activeSeason = seasons[0];
|
||||||
|
|
||||||
let tabsHtml = '';
|
let tabsHtml = '';
|
||||||
if (seasons.length > 1) {
|
if (seasons.length > 1) {
|
||||||
tabsHtml = `<div class="season-tabs">` +
|
tabsHtml = `<div class="season-tabs">` +
|
||||||
@@ -407,15 +366,13 @@
|
|||||||
`</div>`;
|
`</div>`;
|
||||||
}
|
}
|
||||||
$('#i_seasonTabsArea').html(tabsHtml);
|
$('#i_seasonTabsArea').html(tabsHtml);
|
||||||
|
|
||||||
$('.season-tab-btn').off('click').on('click', function() {
|
$('.season-tab-btn').off('click').on('click', function() {
|
||||||
saveCurrentPanelValues(activeSeason); // 탭 이동 시 기존 탭 데이터 저장
|
saveCurrentPanelValues(activeSeason);
|
||||||
$('.season-tab-btn').removeClass('active');
|
$('.season-tab-btn').removeClass('active');
|
||||||
$(this).addClass('active');
|
$(this).addClass('active');
|
||||||
activeSeason = $(this).data('season');
|
activeSeason = $(this).data('season');
|
||||||
renderPricePanel(activeSeason);
|
renderPricePanel(activeSeason);
|
||||||
});
|
});
|
||||||
|
|
||||||
renderPricePanel(activeSeason);
|
renderPricePanel(activeSeason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,15 +386,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
let bodyHtml;
|
let bodyHtml;
|
||||||
if (state.mode === 'basic') {
|
if (state.mode === 'basic') {
|
||||||
bodyHtml = `<div id="i_basicPanel">` + BASIC_SLOTS.map(slot => `
|
bodyHtml = `<div id="i_basicPanel">` + BASIC_SLOTS.map(slot => `
|
||||||
<div class="basic-price-row">
|
<div class="basic-price-row">
|
||||||
<span class="basic-price-label">${slot.label}</span>
|
<span class="basic-price-label">${slot.label}</span>
|
||||||
<div>
|
<div><input type="number" class="form-control form-control-sm basic-price-input i_basic_input" data-id="${slot.id}" value="${state.basic[slot.id]}"> 원/kWh</div>
|
||||||
<input type="number" class="form-control form-control-sm basic-price-input i_basic_input" data-id="${slot.id}" value="${state.basic[slot.id]}"> 원/kWh
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`).join('') + `</div>`;
|
`).join('') + `</div>`;
|
||||||
} else {
|
} else {
|
||||||
@@ -453,9 +407,7 @@
|
|||||||
}
|
}
|
||||||
bodyHtml = `<div class="detail-scroll" id="i_detailPanel">${rows}</div>`;
|
bodyHtml = `<div class="detail-scroll" id="i_detailPanel">${rows}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#i_pricePanelsArea').html(modeToggleHtml + bodyHtml);
|
$('#i_pricePanelsArea').html(modeToggleHtml + bodyHtml);
|
||||||
|
|
||||||
$('.time-mode-btn').off('click').on('click', function() {
|
$('.time-mode-btn').off('click').on('click', function() {
|
||||||
saveCurrentPanelValues(seasonKey);
|
saveCurrentPanelValues(seasonKey);
|
||||||
priceState[seasonKey].mode = $(this).data('mode');
|
priceState[seasonKey].mode = $(this).data('mode');
|
||||||
@@ -466,50 +418,30 @@
|
|||||||
function saveCurrentPanelValues(seasonKey) {
|
function saveCurrentPanelValues(seasonKey) {
|
||||||
const state = priceState[seasonKey];
|
const state = priceState[seasonKey];
|
||||||
if (state.mode === 'basic') {
|
if (state.mode === 'basic') {
|
||||||
$('.i_basic_input').each(function() {
|
$('.i_basic_input').each(function() { state.basic[$(this).data('id')] = parseFloat($(this).val()) || 0; });
|
||||||
state.basic[$(this).data('id')] = parseFloat($(this).val()) || 0;
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
$('.i_detail_input').each(function() {
|
$('.i_detail_input').each(function() { state.detail[$(this).data('hour')] = parseFloat($(this).val()) || 0; });
|
||||||
state.detail[$(this).data('hour')] = parseFloat($(this).val()) || 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadChargerList() {
|
function loadChargerList() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/cms/chgr/list.json",
|
url: "/cms/chgr/list.json", type: "POST", data: { start: 0, length: 9999 },
|
||||||
type: "POST",
|
success: function(res) { renderChargerList(res.data || res.list || []); },
|
||||||
data: {
|
error: function() { $('#i_chargerListArea').html('<div class="text-muted small p-2">충전기 목록을 불러오지 못했습니다.</div>'); }
|
||||||
start: 0,
|
|
||||||
length: 9999
|
|
||||||
},
|
|
||||||
success: function(res) {
|
|
||||||
const list = res.data || res.list || [];
|
|
||||||
renderChargerList(list);
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
$('#i_chargerListArea').html('<div class="text-muted small p-2">충전기 목록을 불러오지 못했습니다.</div>');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderChargerList(list) {
|
function renderChargerList(list) {
|
||||||
const mapped = list.map(c => {
|
const mapped = list.map(c => ({
|
||||||
const chargerCd = `${c.providerId || ''}${c.stId || ''}${c.chgrId || ''}`;
|
chargerCd: `${c.providerId || ''}${c.stId || ''}${c.chgrId || ''}`,
|
||||||
return {
|
chargerName: c.chgrNm || `${c.providerId || ''}${c.stId || ''}${c.chgrId || ''}`,
|
||||||
chargerCd: chargerCd,
|
|
||||||
chargerName: c.chgrNm || chargerCd,
|
|
||||||
location: c.stNm || '',
|
location: c.stNm || '',
|
||||||
chargerType: c.speedTp || ''
|
chargerType: c.speedTp || ''
|
||||||
};
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
$('#i_chargerAllCount').text(mapped.length);
|
$('#i_chargerAllCount').text(mapped.length);
|
||||||
|
|
||||||
let html = mapped.map(c => `
|
let html = mapped.map(c => `
|
||||||
<div class="charger-check-item" data-name="${c.chargerName.toLowerCase()}"
|
<div class="charger-check-item" data-name="${c.chargerName.toLowerCase()}" data-loc="${c.location.toLowerCase()}" data-type="${c.chargerType}">
|
||||||
data-loc="${c.location.toLowerCase()}" data-type="${c.chargerType}">
|
|
||||||
<input type="checkbox" class="charger-check-cb" value="${c.chargerCd}">
|
<input type="checkbox" class="charger-check-cb" value="${c.chargerCd}">
|
||||||
<label>
|
<label>
|
||||||
<div><strong>${c.chargerName}</strong> <span class="badge-square">${c.chargerType}</span></div>
|
<div><strong>${c.chargerName}</strong> <span class="badge-square">${c.chargerType}</span></div>
|
||||||
@@ -517,7 +449,6 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
`).join('');
|
||||||
|
|
||||||
$('#i_chargerListArea').html(html || '<div class="text-muted small p-2">등록된 충전기가 없습니다.</div>');
|
$('#i_chargerListArea').html(html || '<div class="text-muted small p-2">등록된 충전기가 없습니다.</div>');
|
||||||
$('.charger-check-cb').off('change').on('change', updateAllCheckState);
|
$('.charger-check-cb').off('change').on('change', updateAllCheckState);
|
||||||
}
|
}
|
||||||
@@ -541,7 +472,6 @@
|
|||||||
function renderViewPriceTable(detailsTime) {
|
function renderViewPriceTable(detailsTime) {
|
||||||
const seasonsSet = new Set(detailsTime.map(d => d.seasonType));
|
const seasonsSet = new Set(detailsTime.map(d => d.seasonType));
|
||||||
const seasons = seasonsSet.size ? Array.from(seasonsSet) : ['all_year'];
|
const seasons = seasonsSet.size ? Array.from(seasonsSet) : ['all_year'];
|
||||||
|
|
||||||
let priceMap = {};
|
let priceMap = {};
|
||||||
let allIds = new Set();
|
let allIds = new Set();
|
||||||
detailsTime.forEach(d => {
|
detailsTime.forEach(d => {
|
||||||
@@ -551,27 +481,21 @@
|
|||||||
allIds.add(r.id);
|
allIds.add(r.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const isBasic = [1, 2, 3].some(id => allIds.has(id));
|
const isBasic = [1, 2, 3].some(id => allIds.has(id));
|
||||||
|
|
||||||
let headerHtml = seasons.map(s => `<th>${SEASON_LABEL[s] || s}</th>`).join('');
|
let headerHtml = seasons.map(s => `<th>${SEASON_LABEL[s] || s}</th>`).join('');
|
||||||
let rows = '';
|
let rows = '';
|
||||||
|
|
||||||
if (isBasic) {
|
if (isBasic) {
|
||||||
BASIC_SLOTS.forEach(slot => {
|
BASIC_SLOTS.forEach(slot => {
|
||||||
rows += `<tr><td class="border-end py-2 fw-bold">${slot.label}</td>` +
|
rows += `<tr><td class="border-end py-2 fw-bold">${slot.label}</td>` +
|
||||||
seasons.map(s => `<td>${priceMap[slot.id] && priceMap[slot.id][s] != null ? `<span class="val-price">${priceMap[slot.id][s]}</span> <span class="val-unit">원/kWh</span>` : '-'}</td>`).join('') +
|
seasons.map(s => `<td>${priceMap[slot.id] && priceMap[slot.id][s] != null ? `<span class="val-price">${priceMap[slot.id][s]}</span> <span class="val-unit">원/kWh</span>` : '-'}</td>`).join('') + `</tr>`;
|
||||||
`</tr>`;
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
for (let h = 0; h < 24; h++) {
|
for (let h = 0; h < 24; h++) {
|
||||||
const id = h + 4;
|
const id = h + 4;
|
||||||
rows += `<tr><td class="border-end py-2">${String(h).padStart(2, '0')}시</td>` +
|
rows += `<tr><td class="border-end py-2">${String(h).padStart(2, '0')}시</td>` +
|
||||||
seasons.map(s => `<td>${priceMap[id] && priceMap[id][s] != null ? `<span class="val-price">${priceMap[id][s]}</span> <span class="val-unit">원/kWh</span>` : '-'}</td>`).join('') +
|
seasons.map(s => `<td>${priceMap[id] && priceMap[id][s] != null ? `<span class="val-price">${priceMap[id][s]}</span> <span class="val-unit">원/kWh</span>` : '-'}</td>`).join('') + `</tr>`;
|
||||||
`</tr>`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#v_priceTableArea').html(`
|
$('#v_priceTableArea').html(`
|
||||||
<table class="table mb-0 text-center align-middle price-table">
|
<table class="table mb-0 text-center align-middle price-table">
|
||||||
<thead><tr><th class="border-end text-dark">시간대구분</th>${headerHtml}</tr></thead>
|
<thead><tr><th class="border-end text-dark">시간대구분</th>${headerHtml}</tr></thead>
|
||||||
@@ -583,7 +507,6 @@
|
|||||||
function submitRegisterForm() {
|
function submitRegisterForm() {
|
||||||
const seasons = getSeasons();
|
const seasons = getSeasons();
|
||||||
saveCurrentPanelValues(activeSeason);
|
saveCurrentPanelValues(activeSeason);
|
||||||
|
|
||||||
let detailsTime = seasons.map(seasonKey => {
|
let detailsTime = seasons.map(seasonKey => {
|
||||||
const state = priceState[seasonKey];
|
const state = priceState[seasonKey];
|
||||||
let timeRates = [];
|
let timeRates = [];
|
||||||
@@ -624,16 +547,9 @@
|
|||||||
if(chargerList.length === 0) { alert("적용할 충전기를 1개 이상 선택해주세요."); return; }
|
if(chargerList.length === 0) { alert("적용할 충전기를 1개 이상 선택해주세요."); return; }
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: rootPath + "insert.json",
|
url: rootPath + "insert.json", type: "POST", contentType: "application/json; charset=utf-8", data: JSON.stringify(requestDto),
|
||||||
type: "POST",
|
|
||||||
contentType: "application/json; charset=utf-8",
|
|
||||||
data: JSON.stringify(requestDto),
|
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
if(res.result === 'success') {
|
if(res.result === 'success') { alert("등록되었습니다."); } else { alert("오류 발생: " + res.message); }
|
||||||
alert("등록되었습니다.");
|
|
||||||
} else {
|
|
||||||
alert("오류 발생: " + res.message);
|
|
||||||
}
|
|
||||||
$('.modal-footer .btn-cls-main').trigger('click');
|
$('.modal-footer .btn-cls-main').trigger('click');
|
||||||
datatable.ajax.reload();
|
datatable.ajax.reload();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,12 +30,12 @@
|
|||||||
<input type="text" id="chgrIdLike" name="chgrIdLike" class="form-control" placeholder="충전기 ID 입력" maxlength="50">
|
<input type="text" id="chgrIdLike" name="chgrIdLike" class="form-control" placeholder="충전기 ID 입력" maxlength="50">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4 col-sm-6 col-xs-12 pb-1">
|
<!-- <div class="col-lg-4 col-sm-6 col-xs-12 pb-1">-->
|
||||||
<div class="input-group">
|
<!-- <div class="input-group">-->
|
||||||
<span class="input-group-text" style="width:300px">플러그 타입</span>
|
<!-- <span class="input-group-text" style="width:300px">플러그 타입</span>-->
|
||||||
<input type="text" id="plugTypeLike" name="plugTypeLike" class="form-control" placeholder="플러그 타입 입력" maxlength="50">
|
<!-- <input type="text" id="plugTypeLike" name="plugTypeLike" class="form-control" placeholder="플러그 타입 입력" maxlength="50">-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="col-lg-4 col-sm-6 col-xs-12 pb-1">
|
<div class="col-lg-4 col-sm-6 col-xs-12 pb-1">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text" style="width:300px">회원카드번호</span>
|
<span class="input-group-text" style="width:300px">회원카드번호</span>
|
||||||
@@ -48,16 +48,16 @@
|
|||||||
<input type="text" id="creditPPayTrxNoLike" name="creditPPayTrxNoLike" class="form-control" placeholder="신용카드 승인번호 입력" maxlength="50">
|
<input type="text" id="creditPPayTrxNoLike" name="creditPPayTrxNoLike" class="form-control" placeholder="신용카드 승인번호 입력" maxlength="50">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4 col-sm-6 col-xs-12 pb-1">
|
<!-- <div class="col-lg-4 col-sm-6 col-xs-12 pb-1">-->
|
||||||
<div class="input-group">
|
<!-- <div class="input-group">-->
|
||||||
<span class="input-group-text" style="width:300px">신용카드 승인일시</span>
|
<!-- <span class="input-group-text" style="width:300px">신용카드 승인일시</span>-->
|
||||||
<input type="text" id="creditPPayTrxDtLike" name="creditPPayTrxDtLike" class="form-control" placeholder="신용카드 승인일시 입력" maxlength="50">
|
<!-- <input type="text" id="creditPPayTrxDtLike" name="creditPPayTrxDtLike" class="form-control" placeholder="신용카드 승인일시 입력" maxlength="50">-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="col-lg-4 col-sm-6 col-xs-12 pb-1">
|
<div class="col-lg-4 col-sm-6 col-xs-12 pb-1">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text" style="width:300px">충전 시작일시</span>
|
<span class="input-group-text" style="width:300px">충전 시작일시</span>
|
||||||
<input type="text" id="rechgSdtLike" name="rechgSdtLike" class="form-control" placeholder="충전 시작일시 입력" maxlength="50">
|
<input type="date" id="rechgSdtLike" name="rechgSdtLike" class="form-control" placeholder="충전 시작일시 입력" maxlength="50">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-lg-4 col-sm-6 col-xs-12 pb-1">-->
|
<!-- <div class="col-lg-4 col-sm-6 col-xs-12 pb-1">-->
|
||||||
@@ -66,12 +66,17 @@
|
|||||||
<!-- <input type="text" id="rechgRemainTimeLike" name="rechgRemainTimeLike" class="form-control" placeholder="충전 잔여 시간 입력" maxlength="50">-->
|
<!-- <input type="text" id="rechgRemainTimeLike" name="rechgRemainTimeLike" class="form-control" placeholder="충전 잔여 시간 입력" maxlength="50">-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<div class="col-lg-4 col-sm-6 col-xs-12 pb-1">
|
<!-- <div class="col-lg-4 col-sm-6 col-xs-12 pb-1">-->
|
||||||
<div class="input-group">
|
<!-- <div class="input-group">-->
|
||||||
<span class="input-group-text" style="width:300px">결제타입</span>
|
<!-- <span class="input-group-text" style="width:300px">결제타입</span>-->
|
||||||
<input type="text" id="payTypeLike" name="payTypeLike" class="form-control" placeholder="결제타입 입력" maxlength="50">
|
<!-- <select id="payType" name="payType" class="form-select">-->
|
||||||
</div>
|
<!-- <option value="">전체</option>-->
|
||||||
</div>
|
<!-- <option value="회원카드">회원카드</option>-->
|
||||||
|
<!-- <option value="신용카드">신용카드</option>-->
|
||||||
|
<!-- <option value="무과금">무과금</option>-->
|
||||||
|
<!-- </select>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="searchBoxFooter">
|
<div id="searchBoxFooter">
|
||||||
|
|||||||
Reference in New Issue
Block a user