Compare commits

...

14 Commits

Author SHA1 Message Date
이진기
37bc3f423c 문서 추가 2024-12-19 13:01:04 +09:00
이진기
69d84c4706 ReadMe 추가 2024-12-06 09:15:03 +09:00
d84a3313e3 타입 변경 2024-11-30 11:40:29 +09:00
이진기
f786df1d9b /admin/content/list 페이징 처리와 검색 조건 기능 추가 2024-11-27 16:23:07 +09:00
이진기
40a1c2740d 게시판 페이징 처리 추가 2024-11-26 15:08:22 +09:00
이진기
dae8e6d3a7 /admin/content/list 프론트 기능 추가 2024-11-26 14:46:19 +09:00
이진기
505a3e5101 모델 형식 수정 2024-11-26 10:08:00 +09:00
이진기
a697185451 Contents API 추가 수정 2024-11-25 18:12:18 +09:00
이진기
77c0a7d43f Contents API 추가 2024-11-20 15:06:33 +09:00
이진기
843db73d12 시스템관리 > 권한관리 > 사이트관리 화면과 API 추가 2024-11-19 16:01:42 +09:00
이진기
aed1321d88 Vue 로그인 경로 admin 추가 2024-11-19 15:51:49 +09:00
이진기
aef25bc3dc Site API 추가 (JpaRepository 와 Dao 연결) 2024-11-19 15:45:40 +09:00
이진기
711bba3e4b Dao에서 선언한 함수로 호출하게 변경 2024-11-19 11:26:36 +09:00
이진기
13b469d26f AsaSite API 추가 (자동 생성된 findAll 사용) 2024-11-19 11:09:00 +09:00
63 changed files with 2376 additions and 145 deletions

124
.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

40
java/README.md Normal file
View File

