# vue前端框架

本文档可以直接在编辑器中打开，但为了更好的体验建议使用typora来预览。

## 1、基本命令

### 1.1 安装依赖

```
npm install
```

### 1.2 启动项目
```
npm run serve
```

### 1.3 编译打包
```
// 正常打包
npm run build
// 开发环境打包
npm run build-dev
// 测试环境打包
npm run build-test
// 生成环境打包
npm run build-prod

```



## 2、目录结构

```
├── dist                        // 打包后文件
├── node_modules                // 依赖包
├── public                      // html模板和静态文件
├── src                         // 源代码（模块应与apis里的js一一对应）
│   ├── apis                    // 后端接口
│   ├── assets                  // 静态资源
│   ├── components              // 全局公用组件
│   ├── layout             	    // 布局
│   ├── router                  // 路由
│   ├── store                   // 全局状态管理
│   ├── styles                  // 全局样式
│   ├── utils                   // 全局公用方法
│   ├── views                   // 前端页面代码
│   │   ├── admin               // 系统管理模块
│   │   │   ├── menu            // 菜单管理页面
│   │   │   │   ├── components  // 页面组件
│   │   │   │   ├── Index.vue   // 页面入口
│   ├── App.vue                 // 入口页面
│   └── main.js                 // 入口 加载组件 初始化等
├── .env.dev                	// 开发环境配置文件
├── .env.test                	// 测试环境配置文件
├── .env.prod                	// 生产环境配置文件
└── package.json                // 依赖包管理

```



## 3、代码规范

项目中未开启eslink代码校验，但希望尽量以eslink规则来约束自己，写出高质量代码。



## 4、首屏加载优化

### 4.1 按需加载路由

列如：

```
 {
    path: '/login',
    meta: { title: '登录'},
    component: () => import('@/views/base/login/Login')
  }
```



### 4.2 gzip打包

 在nginx的配置文件里面nginx.conf配置的server_name  127.0.0.1;下面添加如下参数，实现gzip静态压缩

```
	gzip_static on;
	gzip_proxied expired no-cache no-store private auth;
```



## 5、后端接口

在个环境对应文件中配置

```
├── .env.dev                	// 开发环境配置文件
├── .env.test                	// 测试环境配置文件
├── .env.prod                	// 生产环境配置文件
```



接口统一注册在apis文件夹的js文件中，每一个模块必须对应着一个js文件。

以全大写模块页面加下划线连接方式命名，如：MENU_CREATE



## 6、公用方法封装

### 6.1 axios 接口请求

```
/**
 * get请求方法
 * @param {String} url 接口
 * @param {Object} param  请求参数
 * @param {function} data 成功回调
 * @param {function} error 失败回调
 */
this.$get( url, param, data => {}, error => {})
```

```
/**
 * post请求方法
 * @param {String} url 接口
 * @param {Object} param  请求参数
 * @param {function} data 成功回调
 * @param {function} error 失败回调
 */
this.$get( url, param, data => {}, error => {})
```

### 6.2 axios 接口同步请求

```
/**
 * post请求方法
 * @param {String} url 接口
 * @param {Object} param  请求参数
 * @param {Boolean} isMsg 是否提示错误消息
 */
this.$postSync( url, param, isMsg)

/**
 * get请求方法
 * @param {String} url 接口
 * @param {Object} param  请求参数
 * @param {Boolean} isMsg 是否提示错误消息
 */
this.$getSync( url, param, isMsg)


// 用法， 方法前加async， 接口请求前面加await， res为接口返回参数
async loadList () {
    let res1 = await this.$postSync(api)
    let res2 = await this.$postSync(api)
}
```



### 6.3 isCode 按钮权限

```
/**
 * 判断资源code是否存在
 * @param {String} code 资源code
 */
$isCode(code)
```



### 6.4 deleteInfo 删除信息

```
/**
 * 删除信息
 * @param {String} api 接口
 * @param {Object} param 接口入参
 * @param {function} callback 成功回调
 */
this.$deleteInfo(api, param, title, callback)
```

### 6.5 parseObj 解构对象给另一个对象

```
/**
 * 解构对象给另一个对象
 * @param {Oject} obj 赋值对象
 * @param {Oject} data 解构对象
 * @param {Array} arr 解构参数
 */
 this.$parseObj(obj, data, arr)
```

### 6.6 getRegionName 查询省市区名称

```
/**
 * 通过code查询省市区名称
 * @param {String} provinceCode 省code
 * @param {String} cityCode 市code
 * @param {String} areaCode 市code
 */
this.$getRegionName(provinceCode, cityCode, areaCode)
```

### 6.7 downloadFile 下载文件

```
/**
 * 下载文件
 * @param {String} api 接口
 * @param {Object} params 请求参数
 * @param {String} fileName 文件名
 */
this.$downloadFile(api, params, fileName) 
```

### 6.8 dayjs 日期格式化

