# vue3-admin项目

## 项目准备

### 创建项目

```sh
npm create vue@latest
```

> 1. 输入项目名称：`vue3-admin`;
> 2. 是否添加`TypeScript` ：`是 `。选择 `yes`;
> 3. 是否添加`JSX `：`否`。选择`no;`
> 4. 是否添加` Vue Router` 用于单页应用程序开发：`否`，选择`no`;
> 5. 是否添加`Pina` ，`Pina`我们后面手动添加所以这里不用添加；`否`，选择`no;`
> 6. 是否添加`Vitest`单元测试：`否`，选择`no`；
> 7. 是否添加`End-to-End `格式：`否`，选择`no`；
> 8. 是否添加`ESLint` ：`是`，选择`yes`；
> 9. 是否添加`Prettier`：是，选择`yes`；

```
✔ Project name: … <your-project-name>
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add an End-to-End Testing Solution? … No / Cypress / Playwright
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes

Scaffolding project in ./<your-project-name>...
Done.
```

#### 初始化项目

```sh
npm install
```

#### 转换本地git仓库

```sh
git init
```

#### 添加本地git仓库

```sh
git add .
```

#### 标注添加的内容

```sh
git commit -m "初始化项目"
```

#### 添加远程苍龙

```sh
git remote add origin 远程仓库地址
```

#### 把代码传送远程仓库

##### 创建分支并切换分支

```sh
git checkout -b 分支名称
```

##### 推送远程仓库

```sh
git push origin 分支名称
```

#### 运行项目

```sh
npm run dev
```

#### debug 运行项目

```sh
npm run build
```

## 项目开始

### 清理不用的文件

> 可以清理的文件名称：`components`文件夹删除 ，并 `assets`文件夹里面文件删除。，并`main.js` 里面的 `css` 引入方法清除就要可以啦。

### V-Router引入

> 引入方法

```sh
npm install vue-router@4
```

#### 创建两个组件

> 按视图`views` 文件夹里面分别创建：`Login` 和 `Dashboard` 。然后每个组件单独创建vue文件。

Login页面（名为：`index.vue` ）。

```vue
<template>
  <div>登录页面</div>
</template>

<script setup lang="ts">

</script>
```

Dashboard页面（名为：`index.vue` ）。

```vue
<template>
  <div>控制台</div>
</template>

<script setup lang="ts">

</script>
```

> 我们用的是路由所以，先创建一个路由文件夹（名为：`router` ）。该路由里面创建一个主入口（名为：`index.ts` ）。

```ts
// 引入router的组件
import type { RouteRecordRaw } from "vue-router";
// 引入两个组件
import LoginView from "@/views/login/index.vue"
import DashboardView from "@/views/dashboard/index.vue"
import {createRouter, createWebHashHistory} from "vue-router";

// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes:Array<RouteRecordRaw> = [
    { path:'/', name : 'dashboard', component : DashboardView },
    { path:'/login', name : 'login', component : LoginView }
]

// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置，但我们在这里
// 暂时保持简单
const router = createRouter({
    // 4. 内部提供了 history 模式的实现。为了简单起见，我们在这里使用 hash 模式。
    history: createWebHashHistory(),
    strict: true,  // 按照严模式匹配
    routes, // `routes: routes` 的缩写
    scrollBehavior : () => ({ left:0, top:0 })   //跳转页面之后回到顶部
})

export default router   // 导出路由
```

#### 创建并挂载根实例（`main.ts`）

```ts
import { createApp } from 'vue'
import App from './App.vue'
// 引入路由
import router from "@/views/router/index.ts";
const app = createApp(App)
// 挂载根实例
app.use(router)
app.mount('#app')
```

#### 跟应用里面引入路由

```vue
<template>
  <router-view></router-view>
</template>

<script lang="ts" setup></script>
```

#### 启动系统

> 启动之后进入的是默认页面，也就是说控制台页面。（`Index.vue`页面）。
>
> 如果是想进去Login页面的话网站后面加入`login` 就能进入登录页面。（`Index.vue` 页面）

### 引入 `T Design` 

#### 引入方法

> 官方网站地址：
>
> ```
> https://tdesign.tencent.com/vue-next/overview
> ```
>
> 安装`TDesign`
>
> ```sh
> npm i tdesign-vue-next
> ```