@@ -0,0 +1,40 @@
### 기본 환경
- Java 11
- MyBatis 4.x
- JPA 2.2
- QueryDSL 5.0
### 개발 규약
- 사용하지 않는 Parameter는 넣지 않는다.
- Request, Response 호출은 EgovRequestUtils을 통해서만 한다.
- 관리자 Session 정보는 EgovAdminSessionUtils로 호출한다.(MultipartRequest는 제외)
- 사용자 Session 정보는 EgovUserSessionUtils로 호출한다.
- Spring context에서 벗어나게 개발하지 않는다.
### 어노테이션
- API Controller: @RestController
- Page Controller: @Controller
- Service: @Service
- Mapper: @Mapper
- DAO 또는 별도 컴포넌트들: @Component
### API URL 규약
- 대국민포털(prefix): 없음
- 참여기관/관리자포털(prefix): /admin
- 페이지: /**
- api: /api/**
- 메뉴 등록 시 full url로 기재할 것!
- 페이지 메뉴는 도메인으로 분기 처리되므로 동일 URL 사용 가능
- id 조회의 경우 반드시 query 처리할 것!
### DB 암호화
- 환경변수 추가 필요(안하면 에러 남)
- {project.baseDir}/main/resources/ksing/db 에 있는 모든 파일을 C:\SecureDBAgent 에 복사
- 아래의 정보로 환경변수 세팅 진행
- SDB_HOME / C:\SecureDBAgent
- SDB_FIRST_PORT / 9909
### 비지니스 로직 로깅 관련
- [필수] 비지니스 로직에 로깅할 경우 class 상단에 @Slf4j 어노테이션 선언
- [필수] Service에서는 전자정부프레임워크에서 제공하는 egovLogger를 사용

29
java/git.md Normal file
View File

@@ -0,0 +1,29 @@
### 임시 git 설정(SSH 터널링)
```
ssh -i KLAC_SYS_ADM.pem -o ServerAliveInterval=60 -L 8081:localhost:8081 -L 5000:localhost:3000 rocky@192.168.30.7 -p 6722
```
### 브랜치 용도
- master: 운영 서버 반영 브랜치
- dev: 개발 서버 반영 브랜치
- mix: 개발용 브랜치
### 신규 브랜치 작성 방법
- feature/gitea아이디/번호
- 예) feature/natoro/1
- push 할 때마다 뒷 번호는 증가
### git 사용 방법
1. 작업하기 전 반드시 mix 브랜치에서 new branch로 생성
2. 작업이 완료될 경우 반드시 commit
3. 새로운 내용을 받을 때 pull(예: mix 브랜치 pull)
4. 작업한 내용을 서버에 올릴 때 push
5. 개발자는 merge 작업하지 말 것!
6. 작업 단위는 작게 진행(기능별로 분리해서 branch 작업)
7. 커미터, 기능별 태그 관리 및 버전 관리할 것
### 소스 관리 및 반영 관리(수정)
1. pull request 처리 주기
2. 코드 리뷰 주기
3. 반영 주기
4. 예) 수요일 - 오후 4시 pull request 처리

8
java/mapper.md Normal file
View File

@@ -0,0 +1,8 @@
Mapper 사용 시 아래와 같이 작성(중괄호는 치환되는 명칭)
```
package: egovframework.com.lasp.{업무명}.mapper
Mapper파일명: {Admin | User}{업무명}Mapper.xml
annotation: org.egovframe.rte.psl.dataaccess.mapper.Mapper
xml파일: \resources\egovframework\sqlmap\mappers\{Mapper명과 동일}.xml
```

View File

@@ -0,0 +1,26 @@
package com.leejk0523.javavue.admin.contents.controller;
import com.leejk0523.javavue.admin.contents.service.AdminContentsService;
import com.leejk0523.javavue.admin.contents.vo.ContentsListResult;
import com.leejk0523.javavue.admin.contents.vo.ContentsPagingQuery;
import com.leejk0523.javavue.model.AsaContent;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class AdminContentsController {
private final AdminContentsService adminContentsService;
@GetMapping("/api/admin/contents/contentsList")
public ResponseEntity<Page<ContentsListResult>> findContentsList(ContentsPagingQuery query) {
final var results = adminContentsService.findContentsList(query);
return ResponseEntity.ok(results);
}
}

View File

@@ -0,0 +1,84 @@
package com.leejk0523.javavue.admin.contents.dao;
import ch.qos.logback.core.util.StringUtil;
import com.leejk0523.javavue.admin.contents.vo.ContentsListResult;
import com.leejk0523.javavue.admin.contents.vo.ContentsPagingQuery;
import com.leejk0523.javavue.common.QueryDSLUtils;
import com.leejk0523.javavue.model.AsaContent;
import com.leejk0523.javavue.model.QAsaContent;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import io.micrometer.common.util.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class AdminContentsDao extends QuerydslRepositorySupport {
public AdminContentsDao() {
super(AsaContent.class);
}
public Page<ContentsListResult> findContentsList(ContentsPagingQuery query) {
QAsaContent asaContent = QAsaContent.asaContent;
final var offset = QueryDSLUtils.getOffset(query);
final var limit = QueryDSLUtils.getLimit(query);
final var pageable = QueryDSLUtils.getPageable(query);
BooleanExpression expression = asaContent.delYn.eq("N");
if (StringUtils.isNotEmpty(query.getKeyword())) {
switch (query.getType()) {
case CONTENT: {
expression = expression.and(asaContent.contents.contains(query.getKeyword()));
break;
}
case TITLE : {
expression = expression.and(asaContent.contentTitle.contains(query.getKeyword()));
break;
}
case TOTAL: {
expression = expression.and(asaContent.contents.contains(query.getKeyword())
.or(asaContent.contentTitle.contains(query.getKeyword())));
}
}
}
if (StringUtils.isNotEmpty(query.getOrgId())) {
expression = expression.and(asaContent.orgId.eq(query.getOrgId()));
}
final var list = from(asaContent)
.select(
Projections.bean(
ContentsListResult.class,
asaContent.contentId,
asaContent.contentTitle,
asaContent.orgId,
asaContent.useYn,
asaContent.frstRgtrId,
asaContent.frstRegDt,
asaContent.lastMdfrId,
asaContent.lastMdfcnDt
)
)
.where(expression)
.limit(limit)
.offset(offset)
.orderBy(asaContent.contentId.desc())
.fetch();
final var total = from(asaContent).where(expression).fetchCount();
return new PageImpl<>(list, pageable, total);
}
}

View File

@@ -0,0 +1,12 @@
package com.leejk0523.javavue.admin.contents.service;
import com.leejk0523.javavue.admin.contents.vo.ContentsListResult;
import com.leejk0523.javavue.admin.contents.vo.ContentsPagingQuery;
import com.leejk0523.javavue.model.AsaContent;
import org.springframework.data.domain.Page;
import java.util.List;
public interface AdminContentsService {
Page<ContentsListResult> findContentsList(ContentsPagingQuery query);
}

View File

@@ -0,0 +1,22 @@
package com.leejk0523.javavue.admin.contents.service;
import com.leejk0523.javavue.admin.contents.dao.AdminContentsDao;
import com.leejk0523.javavue.admin.contents.vo.ContentsListResult;
import com.leejk0523.javavue.admin.contents.vo.ContentsPagingQuery;
import com.leejk0523.javavue.model.AsaContent;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class AdminContentsServiceImpl implements AdminContentsService {
private final AdminContentsDao adminContentsDao;
@Override
public Page<ContentsListResult> findContentsList(ContentsPagingQuery query) {
return adminContentsDao.findContentsList(query);
}
}

View File

@@ -0,0 +1,17 @@
package com.leejk0523.javavue.admin.contents.vo;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class ContentsListResult {
private Integer contentId;
private String contentTitle;
private String orgId;
private String useYn;
private String frstRgtrId;
private LocalDateTime frstRegDt;
private String lastMdfrId;
private LocalDateTime lastMdfcnDt;
}

View File

@@ -0,0 +1,26 @@
package com.leejk0523.javavue.admin.contents.vo;
import com.leejk0523.javavue.common.PagingQuery;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
@Data
public class ContentsPagingQuery implements PagingQuery {
@NotNull
private int page;
@NotNull
private int size;
private String orgId;
private String siteId;
private String keyword;
private Type type;
public enum Type {
TITLE,
CONTENT,
TOTAL
}
}

View File

@@ -1,9 +1,8 @@
package com.leejk0523.javavue.login.controller; package com.leejk0523.javavue.admin.login.controller;
import com.leejk0523.javavue.login.service.UserLoginService; import com.leejk0523.javavue.admin.login.service.UserLoginService;
import com.leejk0523.javavue.login.vo.In; import com.leejk0523.javavue.admin.login.vo.In;
import com.leejk0523.javavue.login.vo.Member; import com.leejk0523.javavue.admin.login.vo.Out;
import com.leejk0523.javavue.login.vo.Out;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -16,7 +15,7 @@ import java.util.Objects;
public class UserLoginController { public class UserLoginController {
private final UserLoginService userLoginService; private final UserLoginService userLoginService;
@PostMapping("/api/login") @PostMapping("/api/admin/login")
private ResponseEntity<Out> login(@RequestBody In in) { private ResponseEntity<Out> login(@RequestBody In in) {
final var authorization = userLoginService.login(in); final var authorization = userLoginService.login(in);

View File

@@ -1,9 +1,9 @@
package com.leejk0523.javavue.login.dao; package com.leejk0523.javavue.admin.login.dao;
import com.leejk0523.javavue.login.vo.AdminMember; import com.leejk0523.javavue.admin.login.vo.AdminMember;
import com.leejk0523.javavue.login.vo.In; import com.leejk0523.javavue.admin.login.vo.In;
import com.leejk0523.javavue.login.vo.Member; import com.leejk0523.javavue.admin.login.vo.Member;
import com.leejk0523.javavue.login.vo.Out; import com.leejk0523.javavue.admin.login.vo.Out;
import com.leejk0523.javavue.model.*; import com.leejk0523.javavue.model.*;
import com.querydsl.core.types.Projections; import com.querydsl.core.types.Projections;
@@ -11,9 +11,6 @@ import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Component @Component
public class UserLoginDao extends QuerydslRepositorySupport { public class UserLoginDao extends QuerydslRepositorySupport {

View File

@@ -0,0 +1,8 @@
package com.leejk0523.javavue.admin.login.service;
import com.leejk0523.javavue.admin.login.vo.In;
import com.leejk0523.javavue.admin.login.vo.Out;
public interface UserLoginService {
Out login(In in);
}

View File

@@ -1,9 +1,8 @@
package com.leejk0523.javavue.login.service; package com.leejk0523.javavue.admin.login.service;
import com.leejk0523.javavue.login.dao.UserLoginDao; import com.leejk0523.javavue.admin.login.dao.UserLoginDao;
import com.leejk0523.javavue.login.vo.In; import com.leejk0523.javavue.admin.login.vo.In;
import com.leejk0523.javavue.login.vo.Member; import com.leejk0523.javavue.admin.login.vo.Out;
import com.leejk0523.javavue.login.vo.Out;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View File

@@ -1,4 +1,4 @@
package com.leejk0523.javavue.login.vo; package com.leejk0523.javavue.admin.login.vo;
import com.leejk0523.javavue.model.AsaAdminMember; import com.leejk0523.javavue.model.AsaAdminMember;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@@ -1,4 +1,4 @@
package com.leejk0523.javavue.login.vo; package com.leejk0523.javavue.admin.login.vo;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;

View File

@@ -1,4 +1,4 @@
package com.leejk0523.javavue.login.vo; package com.leejk0523.javavue.admin.login.vo;
public interface Member { public interface Member {
String getMemberName(); String getMemberName();

View File

@@ -1,4 +1,4 @@
package com.leejk0523.javavue.login.vo; package com.leejk0523.javavue.admin.login.vo;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.leejk0523.javavue.model.AsaMenu; import com.leejk0523.javavue.model.AsaMenu;

View File

@@ -0,0 +1,23 @@
package com.leejk0523.javavue.admin.site.controller;
import com.leejk0523.javavue.model.AsaSite;
import com.leejk0523.javavue.admin.site.service.AdminSiteService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class AdminSiteController {
private final AdminSiteService adminSiteService;
@GetMapping("/api/admin/sys/site/siteList")
public ResponseEntity<List<AsaSite>> siteAllList() {
final var results = adminSiteService.SiteAllList();
return ResponseEntity.ok(results);
}
}

View File

@@ -0,0 +1,22 @@
package com.leejk0523.javavue.admin.site.dao;
import com.leejk0523.javavue.model.AsaSite;
import com.leejk0523.javavue.model.QAsaSite;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class AdminSiteDao extends QuerydslRepositorySupport {
public AdminSiteDao() {
super(AsaSite.class);
}
public List<AsaSite> SiteAllList() {
QAsaSite asaSite = QAsaSite.asaSite;
return from(asaSite)
.fetch();
}
}

View File

@@ -0,0 +1,11 @@
package com.leejk0523.javavue.admin.site.dao;
import com.leejk0523.javavue.model.AsaSite;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface AdminSiteRepository extends JpaRepository<AsaSite, String> {
}

View File

@@ -0,0 +1,9 @@
package com.leejk0523.javavue.admin.site.service;
import com.leejk0523.javavue.model.AsaSite;
import java.util.List;
public interface AdminSiteService {
List<AsaSite> SiteAllList();
List<AsaSite> findAll();
}

View File

@@ -0,0 +1,26 @@
package com.leejk0523.javavue.admin.site.service;
import com.leejk0523.javavue.admin.site.dao.AdminSiteRepository;
import com.leejk0523.javavue.model.AsaSite;
import com.leejk0523.javavue.admin.site.dao.AdminSiteDao;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class AdminSiteServiceImpl implements AdminSiteService {
private final AdminSiteDao adminSiteDao;
private final AdminSiteRepository adminSiteRepository;
@Override
public List<AsaSite> SiteAllList() {
return adminSiteDao.SiteAllList();
}
@Override
public List<AsaSite> findAll() {
return adminSiteRepository.findAll();
}
}

View File

@@ -0,0 +1,48 @@
package com.leejk0523.javavue.code.dao;
import com.leejk0523.javavue.common.GridCode;
import com.leejk0523.javavue.model.ComCd;
import com.leejk0523.javavue.model.QAsaSite;
import com.leejk0523.javavue.model.QIstInst;
import com.querydsl.core.types.Projections;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class CodeDAO extends QuerydslRepositorySupport {
public CodeDAO() {
super(ComCd.class);
}
public List<GridCode> findSiteCodeList() {
final var site = QAsaSite.asaSite;
return from(site)
.select(
Projections.bean(
GridCode.class,
site.siteId.as("value"),
site.siteName.as("text"),
site.siteName.as("label")
)
)
.fetch();
}
public List<GridCode> findInstCodeList() {
final var inst = QIstInst.istInst;
return from(inst)
.select(
Projections.bean(
GridCode.class,
inst.instNo.as("value"),
inst.instNm.as("label"),
inst.instNm.as("text")
)
)
.fetch();
}
}

View File

@@ -0,0 +1,10 @@
package com.leejk0523.javavue.code.service;
import com.leejk0523.javavue.common.GridCode;
import java.util.List;
public interface CodeService {
List<GridCode> findSiteCodeList();
List<GridCode> findInstCodeList();
}

View File

@@ -0,0 +1,27 @@
package com.leejk0523.javavue.code.service.impl;
import com.leejk0523.javavue.code.dao.CodeDAO;
import com.leejk0523.javavue.code.service.CodeService;
import com.leejk0523.javavue.common.GridCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("lasp.codeServiceImpl")
@RequiredArgsConstructor
public class CodeServiceImpl implements CodeService {
private final CodeDAO codeDAO;
@Override
public List<GridCode> findSiteCodeList() {
return codeDAO.findSiteCodeList();
}
@Override
public List<GridCode> findInstCodeList() {
return codeDAO.findInstCodeList();
}
}

View File

@@ -0,0 +1,29 @@
package com.leejk0523.javavue.code.web;
import com.leejk0523.javavue.code.service.CodeService;
import com.leejk0523.javavue.common.GridCode;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class CodeController {
private final CodeService codeService;
@GetMapping("/api/admin/code/siteList")
public ResponseEntity<List<GridCode>> siteCodeList() {
final var results = codeService.findSiteCodeList();
return ResponseEntity.ok(results);
}
@GetMapping("/api/admin/code/instList")
public ResponseEntity<List<GridCode>> instCodeList() {
final var results = codeService.findInstCodeList();
return ResponseEntity.ok(results);
}
}

View File

@@ -0,0 +1,10 @@
package com.leejk0523.javavue.common;
import lombok.Data;
@Data
public class GridCode {
private String label;
private String text;
private String value;
}

View File

@@ -0,0 +1,6 @@
package com.leejk0523.javavue.common;
public interface PagingQuery {
int getPage();
int getSize();
}

View File

@@ -0,0 +1,18 @@
package com.leejk0523.javavue.common;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
public class QueryDSLUtils {
public static Pageable getPageable(PagingQuery query) {
return PageRequest.of(query.getPage() - 1, query.getSize());
}
public static long getOffset(PagingQuery query) {
return (long) (query.getPage() - 1) * query.getSize();
}
public static long getLimit(PagingQuery query) {
return query.getSize();
}
}

View File

@@ -1,11 +0,0 @@
package com.leejk0523.javavue.login.service;
import ch.qos.logback.core.net.SyslogOutputStream;
import com.leejk0523.javavue.login.dao.UserLoginDao;
import com.leejk0523.javavue.login.vo.In;
import com.leejk0523.javavue.login.vo.Member;
import com.leejk0523.javavue.login.vo.Out;
public interface UserLoginService {
Out login(In in);
}

View File

@@ -0,0 +1,54 @@
package com.leejk0523.javavue.model;
import lombok.Getter;
import lombok.Setter;
import jakarta.persistence.*;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
@Getter
@Setter
@Entity
@Table(name = "ASA_CONTENT")
public class AsaContent {
@Id
@SequenceGenerator(name = "SQ_ASA_CONTENT", sequenceName = "SQ_ASA_CONTENT", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_ASA_CONTENT")
@Column(name = "CONTENT_ID", nullable = false)
private Integer contentId;
@Column(name = "ORG_ID", length = 36)
private String orgId;
@Size(max = 500)
@Column(name = "CONTENT_TITLE", length = 500)
private String contentTitle;
@Lob
@Column(name = "CONTENTS")
private String contents;
@Size(max = 4000)
@Column(name = "CONTENT_PLAIN", length = 4000)
private String contentPlain;
@Column(name = "USE_YN", length = 1, nullable = false)
private String useYn;
@Column(name = "DEL_YN", length = 1, nullable = false)
private String delYn;
@Column(name = "FRST_RGTR_ID", length = 50, nullable = false)
private String frstRgtrId;
@Column(name = "FRST_REG_DT", nullable = false)
private LocalDateTime frstRegDt;
@Column(name = "LAST_MDFR_ID", length = 50)
private String lastMdfrId;
@Column(name = "LAST_MDFCN_DT")
private LocalDateTime lastMdfcnDt;
}

View File

@@ -0,0 +1,72 @@
package com.leejk0523.javavue.model;
import lombok.*;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import jakarta.validation.constraints.*;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "asa_site")
public class AsaSite {
@Id
@Size(max = 20)
@Column(name = "SITE_ID", length = 20)
private String siteId;
@Size(max = 200)
@Column(name = "SITE_NAME", length = 200)
private String siteName;
@Size(max = 1000)
@Column(name = "SITE_DESCRIPTION", length = 1000)
private String siteDescription;
@Size(max = 500)
@Column(name = "SITE_DOMAIN", length = 500)
private String siteDomain;
@Enumerated(EnumType.STRING)
@Column(name = "SITE_TYPE", length = 50)
private Type siteType;
@Size(max = 20)
@Column(name = "site_prefix", length = 20)
private String sitePrefix;
@Size(max = 11)
@Column(name = "SITE_MAIN", length = 11)
private long siteMain;
@Size(max = 20)
@Column(name = "SITE_LOCALE", length = 20)
private String siteLocale;
@Size(max = 11)
@Column(name = "SITE_LOGO", length = 11)
private Integer siteLogo;
@Column(name = "SITE_REGDATE")
private LocalDateTime siteRegdate;
@Size(max = 50)
@Column(name = "ORG_ID", length = 50)
private String orgId;
@Size(max = 200)
@Column(name = "BSC_URL", length = 200)
private String bscUrl;
@Size(max = 200)
@Column(name = "LGN_URL", length = 200)
private String lgnUrl;
public enum Type {
ADMIN,
USER
}
}

View File

@@ -0,0 +1,110 @@
package com.leejk0523.javavue.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "com_cd")
@IdClass(ComCd.Key.class)
public class ComCd {
@Id
@NotNull
@Size(max = 20)
@Column(name = "CD_GROUP_ID", nullable = false, length = 20)
private String cdGroupId;
@Id
@Size(max = 6)
@NotNull
@Column(name = "COM_CD", nullable = false, length = 6)
private String comCd;
@Size(max = 100)
@Column(name = "COM_CD_NM", length = 100)
private String comCdNm;
@Size(max = 2000)
@Column(name = "COM_CD_EXPLN", length = 2000)
private String comCdExpln;
@Column(name = "SORT_SEQ", nullable = false)
private Integer sortSeq;
@Column(name = "USE_YN", length = 1, nullable = false)
private String useYn;
@Column(name = "DEL_YN", length = 1, nullable = false)
private String delYn;
@Size(max = 20)
@Column(name = "ARTCL_NM1", length = 20)
private String artclNm1;
@Size(max = 20)
@Column(name = "ARTCL_NM2", length = 20)
private String artclNm2;
@Size(max = 20)
@Column(name = "ARTCL_NM3", length = 20)
private String artclNm3;
@Size(max = 20)
@Column(name = "ARTCL_NM4", length = 20)
private String artclNm4;
@Size(max = 20)
@Column(name = "ARTCL_NM5", length = 20)
private String artclNm5;
@Size(max = 20)
@Column(name = "ARTCL_NM6", length = 20)
private String artclNm6;
@Size(max = 20)
@Column(name = "ARTCL_NM7", length = 20)
private String artclNm7;
@Size(max = 20)
@Column(name = "ARTCL_NM8", length = 20)
private String artclNm8;
@Size(max = 20)
@Column(name = "ARTCL_NM9", length = 20)
private String artclNm9;
@Size(max = 20)
@Column(name = "ARTCL_NM10", length = 20)
private String artclNm10;
@Column(name = "FRST_RGTR_ID", length = 50, nullable = false)
private String frstRgtrId;
@Column(name = "FRST_REG_DT", nullable = false)
private LocalDateTime frstRegDt;
@Column(name = "LAST_MDFR_ID", length = 50)
private String lastMdfrId;
@Column(name = "LAST_MDFCN_DT")
private LocalDateTime lastMdfcnDt;
@Data
public static class Key implements Serializable {
private static final long serialVersionUID = -3281903370957728656L;
private String cdGroupId;
private String comCd;
}
}

View File

@@ -0,0 +1,52 @@
package com.leejk0523.javavue.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "IST_INST")
public class IstInst {
@Id
@Column(name = "INST_NO", length = 10, nullable = false)
private String instNo;
@Column(name = "INST_CLSF_CD", length = 6, nullable = false)
private String instClsfCd;
@Column(name = "INST_NM", length = 200, nullable = false)
private String instNm;
@Column(name = "INST_SRVC_EXPLN", length = 50)
private String instSrvcExpln;
@Column(name = "INST_CN")
private String instCn;
@Column(name = "ATCH_FILE_ID", length = 20)
private String atchFileId;
@Column(name = "USE_YN", length = 1, nullable = false)
private String useYn;
@Column(name = "FRST_RGTR_ID", length = 50, nullable = false)
private String frstRgtrId;
@Column(name = "FRST_REG_DT", nullable = false)
private LocalDateTime frstRegDt;
@Column(name = "LAST_MDFR_ID", length = 50)
private String lastMdfrId;
@Column(name = "LAST_MDFCN_DT")
private LocalDateTime lastMdfcnDt;
}

View File

@@ -7,4 +7,16 @@ spring.datasource.password=Ghtkssk0325
spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show-sql=true spring.jpa.properties.hibernate.show-sql=true
# SQL 출력
#spring.jpa.show-sql=true
# SQL 포맷팅
spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.type=trace
# 바인딩 파라미터 값 로깅
logging.level.org.hibernate.type.descriptor.sql=TRACE
# SQL에 바인딩된 파라미터 값도 출력
logging.level.org.hibernate.SQL=DEBUG

View File

@@ -1,75 +1,71 @@
# Nuxt Minimal Starter ### 기본 환경
- vue 3.x(5.0.8)
- node (v20.17.0)
- vue-router(최신)
- pinia(최신) - store
- Nuxt(최신) - 프레임워크
- antd 4.x - UI/UX
- yarn (1.22.22)
- 추후 환경은 변경될 수 있음
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more. ## 최초 세팅
- terminal(혹은 command창): yarn install
- 실행 시 yarn dev
## Setup ## 개발 시 중요 사항
- 모든 파일은 업무 기준으로 작성됨(예: 사용자 > user)
- 공통사항으로 적용되는 경우 utils 사용할 것!
- 모든 네이밍은 명확한 단어로 사용할 것!
- 반드시 저장할 경우 Eslint, Prettier 적용
Make sure to install dependencies: ## 공통 단어 주의사항
- 비즈니스 로직은 공통이 아님(불허)
- 공통은 언제든지 사용할 수 있는 라이브러리성을 말하는 것임
```bash ## Commit 금지 파일 및 디렉토리
# npm - /node_modules/
npm install - 기타 IDE 환경 파일(.classpath 등등)
# pnpm ### 페이지 작성
pnpm install - pages/도메인/index.vue
- 페이지는 controller와 같은 역할을 함
- useHead를 이용하여 html head 영역을 설정함
# yarn ### 페이지 내 컴포넌트
yarn install - /src/components/도메인/컴포넌트명.vue
# bun ### store 작성 위치
bun install - 디렉토리: /src/stores/도메인/index.ts
### api 작성 위치
- 디렉토리: /src/apis/도메인/index.ts
### Type 지정
- type 및 interface로 타입을 지정하는 경우가 많음
- 법률구조공단은 type으로 모든 객체의 타입을 지정하는 것을 원칙으로 함
- 최대한 undefined를 사용하지 않는 선으로 개발할 것
- 예로 userId: string의 경우 빈값을 표현할 때 userId: '' 형식으로 사용할 것!
- 타입 import 시 아래와 같이 type을 지정해야 함
```
import type {UserItemType} from 'types'
``` ```
## Development Server
Start the development server on `http://localhost:3000`: ### Toast UI Calendar
```
// ES MODULE
import Calendar from '@toast-ui/calendar';
```bash // CSS 적용
# npm import '@toast-ui/calendar/dist/toastui-calendar.min.css';
npm run dev
# pnpm
pnpm dev
# yarn
yarn dev
# bun
bun run dev
``` ```
## Production ### Toast UI Grid
Build the application for production:
```bash
# npm
npm run build
# pnpm
pnpm build
# yarn
yarn build
# bun
bun run build
``` ```
// ES MODULE
import 'tui-grid/dist/tui-grid.css';
import 'tui-date-picker/dist/tui-date-picker.min.css';
Locally preview production build: // CSS 적용
import Grid from 'tui-grid';
```bash ```
# npm
npm run preview
# pnpm
pnpm preview
# yarn
yarn preview
# bun
bun run preview
```
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

View File

@@ -1,37 +0,0 @@
<!-- DateSearch.vue -->
<template>
<div>
<label for="start-date">시작 날짜:</label>
<input type="date" v-model="startDate" id="start-date" />
<label for="end-date">종료 날짜:</label>
<input type="date" v-model="endDate" id="end-date" />
<button @click="searchData">검색</button>
</div>
</template>
<script setup>
import { ref, onMounted, defineEmits } from 'vue';
const startDate = ref('');
const endDate = ref('');
const emit = defineEmits(['search']);
const searchData = () => {
emit('search', { startDate: startDate.value, endDate: endDate.value });
};
const today = new Date();
const tomorrow = new Date();
tomorrow.setDate(today.getDate() + 1);
startDate.value = formatDate(today);
endDate.value = formatDate(tomorrow);
function formatDate(date) {
return date.toISOString().split('T')[0];
}
</script>
<style scoped>
/* 필요한 스타일 */
</style>

