重生之我在公司写前端 | “博灵语音通知终端” | 项目集成

Pinia

# 安装 pinia pinia-plugin-persistedstate
pnpm add pinia pinia-plugin-persistedstate

创建:src/store/index.ts

import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

const pinia = createPinia();

// 注册数据持久化插件
pinia.use(piniaPluginPersistedstate);

export default pinia

配置:main.ts

import { createApp } from 'vue';

// 引入状态管理
import pinia from '@/store';

import App from './App.vue';

const app = createApp(App);

// 挂载状态管理
app.use(pinia);

app.mount('#app');

Vue I18n

# 安装 Vue I18n
pnpm add vue-i18n

创建:src/locales/en-us/index.ts

export default {};

创建:src/locales/zh-cn/index.ts

export default {};

创建:src/types/global.ts

// 语言选项类型
type LangKey = 'zhCn' | 'enUs';

export type { LangKey };

创建:src/types/index.ts

export * from './global';

创建:src/locales/index.ts

import { createI18n } from 'vue-i18n';

import type { LangKey } from '@/types';

import enUs from './en-us/index';
import zhCn from './zh-cn/index';

// 语言选项
const LANG_OPT: Record<LangKey, string> = {
  enUs: 'English',
  zhCn: '简体中文',
};

// 语言包
const langPkg: Record<LangKey, any> = {
  enUs,
  zhCn,
};

// 创建 i18n 实例
const i18n = createI18n({
  // 组合 API
  legacy: false,
  // 默认语言为中文
  locale: 'zhCn',
  // 当语言文件中缺少翻译时,回退到英文
  fallbackLocale: 'enUs',
  // 启用全局注入,允许在组件中使用 `$t` 等方法
  globalInjection: true,
  // 语言包配置
  messages: langPkg,
});

export default i18n;

export { LANG_OPT };

配置:main.ts

import { createApp } from 'vue';

// 引入国际化
import i18n from '@/locales';

import App from './App.vue';

const app = createApp(App);

// 挂载国际化
app.use(i18n);

app.mount('#app');

Vue Router

pnpm add nprogress
pnpm add -D @types/nprogress
# 安装 Vue Router
pnpm add vue-router

创建:src/layout/index.vue

<script setup lang="ts">
defineOptions({ name: 'Layout' });
</script>

<template>
  <div class="container">Layout</div>
</template>

创建:src/views/home/index.vue

<script setup lang="ts">
defineOptions({ name: 'Home' });
</script>

<template>
  <div class="container">Home</div>
</template>

创建:src/router/routes.ts

import type { RouteRecordRaw } from 'vue-router';

// 静态路由
const staticRoutes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Layout',
    component: () => import('@/layout/index.vue'),
    meta: {
      hidden: false,
    },
    redirect: '/home',
    children: [
      {
        path: '/home',
        name: 'Home',
        component: () => import('@/views/home/index.vue'),
        meta: {
          hidden: false,
        },
      },
    ],
  },
];

// 动态路由
const dynamicRoutes: RouteRecordRaw[] = [];

export default [...staticRoutes, ...dynamicRoutes];

export { staticRoutes, dynamicRoutes };

创建:src/router/guards.ts

import nprogress from 'nprogress';

import type { Router } from 'vue-router';

// 引入进度条样式
import 'nprogress/nprogress.css';

/**
 * 注册全局路由守卫
 * @param router - 路由实例
 */
export default function setupRouterGuards(router: Router) {
  // 全局前置守卫
  router.beforeEach((_to, _, next) => {
    // 开启进度条
    nprogress.start();

    next();
  });

  // 全局后置守卫
  router.afterEach(() => {
    // 关闭进度条
    nprogress.done();
  });
}

创建:src/router/index.ts

import { createRouter, createWebHistory } from 'vue-router';

import setupRouterGuards from './guards';
import { routes } from './routes';

