diff --git a/nuxt/app.vue b/nuxt/app.vue index 97c2185..dfb6f25 100644 --- a/nuxt/app.vue +++ b/nuxt/app.vue @@ -1,8 +1,4 @@ diff --git a/nuxt/composables/useAxios.ts b/nuxt/composables/useAxios.ts new file mode 100644 index 0000000..0c92dde --- /dev/null +++ b/nuxt/composables/useAxios.ts @@ -0,0 +1,41 @@ +import axios, { type AxiosError, type AxiosResponse } from 'axios'; +// import { useAuthStore } from '~/stores/login'; +// import { useDefaultStore, useLoadingStore } from '~/stores'; + +const baseURL = import.meta.env.VITE_API_URL as string; + +export const useAxios = () => { + // const loadingStore = useLoadingStore(); + // const defaultStore = useDefaultStore(); + // const { siteInfo } = storeToRefs(defaultStore); + // const authStore = useAuthStore(); + const router = useRouter(); + + const instance = axios.create({ + baseURL, + withCredentials: true + }); + + instance.interceptors.request.use( + (config) => { + return Promise.resolve(config); + }, + (error: AxiosError) => { + return Promise.reject(error); + } + ); + + instance.interceptors.response.use( + (response: AxiosResponse) => { + return Promise.resolve(response); + }, + (error: AxiosError) => { + if (error.status === 403) { + return router.push('/'); + } + return Promise.reject(error); + } + ); + + return instance; +}; diff --git a/nuxt/constants/login/index.ts b/nuxt/constants/login/index.ts new file mode 100644 index 0000000..499e884 --- /dev/null +++ b/nuxt/constants/login/index.ts @@ -0,0 +1,16 @@ +import type { LoginReqType, LoginResType } from '~/types/login'; + +export const DEFAULT_AUTHENTICATION_VALUE: LoginReqType = { + memberId: '', + password: '', + remember: false +}; + +export const DEFAULT_AUTHORIZATION_VALUE: LoginResType = { + memberName: '', + deptNm: '', + instNm: '', + menuList: [], + permitApiList: [], + authenticated: false +}; diff --git a/nuxt/constants/theme/grid/ConditionButtonRenderer.ts b/nuxt/constants/theme/grid/ConditionButtonRenderer.ts new file mode 100644 index 0000000..1488efc --- /dev/null +++ b/nuxt/constants/theme/grid/ConditionButtonRenderer.ts @@ -0,0 +1,36 @@ +import type { CellRendererProps } from 'tui-grid/types/renderer'; + +export class ConditionButtonRenderer { + el: HTMLElement; + + constructor(props: CellRendererProps) { + const { rowKey, grid } = props; + const { options } = props.columnInfo.renderer; + const data = grid.getRow(rowKey); + + console.log(!data.baAnswerYn); + if (!data.baAnswerYn) { + const el = document.createElement('button'); + el.className = 'ant-btn ant-btn-primary'; + el.onclick = () => options?.onClick(data); + el.innerHTML = `${options?.buttonName}`; + this.el = el; + } else { + const el = document.createElement('span'); + el.innerHTML = options?.spanName; + this.el = el; + } + } + + beforeDestroy(): void {} + + focused(): void {} + + getElement(): Element { + return this.el; + } + + mounted(parent: HTMLElement): void {} + + render(props: CellRendererProps): void {} +} diff --git a/nuxt/constants/theme/grid/ConditionIconButtonRenderer.ts b/nuxt/constants/theme/grid/ConditionIconButtonRenderer.ts new file mode 100644 index 0000000..04a4279 --- /dev/null +++ b/nuxt/constants/theme/grid/ConditionIconButtonRenderer.ts @@ -0,0 +1,39 @@ +import type { CellRendererProps } from 'tui-grid/types/renderer'; + +export class ConditionIconButtonRenderer { + el: HTMLElement; + + constructor(props: CellRendererProps) { + const { options } = props.columnInfo.renderer; + const data = props.grid.getRow(props.rowKey); + + if (options?.condition(data)) { + const el = document.createElement('a'); + // @ts-ignore + const { icon } = options; + el.innerHTML = ` + +`; + el.className = 'ant-btn ant-btn-primary'; + el.onclick = () => options?.onClick(data); + + this.el = el; + } else { + this.el = document.createElement('span'); + } + } + + beforeDestroy(): void {} + + focused(): void {} + + getElement(): Element { + return this.el; + } + + mounted(parent: HTMLElement): void {} + + render(props: CellRendererProps): void {} +} diff --git a/nuxt/constants/theme/grid/FunctionalButtonRenderer.ts b/nuxt/constants/theme/grid/FunctionalButtonRenderer.ts new file mode 100644 index 0000000..c60bf9a --- /dev/null +++ b/nuxt/constants/theme/grid/FunctionalButtonRenderer.ts @@ -0,0 +1,28 @@ +import type { CellRendererProps } from 'tui-grid/types/renderer'; + +export class FunctionalButtonRenderer { + el: HTMLElement; + + constructor(props: CellRendererProps) { + const el = document.createElement('button'); + const options = props.columnInfo.renderer.options; + const data = props.grid.getRow(props.rowKey); + el.className = 'ant-btn ant-btn-primary'; + el.onclick = () => options?.onClick(data); + el.innerHTML = `${options?.buttonName}`; + + this.el = el; + } + + beforeDestroy(): void {} + + focused(): void {} + + getElement(): Element { + return this.el; + } + + mounted(parent: HTMLElement): void {} + + render(props: CellRendererProps): void {} +} diff --git a/nuxt/constants/theme/grid/MaxLengthTextEditor.ts b/nuxt/constants/theme/grid/MaxLengthTextEditor.ts new file mode 100644 index 0000000..c249963 --- /dev/null +++ b/nuxt/constants/theme/grid/MaxLengthTextEditor.ts @@ -0,0 +1,27 @@ +import type { CellEditorProps } from 'tui-grid/types/editor'; + +export class MaxLengthTextEditor { + el: HTMLInputElement; + + constructor(props: CellEditorProps) { + const el = document.createElement('input'); + el.type = 'text'; + el.value = props.value as string; + el.maxLength = props.columnInfo.editor?.options?.maxlength; + el.placeholder = props.columnInfo.editor?.options?.placeholder; + + this.el = el; + } + + getElement() { + return this.el; + } + + getValue() { + return this.el.value; + } + + mounted() { + this.el.select(); + } +} diff --git a/nuxt/constants/theme/grid/MenuSatisChargerRenderer.ts b/nuxt/constants/theme/grid/MenuSatisChargerRenderer.ts new file mode 100644 index 0000000..cc5b5a3 --- /dev/null +++ b/nuxt/constants/theme/grid/MenuSatisChargerRenderer.ts @@ -0,0 +1,82 @@ +import type { CellRendererProps } from 'tui-grid/types/renderer'; +import type { MenuType } from '~/types/sys/menu'; + +export class MenuSatisChargerRenderer { + el: HTMLElement; + + constructor(props: CellRendererProps) { + const el = document.createElement('div'); + + el.style['gap'] = '8px'; + el.className = 'flex justify-center'; + + const { rowKey, grid } = props; + const options = props.columnInfo.renderer.options as any; + + const data = grid.getRow(rowKey) as unknown as MenuType; + if (!data.menuType.endsWith('API')) { + if (data?.menuMngId) { + const { onView, onDelete } = options; + const viewLink = document.createElement('a'); + const deleteLink = document.createElement('a'); + + viewLink.innerHTML = '보기'; + viewLink.onclick = () => onView(data); + + deleteLink.innerHTML = '삭제'; + deleteLink.onclick = () => onDelete(data); + + el.append(viewLink, deleteLink); + } else { + const { onEdit } = options; + const link = document.createElement('a'); + link.innerHTML = '등록'; + link.onclick = () => onEdit(data); + + el.append(link); + } + } + + this.el = el; + } + + beforeDestroy(): void {} + + focused(): void {} + + getElement(): Element { + return this.el; + } + + mounted(parent: HTMLElement): void {} + + render(props: CellRendererProps): void { + this.el.innerHTML = ''; + const { rowKey, grid } = props; + const options = props.columnInfo.renderer.options as any; + + const data = grid.getRow(rowKey) as unknown as MenuType; + if (!data.menuType.endsWith('API')) { + if (data?.menuMngId) { + const { onView, onDelete } = options; + const viewLink = document.createElement('a'); + const deleteLink = document.createElement('a'); + + viewLink.innerHTML = '보기'; + viewLink.onclick = () => onView(data); + + deleteLink.innerHTML = '삭제'; + deleteLink.onclick = () => onDelete(data); + + this.el.append(viewLink, deleteLink); + } else { + const { onEdit } = options; + const link = document.createElement('a'); + link.innerHTML = '등록'; + link.onclick = () => onEdit(data); + + this.el.append(link); + } + } + } +} diff --git a/nuxt/constants/theme/grid/RadioHeaderRenderer.ts b/nuxt/constants/theme/grid/RadioHeaderRenderer.ts new file mode 100644 index 0000000..fdbf272 --- /dev/null +++ b/nuxt/constants/theme/grid/RadioHeaderRenderer.ts @@ -0,0 +1,32 @@ +import type { CellRendererProps } from 'tui-grid/types/renderer'; + +export class RadioHeaderRenderer { + el: HTMLElement; + + constructor(props: CellRendererProps) { + const { rowKey, grid } = props; + + const { options } = props.columnInfo.renderer; + const data = grid.getRow(rowKey); + + const el = document.createElement('input'); + el.name = 'gridRadio'; + el.type = 'radio'; + el.className = ''; + el.addEventListener('change', () => options?.onChange(data)); + + this.el = el; + } + + beforeDestroy(): void {} + + focused(): void {} + + getElement(): Element { + return this.el; + } + + mounted(parent: HTMLElement): void {} + + render(props: CellRendererProps): void {} +} diff --git a/nuxt/constants/theme/grid/index.ts b/nuxt/constants/theme/grid/index.ts new file mode 100644 index 0000000..b3846f2 --- /dev/null +++ b/nuxt/constants/theme/grid/index.ts @@ -0,0 +1,65 @@ +import type { OptPreset } from 'tui-grid/types/options'; + +export const TUI_GRID_THEME: OptPreset = { + selection: { + background: '#4daaf9', + border: '#004082' + }, + scrollbar: { + background: '#f5f5f5', + thumb: '#d9d9d9', + active: '#c1c1c1' + }, + outline: { + border: '#e1e2e5' + }, + area: { + header: { + border: '#e1e2e5', + background: '#f8f8f9' + } + }, + row: { + even: { + background: '#EFFAFF' + } + }, + cell: { + normal: { + background: 'white', + border: '#eee', + showVerticalBorder: true + }, + header: { + background: '#f8f8f9', + showHorizontalBorder: true, + showVerticalBorder: true + }, + rowHeader: { + border: '#e1e2e5', + background: '#f8f8f9', + showHorizontalBorder: false, + showVerticalBorder: false + }, + editable: { + // 수정 가능 셀 색상은 아래에 + background: 'white' + }, + selectedHeader: { + background: '#e0e0e0' + }, + focused: { + border: '#418ed4' + }, + disabled: { + text: '#333', + background: 'white' + }, + invalid: { + background: '#D60440' + }, + required: { + background: 'white' + } + } +}; diff --git a/nuxt/pages/login/id.vue b/nuxt/pages/login/id.vue deleted file mode 100644 index 8be2f9c..0000000 --- a/nuxt/pages/login/id.vue +++ /dev/null @@ -1,133 +0,0 @@ - - - diff --git a/nuxt/pages/login/index.vue b/nuxt/pages/login/index.vue index b7132e1..ead26c8 100644 --- a/nuxt/pages/login/index.vue +++ b/nuxt/pages/login/index.vue @@ -1,49 +1,28 @@ @@ -64,7 +43,7 @@ const validateLogin = computed(() => {
- + 키보드보안 프로그램적용
@@ -78,7 +57,7 @@ const validateLogin = computed(() => { @@ -86,10 +65,10 @@ const validateLogin = computed(() => { @@ -97,7 +76,7 @@ const validateLogin = computed(() => { @@ -106,15 +85,15 @@ const validateLogin = computed(() => {
- 아이디 찾기 | - 비밀번호 찾기 | - 회원가입
diff --git a/nuxt/pages/login/join.vue b/nuxt/pages/login/join.vue deleted file mode 100644 index 6e70732..0000000 --- a/nuxt/pages/login/join.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - - - diff --git a/nuxt/pages/login/pw.vue b/nuxt/pages/login/pw.vue deleted file mode 100644 index 204d8a8..0000000 --- a/nuxt/pages/login/pw.vue +++ /dev/null @@ -1,124 +0,0 @@ - - - diff --git a/nuxt/stores/login/index.ts b/nuxt/stores/login/index.ts new file mode 100644 index 0000000..180d45b --- /dev/null +++ b/nuxt/stores/login/index.ts @@ -0,0 +1,27 @@ +import {useAxios} from "~/composables/useAxios"; +import type {LoginRequestType, LoginResponseType} from "~/types/login"; +import { cloneDeep } from 'lodash-es'; +import { + DEFAULT_AUTHENTICATION_VALUE, + DEFAULT_AUTHORIZATION_VALUE +} from '~/constants/login'; + +export const useAuthStore = defineStore('authStore', () => { + const loginRequest = ref( + cloneDeep(DEFAULT_AUTHENTICATION_VALUE) + ); + + const loginResponse = ref( + cloneDeep(DEFAULT_AUTHORIZATION_VALUE) + ); + + const LoginAPI = async () => { + return await useAxios().post(`/api/login`, loginRequest.value); + }; + + return { + loginRequest, + loginResponse, + LoginAPI + }; +}); \ No newline at end of file diff --git a/nuxt/types/login/index.ts b/nuxt/types/login/index.ts new file mode 100644 index 0000000..0e6eb46 --- /dev/null +++ b/nuxt/types/login/index.ts @@ -0,0 +1,33 @@ +import type { MenuType } from '../sys/menu'; + +export type LoginRequestType = { + memberId: string; + password: string; + remember: boolean; +}; + +export type LoginResponseType = { + memberName: string; + instNm: string; + deptNm: string; + menuList: AuthorizationMenuType[]; + permitApiList: PermitApiType[]; + authenticated: boolean; +}; + +export type AuthorizationMenuType = { + menuId: string; + upMenuId: string; + menuDepth: number; + menuName: string; + menuType: MenuType; + menuUrl: string; + bcId: string; + contentId: string; + + children: AuthorizationMenuType[]; +}; + +export type PermitApiType = { + menuUrl: string; +}; diff --git a/nuxt/types/sys/menu/index.ts b/nuxt/types/sys/menu/index.ts new file mode 100644 index 0000000..a2a91bd --- /dev/null +++ b/nuxt/types/sys/menu/index.ts @@ -0,0 +1,25 @@ +export type MenuType = { + menuId: string; + siteId: string; + upMenuId: string; + menuDepth: number; + menuOrder: number; + menuName: string; + menuType: 'MENU' | 'PAGE' | 'API' | 'TAB' | 'COMMON_MENU' | 'COMMON_API'; + menuFeature: 'PAGE' | 'LIST' | 'DETAIL' | 'CREATE' | 'UPDATE' | 'DELETE'; + menuLayout: string; + menuUrl: string; + menuMethod: string; + menuDescription: string; + menuLinkTarget: 'CURRENT' | 'BLANK'; + menuUseSatisfaction: boolean; + menuUseMngInfo: boolean; + menuMngId: string; + menuStatus: 'ENABLED' | 'HIDDEN' | 'DISABLED'; + delYn: boolean; + useYn: boolean; + frstRgtrId: string; + frstRegDt: string; + lastMdfrId: string; + lastMdfcnDt: string; +};