View File

@@ -0,0 +1,40 @@
<script setup lang="ts">
import type { GridCodeType } from '~/types';
const value = defineModel<string>({ default: '' });
const props = defineProps<{
options: GridCodeType[];
className?: string;
selectType?: 'SELECT' | 'ALL';
isLoading?: boolean;
}>();
const selectOptions = computed(() => {
if (props.selectType === 'REQUIRED') {
return [{ label: '선택', value: '' }, ...props.options];
}
if (props.selectType === 'ALL') {
return [{ label: '전체', value: '' }, ...props.options];
}
return props.options;
});
const emit = defineEmits(['change']);
const change = () => {
emit('change');
};
</script>
<template>
<a-select
:class="className"
:options="selectOptions"
:loading="isLoading"
v-model:value="value"
@change="change"
/>
</template>

View File

@@ -0,0 +1,29 @@
<script setup lang="ts">
const props = defineProps<{
className?: string;
selectType?: 'SELECT' | 'ALL';
}>();
const commonCodeStore = useCommonCodeStore();
const value = defineModel<string>('');
const { data, isLoading } = useQuery({
queryKey: ['INST_CODE_LIST'],
queryFn: async () => {
return await commonCodeStore.searchInstCodeList();
},
staleTime: 60 * 1000,
refetchOnWindowFocus: false,
refetchOnMount: false
});
</script>
<template>
<common-default-select-code
v-if="!isLoading"
:class-name="className"
:select-type="selectType"
:options="data"
v-model="value"
/>
</template>