const router = createRouter({
  /*
   * 使用 HTML5 History 模式,支持浏览器的前进、后退操作
   * BASE_URL 从 Vite 配置的环境变量中读取,通常是应用的根路径
   */
  history: createWebHistory(import.meta.env.BASE_URL),

  // 路由配置
  routes,

  // 滚动行为
  scrollBehavior(to, _from, savedPosition) {
    if (savedPosition) {
      // 如果存在保存的位置(如浏览器前进/后退时),恢复到保存的位置
      return savedPosition;
    }
    if (to.hash) {
      // 如果目标路由包含锚点,滚动到锚点位置
      return { el: to.hash, behavior: 'smooth' };
    }
    // 默认滚动到顶部
    return { top: 0 };
  },
});

// 注册全局路由守卫
setupRouterGuards(router);

export default router;

export * from './routes';

配置:main.ts

import { createApp } from 'vue';

// 引入路由
import router from '@/router';

import App from './App.vue';

const app = createApp(App);

// 挂载路由
app.use(router);

app.mount('#app');

配置:App.vue

<script setup lang="ts">
defineOptions({
  name: 'App',
});
</script>

<template>
  <router-view />
</template>

Element Plus

pnpm add element-plus

配置:main.ts

// 引入 element-plus 样式
import 'element-plus/dist/index.css';
// 引入 element-plus 暗黑模式样式
import 'element-plus/theme-chalk/dark/css-vars.css';
# 按需导入
pnpm add -D unplugin-vue-components unplugin-auto-import unplugin-icons
# https://icones.js.org
pnpm add -D @iconify/json

配置:vite.config.ts

import AutoImport from 'unplugin-auto-import/vite';
import IconsResolver from 'unplugin-icons/resolver';
import Icons from 'unplugin-icons/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import Components from 'unplugin-vue-components/vite';

import { defineConfig } from 'vite';

// https://vite.dev/config/
export default defineConfig({
  plugins: [
      AutoImport({
        resolvers: [ElementPlusResolver(), IconsResolver()],
      }),
      Components({
        resolvers: [ElementPlusResolver(), IconsResolver()],
      }),
      Icons({
        compiler: 'vue3'
      }),
    ],
});

Axios

# 安装 Axios
pnpm add axios

创建:src/utils/request.ts

import axios, { type AxiosInstance, type InternalAxiosRequestConfig } from 'axios';

const request: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

request.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    return config;
  },
  (error) => Promise.reject(error),
);

request.interceptors.response.use(
  (response) => {
    const { code, msg } = response.data;

    if (code !== 200) {
      return Promise.reject(new Error(msg || 'Unknown'));
    }

    return response.data;
  },
  (error) => Promise.reject(error),
);

// 响应接口统一格式
interface ApiResponse<T = any> {
  code: number;
  msg: string;
  data: T;
}

// 封装常用方法
const httpGet = <T>(url: string, params?: Record<string, any>): Promise<ApiResponse<T>> =>
  request.get<any, ApiResponse<T>>(url, { params });

const httpPost = <T>(url: string, data?: Record<string, any>): Promise<ApiResponse<T>> =>
  request.post<any, ApiResponse<T>>(url, data);

const httpPut = <T>(url: string, data?: Record<string, any>): Promise<ApiResponse<T>> =>
  request.put<any, ApiResponse<T>>(url, data);

const httpPatch = <T>(url: string, data?: Record<string, any>): Promise<ApiResponse<T>> =>
  request.patch<any, ApiResponse<T>>(url, data);

const httpDelete = <T>(url: string, params?: Record<string, any>): Promise<ApiResponse<T>> =>
  request.delete<any, ApiResponse<T>>(url, { params });

// 可选:支持传入完整的 config(更灵活)
const httpRequest = <T>(config: InternalAxiosRequestConfig): Promise<ApiResponse<T>> => request(config);

export { httpGet, httpPost, httpPut, httpPatch, httpDelete, httpRequest };

配置:src/utils/index.ts

export * from './request';

接下来就可以开始编写我们的管理页面啦!!!

【博灵A3】这是一个掌握天气预报的报警灯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值