[ADD] 프로젝트 생성

main
JUNG HYEJI 1 month ago
parent 581c6da20a
commit 085327c414

@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

@ -0,0 +1,5 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

@ -0,0 +1,82 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"DirectiveBinding": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true,
"Ref": true,
"Slot": true,
"Slots": true,
"VNode": true,
"WritableComputedRef": true,
"computed": true,
"createApp": true,
"customRef": true,
"defineAsyncComponent": true,
"defineComponent": true,
"defineStore": true,
"effectScope": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"inject": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onUnmounted": true,
"onUpdated": true,
"onWatcherCleanup": true,
"provide": true,
"reactive": true,
"readonly": true,
"ref": true,
"resolveComponent": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"storeToRefs": true,
"toRaw": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"unref": true,
"useAttrs": true,
"useCssModule": true,
"useCssVars": true,
"useId": true,
"useModel": true,
"useRoute": true,
"useRouter": true,
"useSlots": true,
"useTemplateRef": true,
"watch": true,
"watchEffect": true,
"watchPostEffect": true,
"watchSyncEffect": true
}
}

22
.gitignore vendored

@ -0,0 +1,22 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

147
auto-imports.d.ts vendored

@ -0,0 +1,147 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
// for vue template auto import
import { UnwrapRef } from 'vue'
declare module 'vue' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router')['onBeforeRouteLeave']>
readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router')['onBeforeRouteUpdate']>
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
readonly ref: UnwrapRef<typeof import('vue')['ref']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
readonly unref: UnwrapRef<typeof import('vue')['unref']>
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useId: UnwrapRef<typeof import('vue')['useId']>
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
readonly watch: UnwrapRef<typeof import('vue')['watch']>
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
}
}

18
components.d.ts vendored

