Commit 95c1b0c5 authored by 高宇's avatar 高宇

wenj

parent 0aaf92b0
# 91isoft_web开发平台 # 信息化管理系统
## Build Setup
[TOC]
## 1. 框架介绍
### 1.1. 框架简介
`91isoft_web`是根据`vue2.7`开发的一款快速开发平台,包含了基础的系统管理,日志管理和登录验证码校验,页面皮肤风格切换等功能
+ 系统管理
+ 用户管理
+ 角色管理
+ 菜单管理
+ 部门管理
+ 字典管理
+ 日志管理
+ 登录日志
+ 操作日志
+ 异常日志
| 版本 | 组件 | 描述 | 维护人 |
| ---- | ---------------- | ------------------------------------------------------------ | ------ |
| v1.0 | vue2.7.10 | 构建用户界面,实现响应式数据绑定和组件化开发 | 杨硕 |
| v1.0 | element-ui2.13.0 | 基于Vue.js的开源UI组件库 | 杨硕 |
| v1.0 | axios0.18.1 | 用于在浏览器和Node.js中发起HTTP请求,提供拦截器、取消请求等功能 | 杨硕 |
| v1.0 | js-base642.6.2 | 对字符串或二进制数据进行Base64编码和解码 | 杨硕 |
| v1.0 | moment2.27.0 | 处理日期和时间相关的逻辑 | 杨硕 |
| v1.0 | qs6.9.4 | qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库 | 杨硕 |
| v1.0 | node-sass4.9.0 | sass-loader的支持模块 | 杨硕 |
| v1.0 | sass-loader7.1.0 | 将sass文件编译成css,依赖于node-sass | 杨硕 |
| v1.0 | eslint5.15.3 | 代码检查工具,统一代码风格规则 | 杨硕 |
| v1.0 | svgo1.2.2 | 基于Nodejs的SVG文件优化工具 | 杨硕 |
| v2.0 | 登录验证码 | 通过拖拽图片或文字输入来验证用户身份,防止登陆时对密码进行暴力破解的行为 | 张伯涛 |
### 1.2. 版本管理
| 版本 | 维护人员 | 维护时间 | 主要内容 | | |
| ---- | -------- | --------- | --------------------------------------------------------- | ---- | ---- |
| v1.0 | 杨硕 | 2023-7-18 | 模版项目搭建 | | |
| v2.0 | 张伯涛 | 2024-1-01 | 1.模块bug修改2.系统皮肤切换功能的完善3.登录验证码功能添加 | | |
### 1.3. 分支管理
| 序号 | 分支 | 类型 | 描述 |
| ---- | -------------- | ---------------------------------- | ------------------------------------------------------------ |
| 1 | rbac_v1.0 | 产品 <br/>【停止更 新】 | 登录账号无角色,若权限为“*”即可登录。自定义按钮组件,使按钮根据权限回显。一个用户只能绑定一个部门 |
| 2 | wbac_v1.0 | 产品 | 一个用户可以绑定多个部门 |
| 3 | rbac_v1.1 | 产品 | 拥有登录验证码校验功能和系统皮肤切换功能 |
| 4 | rbac_v1.0_p_oa | 项目 | 可以把左边菜单栏分为若干个系统,选择不同的系统显示不同的菜单。 |
### 1.4. 项目启动
```bash ```bash
# 克隆项目 # 克隆项目
...@@ -72,51 +19,20 @@ npm install --registry=https://registry.npm.taobao.org ...@@ -72,51 +19,20 @@ npm install --registry=https://registry.npm.taobao.org
npm run dev npm run dev
``` ```
浏览器访问 [http://localhost:8080](http://localhost:8080) 浏览器访问 [http://localhost:9706](http://localhost:9706)
#### 1.4.1. 配置后台接口
vue项目默认端口号为8080,如需自定义端口号,可在vue.config.js文件中的下方位置修改
```js
// 自定义端口号
const port = process.env.port || process.env.npm_config_port || 9706
```
```js
devServer: {
// 如果不自定义port,项目运行的默认端口号默认为8080
port: port,
open: true,
overlay: {
warnings: false,
errors: true
},
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://192.144.239.97:20075/`, // 设置后端接口请求地址
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
}
}
```
## 发布
#### 1.4.2. 项目发布
```bash ```bash
# 1.构建测试环境 # 构建测试环境
npm run build:test npm run build:stage
# 构建生产环境 # 构建生产环境
npm run build:prod npm run build:prod
``` ```
## 其它
```bash ```bash
# 预览发布环境效果 # 预览发布环境效果
npm run preview npm run preview
...@@ -130,1144 +46,77 @@ npm run lint ...@@ -130,1144 +46,77 @@ npm run lint
# 代码格式检查并自动修复 # 代码格式检查并自动修复
npm run lint -- --fix npm run lint -- --fix
``` ```
## 全局清空console.log
1.在main.js文件中配置以下代码
### 1.5. 项目结构
├── build // 构建相关
├── mock // 执行脚本
├── public // 公共文件
│ ├── liulanqi_logo.png // 浏览器图标
│ └── index.html // html模板
├── src // 源代码
│ ├── api // 所有后端请求接口
│ ├──monitor // 日志模块请求接口
│ ├──system // 系统模块请求接口
│ ├──fileUploadPublic.js // 公共上传接口
│ └──login.js // 登录接口
│ ├── assets // 主题 字体 图片等静态资源
│ ├── components // 全局公用组件
│ ├──Breadcrumb // 面包屑
│ ├──coolbutton // 自定义按钮
│ ├──IconSelect // 图标查询
│ ├──Pagination // 分页
│ └──SvgIcon // svg图标
│ ├── directive // 全局指令
│ └──permission // 权限设定
│ ├── layout // 布局
│ ├── plugins // 通用方法
│ ├── router // 路由
│ ├── store // 全局 store管理
│ ├── utils // 全局公用方法
│ ├── views // view
│ ├──controlPlatform // 工作台
│ ├──login // 登录
│ ├──monitor // 日志
│ ├──errorLog // 异常日志
│ ├──loginInfo // 登录日志
│ ├──operLog // 操作日志
│ ├──system // 系统模块
│ ├──dept // 部门
│ ├──otree // 部门树
│ ├──post // 岗位
│ ├──dict // 字典
│ ├──menu // 菜单
│ ├──role // 角色
│ └──user // 用户
│ ├──404.vue // 404页面
│ └──reSetPsw.vue // 修改密码页面
│ ├── App.vue // 入口页面
│ ├── main.js // 入口 加载组件 初始化等
│ ├── permission.js // 权限管理
│ └── settings.js // 系统配置
├── .editorconfig // 编码格式
├── .env.development // 开发环境配置
├── .env.production // 生产环境配置
├── .env.test // 测试环境配置
├── .eslintignore // 忽略语法检查
├── .eslintrc.js // eslint 配置项
├── .gitignore // git 忽略项
├── babel.config.js // babel.config.js
├── package.json // 项目引入的包
└── vue.config.js // vue.config.js
## 2. 产品介绍
### 2.1. 产品特性
| 序号 | 名称 | 编号 |
| ---- | ------------------------ | ------ |
| 1 | 页面跳转后筛选项存储 | P20001 |
| 2 | 登录后跳转第一个权限菜单 | P20002 |
| 3 | 支持4种验证码类型 | P20003 |
| 4 | 皮肤切换功能 | P20004 |
#### 2.1.1. 页面跳转后筛选项存储
​ 路由切换时可以存储列表的筛选条件数据,关闭Tab页签时清除该页签下存储的筛选条件。该功能基于Vuex实现,当用户刷新浏览器页面时,所有存储的数据会自动清除。
**实现方法:**
**① 存储筛选项数据的公共方法 **
文件路径:src/assets/js/filterData.js
```js
import store from '@/store'
// 路由离开前存储筛选条件
export function setDataCache(path,param) {
store.dispatch('searchSave/searchParamsSet', {
path: path,
param: {
...param
}
}).then(r => {} )
}
// 获取缓存的筛选条件 分页参数需统一,如需自定义分页参数,在列表页自行修改
export function getDataCache(routerPath) {
if (store.getters.searchParams[routerPath]) {
const { searchParams } = store.getters;
const path = routerPath
const param = searchParams[path] // 保留着的查询条件
if (param){
return param
} else {
const paramNew = '{"page":1,"rows":10}'
return paramNew
}
} else {
// 如果没有存储筛选条件的数据,返回默认值
const paramNew = '{"page":1,"rows":10}'
return paramNew
}
}
```
**② 子页面调用**
**注:beforeRouteLeave()为vue的生命周期函数,与created()同级。获取筛选条件的数据时,分页参数统一为page=1,rows=10,如需自定义分页参数,请在获取筛选条件的数据后,给分页参数重新赋值。**
```js ```js
// 引用公共方法
import { getDataCache, setDataCache } from '@/assets/js/filterData'
// 路由离开前存储筛选条件
beforeRouteLeave(to, from, next) {
setDataCache(this.$route.path, this.queryParams)
next()
},
created() {
// 获取存储的筛选条件数据
// 分页参数初始化为{"page":1,"rows":10},如需自定义分页参数,自行修改
this.queryParams = JSON.parse(getDataCache(this.$route.path))
},
```
#### 2.2.2. 登录后跳转第一个权限菜单
​ 登录后不再跳转固定页面,而是跳转到用户所拥有菜单权限的第一个菜单。
**实现方法:**
**①路由守卫页面将固定路由跳转换成变量**
**注:将登录后的跳转路由设置为特殊路由,用于区分登录的路由跳转和项目内的其他路由跳转(防止页面刷新,刷新后回到了登录用户的第一个菜单而不是刷新页面)的问题 ** if (process.env.NODE_ENV === 'production') {
if (window) {
```js window.console.log = function() {}
//'/controlPlatform/control'登录后的跳转的特殊路由
if (to.path === '/controlPlatform/control') {
// 判断用户是否有路由
if (routers.accessedRoutes && routers.accessedRoutes.length > 0 && routers.getRouters && routers.getRouters.length > 0) {
// 测试 默认静态页面
// 根据roles权限生成可访问的路由表
router.addRoutes(routers.accessedRoutes) // 动态添加可访问路由表
next({ path: routers.accessedRoutes[0].children[0].path, replace: true }) // 跳转登录用户的第一个菜单
} else {
console.log('用户无权限1')
alert('用户无权限')
store.dispatch('FedLogOut').then(() => {
next({ path: '/login' })
})
} }
} else {
router.addRoutes(routers.accessedRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
} }
``` ```
#### 2.2.3. 支持4种验证码类型 如果想只在某个特地环境将console.log清空,只需替换production即可
​ 登录时验证码分五种类型(无验证码, 计算验证码, 字母验证码, 滑块验证, 文本循序验证码) 例如 将开发环境的console.log清空
**注:根据接口获取的验证码类型决定使用哪个子组件** 把production替换成.env.development文件中 ENV的值即可
文件路径:src/views/js/login/login.vue ## 压缩打包文件
``` 1. 在package.json引入依赖
<div v-if="captchaType === 'MATH' || captchaType === 'CHAR'" class="loginCode_formItem">
<el-form-item prop="code">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
@keypress.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<div class="login-code">
<img class="login-codeImg" :src="codeUrl" @click="getCode">
</div>
</div>
<el-form-item v-if="captchaType === 'BLOCK' || captchaType === 'WORD'" prop="code">
<div class="my_btn" @click="() => {if (!verify) verifyShowFlag = true}">
<div class="my_radar_btn" :class="[verify? 'my_radar_btn_success' : 'my_radar_btn_verify']">
<div class="my_radar_tip">
<el-popover
v-model="verifyShowFlag"
placement="right"
popper-class="verifyPopover"
:visible-arrow="false"
width="345"
trigger="manual"
>
<Verify
ref="verify"
:mode="'fixed'"
:captcha-type="captchaType"
:img-size="{ width: '323px', height: '155px' }"
@success="capctchaCheckSuccess"
/>
<div slot="reference">
<el-button v-show="!verify" class="my_radar_tip_blue" />
<div v-show="verify" class="geetest_success_box">
<div class="geetest_success_show">
<div class="geetest_success_pie" />
<div class="geetest_success_filter" />
<div class="geetest_success_mask" />
</div>
<div class="geetest_success_correct">
<div class="geetest_success_icon" />
</div>
</div>
</div>
</el-popover>
</div>
<div class="my_radar_text">
{{ verify ? '验证成功' : '点击按钮进行验证' }}
</div>
</div>
</div>
</el-form-item>
```
#### 2.2.4. 皮肤切换功能 ```json
"crypto-js": "4.1.1",
"compression-webpack-plugin": "^1.1.12",
```
​ 通过右上角的主题风格设置更改页面的皮肤风格,切换后改变localStorage存储通过localStorage存储的变量决定在manin.js文件引用对应皮肤的css文件 2. vue.config.js 中配置以下代码
​ 四套皮肤的css文件位置:src/styles/themeA||src/styles/themeB||src/styles/themeC||src/styles/themeD ```js
const CompressionWebpackPlugin = require('compression-webpack-plugin')
## 3. 代码规范 const productionGzipExtensions = ['js', 'css']
### 3.1. 基础规范 configureWebpack: {
plugins: [
#### 3.1.1. 列表 new CompressionWebpackPlugin({
filename: '[path].gz[query]', // 提示compression-webpack-plugin@3.0.0的话asset改为filename
![table.png](src%2Fassets%2Fimage%2FreadmeImg%2Ftable.png) algorithm: 'gzip',
+ 列表查询条件绑定的字段名统一命名为 `queryParams` test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
+ 分页参数字段名和默认值统一为 ` page=1,rows=10` threshold: 10240,
+ 查询条件区有统一的css样式,直接设置class名为 `search` minRatio: 0.8
})
##### 3.1.1.1. 查询条件区 ]
}
**注:prop绑定参数需与v-model绑定字段一致** ```
```vue
<div class="search">
<el-form ref="queryForm" style="padding: 0 0 0 10px" class="formClass" :model="queryParams" :inline="true" label-width="auto">
<el-form-item label="登录名" prop="username">
<el-input
v-model="queryParams.username"
placeholder="请输入登录名"
clearable
:maxlength="30"
size="small"
style="width: 150px"
/>
</el-form-item>
<el-form-item label="状态" prop="flag">
<el-select
v-model="queryParams.flag"
placeholder="请选择用户状态"
clearable
size="small"
style="width: 150px"
>
<el-option
v-for="dict in statusOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
</el-form>
</div>
```
##### 3.1.1.2. 按钮区 3.在vue.config.js文件configureWebpack对象配置 以下代码
+ 按钮有统一css样式,如果有特殊需求请与前端负责人沟通
+ 全局操作按钮样式统一使用commonField.js内的参数声明按钮样式和文字。
+ class为按钮的样式类名,type为按钮的类型,icon为按钮引用的图标,size为按钮的大小,@click为按钮点击后调用的方法
```vue
<el-form-item>
<!-- //查询按钮-->
<el-button
:class="commonField.queryClass"
:type="commonField.typePrimary"
:icon="commonField.queryIcon"
:size="commonField.smallSize"
@click="handleQuery"
>{{ commonField.queryName }}</el-button>
<!-- //重置按钮-->
<el-button
:class="commonField.resetClass"
:icon="commonField.resetIcon"
:size="commonField.smallSize"
@click="resetQuery"
>{{ commonField.resetName }}</el-button>
</el-form-item>
```
##### 3.1.1.3. 数据区
+ 表格有统一css样式,如果有特殊需求请与前端负责人沟通
+ data代表表格数据,label为表格列名,prop为对应列内容的字段名,该字段名要和data内的对象的字段名一致
+ 如果某一列的数据过长,使用:show-overflow-tooltip="true"
```vue
<el-table
v-loading="loading"
style="padding-right: 10px"
:data="userList"
>
<el-table-column type="index" label="序号" width="50" />
<el-table-column label="登录名" prop="username" :show-overflow-tooltip="true">
<template slot-scope="scope">
{{ scope.row.username || '-' }}
</template>
</el-table-column>
<el-table-column label="姓名" prop="userType" :show-overflow-tooltip="true">
<template slot-scope="scope">
{{ scope.row.name || '-' }}
</template>
</el-table-column>
<el-table-column label="手机号" prop="phone" :show-overflow-tooltip="true">
<template slot-scope="scope">
{{ scope.row.phone || '-' }}
</template>
</el-table-column>
<el-table-column width="120" label="状态" prop="flag">
<template slot-scope="scope">
<el-switch
v-model="scope.row.flag"
class="switchDisabledStyle"
inactive-value="0"
active-value="1"
@click.native="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="创建时间" prop="createDate" width="160">
<template slot-scope="scope">
<span>{{ scope.row.createDate | transformDateByFormat('YYYY-MM-DD HH:mm') }}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
width="180"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<!-- //修改-->
<el-button
v-hasPermi="hasUpdatePerm"
:class="commonField.updateClass"
:type="commonField.typeParent"
:size="commonField.size"
@click="handleUpdate(scope.row)"
>{{ commonField.updateName }}</el-button>
<!-- //重置密码-->
<el-button
v-hasPermi="hasResetPerm"
:class="commonField.resetPasClass"
:type="commonField.typeParent"
:size="commonField.size"
@click="handleResetPwd(scope.row)"
>{{ commonField.resetPassword }}</el-button>
<!-- //删除-->
<el-button
v-if="scope.row.businessId !== 1"
v-hasPermi="hasDelPerm"
:class="commonField.delClass"
:type="commonField.typeParent"
:size="commonField.size"
@click="handleDelete(scope.row)"
>{{ commonField.deleteName }}</el-button>
</template>
</el-table-column>
</el-table>
```
##### 3.1.1.4. 分页区
+ 分页统一靠右分布,默认为10条/页
+ total代表一共多少数据,page代表页码,limit代表每页的数据量。
```vue
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.page"
:limit.sync="queryParams.rows"
@pagination="getList"
/>
```
#### 3.1.2. 表单
![form.png](src%2Fassets%2Fimage%2FreadmeImg%2Fform.png)
+ 表单有统一css样式,如果有特殊需求请与前端负责人沟通
+ 表单内会有多种组件,如果需要调整某一个组件的全局样式,需要在src/styles/element-ui.scss文件内查找,不是全局样式,在对应的vue文件内进行修改。
+ 对表单数据进行校验,ref属性必须有。el-form中的model代表表单绑定的字段,rules为表单的校验。
+ prop代表表单域 model 字段,在有表单校验的情况下,该属性是必填的,且字段名要与rules内的字段名一致。
##### 3.1.2.1. 内容区
```vue
<el-form
ref="pwdForm"
label-width="80px"
:rules="pwdRules"
:model="pwdList"
>
<el-form-item
prop="oldPass"
label="旧密码"
>
<el-input
v-model="pwdList.oldPass"
type="password"
placeholder="请输入旧密码"
/>
</el-form-item>
<el-form-item
prop="pass"
label="新密码"
>
<el-input
v-model="pwdList.pass"
type="password"
placeholder="8~16位,由字母和数字混合组成"
/>
</el-form-item>
<el-form-item
prop="checkPass"
label="确认密码"
>
<el-input
v-model="pwdList.checkPass"
placeholder="请再次输入新密码"
type="password"
/>
</el-form-item>
<!--按钮区-->
</el-form>
```
##### 3.1.2.2. 按钮区
```vue
<el-form-item>
<el-button class="blue-btn" type="primary" @click="onSubmit">确定</el-button>
</el-form-item>
```
##### 3.1.2.3. 校验
**表单校验**
+ 表单校验中的required为是否必填,message为提示文字,trigger为触发校验方式
+ blur为失去焦点触发,change为数据改变触发。
```js ```js
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> plugins: [
<el-row> new CompressionWebpackPlugin({
<el-col :span="12"> filename: '[path].gz[query]', // 提示compression-webpack-plugin@3.0.0的话asset改为filename
<el-form-item v-if="form.businessId == undefined" label="登录名" prop="username"> algorithm: 'gzip',
<el-input v-model="form.username" placeholder="请输入登录名" /> test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
</el-form-item> threshold: 10240,
</el-col> minRatio: 0.8
<el-col :span="12"> })
<el-form-item label="部门" prop="postId"> ]
<treeSelect
v-model="form.deptId"
:disable-branch-nodes="true"
:options="deptChildren"
:show-count="true"
placeholder="请选择归属部门"
@input="changeValue"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
export default{
data(){
return{
// 表单校验
rules: {
username: [
{ required: true, message: '请输入登录名', trigger: 'blur' }
],
deptId: [
{ required: false, message: '请输入归属部门', trigger: 'change' }
]
}
}
}
}
```
**自定义校验**
+ 自定义校验需在data()里面自定义校验规则,在rules中的validator调用。
```js
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item v-if="form.businessId == undefined" label="密码" prop="password">
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" />
</el-form-item>
</el-col>
</el-row>
</el-form>
export default{
data(){
var trueGroupName = (rule, value, callback) => {
if (value && !value.trim()) {
return callback(new Error('请输入正确的用户昵称'))
}
callback()
}
var passwordCheck = (rule, value, callback) => {
const pattern = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/
if (!pattern.test(value)) {
callback(new Error('新密码必须为数字与字母的组合'))
}
callback()
}
return{
// 表单校验
rules: {
nickName: [
{ required: false, message: '请输入用户昵称', trigger: 'blur' },
{ validator: trueGroupName, message: '请输入正确的用户昵称' }
],
password: [
{ required: true, message: '请输入用户密码', trigger: 'blur' },
{ min: 8, max: 16, message: '长度在 8 到 16 个字符', trigger: 'blur' },
{
validator: passwordCheck,
trigger: 'blur'
}
]
}
}
}
}
``` ```
#### 3.1.3. 弹窗 4. 如果想关闭压缩文件 将第3步注释掉即可
![dialog.png](src%2Fassets%2Fimage%2FreadmeImg%2Fdialog.png)
##### 3.1.3.1. 标题区
+ 弹窗有统一css样式,如果有特殊需求,在对应的vue文件内进行修改。
+ 弹窗需要设置`visible`属性,它接收`Boolean`,当为`true`时显示 Dialog。
+ `title`属性用于定义标题,它是可选的,默认值为空。
```vue
<el-dialog
:close-on-click-modal="false"
title="修改密码"
width="30%"
custom-class="paddingFixed"
:visible.sync="resetPwdDiaLog"
@close="$refs.ruleForm.resetFields(),pwdType = 'password'"
>
<!--内容区-->
<!--按钮区-->
</el-dialog>
```
##### 3.1.3.2. 内容区
+ 弹窗的内容区可以自定义所用组件,不仅限于表单。
```vue
<!--内容区-->
<el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="auto" class="demo-ruleForm">
<el-form-item label="新密码" prop="newPassword">
<el-input
id="restPwd"
v-model.trim="ruleForm.newPassword"
:show-password="false"
autocomplete="off"
auto-complete="off"
:type="pwdType"
placeholder="请输入8~16位,由字母和数字混合所组成的新密码"
:maxlength="16"
>
<svg-icon
slot="suffix"
:style="{ width: '18px', height: '18px', verticalAlign: pwdTypeMap[pwdType] ? 'middle' : '-6px', marginRight: '5px', cursor: 'pointer' }"
:icon-class="pwdType === 'password' ? 'eye' : 'eye-open'"
@click.stop="pwdTypeMap[pwdType] ? pwdType = 'password' : pwdType = 'text'"
/>
</el-input>
</el-form-item>
</el-form>
```
##### 3.1.3.3. 按钮区
+ 弹框的取消按钮和确定按钮全局统一前后位置。
+ 按钮区需要具名为`footer``slot`,应用全局统一的class类名
```vue
<!--按钮区-->
<span slot="footer" class="dialog-footer">
<el-button class="cancelBtn" @click="resetPwdDiaLog = false">取 消</el-button>
<el-button class="submitBtn" :disabled="userRestLoading" :loading="userRestLoading" type="primary" @click="handleResetPwdSure">确 定</el-button>
</span>
```
#### 3.1.4. 后端请求接口
+ 后端请求接口的api文件统一放在/src/api 文件夹下,每个模块在改文件夹下新建文件夹,把对应的接口请求的js文件放在模块的文件夹下。
**注:文件src/utils/request.js已经设置请求头为application/x-www-form-urlencoded,无特殊情况不需要手动设置请求头**
##### 3.1.4.1. GET请求
+ get请求有两种传参方式,具体使用哪一种看后端如何接参。
```js
export function listRole(query) {
return request({
url: '/system/role/list',
method: 'get',
params: query
})
}
```
```js
export function getlistRole() {
return request({
url: 'system/role/listAll',
method: 'get'
})
}
```
```js
export function getRole(businessId) {
return request({
url: '/system/role/detail/' + businessId,
method: 'get'
})
}
```
##### 3.1.4.2. POST请求
```js
export function addRole(data) {
data = Qs.stringify(data) //把传参格式化为一个字符串
return request({
url: '/system/role/add',
method: 'post',
data: data
})
}
```
## 配置移动端控制台
1. 位置 在public文件加下添加 vconsole.min.js文件
##### 3.1.4.3. PUT请求 2. 在 public/index.html 文件夹下配置以下两行代码
+ put请求有两种传参方式,具体使用哪一种看后端如何接参。
```js
export function updateUser(data) {
data = Qs.stringify(data)//把传参格式化为一个字符串
return request({
url: '/system/user/update',
method: 'put',
data: data
})
}
```
```js
export function changeUserStatus(businessId, flag) {
const data = {
businessId,
flag
}
return request({
url: '/system/user/changeStatus',
method: 'put',
params: data
})
}
```
##### 3.1.4.4. DELETE请求
```js
export function delUser(userId) {
return request({
url: '/system/user/deleteLogical/' + userId,
method: 'delete'
})
}
```
#### 3.1.5. 打包地址
##### 3.1.5.1. 测试环境打包地址
文件路径:.env.test
只需修改VUE_APP_BASE_API
```json
# just a flag
ENV = 'test'
# 测试环境
# base api
VUE_APP_BASE_API = 'http://192.144.239.97:20075/' // 配置测试环境打包地址(后端的请求接口地址)
```
打包时运行:
```
npm run build:test
```
##### 3.1.5.2. 生产环境打包地址
文件路径:.env.production
只需修改VUE_APP_BASE_API
```json
# just a flag
ENV = 'production'
# 生产环境
# base api
VUE_APP_BASE_API = 'http://49.232.167.247:20014'// 配置生产环境打包地址(后端的请求接口地址)
```
打包时运行:
```
npm run build:prod
```
###
### 3.2. 全局规范
**注:全局样式如需更改请与前端负责人沟通!**
#### 3.2.1. 左测菜单栏样式
文件路径:对应皮肤文件里的sidebar.scss
#### 3.2.2. 右侧顶部导航栏样式
文件路径:src/layout/components/Navbar.vue
```css
.navbar {
font-size: 14px;
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
//box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
margin: 0 14px;
// 菜单隐藏按钮样式
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
// 右侧下拉菜单样式
.right-menu {
float: right;
height: 100%;
line-height: 50px;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
}
}
}
```
#### 3.2.3. 通用组件样式
文件路径:src/styles/element-ui.scss 该文件内样式为初始样式,每一套皮肤的组件样式在对应的theme文件内的common.scss
##### 3.2.3.1. 弹出框样式
```css
.el-dialog__wrapper {
display: flex;
align-items: center;
justify-content: center;
.el-dialog {
transform: none;
left: 0;
margin-top: 0!important;
position: relative;
margin: 0 auto;
border-radius: 6px;
min-width: 350px;
.el-dialog__header {
//display: flex;
//align-items: center;
//justify-content: center;
//width:100%;
//height:45px;
//padding: 0;
//background:rgba(237,240,245,1);
font-size: 16px;
color: #333333;
border-radius:6px 6px 0px 0px;
.el-dialog__headerbtn {
top: 15px;
}
}
.el-dialog__body {
min-height: 60px;
overflow-y: auto;
max-height: 60vh;
position: relative;
border-bottom: none;
padding: 10px 25px 25px 25px;
font-size: 14px;
color: #666666;
.el-form {
.el-form-item {
margin: 15px;
}
.el-form-item:last-child {
margin-bottom: 0;
}
}
}
.el-dialog__footer {
//border-top: 1px solid rgba(231, 231, 231, 1);
height: 62px;
.el-button {
font-size: 14px !important;
}
}
}
}
```
##### 3.2.3.2. 表单样式
```css
.el-form{
.el-form-item{
.el-form-item__label{
font-weight: inherit;
}
}
.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before, .el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before{
color: #f52929;
}
}
```
##### 3.2.3.3. 开关按钮
```css
.el-switch {
height: 18px; //启停按钮高度,
.el-switch__core {
height: 18px !important; //启停按钮高度
&:after {
content: "";
position: absolute;
top: 0px;
left: 1px;
border-radius: 100%;
-webkit-transition: all .3s;
transition: all .3s;
width: 16px;
height: 16px;
background-color: #fff;
}
}
&.is-checked {
.el-switch__core {
&::after{
left: 100%;
margin-left: -17px;
}
}
}
}
```
##### 3.2.3.4. 下拉框样式
```css
.el-select-dropdown {
.el-select-dropdown__item {
color: #999999;
// 下拉框 hover时显示淡蓝色
&:hover {
background-color: #ecf9fe !important;
}
&.selected {
color: #333333;
}
}
// 多选框 样式更改
&.is-multiple {
.el-select-dropdown__item {
color: #999999;
// 下拉框 hover时显示淡蓝色
&:hover {
background-color: #ecf9fe !important;
}
&.selected {
color: #333333;
}
}
}
}
// 时间选择器样式改写
.el-date-editor {
.el-input__inner {
padding: 0 60px 0 10px;
}
.el-icon-circle-close {
right: 30px !important;
}
.el-input__prefix {
right: 5px !important;
left: auto;
}
.el-input__suffix {
right: 35px !important;
.el-input__suffix-inner {
}
}
}
```
##### 3.2.3.5. 表格样式
```css
.el-table {
th {
padding: 0;
color: #333333;
background-color: #ecf9fe;
border-right: 1px dashed #EBEEF5;
.cell {
font-size: 14px;
//padding: 0;
padding-left: 10px;
display: flex;
height: 43px;
justify-content: flex-start;
align-items: center;
}
}
td {
padding: 0;
border-right: 1px dashed #EBEEF5;
.cell {
font-size: 14px;
//padding: 0;
padding-left: 10px;
height: 39px;
text-align: left;
line-height: 39px;
//justify-content: flex-start;
}
}
tr th:last-child {
border-right: 1px solid #EBEEF5;
}
tr td:last-child {
border-right: 1px solid #EBEEF5;
}
}
// 去掉表格 边框
.el-table--group, .el-table--border {
border: none !important;
}
.el-table--group::after, .el-table--border::after {
top: 0;
right: 0;
width: 0;
height: 100%;
}
.el-table tr td:last-child {
border-right: 0 !important;
}
```
##### 3.2.3.6. 折叠面板样式
```css
.el-collapse {
.el-collapse-item__header {
height: 53px;
line-height: 53px;
}
}
```
##### 3.2.3.7. 按钮样式
```css
// 成功按钮的样式修改
.el-button--success {
color: #fff;
font-size: 14px;
background-color: $color-green !important;
border-color: $color-green !important;
&:hover {
background-color: $color-green-light-btn !important;
border-color: $color-green-light-btn !important;
}
&:focus {
background-color: $color-green-deep !important;
border-color: $color-green-deep !important;
}
}
// 按钮字体14px
.el-button--small {
font-size: 14px;
}
// 文字按钮需要14px
.el-button--text {
border-color: transparent;
background: transparent;
padding-left: 0;
padding-right: 0;
font-size: 14px;
}
// 文字按钮 样式
.el-button--text {
&.primary {
color: $color-theme;
}
&.success {
color: $color-green;
}
&.danger {
color: $color-red;
}
&.warning {
color: $color-orange;
}
}
```
### 3.3. 注意事项
**store、utils文件夹下的js文件可以添加代码,现有代码不要修改!**
**components文件夹下的文件为通用组件,现有组件不要修改!** ```html
<script src="./vconsole.min.js"></script>
<script>new VConsole()</script>
```
**公共的样式不要随意修改,如有修改需要及时沟通!** 3. 去掉移动端控制台 将第二步代码注释掉即可
\ No newline at end of file \ No newline at end of file
...@@ -59,6 +59,13 @@ Viewer.setDefaults({ ...@@ -59,6 +59,13 @@ Viewer.setDefaults({
} }
}) })
// 打包清除所有console.log
if (process.env.NODE_ENV === 'production') {
if (window) {
window.console.log = function() {}
}
}
// 全局方法挂载 // 全局方法挂载
Vue.prototype.$WebView = WebView Vue.prototype.$WebView = WebView
Vue.prototype.getDict = getDict Vue.prototype.getDict = getDict
......
...@@ -58,6 +58,7 @@ export default { ...@@ -58,6 +58,7 @@ export default {
console.log('调用前', getToken()) console.log('调用前', getToken())
const params = { const params = {
flag: 'openCamera', flag: 'openCamera',
subPath: 'jbcheck',
tokenMsg: getToken() tokenMsg: getToken()
} }
this.$WebView.openCamera(params).then(res => { this.$WebView.openCamera(params).then(res => {
...@@ -69,6 +70,7 @@ export default { ...@@ -69,6 +70,7 @@ export default {
/** 拍照取相册按钮*/ /** 拍照取相册按钮*/
handleTakePhotosAlbum() { handleTakePhotosAlbum() {
const params = { const params = {
subPath: 'jbcheck',
tokenMsg: getToken() tokenMsg: getToken()
} }
this.$WebView.openCameraStorage(params).then(res => { this.$WebView.openCameraStorage(params).then(res => {
...@@ -79,6 +81,7 @@ export default { ...@@ -79,6 +81,7 @@ export default {
/** 全部实现功能(带相机,相册,文件资源功能)*/ /** 全部实现功能(带相机,相册,文件资源功能)*/
handlePpenCameraAll() { handlePpenCameraAll() {
const params = { const params = {
subPath: 'jbcheck',
tokenMsg: getToken() tokenMsg: getToken()
} }
this.$WebView.openCameraAll(params).then(res => { this.$WebView.openCameraAll(params).then(res => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment