add
This commit is contained in:
commit
295f14e9f4
69
.eslintrc-auto-import.json
Normal file
69
.eslintrc-auto-import.json
Normal file
@ -0,0 +1,69 @@
|
||||
{
|
||||
"globals": {
|
||||
"Component": true,
|
||||
"ComponentPublicInstance": true,
|
||||
"ComputedRef": true,
|
||||
"EffectScope": true,
|
||||
"ExtractDefaultPropTypes": true,
|
||||
"ExtractPropTypes": true,
|
||||
"ExtractPublicPropTypes": true,
|
||||
"InjectionKey": true,
|
||||
"PropType": true,
|
||||
"Ref": true,
|
||||
"VNode": true,
|
||||
"WritableComputedRef": true,
|
||||
"computed": true,
|
||||
"createApp": true,
|
||||
"customRef": true,
|
||||
"defineAsyncComponent": true,
|
||||
"defineComponent": 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,
|
||||
"onBeforeUnmount": true,
|
||||
"onBeforeUpdate": true,
|
||||
"onDeactivated": true,
|
||||
"onErrorCaptured": true,
|
||||
"onMounted": true,
|
||||
"onRenderTracked": true,
|
||||
"onRenderTriggered": true,
|
||||
"onScopeDispose": true,
|
||||
"onServerPrefetch": true,
|
||||
"onUnmounted": true,
|
||||
"onUpdated": true,
|
||||
"provide": true,
|
||||
"reactive": true,
|
||||
"readonly": true,
|
||||
"ref": true,
|
||||
"resolveComponent": true,
|
||||
"shallowReactive": true,
|
||||
"shallowReadonly": true,
|
||||
"shallowRef": true,
|
||||
"toRaw": true,
|
||||
"toRef": true,
|
||||
"toRefs": true,
|
||||
"toValue": true,
|
||||
"triggerRef": true,
|
||||
"unref": true,
|
||||
"useAttrs": true,
|
||||
"useCssModule": true,
|
||||
"useCssVars": true,
|
||||
"useRoute": true,
|
||||
"useRouter": true,
|
||||
"useSlots": true,
|
||||
"watch": true,
|
||||
"watchEffect": true,
|
||||
"watchPostEffect": true,
|
||||
"watchSyncEffect": true
|
||||
}
|
||||
}
|
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
wwwroot/*.js
|
||||
node_modules
|
||||
typings
|
||||
dist
|
||||
.DS_Store
|
||||
.vscode
|
||||
.idea
|
||||
build
|
||||
yarn.lock
|
2171
api/swagger.yaml
Normal file
2171
api/swagger.yaml
Normal file
File diff suppressed because it is too large
Load Diff
13
index.html
Normal file
13
index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>amber-wails</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="./src/main.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
50
package.json
Normal file
50
package.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build2": "vue-tsc --noEmit && vite build",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"gen": "openapi-generator-cli generate -i ./api/swagger.yaml -g typescript-axios -o ./src/api"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"highlight.js": "^11.10.0",
|
||||
"js-base64": "^3.7.7",
|
||||
"lottie-web": "^5.12.2",
|
||||
"pinia": "^2.2.2",
|
||||
"pinia-plugin-persistedstate": "^4.0.0",
|
||||
"vooks": "^0.2.12",
|
||||
"vue": "^3.2.37",
|
||||
"vue-router": "^4.0.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/types": "^7.18.10",
|
||||
"@types/node": "^22.5.4",
|
||||
"@vicons/ionicons5": "^0.12.0",
|
||||
"@vicons/material": "^0.12.0",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.26.0",
|
||||
"naive-ui": "^2.39.0",
|
||||
"postcss": "^8.4.45",
|
||||
"prettier": "^3.3.2",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"typescript": "^5.5.2",
|
||||
"unplugin-auto-import": "^0.18.2",
|
||||
"unplugin-vue-components": "^0.27.4",
|
||||
"unplugin-vue-router": "^0.10.7",
|
||||
"vfonts": "^0.0.3",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-pages": "^0.32.3",
|
||||
"vite-plugin-vue-layouts": "^0.11.0",
|
||||
"vue": "^3.4.30",
|
||||
"vue-tsc": "^2.0.22"
|
||||
}
|
||||
}
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
117
src/App.vue
Normal file
117
src/App.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<!--<script setup lang="ts">-->
|
||||
<!--import DefaultLayout from './layouts/DefaultLayout.vue'-->
|
||||
|
||||
<!--// const ipcHandle = () => window.electron.ipcRenderer.send('ping')-->
|
||||
<!--</script>-->
|
||||
|
||||
<!--<template>-->
|
||||
<!-- <DefaultLayout />-->
|
||||
<!--</template>-->
|
||||
<template>
|
||||
<n-config-provider
|
||||
:date-locale="dateZhCN"
|
||||
:hljs="hljs"
|
||||
:locale="zhCN"
|
||||
:theme="theme"
|
||||
:theme-overrides="themeOverrides"
|
||||
preflight-style-disabled
|
||||
>
|
||||
<n-global-style />
|
||||
<n-loading-bar-provider>
|
||||
<n-message-provider>
|
||||
<n-notification-provider :max="3">
|
||||
<n-dialog-provider>
|
||||
<!-- <!– 加载动画 –>-->
|
||||
<!-- <transition name="fade">-->
|
||||
|
||||
<!-- <div v-show="load_step === 1">-->
|
||||
<!-- <div class="flex h-screen">-->
|
||||
<!-- <div class="m-auto text-center">-->
|
||||
<!-- <Lottie v-if="osThemeRef === 'dark'" :loop="false" name="lae-jump"/>-->
|
||||
<!-- <Lottie v-else :loop="false" name="lae-jump-black"/>-->
|
||||
<!-- <n-h3>莱云</n-h3>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </transition>-->
|
||||
|
||||
<!-- 页面 -->
|
||||
<!-- <transition name="fade">
|
||||
<div v-if="true">
|
||||
<DefaultLayout />
|
||||
</div>
|
||||
</transition> -->
|
||||
<DefaultLayout />
|
||||
</n-dialog-provider>
|
||||
</n-notification-provider>
|
||||
</n-message-provider>
|
||||
</n-loading-bar-provider>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import hljs from 'highlight.js/lib/core'
|
||||
import ini from 'highlight.js/lib/languages/ini'
|
||||
|
||||
import {
|
||||
darkTheme,
|
||||
dateZhCN,
|
||||
NConfigProvider,
|
||||
NDialogProvider,
|
||||
NGlobalStyle,
|
||||
NLoadingBarProvider,
|
||||
NMessageProvider,
|
||||
NNotificationProvider,
|
||||
useOsTheme,
|
||||
zhCN
|
||||
} from 'naive-ui'
|
||||
// import Lottie from "./components/Lottie.vue";
|
||||
import DefaultLayout from './layouts/DefaultLayout.vue'
|
||||
import { useUserStore } from './stores/user'
|
||||
|
||||
const osThemeRef = useOsTheme()
|
||||
const theme = computed(() => (osThemeRef.value === 'dark' ? darkTheme : null))
|
||||
|
||||
// const load_step = ref(1)
|
||||
//
|
||||
// if (process.env.NODE_ENV === 'production') {
|
||||
// window.onload = () => {
|
||||
// setTimeout(() => {
|
||||
// load_step.value = 1
|
||||
// setTimeout(() => {
|
||||
// load_step.value = 2
|
||||
// }, 500)
|
||||
// }, 250)
|
||||
// }
|
||||
// } else {
|
||||
// load_step.value = 2
|
||||
// }
|
||||
|
||||
hljs.registerLanguage('ini', ini)
|
||||
|
||||
// 主题调整
|
||||
/**
|
||||
* js 文件下使用这个做类型提示
|
||||
* @type import('naive-ui').GlobalThemeOverrides
|
||||
*/
|
||||
// const themeOverrides = {
|
||||
// common: {
|
||||
// primaryColor: '#ec4b2d',
|
||||
// primaryColorHover: '#ec4b2d',
|
||||
// },
|
||||
// Button: {
|
||||
// textColor: '#ec4b2d'
|
||||
// },
|
||||
//
|
||||
// }
|
||||
|
||||
const themeOverrides = {}
|
||||
|
||||
|
||||
|
||||
// UserStore
|
||||
const userStore = useUserStore();
|
||||
userStore.setupTimer();
|
||||
|
||||
</script>
|
4
src/api/.gitignore
vendored
Normal file
4
src/api/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
wwwroot/*.js
|
||||
node_modules
|
||||
typings
|
||||
dist
|
1
src/api/.npmignore
Normal file
1
src/api/.npmignore
Normal file
@ -0,0 +1 @@
|
||||
# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm
|
23
src/api/.openapi-generator-ignore
Normal file
23
src/api/.openapi-generator-ignore
Normal file
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
9
src/api/.openapi-generator/FILES
Normal file
9
src/api/.openapi-generator/FILES
Normal file
@ -0,0 +1,9 @@
|
||||
.gitignore
|
||||
.npmignore
|
||||
.openapi-generator-ignore
|
||||
api.ts
|
||||
base.ts
|
||||
common.ts
|
||||
configuration.ts
|
||||
git_push.sh
|
||||
index.ts
|
1
src/api/.openapi-generator/VERSION
Normal file
1
src/api/.openapi-generator/VERSION
Normal file
@ -0,0 +1 @@
|
||||
7.8.0
|
5854
src/api/api.ts
Normal file
5854
src/api/api.ts
Normal file
File diff suppressed because it is too large
Load Diff
86
src/api/base.ts
Normal file
86
src/api/base.ts
Normal file
@ -0,0 +1,86 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Leaflow Amber
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
import type { Configuration } from './configuration';
|
||||
// Some imports not used depending on template conditions
|
||||
// @ts-ignore
|
||||
import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios';
|
||||
import globalAxios from 'axios';
|
||||
|
||||
export const BASE_PATH = "http://localhost".replace(/\/+$/, "");
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const COLLECTION_FORMATS = {
|
||||
csv: ",",
|
||||
ssv: " ",
|
||||
tsv: "\t",
|
||||
pipes: "|",
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface RequestArgs
|
||||
*/
|
||||
export interface RequestArgs {
|
||||
url: string;
|
||||
options: RawAxiosRequestConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @class BaseAPI
|
||||
*/
|
||||
export class BaseAPI {
|
||||
protected configuration: Configuration | undefined;
|
||||
|
||||
constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) {
|
||||
if (configuration) {
|
||||
this.configuration = configuration;
|
||||
this.basePath = configuration.basePath ?? basePath;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @class RequiredError
|
||||
* @extends {Error}
|
||||
*/
|
||||
export class RequiredError extends Error {
|
||||
constructor(public field: string, msg?: string) {
|
||||
super(msg);
|
||||
this.name = "RequiredError"
|
||||
}
|
||||
}
|
||||
|
||||
interface ServerMap {
|
||||
[key: string]: {
|
||||
url: string,
|
||||
description: string,
|
||||
}[];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const operationServerMap: ServerMap = {
|
||||
}
|
150
src/api/common.ts
Normal file
150
src/api/common.ts
Normal file
@ -0,0 +1,150 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Leaflow Amber
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
import type { Configuration } from "./configuration";
|
||||
import type { RequestArgs } from "./base";
|
||||
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { RequiredError } from "./base";
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const DUMMY_BASE_URL = 'https://example.com'
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws {RequiredError}
|
||||
* @export
|
||||
*/
|
||||
export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) {
|
||||
if (paramValue === null || paramValue === undefined) {
|
||||
throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) {
|
||||
if (configuration && configuration.apiKey) {
|
||||
const localVarApiKeyValue = typeof configuration.apiKey === 'function'
|
||||
? await configuration.apiKey(keyParamName)
|
||||
: await configuration.apiKey;
|
||||
object[keyParamName] = localVarApiKeyValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setBasicAuthToObject = function (object: any, configuration?: Configuration) {
|
||||
if (configuration && (configuration.username || configuration.password)) {
|
||||
object["auth"] = { username: configuration.username, password: configuration.password };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) {
|
||||
if (configuration && configuration.accessToken) {
|
||||
const accessToken = typeof configuration.accessToken === 'function'
|
||||
? await configuration.accessToken()
|
||||
: await configuration.accessToken;
|
||||
object["Authorization"] = "Bearer " + accessToken;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) {
|
||||
if (configuration && configuration.accessToken) {
|
||||
const localVarAccessTokenValue = typeof configuration.accessToken === 'function'
|
||||
? await configuration.accessToken(name, scopes)
|
||||
: await configuration.accessToken;
|
||||
object["Authorization"] = "Bearer " + localVarAccessTokenValue;
|
||||
}
|
||||
}
|
||||
|
||||
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
|
||||
if (parameter == null) return;
|
||||
if (typeof parameter === "object") {
|
||||
if (Array.isArray(parameter)) {
|
||||
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
|
||||
}
|
||||
else {
|
||||
Object.keys(parameter).forEach(currentKey =>
|
||||
setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (urlSearchParams.has(key)) {
|
||||
urlSearchParams.append(key, parameter);
|
||||
}
|
||||
else {
|
||||
urlSearchParams.set(key, parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setSearchParams = function (url: URL, ...objects: any[]) {
|
||||
const searchParams = new URLSearchParams(url.search);
|
||||
setFlattenedQueryParams(searchParams, objects);
|
||||
url.search = searchParams.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
|
||||
const nonString = typeof value !== 'string';
|
||||
const needsSerialization = nonString && configuration && configuration.isJsonMime
|
||||
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
|
||||
: nonString;
|
||||
return needsSerialization
|
||||
? JSON.stringify(value !== undefined ? value : {})
|
||||
: (value || "");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const toPathString = function (url: URL) {
|
||||
return url.pathname + url.search + url.hash
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) {
|
||||
return <T = unknown, R = AxiosResponse<T>>(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||
const axiosRequestArgs = {...axiosArgs.options, url: (axios.defaults.baseURL ? '' : configuration?.basePath ?? basePath) + axiosArgs.url};
|
||||
return axios.request<T, R>(axiosRequestArgs);
|
||||
};
|
||||
}
|
110
src/api/configuration.ts
Normal file
110
src/api/configuration.ts
Normal file
@ -0,0 +1,110 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Leaflow Amber
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
export interface ConfigurationParameters {
|
||||
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
||||
username?: string;
|
||||
password?: string;
|
||||
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
||||
basePath?: string;
|
||||
serverIndex?: number;
|
||||
baseOptions?: any;
|
||||
formDataCtor?: new () => any;
|
||||
}
|
||||
|
||||
export class Configuration {
|
||||
/**
|
||||
* parameter for apiKey security
|
||||
* @param name security name
|
||||
* @memberof Configuration
|
||||
*/
|
||||
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
||||
/**
|
||||
* parameter for basic security
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
username?: string;
|
||||
/**
|
||||
* parameter for basic security
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
password?: string;
|
||||
/**
|
||||
* parameter for oauth2 security
|
||||
* @param name security name
|
||||
* @param scopes oauth2 scope
|
||||
* @memberof Configuration
|
||||
*/
|
||||
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
||||
/**
|
||||
* override base path
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
basePath?: string;
|
||||
/**
|
||||
* override server index
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
serverIndex?: number;
|
||||
/**
|
||||
* base options for axios calls
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
baseOptions?: any;
|
||||
/**
|
||||
* The FormData constructor that will be used to create multipart form data
|
||||
* requests. You can inject this here so that execution environments that
|
||||
* do not support the FormData class can still run the generated client.
|
||||
*
|
||||
* @type {new () => FormData}
|
||||
*/
|
||||
formDataCtor?: new () => any;
|
||||
|
||||
constructor(param: ConfigurationParameters = {}) {
|
||||
this.apiKey = param.apiKey;
|
||||
this.username = param.username;
|
||||
this.password = param.password;
|
||||
this.accessToken = param.accessToken;
|
||||
this.basePath = param.basePath;
|
||||
this.serverIndex = param.serverIndex;
|
||||
this.baseOptions = param.baseOptions;
|
||||
this.formDataCtor = param.formDataCtor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given MIME is a JSON MIME.
|
||||
* JSON MIME examples:
|
||||
* application/json
|
||||
* application/json; charset=UTF8
|
||||
* APPLICATION/JSON
|
||||
* application/vnd.company+json
|
||||
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
||||
* @return True if the given MIME is JSON, false otherwise.
|
||||
*/
|
||||
public isJsonMime(mime: string): boolean {
|
||||
const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
|
||||
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
|
||||
}
|
||||
}
|
57
src/api/git_push.sh
Normal file
57
src/api/git_push.sh
Normal file
@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
|
||||
#
|
||||
# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com"
|
||||
|
||||
git_user_id=$1
|
||||
git_repo_id=$2
|
||||
release_note=$3
|
||||
git_host=$4
|
||||
|
||||
if [ "$git_host" = "" ]; then
|
||||
git_host="github.com"
|
||||
echo "[INFO] No command line input provided. Set \$git_host to $git_host"
|
||||
fi
|
||||
|
||||
if [ "$git_user_id" = "" ]; then
|
||||
git_user_id="GIT_USER_ID"
|
||||
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
|
||||
fi
|
||||
|
||||
if [ "$git_repo_id" = "" ]; then
|
||||
git_repo_id="GIT_REPO_ID"
|
||||
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
|
||||
fi
|
||||
|
||||
if [ "$release_note" = "" ]; then
|
||||
release_note="Minor update"
|
||||
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
|
||||
fi
|
||||
|
||||
# Initialize the local directory as a Git repository
|
||||
git init
|
||||
|
||||
# Adds the files in the local repository and stages them for commit.
|
||||
git add .
|
||||
|
||||
# Commits the tracked changes and prepares them to be pushed to a remote repository.
|
||||
git commit -m "$release_note"
|
||||
|
||||
# Sets the new remote
|
||||
git_remote=$(git remote)
|
||||
if [ "$git_remote" = "" ]; then # git remote not defined
|
||||
|
||||
if [ "$GIT_TOKEN" = "" ]; then
|
||||
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
|
||||
git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git
|
||||
else
|
||||
git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
git pull origin master
|
||||
|
||||
# Pushes (Forces) the changes in the local repository up to the remote repository
|
||||
echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git"
|
||||
git push origin master 2>&1 | grep -v 'To https'
|
18
src/api/index.ts
Normal file
18
src/api/index.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Leaflow Amber
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
export * from "./api";
|
||||
export * from "./configuration";
|
||||
|
93
src/assets/fonts/OFL.txt
Normal file
93
src/assets/fonts/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
src/assets/fonts/nunito-v16-latin-regular.woff2
Normal file
BIN
src/assets/fonts/nunito-v16-latin-regular.woff2
Normal file
Binary file not shown.
BIN
src/assets/images/logo-universal.png
Normal file
BIN
src/assets/images/logo-universal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
129
src/auto-imports.d.ts
vendored
Normal file
129
src/auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
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 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 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 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 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 useRoute: typeof import('vue-router/auto')['useRoute']
|
||||
const useRouter: typeof import('vue-router/auto')['useRouter']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
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, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, 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 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 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 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 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 useRoute: UnwrapRef<typeof import('vue-router/auto')['useRoute']>
|
||||
readonly useRouter: UnwrapRef<typeof import('vue-router/auto')['useRouter']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
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']>
|
||||
}
|
||||
}
|
15
src/components.d.ts
vendored
Normal file
15
src/components.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/* 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 {
|
||||
Container: typeof import('./components/Container.vue')['default']
|
||||
Menu: typeof import('./components/Menu.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
}
|
22
src/components/Container.vue
Normal file
22
src/components/Container.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import router from '../plugins/router';
|
||||
|
||||
const currentRoute = computed(() => router.currentRoute.value.name)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <Header style="min-height: var(--header-height)"></Header> -->
|
||||
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition mode="out-in" name="fade">
|
||||
<div>
|
||||
<component :is="Component" />
|
||||
</div>
|
||||
</transition>
|
||||
</router-view>
|
||||
|
||||
<!-- <router-view></router-view> -->
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
57
src/components/Menu.vue
Normal file
57
src/components/Menu.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<n-menu
|
||||
:value="currentRoute"
|
||||
:collapsed="collapsed"
|
||||
:collapsed-width="64"
|
||||
:collapsed-icon-size="22"
|
||||
:options="menuOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { NIcon, NMenu } from 'naive-ui'
|
||||
import { Home as HomeIcon } from '@vicons/ionicons5'
|
||||
import type { MenuOption } from 'naive-ui'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const currentRoute: any = computed(() => route.name)
|
||||
|
||||
const collapsed = ref(false)
|
||||
const menuOptions: MenuOption[] = [
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
RouterLink,
|
||||
{
|
||||
to: {
|
||||
name: '/'
|
||||
}
|
||||
},
|
||||
{ default: () => 'Amber' }
|
||||
),
|
||||
key: '/',
|
||||
icon: renderIcon(HomeIcon)
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
RouterLink,
|
||||
{
|
||||
to: {
|
||||
name: '/auth/login'
|
||||
}
|
||||
},
|
||||
{ default: () => 'Login' }
|
||||
),
|
||||
key: '/auth/login',
|
||||
icon: renderIcon(HomeIcon)
|
||||
}
|
||||
]
|
||||
|
||||
function renderIcon(icon: Component) {
|
||||
return () => h(NIcon, null, { default: () => h(icon) })
|
||||
}
|
||||
</script>
|
25
src/config/config.ts
Normal file
25
src/config/config.ts
Normal file
@ -0,0 +1,25 @@
|
||||
const config = {
|
||||
app_name: "Amber",
|
||||
oauth_discovery_url:
|
||||
"https://auth.leaflow.cn/.well-known/openid-configuration",
|
||||
oauth_client_id: "90020",
|
||||
oauth_callback_url: "amber-desktop://auth_callback",
|
||||
oauth_storage_key: "code_verifier",
|
||||
oauth_scope: "openid profile",
|
||||
backend: "http://localhost:8080",
|
||||
};
|
||||
|
||||
// @ts-ignore ...
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
config.backend = "https://amber-api.leaflow.cn";
|
||||
config.oauth_callback_url = "https://amber.leaflow.cn/auth/callback";
|
||||
config.oauth_client_id = "16";
|
||||
}
|
||||
|
||||
config.backend = "https://amber-api.leaflow.cn";
|
||||
|
||||
// config.backend = "https://amber-api.leaflow.cn";
|
||||
|
||||
// console.log("api endpoint: " + config.backend);
|
||||
|
||||
export default config;
|
8
src/env.d.ts
vendored
Normal file
8
src/env.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
45
src/layouts/DefaultLayout.vue
Normal file
45
src/layouts/DefaultLayout.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
import Container from "../components/Container.vue";
|
||||
import { NLayout, NLayoutContent, NLayoutSider } from "naive-ui";
|
||||
import { useIsMobile } from "../utils/composables.js";
|
||||
import Menu from "../components/Menu.vue";
|
||||
import { useUserStore } from "../stores/user";
|
||||
import Guest from "../pages/guest/index.vue";
|
||||
import router from "../plugins/router";
|
||||
const currentRoute = computed(() => router.currentRoute.value.name);
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
// import Header from './Header.vue'
|
||||
const isMobile = useIsMobile();
|
||||
// const isTablet = useIsTablet()
|
||||
const menuCollapsed = ref({
|
||||
left: false,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-layout :position="isMobile ? 'static' : 'absolute'" :has-sider="true">
|
||||
<n-layout-sider
|
||||
v-if="userStore.logined"
|
||||
:collapsed-width="0"
|
||||
:native-scrollbar="false"
|
||||
:show-collapsed-content="false"
|
||||
:width="240"
|
||||
bordered
|
||||
collapse-mode="width"
|
||||
show-trigger="arrow-circle"
|
||||
class="select-none"
|
||||
@collapse="menuCollapsed.left = true"
|
||||
@expand="menuCollapsed.left = false"
|
||||
>
|
||||
<Menu></Menu>
|
||||
</n-layout-sider>
|
||||
<n-layout-content>
|
||||
<!-- <Guest v-if="!userStore.logined && currentRoute != '/auth/login'" />
|
||||
<Container v-else /> -->
|
||||
<Guest v-if="!userStore.logined && !currentRoute?.startsWith('/auth')" />
|
||||
<Container v-else />
|
||||
</n-layout-content>
|
||||
</n-layout>
|
||||
</template>
|
23
src/layouts/Header.vue
Normal file
23
src/layouts/Header.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<n-layout>
|
||||
<n-layout-header bordered class="layout-header header-height">
|
||||
<n-grid cols="2" class="header-height">
|
||||
<n-grid-item class="flex items-center justify-start mr-1.5">
|
||||
<div>left</div>
|
||||
</n-grid-item>
|
||||
|
||||
<n-grid-item class="flex items-center justify-end mr-1.5">
|
||||
<div>right</div>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-layout-header>
|
||||
</n-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.header-height {
|
||||
min-height: var(--header-height);
|
||||
}
|
||||
</style>
|
32
src/main.ts
Normal file
32
src/main.ts
Normal file
@ -0,0 +1,32 @@
|
||||
const meta = document.createElement("meta");
|
||||
meta.name = "naive-ui-style";
|
||||
document.head.appendChild(meta);
|
||||
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
import naive from "naive-ui";
|
||||
// 通用字体
|
||||
import "vfonts/Lato.css";
|
||||
// 等宽字体
|
||||
import "vfonts/FiraCode.css";
|
||||
|
||||
|
||||
import App from "./App.vue";
|
||||
import router from "./plugins/router";
|
||||
|
||||
|
||||
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(pinia);
|
||||
app.use(naive);
|
||||
app.use(router);
|
||||
|
||||
app.mount("#app");
|
52
src/pages/auth/callback.vue
Normal file
52
src/pages/auth/callback.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>请稍等片刻</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import axios from "axios";
|
||||
import { useUserStore } from "../../stores/user";
|
||||
import router from "../../plugins/router";
|
||||
import config from "../../config/config";
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
axios.get(config.oauth_discovery_url).then((discovery) => {
|
||||
const localCodeVerifier = localStorage.getItem(config.oauth_storage_key);
|
||||
|
||||
const code: any = router.currentRoute.value.query.code;
|
||||
|
||||
// 从当前页面请求中获取 code
|
||||
const q = new URLSearchParams({
|
||||
client_id: config.oauth_client_id,
|
||||
grant_type: "authorization_code",
|
||||
redirect_uri: config.oauth_callback_url,
|
||||
code_verifier: localCodeVerifier || "",
|
||||
code: code ?? "",
|
||||
});
|
||||
|
||||
const tokenEndpoint = discovery.data.token_endpoint;
|
||||
axios
|
||||
.post(tokenEndpoint, q)
|
||||
.then((r) => {
|
||||
userStore.access_token = r.data.access_token;
|
||||
userStore.refresh_token = r.data.refresh_token;
|
||||
|
||||
userStore.login(
|
||||
r.data.id_token,
|
||||
r.data.access_token,
|
||||
r.data.refresh_token,
|
||||
r.data.expires_in,
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
alert("登录失败");
|
||||
})
|
||||
.finally(() => {
|
||||
// 跳转到 /
|
||||
router.push("/");
|
||||
});
|
||||
});
|
||||
</script>
|
5
src/pages/auth/continue.vue
Normal file
5
src/pages/auth/continue.vue
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>请在新窗口中继续登录</h1>
|
||||
</div>
|
||||
</template>
|
59
src/pages/auth/login.vue
Normal file
59
src/pages/auth/login.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>请稍后...</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script async setup lang="ts">
|
||||
import config from "../../config/config";
|
||||
import axios from "axios";
|
||||
import router from "../../plugins/router";
|
||||
|
||||
function generateRandomString(length: number) {
|
||||
let text = "";
|
||||
const possible =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
async function generateCodeChallenge(codeVerifier: string) {
|
||||
const digest = await crypto.subtle.digest(
|
||||
"SHA-256",
|
||||
new TextEncoder().encode(codeVerifier),
|
||||
);
|
||||
|
||||
return btoa(String.fromCharCode(...new Uint8Array(digest)))
|
||||
.replace(/=/g, "")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_");
|
||||
}
|
||||
|
||||
async function go() {
|
||||
const codeVerifier = generateRandomString(128);
|
||||
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
||||
localStorage.setItem(config.oauth_storage_key, codeVerifier);
|
||||
|
||||
const query = new URLSearchParams({
|
||||
client_id: config.oauth_client_id,
|
||||
redirect_uri: config.oauth_callback_url,
|
||||
response_type: "code",
|
||||
scope: config.oauth_scope,
|
||||
code_challenge: codeChallenge,
|
||||
code_challenge_method: "S256",
|
||||
}).toString();
|
||||
|
||||
const discovery = await axios.get(config.oauth_discovery_url);
|
||||
|
||||
const a = document.createElement('a')
|
||||
a.href = discovery.data.authorization_endpoint + '?' + query
|
||||
a.click()
|
||||
|
||||
}
|
||||
|
||||
go();
|
||||
</script>
|
24
src/pages/guest/index.vue
Normal file
24
src/pages/guest/index.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div class="flex items-center align-center justify-center h-full">
|
||||
<div class="text-center">
|
||||
|
||||
<div class="mt-5 !ml-2">
|
||||
<n-h1> 满身星光,不负众望 </n-h1>
|
||||
<n-p> </n-p>
|
||||
</div>
|
||||
<br />
|
||||
<n-button v-if="!userStore.logined" type="primary" @click="login"> 登录 </n-button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import router from "../../plugins/router";
|
||||
import { useUserStore } from "../../stores/user";
|
||||
const userStore = useUserStore();
|
||||
|
||||
const login = () => {
|
||||
router.push("/auth/login");
|
||||
};
|
||||
</script>
|
46
src/pages/index.vue
Normal file
46
src/pages/index.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<script setup lang="ts">
|
||||
import { useMessage } from "naive-ui";
|
||||
import { useUserStore } from "../stores/user";
|
||||
const message = useMessage();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: "滨海湾金沙,新加坡",
|
||||
key: "marina bay sands",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
label: "布朗酒店,伦敦",
|
||||
key: "brown's hotel, london",
|
||||
},
|
||||
{
|
||||
label: "亚特兰蒂斯巴哈马,拿骚",
|
||||
key: "atlantis nahamas, nassau",
|
||||
},
|
||||
{
|
||||
label: "比佛利山庄酒店,洛杉矶",
|
||||
key: "the beverly hills hotel, los angeles",
|
||||
},
|
||||
];
|
||||
function handleSelect(key: string | number) {
|
||||
message.info(String(key));
|
||||
}
|
||||
|
||||
function logout() {
|
||||
userStore.logout();
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<router-link to="auth/login">go</router-link>
|
||||
<n-dropdown trigger="hover" :options="options" @select="handleSelect">
|
||||
<n-button>找个地方休息111</n-button>
|
||||
</n-dropdown>
|
||||
|
||||
<n-button @click="logout()">退出登录</n-button>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
36
src/plugins/api.ts
Normal file
36
src/plugins/api.ts
Normal file
@ -0,0 +1,36 @@
|
||||
// import {
|
||||
// AssistantApi,
|
||||
// ChatApi,
|
||||
// ChatMessageApi,
|
||||
// ChatPublicApi,
|
||||
// Configuration,
|
||||
// PingApi,
|
||||
// ToolApi,
|
||||
// } from "@/api";
|
||||
// import config from "@/config/config";
|
||||
// import { useUserStore } from "@/stores/user";
|
||||
//
|
||||
// const userStore = useUserStore();
|
||||
//
|
||||
// const conf = new Configuration();
|
||||
//
|
||||
// conf.basePath = config.backend;
|
||||
// conf.apiKey = () => {
|
||||
// return "Bearer " + userStore.id_token;
|
||||
// };
|
||||
|
||||
// userStore.$subscribe((mutation, state) => {
|
||||
// console.log(mutation);
|
||||
// conf.apiKey = "Bearer " + state.id_token;
|
||||
// });
|
||||
|
||||
// const api = {
|
||||
// Chat: new ChatApi(conf),
|
||||
// Assistant: new AssistantApi(conf),
|
||||
// Ping: new PingApi(conf),
|
||||
// Tool: new ToolApi(conf),
|
||||
// ChatMessage: new ChatMessageApi(conf),
|
||||
// ChatPublic: new ChatPublicApi(conf),
|
||||
// };
|
||||
//
|
||||
// export { api, conf };
|
5
src/plugins/axios.ts
Normal file
5
src/plugins/axios.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import axios from 'axios'
|
||||
|
||||
// axios.defaults.adapter = window.axiosHttpAdapter
|
||||
|
||||
export default axios
|
10
src/plugins/router.ts
Normal file
10
src/plugins/router.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import { routes } from 'vue-router/auto-routes'
|
||||
import { setupLayouts } from 'virtual:generated-layouts'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: setupLayouts(routes)
|
||||
})
|
||||
|
||||
export default router
|
31
src/stores/app.ts
Normal file
31
src/stores/app.ts
Normal file
@ -0,0 +1,31 @@
|
||||
// Utilities
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useAppStore = defineStore("app", {
|
||||
persist: false,
|
||||
state: () => ({
|
||||
navigation_drawer: false,
|
||||
navigation_items: [
|
||||
{
|
||||
icon: "mdi-home",
|
||||
text: "主页",
|
||||
to: "/",
|
||||
},
|
||||
{
|
||||
icon: "mdi-assistant",
|
||||
text: "助理",
|
||||
to: "/assistants",
|
||||
},
|
||||
{
|
||||
icon: "mdi-tools",
|
||||
text: "工具",
|
||||
to: "/tools",
|
||||
},
|
||||
{
|
||||
icon: "mdi-key",
|
||||
text: "令牌",
|
||||
to: "/tokens",
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
102
src/stores/user.ts
Normal file
102
src/stores/user.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { defineStore } from "pinia";
|
||||
import axios from "axios";
|
||||
import config from "../config/config";
|
||||
import { Base64 } from "js-base64";
|
||||
|
||||
let timer: any = null;
|
||||
|
||||
export const useUserStore = defineStore("user", {
|
||||
persist: true,
|
||||
state: () => ({
|
||||
logined: false,
|
||||
id_token: "",
|
||||
refresh_token: "",
|
||||
access_token: "",
|
||||
expired_at: 0,
|
||||
user: {
|
||||
id: 0,
|
||||
name: "",
|
||||
email: "",
|
||||
},
|
||||
timer: 0,
|
||||
}),
|
||||
actions: {
|
||||
login(
|
||||
idToken: string,
|
||||
accessToken: string,
|
||||
refreshToken: string,
|
||||
expiredAt: number,
|
||||
) {
|
||||
const idTokenParts = idToken.split(".");
|
||||
|
||||
const idTokenPayload = JSON.parse(Base64.decode(idTokenParts[1]));
|
||||
|
||||
expiredAt = Date.now() + expiredAt * 1000;
|
||||
this.expired_at = expiredAt;
|
||||
|
||||
this.refresh_token = refreshToken;
|
||||
this.access_token = accessToken;
|
||||
|
||||
this.id_token = idToken;
|
||||
this.user.email = idTokenPayload.email;
|
||||
this.user.name = idTokenPayload.name;
|
||||
this.user.id = idTokenPayload.sub;
|
||||
this.logined = true;
|
||||
},
|
||||
checkAndRefresh() {
|
||||
if (this.logined) {
|
||||
if (this.expired_at - Date.now() < 60000) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
},
|
||||
setupTimer() {
|
||||
this.checkAndRefresh();
|
||||
timer = setInterval(() => {
|
||||
this.checkAndRefresh();
|
||||
}, 10 * 1000);
|
||||
},
|
||||
async refresh() {
|
||||
const discovery = await axios.get(config.oauth_discovery_url);
|
||||
|
||||
// post /oauth/token to refresh
|
||||
// 构建 form 参数
|
||||
const data = new URLSearchParams();
|
||||
data.set("grant_type", "refresh_token");
|
||||
data.set("refresh_token", this.refresh_token);
|
||||
data.set("client_id", config.oauth_client_id);
|
||||
data.set("scope", config.oauth_scope);
|
||||
|
||||
axios
|
||||
.post(discovery.data.token_endpoint, data)
|
||||
.then((response) => {
|
||||
this.login(
|
||||
response.data.id_token,
|
||||
response.data.access_token,
|
||||
response.data.refresh_token,
|
||||
response.data.expires_in,
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
// if 401
|
||||
if (error.response.status === 401) {
|
||||
console.log("Refresh token failed");
|
||||
}
|
||||
// logout
|
||||
this.logout();
|
||||
clearInterval(timer);
|
||||
});
|
||||
},
|
||||
logout() {
|
||||
this.user = {
|
||||
id: 0,
|
||||
name: "",
|
||||
email: "",
|
||||
};
|
||||
|
||||
this.id_token = "";
|
||||
this.logined = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
7
src/style.css
Normal file
7
src/style.css
Normal file
@ -0,0 +1,7 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
--header-height: 32px;
|
||||
}
|
27
src/typed-router.d.ts
vendored
Normal file
27
src/typed-router.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/* 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>>,
|
||||
'/auth/callback': RouteRecordInfo<'/auth/callback', '/auth/callback', Record<never, never>, Record<never, never>>,
|
||||
'/auth/continue': RouteRecordInfo<'/auth/continue', '/auth/continue', Record<never, never>, Record<never, never>>,
|
||||
'/auth/login': RouteRecordInfo<'/auth/login', '/auth/login', Record<never, never>, Record<never, never>>,
|
||||
'/guest/': RouteRecordInfo<'/guest/', '/guest', Record<never, never>, Record<never, never>>,
|
||||
}
|
||||
}
|
45
src/utils/composables.ts
Normal file
45
src/utils/composables.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { inject, provide, reactive, toRef, watchEffect } from 'vue'
|
||||
import { useBreakpoint, useMemo } from 'vooks'
|
||||
|
||||
export function useIsMobile() {
|
||||
const breakpointRef = useBreakpoint()
|
||||
return useMemo(() => {
|
||||
return breakpointRef.value === 'xs'
|
||||
})
|
||||
}
|
||||
|
||||
export function useIsTablet() {
|
||||
const breakpointRef = useBreakpoint()
|
||||
return useMemo(() => {
|
||||
return breakpointRef.value === 's'
|
||||
})
|
||||
}
|
||||
|
||||
export function useIsSmallDesktop() {
|
||||
const breakpointRef = useBreakpoint()
|
||||
return useMemo(() => {
|
||||
return breakpointRef.value === 'm'
|
||||
})
|
||||
}
|
||||
|
||||
export const i18n = function (data: any) {
|
||||
const localeReactive = inject('i18n', null)
|
||||
return {
|
||||
// @ts-ignore ...
|
||||
locale: toRef(localeReactive, 'locale'),
|
||||
t(key: any) {
|
||||
// @ts-ignore ...
|
||||
const { locale } = localeReactive
|
||||
return data[locale][key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i18n.provide = function (localeRef: any) {
|
||||
const localeReactive = reactive({})
|
||||
watchEffect(() => {
|
||||
// @ts-ignore ...
|
||||
localeReactive.locale = localeRef.value
|
||||
})
|
||||
provide('i18n', localeReactive)
|
||||
}
|
7
src/vite-env.d.ts
vendored
Normal file
7
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type {DefineComponent} from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
8
tailwind.config.js
Normal file
8
tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"unplugin-vue-router/client"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
11
tsconfig.node.json
Normal file
11
tsconfig.node.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
57
vite.config.ts
Normal file
57
vite.config.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { defineConfig } from "vite"
|
||||
import vue from "@vitejs/plugin-vue"
|
||||
import VueRouter from "unplugin-vue-router/vite"
|
||||
import Layouts from "vite-plugin-vue-layouts"
|
||||
import Components from "unplugin-vue-components/vite"
|
||||
import AutoImport from "unplugin-auto-import/vite"
|
||||
// import { resolve } from "path";
|
||||
// const rootPath = new URL(".", import.meta.url).pathname;
|
||||
|
||||
import { fileURLToPath, URL } from "node:url"
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
extensions: [".js", ".json", ".jsx", ".mjs", ".ts", ".tsx", ".vue"],
|
||||
},
|
||||
plugins: [
|
||||
VueRouter({
|
||||
dts: "src/typed-router.d.ts",
|
||||
routesFolder: [
|
||||
{
|
||||
src: "src/pages",
|
||||
path: "",
|
||||
// override globals
|
||||
exclude: (excluded) => excluded,
|
||||
filePatterns: (filePatterns) => filePatterns,
|
||||
extensions: (extensions) => extensions,
|
||||
},
|
||||
],
|
||||
}),
|
||||
vue(),
|
||||
Layouts(),
|
||||
AutoImport({
|
||||
imports: [
|
||||
"vue",
|
||||
{
|
||||
"vue-router/auto": ["useRoute", "useRouter"],
|
||||
},
|
||||
],
|
||||
dts: "src/auto-imports.d.ts",
|
||||
eslintrc: {
|
||||
enabled: true,
|
||||
},
|
||||
vueTemplate: true,
|
||||
}),
|
||||
Components({
|
||||
dts: "src/components.d.ts",
|
||||
}),
|
||||
],
|
||||
server: {
|
||||
host: true,
|
||||
port: 5173,
|
||||
strictPort: true,
|
||||
},
|
||||
})
|
Loading…
Reference in New Issue
Block a user