diff --git a/项目开发手册.md b/项目开发手册.md
deleted file mode 100644
index d2b30f6..0000000
--- a/项目开发手册.md
+++ /dev/null
@@ -1,845 +0,0 @@
-# Vue3项目开发手册
-
-## 初始化项目
-
-### 技术选型
-
-Vue3 + Element-plus + Vite
-
-- Vue3
-
- >- 支持 Vue2 的大多数特性
- >- 支持 Typescript
- >- 使用 Proxy 代替 defineProperty 实现数据响应式
- >- 重写虚拟 DOM 的实现和 Tree-Shaking
- >- [Vue3中文官网](https://vue3js.cn/docs/zh/guide/introduction.html)
-
-- Element-plus
-
- > - 支持Vue3的element-ui组件库
- >
- > > element-ui只支持到vue2,element-plus可以支持vue3
- >
- > - [Element-plus中文官网](https://element-plus.gitee.io/#/zh-CN)
-
-- Vite
-
- >- 是一种新型前端构建工具,能够显著提升前端开发体验。
- >
- >- [Vite中文官网](https://www.pipipi.net/vite/)
-
-### 创建项目
-
-> 我们将使用vite和vue3手动进行前端项目架构。为方便大家从vue2过渡到vue3,本项目我们先不使用ts。
->
-
-使用vite的命令创建项目:
-
-> 需要 Node.js 版本 >= 12.0.0
-
-```powershell
-# npm 6.x
-npm init @vitejs/app erp-vue3 --template vue
-
-# npm 7+, 需要额外的双横线:
-npm init @vitejs/app erp-vue3 -- --template vue
-
-# yarn
-yarn create @vitejs/app erp-vue3 --template vue
-```
-
-- npm init @vitejs/app 是固定的写法
-
-- erp-vue3 是项目名称
-
-- --template vue 是指定模板预设。指定vue就是使用vue3并且不使用ts。
-
- > 支持的模板预设如下,有兴趣可以挨个试一下
- >
- > - `vanilla`
- > - `vue`
- > - `vue-ts`
- > - `react`
- > - `react-ts`
- > - `preact`
- > - `preact-ts`
- > - `lit-element`
- > - `lit-element-ts`
-
-创建完后,会提示我们进入项目目录,安装依赖,运行项目:
-
-```powershell
-cd erp-vue3
-npm install
-npm run dev
-```
-
-最后我们来看下项目结构
-
-```powershell
-├─node_modules -----------依赖包
-├─public -----------------静态文件
-├─index.html--------------主页面
-├─src---------------------核心文件目录(我们开发的代码都在src目录)
-| ├─assets---------------静态资源(图片,字体,css,js等)
-| ├─components-----------公共组件
-| ├─App.vue--------------根组件
-| ├─main.js--------------入口文件
-├─package.json------------项目基本信息和依赖包信息
-├─vite.config.js----------配置文件
-```
-
-## 完善项目架构
-
-> 目前项目中还没有路由、状态管理、UI组件库、ajax库
-
-### 组件库 Element Plus
-
-- 安装element-plus,并且在main.js中引入
-
- ```powershell
- npm install element-plus
- ```
-
- 引入element-plus
-
- ```js
- // main.js
- import { createApp } from 'vue'
- import App from './App.vue'
-
- // 引入element-plus
- import ElementPlus from "element-plus";
- import "element-plus/lib/theme-chalk/index.css";
-
- // 使用use注册ElementPlus
- createApp(App).use(ElementPlus).mount('#app')
-
- ```
-
-- vue3中如何全局调用element-plus中的提示插件
-
- ```js
- import {getCurrentInstance} from 'vue';
-
- setup () {
- const { ctx } = getCurrentInstance(); // 可以把ctx当成vue2中的this
- ctx.$message.success("yes")
- ctx.$loading()
- }
- ```
-
-### 路由
-
-- 在src目录中创建views目录,用来存放页面
-
- > 我们使用模块化的方式来管理页面,比如用户管理、权限管理等模块,每个模块下可能有多个页面,所以每个模块都要创建一个目录
-
- 在views目录中创建home目录(代表home模块),home目录中创建index.vue,index.vue代表home模块的主页面
-
- ```vue
-
- home
-
- ```
-
- 同样的方式创建一个login模块
-
- ```vue
-
- login
-
- ```
-
-- 安装路由vue-router
-
- ```powershell
- # 安装最新版的vue-router
- npm install vue-router@next
- ```
-
-- 在src目录中创建router目录,用来存放路由配置文件
-
- > 路由配置就是配置views模块中的页面通过什么地址来访问,路由我们也使用模块化管理,views中有多少模块就创建多少路由配置文件,此外还需要一个index.js来统一分配路由模块
-
- router目录中创建modules目录, modules目录中创建home.js和login.js
-
- ```js
- // home.js
- const Home = () => import("../../views/home/index.vue");
-
- export default [
- {
- path: "/home",
- name: "home",
- component: Home,
- }
- ]
- ```
-
- ```js
- // login.js
- const Login = () => import("../../views/login/index.vue");
-
- export default [
- {
- path: "/login",
- name: "login",
- component: Login,
- }
- ]
- ```
-
- router目录中创建index.js
-
- ```js
- // index.js
- import { createRouter, createWebHashHistory } from "vue-router"
- import home from './modules/home'
- import login from './modules/login'
-
- const router = createRouter({
- history: createWebHashHistory(),
- routes: [
- {
- path: '/',
- redirect: '/home'
- },
- ...home,
- ...login
- ],
- });
-
- export default router;
- ```
-
-- 修改App.vue
-
- ```html
-
- ```
-
-
-
- ```
-
-- 挂载路由
-
- > 在main.js中挂载路由
-
- ```js
- // main.js
- import { createApp } from 'vue'
- import App from './App.vue'
-
- // 引入element-plus
- import ElementPlus from "element-plus";
- import "element-plus/lib/theme-chalk/index.css";
-
- // 引入路由
- import router from './router'
-
- // 使用use注册路由
- createApp(App).use(ElementPlus).use(router).mount('#app')
- ```
-
-- 配置alias路径别名
-
- > 文件引入路径比较深的时候,使用相对路径需要写很多`../`,例如上面的`router/modules/home.js`文件
->
- > 所以我们可以配置一个src目录的别名,需要在vite.config.js中配置
-
- ```js
- // vite.config.js
- import { defineConfig } from 'vite'
- import vue from '@vitejs/plugin-vue'
- import path from "path";
-
- // https://vitejs.dev/config/
- export default defineConfig({
- plugins: [vue()],
- resolve: {
- alias: {
- "@": path.resolve(__dirname, "src"),
- },
- },
-})
- ```
-
- 然后我们就可以修改路由组件的引用路径了,在router/modules/home.js中
-
- ```js
- // home.js
- // const Home = () => import("../../views/home/index.vue");
- const Home = () => import("@/views/home/index.vue");
-
- export default [
- {
- path: "/home",
- name: "home",
- component: Home,
- }
- ]
- ```
-
-### 状态管理
-
-- 安装vuex状态管理插件
-
- ```powershell
- # 安装最新版的vuex
- npm install vuex@next
- ```
-
-- 在src目录中创建store目录,用来存放状态模块
-
- > 状态管理也使用模块化的方式
-
- 在store目录中创建modules目录,modules中创建一个模块app.js
-
- ```js
- // app.js
- export default {
- namespaced: true,
- state: {},
- mutations: {},
- actions: {},
- };
- ```
-
- 在store目录中创建index.js
-
- ```js
- //index.js
- import { createStore } from "vuex";
- import app from "./modules/app";
-
- export default createStore({
- modules: {
- app,
- },
- });
-
- ```
-
-- 挂载store
-
- ```js
- // main.js
- import { createApp } from 'vue'
- import App from './App.vue'
-
- // 引入element-plus
- import ElementPlus from "element-plus";
- import "element-plus/lib/theme-chalk/index.css";
-
- // 引入路由
- import router from './router'
-
- // 引入store
- import store from './store'
-
- // 使用use注册路由和store
- createApp(App).use(ElementPlus).use(router).use(store).mount('#app')
- ```
-
-### 接口管理
-
-- 安装axios
-
- ```powershell
- npm install axios
- ```
-
-- 接口管理
-
- > 项目中我们调用接口的时候,有可能有很多页面都会调用同一个接口,所以我们把所有的接口统一进行模块化管理
-
- 在src目录中创建api目录,用来存放所有的接口
-
- 在api目录中创建一个模块login.js,该文件包括跟登录注册相关的所有接口
-
- ```js
- // login.js
- import axios from 'axios'
-
- // 登录接口
- export const Login = data => {
- return axios.request({
- url: "/api/login",
- method: "post",
- data,
- });
- };
-
- // 其它接口...
- ```
-
- 在页面中调用登录接口
-
- > 在views/login/index.vue中:
-
- ```html
-
- login
- 登录
-
-
-
- ```
-
-### 跨域管理
-
-当前端调用后端接口的时候,假设后端接口的域名是`http://dev.erp.com`,那`http://localhost`访问`http://dev.erp.com`是会跨域的,这时候我们就要在vite.config.js中设置代理
-
-```js
-// vite.config.js增加如下配置
-server: {
- proxy: {
- "/api": {
- target: "http://dev.erp.com",
- changeOrigin: true,
- },
- },
-},
-```
-
-### mock管理
-
-> 当后端接口没有开发完成的时候,前端就需要根据接口文档mock数据进行开发
->
-> vite中可以使用vite-plugin-mock插件创建mock服务
-
-- 安装vite-plugin-mock
-
- ```powershell
- npm install -D mockjs vite-plugin-mock
- ```
-
-- 配置mock,需要在vite.config.js中配置
-
- ```js
- // vite.config.js
- import { defineConfig } from 'vite'
- import vue from '@vitejs/plugin-vue'
- import path from "path";
- import { viteMockServe } from "vite-plugin-mock";
-
- // https://vitejs.dev/config/
- export default env => {
- // console.log(env);
-
- return defineConfig({
- plugins: [
- vue(),
- viteMockServe({
- mockPath: "mock", // 指定mock目录中的文件全部是mock接口
- localEnabled: env.mode === "mock", // 指定在mock模式下才启动mock服务(可以在package.json的启动命令中指定mode为mock)
- supportTs: false, // mockPath目录中的文件是否支持ts文件,现在我们不使用ts,所以设为false
- }),
- ],
- resolve: {
- alias: {
- "@": path.resolve(__dirname, "src"),
- },
- },
- server: {
- proxy: {
- "/api": {
- target: "http://dev.erp.com",
- changeOrigin: true,
- },
- },
- },
- });
- };
- ```
-
-- package.json中配置mode为mock的启动命令
-
- ```js
-// ...
- "scripts": {
- "dev": "vite",
- "mock": "vite --mode mock",
- // ...
- ```
-
- 重新启动项目
-
- ```powershell
- npm run mock
- ```
-
-- 在根目录中创建mock目录,用来存放mock接口
-
- 在mock目录中创建一个test.js
-
- ```js
- // test.js
- export default [
- {
- url: "/api/get",
- method: "get",
- response: {
- code: 200,
- data: {
- name: "hello world",
- },
- },
- },
- ]
- ```
-
-
-这个时候我们访问`http://localhost:3000/api/get`,可以看到返回的mock数据了
-
-### 封装axios
-
-> 当我们登录成功之后,后端其实会返回一个token(token就是用来做登录认证的),后续所有请求都需要带上这个token,后端校验token是否有效
->
-> 这个时候,前端要做的就是把token保存在本地存储中,然后所有的请求都要增加一个自定义请求头,用来传递token
->
-> 为了更友好的对请求进行控制(比如添加全局请求头、统一处理错误),我们对axios进行封装,拦截请求和响应
-
-- 在登录的mock接口中返回token
-
- ```js
- // mock/login.js
- export default [
- {
- url: "/api/login",
- method: "post",
- timeout: 1000,
- response: {
- code: 200,
- message: "登录成功",
- data: {
- token: "@word(50, 100)", // @word()是mockjs的语法
- refresh_token: "@word(50, 100)", // refresh_token是用来重新生成token的
- }
- },
- },
- ]
- ```
-
-- 登录之后,把token保存在localStorage和vuex中
-
- > 保存在vuex中为了更好的进行响应式控制
-
- ```js
- // 登录
- const login = async () => {
- const { code, data, message } = await Login({
- userName: 'admin',
- password: '123456'
- })
- if (+code === 200) {
- store.commit("app/setToken", data);
- }
- }
- ```
-
- store/modules/app.js
-
- ```js
- import { getItem, setItem, removeItem } from "@/utils/storage"; //getItem和setItem是封装的操作localStorage的方法
- export const TOKEN = "TOKEN";
-
- export default {
- namespaced: true,
- state: {
- authorization: getItem(TOKEN),
- },
- mutations: {
- setToken(state, data) {
- state.authorization = data;
- // 保存到localStorage
- setItem(TOKEN, data);
- },
- clearToken (state) {
- state.authorization = '';
- // 保存到localStorage
- removeItem(TOKEN);
- },
- },
- actions: {},
- };
- ```
-
- 在src中创建utils目录,在utils中创建storage.js
-
- > utils目录主要是用来存放一些常用工具函数
-
- ```js
- // storage.js
- export const getItem = name => {
- const data = window.localStorage.getItem(name);
- try {
- return JSON.parse(data);
- } catch (err) {
- return data;
- }
- };
-
- export const setItem = (name, value) => {
- if (typeof value === "object") {
- value = JSON.stringify(value);
- }
-
- window.localStorage.setItem(name, value);
- };
-
- export const removeItem = name => {
- window.localStorage.removeItem(name);
- };
-
- ```
-
-- 在utils目录中创建request.js
-
- ```js
-// request.js
- import axios from "axios";
- import { ElMessage } from "element-plus";
- import store from "@/store";
- import router from "@/router";
-
- const service = axios.create({
- baseURL: "/",
- timeout: 10000,
- withCredentials: true,
- });
-
- // 拦截请求
- service.interceptors.request.use(
- (config) => {
- const { authorization } = store.state.app;
- if (authorization) {
- config.headers.Authorization = `Bearer ${authorization.token}`;
- }
- return config;
- },
- (error) => {
- // console.log(error);
- return Promise.reject(error);
- }
- );
-
- // 拦截响应
- service.interceptors.response.use(
- // 响应成功进入第1个函数,该函数的参数是响应对象
- (response) => {
- return response.data;
- },
- // 响应失败进入第2个函数,该函数的参数是错误对象
- async (error) => {
- // 如果响应码是 401 ,则请求获取新的 token
- // 响应拦截器中的 error 就是那个响应的错误对象
- if (error.response && error.response.status === 401) {
- // 校验是否有 refresh_token
- const { authorization } = store.state.app;
- if (!authorization || !authorization.refresh_token) {
- router.push("/login");
-
- // 代码不要往后执行了
- return Promise.reject(error);
- }
- // 如果有refresh_token,则请求获取新的 token
- try {
- const res = await axios({
- method: "PUT",
- url: "/api/authorizations",
- timeout: 10000,
- headers: {
- Authorization: `Bearer ${authorization.refresh_token}`,
- },
- });
- // 如果获取成功,则把新的 token 更新到容器中
- // console.log('刷新 token 成功', res)
- store.commit("app/setToken", {
- token: res.data.data.token, // 最新获取的可用 token
- refresh_token: authorization.refresh_token, // 还是原来的 refresh_token
- });
- // 把之前失败的用户请求继续发出去
- // config 是一个对象,其中包含本次失败请求相关的那些配置信息,例如 url、method 都有
- // return 把 request 的请求结果继续返回给发请求的具体位置
- return service(error.config);
- } catch (err) {
- // 如果获取失败,直接跳转 登录页
- // console.log('请求刷新 token 失败', err)
- router.push("/login");
- // 清除token
- store.commit("app/clearToken")
- return Promise.reject(error);
- }
- }
-
- ElMessage.error(error.message);
-
- return Promise.reject(error);
- }
- );
-
- export default service;
-
- ```
-
- 这时我们再回到api/login.js中,只需要引入上面的request.js就行了
-
- ```js
- // login.js
- // import axios from 'axios'
- import request from '@/utils/request'
-
- // 登录接口
- export const Login = data => {
- return request({
- url: "/api/login",
- method: "post",
- data,
- });
- };
- ```
-
-### 权限控制
-
-> 如果没有登录或者token失效的时候,页面需要重定向到登录页
->
-> 还有一些例如找回密码的页面应该也可以访问,所以我们还是设置一个白名单,没有token的时候只能访问白名单的页面
-
-- 在src目录创建permission.js
-
- ```js
-// permission.js
-
- import router from '@/router'
- import { TOKEN } from '@/store/modules/app' // TOKEN变量名
- // 白名单,里面是路由对象的name
- const WhiteList = ['login']
-
- // vue-router4的路由守卫不再是通过next放行,而是通过return返回false或者一个路由地址
- router.beforeEach((to) => {
- if (!window.localStorage[TOKEN] && !WhiteList.includes(to.name)) {
- return {
- name: 'login',
- query: {
- redirect: to.path // redirect是指登录之后可以跳回到redirect指定的页面
- },
- replace: true
- }
- }
- })
- ```
-
-- 在main.js中引入permission
-
- ```js
- // 权限控制
- import './permission'
- ```
-
-### css
-
-- css预处理器
-
- 由于element-plus使用sass开发,所以本项目我们也使用sass,先安装sass
-
- ```powershell
- npm install -D sass
- ```
-
- 使用sass
-
- ```html
-
- ```
-
-- autoprefixer自动处理css3浏览器前缀
-
- 安装autoprefixer
-
- > 不需要安装postcss,vite内部支持
-
- ```powershell
- npm install autoprefixer -D
- ```
-
- 根目录创建postcss.config.js
-
- ```js
- // postcss.config.js
- module.exports = {
- plugins: {
- // 兼容浏览器,添加前缀
- 'autoprefixer': {}
- }
- }
- ```
-
- package.json中配置浏览器版本
-
- ```js
- //package.json
- {
- "browserslist": [
- "> 1%",
- "last 2 versions"
- ],
- }
- ```
-
-## 项目结构
-
-最终的项目结构如下
-
-> 没有后缀的,代表是一个文件夹
-
-```powershell
-├─node_modules -----------依赖包
-├─mock -------------------mock接口
-├─public -----------------静态文件
-├─index.html--------------主页面
-├─src---------------------核心文件目录(我们开发的代码都在src目录)
-| ├─api------------------接口模块
-| ├─assets---------------静态资源(图片,字体,css,js等)
-| ├─components-----------公共组件
-| ├─router---------------路由配置
-| | ├─index.js----------路由主文件
-| | ├─modules-----------路由模块
-| ├─store----------------状态管理
-| | ├─index.js----------状态主文件
-| | ├─modules-----------状态模块
-| ├─utils----------------工具函数
-| | ├─request.js--------axios封装函数
-| ├─views----------------页面
-| ├─App.vue--------------根组件
-| ├─main.js--------------入口文件
-├─package.json------------项目基本信息和依赖包信息
-├─postcss.config.js-------postcss配置文件
-├─vite.config.js----------打包配置文件
-```
-
-## 登录
-