feat: enhance project configuration and add new features

This commit is contained in:
严浩
2025-09-09 18:19:23 +08:00
parent 88483c26e6
commit 4851b83c37
28 changed files with 4323 additions and 37 deletions

View File

@@ -11,12 +11,19 @@ const getName = async () => {
</script>
<template>
<h1>You did it!</h1>
<p>
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation
</p>
<button class="green" @click="getName" aria-label="get name">Name from API is: {{ name }}</button>
<div>
<h1>You did it!</h1>
<p>
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation
</p>
<button class="green" @click="getName" aria-label="get name">
Name from API is: {{ name }}
</button>
</div>
<DynamicDialog /> <ConfirmDialog /> <Toast />
<RouterView />
</template>
<style scoped></style>

View File

@@ -0,0 +1,10 @@
<script setup lang="ts"></script>
<template>
<div>
<div>AppLayout</div>
<router-view />
</div>
</template>
<style scoped></style>

View File

@@ -1,12 +1,13 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import './styles'
// import { LogLevels } from 'consola';
// consola.level = LogLevels.verbose;
import App from './App.vue'
import router from './router'
const app = createApp(App)
const autoInstallModules = import.meta.glob('./plugins/!(index).ts', { eager: true })
app.use(createPinia())
app.use(router)
// import { setupPlugins } from './plugins'
const setupPlugins = (await import('./plugins')).setupPlugins
app.mount('#app')
setupPlugins(createApp(App), autoInstallModules).mount('#app')

View File

@@ -0,0 +1,16 @@
<script lang="ts" setup>
defineProps<{ path: string }>()
</script>
<template>
<main flex-1 class="flex flex-col items-center justify-center h-full space-y-4">
<h1>Not Found</h1>
<p>{{ path }} does not exist.</p>
<Button @click="$router.back()">Back</Button>
</main>
</template>
<route lang="yaml">
props: true
meta:
layout: false
</route>

7
src/pages/index.page.vue Normal file
View File

@@ -0,0 +1,7 @@
<script setup lang="ts"></script>
<template>
<div></div>
</template>
<style scoped></style>

32
src/plugins/_.ts Normal file
View File

@@ -0,0 +1,32 @@
import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { createHead } from '@unhead/vue/client'
export function install({ app }: { app: import('vue').App<Element> }) {
app.config.globalProperties.__DEV__ = __DEV__
app.use(autoAnimatePlugin) // v-auto-animate="{ duration: 100 }"
app.use(createHead())
app.config.errorHandler = (error, instance, info) => {
console.error('Global error:', error)
console.error('Component:', instance)
console.error('Error Info:', info)
// 这里你可以:
// 1. 发送错误到日志服务
// 2. 显示全局错误提示
// 3. 进行错误分析和处理
}
// if (import.meta.env.MODE === 'development' && '1' === ('2' as never)) {
// // TODO: https://github.com/hu3dao/vite-plugin-debug/
// // https://eruda.liriliri.io/zh/docs/#快速上手
// import('eruda').then(({ default: eruda }) => {
// eruda.init({
// defaults: {
// transparency: 0.9,
// },
// })
// /* eruda.show(); */
// })
// }
}

24
src/plugins/index.ts Normal file
View File

@@ -0,0 +1,24 @@
/**
* https://github.com/antfu-collective/vitesse/blob/47618e72dfba76c77b9b85b94784d739e35c492b/src/modules/README.md
*/
type UserPlugin = (ctx: UserPluginContext) => void
type AutoInstallModule = { [K: string]: unknown; install?: UserPlugin }
type UserPluginContext = { app: import('vue').App<Element> }
export function setupPlugins(
app: import('vue').App,
modules: AutoInstallModule | Record<string, unknown>,
) {
console.group('🔌 Plugins')
for (const path in modules) {
const module = modules[path] as AutoInstallModule
if (module.install) {
module.install({ app })
console.debug(`%c✔ ${path}`, 'color: #07a')
} else {
if (typeof module.setupPlugins === 'function') continue
console.warn(`%c✘ ${path} has no install function`, 'color: #f50')
}
}
console.groupEnd()
return app
}

6
src/plugins/pinia.ts Normal file
View File

@@ -0,0 +1,6 @@
import { PiniaColada } from '@pinia/colada'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
export function install({ app }: { app: import('vue').App<Element> }) {
app.use(createPinia().use(piniaPluginPersistedstate))
app.use(PiniaColada, {})
}

28
src/plugins/primevue.ts Normal file
View File

@@ -0,0 +1,28 @@
/**
* 需要把 <DynamicDialog /> <ConfirmDialog /> <Toast /> 放在 App.vue 的 template 中
*/
import Aura from '@primeuix/themes/aura'
import zhCN from 'primelocale/zh-CN.json'
import PrimeVue from 'primevue/config'
import StyleClass from 'primevue/styleclass'
export function install({ app }: { app: import('vue').App<Element> }) {
app.directive('styleclass', StyleClass)
app.use(PrimeVue, {
locale: {
...zhCN['zh-CN'],
completed: '已上传',
noFileChosenMessage: '未选择文件',
pending: '待上传',
}, // usePrimeVue().config.locale
theme: {
options: {
cssLayer: false,
darkModeSelector: '.app-dark' /* 'system' */,
prefix: 'p',
},
preset: Aura,
},
})
}

58
src/plugins/router.ts Normal file
View File

@@ -0,0 +1,58 @@
import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders'
import { setupLayouts } from 'virtual:meta-layouts'
// import { createGetRoutes, setupLayouts } from 'virtual:generated-layouts';
import { createRouter, createWebHistory } from 'vue-router'
import { handleHotUpdate, routes } from 'vue-router/auto-routes'
const setupLayoutsResult = setupLayouts(routes)
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: /* routes ?? */ setupLayoutsResult,
scrollBehavior: (_to, _from, savedPosition) => {
return savedPosition ?? { left: 0, top: 0 }
},
strict: true,
})
if (import.meta.hot) handleHotUpdate(router)
if (__DEV__) Object.assign(globalThis, { router })
router.onError((error) => {
console.debug('🚨 [router error]:', error)
})
export { router, setupLayoutsResult }
export function install({ app }: { app: import('vue').App<Element> }) {
app
// 在路由之前注册插件
.use(DataLoaderPlugin, { router })
// 添加路由会触发初始导航
.use(router)
}
// ========================================================================
// =========================== Router Guards ==============================
// ========================================================================
{
// 警告:路由守卫的创建顺序会影响执行流程,请勿调整
createNProgressGuard(router)
createLogGuard(router)
Object.assign(globalThis, { stack: createStackGuard(router) })
}
/*
definePage({
meta: { },
});
*/
declare module 'vue-router' {
interface RouteMeta {
/**
* @description 是否在菜单中隐藏
*/
hidden?: boolean
/**
* @description 菜单标题
*/
title?: string
}
}
export { createGetRoutes } from 'virtual:meta-layouts'

17
src/plugins/vue-i18n.ts Normal file
View File

@@ -0,0 +1,17 @@
/* https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#static-bundle-importing
* All i18n resources specified in the plugin `include` option can be loaded
* at once using the import syntax
*/
import messages from '@intlify/unplugin-vue-i18n/messages'
import { createI18n } from 'vue-i18n'
export function install({ app }: { app: import('vue').App<Element> }) {
app.use(
// https://vue-i18n.intlify.dev/guide/essentials/started.html#registering-the-i18n-plugin
createI18n({
legacy: false, // you must set `false`, to use Composition API
locale: navigator.language,
messages,
}),
)
}

View File

@@ -1,8 +0,0 @@
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [],
})
export default router

4
src/styles/index.ts Normal file
View File

@@ -0,0 +1,4 @@
import 'nprogress/nprogress.css' // <link rel="stylesheet" href="https://testingcf.jsdelivr.net/npm/nprogress/nprogress.css" />
//
import 'virtual:uno.css'

9
src/types/global.ts Normal file
View File

@@ -0,0 +1,9 @@
declare global {
const __DEV__: boolean
}
declare module 'vue' {
export interface ComponentCustomProperties {
__DEV__: boolean
}
}