介绍
OA版本的前端是基于 Iview 开发,使用 Vue Cli 3 构建,支持 Chrome、Safari、Firefox 等现代主流浏览器,支持 IE10、IE11、Edge 浏览器。
您可以访问 Iview官网文档 去查阅基础组件API,您还可以查阅 AgileBPM基础组件API
快速开始
安装
请参考README 文件
初次设置
在开始开发前,有一些内容需要提前一次性设置,分别是:
- .env 文件中的 VUE_APP_TITLE 字段,设置为网站的标题,它仅用于在
public/index.html
模板中,替换对应的标题。它决定了最终入口 html 文件的<title></title>
的内容。每页的标题是在路由配置中设置,在新增页面文档中查看。
- 网站 logo 图片,logo 总共有 3 个:
src/assets/images/logo.png
:完整 Logo(深色字),用于背景为浅色时(如登录页、亮色侧边栏);src/assets/images/logo-dark.png
:完整 Logo(白色字),用于背景为深色时(如暗色侧边栏);src/assets/images/logo-small.png
:正方形 Logo,仅 icon,无文字,用于侧边栏折叠时。
目录结构
├── public # 静态资源 |
setting.js业务配置
请参考 setting.js
文中描述
新增页面
增加一个新的页面,需要 3 步:
- 创建新的
.vue
页面文件 - 在路由中添加新页面
- 在菜单中配置该页面
以下是具体使用方法:
创建新的 .vue 页面文件
所有的页面文件在 src/pages
目录下管理,处于可维护性考虑,建议对页面进行目录拆分,而不是直接将 .vue
文件放置在 src/pages
下
在路由中添加新页面
一个页面主要分为两类:
- 在主框架内的页面,即包含了顶部、侧边栏、多页签等基础布局(大部分页面应当属于此类型)
- 在主框架外的页面,常见的有首页、登录 / 注册 / 注册结果页,它们较独立,没有其他布局
打开路由配置文件 src/router/routes.js
。
如果是主框架外的页面,将路由配置添加在 frameOut
中,它不含有基础布局。
如果是主框架内的页面,则将路由配置添加在 frameIn
中。
由于框架内的页面通常较多,处于可维护性考虑,建议分模块,同样以 dashboard
为例,先创建子路由文件:src/router/modules/dashboard.js
,示例内容如下:
import BasicLayout from '@/layouts/basic-layout'; |
其中第一项name: 'dashboard'
并不作为页面直接访问,而是一个中间的二级页面,真正访问的是它的子页面,也就是 children
下的路由。所以在该中间页面中,有一个component: BasicLayout
的设置,它决定了子页面使用哪个布局(默认带的是典型布局,即 BasicLayout),redirect
选项为强制输入该中间路由时,重定向的页面,通常为 children下的第一个页面。
创建好子路由后,在把它设置在顶级路由中即可:
src/router/routes.js
import dashboard from './modules/dashboard';
const frameIn = [
{
path: '/',
redirect: {
name: 'dashboard-console'
},
component: BasicLayout,
children: [
{
path: 'index',
name: 'index',
redirect: {
name: 'dashboard-console'
}
},
{
path: 'log',
name: 'log',
meta: {
title: '前端日志',
auth: true
},
component: () => import('@/pages/system/log')
},
// 刷新页面 必须保留
{
path: 'refresh',
name: 'refresh',
hidden: true,
component: {
beforeRouteEnter (to, from, next) {
next(instance => instance.$router.replace(from.fullPath));
},
render: h => h()
}
},
// 页面重定向 必须保留
{
path: 'redirect/:route*',
name: 'redirect',
hidden: true,
component: {
beforeRouteEnter (to, from, next) {
next(instance => instance.$router.replace(JSON.parse(from.params.route)));
},
render: h => h()
}
}
]
},
dashboard
];
路由的各选项说明
路由中的配置都是 vue-router 的标准配置,除了 meta
选项。
meta 中主要有几个可选项:
- title:当前页面的标题,最终更改文件在
src/libs/util.js
中完成,而调用 util.js 中 修改标题 方法是在src/router/index.js
的router.afterEach
中。util.title 方法还支持另一个选项count
,设置后,标题最终会渲染形如:(3条消息)页面标题 - 标题后缀
可以根据需求在 util.js 中适当修改文案描述和逻辑。
auth:路由级别的鉴权依据,详见文档鉴权篇-路由鉴权。
cache:当前页面是否缓存,如果设置为
true
,该页面会在<keep-alive>
中被缓存closable 2.1.0:设置为
false
,则该页签不可关闭,仅对首页有效。
路由常见问题
- 设置 cache 后缓存无效
设置缓存,需要设置 name,包括路由的 name 和 .vue 页面的 name。
在菜单中配置该页面
在 设计开发平台 -系统配置-资源配置中 新增菜单资源
- 资源树切换平台至 “门户平台-OA”,在资源树中 右键 点击“添加资源”
- 输入资源信息
- 资源别名:唯一的CODE
- 资源名:菜单的名字(国际化版本需要在 内容管理-翻译管理 中定义国际化 别名为menu.资源别名)
- 请求地址:为路由地址
- 默认打开: 菜单默认会以展开形式展现
- 类型: 选择菜单
新增样式
样式是在目录 src/styles
下进行管理的,且使用 less
进行预处理。
入口的 less 文件在src/styles/index.less
内,这里可以导入需要的样式文件。初始时会导入所需的默认配置:
default/index.less:主题修改在这里。
font/iconfont.css:系统所需的第三方 icon
setting.less:样式的全局配置,已在业务配置章节介绍
common.less:通用样式,见下节
layout/index.less:引入布局样式,默认引入的是自带的典型布局样式
pages/account.less:具体的页面样式,如有很多,可以拆分 modules
对于额外的页面样式,有两种方法集成,一种是统一放置在src/styles
里,通过配置 index.less
引入,另一种是直接写在具体的 .vue 页面文件的 <style></style>
里。
由于 less 的特性,建议您这样命名:
- 对于页面,以 .page- 开头,比如 .page-dashboard-monitor-xxxxxx
- 对于通用组件,以 .i- 开头,比如 .i-copyright
如何使用第三方 iconfont
如果 iView 自带的 700+ 图标无法满足业务需求,或需要自定义图标,建议使用 iconfont 管理您的图标
引入外部模块
以 vue-grid-layout
为例
安装依赖
在终端安装 vue-grid-layout:
$ npm install vue-grid-layout --save
使用
全局注册
在 src/main.js
中注册并使用组件:
// src/main.js |
全局注册后,任何地方都可以使用 <i-grid-layout>
和 <i-grid-item>
两个组件了。
局部注册
只在需要的页面或组件中注册:
<template> |
自己封装组件
如果是自己封装的组件,可以放置在src/components
目录内,使用方法不变。
支持IE
OA 前端默认支持 IE 11,但需要屏蔽部分组件
- 屏蔽手写签名组件
abSignature
的引入,引入页面位于:/agilebpm-oa-ui/src/components/ab-form/formService.js
46行
构建和发布
构建
在终端执行命令进行项目打包
:$ npm run build
构建打包成功之后,默认会在根目录生成 dist
文件夹,里面就是构建打包好的文件,通常是 **.js
、*.css
、index.html
等静态文件。
发布
前端是典型的 SPA 类型的工程,打包后的文件分为 index.html 和其它静态资源,整个项目只有 index.html 这一个入口文件,其它都是 Webpack 来管理的了。
所以,发布一个 SPA 项目,核心就是渲染这个 index.html 以及静态资源的位置。
一般来说,你可能使用 Nginx、Apache 等渲染这个入口文件 index.html,也可以使用 CDN 的服务,比如七牛。
更多资料可以查阅 vue官方文档
发布失败常见问题
服务端是否支持 history 路由模式。框架默认为 history 模式,需服务端处理 404 情况,否则可以改为 hash 模式。
静态资源地址 publicPath 是否修改正确,可以修改为绝对地址,避免出错。
使用 Mock 数据模拟
使用方法
OA-UI 是 基于 Mock.js 做的数据模拟
对于 Mock.js 的基本用法,请直接阅读 Mock.js 的文档。
下面介绍如何对一个接口返回内容做模拟。
我们已经使用 Mock.js 做了一些上下文处理,使用者只需要关心自己的接口和返回内容即可。
以登录接口为例:
创建文件 src/mock/api/account.js:
const userDB = [ |
示例中默认导出的数组就是一系列的模拟请求,其中每项配置如下:
- path:请求地址,一般要与真实地址区分,比如真实地址是
/login
,所以模拟请求地址加了前缀/api/login
。 - method:请求方法。
- handle:处理逻辑,这里返回模拟的数据。
定义好了模拟返回数据,使用起来与调用真实接口类似,只用在请求数据时,将请求的真实接口 url 改为模拟数据的 url 即可。
比如登录接口:
// src/api/account.js |
这里的 url
写的就是模拟的 path /api/login
,当测试完成,服务上线后,只用改成真实的 /login
即可。
关闭数据模拟
如果你不需要数据模拟,直接在配置文件 src/setting.env.js
中将 isMock
设置为 false
即可。
或者你可以彻底移除跟 mock 相关的功能,步骤如下:
npm remove mockjs --save
删除
src/mock
删除 vue.config.js 中相关代码:
// 判断是否需要加入模拟数据 |
Vuex
Account
account 模块负责实现用户的注册、登录、注销等功能。
文件位置在 src/store/modules/admin/modules/account.js。
User
user 模块负责实现设置和读取用户的登录信息。
文件位置在 src/store/modules/admin/modules/user.js
。
可以获取当前用户信息如:
//引入 |
设置登录用户信息
this.$store.dispatch("admin/user/set", user); |
DB 前端持久化存储
概念介绍
db 模块负责实现持久化存储。
文件位置在 src/store/modules/admin/modules/db.js
。
持久化存储,通常是指前端将一些数据长期存储在浏览器中,不随着刷新页面、重启浏览器等行为而消失。常见的办法有 Cookies 存储和 LocalStorage 存储
db模块 数据持久化存储方案依赖浏览器的 LocalStorage,基于 lowdb 进行进一步封装,使用体验接近 Vue.js 的模式,并更加简单、高可维护、可扩展。
db模块持久化存储,更像是一个小型数据库,具有以下特征,而这些是直接使用 LocalStorage 所不具备的:
- 可根据不同登录用户划分存储区域,不同的登录(或未登录)用户,所存储的空间是不同的,而不是共享一个存储空间(可开关)。
- 可根据路由划分存储区域,同一个 key,可配置在不同的路由下进行存储,不同路由获取的 value 可不同(可开关,可同时再区分用户)。
- 可快速保存/读取当前 Vue 实例的所有 data(可区分用户)。
使用方法
- 一:保存任意数据 - 区分用户 - 区分页面
写入数据:
const db = await this.$store.dispatch('admin/db/databasePage', { |
读取数据:
const db = await this.$store.dispatch('admin/db/databasePage', { |
- 二:保存任意数据 - 区分用户 - 不区分页面
写入数据:
const db = await this.$store.dispatch('admin/db/database', { |
读取数据:
const db = await this.$store.dispatch('admin/db/database', { |
- 三:保存任意数据 - 不区分用户 - 区分页面
写入数据:
const db = await this.$store.dispatch('admin/db/databasePage'); |
读取数据:
const db = await this.$store.dispatch('admin/db/databasePage'); |
- 四:保存任意数据 - 不区分用户 - 不区分页面
写入数据:
const db = await this.$store.dispatch('admin/db/database'); |
读取数据:
const db = await this.$store.dispatch('admin/db/database'); |
- 五:保存整页数据 $data - 区分用户
写入数据:
this.$store.dispatch('admin/db/pageSet', { |
读取数据:
// 获取数据 |
- 六:保存整页数据 $data - 不区分用户
写入数据:
this.$store.dispatch('admin/db/pageSet', { |
读取数据:
// 获取数据 |
七:Root 级别存储 - 区分用户
提示:该方法应该是开发系统模块所使用,业务中不应该直接使用。
写入数据:
this.$store.dispatch('admin/db/set', { |
读取数据:
const value = await this.$store.dispatch('admin/db/get', { |
- 八:Root 级别存储 - 不区分用户
写入数据:
this.$store.dispatch('admin/db/set', { |
读取数据:
const value = await this.$store.dispatch('admin/db/get', { |
清空存储实例
- 清空持久化数据对象
不区分用户清空:
this.$store.dispatch('admin/db/databaseClear'); |
区分用户清空:
this.$store.dispatch('admin/db/databaseClear', { |
如果您想进行后续操作,可以接受返回值,返回值为可以直接操作的 db 对象:
const db = await this.$store.dispatch('admin/db/databaseClear'); |
清空持久化数据对象 [ 区分页面 ]
不区分用户清空:
this.$store.dispatch('admin/db/databasePageClear'); |
区分用户清空:
this.$store.dispatch('admin/db/databasePageClear', { |
如果您想进行后续操作,可以接受返回值,返回值为可以直接操作的 db 对象:
const db = await this.$store.dispatch('admin/db/databasePageClear'); |
清空页面快照
不区分用户清空:
this.$store.dispatch('admin/db/pageClear'); |
区分用户清空:
this.$store.dispatch('admin/db/pageClear', { |
如果您想进行后续操作,可以接受返回值,返回值为可以直接操作的 db 对象:
const db = await this.$store.dispatch('admin/db/pageClear'); |