View File

@@ -0,0 +1,28 @@
<script setup lang="ts">
import { useAuthStore } from '~/stores/login';
import { some } from 'lodash-es';
const props = defineProps({
api: {
type: String,
required: true
}
});
const authStore = useAuthStore();
const { permitApiList } = storeToRefs(authStore);
const permit = computed(() => {
return some(permitApiList.value, (value) => {
return props.api === value.menuUrl;
});
});
</script>
<template>
<template v-if="permit">
<slot />
</template>
</template>
<style scoped></style>

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { Editor } from '@toast-ui/editor';
import '@toast-ui/editor/dist/toastui-editor.css';
const editorRef = ref();
const instance = ref();
const emit = defineEmits(['change']);
const props = defineProps<{ initialValue: string }>();
onMounted(() => {
instance.value = new Editor({
el: editorRef.value,
initialValue: props.initialValue ?? '',
initialEditType: 'wysiwyg',
hideModeSwitch: true,
usageStatistics: false,
events: {
keyup: () => {
if (instance.value) {
emit('change', instance.value.getHTML());
}
}
}
});
});
</script>
<template>
<div ref="editorRef"></div>
</template>
<style scoped></style>

View File

@@ -0,0 +1,136 @@
<script setup lang="ts">
import 'tui-grid/dist/tui-grid.css';
import 'tui-date-picker/dist/tui-date-picker.min.css';
import Grid, { type RowKey } from 'tui-grid';
import { cloneDeep } from 'lodash-es';
import type { DataGridType } from '~/types/data/grid';
import type { GridEventName, OptRow } from 'tui-grid/types/options';
import { TUI_GRID_THEME } from '~/constants/theme/grid';
Grid.setLanguage('ko', {
display: {
noData: '조회된 데이터가 존재하지 않습니다.'
}
});
Grid.applyTheme('default', TUI_GRID_THEME);
const gridRef = ref();
const instance = ref<Grid>();
const props = defineProps<DataGridType>();
onMounted(() => {
const gridOptions = {
el: gridRef.value,
columns: props.columns ?? [],
data: cloneDeep(props.data) ?? [],
bodyHeight: props.bodyHeight,
columnOptions: props.columnOptions,
keyColumnName: props.keyColumnName,
width: props.width,
heightResizable: props.heightResizable,
minBodyHeight: props.minBodyHeight,
rowHeight: props.rowHeight ?? 40,
minRowHeight: props.minRowHeight,
scrollX: props.scrollX,
scrollY: props.scrollY,
editingEvent: props.editingEvent,
tabMode: props.tabMode,
rowHeaders: props.rowHeaders,
summary: props.summary,
useClientSort: props.useClientSort,
selectionUnit: props.selectionUnit,
showDummyRows: props.showDummyRows,
copyOptions: props.copyOptions,
pageOptions: props.pageOptions,
treeColumnOptions: props.treeColumnOptions,
header: props.header,
usageStatistics: false,
disabled: props.disabled,
draggable: props.draggable,
contextMenu: props.contextMenu
};
if (props.onGridMounted) {
gridOptions['onGridMounted'] = props.onGridMounted;
}
if (props.onGridUpdated) {
gridOptions['onGridUpdated'] = props.onGridUpdated;
}
if (props.onGridBeforeDestroy) {
gridOptions['onGridBeforeDestroy'] = props.onGridBeforeDestroy;
}
instance.value = new Grid(gridOptions);
});
const appendRow = (value: OptRow) => {
instance.value?.appendRow(value);
};
const appendRows = (value: OptRow[]) => {
instance.value?.appendRows(value);
};
const prependRow = (value: OptRow) => {
instance.value?.prependRow(value);
};
const getCheckedRows = () => {
return instance.value?.getCheckedRows();
};
const getData = () => {
return instance.value?.getData();
};
const validate = () => {
return instance.value?.validate();
};
const resetData = (data: OptRow[]) => {
instance.value?.resetData(data);
};
const removeRow = (data: RowKey) => {
instance.value?.removeRow(data);
};
const removeRows = (data: RowKey[]) => {
instance.value?.removeRows(data);
};
const on = (eventName: GridEventName, eventFunction: (event) => void) => {
instance.value?.on(eventName, eventFunction);
};
const off = (eventName: GridEventName) => {
instance.value?.off(eventName);
};
defineExpose({
appendRow,
appendRows,
prependRow,
getCheckedRows,
getData,
validate,
resetData,
on,
off,
removeRow,
removeRows
});
watch(
() => props.data,
(newValue) => {
resetData(newValue);
}
);
</script>
<template>
<div ref="gridRef" />
</template>