#### 引入项目中

> `main.ts` 中引入组件
>
> ```ts
> import { createApp } from 'vue'
> import App from './App.vue'
> // 引入TDesign
> import TDesign from 'tdesign-vue-next';
> // 引入组件库的少量全局样式变量
> import 'tdesign-vue-next/dist/reset.css';
> import 'tdesign-vue-next/es/style/index.css';
> // 引入路由
> import router from "@/views/router/index.ts";
> const app = createApp(App)
> // 挂载根实例
> app.use(router)
> // 挂载根实例
> app.use(TDesign)
> app.mount('#app')
> ```

#### 项目中使用

> Login页面使用一下`t-button` 标签，查看是否成功引入了

```vue
<template>
  <div>登录页面</div>
  <t-button>点击我</t-button>
</template>

<script lang="ts" setup>

</script>

<style scoped>

</style>
```

#### 安装lass 的编译器和lass luodei

> 安装方法：

```sh
npm i less less-loader -D
```

### 登录页面

> 登录页面的装修

```vue
<template>
  <img class="wave" src="../../assets/img/wave.png" alt=""/>
  <div class="container">
    <div class="bg">
      <img src="../../assets/img/bg.svg" alt="">
    </div>
    <div class="login-container">
        // 引入 T-Design 的卡片
      <t-card class="login-cart">
        <img class="avatar" src="../../assets/img/avatar.svg" alt="">
        <h2>Vue3-Admin</h2>
       // 引入 T-Design 的表单
        <t-form ref="form" class="login-from" :colon="true" :label-width="0">
          <t-form-item name="username">
            <t-input clearable placeholder="请输入账户名">
              <template #prefix-icon>
                <icon name="user"/>
              </template>
            </t-input>
          </t-form-item>

          <t-form-item name="password">
            <t-input type="password" clearable placeholder="请输入密码">
              <template #prefix-icon>
                <icon name="lock-on"/>
              </template>
            </t-input>
          </t-form-item>

          <t-form-item>
            <t-button theme="primary" type="submit" block>登录</t-button>
          </t-form-item>
        </t-form>
      </t-card>
    </div>
  </div>
</template>

<script lang="ts" setup>
// 引入icon
import {Icon} from "tdesign-vue-next";
</script>

<style lang="less" scoped>
template {
  overflow: hidden;
}

.wave {
  position: fixed;
  height: 100%;
  left: 0;
  bottom: 0;
  z-index: -1;
}

.container {
  width: 100vw;
  height: 100vh;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-gap: 7rem;
  padding: 0 2rem;

  .bg {
    display: flex;
    align-items: center;
    justify-content: flex-end;
  }

  .bg img {
    width: 500px;
  }

  .avatar {
    width: 100px;
  }

  .login-container {
    display: flex;
    width: 380px;
    flex-direction: column;
    align-items: center;
    text-align: center;
    justify-content: center;

    .login-cart {
      width: 100%;

      h2 {
        font-size: 2.5rem;
        margin: 25px 0;
        color: #333;
      }
    }

    .login-from {
      width: 100%;
    }
  }
}
</style>
```

>引入`T-Design` 的卡片和表单

```vue
<t-card class="login-cart">
        <img class="avatar" src="../../assets/img/avatar.svg" alt="">
        <h2>Vue3-Admin</h2>
        <t-form ref="form" class="login-from" :colon="true" :label-width="0">
          <t-form-item name="username">
            <t-input clearable placeholder="请输入账户名">
              <template #prefix-icon>
                <icon name="user"/>
              </template>
            </t-input>
          </t-form-item>

          <t-form-item name="password">
            <t-input type="password" clearable placeholder="请输入密码">
              <template #prefix-icon>
                <icon name="lock-on"/>
              </template>
            </t-input>
          </t-form-item>

          <t-form-item>
            <t-button theme="primary" type="submit" block>登录</t-button>
          </t-form-item>
        </t-form>
      </t-card>
```

#### 验证账号和密码：

>做一个模型，模型就是`type` 关键词来创建。

```vue
<script lang="ts" setup>
// 引入icon
import {Icon} from "tdesign-vue-next";
// 创建用户和密码的模型
type LoginFrom = {
    username:string,
    password:string
}
// 创建对象,reactive 是对象的关键词，<用户和密码的模型>
const loginFrom = reactive<LoginFrom>({
    username:'',
    password:''
})
</script>
```

