Merge branch 'main-design-layout' of https://git.eactive.synology.me:8090/kjb-eapim/eapim-portal into main-design-layout
@@ -9,12 +9,8 @@ public final class Constants {
|
||||
|
||||
public static final String APIM_FOR_OBP_KEY = "x-obp-trust-system";
|
||||
|
||||
public static final String APIM_FOR_OBP_VALUE = "APIMPT-0002-QVBJTVBULTAwMDI=";
|
||||
|
||||
public static final String APIM_CODE_FOR_OBP_KEY = "x-obp-partnercode";
|
||||
|
||||
public static final String APIM_CODE_FOR_OBP_VALUE = "100001-01";
|
||||
|
||||
public static final String SMS_URL = "/api/messaging/sms";
|
||||
|
||||
public static final String COMMISSION_URL = "/api/billing/billing/findBillingForCondition";
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.eactive.apim.portal.apps.commission.dto.CommissionSearch;
|
||||
import com.eactive.apim.portal.apps.commission.exception.ErrorUtil;
|
||||
import com.eactive.apim.portal.apps.commission.service.ExternalService;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.ArrayList;
|
||||
@@ -16,7 +17,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.stereotype.Controller;
|
||||
@@ -38,14 +38,7 @@ public class CommissionController {
|
||||
private final Logger log = LoggerFactory.getLogger(CommissionController.class);
|
||||
|
||||
private final ExternalService externalService;
|
||||
|
||||
@Value("${obm-url:http://localhost:8080}")
|
||||
private String obmUrl;
|
||||
|
||||
@Value("${provider-code:100001-01}")
|
||||
private String providerCode;
|
||||
|
||||
// ==================== View Controllers ====================
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
|
||||
@GetMapping("/manage")
|
||||
public String commissionManagePage(Model model) {
|
||||
@@ -66,11 +59,10 @@ public class CommissionController {
|
||||
search.setYear(year);
|
||||
search.setMonth(month);
|
||||
|
||||
search.setProvider(providerCode);
|
||||
|
||||
if (!StringUtils.isEmpty(search.getPartnerCode())) {
|
||||
try {
|
||||
String url = obmUrl + Constants.COMMISSION_URL;
|
||||
String obmUrl = portalPropertyService.getPortalPropertiesAsMap("Portal").getOrDefault("obp.obm.url", "");
|
||||
String url = obmUrl + Constants.COMMISSION_PRINT_URL;
|
||||
String result = externalService.getResponseHttpPost(url, toJson(search));
|
||||
HashMap<String, Object> returnObj = new ObjectMapper().readValue(result, HashMap.class);
|
||||
|
||||
@@ -85,10 +77,10 @@ public class CommissionController {
|
||||
search.setPartnerCode("000002-02");
|
||||
String togetherResult = externalService.getResponseHttpPost(url, toJson(search));
|
||||
|
||||
HashMap<String, Object> togetherLendingReturnObj = new ObjectMapper().readValue(togetherResult, HashMap.class);
|
||||
HashMap togetherLendingReturnObj = new ObjectMapper().readValue(togetherResult, HashMap.class);
|
||||
log.debug("togetherLendingReturnObj : " + togetherLendingReturnObj.toString());
|
||||
if (!StringUtils.isEmpty(togetherLendingReturnObj.get("error"))) {
|
||||
HashMap<String, Object> error = (HashMap) togetherLendingReturnObj.get("error");
|
||||
HashMap error = (HashMap) togetherLendingReturnObj.get("error");
|
||||
model.addAttribute("error", error.get("message").toString());
|
||||
return "apps/commission/commissionPrint";
|
||||
}
|
||||
@@ -119,11 +111,11 @@ public class CommissionController {
|
||||
@PostMapping()
|
||||
public ResponseEntity<?> list(@RequestBody CommissionSearch search) {
|
||||
CommissionDTO commissionDTO = null;
|
||||
search.setProvider(providerCode);
|
||||
search.setPartnerCode(SecurityUtil.getUserOrg().getOrgCode());
|
||||
|
||||
if (!StringUtils.isEmpty(search.getPartnerCode())) {
|
||||
try {
|
||||
String obmUrl = portalPropertyService.getPortalPropertiesAsMap("Portal").getOrDefault("obp.obm.url", "");
|
||||
String url = obmUrl + Constants.COMMISSION_URL;
|
||||
String result = externalService.getResponseHttpPost(url, toJson(search));
|
||||
HashMap<String, Object> returnObj = new ObjectMapper().readValue(result, HashMap.class);
|
||||
@@ -170,6 +162,28 @@ public class CommissionController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely parse double value from HashMap
|
||||
* Handles both numeric types and string representations
|
||||
*/
|
||||
private double safeGetDouble(HashMap<String, Object> map, String key) {
|
||||
Object value = map.get(key);
|
||||
if (value == null) {
|
||||
return 0.0;
|
||||
}
|
||||
try {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).doubleValue();
|
||||
} else if (value instanceof String) {
|
||||
return Double.parseDouble((String) value);
|
||||
}
|
||||
return 0.0;
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("Failed to parse double value for key: {} with value: {}", key, value);
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
public HashMap<String, Object> mergeCommissionData(HashMap<String, Object> o1, HashMap<String, Object> o2) {
|
||||
|
||||
HashMap<String, Object> mergeMap = new HashMap<String, Object>();
|
||||
@@ -182,22 +196,22 @@ public class CommissionController {
|
||||
} else {
|
||||
resultStatus = o2Status;
|
||||
}
|
||||
double apiTotalValueSum = MapUtils.getDouble(o1, "apiTotalValueSum") + MapUtils.getDouble(o2, "apiTotalValueSum");
|
||||
double apiSum = MapUtils.getDouble(o1, "apiSum") + MapUtils.getDouble(o2, "apiSum");
|
||||
double apiTotalValueSum2 = MapUtils.getDouble(o1, "apiTotalValueSum2") + MapUtils.getDouble(o2, "apiTotalValueSum2");
|
||||
double apiSum2 = MapUtils.getDouble(o1, "apiSum2") + MapUtils.getDouble(o2, "apiSum2");
|
||||
double productTotalValueCountSum = MapUtils.getDouble(o1, "productTotalValueCountSum") + MapUtils.getDouble(o2, "productTotalValueCountSum");
|
||||
double productTotalValueAmountSum = MapUtils.getDouble(o1, "productTotalValueAmountSum") + MapUtils.getDouble(o2, "productTotalValueAmountSum");
|
||||
double productSum = MapUtils.getDouble(o1, "productSum") + MapUtils.getDouble(o2, "productSum");
|
||||
double productTotalValueCountSum2 = MapUtils.getDouble(o1, "productTotalValueCountSum2") + MapUtils.getDouble(o2, "productTotalValueCountSum2");
|
||||
double productTotalValueAmountSum2 = MapUtils.getDouble(o1, "productTotalValueAmountSum2") + MapUtils.getDouble(o2, "productTotalValueAmountSum2");
|
||||
double productSum2 = MapUtils.getDouble(o1, "productSum2") + MapUtils.getDouble(o2, "productSum2");
|
||||
double totalValueCountSum = MapUtils.getDouble(o1, "totalValueCountSum") + MapUtils.getDouble(o2, "totalValueCountSum");
|
||||
double totalValueCountSum2 = MapUtils.getDouble(o1, "totalValueCountSum2") + MapUtils.getDouble(o2, "totalValueCountSum2");
|
||||
double totalValueAmountSum = MapUtils.getDouble(o1, "totalValueAmountSum") + MapUtils.getDouble(o2, "totalValueAmountSum");
|
||||
double totalValueAmountSum2 = MapUtils.getDouble(o1, "totalValueAmountSum2") + MapUtils.getDouble(o2, "totalValueAmountSum2");
|
||||
double sum = MapUtils.getDouble(o1, "sum") + MapUtils.getDouble(o2, "sum");
|
||||
double sum2 = MapUtils.getDouble(o1, "sum2") + MapUtils.getDouble(o2, "sum2");
|
||||
double apiTotalValueSum = safeGetDouble(o1, "apiTotalValueSum") + safeGetDouble(o2, "apiTotalValueSum");
|
||||
double apiSum = safeGetDouble(o1, "apiSum") + safeGetDouble(o2, "apiSum");
|
||||
double apiTotalValueSum2 = safeGetDouble(o1, "apiTotalValueSum2") + safeGetDouble(o2, "apiTotalValueSum2");
|
||||
double apiSum2 = safeGetDouble(o1, "apiSum2") + safeGetDouble(o2, "apiSum2");
|
||||
double productTotalValueCountSum = safeGetDouble(o1, "productTotalValueCountSum") + safeGetDouble(o2, "productTotalValueCountSum");
|
||||
double productTotalValueAmountSum = safeGetDouble(o1, "productTotalValueAmountSum") + safeGetDouble(o2, "productTotalValueAmountSum");
|
||||
double productSum = safeGetDouble(o1, "productSum") + safeGetDouble(o2, "productSum");
|
||||
double productTotalValueCountSum2 = safeGetDouble(o1, "productTotalValueCountSum2") + safeGetDouble(o2, "productTotalValueCountSum2");
|
||||
double productTotalValueAmountSum2 = safeGetDouble(o1, "productTotalValueAmountSum2") + safeGetDouble(o2, "productTotalValueAmountSum2");
|
||||
double productSum2 = safeGetDouble(o1, "productSum2") + safeGetDouble(o2, "productSum2");
|
||||
double totalValueCountSum = safeGetDouble(o1, "totalValueCountSum") + safeGetDouble(o2, "totalValueCountSum");
|
||||
double totalValueCountSum2 = safeGetDouble(o1, "totalValueCountSum2") + safeGetDouble(o2, "totalValueCountSum2");
|
||||
double totalValueAmountSum = safeGetDouble(o1, "totalValueAmountSum") + safeGetDouble(o2, "totalValueAmountSum");
|
||||
double totalValueAmountSum2 = safeGetDouble(o1, "totalValueAmountSum2") + safeGetDouble(o2, "totalValueAmountSum2");
|
||||
double sum = safeGetDouble(o1, "sum") + safeGetDouble(o2, "sum");
|
||||
double sum2 = safeGetDouble(o1, "sum2") + safeGetDouble(o2, "sum2");
|
||||
|
||||
List<Map> o1List = (ArrayList) o1.get("list");
|
||||
List<Map> o2pList = (ArrayList) o2.get("list");
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.eactive.apim.portal.apps.commission.dto;
|
||||
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -15,7 +14,4 @@ public class CommissionSearch {
|
||||
|
||||
private String partnerCode;
|
||||
|
||||
private PortalOrg organization;
|
||||
|
||||
private String provider;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.eactive.apim.portal.apps.commission.service;
|
||||
|
||||
import com.eactive.apim.portal.apps.commission.constant.Constants;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpEntity;
|
||||
@@ -22,16 +25,13 @@ import org.springframework.web.client.RestTemplate;
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class ExternalService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(ExternalService.class);
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
@Inject
|
||||
public ExternalService(RestTemplate restTemplate) {
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
|
||||
/**
|
||||
* HTTP POST 요청을 통해 외부 API를 호출하고 응답을 받습니다.
|
||||
@@ -42,11 +42,14 @@ public class ExternalService {
|
||||
*/
|
||||
public String getResponseHttpPost(String url, String payload) {
|
||||
try {
|
||||
|
||||
Map<String, String> portalProperties = portalPropertyService.getPortalPropertiesAsMap("Portal");
|
||||
|
||||
// HTTP 헤더 설정
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set(Constants.APIM_FOR_OBP_KEY, Constants.APIM_FOR_OBP_VALUE);
|
||||
headers.set(Constants.APIM_CODE_FOR_OBP_KEY, Constants.APIM_CODE_FOR_OBP_VALUE);
|
||||
headers.set(Constants.APIM_FOR_OBP_KEY, portalProperties.getOrDefault("obp.api_key","APIMPT-0002-QVBJTVBULTAwMDI="));
|
||||
headers.set(Constants.APIM_CODE_FOR_OBP_KEY, portalProperties.getOrDefault("obp.partner_code","100001-01"));
|
||||
|
||||
// HTTP 요청 엔티티 생성 (헤더 + 본문)
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(payload, headers);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.eactive.apim.portal.apps.community.partnership.controller;
|
||||
|
||||
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
||||
import com.eactive.apim.portal.apps.community.partnership.service.PartnershipApplicationFacade;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import java.io.IOException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/partnership")
|
||||
public class PartnershipApplicationController {
|
||||
|
||||
private final PartnershipApplicationFacade partnershipApplicationFacade;
|
||||
|
||||
@Autowired
|
||||
public PartnershipApplicationController(PartnershipApplicationFacade partnershipApplicationFacade){
|
||||
this.partnershipApplicationFacade = partnershipApplicationFacade;
|
||||
}
|
||||
|
||||
|
||||
@GetMapping
|
||||
public String newPartnershipApplicationForm(Model model, HttpServletRequest request) {
|
||||
if (!SecurityUtil.isAuthenticated()) {
|
||||
return "redirect:/login?redirect=/partnership";
|
||||
}
|
||||
|
||||
String referer = request.getHeader("Referer");
|
||||
if(referer != null && !referer.contains("/partnership")) {
|
||||
request.getSession().setAttribute("previousPage", referer);
|
||||
}
|
||||
|
||||
model.addAttribute("partnership", new PartnershipApplicationDTO());
|
||||
return "apps/community/mainPartnershipForm";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping
|
||||
public String createPartnershipApplication(@Valid @ModelAttribute PartnershipApplicationDTO partnershipApplicationDTO,
|
||||
BindingResult bindingResult, HttpServletRequest httpServletRequest, RedirectAttributes redirectAttributes) throws IOException {
|
||||
if (bindingResult.hasErrors()) {
|
||||
return "apps/community/mainPartnershipForm";
|
||||
}
|
||||
|
||||
partnershipApplicationFacade.createPartnershipApplication(partnershipApplicationDTO);
|
||||
|
||||
// 성공 메시지 추가
|
||||
redirectAttributes.addFlashAttribute("success", "사업제휴신청이 완료되었습니다.");
|
||||
|
||||
httpServletRequest.getSession().removeAttribute("previousPage");
|
||||
return "redirect:/partnership";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.eactive.apim.portal.apps.community.partnership.dto;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PartnershipApplicationDTO {
|
||||
|
||||
@Size(max = 255, message = "제목은 255자를 초과할 수 없습니다.")
|
||||
private String bizSubject;
|
||||
|
||||
private String bizDetail;
|
||||
|
||||
/**
|
||||
* 첨부파일ID
|
||||
*/
|
||||
private String fileId;
|
||||
|
||||
private List<MultipartFile> files;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.eactive.apim.portal.apps.community.partnership.mapper;
|
||||
|
||||
|
||||
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
||||
import com.eactive.apim.portal.common.mapper.CommonMapper;
|
||||
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Mapper(componentModel = "spring",
|
||||
uses = {CommonMapper.class},
|
||||
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
@Component
|
||||
|
||||
public interface PartnershipApplicationMapper {
|
||||
|
||||
PartnershipApplication toEntity(PartnershipApplicationDTO dto);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.eactive.apim.portal.apps.community.partnership.repository;
|
||||
|
||||
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
@EMSDataSource
|
||||
public interface PartnershipApplicationRepository extends JpaRepository<PartnershipApplication, String>, JpaSpecificationExecutor<PartnershipApplication> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.eactive.apim.portal.apps.community.partnership.service;
|
||||
|
||||
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface PartnershipApplicationFacade {
|
||||
|
||||
void createPartnershipApplication(PartnershipApplicationDTO partnershipApplicationDTO) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.eactive.apim.portal.apps.community.partnership.service;
|
||||
|
||||
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
||||
import com.eactive.apim.portal.apps.community.partnership.mapper.PartnershipApplicationMapper;
|
||||
import com.eactive.apim.portal.file.entity.FileInfo;
|
||||
import com.eactive.apim.portal.file.service.FileService;
|
||||
import com.eactive.apim.portal.file.service.FileTypeContext;
|
||||
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PartnershipApplicationFacadeImpl implements PartnershipApplicationFacade {
|
||||
|
||||
private final PartnershipApplicationService partnershipApplicationService;
|
||||
private final PartnershipApplicationMapper partnershipApplicationMapper;
|
||||
private final FileService fileService;
|
||||
|
||||
|
||||
@Override
|
||||
public void createPartnershipApplication(PartnershipApplicationDTO partnershipApplicationDTO) throws IOException {
|
||||
|
||||
FileInfo file = null;
|
||||
if (!partnershipApplicationDTO.getFiles().isEmpty()) {
|
||||
FileTypeContext.setFileType("business");
|
||||
file = fileService.createFile(partnershipApplicationDTO.getFiles());
|
||||
}
|
||||
PartnershipApplication partnershipApplication = partnershipApplicationMapper.toEntity(partnershipApplicationDTO);
|
||||
if (file != null) {
|
||||
partnershipApplication.setFileId(file.getFileId());
|
||||
}
|
||||
partnershipApplicationService.createPartnershipApplication(partnershipApplication);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.eactive.apim.portal.apps.community.partnership.service;
|
||||
|
||||
import com.eactive.apim.portal.apps.community.partnership.repository.PartnershipApplicationRepository;
|
||||
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class PartnershipApplicationService {
|
||||
|
||||
private final PartnershipApplicationRepository partnershipApplicationRepository;
|
||||
|
||||
@Autowired
|
||||
public PartnershipApplicationService(PartnershipApplicationRepository partnershipApplicationRepository) {
|
||||
this.partnershipApplicationRepository = partnershipApplicationRepository;
|
||||
}
|
||||
|
||||
public void createPartnershipApplication(PartnershipApplication partnershipApplication) {
|
||||
partnershipApplicationRepository.save(partnershipApplication);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.eactive.apim.portal.apps.community.notice.service.PortalNoticeFacade;
|
||||
import com.eactive.apim.portal.apps.main.service.MainApiFacade;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -25,13 +26,12 @@ public class IndexController {
|
||||
|
||||
private final ApiSearchFacade apiSearchFacade;
|
||||
private final MainApiFacade mainApiFacade;
|
||||
private final PortalNoticeFacade portalNoticeFacade;
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
|
||||
/**
|
||||
* 메인 페이지 API는 Portal Property 에 main.service.list 에 등록된 그룹을 기준으로 API를 조회함.
|
||||
* 프로퍼티에 등록되어 있어도 어드민의 그룹 표시 설정이 N이면 표시 되지 않음.
|
||||
* 어드민의 API 스펙의 표시 설정이 N이면 표시되지 않음.
|
||||
* 그룹 또는 권한이 지정된 경우, 해당사용자의 권한 또는 기관이 일치해야 표시됨.
|
||||
* 어드민의 API 스펙의 표시 설정이 N이면 표시되지 않음. 그룹 또는 권한이 지정된 경우, 해당사용자의 권한 또는 기관이 일치해야 표시됨.
|
||||
* <p>
|
||||
* 검색어는 Portal Property 또는 메인 관리 화면에 main.keyword.list 에 등록된 내용이 표시 됨.
|
||||
*
|
||||
@@ -40,23 +40,8 @@ public class IndexController {
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public String index(Model model) {
|
||||
// Step 1: Fetch and sort API services
|
||||
List<ApiServiceDTO> apiServices = getSortedApiServices(null);
|
||||
|
||||
// Step 2: Create a map of API ID to ApiServiceDTO for icon mapping
|
||||
Map<String, ApiServiceDTO> mainIconsMap = createMainIconsMap(apiServices);
|
||||
|
||||
// Step 3: Merge all API lists from apiServices
|
||||
List<ApiServiceApiDTO> allApis = getAllApis(apiServices);
|
||||
|
||||
// Step 4: Enrich API spec info DTOs with main icon and service info
|
||||
List<ApiSpecInfoDto> apiSpecInfoDtos = enrichApiSpecInfo(apiServices, allApis, mainIconsMap);
|
||||
|
||||
// Step 5: Calculate total API count
|
||||
int totalApiCount = calculateTotalApiCount(apiServices);
|
||||
|
||||
// Step 6: Fetch portal notices and hashtags
|
||||
List<PortalNoticeDTO> portalNotices = portalNoticeFacade.getLatestNotices();
|
||||
List<ApiServiceDTO> services = mainApiFacade.getOpenApiServices();
|
||||
List<String> hashTags = mainApiFacade.getHashTags();
|
||||
|
||||
ApiGroupSearch search = new ApiGroupSearch();
|
||||
@@ -64,107 +49,19 @@ public class IndexController {
|
||||
|
||||
int selectedApiCount = (int) searchResult.get("selectedApiCount");
|
||||
|
||||
// 서비스 이용 수
|
||||
int serviceCount = ((List<?>) searchResult.get("services")).size();
|
||||
|
||||
// 승인된 기업 건수
|
||||
int approvedOrgCount = mainApiFacade.getApprovedOrgCount();
|
||||
|
||||
// Step 7: Add attributes to model
|
||||
addAttributesToModel(model, apiServices, apiSearchFacade.sortApisByService(apiSpecInfoDtos, apiServices), totalApiCount, portalNotices, hashTags, serviceCount, approvedOrgCount, selectedApiCount);
|
||||
addAttributesToModel(model, services, hashTags, serviceCount, approvedOrgCount, selectedApiCount);
|
||||
|
||||
return "apps/main/index";
|
||||
}
|
||||
|
||||
private List<ApiServiceDTO> getSortedApiServices(String apiId) {
|
||||
List<ApiServiceDTO> apiServices = mainApiFacade.getOpenApiServices(apiId);
|
||||
apiServices.sort(Comparator.comparing(ApiServiceDTO::getDisplayOrder));
|
||||
return apiServices;
|
||||
}
|
||||
|
||||
private Map<String, ApiServiceDTO> createMainIconsMap(List<ApiServiceDTO> apiServices) {
|
||||
Map<String, ApiServiceDTO> mainIconsMap = new HashMap<>();
|
||||
apiServices.forEach(service ->
|
||||
service.getApiGroupApiList().forEach(api ->
|
||||
mainIconsMap.put(api.getApiId(), service)
|
||||
)
|
||||
);
|
||||
return mainIconsMap;
|
||||
}
|
||||
|
||||
private List<ApiServiceApiDTO> getAllApis(List<ApiServiceDTO> apiServices) {
|
||||
return apiServices.stream()
|
||||
.flatMap(service -> service.getApiGroupApiList().stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<ApiSpecInfoDto> enrichApiSpecInfo(List<ApiServiceDTO> services, List<ApiServiceApiDTO> allApis, Map<String, ApiServiceDTO> mainIconsMap) {
|
||||
List<String> apiIds = allApis.stream().map(ApiServiceApiDTO::getApiId).collect(Collectors.toList());
|
||||
List<ApiSpecInfoDto> apiSpecInfoDtos = mainApiFacade.getOpenApis(apiIds);
|
||||
apiSpecInfoDtos.forEach(spec -> {
|
||||
ApiServiceDTO serviceDTO = mainIconsMap.get(spec.getApiId());
|
||||
if (serviceDTO != null) {
|
||||
spec.setMainIcon(serviceDTO.getMainIcon());
|
||||
spec.setService(serviceDTO.getGroupName());
|
||||
}
|
||||
});
|
||||
|
||||
boolean isAuthenticated = SecurityUtil.isAuthenticated();
|
||||
String roleCode;
|
||||
String org;
|
||||
|
||||
if (isAuthenticated) {
|
||||
roleCode = SecurityUtil.getPortalAuthenticatedUser().getRoleCode().toString();
|
||||
org = SecurityUtil.getUserOrg().getId();
|
||||
} else {
|
||||
roleCode = null;
|
||||
org = null;
|
||||
}
|
||||
|
||||
List<ApiSpecInfoDto> filteredApiSpecInfoDtos = apiSpecInfoDtos.stream()
|
||||
.filter(spec -> {
|
||||
if (!isAuthenticated) {
|
||||
return spec.getDisplayOrg() == null && spec.getDisplayRoleCode() == null;
|
||||
}
|
||||
boolean orgMatch = false;
|
||||
if (org != null) {
|
||||
orgMatch = spec.getDisplayOrg() == null || spec.getDisplayOrg().isEmpty() || spec.getDisplayOrg().contains(org);
|
||||
}
|
||||
boolean roleMatch = spec.getDisplayRoleCode() == null || spec.getDisplayRoleCode().isEmpty() || spec.getDisplayRoleCode().contains(roleCode);
|
||||
return orgMatch || roleMatch;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<String> filteredApiIds = filteredApiSpecInfoDtos.stream()
|
||||
.map(ApiSpecInfoDto::getApiId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
services.forEach(service -> {
|
||||
if (service.getApiGroupApiList() != null) {
|
||||
List<ApiServiceApiDTO> filteredApiList = service.getApiGroupApiList().stream()
|
||||
.filter(api -> filteredApiIds.contains(api.getApiId()))
|
||||
.collect(Collectors.toList());
|
||||
service.setApiGroupApiList(filteredApiList);
|
||||
}
|
||||
});
|
||||
|
||||
return filteredApiSpecInfoDtos.stream().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private int calculateTotalApiCount(List<ApiServiceDTO> apiServices) {
|
||||
return apiServices.stream()
|
||||
.mapToInt(service -> service.getApiGroupApiList().size())
|
||||
.sum();
|
||||
}
|
||||
|
||||
private void addAttributesToModel(Model model, List<ApiServiceDTO> apiServices,
|
||||
List<ApiSpecInfoDto> apiSpecInfoDtos, int totalApiCount,
|
||||
List<PortalNoticeDTO> portalNotices, List<String> hashTags, int serviceCount, int approvedOrgCount, int selectedApiCount) {
|
||||
private void addAttributesToModel(Model model, List<ApiServiceDTO> apiServices, List<String> hashTags, int serviceCount, int approvedOrgCount, int selectedApiCount) {
|
||||
|
||||
model.addAttribute("services", apiServices);
|
||||
model.addAttribute("apis", apiSpecInfoDtos);
|
||||
model.addAttribute("totalApiCount", totalApiCount);
|
||||
model.addAttribute("portalNotices", portalNotices);
|
||||
model.addAttribute("hashtags", hashTags);
|
||||
|
||||
model.addAttribute("serviceCount", serviceCount);
|
||||
@@ -172,15 +69,4 @@ public class IndexController {
|
||||
model.addAttribute("selectedApiCount", selectedApiCount);
|
||||
}
|
||||
|
||||
@GetMapping("/api_fragments")
|
||||
public String getApiFragments(@RequestParam(value = "id", required = false) String id, Model model) {
|
||||
List<ApiServiceDTO> apiServices = getSortedApiServices(id);
|
||||
Map<String, ApiServiceDTO> mainIconsMap = createMainIconsMap(apiServices);
|
||||
List<ApiServiceApiDTO> allApis = getAllApis(apiServices);
|
||||
List<ApiSpecInfoDto> apiSpecInfoDtos = enrichApiSpecInfo(apiServices, allApis, mainIconsMap);
|
||||
model.addAttribute("apis", apiSpecInfoDtos);
|
||||
return "apps/main/apiListFragment :: apiListFragment";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,17 +7,13 @@ import com.eactive.apim.portal.apps.apiservice.dto.ApiServiceDTO;
|
||||
import com.eactive.apim.portal.apps.apiservice.service.ApiServiceService;
|
||||
import com.eactive.apim.portal.apps.user.service.PortalOrgService;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Transactional
|
||||
@Service
|
||||
@@ -34,17 +30,13 @@ public class MainApiFacade {
|
||||
return portalOrgService.getActiveApprovedOrgCount();
|
||||
}
|
||||
|
||||
public List<ApiServiceDTO> getOpenApiServices(String serviceId) {
|
||||
public List<ApiServiceDTO> getOpenApiServices() {
|
||||
ApiGroupSearch search = new ApiGroupSearch();
|
||||
|
||||
Map<String, String> property = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY);
|
||||
String services = property.getOrDefault("main.service.list", "");
|
||||
|
||||
if (StringUtils.hasText(serviceId) && services.contains(serviceId)) {
|
||||
search.setGroupIds(Collections.singletonList(serviceId));
|
||||
} else {
|
||||
search.setGroupIds(Arrays.asList(services.split(",")));
|
||||
}
|
||||
search.setGroupIds(Arrays.asList(services.replace(" ", "").split(",")));
|
||||
|
||||
return apiServiceService.searchApiGroups(search);
|
||||
}
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
package com.eactive.apim.portal.apps.proxy;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/_proxy") // /proxy 대신 /_proxy 사용
|
||||
@Slf4j
|
||||
public class ApimProxyController {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private final ProxyProperties proxyProperties;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final MediaType JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON, StandardCharsets.UTF_8);
|
||||
|
||||
|
||||
public ApimProxyController(
|
||||
RestTemplateBuilder restTemplateBuilder,
|
||||
ProxyProperties proxyProperties,
|
||||
ObjectMapper objectMapper) {
|
||||
this.proxyProperties = proxyProperties;
|
||||
this.objectMapper = objectMapper;
|
||||
this.restTemplate = restTemplateBuilder
|
||||
.setConnectTimeout(Duration.ofMillis(proxyProperties.getTimeout().getConnect()))
|
||||
.setReadTimeout(Duration.ofMillis(proxyProperties.getTimeout().getRead()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ResponseEntity<String> createJsonResponse(HttpStatus status, String message) {
|
||||
ObjectNode jsonResponse = objectMapper.createObjectNode()
|
||||
.put("status", status.value())
|
||||
.put("message", message);
|
||||
return ResponseEntity
|
||||
.status(status)
|
||||
.contentType(JSON_UTF8)
|
||||
.body(jsonResponse.toString());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/**")
|
||||
public ResponseEntity<String> proxyRequest(
|
||||
HttpServletRequest request,
|
||||
@RequestBody(required = false) String body,
|
||||
@RequestHeader HttpHeaders headers) {
|
||||
|
||||
String targetKey = headers.getFirst("target_host");
|
||||
if (targetKey == null || targetKey.trim().isEmpty()) {
|
||||
log.error("Missing or empty target_host header");
|
||||
return createJsonResponse(HttpStatus.BAD_REQUEST, "Error: target_host header is required");
|
||||
}
|
||||
|
||||
String targetUrl = proxyProperties.getTargets().get(targetKey.trim().toLowerCase());
|
||||
if (targetUrl == null) {
|
||||
log.error("Invalid target_host: {}. Available targets: {}",
|
||||
targetKey, proxyProperties.getTargets().keySet());
|
||||
return createJsonResponse(HttpStatus.BAD_REQUEST,
|
||||
"Error: Invalid target_host. Must be one of: " +
|
||||
String.join(", ", proxyProperties.getTargets().keySet()));
|
||||
}
|
||||
|
||||
try {
|
||||
String requestUrl = request.getRequestURI().replace("/_proxy", "");
|
||||
URI uri = UriComponentsBuilder
|
||||
.fromHttpUrl(targetUrl + requestUrl)
|
||||
.query(request.getQueryString())
|
||||
.build()
|
||||
.toUri();
|
||||
|
||||
HttpMethod method = HttpMethod.valueOf(request.getMethod());
|
||||
|
||||
HttpHeaders proxyHeaders = new HttpHeaders();
|
||||
headers.forEach((key, value) -> {
|
||||
if (!key.equalsIgnoreCase("host") &&
|
||||
!key.equalsIgnoreCase("target_host")) {
|
||||
proxyHeaders.addAll(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
HttpEntity<String> httpEntity = new HttpEntity<>(body, proxyHeaders);
|
||||
|
||||
log.debug("Forwarding request to: {} ({})", targetKey, uri);
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
uri,
|
||||
method,
|
||||
httpEntity,
|
||||
String.class
|
||||
);
|
||||
log.debug("Received response status: {}", response.getStatusCode());
|
||||
|
||||
// Create JSON response with the original response data
|
||||
ObjectNode jsonResponse = objectMapper.createObjectNode()
|
||||
.put("status", response.getStatusCode().value());
|
||||
|
||||
// Try to parse the response body as JSON, if it fails, include it as a string
|
||||
try {
|
||||
jsonResponse.set("data", objectMapper.readTree(response.getBody()));
|
||||
} catch (Exception e) {
|
||||
jsonResponse.put("data", response.getBody());
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.status(response.getStatusCode())
|
||||
.contentType(JSON_UTF8)
|
||||
.body(jsonResponse.toString());
|
||||
|
||||
} catch (HttpStatusCodeException e) {
|
||||
log.error("Target server returned error: {} for host: {}", e.getStatusCode(), targetKey);
|
||||
ObjectNode jsonResponse = objectMapper.createObjectNode()
|
||||
.put("status", e.getStatusCode().value());
|
||||
|
||||
// Try to parse the error response body as JSON, if it fails, include it as a string
|
||||
try {
|
||||
jsonResponse.set("data", objectMapper.readTree(e.getResponseBodyAsString()));
|
||||
} catch (Exception ex) {
|
||||
jsonResponse.put("data", e.getResponseBodyAsString());
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.status(e.getStatusCode())
|
||||
.contentType(JSON_UTF8)
|
||||
.body(jsonResponse.toString());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Error during proxy request to: {}", targetKey, e);
|
||||
return createJsonResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.eactive.apim.portal.apps.proxy;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "proxy")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProxyProperties {
|
||||
private Map<String, String> targets;
|
||||
private Timeout timeout = new Timeout();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class Timeout {
|
||||
private int connect = 5000;
|
||||
private int read = 5000;
|
||||
}
|
||||
}
|
||||
@@ -49,9 +49,11 @@ public final class SecurityUtil {
|
||||
|
||||
public static PortalOrgDTO getUserOrg() {
|
||||
PortalOrgDTO portalOrgDTO = new PortalOrgDTO();
|
||||
if (Objects.requireNonNull(getPortalAuthenticatedUser()).getPortalOrg() != null) {
|
||||
portalOrgDTO.setOrgName(getPortalAuthenticatedUser().getPortalOrg().getOrgName());
|
||||
portalOrgDTO.setId(getPortalAuthenticatedUser().getPortalOrg().getId());
|
||||
PortalAuthenticatedUser portalAuthenticatedUser = getPortalAuthenticatedUser();
|
||||
if (Objects.requireNonNull(portalAuthenticatedUser).getPortalOrg() != null) {
|
||||
portalOrgDTO.setOrgName(portalAuthenticatedUser.getPortalOrg().getOrgName());
|
||||
portalOrgDTO.setId(portalAuthenticatedUser.getPortalOrg().getId());
|
||||
portalOrgDTO.setOrgCode(portalAuthenticatedUser.getPortalOrg().getOrgCode());
|
||||
}
|
||||
|
||||
return portalOrgDTO;
|
||||
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 259 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 712 KiB |
|
After Width: | Height: | Size: 403 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 149 KiB |
@@ -60,7 +60,7 @@
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
z-index: 1000;
|
||||
height: 90px;
|
||||
height: 112px;
|
||||
transition: all 0.3s ease;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
}
|
||||
@@ -693,9 +693,7 @@
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background: var(--light-bg);
|
||||
color: var(--primary-blue);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,7 +786,7 @@
|
||||
// Body Layout Compensation
|
||||
// ===========================
|
||||
body {
|
||||
padding-top: 65px; // Compensate for fixed header
|
||||
padding-top: 112px; // Compensate for fixed header (112px height)
|
||||
}
|
||||
|
||||
// ===========================
|
||||
@@ -796,7 +794,7 @@ body {
|
||||
// ===========================
|
||||
@media (max-width: 768px) {
|
||||
.global-header {
|
||||
height: 60px;
|
||||
height: 90px;
|
||||
|
||||
.container .header-content {
|
||||
padding: 0 16px;
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
@import 'pages/notice';
|
||||
@import 'pages/inquiry';
|
||||
@import 'pages/org-register';
|
||||
@import 'pages/partnership';
|
||||
@import 'pages/user-management';
|
||||
@import 'pages/commission';
|
||||
@import 'pages/terms-agreements';
|
||||
|
||||
@@ -6,21 +6,22 @@
|
||||
.api-market-container {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
background-color: $gray-bg;
|
||||
background-color: $white;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
// Sidebar Navigation
|
||||
.api-market-sidebar {
|
||||
width: 280px;
|
||||
background-color: $white;
|
||||
border-right: 1px solid $border-gray;
|
||||
width: 283px;
|
||||
background-color: #FDFDFD;
|
||||
border-radius: 20px;
|
||||
padding: $spacing-2xl $spacing-lg;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
top: $spacing-lg;
|
||||
height: calc(100vh - 32px);
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
margin: $spacing-md;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
width: 240px;
|
||||
@@ -35,6 +36,8 @@
|
||||
box-shadow: $shadow-lg;
|
||||
z-index: $z-index-modal;
|
||||
height: calc(100vh - 60px); // Full height minus header
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
|
||||
&.mobile-open {
|
||||
transform: translateX(0);
|
||||
@@ -42,30 +45,59 @@
|
||||
}
|
||||
}
|
||||
|
||||
.api-sidebar-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: $spacing-xl;
|
||||
padding-bottom: $spacing-lg;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.api-sidebar-nav {
|
||||
.menu-section {
|
||||
margin-bottom: $spacing-xs;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 1px solid #DDDDDD;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
padding: 12px $spacing-md;
|
||||
padding: 16px 10px;
|
||||
font-size: $font-size-sm;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $secondary-blue;
|
||||
color: $text-dark;
|
||||
cursor: pointer;
|
||||
border-radius: $border-radius-md;
|
||||
transition: $transition-base;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: $gray-bg;
|
||||
background-color: rgba($primary-blue, 0.05);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $light-bg;
|
||||
color: $secondary-blue;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 6px 0 6px 8px;
|
||||
border-color: transparent transparent transparent $text-dark;
|
||||
}
|
||||
}
|
||||
|
||||
.api-count {
|
||||
@@ -303,9 +335,15 @@
|
||||
// Card Grid
|
||||
.api-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
grid-template-columns: repeat(3, 1fr); // 3 cards per row on desktop
|
||||
gap: $spacing-lg;
|
||||
|
||||
// Tablet view - 2 cards per row
|
||||
@media (max-width: $breakpoint-md) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
// Mobile view - 1 card per row
|
||||
@media (max-width: $breakpoint-sm) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@@ -317,119 +355,80 @@
|
||||
border-radius: $border-radius-lg;
|
||||
padding: $spacing-xl;
|
||||
box-shadow: $shadow-sm;
|
||||
transition: $transition-base;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
min-height: 220px;
|
||||
gap: $spacing-md;
|
||||
min-height: 180px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: $gradient-primary;
|
||||
transform: scaleX(0);
|
||||
transform-origin: left;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: $shadow-lg;
|
||||
transform: translateY(-5px);
|
||||
|
||||
&::before {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.api-card-icon {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
border: 1px solid $border-gray;
|
||||
|
||||
&:active {
|
||||
transform: translateY(-3px);
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.api-card-header {
|
||||
// Group Info Section (Icon + Name)
|
||||
.api-card-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-sm;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.api-card-badge {
|
||||
display: inline-flex;
|
||||
.api-card-group-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
background-color: $gray-bg;
|
||||
border-radius: $border-radius-sm;
|
||||
font-size: $font-size-xs;
|
||||
color: $text-gray;
|
||||
font-weight: $font-weight-medium;
|
||||
justify-content: center;
|
||||
background: $gray-bg;
|
||||
border-radius: $border-radius-md;
|
||||
flex-shrink: 0;
|
||||
|
||||
&::before {
|
||||
content: "◉";
|
||||
img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
color: $primary-blue;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.api-card-title {
|
||||
font-size: $font-size-md;
|
||||
.api-card-group-name {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-gray;
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
// API Name (Title)
|
||||
.api-card-name {
|
||||
font-size: $font-size-lg;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $text-dark;
|
||||
margin-bottom: 12px;
|
||||
line-height: $line-height-tight;
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
// API Description
|
||||
.api-card-description {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-gray;
|
||||
line-height: $line-height-normal;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.api-card-icon {
|
||||
text-align: center;
|
||||
margin-top: $spacing-lg;
|
||||
font-size: 48px;
|
||||
opacity: 0.8;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
img {
|
||||
max-width: 60px;
|
||||
max-height: 60px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
// Icon color variations
|
||||
.api-card:nth-child(3n+1) .api-card-icon {
|
||||
color: #60a5fa;
|
||||
}
|
||||
|
||||
.api-card:nth-child(3n+2) .api-card-icon {
|
||||
color: #34d399;
|
||||
}
|
||||
|
||||
.api-card:nth-child(3n+3) .api-card-icon {
|
||||
color: #818cf8;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
// Empty State
|
||||
@@ -777,4 +776,4 @@
|
||||
color: $primary-blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
.hero-carousel-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 800px;
|
||||
height: 720px;
|
||||
overflow: hidden;
|
||||
|
||||
@include respond-to('md') {
|
||||
@@ -369,8 +369,19 @@
|
||||
.api-search-section {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin-bottom: 80px;
|
||||
margin-top: -80px;
|
||||
//margin-top: -80px;
|
||||
overflow: hidden;
|
||||
background: #e9f9ff;
|
||||
|
||||
.search-background {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url('/img/bg_main_intersect.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.search-content-wrapper {
|
||||
position: relative;
|
||||
@@ -378,7 +389,6 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 40px;
|
||||
padding-top: 60px;
|
||||
z-index: 1;
|
||||
|
||||
@include respond-to('md') {
|
||||
@@ -527,12 +537,13 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
padding: 0 20px 40px;
|
||||
padding: 0 20px 0px;
|
||||
z-index: 1;
|
||||
|
||||
@include respond-to('md') {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 20px 30px;
|
||||
}
|
||||
@@ -553,6 +564,7 @@
|
||||
flex-wrap: wrap;
|
||||
|
||||
@include respond-to('md') {
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
@@ -597,8 +609,19 @@
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center; // 수직 중앙 정렬
|
||||
padding: 80px 0 100px;
|
||||
padding: 175px 0 100px;
|
||||
background: $white;
|
||||
overflow: hidden;
|
||||
|
||||
.showcase-background {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url('/img/bg_main_recommend_apis.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.showcase-wrapper {
|
||||
max-width: 1228px;
|
||||
@@ -606,15 +629,17 @@
|
||||
padding: 0 20px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 140px;
|
||||
margin-bottom: 24px;
|
||||
position: relative;
|
||||
padding-right: 150px; // 버튼 공간 확보
|
||||
|
||||
@include respond-to('md') {
|
||||
margin-bottom: 80px;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,7 +649,7 @@
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
color: #000000;
|
||||
margin: 0 0 16px 0;
|
||||
margin: 0;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 36px;
|
||||
@@ -641,7 +666,7 @@
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #1E1E1E;
|
||||
margin: 0;
|
||||
margin-bottom: 30px;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 20px;
|
||||
@@ -655,34 +680,43 @@
|
||||
|
||||
.btn-all-apis {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
top: 64px;
|
||||
transform: translateY(-50%);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 15px 20px;
|
||||
justify-content: center;
|
||||
gap: 21px;
|
||||
padding: 12px 24px;
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
font-size: 18px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #000000;
|
||||
color: #FFFFFF;
|
||||
background: #008ae2;
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
transition: all 0.3s ease;
|
||||
height: 40px;
|
||||
width: 135px;
|
||||
|
||||
@include respond-to('md') {
|
||||
position: static;
|
||||
margin-top: 24px;
|
||||
justify-content: center;
|
||||
transform: none;
|
||||
margin: 24px auto 0;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 7px;
|
||||
height: 15px;
|
||||
width: 11px;
|
||||
height: 17px;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
path {
|
||||
stroke: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #F5F5F5;
|
||||
background: darken(#008ae2, 10%);
|
||||
|
||||
svg {
|
||||
transform: translateX(4px);
|
||||
@@ -708,16 +742,24 @@
|
||||
|
||||
.api-card {
|
||||
width: 283px;
|
||||
height: 360px;
|
||||
height: 320px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #DDDDDD;
|
||||
border-radius: 30px;
|
||||
padding: 56px 25px 48px;
|
||||
border-radius: 20px;
|
||||
padding: 36px 38px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
gap: 0px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||
border-color: #008ae2;
|
||||
}
|
||||
|
||||
@include respond-to('md') {
|
||||
width: calc(50% - 10px);
|
||||
@@ -736,12 +778,12 @@
|
||||
font-weight: 700;
|
||||
line-height: 1.67;
|
||||
color: #2A2A2A;
|
||||
margin: 0 0 16px 0;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
|
||||
.card-description {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
font-size: 14px;
|
||||
font-size: 15px;
|
||||
font-weight: 400;
|
||||
line-height: 1.43;
|
||||
color: #515151;
|
||||
@@ -751,13 +793,13 @@
|
||||
}
|
||||
|
||||
.card-illustration {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: auto;
|
||||
align-self: center;
|
||||
align-self: flex-end;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
@@ -783,7 +825,6 @@
|
||||
min-height: 980px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 150px;
|
||||
|
||||
.info-background {
|
||||
position: absolute;
|
||||
@@ -894,6 +935,7 @@
|
||||
white-space: nowrap;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 310px;
|
||||
height: 128px;
|
||||
|
||||
@include respond-to('sm') {
|
||||
font-size: 20px;
|
||||
@@ -912,20 +954,20 @@
|
||||
}
|
||||
|
||||
.action-btn-primary {
|
||||
background: #00acdd;
|
||||
background: #0049B4;
|
||||
color: #FFFFFF;
|
||||
|
||||
&:hover {
|
||||
background: darken(#00acdd, 10%);
|
||||
background: darken(#0049B4, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.action-btn-secondary {
|
||||
background: #d5a654;
|
||||
background: #00ACDD;
|
||||
color: #FFFFFF;
|
||||
|
||||
&:hover {
|
||||
background: darken(#d5a654, 10%);
|
||||
background: darken(#00ACDD, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -953,52 +995,70 @@
|
||||
// Support Center section styles
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Support Center Section - 비지니스의 시작 (Figma Design)
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
// Support Center Section - 비지니스의 시작 (Figma Design)
|
||||
// -----------------------------------------------------------------------------
|
||||
.support-center {
|
||||
position: relative;
|
||||
padding: $spacing-6xl 0;
|
||||
background: #f2f6fb;
|
||||
padding: 150px 0;
|
||||
background: #eef7fd;
|
||||
overflow: hidden;
|
||||
min-height: 980px;
|
||||
|
||||
.support-background-pattern {
|
||||
.support-background {
|
||||
position: absolute;
|
||||
right: 320px;
|
||||
top: 0;
|
||||
width: 700px;
|
||||
height: 660px;
|
||||
background-image: url('/img/bg_main_community.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 1920px;
|
||||
pointer-events: none;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 17px; // Figma: top-[3234px] relative to page, section starts at ~3217px
|
||||
left: 46%; // Approximate positioning
|
||||
width: 693px;
|
||||
height: 597px;
|
||||
background-image: url('/img/bg_support_center.png'); // Assuming this image exists or use placeholder
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
opacity: 0.5; // Adjust based on visual
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
margin-bottom: $spacing-4xl;
|
||||
text-align: left;
|
||||
margin-bottom: 80px;
|
||||
text-align: center;
|
||||
|
||||
.section-title {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
font-size: 44px;
|
||||
line-height: 70px;
|
||||
line-height: 1.6;
|
||||
color: #000000;
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 36px;
|
||||
line-height: 60px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
font-size: 28px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.title-regular {
|
||||
@@ -1014,104 +1074,46 @@
|
||||
.support-grid {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
max-width: 1228px; // 598 + 283 + 283 + (32 * 2) = 1228px
|
||||
margin: 0 auto;
|
||||
|
||||
@include respond-to('md') {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
// 공지사항 - 큰 카드
|
||||
.support-card-large {
|
||||
flex: 1;
|
||||
max-width: 598px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 55px 52px 37px;
|
||||
// 통합 Support Card
|
||||
.support-card {
|
||||
background: #FFFFFF;
|
||||
border-radius: 20px;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
min-height: 377px;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 377px; // 모든 카드 동일 높이
|
||||
|
||||
.card-icon {
|
||||
width: 104px;
|
||||
height: 104px;
|
||||
margin-bottom: 42px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: #212529;
|
||||
margin: 0 0 10px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
color: #515961;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
@include respond-to('md') {
|
||||
width: 100%;
|
||||
max-width: 598px;
|
||||
height: auto;
|
||||
min-height: 260px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-8px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 30px rgba(0, 73, 180, 0.15);
|
||||
}
|
||||
|
||||
@include respond-to('md') {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 오른쪽 작은 카드들 컨테이너
|
||||
.support-cards-small {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 32px;
|
||||
|
||||
@include respond-to('md') {
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ, Q&A - 작은 카드
|
||||
.support-card-small {
|
||||
width: 283px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 55px 52px 37px;
|
||||
background: #FAFAFA;
|
||||
border: 1px solid #DDDDDD;
|
||||
border-radius: 20px;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
min-height: 377px;
|
||||
|
||||
.card-icon {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
@@ -1121,33 +1123,146 @@
|
||||
}
|
||||
|
||||
.card-content {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
h3 {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
font-size: 36px;
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: #000000;
|
||||
color: #212529;
|
||||
margin: 0 0 10px 0;
|
||||
line-height: 1.3;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
color: #515961;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-8px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||
background: #FFFFFF;
|
||||
// 공지사항 카드 (598px width)
|
||||
&--notice {
|
||||
width: 598px;
|
||||
flex-shrink: 0;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 60px 40px;
|
||||
background: #0049B4;
|
||||
|
||||
@include respond-to('md') {
|
||||
width: 100%;
|
||||
max-width: 598px;
|
||||
padding: 50px 40px;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 174px;
|
||||
height: 120px;
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
h3 {
|
||||
color: #FFFFFF;
|
||||
font-size: 36px;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 20px;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: darken(#0049B4, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
@include respond-to('md') {
|
||||
width: 100%;
|
||||
// FAQ & Q&A Cards (283px width each)
|
||||
&--faq, &--qna {
|
||||
width: 283px;
|
||||
flex-shrink: 0;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 60px 40px;
|
||||
|
||||
@include respond-to('md') {
|
||||
width: 100%;
|
||||
max-width: 598px;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin-bottom: 36px;
|
||||
|
||||
}
|
||||
|
||||
.card-content {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
flex: none;
|
||||
|
||||
h3 {
|
||||
font-size: 36px;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
|
||||
@include respond-to('md') {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ Card Specifics
|
||||
&--faq {
|
||||
background: #DAF0FF;
|
||||
|
||||
.card-content h3 {
|
||||
color: #212529;
|
||||
}
|
||||
}
|
||||
|
||||
// Q&A Card Specifics
|
||||
&--qna {
|
||||
background: #D9F6F8;
|
||||
|
||||
.card-content h3 {
|
||||
color: #212529;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: $spacing-4xl;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
|
||||
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_apikey_layout}">
|
||||
<body>
|
||||
|
||||
<section layout:fragment="contentFragment" class="content">
|
||||
|
||||
<div class="content_wrap">
|
||||
<div class="sub_title3">
|
||||
<h2 class="title">API키 신청</h2>
|
||||
</div>
|
||||
<div class="inner i_cs h_inner5">
|
||||
<div class="form_type">
|
||||
<div class="info1 form_top">
|
||||
<p class="title w_tit">
|
||||
<span class="dot">API키 이름</span>
|
||||
</p>
|
||||
<div class="info_line info_add">
|
||||
<div class="info_box1 w_inp4">
|
||||
<input type="text" name="name" style="max-width: 300px;" id="appRequestClientName" class="common_input_type_1 h_inp2" placeholder="API키 이름 입력">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infor api_dot top" style="margin-top: 10px;">
|
||||
<ul>
|
||||
<li>
|
||||
<p>인증키가 없을 경우, 승인 시, 인증키는 신규로 발급 됩니다.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<p class="pop_text l_text m-only" style="margin-top: 10px; font-weight: 700;">API</p>
|
||||
<div class="board_search sh_box top">
|
||||
<p class="pop_text l_text pc-only">API</p>
|
||||
<div class="search_txt ser_api w_inp2">
|
||||
<input type="text" class="common_input_type_1 h_inp2" id="api_keyword" placeholder="API 검색">
|
||||
</div>
|
||||
<div class="btn_wrap search_btn">
|
||||
<button type="button" class="btn_search" id="api_search">검색</button>
|
||||
<i class="i_search"></i>
|
||||
</div>
|
||||
<p class="pop_text l_text pop_text2 pc-only" style="margin-left:76px;">신청 API</p>
|
||||
</div>
|
||||
<div class="tb_conbox top">
|
||||
<div class="box table_type2 top_type">
|
||||
<table class="table_col table_min tb_bdtop" id="sourceTable" cellspacing="0" cellpadding="0" width="100%">
|
||||
<colgroup>
|
||||
<col width="60px">
|
||||
<col width="140px">
|
||||
<col width="230px">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<div class="total_wrap">
|
||||
<span class="inp_check b_tit">
|
||||
<input type="checkbox" class="agree_all" id="selectAllSourceTable" name="selectall" data-group="total">
|
||||
<label for="selectAllSourceTable"></label>
|
||||
</span>
|
||||
</div>
|
||||
</th>
|
||||
<th>서비스</th>
|
||||
<th>API</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="box pop_arrow m-only" style="text-align:center;">
|
||||
<a href="#none" class="add_apis"><img th:src="@{/img/icon/Icon_arrow_btn_down.png}" alt="올리기"></a>
|
||||
<a href="#none" class="remove_apis"><img th:src="@{/img/icon/Icon_arrow_btn_up.png}" alt="내리기"></a>
|
||||
</div>
|
||||
<div class="box pop_arrow pc-only" style="text-align:center;">
|
||||
<p>
|
||||
<a href="#none" class="add_apis"><img th:src="@{/img/icon/icon_arrow_btn_r.png}" alt="넣기"></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#none" class="remove_apis"><img th:src="@{/img/icon/icon_arrow_btn_l.png}" alt="빼기"></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="box table_type2 top_type">
|
||||
<table class="table_col table_min tb_bdtop" id="targetTable" cellspacing="0" cellpadding="0" width="100%">
|
||||
<colgroup>
|
||||
<col width="60px">
|
||||
<col width="140px">
|
||||
<col width="230px">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<div class="total_wrap">
|
||||
<span class="inp_check b_tit">
|
||||
<input type="checkbox" class="agree_all" id="selectAllTargetTable" name="selectall2" data-group="total2">
|
||||
<label for="selectAllTargetTable"></label>
|
||||
</span>
|
||||
</div>
|
||||
</th>
|
||||
<th>서비스</th>
|
||||
<th>API</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="pop_text l_text2">신청사유</p>
|
||||
<div class="pop_textbox">
|
||||
<textarea name="reason" rows="5" cols="30" class="common_textareaType_1" placeholder="신청사유를 입력해 주세요."></textarea>
|
||||
</div>
|
||||
<div class="form_type">
|
||||
<div class="btn_application btn_top3">
|
||||
<a th:href="@{/}" class="common_btn_type_1 gray"><span>취소</span></a>
|
||||
<div class="btn_gap"></div>
|
||||
<a href="#none" class="common_btn_type_1 request_apis"><span>확인</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<section layout:fragment="pagePopups" class="content pop">
|
||||
<th:block th:replace="~{fragment/apikey-request :: apiKeyRequestScript}"></th:block>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
$('.btn_cancel').on('click', function(){
|
||||
window.location.href = '/apis';
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -2,15 +2,25 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout/kjbank_base_layout}">
|
||||
layout:decorate="~{layout/kjbank_title_layout}">
|
||||
|
||||
<body>
|
||||
<th:block layout:fragment="title">
|
||||
<div class="org-page-title-banner" style="margin-bottom: 40px;">
|
||||
<h1>API 마켓</h1>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="contentFragment">
|
||||
<section class="api-market-container">
|
||||
|
||||
<!-- Sidebar Navigation -->
|
||||
<aside class="api-market-sidebar" id="apiSidebar">
|
||||
<!-- Sidebar Header Image -->
|
||||
<div class="api-sidebar-header">
|
||||
<img th:src="@{/img/api_sidebar.png}" alt="API">
|
||||
</div>
|
||||
|
||||
<nav class="api-sidebar-nav">
|
||||
<!-- All APIs -->
|
||||
<div class="menu-section">
|
||||
@@ -45,10 +55,6 @@
|
||||
|
||||
<!-- Header -->
|
||||
<div class="api-market-header">
|
||||
<div class="api-market-title">
|
||||
<h1>오픈API</h1>
|
||||
<h2>API 마켓</h2>
|
||||
</div>
|
||||
<div class="api-market-search">
|
||||
<form id="searchForm" th:action="@{/apis}" method="get">
|
||||
<input type="hidden" name="groupIds" th:value="${search.groupIds != null and !search.groupIds.isEmpty() ? search.groupIds[0] : ''}"/>
|
||||
@@ -76,33 +82,29 @@
|
||||
th:data-href="@{/apis/detail(id=${api.apiId})}"
|
||||
role="button"
|
||||
tabindex="0">
|
||||
<div>
|
||||
<!-- Card Header with Badge -->
|
||||
<div class="api-card-header">
|
||||
<span class="api-card-badge" th:if="${api.apiGroupName}" th:text="${api.apiGroupName}">
|
||||
카테고리
|
||||
</span>
|
||||
<!-- Group Info -->
|
||||
<div class="api-card-group">
|
||||
<div class="api-card-group-icon">
|
||||
<img th:if="${api.mainIcon}"
|
||||
th:src="${api.mainIcon}"
|
||||
th:alt="${api.apiGroupName}"
|
||||
onerror="this.style.display='none'; this.parentElement.innerHTML='<i class=\'fas fa-cube\'></i>'">
|
||||
<i th:if="${#strings.isEmpty(api.mainIcon)}" class="fas fa-cube"></i>
|
||||
</div>
|
||||
|
||||
<!-- Card Title -->
|
||||
<h3 class="api-card-title" th:text="${api.apiName}">
|
||||
API 이름
|
||||
</h3>
|
||||
|
||||
<!-- Card Description -->
|
||||
<p class="api-card-description" th:text="${api.apiSimpleDescription ?: 'API 설명이 없습니다.'}">
|
||||
API 설명
|
||||
</p>
|
||||
<span class="api-card-group-name" th:text="${api.apiGroupName}">
|
||||
그룹 이름
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Card Icon -->
|
||||
<div class="api-card-icon">
|
||||
<img th:if="${api.mainIcon}"
|
||||
th:src="${api.mainIcon}"
|
||||
th:alt="${api.apiName}"
|
||||
onerror="this.style.display='none'; this.parentElement.innerHTML='📄'">
|
||||
<span th:if="${#strings.isEmpty(api.mainIcon)}">📄</span>
|
||||
</div>
|
||||
<!-- API Name -->
|
||||
<h3 class="api-card-name" th:text="${api.apiName}">
|
||||
API 이름
|
||||
</h3>
|
||||
|
||||
<!-- API Description -->
|
||||
<p class="api-card-description" th:text="${api.apiSimpleDescription ?: 'API 설명이 없습니다.'}">
|
||||
API 설명
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_api_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
<body>
|
||||
|
||||
<section layout:fragment="contentFragment" class="content api_con">
|
||||
@@ -379,4 +379,4 @@ grant_type=client_credentials&client_id=your_client_id&client_secret=your_client
|
||||
</script>
|
||||
</th:block>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -215,7 +215,7 @@
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': /*[[${_csrf.token}]]*/ ''
|
||||
'X-XSRF-TOKEN': /*[[${_csrf.token}]]*/ ''
|
||||
},
|
||||
body: JSON.stringify({
|
||||
year: year,
|
||||
|
||||
@@ -1,77 +1,111 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_base_layout}">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
|
||||
|
||||
<body>
|
||||
|
||||
<section class="content" layout:fragment="contentFragment">
|
||||
<div class="content_wrap">
|
||||
<div class="sub_title3">
|
||||
<h2 class="title">사업 제휴 신청</h2>
|
||||
</div>
|
||||
<div class="inner i_cs h_inner6">
|
||||
<div class="con_title f_tit">
|
||||
<p>Kbank는 온라인 비즈니스 혁신을 위한 <span>사업 제안을 환영</span>합니다.</p>
|
||||
<!-- Page Header -->
|
||||
<div class="page-header">
|
||||
<div class="page-header-content">
|
||||
<h1 class="page-title">
|
||||
<i class="fas fa-handshake"></i>
|
||||
사업 제휴 신청
|
||||
</h1>
|
||||
<p class="page-description">
|
||||
광주은행은 온라인 비즈니스 혁신을 위한 <span class="highlight">사업 제안을 환영</span>합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form_type">
|
||||
<!-- Partnership Form Card -->
|
||||
<div class="partnership-form-container">
|
||||
<div class="card partnership-card">
|
||||
<form name="partnershipForm" id="partnershipForm" th:action="@{/partnership}" th:object="${partnership}"
|
||||
enctype="multipart/form-data" method="post">
|
||||
<div class="info1">
|
||||
<p class="title w_tit">
|
||||
<span class="dot">사업 제목</span>
|
||||
</p>
|
||||
<div class="info_line info_add">
|
||||
<div class="info_box1 w_inp4">
|
||||
<input type="text" class="common_input_type_1" id="bizSubject" th:field="*{bizSubject}"
|
||||
placeholder="제안하고자 하시는 사업제목" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('bizSubject')}"
|
||||
th:errors="*{bizSubject}"></div>
|
||||
</div>
|
||||
|
||||
<div class="info1">
|
||||
<p class="title w_tit">
|
||||
<span class="dot">사업 내용</span>
|
||||
</p>
|
||||
<div class="info_line info_add">
|
||||
<div class="info_box1 qna_text w_inp4">
|
||||
<textarea class="common_textareaType_1 f_inp" id="bizDetail" th:field="*{bizDetail}"
|
||||
placeholder="제안하고자 하시는 사업내용" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('bizDetail')}"
|
||||
th:errors="*{bizDetail}"></div>
|
||||
</div>
|
||||
|
||||
<div class="info1">
|
||||
<p class="title tit_add w_tit">첨부파일</p>
|
||||
<div class="info_line info_add">
|
||||
<div class="info_box1 info_add2">
|
||||
<div class="filebox">
|
||||
<input class="upload-name" value="첨부파일을 등록 해 주세요" disabled="disabled">
|
||||
</div>
|
||||
<div class="btn_check">
|
||||
<div class="file_btn">
|
||||
<label for="file">파일선택</label>
|
||||
<input type="file" id="file" name="files" accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.hwp,.gif,.jpg,.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-dot">
|
||||
<p>첨부파일은 10MB 이내로 등록해 주세요.</p>
|
||||
<p>문서파일과 이미지 파일만 등록 가능합니다. (pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg,
|
||||
png)</p>
|
||||
</div>
|
||||
<!-- 사업 제목 -->
|
||||
<div class="form-group">
|
||||
<label for="bizSubject">
|
||||
<i class="fas fa-lightbulb"></i>
|
||||
사업 제목
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
id="bizSubject"
|
||||
th:field="*{bizSubject}"
|
||||
placeholder="제안하고자 하시는 사업 제목을 입력해 주세요"
|
||||
required>
|
||||
<div class="form-error" th:if="${#fields.hasErrors('bizSubject')}" th:errors="*{bizSubject}">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn_application m_top">
|
||||
<a th:href="@{/}" id="cancelButton" class="common_btn_type_1 gray"><span>취소</span></a>
|
||||
<div class="btn_gap"></div>
|
||||
<button type="button" class="common_btn_type_1 btn_register"><span>제휴신청</span></button>
|
||||
<!-- 사업 내용 -->
|
||||
<div class="form-group">
|
||||
<label for="bizDetail">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
사업 내용
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
<textarea class="form-control"
|
||||
id="bizDetail"
|
||||
th:field="*{bizDetail}"
|
||||
rows="8"
|
||||
placeholder="제안하고자 하시는 사업 내용을 상세히 입력해 주세요"
|
||||
required></textarea>
|
||||
<div class="form-hint">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
사업의 목적, 내용, 기대 효과 등을 구체적으로 작성해 주세요
|
||||
</div>
|
||||
<div class="form-error" th:if="${#fields.hasErrors('bizDetail')}" th:errors="*{bizDetail}">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 첨부파일 -->
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<i class="fas fa-paperclip"></i>
|
||||
첨부파일
|
||||
</label>
|
||||
<div class="file-upload-wrapper">
|
||||
<input type="text"
|
||||
class="file-name-display"
|
||||
value="첨부파일을 등록해 주세요"
|
||||
readonly>
|
||||
<label for="file" class="btn btn-primary">
|
||||
<i class="fas fa-upload"></i>
|
||||
파일 선택
|
||||
</label>
|
||||
<button type="button" class="file-remove-btn" style="display: none;">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
<input type="file"
|
||||
id="file"
|
||||
name="files"
|
||||
accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.hwp,.gif,.jpg,.png">
|
||||
</div>
|
||||
<div class="form-help-text">
|
||||
<p><i class="fas fa-check-circle"></i> 첨부파일은 10MB 이내로 등록해 주세요</p>
|
||||
<p><i class="fas fa-check-circle"></i> 문서파일과 이미지 파일만 등록 가능합니다 (pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 버튼 영역 -->
|
||||
<div class="form-actions">
|
||||
<a th:href="@{/}" id="cancelButton" class="action-btn-secondary">
|
||||
<i class="fas fa-times"></i>
|
||||
취소
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary btn_register">
|
||||
<i class="fas fa-paper-plane"></i>
|
||||
제휴 신청
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -97,17 +131,21 @@
|
||||
</script>
|
||||
<script th:inline="javascript">
|
||||
$(function () {
|
||||
let fnRegister = document.querySelector('.btn_register');
|
||||
let cancelButton = document.getElementById('cancelButton');
|
||||
const fnRegister = document.querySelector('.btn_register');
|
||||
const fileInput = document.getElementById('file');
|
||||
const fileNameInput = document.querySelector('.file-name-display');
|
||||
const fileRemoveBtn = document.querySelector('.file-remove-btn');
|
||||
const allowFileExtention = ['pdf','doc','docx','xls','xlsx','ppt','pptx','hwp','gif','jpg','png'];
|
||||
|
||||
// Form submission
|
||||
fnRegister.addEventListener('click', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
let form = document.getElementById('partnershipForm');
|
||||
let bizSubject = document.getElementById('bizSubject').value.trim();
|
||||
let bizDetail = document.getElementById('bizDetail').value.trim();
|
||||
const form = document.getElementById('partnershipForm');
|
||||
const bizSubject = document.getElementById('bizSubject').value.trim();
|
||||
const bizDetail = document.getElementById('bizDetail').value.trim();
|
||||
|
||||
// validation 체크
|
||||
// Validation
|
||||
if (!bizSubject) {
|
||||
customPopups.showAlert('사업 제목을 작성해 주세요.');
|
||||
document.getElementById('bizSubject').focus();
|
||||
@@ -123,51 +161,54 @@
|
||||
form.submit();
|
||||
});
|
||||
|
||||
document.getElementById('partnershipForm').bizSubject.focus();
|
||||
const fileInput = document.getElementById('file');
|
||||
const fileNameInput = document.querySelector('.upload-name');
|
||||
|
||||
const allowFileExtention = ['pdf','doc','docx','xls','xlsx','ppt','pptx','hwp','gif','jpg','png'];
|
||||
// Auto focus on first field
|
||||
document.getElementById('bizSubject').focus();
|
||||
|
||||
// File validation functions
|
||||
function isValidFileExtention(filename) {
|
||||
const extention = filename.split('.').pop().toLowerCase();
|
||||
return allowFileExtention.includes(extention);
|
||||
}
|
||||
|
||||
function isValidFileSize(filesize) {
|
||||
const maxSize = 10 * 1024 * 1024;
|
||||
const maxSize = 10 * 1024 * 1024; // 10MB
|
||||
return filesize <= maxSize;
|
||||
|
||||
}
|
||||
|
||||
// File input change event
|
||||
fileInput.addEventListener('change', function () {
|
||||
|
||||
const file = fileInput.files[0];
|
||||
|
||||
if (file) {
|
||||
if(!isValidFileExtention(file.name)) {
|
||||
const errorMsg = '허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br> (pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)';
|
||||
const formattedMsg = errorMsg.replace(/\n/g,'<br>');
|
||||
$('#customAlertMessage').html(formattedMsg);
|
||||
// Validate file extension
|
||||
if (!isValidFileExtention(file.name)) {
|
||||
const errorMsg = '허용된 파일 형식이 아닙니다.<br>문서파일과 이미지 파일만 등록 가능합니다.<br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)';
|
||||
$('#customAlertMessage').html(errorMsg);
|
||||
$('#customAlert').css('display','flex');
|
||||
fileInput.value = '';
|
||||
return;
|
||||
}
|
||||
if(!isValidFileSize(file.size)) {
|
||||
customPopups.showAlert('첨부파일은 10MB 이내로 등록해 주세요.')
|
||||
|
||||
// Validate file size
|
||||
if (!isValidFileSize(file.size)) {
|
||||
customPopups.showAlert('첨부파일은 10MB 이내로 등록해 주세요.');
|
||||
fileInput.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
fileNameInput.value = file.name;
|
||||
fileNameInput.classList.remove('before');
|
||||
fileNameInput.classList.add('i_trash', 'after');
|
||||
fileNameInput.classList.add('has-file');
|
||||
fileRemoveBtn.style.display = 'inline-flex';
|
||||
}
|
||||
});
|
||||
|
||||
fileNameInput.addEventListener('click', function () {
|
||||
if (fileNameInput.classList.contains('i_trash')) {
|
||||
fileInput.value = '';
|
||||
fileNameInput.value = '';
|
||||
fileNameInput.classList.remove('i_trash', 'after');
|
||||
fileNameInput.classList.add('before');
|
||||
}
|
||||
// File remove button click event
|
||||
fileRemoveBtn.addEventListener('click', function () {
|
||||
fileInput.value = '';
|
||||
fileNameInput.value = '첨부파일을 등록해 주세요';
|
||||
fileNameInput.classList.remove('has-file');
|
||||
fileRemoveBtn.style.display = 'none';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
|
||||
<!-- API 검색 섹션 -->
|
||||
<section class="api-search-section">
|
||||
<div class="search-background"></div>
|
||||
<div class="search-content-wrapper">
|
||||
<div class="search-character">
|
||||
<img th:src="@{/img/img_search_character.png}" alt="검색">
|
||||
@@ -132,60 +133,36 @@
|
||||
|
||||
<!-- 추천 API 섹션 -->
|
||||
<section class="api-showcase">
|
||||
<div class="showcase-background"></div>
|
||||
<div class="showcase-wrapper">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">추천 API</h2>
|
||||
<p class="section-subtitle">다양한 금융 API상품을 소개합니다.</p>
|
||||
<a th:href="@{/apis}" class="btn-all-apis">
|
||||
API 전체보기
|
||||
<svg width="7" height="15" viewBox="0 0 7 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 1L6 7.5L1 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
전체보기
|
||||
<svg width="9" height="15" viewBox="0 0 9 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.509766 13.5496L7.50977 7.04956L0.509766 0.549561" stroke="white" stroke-width="1.5" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="api-cards-container">
|
||||
<!-- 1원 이체 인증 -->
|
||||
<div class="api-card">
|
||||
<h3 class="card-title">1원 이체 인증</h3>
|
||||
<!-- Services 데이터를 반복하여 API 카드 표시 (최대 4개) -->
|
||||
<div class="api-card" th:each="service, iterStat : ${services}"
|
||||
th:if="${iterStat.index < 4}"
|
||||
th:onclick="${service.id != null} ? |location.href='@{/apis(groupId=${service.id})}'| : |location.href='@{/apis}'|">
|
||||
<h3 class="card-title" th:text="${service.groupName}">API 서비스</h3>
|
||||
<p class="card-description">
|
||||
고객이 기존에 가지고 있는 계좌로 이체를 통해서 간편하게 비대면 실명확인을 도와드리는 서비스입니다.
|
||||
<span th:if="${service.groupDesc != null and !#strings.isEmpty(service.groupDesc)}"
|
||||
th:text="${service.groupDesc}">서비스 설명</span>
|
||||
<span th:unless="${service.groupDesc != null and !#strings.isEmpty(service.groupDesc)}">
|
||||
광주은행 API 서비스를 이용해보세요.
|
||||
</span>
|
||||
</p>
|
||||
<div class="card-illustration">
|
||||
<img th:src="@{/img/api_icon_1won.png}" alt="1원 이체 인증">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 수신 -->
|
||||
<div class="api-card">
|
||||
<h3 class="card-title">수신</h3>
|
||||
<p class="card-description">
|
||||
광주은행 수신 계좌들을 조회하는 서비스입니다.
|
||||
</p>
|
||||
<div class="card-illustration">
|
||||
<img th:src="@{/img/api_icon_deposit.png}" alt="수신">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 여신 -->
|
||||
<div class="api-card">
|
||||
<h3 class="card-title">여신</h3>
|
||||
<p class="card-description">
|
||||
대출관련 한도, 금리와 대출 계좌들을 조회하는 서비스입니다.
|
||||
</p>
|
||||
<div class="card-illustration">
|
||||
<img th:src="@{/img/api_icon_loan.png}" alt="여신">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 간편결제 -->
|
||||
<div class="api-card">
|
||||
<h3 class="card-title">간편결제</h3>
|
||||
<p class="card-description">
|
||||
광주은행 간편결제 승인/취소와 제휴 대사자료 생성/전송 요청하는 서비스입니다.
|
||||
</p>
|
||||
<div class="card-illustration">
|
||||
<img th:src="@{/img/api_icon_payment.png}" alt="간편결제">
|
||||
<!-- 서비스별 아이콘 매핑 - base64 인코딩된 이미지 사용 -->
|
||||
<img th:src="${service.mainIcon != null and !#strings.isEmpty(service.mainIcon)} ? ${service.mainIcon} : @{/img/api_icon_default.png}"
|
||||
th:alt="${service.groupName}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -227,7 +204,7 @@
|
||||
|
||||
<!-- 지원 센터 섹션 -->
|
||||
<section class="support-center">
|
||||
<div class="support-background-pattern"></div>
|
||||
<div class="support-background"></div>
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">
|
||||
@@ -236,36 +213,38 @@
|
||||
</h2>
|
||||
</div>
|
||||
<div class="support-grid">
|
||||
<!-- 공지사항 - 큰 카드 -->
|
||||
<a th:href="@{/portalnotice}" class="support-card support-card-large">
|
||||
<!-- 공지사항 카드 (50% width) -->
|
||||
<a th:href="@{/portalnotice}" class="support-card support-card--notice">
|
||||
<div class="card-icon">
|
||||
<img th:src="@{/img/icon_notice.png}" alt="공지사항">
|
||||
</div>
|
||||
<h3>공지사항</h3>
|
||||
<p>광주은행 API의 새로운 소식을 확인해보세요.</p>
|
||||
<div class="card-content">
|
||||
<h3>공지사항</h3>
|
||||
<p>광주은행 API의 새로운 소식을 확인해보세요.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 오른쪽 작은 카드들 -->
|
||||
<div class="support-cards-small">
|
||||
<a th:href="@{/faq_list}" class="support-card support-card-small">
|
||||
<div class="card-icon">
|
||||
<img th:src="@{/img/icon_faq.png}" alt="FAQ">
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>FAQ</h3>
|
||||
<p>자주 묻는 질문</p>
|
||||
</div>
|
||||
</a>
|
||||
<a th:href="@{/inquiry}" class="support-card support-card-small">
|
||||
<div class="card-icon">
|
||||
<img th:src="@{/img/icon_qna.png}" alt="Q&A">
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>Q&A</h3>
|
||||
<p>문의하기</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- FAQ Card (25% width) -->
|
||||
<a th:href="@{/faq_list}" class="support-card support-card--faq">
|
||||
<div class="card-icon">
|
||||
<img th:src="@{/img/icon_faq.png}" alt="FAQ">
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>FAQ</h3>
|
||||
<p>자주 묻는 질문</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Q&A Card (25% width) -->
|
||||
<a th:href="@{/inquiry}" class="support-card support-card--qna">
|
||||
<div class="card-icon">
|
||||
<img th:src="@{/img/icon_qna.png}" alt="Q&A">
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>Q&A</h3>
|
||||
<p>문의하기</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -284,13 +263,13 @@
|
||||
<div class="stat-card">
|
||||
<p class="stat-label">서비스 이용 수</p>
|
||||
<div class="stat-icon">
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="100" height="100" fill="url(#pattern0_2007_122)"/>
|
||||
<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="90" height="90" fill="url(#pattern0_892_75)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0_2007_122" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_2007_122" transform="translate(0 -0.00684932) scale(0.00684932)"/>
|
||||
<pattern id="pattern0_892_75" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_892_75" transform="scale(0.00537634)"/>
|
||||
</pattern>
|
||||
<image id="image0_2007_122" width="146" height="148" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJIAAACUCAYAAAB4InCTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MjE2MEY5MTNCMUQwMTFGMEI4MkNBREYwOTFGQThDQ0YiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MjE2MEY5MTRCMUQwMTFGMEI4MkNBREYwOTFGQThDQ0YiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyMTYwRjkxMUIxRDAxMUYwQjgyQ0FERjA5MUZBOENDRiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyMTYwRjkxMkIxRDAxMUYwQjgyQ0FERjA5MUZBOENDRiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PtyO1z0AAAQbSURBVHja7N3BaxxlGMDhmWYT1myQNKlFFBHBg7fSCgUp8RAQLyIVevImnvwD9F/w4FXwJN48CYpIIVRz6KUgaOnNg9CDGMSULUqyW5qk4zt2rGabxOzOZmaSfR54mZKS3fm++ZHdaUOSZlmWQFmnbAFCojnyl7aT/vIW62vHfBizllVnrXjO9kT0c9JDirW1Yr7L6pM/d+ukhzQJL21vxyzX+PzLxTl4j3TMveEchDQOZ52DkBASQoIhtSZ9A7a2tpLNzc1Sj9HpdJLp6WkhTbKdnZ2k3++Xeox2uz3xIXlpQ0gICSGBkBASQkJIICSEhJAQEggJISEkEBJCQkgICYSEkBASQgIhISSEhJBASAgJIYGQGKND/XykLMteisPTFZxP/gO/f07T9FeX5sDr8WwcXoxJK3i63+J6/FQqpDjh83H4LOZcxRv1dRzejQXckc2ufTkTh09j3qz4eW/F4Z24HjeHfmmLT34+DqtVR1TIN2rlJP/E/BEuZr4XK1VHVMgbWC2aGPo90gcx8zXu3YWYKxJ65EqxJ3WZL5oYOqRLDdi8Jf00ai8ujRLSfANOvKOfRu3FvNt/jpSQEBLNMfLtda/XSzY2Nko9+cLCQtJqucMfh+3t7aTb7ZZ6jLm5uWR2drbakPLfGpj/1Pwy/Ibv8an7enhpw3skhISQQEgICSEhJBASQkJICAmEhJAQEggJISEkhARCQkgICSGBkBASQkJIICSEhJBASAgJISEkEBJCQkgICYSEkBASQgIhISSEBEJCSAgJIYGQEBJCQkggJISEkBASCAkhIST4r9aonzg1NZXMzMyUq/hU/R3n52Ad/17TykNqt9t/z3GXb/7i4uKxX0ceQZ3r8NKGkBASExTSegPO748xPEa3AevoNmQvylofJaTVBpz4t2N4jGsNWMe1huxFWfs2kWZZ9vAPabrrL+LjT8Xhh5jnatz81+O8sjIPEut4Ig43Ys7VtI5bMa/EOvol15FfoJWY12paxy8xL8c61gfO6+CvSMUnLMV8E/OgwhPON/zjmMtlIyrWkT/ecsznMfcrXMf94jmXy0ZUrCPfi8vF3vQrXMeDooGlwYgO9RVpoLon47BQ0YmvxbkcyQWPdczG4WxF6/g91tE7onXk//L4TFXv72Idfx5wLocPCf4vJLf/HPntPwgJISEkhARCQkgICYTEWD32PdtZlp2Ow6sxp20Pe7gbcz1N07v7hhQRvReHj2I69osDbEYr70dMn/zzgUf/aZs8/BaFL+0RQ3gr5qvBkH6MOW9vGMLNmAuDIe14882Q8m96mxq8a7tnXxjSvb1u/6/aF4Z0da832y/EfB9zxv5wCHdiLsbc3vUVKW7lbhd/8UVMzz6xj17RyMWimce+IsHI3KUhJJrjLwEGAL+X+MkwwRFJAAAAAElFTkSuQmCC"/>
|
||||
<image id="image0_892_75" width="186" height="186" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"/>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
@@ -302,13 +281,13 @@
|
||||
<div class="stat-card">
|
||||
<p class="stat-label">API 이용 건수</p>
|
||||
<div class="stat-icon">
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="100" height="100" fill="url(#pattern0_2007_127)"/>
|
||||
<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="90" height="90" fill="url(#pattern0_892_81)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0_2007_127" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_2007_127" transform="translate(0 -0.00684932) scale(0.00684932)"/>
|
||||
<pattern id="pattern0_892_81" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_892_81" transform="scale(0.00543478)"/>
|
||||
</pattern>
|
||||
<image id="image0_2007_127" width="146" height="148" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJIAAACUCAYAAAB4InCTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDM4MERCNkFCMUQwMTFGMDhFRkQ5RTJDMzIxRTM5RTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDM4MERCNkJCMUQwMTFGMDhFRkQ5RTJDMzIxRTM5RTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzgwREI2OEIxRDAxMUYwOEVGRDlFMkMzMjFFMzlFMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzgwREI2OUIxRDAxMUYwOEVGRDlFMkMzMjFFMzlFMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PlF4bcgAAAgiSURBVHja7J0LiBVV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"/>
|
||||
<image id="image0_892_81" width="184" height="184" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"/>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
@@ -320,13 +299,13 @@
|
||||
<div class="stat-card">
|
||||
<p class="stat-label">API 활용 기업</p>
|
||||
<div class="stat-icon">
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="100" height="100" fill="url(#pattern0_2007_161)"/>
|
||||
<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="90" height="90" fill="url(#pattern0_892_93)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0_2007_161" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_2007_161" transform="translate(0 -0.00684932) scale(0.00684932)"/>
|
||||
<pattern id="pattern0_892_93" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_892_93" transform="scale(0.00540541)"/>
|
||||
</pattern>
|
||||
<image id="image0_2007_161" width="146" height="148" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJIAAACUCAYAAAB4InCTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NkU5Mzk4MDhCMUQwMTFGMDlFMzFEOEYxRTE4RTBGOUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NkU5Mzk4MDlCMUQwMTFGMDlFMzFEOEYxRTE4RTBGOUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2RTkzOTgwNkIxRDAxMUYwOUUzMUQ4RjFFMThFMEY5QiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo2RTkzOTgwN0IxRDAxMUYwOUUzMUQ4RjFFMThFMEY5QiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvePPbQAAAbISURBVHja7J1biFVV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"/>
|
||||
<image id="image0_892_93" width="185" height="185" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALkAAAC5CAYAAAB0rZ5cAAAACXBIWXMAABcSAAAXEgFnn9JSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA55JREFUeNrs3eFt01AUgFEbdYCyQUbICM4ITNAyAhPUmaBigqYTwAYJE5ARvEGzweOZGKlUQraT28QJ50imPzB59PqrZVpil0UnpVTlDw95qwqmoMnbsizLlVEcp+wCv88fnoxjklY59M/GcETk3Rl8bRST1p7Ra2M4PPK1S5TJ2+XIPxrD4ZEnY7gIixz6xhjG+2AEiBxEDiIHkYPI4Qg3I/f/kretsYWY5+3RGKYX+db3amP48YTLFRA5iBxEjshB5CByEDmIHEQOIgeRI3IQOYgcRA4iB5GDyBE5iBxEDiKH/yvylFKd4tQD16wC1/RkDpGDyEHkIHIQOYgckYPIQeQgchA5iBxEDjdGcDHu2v9JaQyDtE8p/C7yy3NvBMPlE0KTP3zKsW9drnCtZnlb59jnIuea3ebtSeRcu3mZxj3/euGx42HXjO0/Ir2N7gScyRE5iBxEDiIHkcMx/Fj/cvj27StjvvXtTI7LFRA5iBxEDiIHkYPIETmIHEQOIgeRg8hB5CByRA4ih0t0lre/pZRmxf6GjBGasiybAWu298WbB625a++WOtWDGnmL57633LU31Cz29xyM0N5yeXcVkRf72xA/BL3WMm/1gP3agxF1W7b2wC8mfPKKvP1c2fP7j3mL+qJadLN1uQIiB5EjchA5iBxEDiIHkYPIQeSIHEQOIgeRg8hB5NDnXO8Maoq4d4A0A/fbBa65nfhx3ZxwrchZ7N7lb5jGqZwXwuZemf1punW5gmtyEDmIHEQOIgeRg8gROYgcRA4iB5GDyEHkIHJEDiIHkYPIQeQgchA5vHGWmwt19xCpgl5u0/f8927NWbF/3HmEJq+5mupBzZ9rHfVa+fOse9ZqZzoLWm6V12uuIvIu8IfA19sM2GcWuGa73mQjD55t3xfMXeQJqxh+RzSXKyByRA4iB5GDyEHkIHIQOYgckYPIQeQgchA5iBxEjshB5HDJzvUez80ZXqvJ2zJozWbix3V5wrWe8/Zj0nNN41TOC2Fzr8z+NN26XME1OYgcRA4iB5GDyEHkiBxEDiIHkYPIQeQgchA5IgeRg8hB5CByEDmIHESOyEHkIHIQOYgcRA4iB5Ejct7f1ghOF3kzYv/GyGKUZbkbOU9fFAfOo4186PNlVvnAiDzW84jZ74zrL18H7rf5/WtKad3z2JWfebs113hmf9Tsnnpm95K32es/8PiPHb8Z8rsfLLM/fHZ1F/Nb6z+B/xJgACa/EiM9CgOoAAAAAElFTkSuQmCC"/>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" name="organizationId" class="org-form-input input-readonly"
|
||||
th:value="${user.portalOrg.orgCode}"
|
||||
placeholder="k000000001"
|
||||
placeholder="XXXXXX-01"
|
||||
disabled="disabled">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<aside layout:fragment="apiAside" class="lnb">
|
||||
<nav th:with="services=${@apiServiceService.searchApiGroupsForLnb()}">
|
||||
<ul class="lnb_list_type">
|
||||
<li>
|
||||
<a href="#none">공통안내</a>
|
||||
<ul class="lnb_list_nav">
|
||||
<li> <a th:href="@{/apis/common}">API 개발 공통</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U3}">가상계좌 응답 코드</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U4}">가상계좌 배치 설계</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U5}">가상계좌 VAN사 코드</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U6}">펌뱅킹 응답코드</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U7}">펌뱅킹 배치 설계</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U8}">대출금리 응답코드</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U9}">케이뱅크 페이 응답코드</a></li>
|
||||
<li> <a th:href="@{/apis/KAPAP004U10}">케이뱅크 페이 복합과세 예제</a></li>
|
||||
<li> <a th:href="@{/apis/token-spec}">케이뱅크 OAuth 2.0 토큰 발급</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li th:each="apiService : ${services}">
|
||||
<a href="#none" th:text="${apiService.groupName}">API Group Name</a>
|
||||
<ul class="lnb_list_nav">
|
||||
<li th:each="api : ${apiService.apiGroupApiList}">
|
||||
<a th:href="@{/apis/detail(id=${api.apiId})}" th:text="${api.apiDesc}">API Description</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
@@ -1,29 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
>
|
||||
|
||||
<body>
|
||||
<footer th:fragment="footerFragment" id="footer">
|
||||
<div class="container">
|
||||
<div class="policy-site">
|
||||
<div class="ft_logo">
|
||||
<a href="#none">
|
||||
<img th:src="@{/img/logo/img_mlogo2.png}" alt="">
|
||||
</a>
|
||||
</div>
|
||||
<div class="f-info">
|
||||
<a th:href="@{/agreements/terms(tab='terms')}">이용약관</a><span>/</span><a th:href="@{/agreements/terms(tab='privacy')}" class="bold-link" >개인정보처리방침</a>
|
||||
</div>
|
||||
<div class="family-sites">
|
||||
<h3 id="family-sites-toggle">케이뱅크 관련사이트</h3>
|
||||
<ul id="family-sites-list" class="collapsed">
|
||||
<li><a target="_blank" href="//www.kbanknow.com">케이뱅크 홈페이지</a></li>
|
||||
<li><a target="_blank" href="//biz.kbanknow.com">케이뱅크 기업뱅킹</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<p class="f-info2">고객센터 : 1522-1000 / 해외 : +82-2-3778-9111</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,52 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head th:fragment="headFragment">
|
||||
<title th:text="#{title.html}">개발자 포털</title>
|
||||
|
||||
<meta content="https://www.eactive.co.kr/" property="og:url"/>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="max-age=0, public" http-equiv="Cache-Control"/>
|
||||
<meta content="index, follow" name="robots"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||||
<meta http-equiv="Cache-Control" content="no-cache">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/style2.css}">
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/common2.css}">
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/slick.css}">
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/daterangepicker.css}">
|
||||
|
||||
<link rel="stylesheet" th:href="@{/plugins/codemirror/codemirror.css}" type="text/css"/>
|
||||
<link rel="stylesheet" th:href="@{/plugins/codemirror/theme/monokai.css}" type="text/css"/>
|
||||
<link rel="stylesheet" th:href="@{/plugins/summernote/summernote-lite.css}" type="text/css" />
|
||||
<link rel="stylesheet" th:href="@{/plugins/jquery-ui/jquery-ui.min.css}" />
|
||||
<link rel="icon" type="image/ico" th:href="@{/favicon_16px.png}">
|
||||
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||||
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<script th:src="@{/plugins/jquery/jquery-3.7.1.min.js}"></script>
|
||||
<script th:src="@{/js/lodash.js}"></script>
|
||||
<script th:src="@{/js/common.js}"></script>
|
||||
<script th:src="@{/js/moment.min.js}"></script>
|
||||
<script th:src="@{/js/daterangepicker.js}"></script>
|
||||
<script th:src="@{/plugins/codemirror/codemirror.js}"></script>
|
||||
<script th:src="@{/plugins/codemirror/mode/clike.js}"></script>
|
||||
<script th:src="@{/plugins/codemirror/mode/javascript.js}"></script>
|
||||
<script th:src="@{/plugins/codemirror/addon/display/fullscreen.js}"></script>
|
||||
<script th:src="@{/plugins/codemirror/addon/display/placeholder.js}"></script>
|
||||
<script th:src="@{/plugins/summernote/summernote-lite.min.js}"></script>
|
||||
<script th:src="@{/plugins/summernote/summernote-cleaner.js}"></script>
|
||||
<script th:src="@{/plugins/jquery-ui/jquery-ui.min.js}"></script>
|
||||
<script th:src="@{/js/htmx.min.js}"></script>
|
||||
</head>
|
||||
|
||||
</html>
|
||||
@@ -1,50 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header th:fragment="headerFragment" id="header" class="header">
|
||||
|
||||
<div class="container" th:replace="fragment/kbank/header_container :: headerFragment"></div>
|
||||
|
||||
<div class="navigation" th:replace="fragment/kbank/header_nav :: headerFragment"></div>
|
||||
|
||||
</header>
|
||||
|
||||
<!-- header script -->
|
||||
<th:block th:fragment="headerScript">
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Login button
|
||||
const loginBtn = document.querySelector('.btn_loginbt');
|
||||
if (loginBtn) {
|
||||
loginBtn.addEventListener('click', function() {
|
||||
window.location.href = '/login';
|
||||
});
|
||||
}
|
||||
|
||||
// Sign up button
|
||||
const signupBtn = document.querySelector('.btn_memberbt');
|
||||
if (signupBtn) {
|
||||
signupBtn.addEventListener('click', function() {
|
||||
window.location.href = '/signup';
|
||||
});
|
||||
}
|
||||
|
||||
// Logout button
|
||||
const logoutBtn = document.querySelector('.btn_logout');
|
||||
if (logoutBtn) {
|
||||
logoutBtn.addEventListener('click', function() {
|
||||
window.location.href = '/actionLogout.do';
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,143 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div th:fragment="headerFragment" class="header-container">
|
||||
<!-- Unified Header -->
|
||||
<header id="page-header">
|
||||
<div class="header-content">
|
||||
<!-- Logo -->
|
||||
<h1 class="logo">
|
||||
<a th:href="@{/}"><span class="blind">kbank</span></a>
|
||||
</h1>
|
||||
|
||||
<!-- Mobile-only Subtitle -->
|
||||
<div class="sub_title m-only">
|
||||
<p th:text="${pageName}">API Portal</p>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Home Button -->
|
||||
<div class="home m-only">
|
||||
<a th:href="@{/}"><span class="blind">home</span></a>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Menu Toggle -->
|
||||
<button type="button" class="btn-mobilemenu m-only">
|
||||
<span>모바일메뉴 열기</span>
|
||||
</button>
|
||||
|
||||
<!-- Unified Navigation -->
|
||||
<nav class="main-nav m-nav">
|
||||
<!-- Login/Profile Section (Mobile) -->
|
||||
<div class="nav-header m-only">
|
||||
<div class="login_btn_group">
|
||||
<div class="header_btn_group">
|
||||
<div class="login_wrap flex_no" sec:authorize="isAnonymous()">
|
||||
<div class="login_prev">
|
||||
<a th:href="@{/login}" class="btn btn_loginbt">로그인</a>
|
||||
<a th:href="@{/signup}" class="btn btn_memberbt">회원가입</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login_wrap" sec:authorize="isAuthenticated()">
|
||||
<div class="profile_type">
|
||||
<a th:href="@{/mypage}">
|
||||
<p>[[${#authentication.principal.userName}]]님</p>
|
||||
<span>즐거운 하루 되세요!</span>
|
||||
</a>
|
||||
</div>
|
||||
<a th:href="@{/actionLogout.do}" class="btn btn_logout">로그아웃</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Menu List -->
|
||||
<ul class="nav-list">
|
||||
<li class="nav-item has-submenu">
|
||||
<a th:href="@{/intro}">안내</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a th:href="@{/intro}">API Portal 소개</a></li>
|
||||
<li><a th:href="@{/guide}">이용 안내</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item has-submenu">
|
||||
<a th:href="@{/apis}">API</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a th:href="@{/apis}">API 목록</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item has-submenu">
|
||||
<a th:href="@{/apis/testbed}">테스트 베드</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a th:href="@{/apis/testbed}">테스트베드</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item has-submenu">
|
||||
<a href="#">고객지원</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a th:href="@{/portalnotice}">공지사항</a></li>
|
||||
<li><a th:href="@{/faq_list}">FAQ</a></li>
|
||||
<li><a th:href="@{/inquiry}">Q&A</a></li>
|
||||
<li><a th:href="@{/partnership}">사업제휴</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item has-submenu" sec:authorize="isAuthenticated()">
|
||||
<a href="#">마이페이지</a>
|
||||
<ul class="sub-menu">
|
||||
<li sec:authorize="hasRole('ROLE_DASHBOARD')"><a th:href="@{/dashboard}">대시보드</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_USER_MANAGER')"><a th:href="@{/users}">이용자 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_APP')"><a th:href="@{/myapikey}">인증 키 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_API_KEY_REQUEST_VIEW')"><a th:href="@{/myapikey/api_key_request/history}">인증키 신청 목록</a></li>
|
||||
<li><a th:href="@{/mypage}">내 정보 관리</a></li>
|
||||
<li><a th:href="@{/change_password}">비밀번호 변경</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Footer Info -->
|
||||
<div class="info_wrap m-only">
|
||||
<p class="tit1">
|
||||
<a th:href="@{/agreements/terms(tab='terms')}">이용약관</a> <span>/</span> <a th:href="@{/agreements/terms(tab='privacy')}">개인정보처리방침</a>
|
||||
</p>
|
||||
<p class="tit2">
|
||||
<span>고객센터 : 1522-1000</span>
|
||||
<span>해외 : +82-2-3778-9111</span>
|
||||
</p>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Login/Profile Section (Desktop) -->
|
||||
<div id="login_group" class="pc-only">
|
||||
<ul sec:authorize="isAnonymous()" class="login_type">
|
||||
<li><a th:href="@{/login}">로그인</a></li>
|
||||
</ul>
|
||||
<ul sec:authorize="isAuthenticated()" class="logout_type">
|
||||
<li class="icon line"><a th:href="@{/mypage}">[[${#authentication.principal.userName}]]님</a></li>
|
||||
<li><span>|</span></li>
|
||||
<li><a th:href="@{/actionLogout.do}">로그아웃</a></li>
|
||||
<li><span>|</span></li>
|
||||
<li class="mp_arrow">
|
||||
<a th:href="@{/dashboard}">마이페이지</a>
|
||||
<div class="mp_type">
|
||||
<ul class="mp_list">
|
||||
<li sec:authorize="hasRole('ROLE_DASHBOARD')"><a th:href="@{/dashboard}">대시보드</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_USER_MANAGER')"><a th:href="@{/users}">이용자 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_APP')"><a th:href="@{/myapikey}">인증키 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_API_KEY_REQUEST_VIEW')"><a th:href="@{/myapikey/api_key_request/history}">인증키 신청 목록</a></li>
|
||||
<li><a th:href="@{/mypage}">내 정보 관리</a></li>
|
||||
<li><a th:href="@{/change_password}">비밀번호 변경</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div th:fragment="headerFragment" class="navigation" id="navigation">
|
||||
<ul class="navigation-area">
|
||||
<li th:each="crumb : ${breadcrumb}">
|
||||
<a th:href="${crumb.path}" class="navigation-button" th:text="${crumb.name}">Unknown Page</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,46 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header th:fragment="headerFragment" id="header" class="header">
|
||||
<div class="container" th:replace="fragment/kbank/header_container :: headerFragment"></div>
|
||||
</header>
|
||||
|
||||
<!-- header script -->
|
||||
<th:block th:fragment="headerScript">
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Login button
|
||||
const loginBtn = document.querySelector('.btn_loginbt');
|
||||
if (loginBtn) {
|
||||
loginBtn.addEventListener('click', function() {
|
||||
window.location.href = '/login';
|
||||
});
|
||||
}
|
||||
|
||||
// Sign up button
|
||||
const signupBtn = document.querySelector('.btn_memberbt');
|
||||
if (signupBtn) {
|
||||
signupBtn.addEventListener('click', function() {
|
||||
window.location.href = '/signup';
|
||||
});
|
||||
}
|
||||
|
||||
// Logout button
|
||||
const logoutBtn = document.querySelector('.btn_logout');
|
||||
if (logoutBtn) {
|
||||
logoutBtn.addEventListener('click', function() {
|
||||
window.location.href = '/actionLogout.do';
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<aside class="sidebar" th:fragment="menuFragment">
|
||||
|
||||
</aside>
|
||||
|
||||
<!-- menu script -->
|
||||
<th:block th:fragment="menuScript">
|
||||
<script th:inline="javascript">
|
||||
|
||||
$(function () {
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,74 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout/kbank_base_layout}">
|
||||
<body>
|
||||
<section layout:fragment="contentFragment" class="content">
|
||||
<div class="content_wrap">
|
||||
<div class="sub_title2">
|
||||
<h2 class="title" th:classappend="${isTermsOfUse ? 'add3' : 'add4'}"
|
||||
th:text="${agreementTitle}">이용약관</h2>
|
||||
</div>
|
||||
<div class="inner cs2">
|
||||
<div class="tab-wrap">
|
||||
<div class="tabs">
|
||||
<ul class="tab_nav tab_bt">
|
||||
<li th:class="${isTermsOfUse ? 'active' : ''}">
|
||||
<a th:href="@{/agreements/terms(tab='terms')}">이용약관</a>
|
||||
</li>
|
||||
<li th:class="${isPrivacyPolicy ? 'active' : ''}">
|
||||
<a th:href="@{/agreements/terms(tab='privacy')}">개인정보처리방침</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab active" th:id="${isTermsOfUse ? 'tab1' : 'tab2'}">
|
||||
<div class="form_type">
|
||||
<div class="info1 ts_top">
|
||||
<div class="info_line ts_left">
|
||||
<div class="info_box1 info_add3 info_top">
|
||||
<span class="input">
|
||||
<form id="agreementForm" th:action="@{/agreements/terms}" method="get">
|
||||
<input type="hidden" name="tab"
|
||||
th:value="${currentTab}">
|
||||
<div class="custom_select" id="agreement_select">
|
||||
<div class="select_selected">
|
||||
시행일자 : <span th:text="${#temporals.format(selectedAgreement.publishedOn, 'yyyy.MM.dd')}"></span>
|
||||
</div>
|
||||
<ul class="common_selecttype select_items select_hide">
|
||||
<li th:each="agreement : ${agreementsList}"
|
||||
th:data-id="${#temporals.format(agreement.publishedOn, 'yyyy-MM-dd')}"
|
||||
th:text="'시행일자 : ' + ${#temporals.format(agreement.publishedOn, 'yyyy.MM.dd')}"
|
||||
th:class="${#temporals.format(agreement.publishedOn, 'yyyy-MM-dd') == selectedDate ? 'selected' : ''}">
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="hidden" name="publishedOn" id="publishedOnInput">
|
||||
</form>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="terms_contents m_termst" th:utext="${selectedAgreement.contents}"
|
||||
style="white-space: pre-wrap; word-wrap: break-word;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<script layout:fragment="contentScript">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const selects = document.getElementById('agreement_select');
|
||||
const form = document.getElementById('agreementForm');
|
||||
const publishedOnInput = document.getElementById('publishedOnInput');
|
||||
|
||||
createCustomSelect(selects, {
|
||||
onSelect: (item) => {
|
||||
publishedOnInput.value = item;
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,6 +29,7 @@
|
||||
<li><a th:href="@{/portalnotice}">공지사항</a></li>
|
||||
<li><a th:href="@{/faq_list}">FAQ</a></li>
|
||||
<li><a th:href="@{/inquiry}">Q&A</a></li>
|
||||
<li><a th:href="@{/partnership}">사업 제휴 문의</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
|
||||
<head th:replace="fragment/kbank/head :: headFragment">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="loading-overlay" style="display: none;">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
<ul class="skip">
|
||||
<li>
|
||||
<a href="#skipCt">본문 바로가기</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#gnb">대 메뉴 바로가기</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="wrap">
|
||||
<!-- header -->
|
||||
<header th:replace="fragment/kbank/header :: headerFragment"></header>
|
||||
<th:block th:replace="fragment/kbank/header :: headerScript"></th:block>
|
||||
|
||||
<aside layout:replace="fragment/kbank/api_lnb :: apiAside"></aside>
|
||||
<section layout:fragment="contentFragment">
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
</th:block>
|
||||
|
||||
<footer th:replace="fragment/kbank/footer :: footerFragment"></footer>
|
||||
<script th:src="@{/js/front2.js}"></script>
|
||||
|
||||
</div>
|
||||
<section th:replace="fragment/popup/apiKeyRequestPopup :: apiKeyRequestPopup"></section>
|
||||
<div th:replace="fragment/popup/customPopups :: customPopups"></div>
|
||||
<script th:src="@{/js/popup/custom-popups.js}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,42 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head th:replace="fragment/kbank/head :: headFragment">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="loading-overlay" style="display: none;">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
<ul class="skip">
|
||||
<li>
|
||||
<a href="#skipCt">본문 바로가기</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#gnb">대 메뉴 바로가기</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="wrap">
|
||||
<!-- header -->
|
||||
<header th:replace="fragment/kbank/header :: headerFragment"></header>
|
||||
<th:block th:replace="fragment/kbank/header :: headerScript"></th:block>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
</th:block>
|
||||
|
||||
<footer th:replace="fragment/kbank/footer :: footerFragment"></footer>
|
||||
|
||||
<script th:src="@{/js/front2.js}"></script>
|
||||
</div>
|
||||
<section layout:fragment="pagePopups">
|
||||
</section>
|
||||
<section th:replace="fragment/popup/customPopups :: customPopups"></section>
|
||||
<script th:src="@{/js/popup/custom-popups.js}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,40 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head th:replace="fragment/kbank/head :: headFragment">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="loading-overlay" style="display: none;">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
<ul class="skip">
|
||||
<li>
|
||||
<a href="#skipCt">본문 바로가기</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#gnb">대 메뉴 바로가기</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="wrap">
|
||||
<!-- header -->
|
||||
<header th:replace="fragment/kbank/header :: headerFragment"></header>
|
||||
<th:block th:replace="fragment/kbank/header :: headerScript"></th:block>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
</th:block>
|
||||
<footer th:replace="fragment/kbank/footer :: footerFragment"></footer>
|
||||
<script th:src="@{/js/daterangepicker.js}"></script>
|
||||
<script th:src="@{/js/front2.js}"></script>
|
||||
</div>
|
||||
<section th:replace="fragment/popup/customPopups :: customPopups"></section>
|
||||
<section layout:fragment="pagePopups"></section>
|
||||
<script th:src="@{/js/popup/custom-popups.js}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,39 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
|
||||
<head th:replace="fragment/kbank/head :: headFragment">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul class="skip">
|
||||
<li>
|
||||
<a href="#skipCt">본문 바로가기</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#gnb">대 메뉴 바로가기</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="wrap">
|
||||
<!-- header -->
|
||||
<header th:replace="fragment/kbank/index_header :: headerFragment"></header>
|
||||
<th:block th:replace="fragment/kbank/index_header :: headerScript"></th:block>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
</th:block>
|
||||
|
||||
<footer th:replace="fragment/kbank/footer :: footerFragment"></footer>
|
||||
<script th:src="@{/js/slick.min.js}"></script>
|
||||
<script th:src="@{/js/front2.js}"></script>
|
||||
|
||||
</div>
|
||||
<section th:replace="fragment/popup/customPopups :: customPopups"></section>
|
||||
<script th:src="@{/js/popup/custom-popups.js}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,39 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head th:replace="fragment/kbank/head :: headFragment">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul class="skip">
|
||||
<li>
|
||||
<a href="#skipCt">본문 바로가기</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#gnb">대 메뉴 바로가기</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="wrap">
|
||||
<!-- header -->
|
||||
<header th:replace="fragment/kbank/header :: headerFragment"></header>
|
||||
<th:block th:replace="fragment/kbank/header :: headerScript"></th:block>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
</th:block>
|
||||
<footer th:replace="fragment/kbank/footer :: footerFragment"></footer>
|
||||
<script th:src="@{/js/daterangepicker.js}"></script>
|
||||
<script th:src="@{/js/front2.js}"></script>
|
||||
</div>
|
||||
<section th:replace="fragment/popup/customPopups :: customPopups"></section>
|
||||
<section layout:fragment="pagePopups"></section>
|
||||
<script th:src="@{/js/popup/custom-popups.js}"></script>
|
||||
<section th:replace="fragment/popup/withdrawalPopup :: withdrawalPopup"></section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
|
||||
<head th:replace="fragment/kbank/head :: headFragment">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<section layout:fragment="contentFragment">
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
</th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||