```
/**
 * 日期格式化
 * @param {String} 要格式化的日期
 * @param {String} 格式化
 * @return {String} 格式化后的日期
 */
this.$dayjs(param).format('YYYY-MM-DD HH:mm:ss')

// 更多使用方法请参考
https://www.cnblogs.com/cjrfan/p/9154539.html
```

### 6.9 debounce 防抖函数

```
/**
 * 防抖函数
 * @param {function} fn 函数
 * @param {number} delay 延迟
 */
this.$debounce(fn) 

// 用法
loadList: window.Vue.prototype.$debounce(function () {
	this.$refs.table.loadList()
})
```

### 6.10 throttle 节流函数

```
/**
 * 节流函数
 * @param {function} fn 函数
 * @param {number} delay 延迟
 */
this.$throttle(fn)


//用法
loadList: window.Vue.prototype.$throttle(function () {
	this.$refs.table.loadList()
})
```

### 6.11 deepClone 深拷贝

```
/**
 * 深拷贝对象
 * @param {Object} obj 拷贝对象
 * @retrun Object
 */
this.$deepClone(obj)
```



## 7、基础组件

sanh-ui是基于element-ui进行的二次封装，所有的封装都会把el改为sh。所以项目中尽量使用sh标签进行开发。

### 7.1 sh-search 表格检索

```
/**
 * 搜索框超出两行后会显示展开折叠按钮
 * :resetBtn 是否显示重置按钮
 * :span 所占的宽度（24为100%，8则为三分之一即三列）
 * slot="btn" 右侧的按钮组
 * :btnSpan 按钮组所占的宽度
 * :btnGutter 按钮组与输入框的间隔
 */
<sh-search ref="search" :model="form" :resetBtn="true">
  <sh-form-item label="权限组编号" :span="8" prop="permissionGroup">
    <sh-input v-model="form.permissionGroup"></sh-input>
  </sh-form-item>
  <sh-form-item label="接口" :span="8" prop="permissionApi">
    <sh-input v-model="form.permissionApi"></sh-input>
  </sh-form-item>
  <template slot="btn">
    <sh-button type="primary" @click="loadList">查询</sh-button>
    <sh-button type="success" @click="onCreate" v-if="$isCode ('admin-api-add')">新增</sh-button>
  </template>
</sh-search>
```

### 7.2 sh-table 表格

```

/**
 * 对分页及table数据请求进行封装
 * :api 接口
 * :param 检索参数Object
 * :data table数据
 * :layout 分页layout
 * :pageSizes 分页pageSizes
 * :page 当前页
 * :limit 每页条数 
 * :count 总条数
 * :showPage 是否显示分页
 * @loadList 重载table方法
 */
<sh-table ref="table" class="space-top" :api="tableApi" :param="form">
  <sh-table-column type="index" label="序号" width="50"> </sh-table-column>
  <sh-table-column prop="permissionGroup" label="权限组编号" min-width="80"> </sh-table-column>
  <sh-table-column prop="permissionApi" label="接口" min-width="80" :show-overflow-tooltip="true"> </sh-table-column>
  <sh-table-column prop="description" label="说明" min-width="80"> </sh-table-column>
  <sh-table-column prop="state" label="状态" min-width="80">
    <template slot-scope="scope">
      <el-switch v-model="scope.row.state" @change="changeState(scope.row)" :active-value="1" :inactive-value="2">
      </el-switch>
    </template>
  </sh-table-column>
  <sh-table-column label="操作" min-width="80">
    <template slot-scope="scope">
      <el-button @click="onUpdate(scope.row)" type="text">编辑</el-button>
      <!-- <el-button @click="onUpdate(scope.row)" type="text" v-if="$isCode ('admin-api-edit')">编辑</el-button>
      <el-button type="text" @click="onDelete(scope.row)" v-if="$isCode ('admin-api-delete')">删除</el-button> -->
    </template>
  </sh-table-column>
</sh-table>
```

### 7.3 sh-form 表单

```
/**
 * :span 所占的宽度（24为100%，8则为三分之一即三列）
 * rules 检验规则
 * :labelWidth label的宽度
 * :gutter 间隔
 */
<sh-form :model="form" ref="form" >
  <sh-form-item label="姓名"  prop="personName" rules="required">
    <sh-input v-model="form.personName" placeholder="请输入权限组编号"></sh-input>
  </sh-form-item>
  <sh-form-item label="性别"  prop="sex" rules="required">
    <el-radio-group v-model="form.sex">
      <el-radio :label="1">男</el-radio>
      <el-radio :label="0">女</el-radio>
    </el-radio-group>
  </sh-form-item>
  <sh-form-item label="证件类型"  prop="idcardType" rules="required">
    <sh-input v-model="form.idcardType" placeholder="请输入说明"></sh-input>
  </sh-form-item>
  <sh-form-item label="证件号码"  prop="idcardType" rules="required">
    <sh-input v-model="form.idcard" placeholder="请输入说明"></sh-input>
  </sh-form-item>
  <sh-form-item label="出生日期" prop="birthday" rules="required">
    <sh-date-picker v-model="form.birthday" type="date" placeholder="选择日期"></sh-date-picker>
  </sh-form-item>
  <sh-form-item label="手机号"  prop="mobilephone" rules="required||phone">
    <sh-input v-model="form.mobilephone" placeholder="请输入说明"></sh-input>
  </sh-form-item>
</sh-form>
```