View File

@@ -0,0 +1,163 @@
<script setup lang="ts">
import 'tui-pagination/dist/tui-pagination.css';
import type { PaginationType } from '~/types/data/pagination';
import {
DoubleLeftOutlined,
DoubleRightOutlined,
LeftOutlined,
RightOutlined
} from '@ant-design/icons-vue';
const props = defineProps<PaginationType>();
const emit = defineEmits(['change']);
const totalPages = computed(() => Math.ceil(props.totalElements / props.size));
const rangePages = computed(() =>
Array.from({ length: totalPages.value }, (_, i) => i + 1)
);
const ranges = computed(() => {
const ranges: number[][] = [];
do {
ranges.push(rangePages.value.splice(0, props.showPaginationCount));
} while (rangePages.value.length !== 0);
if (ranges[0].length === 0) {
ranges[0][0] = 1;
}
return ranges;
});
const currentRange = computed(() => {
for (const range of ranges.value) {
if (range.some((i) => i === props.page)) {
return range;
}
}
return [];
});
const currentPeriod = computed(() => {
for (let i = 0; i < ranges.value.length; ++i) {
if (ranges.value[i].some((i) => i === props.page)) {
return i;
}
}
return -1;
});
const prevPageNumber = computed(() => {
const range = ranges.value[currentPeriod.value - 1];
if (range) {
return range[range.length - 1];
}
return props.page;
});
const nextPageNumber = computed(() => {
const range = ranges.value[currentPeriod.value + 1];
if (range) {
return range[0];
}
return props.page;
});
const firstPage = () => {
submitPage(1);
};
const prevPage = () => {
submitPage(prevPageNumber.value);
};
const nextPage = () => {
submitPage(nextPageNumber.value);
};
const lastPage = () => {
submitPage(totalPages.value ? totalPages.value : 1);
};
const change = (value) => {
if (props.size !== value) {
emit('change', props.page, value);
}
};
const movePage = (value) => {
submitPage(value);
};
const submitPage = (page: number) => {
if (props.page !== page) {
emit('change', page, props.size);
}
};
const options = [
{ label: '15', value: 15 },
{ label: '30', value: 30 },
{ label: '50', value: 50 },
{ label: '100', value: 100 }
];
</script>
<template>
<a-row justify="space-between" class="mt-5">
<a-col>
<a-space>
<a-select :options="options" :value="size" @change="change" />
<span>/페이지 ( {{ totalElements }})</span>
</a-space>
</a-col>
<a-col
><a-space>
<a-button
type="link"
:icon="h(DoubleLeftOutlined)"
size="small"
class="pagination-icon-size text-black"
@click="firstPage"
/>
<a-button
type="link"
:icon="h(LeftOutlined)"
class="pagination-icon-size text-black"
size="small"
@click="prevPage"
/>
<a-space>
<a-button
size="small"
:type="pageNo === page ? 'default' : `link`"
class="text-black"
v-for="pageNo in currentRange"
:key="`pagination-${pageNo}`"
@click="() => movePage(pageNo)"
>{{ pageNo }}</a-button
>
</a-space>
<a-button
type="link"
:icon="h(RightOutlined)"
size="small"
class="pagination-icon-size text-black"
@click="nextPage"
/>
<a-button
type="link"
:icon="h(DoubleRightOutlined)"
class="pagination-icon-size text-black"
size="small"
@click="lastPage"
/>
</a-space>
</a-col>
<a-col></a-col>
</a-row>
</template>

