Appearance
核心扩展包 mas-core
核心扩展包负责构建前端基础框架,引入前端框架Vue
、状态管理库Vuex
,封装本地缓存Cache
、消息推送WebSocket
、服务接口API
及Vue框架扩展等,为前端开发提供基础封装、能力支持。
核心扩展包不包含UI相关内容,可以同时支持PC端、移动端等
为平台扩展的能力
- 状态管理(Vuex)
- Ajax请求(Axios)
- 服务接口
- 本地缓存(localStorage、sessionStorage)
- WebSocket
- 前端消息总线
- 当前微应用与上下文获取
- 权限判断
- 异步资源加载
- 树形数据合并工具
- 时间、数字、金额等格式化工具方法
引入的框架
Vue框架
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。MAUI系统采用外部依赖Vue方式,由前端底座负责载入,当前版本为 2.6.12
。 具体文档可查看 Vue2官网
说明
Vue 由前端底座统一引入,各微应用设置为外部依赖后打包发布。
Vuex库
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 当前版本为 3.6.2
,具体文档可查看 Vuex3官网
Axios库
Axios
是一个基于 promise
的网络请求库,可以用于浏览器和 node.js
,使用简单,包尺寸小且提供了易于扩展的接口。当前版本为 0.21.4
,具体文档可查看 Axios 官方文档
封装的对象
本地缓存
注意
直接采用localStorage
与sessionStorage
操作数据将出现租户、站点数据污染,务必使用封装的缓存对象操作。
本地缓存通过分装localStorage
与sessionStorage
实现,分别提供local
和session
对象,分别提供 get
、set
和remove
方法,具体如下:
js
// 设置缓存
set(key, value) {}
// 读取缓存
get(key, defaultValue) {}
// 移除缓存数据
remove(key) {}
说明
local对象使用localStorage存储,不随浏览器的关闭而消失,但它的存储空间较小(一般为5M),而且缺少安全机制,因此不宜存储敏感信息和大量信息
WebSocket 消息推送
通过封装WebSocket对象,提供 conn
、 open
、 close
、 send
等方法,具体如下:
js
class WSClient {
// 地址默认从window.location中获取,默认为:hostname:port/ws
url,
// 断网是否重连
reconn : true
// 是否禁用
disableWebSocket: true
// 连接
conn(url) { }
// 根据上下文,打开WebSocket连接
open(ctx) { }
// 关闭连接
close() { }
// 发送消息
send(msg) { }
}
url 默认从网页中计算获得,计算规则为: hostname:port/ws
可以通过上下文的 disableWebSocket
属性,设置是否禁用 WebSocket
连接
对微应用能力的扩展
状态管理
平台基于Vuex实现状态管理,分为全局状态管理和各微应用的模块化状态管理两个部分。
全局状态管理
全局状态管理由核心扩展模块定义,各微应用可以通过 this.$app.ctx.store
方式调用,具体如下:
js
{
state: {
// 是否锁屏
locked: false,
// 当前页面访问路径
path: '/',
// 公开页面路径集合
publics: new Set(),
// 会话ID
sessionId: "",
// 用户信息
user: {
// 登录名
username: "",
// 是否登录
auth: false,
// 头像
avatar: ''
},
// 站点配置信息
setting: {},
// 会话超时重新登录后需要自动发起的请求
reloads: [],
// 登录错误信息
error: "",
// 当前用户权限信息
powers: {
r: {},
p: {}
},
// 业务菜单
navs: [],
// 系统菜单
sysNavs: [],
// 有权限访问的路径集合
paths: new Set(),
// 登录后的首页
home: "/",
// 表格建议高度
tableBodyHeight: 0,
// 是否全屏
fullscreen: false,
printAll: true,
showTenantGuide: false,
badge: {},
isShowMessages: false,
messagesContet: ''
},
mutations: {
// 设置租户配置信息(用于租户标识请求获取时)
config(state, { setting, tenant }) {},
// 设置租户配置信息(用于设置缓存读取时)
setting(state, setting) {},
// 锁定屏幕
lockscreen(state) {},
// 解锁屏幕
unlockscreen(state) {},
// 强制要求身份认证
auth(state) {},
// 设置会话ID
sessionId(state, sessionId) {},
// 设置用户信息,并重新计算菜单
user(state, user) {},
// 重新计算菜单
navs(state) {},
setNavs(state, navs) {},
// 退出
logout(state) {},
// 重新请求服务
reload(state, request) {},
// 设置错误信息
error(state, error) {},
// 设置默认打开页面
home(state, home) {},
tableBodyHeight(state, tableBodyHeight) {},
fullscreen(state, fullscreen) {},
printAllChanged(state) {},
showTenantGuide(state, flag) {},
clearBadge(state) {},
setBadge(state, obj) {},
showMessage(state) {},
hideMessage(state) {},
hideIsNeedChangePwd(state) {},
hideForceChangePassword(state) {},
setMessage(state, content) {}
},
actions: {
// 判断路由页面是否有权限
access(context, router) {},
// 重新发起请求
reload(context, request) {},
// 登出系统
logout(context) {},
// 账号密码登录
login(context, { username, password, reload }) {},
// 扫码登录
qrLogin(context, { qrCode, reload }) {},
// 政务钉登录
ddLogin(context, { code, reload }) {},
// 锁定页面
lockscreen(context) {},
// 解锁页面
unlockscreen(context, {
username,
password
}) {},
changePwd(context, changeForm) {}
},
getters: {
auth(state) {},
user(state) {},
setting(state) {},
reloads(state) {},
error(state) {},
navs(state) {},
sysNavs(state) {},
home(state) {},
powers(state) {},
locked(state) {},
tableBodyHeight(state) {},
fullscreen(state) {},
printAll(state) {},
showTenantGuide(state) {},
badge: (state) => (names) => {},
showMessage(state) {},
getMessage(state) {},
},
// 根据各应用定义的store属性,生成并注册模块
modules
}
微应用的模块化状态管理
各微应用可以以模块化方式定义自己的状态对象,通过 this.$app.store
方式调用,可通过在Application参数对象中定义 store
属性,属性值参考如下:
js
{
// 默认采用独立命名空间模式,空间名为应用的name属性值
// namespaced: false,
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
每个应用的状态管理对象采用独立命名空间模式注册,空间名为应用的 name
属性值,如不想使用独立命名空间模式时,可将 namespaced
设置为 false
。
模块模式的状态管理用法,参考 Vuex 模块
Ajax请求
平台通过Axios库来实现前后端请求交互,可通过 this.$app.axios
获取每个微应用的 Axios
实例,此实例提供缓存、统一的异常处理等
缓存
所有 get
请求,只要在请求参数对象中,设置 cache > 0
,就会开启用缓存,在设定的时间范围内,多次请求均只会根据第一次返回的结果来返回,避免频繁请求后台导致的性能问题。
axios(config)
json
{
...
// 缓存时间,以秒为单位,大于0时启用缓存
cache,
// 仅为GET方法启用缓存
method,
// 如果没有cacheKey属性,缓存以url作为唯一性标识
url,
// 如果多个不同请求参数有差异,但url相同,
// 需要开启缓存的话,必须设置cacheKey代替url作为可区分的唯一性标识
cacheKey
}
错误处理
401身份认证错误
针对会话超时,需要重新登录的情况,统一弹出登录窗口,并在登录成功后对原始请求实现重发。
TODO
此处可以优化,需要重新加载的请求无需放入状态管理。
其他错误
平台提供默认的错误显示功能,特殊请求中如不需要平台接手并显示错误信息,可在 config
配置对象中增加 systemErrorShow
属性并设置为 false
即可。
服务接口
服务接口是通过配置方式来简化Ajax调用的一种便捷方式。各微应用可通过在配置参数中增加 apis
属性,定义后台接口,应用页面中可通过 this.$app.$api_<api_name>
方式调用,具体定义格式如下:
js
{
// 定义基础路径,作为api路径的前缀自动拼接
base: '/api',
// 字符串模式,默认get模式
userInfo: "/user-info",
// post模式
addUser: "post:/user-add",
// 对象模式定义
delUser: {
method: "post",
url: "/user-del",
...
}
}
微应用服务接口可以通过字符串和对象两种模式定义。字符串模式定义时,key
为接口名称 <api_name>
,值为 <url>
或者 <method>:<url>
,<method>
未定义时为 get
;对象模式时,结构同 Axios
请求的 config
对象。
定义的服务接口,会自动以 $api_<api_name>(config)
(get时) 或 $api_<api_name>(data, config)
(post/put/option等) 方法,绑定在 Application
实例上,页面中可以 `this.$app.$api_<api_name>方式调用。
说明
每个微应用拥有一个独立的Axios实例
用户登入/退出事件
当微应用中需要监听用户登入/退出事件时,只需要在应用定义中实现 "logged-in"(user)
和 "logged-out"()
方法即可,设置如下:
js
{
...
"logged-in": function(user) {
// 用户登入后运行,user为用户信息对象
},
"logged-out": function() {
// 用户退出系统后运行
}
}
对上下文对象的扩展
为上下文增加WebSocket连接、合并树形数据、本地缓存和状态管理能力
js
{
// WebSocket连接
ws,
// 合并带插槽特性的树形参数,并做节点转换
_mergeTreeSlots(name, defaultSlot, rootSlot, handler){},
// 合并
_mergeTree(name, sameAttrName, mergeFunc, itemFunc){},
// 基于localStorage的缓存
local,
// 基于sessionStorage的缓存
session,
// 平台全局状态管理对象,基于Vuex
store,
}
_mergeTreeSlots
与 _mergeTree
两个方法用于应用配置对象树形数据的合并。前者支持插槽机制,可以灵活组装树型数据;后者合并树形数据,无插槽机制,效率更高。
对Vue原型的扩展
当前微应用
页面中可通过 this.$app
获取当前页面所在微应用实例对象
说明
此处采用 Vue
的 provide/inject
机制,实现父子继承方式,传递微应用实例对象
权限判断
页面中可通过 this.$auth(rightExp)
校验登录用户的权限信息是否具备,true
表示用户具备表达式所述权限。
其中 rightExp
为权限表达式,可采用 r.<role_code>
、p.<permission_code>
分别代表指定code的角色和权限项,还可以使用 &&
、||
、()
等,分别表示与、或和优先计算,举例如下:
js
// 管理员角色
r.admin
// 修改用户或删除用户权限
p.edit_user || p.del_user
// 管理员,或者具备删除用户权限的子管理员
r.admin || (r.sub_admin && p.del_user)
本地缓存
页面可通过 this.$local
访问 localStorage 缓存封装对象 本地缓存,同 this.$app.ctx.local
会话缓存
页面可通过 this.$session
访问 sessionStorage 缓存封装对象 本地缓存,同 this.$app.ctx.session
异步加载资源文件
js
$js(moduleName, url).then(module=>{
// moduleName 为js文件中定义的模块名称,如echarts,此名称必须和js中定义的
// url 为js文件地址,如https://unpkg.zhimg.com/echarts@5.0.2/dist/echarts.common.min.js,js文件中必须把需要加载的模块,定义为window[moduleName]
// module 为加载后的模块
... // 此处代码为css加载成功后执行
})
$loadJs(moduleName, url).then(module=>{
// 同$js方法
})
$css(url, id, reload).then(()=> {
// url 为需要加载的css文件地址
// id 为页面加载对象的唯一编号,用于删除和重新加载,单次加载可不指定
// reload 强制重新加载,默认首次加载即缓存,设置为true后,会再次加载并覆盖原先相同id的css文件
... // 此处代码为css加载成功后执行
})
$loadStyle(url, id, reload).then(()=> {
// 同$css方法
})
$removeStyle(id) // 根据id,删除css加载对象,加载的css文件内容将失效
可以通过以上方法,异步加载js文件、css文件等
WebSocket
js
$ws // 提供WebSocket封装对象的引用
前端消息
js
$eventbus // 提供Vue内置的前端消息引擎
系统时间
js
$now() // 当前时间,"YYYY-MM-DD HH:mm:ss"
$today() // 今天,"YYYY-MM-DD"
$CNToday() // 今天,"YYYY年MM月DD日"
$datetime(time) // 格式化为"YYYY-MM-DD HH:mm:ss"
$MDTime(time) // 格式化为"MM-DD HH:mm:ss"
$date(time) // 格式化为"YYYY-MM-DD"
$weekday(time) // 格式化为"星期?"
$time(time) // 格式化为"HH:mm:ss"
$CNDate(time) // 格式化为"YYYY年MM月DD日"
$CNYearMonth(time) // 格式化为"YYYY年MM月"
$90days() // 获取最近90天的起止时间,返回"YYYY-MM-DD HH:mm:ss"格式的字符串数组[start, end]
$360days() // 获取最近360天的起止时间,返回"YYYY-MM-DD HH:mm:ss"格式的字符串数组[start, end]
数字
js
$number(value, pattern) // value为数字, pattern为格式,如“0,000.00”,将数字格式化为字符串
value | pattern | String |
---|---|---|
10000 | '0,0.0000' | 10,000.0000 |
10000.23 | '0,0' | 10,000 |
10000.23 | '+0,0' | +10,000 |
-10000 | '0,0.0' | -10,000.0 |
10000.1234 | '0.000' | 10000.123 |
100.1234 | '00000' | 00100 |
1000.1234 | '000000,0' | 001,000 |
10 | '000.00' | 010.00 |
10000.1234 | '0[.]00000' | 10000.12340 |
-10000 | '(0,0.0000)' | (10,000.0000) |
-0.23 | '.00' | -.23 |
-0.23 | '(.00)' | (.23) |
0.23 | '0.00000' | 0.23000 |
0.23 | '0.0[0000]' | 0.23 |
1230974 | '0.0a' | 1.2m |
1460 | '0 a' | 1 k |
-104000 | '0a' | -104k |
1 | '0%' | 100% |
0.974878234 | '0.000%' | 97.488% |
-0.43 | '0 %' | -43 % |
0.43 | '(0.000 %)' | 43.000 % |
金额
js
$CNY(number) // number为分的整数,格式化为中文的元角分
$money(number) // number为分的整数,格式化为"0,000.00"
具体使用可参考 websocket-消息推送
全部角色、权限项
扩展应用配置对象,通过增加 roles
和 permissions
分别定义微应用所需的角色和权限项,平台通过合并获取全部的角色、权限项及角色与权限项之间的关系。
此信息用于初始化,不作为登录用户的权限数据