rules检验规则：

```
required: 必填项
number: 数字
integer: 整数
email: 邮箱
date: 日期
phone: 手机号
special: 特殊字符
account: 必须包含数字、字母、下划线中的两种或以上
password: 必须包含字母和数字,且在6~18位之间
identity: 身份证号
url: url
api: 通过接口校验
```

当一个检验时：rules=“required”，

当多个时可以用||隔开：rules=“required||number||integer”

当自定义校验或通过接口校验时需要用数组：

```
/**
 * type 类型
 * message 提示信息
 * api 接口
 * param 检索参数（输入框对应的键值）
 * search 其它检索参数Object
 */
:rules="['required',{type: 'number', message: '必须为数字'}, {type: 'api', api: apiIsUnifiedcode, param: 'unifiedcode'}]"
```

### 7.4 sh-dialog 弹框

```
/**
 * :visible.sync 是否打开弹框
 */
<sh-dialog
  title="标题"
  :visible.sync="dialogVisible"
  width="30%"
  :before-close="handleClose">
  <span>弹框内容</span>
  <span slot="footer" class="dialog-footer">
    <sh-button @click="dialogVisible = false">取 消</sh-button>
    <sh-button type="primary" @click="dialogVisible = false">确 定</sh-button>
  </span>
</sh-dialog>
```

### 7.4 sh-dialog-tree 弹框树

```
/**
 * api 接口
 * title 标题
 * dialogTreeVisible 是否显示
 * param 检索参数
 * @handleEvent 事件
 * :height 高度
 * :defaultProps 自定义节点标识
 * :radio 为true时单选
 */
<sh-tree-dialog
    :api="api"
    :title="title"
    :dialogVisible.sync="dialogTreeVisible"
    @handleEvent="handleEvent"
></sh-tree-dialog>
```

### 7.5 sh-region-cascader 省市区下拉框

```
/**
 * :provinceCode 省code
 * :cityCode 市code
 * :areaCode 区code
 * v-model 数据数组
 */
<sh-region-cascader :provinceCode.sync="provinceCode" :cityCode.sync="cityCode" :areaCode.sync="areaCode">
</sh-region-cascader>
```

### 7.6 sh-select-search  检索下拉框

```
/**
 * v-model 字段
 * :api 接口
 * :param 检索Object
 * :defaultProps="{label: 'typeName', value: 'id'}"  label显示的字段，value赋值的字段
 */
<sh-select-search v-model="form.unitType" :api="selectApi" :search="{type:2}"
          :defaultProps="{label: 'typeName', value: 'id'}"></sh-select-search>
```

### 7.6 sh-upload  上传文件

```
/**
 * :api 接口
 * :param 检索Object
 * :accept 文件类型['jpg', 'png', 'txt', 'zip', 'rar', 'pdf', 'doc', 'docx', 'xlsx']
 * :param 检索Object
 * :size 最大上传文件（单位为m，默认值5）
 * @callBack 上传后回调function
 */
<sh-upload ref="upload" api="/update" :param="{type: 123}"></sh-upload>

// 打开上传弹框
this.$refs.upload.uploadFile()
```


### 7.7 pdf预览弹框

```
// 引入组件
import { SHPdfDiglog } from '@/components'

// 注册组件
components: { PdfDiglog }
/**
 * :dialogVisible.sync 是否显示弹框
 * :param 接口参数
 * :downList 下载pdf列表
 */
<sh-pdf-diglog :dialogVisible.sync="dialogVisible" :param="{id: 'b735b9c0ce994dbdb94a08c9f8064b48'}" :downList="[{name: 'vue框架环境搭建', id: 'b735b9c0ce994dbdb94a08c9f8064b48'}]"/></sh-pdf-diglog>
```

## 8、公用组件

### 8.1 OrgDialog  组织结构弹框树

```
// 引入组件
import { OrgDialog } from '@/components'

// 注册组件
components: { OrgDialog }

/**
 * :dialogVisible.sync 是否打开弹框
 * :radio 是否单选
 * @handleEvent 点击确认后回调方法
 * :defaultTreeData 回显数据
 */
<OrgDialog :dialogVisible.sync="dialogTreeVisible" @handleEvent="handleEvent"  />

```

### 8.2 OrgPersonDialog 组织结构及和员弹框

```
// 引入组件
import { OrgPersonDialog } from '@/components'

// 注册组件
components: { OrgPersonDialog }

/**
 * :dialogVisible.sync 是否打开弹框
 * @handleEvent 点击确认后回调方法
 * :data 回显数据
 */
<OrgPersonDialog :dialogVisible.sync="dialogTreeVisible" @handleEvent="handleEvent"  />



```