View File

@@ -10,7 +10,7 @@ import { LogoutOutlined } from '@ant-design/icons-vue';
</a-button> </a-button>
</a-col> </a-col>
<router-link to="/login" style="color: #1890ff"> <router-link to="/admin/login" style="color: #1890ff">
로그아웃 로그아웃
</router-link> </router-link>

View File

@@ -0,0 +1,20 @@
export const BOOLEANS = [
{ text: '사용', value: 'true' },
{ text: '미사용', value: 'false' }
];
export const YES_OR_NO_CODE_LIST = [
{ text: '예', value: 'true' },
{ text: '아니오', value: 'false' }
];
export const LOCK_CODE_LIST = [
{ text: '정상', value: 'false' },
{ text: '잠김', value: 'true' }
];
export const ADMIN_STATUS_CODE_LIST = [
{ text: '미승인', value: 'NONE' },
{ text: '승인', value: 'APRV' },
{ text: '반려', value: 'RJCT' }
];

View File

@@ -1,12 +1,12 @@
import type { LoginReqType, LoginResType } from '~/types/login'; import type { LoginRequestType, LoginResponseType } from '~/types/login';
export const DEFAULT_AUTHENTICATION_VALUE: LoginReqType = { export const DEFAULT_AUTHENTICATION_VALUE: LoginRequestType = {
memberId: '', memberId: '',
password: '', password: '',
remember: false remember: false
}; };
export const DEFAULT_AUTHORIZATION_VALUE: LoginResType = { export const DEFAULT_AUTHORIZATION_VALUE: LoginResponseType = {
memberName: '', memberName: '',
deptNm: '', deptNm: '',
instNm: '', instNm: '',

View File

@@ -21,12 +21,6 @@ export default defineNuxtConfig({
autoImport: true autoImport: true
}, },
devtools: { enabled: true }, devtools: { enabled: true },
// plugins: [
// '~/plugins/ant-design-vue.ts'
// ],
// css: [
// 'ant-design-vue/dist/reset.css'
// ],
modules: [ modules: [
'@pinia/nuxt', '@pinia/nuxt',
'@unocss/nuxt', '@unocss/nuxt',
@@ -35,11 +29,11 @@ export default defineNuxtConfig({
], ],
vite: { vite: {
optimizeDeps: { optimizeDeps: {
include: ['tui-grid', '@ant-design', 'ant-design-vue'] include: ['tui-grid', 'ant-design-vue']
} }
}, },
alias: {}, alias: {},
experimental: { experimental: {
payloadExtraction: false payloadExtraction: true
} }
}); });

View File

@@ -0,0 +1,126 @@
<script setup lang="ts">
import { useContentStore } from '~/stores/contents';
const route = useRoute();
const router = useRouter();
const contentId = route.query.contentId;
const editorRef = ref();
const contentStore = useContentStore();
const { contents, initialValue } = storeToRefs(contentStore);
onBeforeMount(() => {
if (contentId) {
contentStore.searchContents(Number(contentId));
} else {
contentStore.resetContents();
}
});
const save = () => {
contents.value.contents = editorRef.value.getValue();
contentStore
.updateContents()
.then(() => {
message.success('콘텐츠 정보가 저장이 되었습니다.');
moveList();
})
.catch(() => {
message.error('콘텐츠 저장에 실패하였습니다.');
});
};
const moveList = () => {
router.push('/admin/content/list');
};
const nonValid = computed(() => {
return !contents.value.contentTitle;
});
</script>
<template>
<client-only>
<a-space direction="vertical" class="w-full">
<a-card>
<a-row>
<a-col :span="24">
<a-form-item
label="제목"
label-align="left"
:colon="false"
:label-col="{ span: 2 }"
>
<a-input
title="제목"
placeholder="콘텐츠 제목"
v-model:value="contents.contentTitle"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item
label="기관"
label-align="left"
:colon="false"
:label-col="{ span: 2 }"
>
<common-inst-code-select v-model:value="contents.orgId" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item
label="내용"
label-align="left"
:colon="false"
:label-col="{ span: 2 }"
:wrapper-col="{ span: 22 }"
>
<lazy-data-editor ref="editorRef" :initial-value="initialValue" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item
label="사용여부"
label-align="left"
:colon="false"
:label-col="{ span: 2 }"
:wrapper-col="{ span: 22 }"
>
<a-switch v-model:checked="contents.useYn" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-flex justify="space-between">
<a-space>
<common-permit-button api="/api/admin/contents/updateContents">
<a-button
type="primary"
@click="save"
:disabled="nonValid"
v-if="!contentId"
>저장</a-button
>
<a-button
type="primary"
@click="save"
v-if="contentId != null"
>수정</a-button
>
</common-permit-button>
<a-button type="default" @click="moveList">목록</a-button>
</a-space>
</a-flex>
</a-col>
</a-row>
</a-card>
</a-space>
</client-only>
</template>

View File

@@ -0,0 +1,202 @@
<script setup lang="ts">
import type { OptColumn, OptRowHeader } from 'tui-grid/types/options';
import { useContentStore } from '~/stores/contents';
import type { ContentType } from '~/types/contents';
import { useCommonCodeStore } from '~/stores';
const router = useRouter();
const instCodeList = await useCommonCodeStore().searchInstCodeList();
const contentStore = useContentStore();
const { contentsList, contentsQuery } = storeToRefs(contentStore);
const gridRef = ref();
const gridRowHeaders: OptRowHeader[] = ['checkbox', 'rowNum'];
const columns: OptColumn[] = [
{
name: 'contentId',
hidden: true
},
{
name: 'contentTitle',
header: '콘텐츠제목'
},
{
name: 'orgId',
header: '관리기관',
width: 100,
disabled: true,
formatter: 'listItemText',
resizable: true,
editor: {
type: 'select',
options: {
listItems: instCodeList
}
}
},
{
name: 'useYn',
header: '사용여부',
width: 80,
align: 'center',
},
{
name: 'frstRgtrId',
header: '작성자',
width: 100
},
{
name: 'frstRegDt',
header: '작성일',
width: 130
},
{
name: 'lastMdfrId',
header: '수정자',
width: 100
},
{
name: 'lastMdfcnDt',
header: '수정일',
width: 130
}
];
const contentType = [
{ label: '전체', value: 'TOTAL' },
{ label: '제목', value: 'TITLE' },
{ label: '내용', value: 'CONTENT' }
];
onBeforeMount(() => {
contentStore.searchContentList();
});
onBeforeUnmount(() => {
// contentStore.resetContentListQuery();
});
const search = () => {
contentStore.searchContentList();
};
const list = computed(() => {
return contentsList.value.content;
});
watch(list, (newValue) => {
if (gridRef.value) {
gridRef.value.off('dblclick');
if (newValue.length > 0) {
setTimeout(() => {
gridRef.value.on('dblclick', ({ instance, rowKey }) => {
const row = instance.getRow(rowKey);
editPage(row.contentId);
});
}, 100);
}
}
});
const deleteContentList = async () => {
const checkedRows = gridRef.value.getCheckedRows() as Array<ContentType>;
if (!checkedRows.length) {
message.warn('삭제할 콘텐츠가 없습니다.');
return;
}
Modal.confirm({
type: 'warning',
okText: '예',
cancelText: '아니오',
title: '컨텐츠 삭제',
content: '선택한 컨텐츠를 삭제하시겠습니까?',
onOk: async () => {
const createdRows = checkedRows.filter((row) => row.contentId);
await contentStore.deleteContents(createdRows);
await contentStore.searchContentList();
}
});
};
const movePage = (page: number) => {
contentsQuery.value.page = page;
search();
};
const editPage = (contentId: any) => {
const query = typeof contentId === 'number' ? `?contentId=${contentId}` : '';
router.push(`/admin/content${query}`);
};
</script>
<template>
<client-only>
<a-space direction="vertical" class="w-full">
<a-card>
<a-row :gutter="[16, 8]">
<a-col>
<a-space>
<a-typography-text>관리기관</a-typography-text>
<lazy-common-inst-code-select
key="inst-code-select"
v-model="contentsQuery.orgId"
class-name="w-40"
select-type="ALL"
/>
</a-space>
</a-col>
<a-col>
<a-space>
<a-typography-text>검색어</a-typography-text>
<a-select
title="컨텐츠 구분"
class="w-20"
v-model:value="contentsQuery.type"
:options="contentType"
/>
<a-input title="검색어" placeholder="Search" class="w-60"
v-model:value="contentsQuery.keyword" allow-clear/>
</a-space>
</a-col>
<a-col>
<a-button type="primary" @click="search">검색</a-button>
</a-col>
</a-row>
</a-card>
<a-card>
<a-space direction="vertical" class="w-full">
<a-flex justify="space-between">
<!-- <common-permit-button api="/api/admin/contents/deleteContents">-->
<!-- <a-button type="primary" danger @click="deleteContentList"-->
<!-- >삭제-->
<!-- </a-button>-->
<!-- </common-permit-button>-->
<!-- <common-permit-button api="/api/admin/contents/updateContents">-->
<!-- <a-button type="primary" @click="editPage">추가</a-button>-->
<!-- </common-permit-button>-->
</a-flex>
<data-grid
:key="`board-content-grid-${Math.random()}`"
:row-headers="gridRowHeaders"
:data="contentsList.content"
:columns="columns"
ref="gridRef"
/>
<data-pagination
:key="`pagination-${Math.random()}`"
:total-elements="contentsList.totalElements"
:show-pagination-count="10"
:size="contentsQuery.size"
:page="contentsQuery.page"
@change="movePage"
/>
</a-space>
</a-card>
</a-space>
</client-only>
</template>