@ -0,0 +1,18 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
// biome-ignore lint: disable
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AppFooter: typeof import('./src/components/AppFooter.vue')['default']
DrawerComponent: typeof import('./src/components/common/DrawerComponent.vue')['default']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
LayoutComponent: typeof import('./src/components/common/LayoutComponent.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}

@ -0,0 +1,3 @@
import vuetify from 'eslint-config-vuetify'
export default vuetify()

@ -0,0 +1,13 @@
<!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>Welcome to Vuetify 3</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

@ -0,0 +1,20 @@
{
"compilerOptions": {
"allowJs": true,
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "bundler",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

6146
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,35 @@
{
"name": "autoflow-web-console",
"private": true,
"type": "module",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --fix"
},
"dependencies": {
"@fontsource/roboto": "5.2.5",
"@mdi/font": "7.4.47",
"prettier": "^3.5.3",
"vue": "^3.5.13",
"vuetify": "^3.8.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.3",
"eslint": "^9.23.0",
"eslint-config-vuetify": "^4.0.0",
"globals": "^16.0.0",
"pinia": "^3.0.1",
"sass-embedded": "^1.86.3",
"unplugin-auto-import": "^19.1.1",
"unplugin-fonts": "^1.3.1",
"unplugin-vue-components": "^28.4.1",
"unplugin-vue-router": "^0.12.0",
"vite": "^6.2.2",
"vite-plugin-vue-layouts-next": "^0.0.8",
"vite-plugin-vuetify": "^2.1.1",
"vue-router": "^4.5.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -0,0 +1,9 @@
<template>
<v-app>
<router-view />
</v-app>
</template>
<script setup>
//
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -0,0 +1,6 @@
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M261.126 140.65L164.624 307.732L256.001 466L377.028 256.5L498.001 47H315.192L261.126 140.65Z" fill="#1697F6"/>
<path d="M135.027 256.5L141.365 267.518L231.64 111.178L268.731 47H256H14L135.027 256.5Z" fill="#AEDDFF"/>
<path d="M315.191 47C360.935 197.446 256 466 256 466L164.624 307.732L315.191 47Z" fill="#1867C0"/>
<path d="M268.731 47C76.0026 47 141.366 267.518 141.366 267.518L268.731 47Z" fill="#7BC6FF"/>
</svg>

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -0,0 +1,82 @@
<template>
<v-footer
app
height="40"
>
<a
v-for="item in items"
:key="item.title"
class="d-inline-block mx-2 social-link"
:href="item.href"
rel="noopener noreferrer"
target="_blank"
:title="item.title"
>
<v-icon
:icon="item.icon"
:size="item.icon === '$vuetify' ? 24 : 16"
/>
</a>
<div
class="text-caption text-disabled"
style="position: absolute; right: 16px;"
>
&copy; 2016-{{ (new Date()).getFullYear() }} <span class="d-none d-sm-inline-block">Vuetify, LLC</span>
<a
class="text-decoration-none on-surface"
href="https://vuetifyjs.com/about/licensing/"
rel="noopener noreferrer"
target="_blank"
>
MIT License
</a>
</div>
</v-footer>
</template>
<script setup>
const items = [
{
title: 'Vuetify Documentation',
icon: `$vuetify`,
href: 'https://vuetifyjs.com/',
},
{
title: 'Vuetify Support',
icon: 'mdi-shield-star-outline',
href: 'https://support.vuetifyjs.com/',
},
{
title: 'Vuetify X',
icon: ['M2.04875 3.00002L9.77052 13.3248L1.99998 21.7192H3.74882L10.5519 14.3697L16.0486 21.7192H22L13.8437 10.8137L21.0765 3.00002H19.3277L13.0624 9.76874L8.0001 3.00002H2.04875ZM4.62054 4.28821H7.35461L19.4278 20.4308H16.6937L4.62054 4.28821Z'],
href: 'https://x.com/vuetifyjs',
},
{
title: 'Vuetify GitHub',
icon: `mdi-github`,
href: 'https://github.com/vuetifyjs/vuetify',
},
{
title: 'Vuetify Discord',
icon: ['M22,24L16.75,19L17.38,21H4.5A2.5,2.5 0 0,1 2,18.5V3.5A2.5,2.5 0 0,1 4.5,1H19.5A2.5,2.5 0 0,1 22,3.5V24M12,6.8C9.32,6.8 7.44,7.95 7.44,7.95C8.47,7.03 10.27,6.5 10.27,6.5L10.1,6.33C8.41,6.36 6.88,7.53 6.88,7.53C5.16,11.12 5.27,14.22 5.27,14.22C6.67,16.03 8.75,15.9 8.75,15.9L9.46,15C8.21,14.73 7.42,13.62 7.42,13.62C7.42,13.62 9.3,14.9 12,14.9C14.7,14.9 16.58,13.62 16.58,13.62C16.58,13.62 15.79,14.73 14.54,15L15.25,15.9C15.25,15.9 17.33,16.03 18.73,14.22C18.73,14.22 18.84,11.12 17.12,7.53C17.12,7.53 15.59,6.36 13.9,6.33L13.73,6.5C13.73,6.5 15.53,7.03 16.56,7.95C16.56,7.95 14.68,6.8 12,6.8M9.93,10.59C10.58,10.59 11.11,11.16 11.1,11.86C11.1,12.55 10.58,13.13 9.93,13.13C9.29,13.13 8.77,12.55 8.77,11.86C8.77,11.16 9.28,10.59 9.93,10.59M14.1,10.59C14.75,10.59 15.27,11.16 15.27,11.86C15.27,12.55 14.75,13.13 14.1,13.13C13.46,13.13 12.94,12.55 12.94,11.86C12.94,11.16 13.45,10.59 14.1,10.59Z'],
href: 'https://community.vuetifyjs.com/',
},
{
title: 'Vuetify Reddit',
icon: `mdi-reddit`,
href: 'https://reddit.com/r/vuetifyjs',
},
]
</script>
<style scoped lang="sass">
.social-link :deep(.v-icon)
color: rgba(var(--v-theme-on-background), var(--v-disabled-opacity))
text-decoration: none
transition: .2s ease-in-out
&:hover
color: rgba(25, 118, 210, 1)
</style>

@ -0,0 +1,90 @@
<template>
<v-container class="fill-height" max-width="900">
<div>
<v-img
class="mb-4"
height="150"
src="@/assets/logo.png"
/>
<div class="mb-8 text-center">
<div class="text-body-2 font-weight-light mb-n1">Welcome to</div>
<h1 class="text-h2 font-weight-bold">Vuetify</h1>
</div>
<v-row>
<v-col cols="12">
<v-card
class="py-4"
color="surface-variant"
image="https://cdn.vuetifyjs.com/docs/images/one/create/feature.png"
prepend-icon="mdi-rocket-launch-outline"
rounded="lg"
variant="tonal"
>
<template #image>
<v-img position="top right" />
</template>
<template #title>
<h2 class="text-h5 font-weight-bold">
Get started
</h2>
</template>
<template #subtitle>
<div class="text-subtitle-1">
Change this page by updating <v-kbd>{{ `<HelloWorld />` }}</v-kbd> in <v-kbd>components/HelloWorld.vue</v-kbd>.
</div>
</template>
</v-card>
</v-col>
<v-col v-for="link in links" :key="link.href" cols="6">
<v-card
append-icon="mdi-open-in-new"
class="py-4"
color="surface-variant"
:href="link.href"
:prepend-icon="link.icon"
rel="noopener noreferrer"
rounded="lg"
:subtitle="link.subtitle"
target="_blank"
:title="link.title"
variant="tonal"
/>
</v-col>
</v-row>
</div>
</v-container>
</template>
<script setup>
const links = [
{
href: 'https://vuetifyjs.com/',
icon: 'mdi-text-box-outline',
subtitle: 'Learn about all things Vuetify in our documentation.',
title: 'Documentation',
},
{
href: 'https://vuetifyjs.com/introduction/why-vuetify/#feature-guides',
icon: 'mdi-star-circle-outline',
subtitle: 'Explore available framework Features.',
title: 'Features',
},
{
href: 'https://vuetifyjs.com/components/all',
icon: 'mdi-widgets-outline',
subtitle: 'Discover components in the API Explorer.',
title: 'Components',
},
{
href: 'https://discord.vuetifyjs.com',
icon: 'mdi-account-group-outline',
subtitle: 'Connect with Vuetify developers.',
title: 'Community',
},
]
</script>

@ -0,0 +1,35 @@
# Components
Vue template files in this folder are automatically imported.
## 🚀 Usage
Importing is handled by [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components). This plugin automatically imports `.vue` files created in the `src/components` directory, and registers them as global components. This means that you can use any component in your application without having to manually import it.
The following example assumes a component located at `src/components/MyComponent.vue`:
```vue
<template>
<div>
<MyComponent />
</div>
</template>
<script lang="ts" setup>
//
</script>
```
When your template is rendered, the component's import will automatically be inlined, which renders to this:
```vue
<template>
<div>
<MyComponent />
</div>
</template>
<script lang="ts" setup>
import MyComponent from '@/components/MyComponent.vue'
</script>
```

@ -0,0 +1,139 @@
<script setup>
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { useRouter } from "vue-router";
import { menuUtils } from "@/utils/menuUtils";
import { storage } from "@/utils/storage";
const route = useRoute();
const router = useRouter();
const isShowAuth = ref(false);
const isLinkActive = (link) => {
return route.path.includes(link);
};
const goMain = () => {
router.push("/home");
};
onMounted(() => {
isShowAuth.value = true;
//storage.getAuth().auth === "ADMIN";
});
</script>
<template>
<v-card flat class="mx-auto">
<v-card
:ripple="false"
flat
class="bg-shades-transparent font-weight-bold d-flex w-100 justify-center text-h5 pa-4 pb-16"
@click="goMain"
>
<div>
<v-img :src="logo" width="auto" height="32" />
</div>
</v-card>
<v-list nav class="pa-5">
<template
v-for="({ title, value, icon, path, depth }, i) in menuUtils.menuItem"
:key="`group_id_${i}`"
>
<template v-if="depth && depth.length > 0">
<v-list-group :key="`group_id_${i}`">
<template #activator="{ props }">
<v-list-item
rounded
v-bind="props"
:title="title"
:prepend-icon="icon"
class="pa-2 rounded-lg"
>
</v-list-item>
</template>
<v-list-item
v-for="({ title: t, path: p }, j) in depth"
:key="`id_${j}`"
rounded
:title="t"
:value="t"
:to="p"
:active-color="isLinkActive(p) ? 'primary' : null"
:active="isLinkActive(p)"
class="pa-2 rounded-lg"
></v-list-item>
</v-list-group>
</template>
<template v-else>
<v-list-item
rounded
:title="title"
:value="value"
:to="path"
:prepend-icon="icon"
:active="isLinkActive(path)"
style="padding-inline-start: 10px"
:active-color="isLinkActive(path) ? 'primary' : null"
density="compact"
class="pa-2 rounded-lg"
></v-list-item>
</template>
</template>
<template v-if="isShowAuth">
<template
v-for="(
{ title, value, icon, path, depth }, i
) in menuUtils.adminMenuItem"
:key="`group_id_6`"
>
<template v-if="depth && depth.length > 0">
<v-list-group :key="`group_id_${i}`">
<template #activator="{ props }">
<v-list-item
rounded
v-bind="props"
:title="title"
:prepend-icon="icon"
class="pa-2 rounded-lg"
>
</v-list-item>
</template>
<v-list-item
v-for="({ title: t, path: p }, j) in depth"
:key="`id_${j}`"
rounded
:title="t"
:value="t"
:to="p"
:active-color="isLinkActive(p) ? 'primary' : null"
:active="isLinkActive(p)"
class="pa-2 rounded-lg"
></v-list-item>
</v-list-group>
</template>
<template v-else>
<v-list-item
rounded
:title="title"
:value="value"
:to="path"
:prepend-icon="icon"
:active="isLinkActive(path)"
style="padding-inline-start: 10px"
:active-color="isLinkActive(path) ? 'primary' : null"
density="compact"
class="pa-2 rounded-lg"
></v-list-item>
</template>
</template>
</template>
</v-list>
</v-card>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,154 @@
<script setup>
import {useRoute, useRouter} from "vue-router";
import {storage} from "@/utils/storage.js";
import DrawerComponent from "@/components/common/DrawerComponent.vue";
import {watchEffect} from "vue";
const route = useRoute();
const router = useRouter();
const menu = ref([]);
const menuItems = [
{
title: "Select Project",
},
{
title: "Change Password",
click: () => {
showPasswordModal.value = true;
},
},
{
title: "Logout",
icon: "mdi-logout",
click: () => {
logOut();
},
},
];
const userMenuItems = [
{
title: "Select Project",
},
{
title: "Change Password",
},
{
title: "Logout",
icon: "mdi-logout",
click: () => {
logOut();
},
},
];
const drawer = ref(null);
const pageTitle = computed(() => {
return route.meta.title;
});
const pagePath = computed(() => {
return route.path;
});
const logOut = () => {
storage.clearAuth();
router.push("/signin");
};
const goHome = () => {
router.push("/main");
};
const showPasswordModal = ref(false);
const selectedUserData = ref({});
watchEffect(() => {
// const auth = storage.getAuth().auth;
// if (auth === "ADMIN") {
menu.value = menuItems;
// } else {
// menu.value = userMenuItems;
// }
});
</script>
<template>
<v-app>
<v-navigation-drawer v-model="drawer" border="0" hide-overlay permanent>
<DrawerComponent />
</v-navigation-drawer>
<v-app-bar class="bg-shades-transparent" flat>
<div class="px-8 text-h6 text-secondary font-weight-medium">
Autoflow Web Console
</div>
<v-spacer></v-spacer>
<v-menu location="bottom end">
<template v-slot:activator="{ props }">
<v-tooltip location="bottom" text="dashboard">
<template #activator="{ props }">
<v-btn
icon
color="secondary"
class="mr-3"
v-bind="props"
>
<v-icon>mdi-settings</v-icon>
</v-btn>
</template>
</v-tooltip>
<v-tooltip location="bottom" text="dashboard">
<template #activator="{ props }">
<v-btn
icon
color="secondary"
class="mr-3"
@click="goHome"
v-bind="props"
>
<v-icon>mdi-home</v-icon>
</v-btn>
</template>
</v-tooltip>
<div style="min-width: 180px" class="d-flex flex-column align-end">
<div class="font-weight-black">ADMIN_001</div>
<div class="text-subtitle-2">No Project Selected</div>
</div>
<v-btn icon color="secondary" v-bind="props" class="mr-3">
<v-icon>mdi-arrow-down-drop-circle-outline</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in menu"
:key="index"
:value="index"
@click="item.click"
:prepend-icon="item.icon"
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-app-bar>
<v-main>
<v-container
fluid
class="pa-16 background d-flex justify-center"
style="width: 100%"
>
<slot></slot>
</v-container>
</v-main>
</v-app>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,5 @@
# Layouts
Layouts are reusable components that wrap around pages. They are used to provide a consistent look and feel across multiple pages.
Full documentation for this feature can be found in the Official [vite-plugin-vue-layouts-next](https://github.com/loicduong/vite-plugin-vue-layouts-next) repository.

@ -0,0 +1,9 @@
<template>
<LayoutComponent>
<router-view />
</LayoutComponent>
</template>
<script setup>
import LayoutComponent from '@/components/common/LayoutComponent.vue';
</script>

@ -0,0 +1,23 @@
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './App.vue'
// Composables
import { createApp } from 'vue'
// Styles
import 'unfonts.css'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,159 @@
<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import { storage } from "@/utils/storage";
import logo from "@/assets/wordmark.png";
import logo2 from "@/assets/workflow.png";
const router = useRouter();
const data = ref({
form: false,
userId: "",
userPw: "",
loading: false,
snackbar: false,
snackbarText: "",
snackbarColor: "",
});
const resetForm = () => {
data.value.userId = "";
data.value.userPw = "";
data.value.loading = false;
};
const signIn = () => {
// if (!data.value.form) return;
// data.value.loading = true;
// setTimeout(() => (data.value.loading = false), 2000);
// const params = {
// userId: data.value.userId,
// password: data.value.userPw,
// };
//
// UserManagerService.signIn(params).then((d) => {
// if (d.data.success === true) {
// storage.setAuth(d.data.data);
router.push("/main");
// } else {
// resetForm();
// data.value.snackbar = true;
// }
// });
};
</script>
<template>
<v-container :fluid="true" class="pa-0">
<v-sheet
class="background-image w-100 h-screen d-flex align-center justify-center flex-column"
>
<v-card flat class="bg-transparent d-flex align-center flex-column">
<v-card
class="mx-auto pa-10 mb-4 login-box rounded-lg d-flex flex-column"
style="min-width: 450px !important;"
density="comfortable"
>
<div class="mb-4 w-100 d-flex justify-center">
<div
class="bg-transparent rounded-circle pa-2"
style="border: 1.5px solid #f7f7f8"
>
<v-icon>mdi-shield-key-outline</v-icon>
</div>
</div>
<div class="text-h5 pb-2 text-center font-weight-bold">
Autoflow Web Console
</div>
<v-form v-model="data.form" @submit.prevent="signIn" class="mt-3">
<v-text-field
v-model="data.userId"
:readonly="data.loading"
class="mb-2"
variant="outlined"
color="secondary"
placeholder="아이디를 입력해주세요."
></v-text-field>
<v-text-field
v-model="data.userPw"
:readonly="data.loading"
type="password"
variant="outlined"
color="secondary"
class="mb-2"
placeholder="비밀번호를 입력해주세요."
></v-text-field>
<v-btn
:disabled="!data.form"
:loading="data.loading"
block
color="primary"
size="large"
type="submit"
variant="flat"
>
login
</v-btn>
</v-form>
</v-card>
</v-card>
<v-sheet
class="position-absolute w-100 bg-transparent pa-4"
style="bottom: 0; left: 0"
>
<v-sheet class="bg-shades-transparent d-flex align-end"
>Copyright © 2025 Autoflow Web Console
</v-sheet>
</v-sheet>
<v-sheet
class="position-absolute w-100 bg-transparent pa-4"
style="bottom: 0; right: 0"
>
<v-sheet class="bg-shades-transparent d-flex justify-end">
<img :src="logo" style="width: 5%" />
</v-sheet>
</v-sheet>
</v-sheet>
</v-container>
<v-snackbar
v-model="data.snackbar"
timeout="2000"
location="button"
:color="data.snackbarColor"
>
{{ data.snackbarText }}
<template #actions>
<v-btn variant="text" @click="data.snackbar = false"> 닫기 </v-btn>
</template>
</v-snackbar>
</template>
<style scoped>
.login-box {
background-color: rgba(18, 18, 18, 0.4); /* 흰색 배경에 30% 불투명도 */
backdrop-filter: blur(10px); /* 배경 블러 효과 */
}
.background-image {
background-image: linear-gradient(
90deg,
rgba(19, 18, 18, 0.5),
rgba(19, 18, 18, 0.3),
rgba(19, 18, 18, 0.3),
rgba(19, 18, 18, 0.5)
),url("@/assets/4117551.jpg"); /* 배경 이미지 경로 */
background-size: cover; /* 이미지가 화면을 꽉 채우도록 설정 */
background-position: center; /* 이미지 중앙 정렬 */
background-repeat: no-repeat; /* 이미지 반복 방지 */
min-height: 100vh; /* 화면 전체 높이 설정 */
}
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,5 @@
# Pages
Vue components created in this folder will automatically be converted to navigatable routes.
Full documentation for this feature can be found in the Official [unplugin-vue-router](https://github.com/posva/unplugin-vue-router) repository.

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<div>main</div>
</template>
<style scoped lang="sass">
</style>

@ -0,0 +1,7 @@
<template>
<HelloWorld />
</template>
<script setup>
//
</script>

@ -0,0 +1,3 @@
# Plugins
Plugins are a way to extend the functionality of your Vue application. Use this folder for registering plugins that you want to use globally.

@ -0,0 +1,17 @@
/**
* plugins/index.js
*
* Automatically included in `./src/main.js`
*/
// Plugins
import vuetify from './vuetify'
import pinia from '@/stores'
import router from '@/router'
export function registerPlugins (app) {
app
.use(vuetify)
.use(router)
.use(pinia)
}

@ -0,0 +1,19 @@
/**
* plugins/vuetify.js
*
* Framework documentation: https://vuetifyjs.com`
*/
// Styles
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
// Composables
import { createVuetify } from 'vuetify'
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
export default createVuetify({
theme: {
defaultTheme: 'dark',
},
})

@ -0,0 +1,146 @@
import { createRouter, createWebHistory } from "vue-router";
import { storage } from "@/utils/storage";
const rootPath = import.meta.env.VITE_ROOT_PATH;
const routes = [
{
path: `/`,
component: () => import('@/layouts/default.vue'),
redirect: { name: "signin" },
children: [
{
name: "main",
path: `/main`,
meta: {
title: "",
requiresAuth: false,
},
component: () => import('@/pages/MainView.vue'),
},
{
name: "home",
path: `/home`,
meta: {
title: "Home",
requiresAuth: false,
},
component: () => import("@/pages/HomeView.vue"),
},
{
name: "workflows",
path: `/workflows`,
meta: {
title: "Workflows",
requiresAuth: false,
},
component: () => import("@/pages/WorkflowView.vue"),
},
{
name: "workflow-step-config",
path: `/workflow-step-config`,
meta: {
title: "Workflow Step Config",
requiresAuth: false,
},
component: () => import("@/pages/WorkflowStepConfigView.vue"),
},
{
name: "run",
path: `/run`,
meta: {
title: "Run",
requiresAuth: false,
},
redirect: { name: "experiment" },
children: [
{
name: "experiment",
path: `/run/experiment`,
meta: {
title: "Experiment",
requiresAuth: false,
},
component: () => import("@/pages/ExperimentView.vue"),
},
{
name: "Excutions",
path: `/run/excutions`,
meta: {
title: "Excutions",
requiresAuth: false,
},
component: () => import("@/pages/ExcutionsView.vue"),
},
],
},
{
name: "deployment",
path: `/deployment`,
meta: {
title: "Deployment",
requiresAuth: false,
},
component: () => import("@/pages/DeploymentView.vue"),
},
{
name: "training-script",
path: `/training-script`,
meta: {
title: "Training Script",
requiresAuth: true,
},
component: () => import("@/pages/TrainingScriptView.vue"),
},
{
name: "datasets",
path: `/datasets`,
meta: {
title: "Datasets",
requiresAuth: true,
},
component: () => import("@/pages/DatasetView.vue"),
},
],
},
{
name: "signin",
path: `/signin`,
meta: {
title: "로그인",
requiresAuth: false,
},
component: () => import('@/pages/LoginView.vue'),
},
];
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_ROOT_PATH),
routes,
});
// router.beforeEach((to) => {
// if (!storage.getAuth() && to.name !== "signin") {
// return { name: "signin" };
// } else if (storage.getAuth() && to.name === "signin") {
// return { name: "main" };
// }
//
// // 권한 검사
// if (to.meta.requiresAuth) {
// if (storage.getAuth().auth !== "ADMIN") {
// // const store = commonStore();
// // store.setSnackbarMsg({
// // text: "접근 권한이 없습니다.",
// // result: 500,
// // color: "error",
// // });
// return { name: "main" };
// }
// }
//
// return true; // 허용된 경우 라우트 진행
// });
export default router;

@ -0,0 +1,5 @@
# Store
Pinia stores are used to store reactive state and expose actions to mutate it.
Full documentation for this feature can be found in the Official [Pinia](https://pinia.esm.dev/) repository.

@ -0,0 +1,8 @@
// Utilities
import { defineStore } from 'pinia'
export const useAppStore = defineStore('app', {
state: () => ({
//
}),
})

@ -0,0 +1,4 @@
// Utilities
import { createPinia } from 'pinia'
export default createPinia()

@ -0,0 +1,3 @@
# Styles
This directory is for configuring the styles of the application.

@ -0,0 +1,10 @@
/**
* src/styles/settings.scss
*
* Configures SASS variables and Vuetify overwrites
*/
// https://vuetifyjs.com/features/sass-variables/`
// @use 'vuetify/settings' with (
// $color-pack: false
// );

@ -0,0 +1,52 @@
export const menuUtils = {
menuItem: [
{
title: "Home",
path: "/home",
value: "home",
icon: "mdi-monitor-multiple",
},
{
title: "Workflows",
path: "/workflows",
value: "workflows",
icon: "mdi-code-braces",
},
{
title: "Workflow Step Config",
path: "/workflow-step-config",
value: "workflow-step-config",
icon: "mdi-hammer-wrench",
},
{
title: "Run",
path: "/run",
value: "run",
icon: "mdi-format-list-bulleted-square",
depth: [
{ title: "Experiment", path: "/run/experiment" },
{ title: "Excutions", path: "/run/excutions" },
],
},
{
title: "Deployment",
path: "/deployment",
value: "deployment",
icon: "mdi-folder-search",
},
],
adminMenuItem: [
{
title: "Training Script",
path: "/training-script",
value: "training-script",
icon: "mdi-account",
},
{
title: "Datasets",
path: "/datasets",
value: "datasets",
icon: "mdi-account",
},
],
};

@ -0,0 +1,46 @@
export const storage = {
get: (key) => {
return localStorage.getItem(key);
},
set: (key, value) => {
localStorage.setItem(key, value);
},
getToken: () => {
const authString = localStorage.getItem("autoflow-auth");
if (authString !== null) {
const auth = JSON.parse(authString);
return auth.token;
}
return "";
},
getUserId: () => {
const authString = localStorage.getItem("autoflow-auth");
if (authString !== null) {
const auth = JSON.parse(authString);
return auth.userId;
}
return "";
},
getId: () =>{
const authString = localStorage.getItem("autoflow-auth");
if (authString !== null) {
const auth = JSON.parse(authString);
return auth.id;
}
return "";
},
getAuth: () => {
const authString = localStorage.getItem("autoflow-auth");
if (authString !== null) {
return JSON.parse(authString);
}
return null;
},
setAuth: (value) => {
localStorage.setItem("autoflow-auth", JSON.stringify(value));
},
clearAuth: () => {
localStorage.removeItem("autoflow-auth");
},
};

33
typed-router.d.ts vendored

@ -0,0 +1,33 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️
// It's recommended to commit this file.
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
declare module 'vue-router/auto-routes' {
import type {
RouteRecordInfo,
ParamValue,
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
} from 'vue-router'
/**
* Route name map generated by unplugin-vue-router
*/
export interface RouteNamedMap {
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
'/DatasetView': RouteRecordInfo<'/DatasetView', '/DatasetView', Record<never, never>, Record<never, never>>,
'/DeploymentView': RouteRecordInfo<'/DeploymentView', '/DeploymentView', Record<never, never>, Record<never, never>>,
'/ExcutionsView': RouteRecordInfo<'/ExcutionsView', '/ExcutionsView', Record<never, never>, Record<never, never>>,
'/ExperimentView': RouteRecordInfo<'/ExperimentView', '/ExperimentView', Record<never, never>, Record<never, never>>,
'/HomeView': RouteRecordInfo<'/HomeView', '/HomeView', Record<never, never>, Record<never, never>>,
'/LoginView': RouteRecordInfo<'/LoginView', '/LoginView', Record<never, never>, Record<never, never>>,
'/MainView': RouteRecordInfo<'/MainView', '/MainView', Record<never, never>, Record<never, never>>,
'/TrainingScriptView': RouteRecordInfo<'/TrainingScriptView', '/TrainingScriptView', Record<never, never>, Record<never, never>>,
'/WorkflowStepConfigView': RouteRecordInfo<'/WorkflowStepConfigView', '/WorkflowStepConfigView', Record<never, never>, Record<never, never>>,
'/WorkflowView': RouteRecordInfo<'/WorkflowView', '/WorkflowView', Record<never, never>, Record<never, never>>,
}
}

@ -0,0 +1,90 @@
// Plugins
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import Fonts from 'unplugin-fonts/vite'
import Layouts from 'vite-plugin-vue-layouts-next'
import Vue from '@vitejs/plugin-vue'
import VueRouter from 'unplugin-vue-router/vite'
import { VueRouterAutoImports } from 'unplugin-vue-router'
import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
// Utilities
import { defineConfig } from 'vite'
import { fileURLToPath, URL } from 'node:url'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
VueRouter(),
Layouts(),
Vue({
template: { transformAssetUrls },
}),
// https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme
Vuetify({
autoImport: true,
styles: {
configFile: 'src/styles/settings.scss',
},
}),
Components(),
Fonts({
google: {
families: [{
name: 'Roboto',
styles: 'wght@100;300;400;500;700;900',
}],
},
}),
AutoImport({
imports: [
'vue',
VueRouterAutoImports,
{
pinia: ['defineStore', 'storeToRefs'],
},
],
eslintrc: {
enabled: true,
},
vueTemplate: true,
}),
],
optimizeDeps: {
exclude: [
'vuetify',
'vue-router',
'unplugin-vue-router/runtime',
'unplugin-vue-router/data-loaders',
'unplugin-vue-router/data-loaders/basic',
],
},
define: { 'process.env': {} },
resolve: {
alias: {
'@': fileURLToPath(new URL('src', import.meta.url)),
},
extensions: [
'.js',
'.json',
'.jsx',
'.mjs',
'.ts',
'.tsx',
'.vue',
],
},
server: {
port: 3000,
},
css: {
preprocessorOptions: {
sass: {
api: 'modern-compiler',
},
scss: {
api: 'modern-compiler',
},
},
},
})
Loading…
Cancel
Save