#### 数据绑定

> 数据绑定：
>
> * 使用`:data="loginFrom"` 来绑定数据。数据绑定在 `t-form` 标签里面写入。
> * 使用`v-model="loginFrom.username"` 来绑定用户数据。该数据 `t-input` 里面写入。
> * 使用`v-model="loginFrom.password"` 来绑定密码数据。该数据 `t-input` 里面写入。
>
> 查看相应，打开网站的检查vue，然后输入在里面检查就可以啦。

#### 验证规则

> 验证规则是用`rules`

```vue
<script lang="ts" setup>
    const rules = {
        username:[
         { required: true, message: '请输入账号...' },
        ],
        password:[
          { required: true, message: '请输入密码...' },
        ]
    }
         
</script>
```

#### 登录功能及Pina全局状态管理

##### API简单封装，API错误处理和全局提示

> 安装API封装组件：`axios`  。

```sh
npm install axios
```

> 安装完成后，我们总是API封装 `src` 目录里面创建一个单独 `api` 文件夹，并创建`request.ts` 文件。
>
> `request.ts` 文件的作用：封装操作，

* 引入 `axios` 

```ts
import axios from "axios";
```

* 定义常量

  > 请求常量

  ```ts
  const BASE_URL = import.mate.env.VITE_API_BASE_URL;
  ```

* 创建实例

  ```ts
  // 创建实例
  const instanse:AxiosInstance = axios.create({
  // 添加参数
      baseURL: BASE_URL,   //路径参数
      timeout: 60000       // 请求超时设置1分钟
  })
  ```

* 总体代码

```ts
// 引入axios组件
import axios from "axios";
import type {AxiosInstance} from "axios"
/**
 * 指定常量  环境变量来定义自定义环境,指定环境变量
 * 指定环境变量前面加前缀名VITE_API不然不能读取
  */
const BASE_URL:string = import.meta.env.VITE_API_BASE_URL;

// 创建实例
const instanse:AxiosInstance = axios.create({
// 添加参数
    baseURL: BASE_URL,   //路径参数
    timeout: 60000       // 请求超时设置1分钟
})

// 导出参数
export default instanse
```

##### 编辑多态化文件

> 多态化环境编辑文件名称：`.env.development` 。
>
> 在总根目录里面创建这个文件。

```
// 自定义环境变量里面绑定有个有前缀的api
VITE_API_BASE_URL = /api
```

##### 创建实例化API封装文件

* 创建`token`接口

  > 在api文件夹里面创建`token.ts` 文件。

  ```ts
  import * as process from "process";
  import type {AxiosPromise} from "axios";
  import request from "@/api/request";
  import type { TokenRequest } from "@/api/types"
  
  
  const createToken = (tokenRequest:TokenRequest):Promise<AxiosPromise<string>> => {
      return request.post('/token', tokenRequest)
  }
  
  
  export default {
      createToken,  // 导出createToken接口
  };
  ```

  

* 创建一个专门管理`type` 的文件。文件名称为：`types.ts` 

  > 作用：

  ```ts
  //创建模型
  export type TokenRequest = {
      username: string,
      password: string
  }
  ```

  

* `Index.vue` 的修改

  > `Index.vue` 里面传入`types.ts` 文件，并且修改关键词

  ```vue
  <script lang="ts" setup>
  	import type { TokenRequest } from "@/api/token"
      
      // 创建对象,reactive 是对象的关键词，<用户和密码的模型>
  	const loginFrom = reactive<TokenRequest>({
      	username:'',
      	password:''
  	})
  </script>
  ```

* 









## 问题：

### 1. `request.ts` 里面显示的错误提示

![image-20231206220046321](C:\Users\托合提如苏力\AppData\Roaming\Typora\typora-user-images\image-20231206220046321.png)

解决方案：





### 2.  `token.ts` 里面显示的错误提示

![image-20231206220229618](C:\Users\托合提如苏力\AppData\Roaming\Typora\typora-user-images\image-20231206220229618.png)

解决方案：



### 3.   `Index.vue` 里面显示的错误提示

![image-20231206220326349](C:\Users\托合提如苏力\AppData\Roaming\Typora\typora-user-images\image-20231206220326349.png)

解决方案：

