Răsfoiți Sursa

feat(router): 添加路由配置和基础页面结构

- 创建路由配置文件并设置基础路由
- 添加主页视图组件
- 配置自动导入类型声明
- 添加Element Plus图标依赖
- 删除无用组件文件
- 更新tsconfig和vite配置以支持新功能
piks 1 săptămână în urmă
părinte
comite
4947f2780f

+ 90 - 0
auto-imports.d.ts

@@ -0,0 +1,90 @@
+/* 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 acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
+  const computed: typeof import('vue').computed
+  const createApp: typeof import('vue').createApp
+  const createPinia: typeof import('pinia').createPinia
+  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 getActivePinia: typeof import('pinia').getActivePinia
+  const getCurrentInstance: typeof import('vue').getCurrentInstance
+  const getCurrentScope: typeof import('vue').getCurrentScope
+  const getCurrentWatcher: typeof import('vue').getCurrentWatcher
+  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 isShallow: typeof import('vue').isShallow
+  const mapActions: typeof import('pinia').mapActions
+  const mapGetters: typeof import('pinia').mapGetters
+  const mapState: typeof import('pinia').mapState
+  const mapStores: typeof import('pinia').mapStores
+  const mapWritableState: typeof import('pinia').mapWritableState
+  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 setActivePinia: typeof import('pinia').setActivePinia
+  const setMapStoreSuffix: typeof import('pinia').setMapStoreSuffix
+  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 useLink: typeof import('vue-router').useLink
+  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, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
+  import('vue')
+}

+ 11 - 0
components.d.ts

@@ -11,6 +11,17 @@ export {}
 /* prettier-ignore */
 declare module 'vue' {
   export interface GlobalComponents {
+    ElAvatar: typeof import('element-plus/es')['ElAvatar']
+    ElButton: typeof import('element-plus/es')['ElButton']
+    ElDropdown: typeof import('element-plus/es')['ElDropdown']
+    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
+    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
+    ElIcon: typeof import('element-plus/es')['ElIcon']
+    ElMenu: typeof import('element-plus/es')['ElMenu']
+    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+    ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
+    ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
+    ElSwitch: typeof import('element-plus/es')['ElSwitch']
     HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']

+ 1 - 0
package.json

@@ -9,6 +9,7 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@element-plus/icons-vue": "^2.3.2",
     "@vueuse/core": "^14.2.1",
     "axios": "^1.13.6",
     "element-plus": "^2.13.5",

+ 3 - 0
pnpm-lock.yaml

@@ -8,6 +8,9 @@ importers:
 
   .:
     dependencies:
+      '@element-plus/icons-vue':
+        specifier: ^2.3.2
+        version: 2.3.2(vue@3.5.30(typescript@5.9.3))
       '@vueuse/core':
         specifier: ^14.2.1
         version: 14.2.1(vue@3.5.30(typescript@5.9.3))

+ 0 - 28
src/layout/components/Sidebar/Logo.vue

@@ -1,28 +0,0 @@
-<template>
-  <div class="sidebar-logo-container" :class="{ 'collapse': collapse }">
-    <transition name="sidebarLogoFade">
-      <router-link key="collapse" class="sidebar-logo-link" to="/">
-        <img :src="logo" class="sidebar-logo" />
-        <h1 class="sidebar-title">{{ title }}</h1>
-      </router-link>
-    </transition>
-  </div>
-</template>
-
-<script setup lang="ts">
-import logo from '@/assets/logo/logo.png'
-
-defineProps({
-  collapse: {
-    type: Boolean,
-    required: true
-  }
-})
-
-const title = import.meta.env.VITE_APP_TITLE
-
-
-
-</script>
-
-<style lang="scss" scoped></style>

+ 0 - 8
src/layout/components/Sidebar/index.vue

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

+ 2 - 0
src/main.ts

@@ -2,9 +2,11 @@ import { createApp } from 'vue'
 import App from './App.vue'
 import 'element-plus/dist/index.css'
 import store from './store'
+import router from './router'
 
 const app = createApp(App)
 
 app.use(store)
+app.use(router)
 
 app.mount('#app')

+ 202 - 0
src/mock/sidebarRouters.ts

@@ -0,0 +1,202 @@
+// Mock侧边栏路由数据
+export const sidebarRouters = [
+  {
+    path: '/dashboard',
+    name: 'Dashboard',
+    meta: {
+      title: '仪表盘',
+      icon: 'dashboard'
+    },
+    component: () => import('@/views/Home.vue')
+  },
+  // {
+  //   path: '/user',
+  //   name: 'User',
+  //   meta: {
+  //     title: '用户管理',
+  //     icon: 'user'
+  //   },
+  //   component: () => import('@/views/user/index.vue'),
+  //   children: [
+  //     {
+  //       path: 'list',
+  //       name: 'UserList',
+  //       meta: {
+  //         title: '用户列表',
+  //         icon: 'user-list'
+  //       },
+  //       component: () => import('@/views/user/list.vue')
+  //     },
+  //     {
+  //       path: 'role',
+  //       name: 'UserRole',
+  //       meta: {
+  //         title: '角色管理',
+  //         icon: 'role'
+  //       },
+  //       component: () => import('@/views/user/role.vue')
+  //     },
+  //     {
+  //       path: 'permission',
+  //       name: 'UserPermission',
+  //       meta: {
+  //         title: '权限设置',
+  //         icon: 'permission'
+  //       },
+  //       component: () => import('@/views/user/permission.vue')
+  //     }
+  //   ]
+  // },
+  // {
+  //   path: '/order',
+  //   name: 'Order',
+  //   meta: {
+  //     title: '订单管理',
+  //     icon: 'order'
+  //   },
+  //   component: () => import('@/views/order/index.vue'),
+  //   children: [
+  //     {
+  //       path: 'pending',
+  //       name: 'OrderPending',
+  //       meta: {
+  //         title: '待处理订单',
+  //         icon: 'pending'
+  //       },
+  //       component: () => import('@/views/order/pending.vue')
+  //     },
+  //     {
+  //       path: 'shipped',
+  //       name: 'OrderShipped',
+  //       meta: {
+  //         title: '已发货订单',
+  //         icon: 'shipped'
+  //       },
+  //       component: () => import('@/views/order/shipped.vue')
+  //     },
+  //     {
+  //       path: 'completed',
+  //       name: 'OrderCompleted',
+  //       meta: {
+  //         title: '已完成订单',
+  //         icon: 'completed'
+  //       },
+  //       component: () => import('@/views/order/completed.vue')
+  //     },
+  //     {
+  //       path: 'canceled',
+  //       name: 'OrderCanceled',
+  //       meta: {
+  //         title: '已取消订单',
+  //         icon: 'canceled'
+  //       },
+  //       component: () => import('@/views/order/canceled.vue')
+  //     }
+  //   ]
+  // },
+  // {
+  //   path: '/product',
+  //   name: 'Product',
+  //   meta: {
+  //     title: '产品管理',
+  //     icon: 'product'
+  //   },
+  //   component: () => import('@/views/product/index.vue'),
+  //   children: [
+  //     {
+  //       path: 'list',
+  //       name: 'ProductList',
+  //       meta: {
+  //         title: '产品列表',
+  //         icon: 'product-list'
+  //       },
+  //       component: () => import('@/views/product/list.vue')
+  //     },
+  //     {
+  //       path: 'category',
+  //       name: 'ProductCategory',
+  //       meta: {
+  //         title: '产品分类',
+  //         icon: 'category'
+  //       },
+  //       component: () => import('@/views/product/category.vue')
+  //     },
+  //     {
+  //       path: 'brand',
+  //       name: 'ProductBrand',
+  //       meta: {
+  //         title: '产品品牌',
+  //         icon: 'brand'
+  //       },
+  //       component: () => import('@/views/product/brand.vue')
+  //     }
+  //   ]
+  // },
+  // {
+  //   path: '/system',
+  //   name: 'System',
+  //   meta: {
+  //     title: '系统设置',
+  //     icon: 'system'
+  //   },
+  //   component: () => import('@/views/system/index.vue'),
+  //   children: [
+  //     {
+  //       path: 'config',
+  //       name: 'SystemConfig',
+  //       meta: {
+  //         title: '系统配置',
+  //         icon: 'config'
+  //       },
+  //       component: () => import('@/views/system/config.vue')
+  //     },
+  //     {
+  //       path: 'log',
+  //       name: 'SystemLog',
+  //       meta: {
+  //         title: '系统日志',
+  //         icon: 'log'
+  //       },
+  //       component: () => import('@/views/system/log.vue')
+  //     },
+  //     {
+  //       path: 'backup',
+  //       name: 'SystemBackup',
+  //       meta: {
+  //         title: '数据备份',
+  //         icon: 'backup'
+  //       },
+  //       component: () => import('@/views/system/backup.vue')
+  //     }
+  //   ]
+  // },
+  // {
+  //   path: '/external-link',
+  //   name: 'ExternalLink',
+  //   meta: {
+  //     title: '外部链接',
+  //     icon: 'external-link'
+  //   },
+  //   component: () => import('@/views/external/index.vue'),
+  //   children: [
+  //     {
+  //       path: 'github',
+  //       name: 'GithubLink',
+  //       meta: {
+  //         title: 'GitHub',
+  //         icon: 'github'
+  //       },
+  //       component: () => import('@/views/external/github.vue')
+  //     },
+  //     {
+  //       path: 'documentation',
+  //       name: 'DocumentationLink',
+  //       meta: {
+  //         title: '文档中心',
+  //         icon: 'documentation'
+  //       },
+  //       component: () => import('@/views/external/documentation.vue')
+  //     }
+  //   ]
+  // }
+]

+ 22 - 0
src/router/index.ts

@@ -0,0 +1,22 @@
+import { createRouter, createWebHistory } from 'vue-router'
+import Layout from '@/layout/index.vue'
+
+const router = createRouter({
+  history: createWebHistory(),
+  routes: [
+    {
+      path: '/',
+      component: Layout,
+      children: [
+        {
+          path: '',
+          name: 'Home',
+          // 这里可以替换为实际的主页组件
+          component: () => import('@/views/Home.vue')
+        }
+      ]
+    }
+  ]
+})
+
+export default router

+ 0 - 0
src/routers/index.ts


+ 123 - 0
src/utils/validate.ts

@@ -0,0 +1,123 @@
+/**
+ * 路径匹配器
+ * @param pattern 匹配模式
+ * @param path 路径字符串
+ * @returns 是否匹配
+ */
+export function isPathMatch(pattern: string, path: string): boolean {
+  const regexPattern = pattern.replace(/\//g, '\\/').replace(/\*\*/g, '.*').replace(/\*/g, '[^\\/]*')
+  const regex = new RegExp(`^${regexPattern}$`)
+  return regex.test(path)
+}
+
+/**
+ * 判断value字符串是否为空 
+ * @param value 要检查的值
+ * @returns 是否为空
+ */
+export function isEmpty(value: any): boolean {
+  if (value == null || value === "" || value === "undefined") {
+    return true
+  }
+  return false
+}
+
+/**
+ * 判断url是否是http或https 
+ * @param url URL字符串
+ * @returns 是否为http或https
+ */
+export function isHttp(url: string): boolean {
+  return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
+}
+
+/**
+ * 判断path是否为外链
+ * @param path 路径字符串或路由对象
+ * @returns 是否为外链
+ */
+export function isExternal(path: string | Record<string, any>): boolean {
+  const url = typeof path === 'string' ? path : path.path
+  return /^(https?:|mailto:|tel:)/.test(url)
+}
+
+/**
+ * 验证用户名
+ * @param str 用户名字符串
+ * @returns 是否为有效用户名
+ */
+export function validUsername(str: string): boolean {
+  const validMap: string[] = ['admin', 'editor']
+  return validMap.indexOf(str.trim()) >= 0
+}
+
+/**
+ * 验证URL格式
+ * @param url URL字符串
+ * @returns 是否为有效URL
+ */
+export function validURL(url: string): boolean {
+  const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+  return reg.test(url)
+}
+
+/**
+ * 验证是否为小写字母
+ * @param str 字符串
+ * @returns 是否全为小写字母
+ */
+export function validLowerCase(str: string): boolean {
+  const reg = /^[a-z]+$/
+  return reg.test(str)
+}
+
+/**
+ * 验证是否为大写字母
+ * @param str 字符串
+ * @returns 是否全为大写字母
+ */
+export function validUpperCase(str: string): boolean {
+  const reg = /^[A-Z]+$/
+  return reg.test(str)
+}
+
+/**
+ * 验证是否为字母
+ * @param str 字符串
+ * @returns 是否全为字母
+ */
+export function validAlphabets(str: string): boolean {
+  const reg = /^[A-Za-z]+$/
+  return reg.test(str)
+}
+
+/**
+ * 验证邮箱格式
+ * @param email 邮箱字符串
+ * @returns 是否为有效邮箱
+ */
+export function validEmail(email: string): boolean {
+  const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+  return reg.test(email)
+}
+
+/**
+ * 判断是否为字符串
+ * @param str 要检查的值
+ * @returns 是否为字符串
+ */
+export function isString(str: any): boolean {
+  return typeof str === 'string' || str instanceof String
+}
+
+/**
+ * 判断是否为数组
+ * @param arg 要检查的值
+ * @returns 是否为数组
+ */
+export function isArray<T>(arg: T | T[]): arg is T[] {
+  if (typeof Array.isArray === 'undefined') {
+    return Object.prototype.toString.call(arg) === '[object Array]'
+  }
+  return Array.isArray(arg)
+}

+ 32 - 0
src/views/Home.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="home-container">
+    <h1>欢迎使用DDAC系统</h1>
+    <p>这是系统的主页内容区域</p>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 主页组件逻辑
+</script>
+
+<style lang="scss" scoped>
+.home-container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 40px;
+  text-align: center;
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+}
+
+h1 {
+  color: #333;
+  margin-bottom: 20px;
+}
+
+p {
+  color: #666;
+  font-size: 16px;
+}
+</style>

+ 2 - 1
tsconfig.app.json

@@ -22,6 +22,7 @@
   "include": [
     "src/**/*.ts",
     "src/**/*.tsx",
-    "src/**/*.vue"
+    "src/**/*.vue",
+    "auto-imports.d.ts"
   ]
 }

+ 2 - 1
vite.config.ts

@@ -28,7 +28,8 @@ export default defineConfig(({ mode, command }) => {
     resolve: {
       tsconfigPaths: true,
       alias: {
-        '~': path.resolve(__dirname, './')
+        '~': path.resolve(__dirname, './'),
+        '@': path.resolve(__dirname, './src')
       },
 
       extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']

+ 2 - 2
vite/plugins/auto-import.ts

@@ -11,8 +11,8 @@ export default function createAutoImport(): PluginOption[] {
       imports: ['vue', 'vue-router', 'pinia'],
       // 同时保留 Element Plus 的解析器
       resolvers: [ElementPlusResolver()],
-      // 可选:是否生成类型声明文件,false 表示不生成(根据你的需求调整)
-      dts: false
+      // 生成类型声明文件
+      dts: true
     }),
     Components({
       resolvers: [ElementPlusResolver()]