View File

@@ -0,0 +1,192 @@
<script setup lang="ts">
import type { OptColumn, OptRowHeader } from 'tui-grid/types/options';
import { useSiteStore } from '~/stores/sys/site';
import type { SiteType } from '~/types/sys/site';
import { MaxLengthTextEditor } from '~/constants/theme/grid/MaxLengthTextEditor';
const siteStore = useSiteStore();
const { siteList } = storeToRefs(siteStore);
const gridRef = ref();
const gridRowHeaders: OptRowHeader[] = ['checkbox', 'rowNum'];
const columns: OptColumn[] = [
{
name: 'siteId',
header: '사이트 ID',
width: 80,
editor: {
type: 'text'
},
validation: {
required: true
}
},
{
name: 'siteName',
header: '사이트명',
width: 120,
editor: {
type: 'text'
},
validation: {
required: true
}
},
{
name: 'siteDescription',
header: '사이트 설명',
width: 200,
editor: {
type: 'text'
}
},
{
name: 'siteDomain',
header: '사이트 도메인',
width: 150,
editor: {
type: 'text'
},
validation: {
required: true
}
},
{
name: 'siteType',
header: '사이트 형식',
width: 80,
formatter: 'listItemText',
editor: {
type: 'select',
options: {
listItems: [
{ text: '사용자', value: 'USER' },
{ text: '관리자', value: 'ADMIN' }
]
}
},
validation: {
required: true
}
},
{
name: 'sitePrefix',
header: '사이트 구분',
width: 120,
editor: {
type: 'select',
options: {
listItems: [
{ text: '대국민포털', value: 'portal' },
{ text: '참여기관포털', value: 'admin' }
]
}
}
},
{
name: 'lgnUrl',
header: '로그인 URL',
width: 120,
editor: {
type: MaxLengthTextEditor,
options: {
maxlength: 200,
placeholder: '로그인 URL을 입력해주세요.'
}
}
},
{
name: 'bscUrl',
header: '기본 URL',
width: 120,
editor: {
type: MaxLengthTextEditor,
options: {
maxlength: 200,
placeholder: '로그인 후 이동될 URL을 입력해주세요.'
}
}
},
{ name: 'siteRegdate', header: '등록일시', width: 140 }
];
onBeforeMount(() => {
siteStore.searchSiteList();
});
const save = () => {
if (gridRef.value.validate().length) {
alert('len:::' + gridRef.value.validate().length);
message.warn('입력된 사이트 정보를 확인해주세요.');
return;
}
Modal.confirm({
type: 'info',
title: '사이트 정보 저장',
content: '선택한 사이트 정보를 저장하시겠습니까?',
okText: '예',
cancelText: '아니오',
onOk: async () => {
try {
const data = gridRef.value.getData();
siteStore.updateSiteList(data);
} catch (e) {
message.error('사이트 정보를 저장하는 도중 에러가 발생되었습니다.');
}
}
});
};
const deleteSiteList = () => {
const checkedRows = gridRef.value.getCheckedRows() as Array<SiteType>;
if (!checkedRows.length) {
message.warn('삭제할 사이트가 없습니다.');
return;
}
const params = new URLSearchParams();
checkedRows.forEach((value) => {
params.append('siteId', value.siteId);
});
};
const addRow = () => {
gridRef.value.appendRow({});
};
</script>
<template>
<client-only>
<a-space direction="vertical" style="width: 100%">
<a-card>
<a-space direction="vertical" style="width: 100%">
<a-flex justify="space-between">
<common-permit-button api="/api/admin/sys/site/deleteSiteList">
<a-button type="primary" danger @click="deleteSiteList"
>삭제</a-button
>
</common-permit-button>
<common-permit-button api="/api/admin/sys/site/updateSiteList">
<a-space>
<a-button type="primary" @click="addRow">추가</a-button>
<a-button type="primary" @click="save">저장</a-button>
</a-space>
</common-permit-button>
</a-flex>
<data-grid
:key="`site-grid-${Math.random()}`"
:row-headers="gridRowHeaders"
:data="siteList"
:columns="columns"
ref="gridRef"
/>
</a-space>
</a-card>
</a-space>
</client-only>
</template>
<style scoped></style>

View File

@@ -0,0 +1,140 @@
import type {
ContentListQueryType,
ContentListType,
ContentType
} from '~/types/contents';
import { cloneDeep } from 'lodash-es';
import type { Page } from '~/types/common';
import { defineStore } from 'pinia';
import { ref } from 'vue';
import { useAxios } from '~/composables/useAxios';
import { message } from 'ant-design-vue';
const DEFAULT_CONTENT_QUERY: ContentListQueryType = {
keyword: '',
orgId: '',
page: 1,
siteId: '',
size: 10,
type: 'TOTAL'
};
const DEFAULT_CONTENTS_LIST: Page<ContentListType> = {
content: [],
totalElements: 0,
totalPages: 0
};
const DEFAULT_CONTENTS: ContentType = {
contentTitle: '',
contentPlain: '',
contents: '',
frstRegDt: '',
frstRgtrId: '',
lastMdfcnDt: '',
lastMdfrId: '',
orgId: '',
siteId: '',
useYn: true
};
export const useContentStore = defineStore('useContentStore', () => {
const contentsQuery = ref<ContentListQueryType>(
cloneDeep(DEFAULT_CONTENT_QUERY)
);
const contentsList = ref<Page<ContentListType>>(
cloneDeep(DEFAULT_CONTENTS_LIST)
);
const contents = ref<ContentType>(cloneDeep(DEFAULT_CONTENTS));
const initialValue = ref<string>('');
const resetContentListQuery = () => {
contentsQuery.value = cloneDeep(DEFAULT_CONTENT_QUERY);
};
const resetContentList = () => {
contentsList.value = cloneDeep(DEFAULT_CONTENTS_LIST);
};
const resetContents = () => {
contents.value = cloneDeep(DEFAULT_CONTENTS);
initialValue.value = '';
};
const initContentsQuery = () => {
contentsQuery.value = cloneDeep(DEFAULT_CONTENT_QUERY);
};
const searchContentList = async () => {
try {
const { data } = await useAxios().get(
'/api/admin/contents/contentsList',
{
params: {
...contentsQuery.value
}
}
);
contentsList.value = data;
} catch (e) {
message.error('사이트 리스트를 불러오는데 실패하였습니다.');
}
};
const searchContents = async (contentId: number) => {
try {
const { data } = await useAxios().get('/api/admin/contents/detail', {
params: {
contentId
}
});
contents.value = data;
initialValue.value = data.contents;
} catch (e) {
message.error('컨텐츠 정보를 불러오는데 실패하였습니다.');
}
};
const updateContents = () => {
console.log(contents.value);
return useAxios().post(
'/api/admin/contents/updateContents',
contents.value
);
};
const deleteContents = async (data: ContentType[]) => {
try {
const params = new URLSearchParams();
data.forEach((item) => {
params.append('contentId', String(item.contentId));
});
await useAxios().post('/api/admin/contents/deleteContents', null, {
params
});
message.success('컨텐츠 정보가 삭제 되었습니다.');
} catch (e) {
message.error('컨텐츠 정보 삭제에 실패하였습니다.');
}
};
return {
contentsQuery,
contentsList,
contents,
initialValue,
resetContentListQuery,
searchContentList,
searchContents,
resetContentList,
resetContents,
initContentsQuery,
deleteContents,
updateContents
};
});

