简体中文 | English
- 数据请求的处理
- 支持获取全部数据
- 支持分页获取数据
- 支持对数据的各种请求处理(PUT、POST、GET、PATCH、DELETE、HEAD 等)
src/stores/base.js
- 资源数据的 Store 继承于 BaseStore 类
- 代码位置:
src/stores/xxx/xxx.js
,如云主机对应的 store 在src/stores/nova/instance.js
- 只需要复写部分函数即可完成数据的请求操作
- 属性与函数分为以下四种,
- 通常需要复写的属性与函数,主要包含:
- 与生成 url 相关的属性与函数
- 按需复写的函数与属性,主要包含:
- 列表数据的再加工
- 详情数据的再加工
- 请求参数的处理
- url 的处理
- 无需复写的函数与属性,主要包含:
- 清空数据
- 封装数据时对项目信息的处理
- 基类中的基础函数,主要包含:
- 处理分页数据的
marker
- 处理分页数据的
- 更详细与全面的介绍见下
- 通常需要复写的属性与函数,主要包含:
- 前端分页
- 一次性从后端获取所有列表数据
- 前端基于获取到的数据总量、页面内配置的当前页数、每页数量来展示数据(
BaseList
组件处理)
- 后端分页
- 以当前页号、每页数量向后端请求数据
- 前端排序
- 使用前端分页时,按设定的排序信息对所有数据排序
- 使用后端分页时,按设定的排序信息对当前页内的数据排序
- 后端排序
- 以当前页号、每页数量、当前排序信息向后端请求数据
- 不存在前端分页+后端排序这种组合方式
-
module
:-
必须复写该函数
-
资源对应的模块
-
该函数用于生成请求的 url
-
以云主机
src/stores/nova/instance.js
为例get module() { return 'servers'; }
-
-
apiVersion
-
必须复写该函数
-
资源对应的 api 前缀
-
因所有的请求需要由服务端转发,所以,api 的前缀需要基于
profile
内的信息生成 -
以云主机
src/stores/nova/instance.js
为例get apiVersion() { return novaBase(); }
-
-
responseKey
-
listDidFetch
-
列表数据二次加工使用的函数
-
可请求其他 API 后,整合数据
-
可过滤数据
-
请求某个指定云硬盘的快照列表时,可以基于
filters
中的参数再次过滤数据-
以云硬盘快照
src/stores/cinder/snapshot.js
为例async listDidFetch(items, allProjects, filters) { if (items.length === 0) { return items; } const { id } = filters; const data = id ? items.filter((it) => it.volume_id === id) : items; return data; }
-
-
如果需要显示加密信息,需要发起额外请求后,整合数据
-
以云硬盘类型
src/stores/cinder/volume-type.js
为例async listDidFetch(items, allProjects, filters) { const { showEncryption } = filters; if (items.length === 0) { return items; } if (!showEncryption) { return items; } const promiseList = items.map((i) => request.get(`${this.getDetailUrl({ id: i.id })}/encryption`) ); const encryptionList = await Promise.all(promiseList); const result = items.map((i) => { const { id } = i; const encryption = encryptionList.find((e) => e.volume_type_id === id); return { ...i, encryption, }; }); return result; }
-
-
-
detailDidFetch
-
详情数据二次加工使用的函数
-
可请求其他 API 后,整合数据
-
以云硬盘快照
src/stores/cinder/snapshot.js
为例async detailDidFetch(item) { const { volume_id } = item; const volumeUrl = `${cinderBase()}/${ globals.user.project.id }/volumes/${volume_id}`; const { volume } = await request.get(volumeUrl); item.volume = volume; return item; }
-
-
listResponseKey
-
列表数据的返回 Key
-
默认是
${this.responseKey}s
-
以云硬盘快照
src/stores/cinder/snapshot.js
为例get responseKey() { return 'snapshot'; } get listResponseKey() { return 'volume_snapshots'; }
-
-
getListUrl
-
请求数据使用的 url
-
前端分页请求列表数据(即一次性获取所有数据)时,优先使用
this.getListDetailUrl()
-
后端分页请求列表数据时,按优先级
this.getListPageUrl()
>this.getListDetailUrl()
>this.getListUrl()
-
默认值为
getListUrl = () => `${this.apiVersion}/${this.module}`;
-
以 Heat 的堆栈的日志
src/stores/heat/event.js
为例getListUrl = ({ id, name }) => `${this.apiVersion}/${this.module}/${name}/${id}/events`;
-
-
getListDetailUrl
-
请求数据使用的 url
-
前端分页请求列表数据(即一次性获取所有数据)时,优先使用
this.getListDetailUrl()
-
后端分页请求列表数据时,按优先级
this.getListPageUrl()
>this.getListDetailUrl()
>this.getListUrl()
-
默认值为
getListDetailUrl = () => '';
-
以云硬盘
src/stores/cinder/volume.js
为例getListDetailUrl = () => `${skylineBase()}/extension/volumes`;
-
-
getListPageUrl
-
后端分页数据使用的 url
-
后端分页请求列表数据时,按优先级
this.getListPageUrl()
>this.getListDetailUrl()
>this.getListUrl()
-
默认值为
getListPageUrl = () => '';
-
以云硬盘
src/stores/cinder/volume.js
为例getListPageUrl = () => `${skylineBase()}/extension/volumes`;
-
-
getDetailUrl
-
详情数据对应的 url
-
使用 rest 风格的 API,所以,该 url 也是 put, delete, patch 对应的 url
-
默认值为
getDetailUrl = ({ id }) => `${this.getListUrl()}/${id}`;
-
以堆栈
src/stores/heat/stack.js
为例getDetailUrl = ({ id, name }) => `${this.getListUrl()}/${name}/${id}`;
-
-
needGetProject
-
对服务端返回的数据是否需要二次加工其中的项目信息
-
一般 Openstack API 返回的数据只有
project_id
信息,按页面展示的需求,在管理平台需要展示项目名称 -
默认值是
true
-
以元数据
src/stores/glance/metadata.js
为例get needGetProject() { return false; }
-
-
mapper
-
对服务端返回的列表、详情数据做二次加工
-
一般是为了更便捷的在资源列表、资源详情中展示数据使用
-
默认值为
get mapper() { return (data) => data; }
-
以云硬盘
src/stores/cinder/volume.js
为例get mapper() { return (volume) => ({ ...volume, disk_tag: isOsDisk(volume) ? 'os_disk' : 'data_disk', description: volume.description || (volume.origin_data || {}).description, }); }
-
-
mapperBeforeFetchProject
-
在处理项目信息前,对服务端返回的列表、详情数据做二次加工
-
一般是为了处理返回数据中的项目信息使用
-
默认值为
get mapperBeforeFetchProject() { return (data) => data; }
-
以镜像
src/stores/glance/image.js
为例get mapperBeforeFetchProject() { return (data, filters, isDetail) => { if (isDetail) { return { ...data, project_id: data.owner, }; } return { ...data, project_id: data.owner, project_name: data.owner_project_name || data.project_name, }; }; }
-
-
paramsFunc
-
前端分页请求(即
fetchList
)时,对请求参数的更新 -
默认是对从资源列表代码(
pages/xxxx/xxx/index.jsx
)使用fetchList
时,参数的过滤 -
默认值
get paramsFunc() { if (this.filterByApi) { return (params) => params; } return (params) => { const reservedKeys = [ 'all_data', 'all_projects', 'device_id', 'network_id', 'floating_network_id', 'start_at_gt', 'start_at_lt', 'binary', 'fixed_ip_address', 'device_owner', 'project_id', 'type', 'sort', 'security_group_id', 'id', 'security_group_id', 'owner_id', 'status', 'fingerprint', 'resource_types', 'floating_ip_address', 'uuid', 'loadbalancer_id', 'ikepolicy_id', 'ipsecpolicy_id', 'endpoint_id', 'peer_ep_group_id', 'local_ep_group_id', 'vpnservice_id', ]; const newParams = {}; Object.keys(params).forEach((key) => { if (reservedKeys.indexOf(key) >= 0) { newParams[key] = params[key]; } }); return newParams; }; }
-
以云硬盘
src/stores/cinder/volume.js
为例get paramsFunc() { return (params) => { const { serverId, ...rest } = params; return rest; }; }
-
-
paramsFuncPage
-
后端分页请求(即
fetchListByPage
)时,对请求参数的更新 -
默认是对从资源列表代码(
pages/xxxx/xxx/index.jsx
)使用fetchListByPage
时,参数的过滤 -
默认值
get paramsFuncPage() { return (params) => { const { current, ...rest } = params; return rest; }; }
-
以云硬盘类型
src/stores/cinder/volume-type.js
为例get paramsFuncPage() { return (params) => { const { current, showEncryption, ...rest } = params; return rest; }; }
-
-
fetchListByLimit
-
前端分页请求所有数据时,是否要基于
limit
发起多个请求,最终实现所有数据的获取 -
Openstack API 默认返回的是 1000 个数据,对于某些资源数据很多的情况,需要使用该配置以便获取到所有数据
-
默认值是
false
-
以镜像
src/stores/glance/image.js
为例get fetchListByLimit() { return true; }
-
-
markerKey
-
后端分页请求数据时,marker 的来源
-
因为对 Openstack 的请求是由后端转发的,所以并没有直接使用列表数据返回的 Openstack 拼接好的下一页数据应该使用的 Url,而是根据返回的数据,解析出
marker
-
默认值是
id
-
通常不需要复写
-
以密钥
src/stores/nova/keypair.js
为例get markerKey() { return 'keypair.name'; }
-
-
requestListByMarker
-
后端分页时,使用
marker
请求分页下的数据 -
通常不需要复写
-
默认值是
async requestListByMarker(url, params, limit, marker) { const newParams = { ...params, limit, }; if (marker) { newParams.marker = marker; } return request.get(url, newParams); }
-
以云主机组
src/stores/nova/server-group.js
为例async requestListByMarker(url, params, limit, marker) { const newParams = { ...params, limit, }; if (marker) { newParams.offset = marker; } return request.get(url, newParams); }
-
-
requestListAllByLimit
- 当
this.fetchListByLimit=true
时,前端分页使用该方法获取所有数据 - 通常不需要复写
- 当
-
updateUrl
- 更新列表数据请求的 url
- 不常用
-
updateParamsSortPage
-
使用后端排序时,对排序参数的处理
-
使用后端排序时,会在资源列表代码
pages/xxx/XXX/index.jsx
中自动生成相应的请求参数,store 对这些参数往往需要再次整理,否则会不符合 API 的参数要求 -
以云硬盘
src/stores/cinder/volume.js
为例updateParamsSortPage = (params, sortKey, sortOrder) => { if (sortKey && sortOrder) { params.sort_keys = sortKey; params.sort_dirs = sortOrder === 'descend' ? 'desc' : 'asc'; } };
-
-
listFilterByProject
-
列表数据是否需要基于项目信息过滤
-
admin
权限下的部分 Openstack 资源(如neutron
),会默认返回所有项目的数据,所以在控制台展示资源时,会根据该配置过滤数据 -
默认值是
false
-
以 VPN
src/stores/neutron/vpn-service.js
为例get listFilterByProject() { return true; }
-
-
fetchList
pages
下的列表页通常使用this.store.fetchList
来获取前端分页数据- 不建议复写该函数,如果需要再加工数据,建议使用
listDidFetch
- 该函数会更新
this.list
属性中的相关数据,pages
下的资源列表组件也是基于this.list
进行数据展示
-
fetchListByPage
pages
下的列表页通常使用this.store.fetchList
来获取后端分页数据- 不建议复写该函数,如果需要再加工数据,建议使用
listDidFetch
- 该函数会更新
this.list
属性中的相关数据,pages
下的资源列表组件也是基于this.list
进行数据展示
-
getCountForPage
- 获取列表数据的总量
- 通常在后端分页时可复写
-
getDetailParams
-
更新详情数据请求时的参数
-
默认值为
getDetailParams = () => undefined;
-
-
fetchDetail
pages
下的详情页通常使用this.store.fetchDetail
来获取详情数据- 通常不需要复写
- 数据再加工通常是重写
mapper
或detailDidFetch
-
create
- 创建资源
- 使用
POST
api - 通常不需要复写
- 使用
this.submitting
保证在发送请求时页面处于loading
状态
-
edit
- 更新资源
- 使用
PUT
api - 通常不需要复写
- 使用
this.submitting
保证在发送请求时页面处于loading
状态
-
patch
- 更新资源
- 使用
PATCH
api - 通常不需要复写
- 使用
this.submitting
保证在发送请求时页面处于loading
状态
-
delete
- 删除资源
- 使用
DELETE
api - 通常不需要复写
- 使用
this.submitting
保证在发送请求时页面处于loading
状态
submitting
- 用于数据创建、数据更新时
- 依据请求的响应变更
this.isSubmitting
,对应的 Form,列表页等会展示 Loading 状态
currentProject
- 当前用户登录的项目 ID
itemInCurrentProject
- 数据是否属于当前用户登录的项目
listDidFetchProject
- 对列表数据添加项目信息
requestListAll
- 前端分页获取所有数据
requestListByPage
- 后端分页所有当前页的数据
pureFetchList
- 列表数据的请求函数
- 返回原始数据,不会对 API 的返回数据做加工
parseMarker
- 使用后端分页时,从返回数据中解析出
marker
,用于请求上一页、下一页数据时使用
- 使用后端分页时,从返回数据中解析出
updateMarker
- 更新
list
的markers
list.markers
是个数组,每个元素对应于下标+1
页的marker
- 更新
getMarker
- 获取指定页对应的
marker
- 获取指定页对应的
getListDataFromResult
- 从 API 的返回值中取出列表数据
- 利用
this.listResponseKey
获取
setSelectRowKeys
- 对
pages
下的资源列表组件列表中数据项的选中记录
- 对
clearData
- 清空
list
数据
- 清空
- 建议查看代码理解,
src/stores/base.js