첫 커밋
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