첫 커밋
This commit is contained in:
commit
1e374d9973
3
56DA6C13A51666386B7D2E61E85EF2E2.txt
Normal file
3
56DA6C13A51666386B7D2E61E85EF2E2.txt
Normal file
@ -0,0 +1,3 @@
|
||||
3799CE17CA15679658F7CAE69B19A8F1EFB13A7E2F138F035CE2F6ECCBD65963
|
||||
sectigo.com
|
||||
dcv20240722dfb99
|
1
allscore/.env
Normal file
1
allscore/.env
Normal file
@ -0,0 +1 @@
|
||||
VITE_APP_API_URL=http://localhost:5001/
|
1
allscore/.env.development
Normal file
1
allscore/.env.development
Normal file
@ -0,0 +1 @@
|
||||
VITE_APP_API_URL=http://localhost:5000/
|
33
allscore/.eslintrc.cjs
Normal file
33
allscore/.eslintrc.cjs
Normal file
@ -0,0 +1,33 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-prettier'
|
||||
],
|
||||
env: {
|
||||
'vue/setup-compiler-macros': true
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module'
|
||||
},
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
singleQuote: true,
|
||||
// semi: true
|
||||
// tabWidth: 4,
|
||||
// trailingComma: 'all',
|
||||
printWidth: 80,
|
||||
bracketSpacing: true,
|
||||
arrowParens: 'avoid',
|
||||
endOfLine: 'auto' // 한줄 추가
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
30
allscore/.gitignore
vendored
Normal file
30
allscore/.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
8
allscore/.prettierrc.json
Normal file
8
allscore/.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
7
allscore/.vscode/extensions.json
vendored
Normal file
7
allscore/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
35
allscore/README.md
Normal file
35
allscore/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# vue3-posts
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
42
allscore/components.d.ts
vendored
Normal file
42
allscore/components.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AboutView: typeof import('./src/views/AboutView.vue')['default']
|
||||
App: typeof import('./src/App.vue')['default']
|
||||
AppAlert: typeof import('./src/components/app/AppAlert.vue')['default']
|
||||
AppCard: typeof import('./src/components/app/AppCard.vue')['default']
|
||||
AppError: typeof import('./src/components/app/AppError.vue')['default']
|
||||
AppGrid: typeof import('./src/components/app/AppGrid.vue')['default']
|
||||
AppLoading: typeof import('./src/components/app/AppLoading.vue')['default']
|
||||
AppModal: typeof import('./src/components/app/AppModal.vue')['default']
|
||||
AppPagination: typeof import('./src/components/app/AppPagination.vue')['default']
|
||||
Card: typeof import('./src/card/Card.vue')['default']
|
||||
CardTest: typeof import('./src/card/CardTest.vue')['default']
|
||||
copy: typeof import('./src/card/Card copy.vue')['default']
|
||||
HomeView: typeof import('./src/views/HomeView.vue')['default']
|
||||
MyPage: typeof import('./src/views/MyPage.vue')['default']
|
||||
NestedHomeView: typeof import('./src/views/nested/NestedHomeView.vue')['default']
|
||||
NestedOneView: typeof import('./src/views/nested/NestedOneView.vue')['default']
|
||||
NestedTwoView: typeof import('./src/views/nested/NestedTwoView.vue')['default']
|
||||
NestedView: typeof import('./src/views/nested/NestedView.vue')['default']
|
||||
NotFoundView: typeof import('./src/views/NotFoundView.vue')['default']
|
||||
PostCreateView: typeof import('./src/views/posts/PostCreateView.vue')['default']
|
||||
PostDetailView: typeof import('./src/views/posts/PostDetailView.vue')['default']
|
||||
PostEditView: typeof import('./src/views/posts/PostEditView.vue')['default']
|
||||
PostFilter: typeof import('./src/components/posts/PostFilter.vue')['default']
|
||||
PostForm: typeof import('./src/components/posts/PostForm.vue')['default']
|
||||
PostItem: typeof import('./src/components/posts/PostItem.vue')['default']
|
||||
PostListView: typeof import('./src/views/posts/PostListView.vue')['default']
|
||||
PostModal: typeof import('./src/components/posts/PostModal.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
TheHeader: typeof import('./src/layouts/TheHeader.vue')['default']
|
||||
TheView: typeof import('./src/layouts/TheView.vue')['default']
|
||||
}
|
||||
}
|
52
allscore/db.json
Normal file
52
allscore/db.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"posts": [
|
||||
{
|
||||
"title": "asdf11@@1",
|
||||
"content": "123ㅋ",
|
||||
"createdAt": 1717335471487,
|
||||
"id": 13
|
||||
},
|
||||
{
|
||||
"title": "제목1",
|
||||
"content": "내용1\n1",
|
||||
"createdAt": 1717336912826,
|
||||
"id": 14
|
||||
},
|
||||
{
|
||||
"title": "제목111",
|
||||
"content": "내용111",
|
||||
"createdAt": 1717339828635,
|
||||
"id": 15
|
||||
},
|
||||
{
|
||||
"title": "123",
|
||||
"content": "12311ㅁ",
|
||||
"createdAt": 1717585818053,
|
||||
"id": 16
|
||||
},
|
||||
{
|
||||
"title": "ㅁㄴㅇㄻㄴㅇㄹ1",
|
||||
"content": "ㅁㄴㅇㄻㄴㅇㄹ2",
|
||||
"createdAt": 1717586219791,
|
||||
"id": 17
|
||||
},
|
||||
{
|
||||
"title": "asdfasdf",
|
||||
"content": "asdfasdfasdf",
|
||||
"createdAt": 1717591306939,
|
||||
"id": 18
|
||||
},
|
||||
{
|
||||
"title": "111111111111",
|
||||
"content": "1222222",
|
||||
"createdAt": 1717591390087,
|
||||
"id": 20
|
||||
},
|
||||
{
|
||||
"title": "운동 나무 위키운동 나무 위키운동 나무 위키운동 나무 위키",
|
||||
"content": "운동 나무 위키운동 나무 위키운동 나무 위키운동 나무 위키",
|
||||
"createdAt": 1718100857725,
|
||||
"id": 21
|
||||
}
|
||||
]
|
||||
}
|
14
allscore/index.html
Normal file
14
allscore/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="modal"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
10
allscore/jsconfig.json
Normal file
10
allscore/jsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"jsx": "preserve",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
4247
allscore/package-lock.json
generated
Normal file
4247
allscore/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
allscore/package.json
Normal file
34
allscore/package.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "vue3-posts",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --port 3000",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/",
|
||||
"db": "json-server --watch db.json --port 5000"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
"bootstrap": "^5.3.3",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"dayjs": "^1.11.11",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "^3.4.21",
|
||||
"vue-router": "^4.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"json-server": "^0.17.4",
|
||||
"prettier": "^3.2.5",
|
||||
"unplugin-vue-components": "^0.27.0",
|
||||
"vite": "^5.2.8"
|
||||
}
|
||||
}
|
BIN
allscore/public/favicon.ico
Normal file
BIN
allscore/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
28
allscore/src/App.vue
Normal file
28
allscore/src/App.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<!-- <script setup>
|
||||
import TheHeader from '@/layouts/TheHeader.vue'
|
||||
import TheView from '@/layouts/TheView.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TheHeader></TheHeader>
|
||||
<TheView></TheView>
|
||||
<AppAlert />
|
||||
</template>
|
||||
|
||||
<style scoped></style> -->
|
||||
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* App.vue에 대한 스타일을 추가할 수 있습니다 */
|
||||
</style>
|
10
allscore/src/api/index.js
Normal file
10
allscore/src/api/index.js
Normal file
@ -0,0 +1,10 @@
|
||||
import axios from 'axios'
|
||||
|
||||
function create(baseURL, options) {
|
||||
const instance = axios.create(Object.assign({ baseURL }, options))
|
||||
return instance
|
||||
}
|
||||
|
||||
export const posts = create(`${import.meta.env.VITE_APP_API_URL}posts/`)
|
||||
// development : http://localhost:5000/posts/
|
||||
// production : http://localhost:5001/posts/
|
25
allscore/src/api/posts.js
Normal file
25
allscore/src/api/posts.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { posts } from '.'
|
||||
|
||||
export function getPosts(params) {
|
||||
return posts.get('/', { params })
|
||||
}
|
||||
|
||||
export function getPostById(id) {
|
||||
return posts.get(`/${id}`)
|
||||
}
|
||||
|
||||
export function createPost(data) {
|
||||
return posts.post('/', data)
|
||||
}
|
||||
|
||||
export function updatePost(id, data) {
|
||||
return posts.patch(`/${id}`, data)
|
||||
}
|
||||
|
||||
// export function updatePost(id, data) {
|
||||
// return posts.put(`/${id}`, data)
|
||||
// }
|
||||
|
||||
export function deletePost(id) {
|
||||
return posts.delete(`/${id}`)
|
||||
}
|
86
allscore/src/assets/base.css
Normal file
86
allscore/src/assets/base.css
Normal file
@ -0,0 +1,86 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family:
|
||||
Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
1
allscore/src/assets/logo.svg
Normal file
1
allscore/src/assets/logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
After Width: | Height: | Size: 276 B |
35
allscore/src/assets/main.css
Normal file
35
allscore/src/assets/main.css
Normal file
@ -0,0 +1,35 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
150
allscore/src/card/Card.vue
Normal file
150
allscore/src/card/Card.vue
Normal file
@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<h1>법인카드1</h1>
|
||||
<h1>사용장부</h1>
|
||||
<div class="form-group">
|
||||
<label for="year">연도</label>
|
||||
<select id="year" v-model="selectedYear" class="form-control">
|
||||
<option v-for="year in years" :key="year" :value="year">
|
||||
{{ year }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="month">월</label>
|
||||
<select id="month" v-model="selectedMonth" class="form-control">
|
||||
<option v-for="month in months" :key="month" :value="month">
|
||||
{{ month }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<button @click="downloadSummary" class="btn btn-primary">통계 다운로드</button>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label>사용자</label>
|
||||
<div v-for="user in users" :key="user.id" class="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="form-check-input"
|
||||
:id="user.id"
|
||||
:value="user.id"
|
||||
v-model="selectedUsers"
|
||||
/>
|
||||
<label :for="user.id" class="form-check-label">{{ user.name }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="amount">사용 금액</label>
|
||||
<input type="number" id="amount" v-model="form.amount" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="purpose">사용 목적</label>
|
||||
<input type="text" id="purpose" v-model="form.purpose" class="form-control" />
|
||||
</div>
|
||||
<button @click="submitForm" class="btn btn-success">제출하기</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: 'https://eldsoft.com:8097/api/card'
|
||||
})
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
amount: '',
|
||||
purpose: ''
|
||||
},
|
||||
selectedUsers: [],
|
||||
selectedYear: new Date().getFullYear(),
|
||||
selectedMonth: new Date().getMonth() + 1,
|
||||
years: Array.from({ length: 10 }, (v, i) => new Date().getFullYear() - i),
|
||||
months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
users: [
|
||||
{ id: 'jang', name: '장진아' },
|
||||
{ id: 'yeo', name: '여정훈' },
|
||||
{ id: 'kim', name: '김지수' },
|
||||
{ id: 'choi', name: '최재혁' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async downloadSummary() {
|
||||
const payload_excel = {
|
||||
year: this.selectedYear,
|
||||
month: this.selectedMonth
|
||||
}
|
||||
|
||||
console.log('Download Payload:', payload_excel)
|
||||
|
||||
try {
|
||||
const response = await axiosInstance.post('/excel', payload_excel, {
|
||||
responseType: 'blob'
|
||||
})
|
||||
|
||||
if (response.data.size === 0) {
|
||||
alert('해당월에 데이터가 없습니다')
|
||||
return
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(
|
||||
new Blob([response.data], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
})
|
||||
)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute('download', 'summary.xlsx')
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
} catch (error) {
|
||||
console.error('There was an error downloading the file!', error)
|
||||
alert('An error occurred while downloading the file.')
|
||||
}
|
||||
},
|
||||
async submitForm() {
|
||||
const payload_regist = {
|
||||
jang: this.selectedUsers.includes('jang') ? 'Y' : 'N',
|
||||
yeo: this.selectedUsers.includes('yeo') ? 'Y' : 'N',
|
||||
kim: this.selectedUsers.includes('kim') ? 'Y' : 'N',
|
||||
choi: this.selectedUsers.includes('choi') ? 'Y' : 'N',
|
||||
amount: this.form.amount,
|
||||
purpose: this.form.purpose
|
||||
}
|
||||
|
||||
console.log('Request Payload:', payload_regist)
|
||||
|
||||
try {
|
||||
const response = await axiosInstance.post('/regist', payload_regist)
|
||||
alert('Registration successful')
|
||||
console.log('Response Data:', response.data)
|
||||
} catch (error) {
|
||||
console.error('There was an error!', error)
|
||||
alert('An error occurred: Server error')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.btn {
|
||||
margin-top: 20px;
|
||||
}
|
||||
hr {
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
115
allscore/src/card/CardTest.vue
Normal file
115
allscore/src/card/CardTest.vue
Normal file
@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<nav class="navbar">
|
||||
<div class="logo">
|
||||
<img src="@/assets/logo.svg" alt="Logo" />
|
||||
</div>
|
||||
<ul class="nav-links">
|
||||
<li><a href="#">공지사항</a></li>
|
||||
</ul>
|
||||
<div class="auth-buttons">
|
||||
<button @click="login">로그인</button>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="content">
|
||||
<div class="main-title">법인카드 사용장부</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
export default {
|
||||
name: 'App',
|
||||
methods: {
|
||||
login() {
|
||||
console.log('로그인 버튼 클릭됨')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 20px;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
list-style: none;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%; /* 부모 높이만큼 높이 설정 */
|
||||
}
|
||||
|
||||
.nav-links li {
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
align-items: center; /* 수직 중앙 정렬 */
|
||||
height: 100%; /* 부모 높이만큼 높이 설정 */
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.auth-buttons {
|
||||
display: flex;
|
||||
align-items: center; /* 수직 중앙 정렬 */
|
||||
}
|
||||
|
||||
.auth-buttons button {
|
||||
background-color: #ff6600;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.auth-buttons button:hover {
|
||||
background-color: #e65c00;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center; /* 수평 중앙 정렬 */
|
||||
align-items: flex-start; /* 상단 정렬 */
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-top: 70px;
|
||||
width: 1000px; /* 원하는 고정 너비 */
|
||||
text-align: center; /* 내부 콘텐츠의 수평 중앙 정렬 */
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 1000px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
44
allscore/src/components/app/AppAlert.vue
Normal file
44
allscore/src/components/app/AppAlert.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="app-alert">
|
||||
<TransitionGroup name="slide">
|
||||
<div
|
||||
v-for="({ message, type }, index) in alerts"
|
||||
:key="index"
|
||||
class="alert"
|
||||
:class="typeStyle(type)"
|
||||
role="alert"
|
||||
>
|
||||
{{ message }}
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useAlert } from '@/composables/alert'
|
||||
const { alerts } = useAlert()
|
||||
const typeStyle = (type) => (type === 'error' ? 'alert-danger' : 'alert-primary')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-alert {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.slide-enter-from,
|
||||
.slide-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
.slide-enter-active,
|
||||
.vslide-leave-active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
.slide-enter-to,
|
||||
.slide-leave-from {
|
||||
transform: translateY(0px);
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
13
allscore/src/components/app/AppCard.vue
Normal file
13
allscore/src/components/app/AppCard.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div v-if="$slots.header" class="card-header">
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
<div v-if="$slots.default" class="card-body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div v-if="$slots.footer" class="card-footer">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
13
allscore/src/components/app/AppError.vue
Normal file
13
allscore/src/components/app/AppError.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div class="text-center text-danger py-4">
|
||||
{{ message }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
message: String
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
22
allscore/src/components/app/AppGrid.vue
Normal file
22
allscore/src/components/app/AppGrid.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div class="row g-3">
|
||||
<div v-for="(item, index) in items" :key="index" :class="colClass">
|
||||
<slot :item="item" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
colClass: {
|
||||
type: String,
|
||||
default: 'col-4'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
7
allscore/src/components/app/AppLoading.vue
Normal file
7
allscore/src/components/app/AppLoading.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
61
allscore/src/components/app/AppModal.vue
Normal file
61
allscore/src/components/app/AppModal.vue
Normal file
@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<Transition>
|
||||
<div v-if="modelValue">
|
||||
<div class="modal-backdrop fade show"></div>
|
||||
<div
|
||||
class="modal fade show d-block"
|
||||
tabindex="-1"
|
||||
aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<slot name="header">
|
||||
<h1 class="modal-title fs-5" id="exampleModalLabel">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
@click="$emit('update:modelValue', false)"
|
||||
></button>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<slot name="actions"> </slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
modelValue: Boolean,
|
||||
title: String
|
||||
})
|
||||
defineEmits(['close', 'update:modelValue'])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-enter-from,
|
||||
.v-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.v-enter-active,
|
||||
.v-leave-active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
.v-enter-to,
|
||||
.v-leave-from {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
58
allscore/src/components/app/AppPagination.vue
Normal file
58
allscore/src/components/app/AppPagination.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<nav class="mt-5" aria-label="Page navigation example">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item" :class="isPrevPage">
|
||||
<a
|
||||
class="page-link"
|
||||
href="#"
|
||||
aria-label="Previous"
|
||||
@click.prevent="$emit('page', currentPage - 1)"
|
||||
>
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
v-for="page in pageCount"
|
||||
:key="page"
|
||||
class="page-item"
|
||||
:class="{ active: currentPage === page }"
|
||||
>
|
||||
<a class="page-link" href="#" @click.prevent="$emit('page', page)">{{
|
||||
page
|
||||
}}</a>
|
||||
</li>
|
||||
<li class="page-item" :class="isNextPage">
|
||||
<a
|
||||
class="page-link"
|
||||
href="#"
|
||||
aria-label="Next"
|
||||
@click.prevent="$emit('page', currentPage + 1)"
|
||||
>
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
currentPage: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
pageCount: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
defineEmits(['page'])
|
||||
const isPrevPage = computed(() => ({ disabled: !(props.currentPage > 1) }))
|
||||
const isNextPage = computed(() => ({
|
||||
disabled: !(props.currentPage < props.pageCount)
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
41
allscore/src/components/posts/PostFilter.vue
Normal file
41
allscore/src/components/posts/PostFilter.vue
Normal file
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<form @submit.prevent>
|
||||
<div class="row g-3">
|
||||
<div class="col">
|
||||
<input
|
||||
:value="title"
|
||||
@input="changeTitle"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="제목으로 검색해주세요."
|
||||
/>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<select
|
||||
:value="limit"
|
||||
@input="$emit('update:limit', $event.target.value)"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="6">6개씩 보기</option>
|
||||
<option value="12">12개씩 보기</option>
|
||||
<option value="18">18개씩 보기</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
title: String,
|
||||
limit: Number
|
||||
})
|
||||
const emits = defineEmits(['update:title', 'update:limit'])
|
||||
const changeTitle = (event) => {
|
||||
setTimeout(() => {
|
||||
emits('update:title', event.target.value)
|
||||
}, 500)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
45
allscore/src/components/posts/PostForm.vue
Normal file
45
allscore/src/components/posts/PostForm.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">제목</label>
|
||||
<input
|
||||
v-focus
|
||||
v-color="'red'"
|
||||
:value="title"
|
||||
@input="$emit('update:title', $event.target.value)"
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="title"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="contents" class="form-label">내용</label>
|
||||
<textarea
|
||||
:value="content"
|
||||
@input="$emit('update:content', $event.target.value)"
|
||||
class="form-control"
|
||||
id="contents"
|
||||
rows="3"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="d-flex gap-2 mt-4">
|
||||
<slot name="actions"></slot>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const vFocus = {
|
||||
mounted: el => {
|
||||
el.focus()
|
||||
}
|
||||
}
|
||||
|
||||
defineProps({
|
||||
title: String,
|
||||
content: String
|
||||
})
|
||||
defineEmits(['update:title', 'update:content'])
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
41
allscore/src/components/posts/PostItem.vue
Normal file
41
allscore/src/components/posts/PostItem.vue
Normal file
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<AppCard>
|
||||
<h5 class="card-title text-truncate">{{ title }}</h5>
|
||||
<p class="card-text text-truncate">
|
||||
{{ content }}
|
||||
</p>
|
||||
<p class="text-muted">{{ createdDate }}</p>
|
||||
<template #footer>
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<button class="btn p-1" @click.stop="$emit('modal')">
|
||||
<i class="bi bi-emoji-sunglasses"></i>
|
||||
</button>
|
||||
<button class="btn p-1" @click.stop="$emit('preview')">
|
||||
<i class="bi bi-airplane"></i>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</AppCard>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, inject } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
content: {
|
||||
type: String
|
||||
},
|
||||
createdAt: {
|
||||
type: [String, Date, Number]
|
||||
}
|
||||
})
|
||||
defineEmits(['modal', 'preview'])
|
||||
const dayjs = inject('dayjs')
|
||||
const createdDate = computed(() => dayjs(props.createdAt).format('YYYY. MM. DD HH:mm:ss'))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
45
allscore/src/components/posts/PostModal.vue
Normal file
45
allscore/src/components/posts/PostModal.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<AppModal v-model="show" title="게시글">
|
||||
<template #default>
|
||||
<div class="row g-3">
|
||||
<div class="col-3 text-muted">제목</div>
|
||||
<div class="col-9">{{ title }}</div>
|
||||
<div class="col-3 text-muted">내용</div>
|
||||
<div class="col-9">{{ content }}</div>
|
||||
<div class="col-3 text-muted">등록일</div>
|
||||
<div class="col-9">
|
||||
{{ $dayjs(createdAt).format('YYYY. MM. DD HH:mm:ss') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions>
|
||||
<button type="button" class="btn btn-secondary" @click="closeModal">
|
||||
닫기
|
||||
</button>
|
||||
</template>
|
||||
</AppModal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
title: String,
|
||||
content: String,
|
||||
createdAt: [String, Number]
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const show = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
const closeModal = () => (show.value = false)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
13
allscore/src/composables/alert.js
Normal file
13
allscore/src/composables/alert.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { useAlertStore } from '@/stores/alert'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
export function useAlert() {
|
||||
const { alerts } = storeToRefs(useAlertStore())
|
||||
const { vAlert, vSuccess } = useAlertStore()
|
||||
|
||||
return {
|
||||
alerts,
|
||||
vAlert,
|
||||
vSuccess
|
||||
}
|
||||
}
|
11
allscore/src/composables/number.js
Normal file
11
allscore/src/composables/number.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { computed, unref } from 'vue'
|
||||
|
||||
export const useNumber = (number) => {
|
||||
const isOdd = computed(() => unref(number) % 2 === 1)
|
||||
const isEven = computed(() => !isOdd.value)
|
||||
|
||||
return {
|
||||
isOdd,
|
||||
isEven
|
||||
}
|
||||
}
|
5
allscore/src/directives/color.js
Normal file
5
allscore/src/directives/color.js
Normal file
@ -0,0 +1,5 @@
|
||||
function color(el, binding) {
|
||||
el.style.color = binding.value
|
||||
}
|
||||
|
||||
export default color
|
5
allscore/src/directives/focus.js
Normal file
5
allscore/src/directives/focus.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
mounted: el => {
|
||||
el.focus()
|
||||
}
|
||||
}
|
0
allscore/src/hooks/alert.js
Normal file
0
allscore/src/hooks/alert.js
Normal file
0
allscore/src/hooks/useAlert.js
Normal file
0
allscore/src/hooks/useAlert.js
Normal file
66
allscore/src/hooks/useAxios.js
Normal file
66
allscore/src/hooks/useAxios.js
Normal file
@ -0,0 +1,66 @@
|
||||
import axios from 'axios'
|
||||
import { isRef, ref, unref, watchEffect } from 'vue'
|
||||
|
||||
axios.defaults.baseURL = import.meta.env.VITE_APP_API_URL
|
||||
|
||||
const defaultConfig = {
|
||||
method: 'get'
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
immediate: true
|
||||
}
|
||||
|
||||
export const useAxios = (url, config = {}, options = {}) => {
|
||||
const response = ref(null)
|
||||
const data = ref(null)
|
||||
const error = ref(null)
|
||||
const loading = ref(false)
|
||||
|
||||
const { onSuccess, onError, immediate } = { ...defaultOptions, ...options }
|
||||
|
||||
const { params } = config
|
||||
const execute = (body) => {
|
||||
data.value = null
|
||||
error.value = null
|
||||
loading.value = true
|
||||
axios(unref(url), {
|
||||
...defaultConfig,
|
||||
...config,
|
||||
params: unref(params),
|
||||
data: typeof body === 'object' ? body : {}
|
||||
})
|
||||
.then((res) => {
|
||||
response.value = res
|
||||
data.value = res.data
|
||||
if (onSuccess) {
|
||||
onSuccess(res)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
error.value = err
|
||||
if (onError) {
|
||||
onError(err)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
if (isRef(params) || isRef(url)) {
|
||||
watchEffect(execute)
|
||||
} else {
|
||||
if (immediate) {
|
||||
execute()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
response,
|
||||
data,
|
||||
error,
|
||||
loading,
|
||||
execute
|
||||
}
|
||||
}
|
55
allscore/src/layouts/TheHeader.vue
Normal file
55
allscore/src/layouts/TheHeader.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-dark bg-primary">
|
||||
<div class="container-fluid">
|
||||
<RouterLink class="navbar-brand" to="/">ELD</RouterLink>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<RouterLink class="nav-link" active-class="active" to="/">Home</RouterLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<RouterLink class="nav-link" active-class="active" to="/about">about</RouterLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<RouterLink class="nav-link" active-class="active" to="/posts">게시글</RouterLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<RouterLink class="nav-link" active-class="active" to="/Nested">Nested</RouterLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<RouterLink class="nav-link" active-class="active" to="/my">MyPage</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="d-flex" role="search">
|
||||
<button class="btn btn-outline-light" type="button" @click="goPage">글쓰기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const goPage = () => {
|
||||
router.push({
|
||||
name: 'PostCreate'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
11
allscore/src/layouts/TheView.vue
Normal file
11
allscore/src/layouts/TheView.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<main>
|
||||
<div class="container py-4">
|
||||
<RouterView></RouterView>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
45
allscore/src/main.js
Normal file
45
allscore/src/main.js
Normal file
@ -0,0 +1,45 @@
|
||||
// import './assets/main.css'
|
||||
// import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
// import 'bootstrap-icons/font/bootstrap-icons.css'
|
||||
|
||||
// import { createApp } from 'vue'
|
||||
// import App from './App.vue'
|
||||
// import { createPinia } from 'pinia'
|
||||
|
||||
// import router from '@/router'
|
||||
// import globalComponents from './plugins/global-components'
|
||||
// import globalDirectives from './plugins/global-directives'
|
||||
// import dayjs from './plugins/dayjs'
|
||||
|
||||
// const app = createApp(App)
|
||||
// // app.directive('focus', focus)
|
||||
// app.use(dayjs)
|
||||
// app.use(globalDirectives)
|
||||
// app.use(router)
|
||||
// app.use(globalComponents)
|
||||
// app.use(createPinia())
|
||||
// app.mount('#app')
|
||||
// import 'bootstrap/dist/js/bootstrap.js'
|
||||
|
||||
import './assets/main.css'
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import 'bootstrap-icons/font/bootstrap-icons.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
import router from '@/router' // 라우터 임포트 다시 활성화
|
||||
import globalComponents from './plugins/global-components'
|
||||
import globalDirectives from './plugins/global-directives'
|
||||
import dayjs from './plugins/dayjs'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(dayjs)
|
||||
app.use(globalDirectives)
|
||||
app.use(router) // 라우터 사용
|
||||
app.use(globalComponents)
|
||||
app.use(createPinia())
|
||||
app.mount('#app')
|
||||
|
||||
import 'bootstrap/dist/js/bootstrap.js'
|
8
allscore/src/plugins/dayjs.js
Normal file
8
allscore/src/plugins/dayjs.js
Normal file
@ -0,0 +1,8 @@
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
app.config.globalProperties.$dayjs = dayjs
|
||||
app.provide('dayjs', dayjs)
|
||||
}
|
||||
}
|
5
allscore/src/plugins/func.js
Normal file
5
allscore/src/plugins/func.js
Normal file
@ -0,0 +1,5 @@
|
||||
function funcPlugins(app, options) {
|
||||
console.log('funcPlugins')
|
||||
}
|
||||
|
||||
export default funcPlugins
|
15
allscore/src/plugins/global-components.js
Normal file
15
allscore/src/plugins/global-components.js
Normal file
@ -0,0 +1,15 @@
|
||||
import AppAlert from '@/components/app/AppAlert.vue'
|
||||
import AppCard from '@/components/app/AppCard.vue'
|
||||
import AppModal from '@/components/app/AppModal.vue'
|
||||
import AppGrid from '@/components/app/AppGrid.vue'
|
||||
import AppPagination from '@/components/app/AppPagination.vue'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
app.component('AppAlert', AppAlert)
|
||||
app.component('AppCard', AppCard)
|
||||
app.component('AppModal', AppModal)
|
||||
app.component('AppGrid', AppGrid)
|
||||
app.component('AppPagination', AppPagination)
|
||||
}
|
||||
}
|
9
allscore/src/plugins/global-directives.js
Normal file
9
allscore/src/plugins/global-directives.js
Normal file
@ -0,0 +1,9 @@
|
||||
import focus from '@/directives/focus'
|
||||
import color from '@/directives/color.js'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
app.directive('focus', focus)
|
||||
app.directive('color', color)
|
||||
}
|
||||
}
|
12
allscore/src/plugins/obj.js
Normal file
12
allscore/src/plugins/obj.js
Normal file
@ -0,0 +1,12 @@
|
||||
const objPlugins = {
|
||||
install(app, options) {
|
||||
console.log('objPlugins app: ', app)
|
||||
console.log('objPlugins options: ', options)
|
||||
// app.component() 전역 컴포넌트
|
||||
// app.config.globalProperies 전역 애플리케이션 인스턴스에 속성 추가
|
||||
// app.directive 커스텀 디렉티브
|
||||
// app.provide 리소스
|
||||
}
|
||||
}
|
||||
|
||||
export default objPlugins
|
13
allscore/src/plugins/person.js
Normal file
13
allscore/src/plugins/person.js
Normal file
@ -0,0 +1,13 @@
|
||||
export default {
|
||||
install(app, options) {
|
||||
const person = {
|
||||
name: '짐코딩',
|
||||
say() {
|
||||
alert(this.name)
|
||||
},
|
||||
...options
|
||||
}
|
||||
app.config.globalProperties.$person = person
|
||||
app.provide('person', person)
|
||||
}
|
||||
}
|
130
allscore/src/router/index.js
Normal file
130
allscore/src/router/index.js
Normal file
@ -0,0 +1,130 @@
|
||||
// import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
|
||||
|
||||
// import HomeView from '@/views/HomeView.vue'
|
||||
// import AboutView from '@/views/AboutView.vue'
|
||||
// import PostCreateView from '@/views/posts/PostCreateView.vue'
|
||||
// import PostDetailView from '@/views/posts/PostDetailView.vue'
|
||||
// import PostEditView from '@/views/posts/PostEditView.vue'
|
||||
// import PostListView from '@/views/posts/PostListView.vue'
|
||||
// import NotFoundView from '@/views/NotFoundView.vue'
|
||||
// import NestedView from '@/views/nested/NestedView.vue'
|
||||
// import NestedOneView from '@/views/nested/NestedOneView.vue'
|
||||
// import NestedTwoView from '@/views/nested/NestedTwoView.vue'
|
||||
// import NestedHomeView from '@/views/nested/NestedHomeView.vue'
|
||||
// import MyPage from '@/views/MyPage.vue'
|
||||
|
||||
// const routes = [
|
||||
// {
|
||||
// path: '/',
|
||||
// name: 'home',
|
||||
// component: HomeView
|
||||
// },
|
||||
// {
|
||||
// path: '/about',
|
||||
// name: 'about',
|
||||
// component: AboutView
|
||||
// },
|
||||
// {
|
||||
// path: '/posts',
|
||||
// name: 'PostList',
|
||||
// component: PostListView
|
||||
// },
|
||||
// {
|
||||
// path: '/posts/create',
|
||||
// name: 'PostCreate',
|
||||
// component: PostCreateView
|
||||
// },
|
||||
// {
|
||||
// path: '/posts/:id',
|
||||
// name: 'PostDetail',
|
||||
// component: PostDetailView,
|
||||
// props: true
|
||||
// // props: (route) => ({ id: parseInt(route.params.id) })
|
||||
// },
|
||||
// {
|
||||
// path: '/posts/:id/edit',
|
||||
// name: 'PostEdit',
|
||||
// component: PostEditView
|
||||
// },
|
||||
// { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFoundView },
|
||||
// {
|
||||
// path: '/nested',
|
||||
// name: 'Nested',
|
||||
// component: NestedView,
|
||||
// children: [
|
||||
// {
|
||||
// path: '',
|
||||
// name: 'NestedHome',
|
||||
// component: NestedHomeView
|
||||
// },
|
||||
// {
|
||||
// path: 'one',
|
||||
// name: 'NestedOne',
|
||||
// component: NestedOneView
|
||||
// },
|
||||
// {
|
||||
// path: 'two',
|
||||
// name: 'NestedTwo',
|
||||
// component: NestedTwoView
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/my',
|
||||
// name: 'MyPage',
|
||||
// component: MyPage,
|
||||
// beforeEnter: [removeQueryString]
|
||||
// // console.log('to: ', to)
|
||||
// // console.log('from: ', from)
|
||||
// // return false
|
||||
// // return { name: 'home' }
|
||||
// }
|
||||
// ]
|
||||
|
||||
// function removeQueryString(to) {
|
||||
// if (Object.keys(to.query).length > 0) {
|
||||
// return { path: to.path, query: {} }
|
||||
// }
|
||||
// }
|
||||
|
||||
// const router = createRouter({
|
||||
// history: createWebHistory(),
|
||||
// // history: createWebHashHistory('/base'),
|
||||
// routes
|
||||
// })
|
||||
|
||||
// // router.beforeEach((to, from) => {
|
||||
// // console.log('to: ', to)
|
||||
// // console.log('from: ', from)
|
||||
// // if (to.name === 'MyPage') {
|
||||
// // // return false
|
||||
// // // return { name: 'home' }
|
||||
// // return '/posts'
|
||||
// // }
|
||||
// // })
|
||||
|
||||
// export default router
|
||||
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import Card from '@/card/Card.vue'
|
||||
import CardTest from '@/card/CardTest.vue'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Card',
|
||||
component: Card
|
||||
},
|
||||
{
|
||||
path: '/test',
|
||||
name: 'CardTest',
|
||||
component: CardTest
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory('/'), // process.env.BASE_URL 대신 '/' 사용
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
18
allscore/src/stores/alert.js
Normal file
18
allscore/src/stores/alert.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useAlertStore = defineStore('alert', {
|
||||
state: () => ({
|
||||
alerts: []
|
||||
}),
|
||||
actions: {
|
||||
vAlert(message, type = 'error') {
|
||||
this.alerts.push({ message, type })
|
||||
setTimeout(() => {
|
||||
this.alerts.shift()
|
||||
}, 2000)
|
||||
},
|
||||
vSuccess(message) {
|
||||
this.vAlert(message, 'success')
|
||||
}
|
||||
}
|
||||
})
|
18
allscore/src/stores/counter.js
Normal file
18
allscore/src/stores/counter.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useCounterStore = defineStore('counter', {
|
||||
state: () => ({
|
||||
counter: 1
|
||||
}),
|
||||
getters: {
|
||||
doubleCount: (state) => state.counter * 2,
|
||||
doubleCountPlusOne() {
|
||||
return this.doubleCount + 1
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
increment() {
|
||||
this.counter++
|
||||
}
|
||||
}
|
||||
})
|
29
allscore/src/views/AboutView.vue
Normal file
29
allscore/src/views/AboutView.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>About View</h2>
|
||||
<p>{{ $route.path }}</p>
|
||||
<p>{{ $route.name }}</p>
|
||||
<button class="btn btn-primary" @click="$router.push('/')">Home으로 이동</button>
|
||||
<h2>Store</h2>
|
||||
<p>counter: {{ counter }}</p>
|
||||
<p>doubleCount: {{ doubleCount }}</p>
|
||||
<p>doubleCount: {{ doubleCountPlusOne }}</p>
|
||||
<button @click="increment()">Click!</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useCounterStore } from '@/stores/counter'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const route = useRoute()
|
||||
console.log('route.pathe:, ', route.path)
|
||||
|
||||
const store = useCounterStore()
|
||||
|
||||
const { counter, doubleCount, doubleCountPlusOne } = storeToRefs(store)
|
||||
const { increment } = store
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
50
allscore/src/views/HomeView.vue
Normal file
50
allscore/src/views/HomeView.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>Home View</h2>
|
||||
<p>{{ $route.path }}</p>
|
||||
<p>{{ $route.name }}</p>
|
||||
<button class="btn btn-primary" @click="goAboutPage">About으로 이동</button>
|
||||
<hr class="my-4" />
|
||||
<AppGrid :items="items" v-slot="{ item }" col-class="col-6">
|
||||
<AppCard>{{ item }}</AppCard>
|
||||
</AppGrid>
|
||||
<hr class="my-4" />
|
||||
<!-- <h2>{{ $person.name }}</h2>
|
||||
<button class="btn btn-primary" @click="person.say">click person</button> -->
|
||||
<h2>{{ position }}</h2>
|
||||
<h2>x: {{ x }} y: {{ y }}</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
created() {
|
||||
// console.log(this.$person.name)
|
||||
// this.$person.say()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, toRef, toRefs } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const goAboutPage = () => {
|
||||
router.push('/about')
|
||||
}
|
||||
|
||||
const items = ref(['사과', '딸기', '포토', '바나나'])
|
||||
|
||||
// const person = inject('person')
|
||||
// console.log('person.name: ', person.name)
|
||||
const position = reactive({
|
||||
x: 100,
|
||||
y: 1000
|
||||
})
|
||||
// const x = toRef(position, 'x')
|
||||
// const y = toRef(position, 'y')
|
||||
const { x, y } = toRefs(position)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
10
allscore/src/views/MyPage.vue
Normal file
10
allscore/src/views/MyPage.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>MyPage</h2>
|
||||
<hr />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
17
allscore/src/views/NotFoundView.vue
Normal file
17
allscore/src/views/NotFoundView.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<div class="text-center py-5">
|
||||
<h1>Oops!</h1>
|
||||
<h2>404 Not Found</h2>
|
||||
<div class="text-muted">요청한 페이지를 찾을 수 없습니다!</div>
|
||||
<!-- {{ $route.params.pathMatch }} -->
|
||||
<div class="mt-4">
|
||||
<RouterLink to="/">
|
||||
<button class="btn btn-primary">Home</button>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
12
allscore/src/views/nested/NestedHomeView.vue
Normal file
12
allscore/src/views/nested/NestedHomeView.vue
Normal file
@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-header">Nested Home</div>
|
||||
<div class="card-body">
|
||||
<h1 class="card-title">Nested routes home...</h1>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
16
allscore/src/views/nested/NestedOneView.vue
Normal file
16
allscore/src/views/nested/NestedOneView.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-header">Nested One</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Special title treatment</h5>
|
||||
<p class="card-text">
|
||||
With supporting text below as a natural lead-in to additional content.
|
||||
</p>
|
||||
<a href="#" class="btn btn-danger">Go somewhere</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
16
allscore/src/views/nested/NestedTwoView.vue
Normal file
16
allscore/src/views/nested/NestedTwoView.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-header">Nested Two</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Special title treatment</h5>
|
||||
<p class="card-text">
|
||||
With supporting text below as a natural lead-in to additional content.
|
||||
</p>
|
||||
<a href="#" class="btn btn-warning">Go somewhere</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
30
allscore/src/views/nested/NestedView.vue
Normal file
30
allscore/src/views/nested/NestedView.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<ul class="nav nav-pills">
|
||||
<li class="nav-item">
|
||||
<RouterLink
|
||||
class="nav-link"
|
||||
active-class="active"
|
||||
:to="{ name: 'NestedOne', replace: true }"
|
||||
>
|
||||
Nested One
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<RouterLink
|
||||
class="nav-link"
|
||||
active-class="active"
|
||||
:to="{ name: 'NestedTwo', replace: true }"
|
||||
>
|
||||
Nested Two
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<RouterView></RouterView>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
88
allscore/src/views/posts/PostCreateView.vue
Normal file
88
allscore/src/views/posts/PostCreateView.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2 @click="visibleForm = !visibleForm">게시글 등록</h2>
|
||||
<hr class="my-4" />
|
||||
<AppError v-if="error" :message="error.message" />
|
||||
<PostForm
|
||||
v-if="visibleForm"
|
||||
v-model:title="form.title"
|
||||
v-model:content="form.content"
|
||||
@submit.prevent="save"
|
||||
>
|
||||
<template #actions>
|
||||
<button type="button" class="btn btn-outline-dark me-2" @click="goListPage">목록</button>
|
||||
<button class="btn btn-primary" :disabled="loading">
|
||||
<template v-if="loading">
|
||||
<span class="spinner-grow spinner-grow-sm" aria-hidden="true"></span>
|
||||
<span class="visually-hidden" role="status">Loading...</span>
|
||||
</template>
|
||||
<template v-else> 저장 </template>
|
||||
</button>
|
||||
</template>
|
||||
</PostForm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { createPost } from '@/api/posts'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import PostForm from '@/components/posts/PostForm.vue'
|
||||
import { useAlert } from '@/composables/alert'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
|
||||
const { vAlert, vSuccess } = useAlert()
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const form = ref({
|
||||
title: null,
|
||||
content: null
|
||||
})
|
||||
|
||||
const { error, loading, execute } = useAxios(
|
||||
'/posts',
|
||||
{
|
||||
method: 'post'
|
||||
},
|
||||
{
|
||||
immediate: false,
|
||||
onSuccess: () => {
|
||||
router.push({ name: 'PostList' })
|
||||
vSuccess('등록이 완료되었습니다.')
|
||||
},
|
||||
onError: (err) => {
|
||||
vAlert(err.message)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const save = async () => {
|
||||
execute({ ...form.value, createdAt: Date.now() })
|
||||
}
|
||||
|
||||
// const save = async () => {
|
||||
// try {
|
||||
// loading.value = true
|
||||
// await createPost({
|
||||
// ...form.value,
|
||||
// createdAt: Date.now()
|
||||
// })
|
||||
// router.push({ name: 'PostList' })
|
||||
// vSuccess('등록이 완료되었습니다.')
|
||||
// } catch (err) {
|
||||
// vAlert(err.message)
|
||||
// error.value = err
|
||||
// } finally {
|
||||
// loading.value = false
|
||||
// }
|
||||
// }
|
||||
|
||||
// const id = route.params.id
|
||||
|
||||
const goListPage = () => router.push({ name: 'PostList' })
|
||||
const visibleForm = ref(true)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
114
allscore/src/views/posts/PostDetailView.vue
Normal file
114
allscore/src/views/posts/PostDetailView.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<AppLoading v-if="loading" />
|
||||
<AppError v-else-if="error" :message="error.message" />
|
||||
<div v-else>
|
||||
<h2>{{ post.title }}</h2>
|
||||
<p>id: {{ props.id }}, isOdd: {{ isOdd }}</p>
|
||||
<p>{{ post.content }}</p>
|
||||
<p class="text-muted">
|
||||
{{ $dayjs(post.createdAt).format('YYYY. MM. DD HH:mm:ss') }}
|
||||
</p>
|
||||
<hr class="my-4" />
|
||||
<AppError v-if="removeError" :message="removeError.message" />
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-outline-dark" @click="$router.push('/posts/18')">이전글</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-outline-dark" @click="$router.push('/posts/20')">다음글</button>
|
||||
</div>
|
||||
<div class="col-auto me-auto"></div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-outline-dark" @click="gotListPage">목록</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-outline-primary" @click="goEditPage">수정</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-outline-danger" @click="remove" :disabled="removeLoading">
|
||||
<template v-if="removeLoading">
|
||||
<span class="spinner-grow spinner-grow-sm" aria-hidden="true"></span>
|
||||
<span class="visually-hidden" role="status">Loading...</span>
|
||||
</template>
|
||||
<template v-else> 삭제 </template>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import { deletePost } from '@/api/posts'
|
||||
import { computed, ref, toRef, toRefs } from 'vue'
|
||||
import { useAlert } from '@/composables/alert'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useNumber } from '@/composables/number'
|
||||
|
||||
const { vAlert, vSuccess } = useAlert()
|
||||
|
||||
const props = defineProps({
|
||||
id: [String, Number]
|
||||
})
|
||||
|
||||
// const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { id: idref } = toRefs(props)
|
||||
const { isOdd } = useNumber(idref)
|
||||
|
||||
// const id = route.params.id
|
||||
const url = computed(() => `/posts/${props.id}`)
|
||||
const { data: post, error, loading } = useAxios(url)
|
||||
|
||||
const {
|
||||
error: removeError,
|
||||
loading: removeLoading,
|
||||
execute
|
||||
} = useAxios(
|
||||
`/posts/${props.id}`,
|
||||
{ method: 'delete' },
|
||||
{
|
||||
immediate: false,
|
||||
onSuccess: () => {
|
||||
vSuccess('삭제가 완료되었습니다.')
|
||||
router.push({ name: 'PostList' })
|
||||
},
|
||||
onError: (err) => {
|
||||
vAlert(err.message)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const remove = async () => {
|
||||
if (confirm('삭제 하시겠습니까?') === false) {
|
||||
return
|
||||
}
|
||||
execute()
|
||||
}
|
||||
|
||||
const gotListPage = () => {
|
||||
router.push({ name: 'PostList' })
|
||||
}
|
||||
const goEditPage = () => {
|
||||
router.push({
|
||||
name: 'PostEdit',
|
||||
params: { id: props.id }
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(() => {
|
||||
console.log('onBeforeRouteUpdate')
|
||||
})
|
||||
onBeforeRouteLeave(() => {
|
||||
console.log('onBeforeRouteLeave')
|
||||
})
|
||||
</script>
|
||||
<script>
|
||||
export default {
|
||||
beforeRouteEnter() {
|
||||
console.log('beforeRouteEnter')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
69
allscore/src/views/posts/PostEditView.vue
Normal file
69
allscore/src/views/posts/PostEditView.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<AppLoading v-if="loading" />
|
||||
<AppError v-else-if="error" :message="error.message" />
|
||||
<div v-else>
|
||||
<h2>게시글 수정</h2>
|
||||
<hr class="my-4" />
|
||||
<AppError v-if="editError" :message="editError.message" />
|
||||
<PostForm v-model:title="form.title" v-model:content="form.content" @submit.prevent="edit">
|
||||
<template #actions>
|
||||
<button type="button" class="btn btn-outline-danger" @click="goDetailPage">취소</button>
|
||||
<button class="btn btn-primary" :disabled="editLoading">
|
||||
<template v-if="editLoading">
|
||||
<span class="spinner-grow spinner-grow-sm" aria-hidden="true"></span>
|
||||
<span class="visually-hidden" role="status">Loading...</span>
|
||||
</template>
|
||||
<template v-else> 수정 </template>
|
||||
</button>
|
||||
</template>
|
||||
</PostForm>
|
||||
<!-- <AppAlert :show="showAlert" :message="alertMessage" :type="alertType" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { getPostById, updatePost } from '@/api/posts'
|
||||
import PostForm from '@/components/posts/PostForm.vue'
|
||||
import { useAlert } from '@/composables/alert'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
|
||||
const { vAlert, vSuccess } = useAlert()
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const id = route.params.id
|
||||
|
||||
const { data: form, error, loading } = useAxios(`/posts/${id}`)
|
||||
|
||||
const {
|
||||
error: editError,
|
||||
loading: editLoading,
|
||||
execute
|
||||
} = useAxios(
|
||||
`/posts/${id}`,
|
||||
{ method: 'patch' },
|
||||
{
|
||||
immediate: false,
|
||||
onSuccess: () => {
|
||||
vSuccess('수정이 완료되었습니다!', 'success')
|
||||
router.push({ name: 'PostDetail', params: { id } })
|
||||
},
|
||||
onError: (err) => {
|
||||
vAlert(err.message)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const edit = () => {
|
||||
execute({
|
||||
...form.value
|
||||
})
|
||||
}
|
||||
|
||||
const goDetailPage = () => router.push({ name: 'PostDetail', params: { id } })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
129
allscore/src/views/posts/PostListView.vue
Normal file
129
allscore/src/views/posts/PostListView.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>게시글 목록</h2>
|
||||
<hr class="my-4" />
|
||||
<PostFilter
|
||||
v-model:title="params.title_like"
|
||||
v-model:limit="params._limit"
|
||||
@update:limit="changeLimit"
|
||||
/>
|
||||
<hr class="my-4" />
|
||||
|
||||
<AppLoading v-if="loading" />
|
||||
<AppError v-else-if="error" :message="error.message" />
|
||||
|
||||
<template v-else-if="!isExist">
|
||||
<p class="text-center py-5 text-muted">No Results</p>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<AppGrid :items="posts" col-class="col-12 col-sd-6 col-lg-4">
|
||||
<template v-slot="{ item }">
|
||||
<PostItem
|
||||
:title="item.title"
|
||||
:content="item.content"
|
||||
:createdAt="item.createdAt"
|
||||
@click="goPage(item.id)"
|
||||
@modal="openModal(item)"
|
||||
@preview="selectPreview(item.id)"
|
||||
></PostItem>
|
||||
</template>
|
||||
</AppGrid>
|
||||
<AppPagination
|
||||
:current-page="params._page"
|
||||
:page-count="pageCount"
|
||||
@page="(page) => (params._page = page)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<Teleport to="#modal">
|
||||
<PostModal
|
||||
v-model="show"
|
||||
:title="modalTitle"
|
||||
:content="modalContent"
|
||||
:created-at="modalCreatedAt"
|
||||
/>
|
||||
</Teleport>
|
||||
|
||||
<template v-if="previewId">
|
||||
<hr class="my-5" />
|
||||
<AppCard>
|
||||
<PostDetailView :id="previewId"></PostDetailView>
|
||||
</AppCard>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import PostDetailView from '@/views/posts/PostDetailView.vue'
|
||||
import PostItem from '@/components/posts/PostItem.vue'
|
||||
import PostFilter from '@/components/posts/PostFilter.vue'
|
||||
import PostModal from '@/components/posts/PostModal.vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const previewId = ref(null)
|
||||
const selectPreview = (id) => (previewId.value = id)
|
||||
|
||||
const params = ref({
|
||||
_sort: 'createdAt',
|
||||
_order: 'desc',
|
||||
_page: 1,
|
||||
_limit: 6,
|
||||
title_like: ''
|
||||
})
|
||||
const changeLimit = (value) => {
|
||||
params.value._limit = value
|
||||
params.value._page = 1
|
||||
}
|
||||
|
||||
const { response, data: posts, error, loading } = useAxios('/posts', { method: 'get', params })
|
||||
const isExist = computed(() => posts.value && posts.value.length)
|
||||
|
||||
// 페이징 관련
|
||||
const totalCount = computed(() => response.value.headers['x-total-count'])
|
||||
const pageCount = computed(() => Math.ceil(totalCount.value / params.value._limit))
|
||||
|
||||
// const fetchPosts = async () => {
|
||||
// try {
|
||||
// loading.value = true
|
||||
// const { data, headers } = await getPosts(params.value)
|
||||
// posts.value = data
|
||||
// totalCount.value = headers['x-total-count']
|
||||
// } catch (err) {
|
||||
// error.value = err
|
||||
// } finally {
|
||||
// loading.value = false
|
||||
// }
|
||||
// }
|
||||
// // fetchPosts()
|
||||
// watchEffect(fetchPosts)
|
||||
|
||||
const goPage = (id) => {
|
||||
// router.push(`/posts/${id}`)
|
||||
router.push({
|
||||
name: 'PostDetail',
|
||||
params: { id: id },
|
||||
query: { searchText: 'hello' },
|
||||
hash: '#world!'
|
||||
})
|
||||
}
|
||||
|
||||
//modal
|
||||
const show = ref(false)
|
||||
const modalTitle = ref('')
|
||||
const modalContent = ref('')
|
||||
const modalCreatedAt = ref('')
|
||||
const openModal = ({ title, content, createdAt }) => {
|
||||
show.value = true
|
||||
modalTitle.value = title
|
||||
modalContent.value = content
|
||||
modalCreatedAt.value = createdAt
|
||||
}
|
||||
const closeModal = () => (show.value = false)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
25
allscore/vite.config.js
Normal file
25
allscore/vite.config.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
Components({
|
||||
dirs: [''],
|
||||
dts: true
|
||||
})
|
||||
],
|
||||
// mode: 'production',
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist'
|
||||
}
|
||||
})
|
14
docker-compose.yml
Normal file
14
docker-compose.yml
Normal file
@ -0,0 +1,14 @@
|
||||
version: '3'
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
container_name: vue-nginx
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- /home/ec2-user/eld/card_service/frontend/DIST_240708:/usr/share/nginx/html
|
||||
- /home/ec2-user/eld/card_service/frontend/eld.crt:/home/ec2-user/eld/card_service/frontend/eld.crt
|
||||
- /home/ec2-user/eld/card_service/frontend/eld.key:/home/ec2-user/eld/card_service/frontend/eld.key
|
||||
- /home/ec2-user/eld/card_service/frontend/56DA6C13A51666386B7D2E61E85EF2E2.txt:/home/ec2-user/eld/card_service/frontend/56DA6C13A51666386B7D2E61E85EF2E2.txt
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
35
eld.crt
Normal file
35
eld.crt
Normal file
@ -0,0 +1,35 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGCDCCBPCgAwIBAgIQWwEQbfqkdYEA35goU9JMADANBgkqhkiG9w0BAQsFADBM
|
||||
MQswCQYDVQQGEwJMVjENMAsGA1UEBxMEUmlnYTERMA8GA1UEChMIR29HZXRTU0wx
|
||||
GzAZBgNVBAMTEkdvR2V0U1NMIFJTQSBEViBDQTAeFw0yNDA3MjMwMDAwMDBaFw0y
|
||||
NTA3MjMyMzU5NTlaMBYxFDASBgNVBAMTC2VsZHNvZnQuY29tMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkYA7IYc330ya/BFBhcG8QQrdKuV5GPV5rh0K
|
||||
NIeCU0yWl5ydYzpXhWuFE/qnQfVRK5g+1jAfBK4UHTZdpdvWzdDlZFkJBiQO0MS2
|
||||
/ujWpTWSEYqalgRxZylTDSOG+KAt+Tpo0ZWv/T6okjW54+J2vi4E/2QGPzi/Dr5c
|
||||
d9hlMBB3VREsmDqDScVnHOlxbMVLf/EgIEP5CbGwdV71/R5Tpcdkr9ubw5s1RdMz
|
||||
GEYfQEJM56zdlAwhG7ucadoIVXRlP6BWmyrk9uZgcDg1waUoFekyCGg/gwhdzoH5
|
||||
xglDwb1tL/b+jxhgm8Cu0Av5GwaD45LSc1B1+AHM99qnoETuKQIDAQABo4IDGjCC
|
||||
AxYwHwYDVR0jBBgwFoAU+ftQxItnu2dk/oMhpqnOP1WEk5kwHQYDVR0OBBYEFLxH
|
||||
VZ+saqBmJr8jEwI3UhYLh4DLMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAA
|
||||
MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBLBgNVHSAERDBCMDYGCysG
|
||||
AQQBsjEBAgJAMCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8vY3BzLnVzZXJ0cnVzdC5j
|
||||
b20wCAYGZ4EMAQIBMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwudXNlcnRy
|
||||
dXN0LmNvbS9Hb0dldFNTTFJTQURWQ0EuY3JsMG8GCCsGAQUFBwEBBGMwYTA4Bggr
|
||||
BgEFBQcwAoYsaHR0cDovL2NydC51c2VydHJ1c3QuY29tL0dvR2V0U1NMUlNBRFZD
|
||||
QS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wFgYD
|
||||
VR0RBA8wDYILZWxkc29mdC5jb20wggGABgorBgEEAdZ5AgQCBIIBcASCAWwBagB2
|
||||
AN3cyjSV1+EWBeeVMvrHn/g9HFDf2wA6FBJ2Ciysu8gqAAABkN5FaiIAAAQDAEcw
|
||||
RQIgHTbwtmQN6xLMETdF+8eqQ7AKqXO8N2f+bD7Fx7tzlo4CIQDc3kmta7RofW+L
|
||||
jZxQtI4p3b4hFUFCDw85ibQgCSpH6QB3AA3h8jAr0w3BQGISCepVLvxHdHyx1+kw
|
||||
7w5CHrR+Tqo0AAABkN5Fae8AAAQDAEgwRgIhAI2ZgaTuuAjcfrg6o2KeX+O8ga8e
|
||||
tGY7+NZRt/yRXuyXAiEA5bEkR2LchqMV3vYr5Eo/7nKm8eTXNBhduxNIPxNzRoAA
|
||||
dwAS8U40vVNyTIQGGcOPP3oT+Oe1YoeInG0wBYTr5YYmOgAAAZDeRWnNAAAEAwBI
|
||||
MEYCIQDT4+jvqlZboMs6AeqxZRu0TyKB/zA5UzGfJdaCaWQ8iAIhAKgg7Q+W0sd/
|
||||
Gxaa2pHXpHSxP3sfkT9o5Br8S4pILca3MA0GCSqGSIb3DQEBCwUAA4IBAQA51hYf
|
||||
mw+kueMcWmPUlUikrK0/KuLpSfWPvHOj+r84Y5AS9JxZmi9b+9W18p1VwO0YXR6U
|
||||
ho4PyHjuIviT2LviAWyvRTFc9Il+e920+RyMiAdfQ/Af15xdcAJOjSMlZu3xkqvW
|
||||
gkgE1kPvIQevqCmEEzUqsUVEn7ftoDcT9SEJBpLFwB6FAFBfw0pvJ0qUr9LAin4p
|
||||
bklWGaY2laI2py7MXZNUO35rahA0DNS/Y2sY3TbH/WXilJ/sbJ9sO83/XC2T7vgC
|
||||
Le2cv9gNFJPiTW++OROxybXzarwIwWFHO7aPc5Ehv9U54/XlzBIzrRsJuvtXkc0I
|
||||
0nuiAfpjOom89Z1W
|
||||
-----END CERTIFICATE-----
|
17
eld.csr
Normal file
17
eld.csr
Normal file
@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICrzCCAZcCAQAwbDEUMBIGA1UEAwwLZWxkc29mdC5jb20xHzAdBgNVBAoMFuyj
|
||||
vOyLne2ajOyCrCDsnbTsl5jrlJQxEjAQBgNVBAgMCeuMgOyghOyLnDESMBAGA1UE
|
||||
BwwJ7Jyg7ISx6rWsMQswCQYDVQQGEwJLUjCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAJGAOyGHN99MmvwRQYXBvEEK3SrleRj1ea4dCjSHglNMlpecnWM6
|
||||
V4VrhRP6p0H1USuYPtYwHwSuFB02XaXb1s3Q5WRZCQYkDtDEtv7o1qU1khGKmpYE
|
||||
cWcpUw0jhvigLfk6aNGVr/0+qJI1uePidr4uBP9kBj84vw6+XHfYZTAQd1URLJg6
|
||||
g0nFZxzpcWzFS3/xICBD+QmxsHVe9f0eU6XHZK/bm8ObNUXTMxhGH0BCTOes3ZQM
|
||||
IRu7nGnaCFV0ZT+gVpsq5PbmYHA4NcGlKBXpMghoP4MIXc6B+cYJQ8G9bS/2/o8Y
|
||||
YJvArtAL+RsGg+OS0nNQdfgBzPfap6BE7ikCAwEAATANBgkqhkiG9w0BAQsFAAOC
|
||||
AQEAZhOyuc//t8Vp+Iog/C12fFSIB4baHBS/GV3C/xm1gvmn/Vl8ynaswPA3ei0U
|
||||
rvoXidZHYt7gdcBq1DlPDGxbnEwNYZhNFR0Sv622EO9MrsiUsje6yWm2xmCgM8zw
|
||||
ChhifmEulSBEFcOQGi9eKA19jJHKEqRx5QhlZHsRdVD+glxyESpOM0cfUXGsYXhn
|
||||
Pvm9EvlZfYyoVBRjIwO3CIKSaGsgg2FKUKnmgMo28BKVPYM1/gNC47ozhwMOgDrO
|
||||
fg1KZ3CtOMn3ZG7OiN2HamnBNKQDDp6mZJT1aoq1GsENYFNJUfW768G2rmAUGNfw
|
||||
My3PBjidoiuChvimG1Fqpnioxw==
|
||||
-----END CERTIFICATE REQUEST-----
|
27
eld.key
Normal file
27
eld.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAkYA7IYc330ya/BFBhcG8QQrdKuV5GPV5rh0KNIeCU0yWl5yd
|
||||
YzpXhWuFE/qnQfVRK5g+1jAfBK4UHTZdpdvWzdDlZFkJBiQO0MS2/ujWpTWSEYqa
|
||||
lgRxZylTDSOG+KAt+Tpo0ZWv/T6okjW54+J2vi4E/2QGPzi/Dr5cd9hlMBB3VREs
|
||||
mDqDScVnHOlxbMVLf/EgIEP5CbGwdV71/R5Tpcdkr9ubw5s1RdMzGEYfQEJM56zd
|
||||
lAwhG7ucadoIVXRlP6BWmyrk9uZgcDg1waUoFekyCGg/gwhdzoH5xglDwb1tL/b+
|
||||
jxhgm8Cu0Av5GwaD45LSc1B1+AHM99qnoETuKQIDAQABAoIBAAhxYU0CYoe4s2AX
|
||||
1L5hFe5MxfVqpCaifOVxbjGK4PE6Nx1UU04qGSDG8s2MXIb/aA7AanoFiBE+lDB3
|
||||
QoMgsPPXsK3sXDGQ51KuLYO4aVckFwYhTbPRjW6L53OyWW9FJTHKdcFenxwR9hho
|
||||
2XDrp9IEi9nxeQrTXUPK4ET8h6+cmHgEDEXJ18xyn3EMrXbBTOBaAGJwdA/kE947
|
||||
o85Yu+o3sKA+3JsuuMijSy2XSqvslNNeyOvlcFcq88eDY5pXuDGbRQPnIQe3t0Fc
|
||||
DMtIF2E2jOtIbMuBdcdZaUduiPqVRT3ojW2LaDc58H7+piAgBUVGJCLuqIgujBa0
|
||||
t3n9M3ECgYEA1oe+oVG8+OVvcg9IJyQmnZOIR3hopuDvZOCYuSOsOS8DMo+p066z
|
||||
6rSKpvtIcJJ8l0mM8Rw4WifEbEYOgkt9yGVK80mMI2BkSwmq5U4hOWg/xxqATTz5
|
||||
PBgz0bBwZ6ZgW/3RD+jWybX3vy+beifAL3v52q+hnZdZf1q1rBYYWXECgYEAraB/
|
||||
C/a4RO0LygrncUgn9MX4mGe2zRVAszZcbcX2iG4o1mseoZ16HO1ipS4Q/kI/znpY
|
||||
r7XT4QgF98Fdkcl8MYKP+snUv9TG7zOFiYOe0JeaafBuukMDPUqeQXk/d9rSrJg9
|
||||
lqiw1LYYyxPnh8aTEfwMBPqaRhLiMeD63PsHRDkCgYEAzwflUi1dnx1b9ckFqrBa
|
||||
i8tqwv5SkGmW3dVZzaG9fNn/zfWSwPRiMOjWvdrWx7y2fBHA8JZ5U5f5GTxqmBde
|
||||
ZdxK/opFsYY+g6PqxqwlqA8RLYZHt0JWjEYXDA+oCn8nkt9ZuG7NiZAQbPL2qmZe
|
||||
M/UC5KaF413CQwM5O79+9CECgYBT/D+YNOabiKJcP/wGAuY48441gm2dNDuQtKnu
|
||||
+4QuKEMevMAbYwZPedBuoCLeKoOcx/egPu7Xej8QwfsV6wVlGYe1wu1jQXRc/moI
|
||||
w58NvVeXCRM2i/XELxTwDMtTmYiwrg+UkdK/gbnqeZ1UQwye9XGG8wWvAbFieTY/
|
||||
sDmqmQKBgQCUyu98Gpatoe8MdyHZf9h+QfYcUkpLuhJOvWCGQt9QyfiIal5eleXG
|
||||
YPNaQBk3GtSPyuB1nDrjtHaIlyw1ScjRCfzth3VJvwWnqz9y7XP2pow2+TnY0Jco
|
||||
lvMRY9n55TgAPdTdgHshUyDRAM1/aUbiBIPPOP/XAcmONZ1lpayZ7A==
|
||||
-----END RSA PRIVATE KEY-----
|
40
nginx.conf
Normal file
40
nginx.conf
Normal file
@ -0,0 +1,40 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# DCV 검증을 위한 추가 설정
|
||||
location = /.well-known/pki-validation/56DA6C13A51666386B7D2E61E85EF2E2.txt {
|
||||
alias /home/ec2-user/eld/card_service/frontend/56DA6C13A51666386B7D2E61E85EF2E2.txt;
|
||||
}
|
||||
|
||||
error_page 404 /index.html;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name _;
|
||||
|
||||
ssl_certificate /home/ec2-user/eld/card_service/frontend/eld.crt;
|
||||
ssl_certificate_key /home/ec2-user/eld/card_service/frontend/eld.key;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# DCV 검증을 위한 추가 설정
|
||||
location = /.well-known/pki-validation/56DA6C13A51666386B7D2E61E85EF2E2.txt {
|
||||
alias /home/ec2-user/eld/card_service/frontend/56DA6C13A51666386B7D2E61E85EF2E2.txt;
|
||||
}
|
||||
|
||||
error_page 404 /index.html;
|
||||
}
|
Loading…
Reference in New Issue
Block a user