80
nuxt/stores/index.ts Normal file
View File

@@ -0,0 +1,80 @@
import type { SiteType } from '~/types/sys/site';
import type { GridCodeType } from '~/types';
import { defineStore } from 'pinia';
import { computed, ref } from 'vue';
import { useAxios } from '~/composables/useAxios';
export const useLoadingStore = defineStore('useLoadingStore', () => {
const loadCount = ref<number>(0);
const incrementLoadCount = () => {
loadCount.value++;
};
const decrementLoadCount = () => {
loadCount.value--;
};
const resetLoadCount = () => {
loadCount.value = 0;
};
const isLoading = computed(() => {
return loadCount.value > 0;
});
return {
isLoading,
resetLoadCount,
incrementLoadCount,
decrementLoadCount
};
});
export const useDefaultStore = defineStore('useDefaultStore', () => {
const siteInfo = ref<SiteType>({
siteId: '',
siteName: '',
siteDescription: '',
siteDomain: '',
siteType: '',
sitePrefix: '',
siteLocale: '',
siteLogo: '',
bscUrl: '',
lgnUrl: '',
delYn: false,
useYn: true,
frstRgtrId: '',
frstRegDt: '',
lastMdfrId: '',
lastMdfcnDt: ''
});
const fetchSiteInfo = async () => {
const { data } = await useAxios().get<SiteType>('/api/admin/siteInfo');
siteInfo.value = data;
};
return { siteInfo, fetchSiteInfo };
});
export const useCommonCodeStore = defineStore('useCommonCodeStore', () => {
const searchSiteCodeList = async (): Promise<GridCodeType[]> => {
const { data } = await useAxios().get('/api/admin/code/siteList');
return data;
};
const searchInstCodeList = async (): Promise<GridCodeType[]> => {
const { data } = await useAxios().get<GridCodeType[]>(
'/api/admin/code/instList'
);
return data;
};
return {
searchInstCodeList,
searchSiteCodeList
};
});

View File

@@ -16,12 +16,17 @@ export const useAuthStore = defineStore('authStore', () => {
); );
const LoginAPI = async () => { const LoginAPI = async () => {
return await useAxios().post(`/api/login`, loginRequest.value); return await useAxios().post(`/api/admin/login`, loginRequest.value);
}; };
const permitApiList = computed(() => {
return loginResponse.value.permitApiList;
});
return { return {
loginRequest, loginRequest,
loginResponse, loginResponse,
LoginAPI LoginAPI,
permitApiList
}; };
}); });

View File

@@ -0,0 +1,34 @@
import type { SiteType } from '~/types/sys/site';
export const useSiteStore = defineStore('useSiteStore', () => {
const siteList = ref<SiteType[]>([]);
const resetSiteList = () => {
siteList.value = [];
};
const searchSiteList = async () => {
try {
const { data } = await useAxios().get('/api/admin/sys/site/siteList');
siteList.value = data;
} catch (e) {
message.error('사이트 리스트를 불러오는데 실패하였습니다.');
}
};
const updateSiteList = async (data: SiteType[]) => {
try {
await useAxios().post('/api/admin/sys/site/updateSiteList', data);
message.success('사이트 정보가 저장이 되었습니다.');
} catch (e) {
message.error('사이트 저장에 실패하였습니다.');
}
};
return {
siteList,
resetSiteList,
searchSiteList,
updateSiteList
};
});

View File

@@ -0,0 +1,10 @@
export type Page<T> = {
content: T[];
totalElements: number;
totalPages: number;
};
export type PagingQuery = {
page: number;
size: number;
};

View File

@@ -0,0 +1,32 @@
export type ContentListQueryType = {
page: number;
size: number;
siteId: string;
orgId: string;
keyword: string;
type: 'TOTAL' | 'TITLE' | 'CONTENT';
};
export type ContentListType = {
contentId: number;
contentTitle: string;
useYn: boolean;
frstRgtrId: string;
frstRegDt: string;
lastMdfrId: string;
lastMdfcnDt: string;
};
export type ContentType = {
contentId?: number;
siteId: string;
orgId: string;
contentTitle: string;
contents: string;
contentPlain: string;
useYn: boolean;
frstRgtrId: string;
frstRegDt: string;
lastMdfrId: string;
lastMdfcnDt: string;
};

50
nuxt/types/data/grid.ts Normal file
View File

@@ -0,0 +1,50 @@
import type {
GridEventListener,
OptColumn,
OptHeader,
OptRow,
OptRowHeader,
OptSummaryData,
OptTree
} from 'tui-grid/types/options';
import type { EditingEvent, TabMode } from 'tui-grid/types/store/focus';
import type { SelectionUnit } from 'tui-grid/types/store/selection';
import type {
ClipboardCopyOptions,
ColumnOptions
} from 'tui-grid/types/store/column';
import type { PageOptions } from 'tui-grid/types/store/data';
import type { CreateMenuGroups } from 'tui-grid/types/store/contextMenu';
export type DataGridType = {
data: OptRow[];
columns: OptColumn[];
bodyHeight?: number | 'fitToParent' | 'auto';
columnOptions?: ColumnOptions;
keyColumnName?: String;
width?: number | 'auto';
heightResizable?: Boolean;
minBodyHeight?: Number;
rowHeight?: number | 'auto';
minRowHeight?: Number;
scrollX?: Boolean;
scrollY?: Boolean;
editingEvent?: EditingEvent;
tabMode?: TabMode;
rowHeaders?: OptRowHeader[];
summary?: OptSummaryData;
useClientSort?: Boolean;
selectionUnit?: SelectionUnit;
showDummyRows?: Boolean;
copyOptions?: ClipboardCopyOptions;
pageOptions?: PageOptions;
treeColumnOptions?: OptTree;
header?: OptHeader;
usageStatistics?: Boolean;
disabled?: Boolean;
onGridMounted?: GridEventListener;
onGridUpdated?: GridEventListener;
onGridBeforeDestroy?: GridEventListener;
draggable?: Boolean;
contextMenu?: CreateMenuGroups;
};

View File

@@ -0,0 +1,7 @@
export type PaginationType = {
page: number;
size: number;
totalElements: number;
showPaginationCount: number;
};

20
nuxt/types/index.ts Normal file
View File

@@ -0,0 +1,20 @@
export type PagingQueryType = {
page: number;
size: number;
};
export type GridCodeType = {
label?: string;
text?: string;
value: string;
};
export type FileInfoType = {
fileId: number;
fileOriginalName: string;
filePath: string;
fileMimeType: string;
fileSize: number;
fileAltText: string;
fileDownloadCount: number;
};

View File

@@ -0,0 +1,13 @@
export type SiteType = {
siteId: string;
siteName: string;
siteDescription: string;
siteDomain: string;
siteType: '' | 'ADMIN' | 'USER';
sitePrefix: string;
siteLocale: string;
siteLogo: string;
bscUrl: string;
lgnUrl: string;
siteRegdate: string;
};