快速上手
# 快速上手
本节将介绍如何快速搭建一个应用环境
# 1.准备工作
Tips
以下步骤将假设你知道Node.js (opens new window)、npm
并在你的机器上正确安装了它们。如不知道请点击安装并配置正确的环境变量 (opens new window)
# 2.下载代码
Hai Design代码存放gitlab (opens new window)上,请确保你有权限 clone
代码。
git clone https://gitlab.haierbiomedical.com/ran.li/biopl:::infoatform-pro.git
你将得到如下目录结构
───Jenkinsfile
├───babel.config.js
├───bin
├──────bin/build.bat
├──────bin/package.bat
├──────bin/run-web.bat
├───build
├──────build/index.js
├───fileTree.txt
├───getFileTree.js
├───package.json
├───public
├──────public/assets
├──────public/bootstrapmb.com.js
├──────public/dashboard.html
├──────public/favicon.ico
├──────public/html
├──────public/index.html
├──────public/libs
├──────public/robots.txt
├───src
├──────src/App.vue
├──────src/api
├──────src/assets
├──────src/components
├──────src/directive
├──────src/icons
├──────src/layout
├──────src/main.js
├──────src/permission.js
├──────src/plugins
├──────src/router
├──────src/settings.js
├──────src/store
├──────src/styles
├──────src/tongji.js
├──────src/utils
├──────src/views
├───vue.config.js
└───yarn.lock
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 3.安装依赖
# 3.1.安装nrm源管理器
npm i nrm -g
# 3.2.添加私库源地址
nrm add haiDesign http://115.28.130.139:8081/repository/npm-public/
# 3.3.切换至haiDesign
nrm use haiDesign
# 3.4.安装(hai-design-magic)
npm install
# 4.启动
npm run dev
更多启动命令请参考package.json
"scripts": {
"local": "vue-cli-service serve --mode local",
"dev": "vue-cli-service serve --mode dev",
"build:prod": "vue-cli-service build --mode prod",
"build:stage": "vue-cli-service build --mode stage",
"build:dev": "vue-cli-service build --mode dev",
"build:demo1024": "vue-cli-service build --mode demo1024",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src"
},
2
3
4
5
6
7
8
9
10
# 5.开发一个页面
Tips
开始之前,你可能需要知道一些关于Vue (opens new window),ElementUI (opens new window),VxeTable (opens new window),ES6 (opens new window)等知识。
# 5.1.Hello World
本例子实现在页面中显示一段歌词
- 在
bloplatform-rop-web/src/views/
目录下创建一个新的目录,命名为study
, - 在
study
目录下创建一个新文件,命名为index.vue
- 开始编写你的页面
<template>
<div class="app-container">
<h1>Through the Valley</h1>
<h5>Shawn James</h5>
<p>I walk through the valley</p>
<p>of the shadow of death</p>
<p>And I fear no evil</p>
<p>Because I am blind to it all</p>
<p>And my mind,</p>
<p>my gun, they comfort me</p>
<p>Because I know I will kill my enemies</p>
<p>when they come</p>
<p>Surely goodness and mercy will</p>
<p>follow me all the days of my life</p>
<p>And I will dwell</p>
<p>on this earth forever more</p>
<p>Said I walk beside of still water and they</p>
<p>restore of my soul</p>
<p>But I can't walk on the path of the right</p>
<p>Because I am wrong</p>
<p>no,I can't walk</p>
<p>on the path of the right</p>
<p>Because I'm wrong</p>
</div>
</template>
<script>
</script>
<style lang="scss" scoped>
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
4.打开页面 -> 系统管理 -> 菜单管理,新建->主目录
然后在该目录下新建菜单,组件路径是该文件所在的文件路径,如果该菜单有权限需填入权限标识
5.打开页面 -> 角色管理 -> 更堵->权限,将你的菜单勾选上(配置权限)
6.刷新页面或重新登录,点击你配置出来的菜单,你将看到你编写的页面
# 6.开发一个功能模块
本章节复刻【数据字典】表格页面,演示如何基于Hai Design开发一个功能模块。详细请查看系统管理->字典管理 具体代码地址 src/views/system/dict/index.vue
Tips
开始之前,你可能需要知道一些关于Vue (opens new window),ElementUI (opens new window),VxeTable (opens new window),ES6 (opens new window)等知识。
- 基础表格
- 功能模块
- 复杂表格
- 树形表格
- 可编辑表格
- 高级表格
- 虚拟滚动
- 渲染器->可编辑渲染,单元格渲染,内容渲染,工具栏渲染,筛选渲染,表单渲染
- 指令API
同时你需要熟练使用(后端进阶也可以学习此知识)
- 指令
- 插槽
- JSX
- render函数
Note
因为官方文档不是特别健全,所以在学习过程中好多概念会让你很困惑,但是等你熟悉后会给你的开发效率,应用的扩展性带来极大的提升
如果你是 后端开发
或者想快速体验,Hai Design
封装好并且可以近乎0配置升级迭代
应用全局配置如下,具体可参考官方文档
/*
* @Author: 王祥(工号22020620)
* @Date: 2022-01-20 16:53:44
* @LastEditors: 王祥(工号22020620)
* @LastEditTime: 2022-05-06 16:50:18
* @Description: 海尔生物医疗-软件平台-研发部
*/
import Cookies from 'js-cookie'
import { options } from 'runjs'
// 设置全局参数
export function setupVxe(VXETable, size) {
VXETable.setup({
size: size ? size : Cookies.get('size') || 'medium', // 全局尺寸
zIndex: 999, // 全局 zIndex 起始值,如果项目的的 z-index 样式值过大时就需要跟随设置更大,避免被遮挡
version: 2.0, // 版本号,对于某些带数据缓存的功能有用到,上升版本号可以用于重置数据
table: {
headerAlign: 'left',
align: 'left',
showHeader: true,
keepSource: false,
delayHover: 250,
showOverflow: true,
showHeaderOverflow: null,
showFooterOverflow: null,
size: null,
minWidth: 200,
// autoResize: true,
stripe: false,
border: "inner",
round: false,
emptyText: '暂无数据',
rowId: '_X_ID', // 行数据的唯一主键字段名
rowConfig: {
isHover: true,
},
columnConfig: {
resizable: true,
// width: 100,
// minWidth: 80
},
customConfig: {
storage: true,
},
radioConfig: {
trigger: 'default'
},
checkboxConfig: {
strict: false,
highlight: false,
range: false,
trigger: 'default'
},
sortConfig: {
remote: true,
trigger: 'cell',
orders: ['asc', 'desc', null],
sortMethod: null
},
filterConfig: {
remote: true,
filterMethod: null
},
expandConfig: {
trigger: 'default',
showIcon: true
},
treeConfig: {
rowField: 'id',
parentField: 'parentId',
children: 'children',
hasChild: 'hasChild',
mapChildren: '_X_CHILD',
indent: 20,
showIcon: true
},
tooltipConfig: {
theme: 'dark',
enterable: true,
},
menuConfig: {
visibleMethod() { }
},
editConfig: {
mode: 'cell',
showAsterisk: true
},
importConfig: {
modes: ['insert', 'covering']
},
exportConfig: {
},
scrollX: {
gt: 60
},
scrollY: {
gt: 100
},
// keyboardConfig: {
// isArrow: true
// },
// rowConfig: {
// isCurrent: true
// },
},
grid: {
headerAlign: 'left',
align: 'left',
size: null,
zoomConfig: {
escRestore: true
},
toolbarConfig: {
zoom: true,
custom: true,
// export: true,
slots: {
buttons: "toolbar_buttons",
},
},
},
// 全局分页配置
pager: {
size: null,
perfect: false,
autoHidden: false,
background: true,
border: false,
pageSize: 10,
pageSizes: [10, 20, 50, 100, 500, 1000],
layouts: [
"PrevJump",
"PrevPage",
"Number",
"NextPage",
"NextJump",
"Sizes",
"FullJump",
"Total",
],
},
form: {
preventSubmit: false,
validConfig: {
autoPos: true
},
size: null,
colon: false,
titleAsterisk: true
},
input: {
size: null,
transfer: false,
parseFormat: 'yyyy-MM-dd HH:mm:ss.SSS',
labelFormat: '',
valueFormat: '',
startDay: 1,
digits: 2,
controls: true
},
textarea: {
size: null,
autosize: {
minRows: 1,
maxRows: 10
}
},
select: {
size: null,
transfer: false,
multiCharOverflow: 8
},
toolbar: {
size: null,
import: {
mode: 'covering'
},
export: {
types: ['csv', 'html', 'xml', 'txt']
},
custom: {
isFooter: true
},
buttons: [],
tools: []
},
button: {
size: null,
transfer: false
},
radio: {
size: null
},
checkbox: {
size: null
},
switch: {
size: null
},
modal: {
// size: null,
marginSize: -500,
},
list: {
scrollY: {
gt: 100
}
}
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# 7.开发搜索表单
强烈建议保留此代码结构,因为基础样式,以及表格的动态表格都是依赖
app-container
计算的
添加搜索组件
<template>
<div class="app-container">
</div>
</template>
2
3
4
<template>
<div class="app-container">
<vxe-form
class="mb-10"
title-width="90"
:data="queryParams"
:items="formItems"
@submit="handleQuery"
@reset="resetQuery"
>
<!-- 插槽功能演示-->
<!-- <template #channelId="{ data }">
<el-select
v-model="data.channelId"
placeholder="请选择短信渠道"
clearable
>
<el-option
v-for="channel in channels"
:key="channel.value"
:value="channel.value"
:label="channel.label"
/>
</el-select>
</template> -->
</vxe-form>
</div>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
更多vxe-form
(opens new window)详细参数请自行查看文档prop
queryParams
既提交的查询参数,注意这里不需要额外加分页参数,因为已经全局配置,默认10条/页,如需更改,请修改全局配置或者在具体应用中覆盖
queryParams: {
name: null,
type: null,
status: null,
dateRangeCreateTime: null,
},
2
3
4
5
6
formItems
配置如下后续应用可在此基础结构修改
formItems: [
{
title: "左侧",
span: 18,
children: [
{
field: "name",
title: "字典名称",
className: gaidCol,
itemRender: {
name: "ElInput",
props: { clearable: true },
attrs: { placeholder: "请输入字典名称" },
},
},
// 如果不满足你还可以使用插槽功能,注意一旦使用了插槽,该项配置需要手动重置
{
// field: "channelId",
// title: "短信渠道",
// className: gaidCol,
// slots: { default: "channelId" },
// },
{
field: "type",
title: "字典类型",
className: gaidCol,
itemRender: {
name: "ElInput",
props: { clearable: true },
attrs: { placeholder: "请输入字典类型" },
},
},
{
field: "status",
title: "状态",
className: gaidCol,
itemRender: {
name: "ElSelect",
options: this.getDictDatas(this.DICT_TYPE.COMMON_STATUS),
props: { placeholder: "请选择岗位状态", clearable: true },
},
},
{
field: "dateRangeCreateTime",
title: "创建时间",
folding: true,
// titleWidth: 90,
className: "el-col-lg-16 el-col-md-12",
itemRender: {
name: "ElDatePicker",
props: {
clearable: true,
valueFormat: "yyyy-MM-dd",
type: "daterange",
startplaceholder: "开始日期",
endplaceholder: "结束日期",
},
attrs: { placeholder: "请输入创建时间" },
},
},
],
},
{
title: "右侧",
span: 6,
children: [
{
align: "right",
span: 24,
className: "searchButton",
collapseNode: true,
itemRender: {
name: "$buttons",
children: [
{
props: {
type: "submit",
content: "搜索",
status: "primary",
icon: "el-icon-search",
},
},
{
props: {
type: "reset",
icon: "el-icon-refresh",
content: "重置",
},
},
],
},
},
],
},
],
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 7.1.左侧搜索区域配置参数说明
span
响应式栅格,默认左右布局,左侧为搜索区域,右侧为操作区域默认 18
-6
分布一共 24
栅格
field
表单字段
title
表单标题
className
自定义子表单样式
folding
高级查询字段,true
时会被隐藏,只有点击展开才会显示
Note
vxt-table
没有提供响应式栅格,因此我们可以直接使用 ElementUI
的响应式栅格样式并结合 className
来实现 const gaidCol = "el-col-lg-8 el-col-md-12";
大屏一行显示24/8=3个,中屏一行显示24/12=2个,中屏以下会出现滚动条,具体排列请根据具体需求,标题,组件长度自行搭配实现
itemRender
具体渲染内容
name
组件名称对应 ElementUI
的 el-input
,支持 ElInput
, ElInputNumber
, ElAutocomplete
, ElSelect
, ElDatePicker
, ElSwitch
, ElRate
, ElSlider
, ElRadio
, ElCheckbox
, ElButton
, ElButtons
具体内容可参考配置文档 (opens new window) ElRadio
, ElCheckbox
用法与 ElSelect
相同
options:[{label:'1':value:1},{label:'2':value:2}]
optionProps:{ value: 'value', label: 'label' }配置label,value关联字段
2
事件用法,对应组件事件
{
field: "status",
title: "状态",
className: gaidCol,
itemRender: {
name: "ElSelect",
events: { change: (e) => { console.log(e) } }
},
},
2
3
4
5
6
7
8
9
插槽用法
<template #channelId="{ data }">
<el-select
v-model="data.channelId"
placeholder="请选择短信渠道"
clearable
>
<el-option
v-for="channel in channels"
:key="channel.value"
:value="channel.value"
:label="channel.label"
/>
</el-select>
</template>
{
field: "channelId",
title: "短信渠道",
className: gaidCol,
slots: { default: "channelId" },
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
因
ElementUI
毕竟第三方集成,在具体使用中如果有问题,可以使用vex-table
原生类型$input
,$textarea
,$select
,$button
,$buttons
,$radio
,$checkbox
,$switch
props
对应具体组件的prop属性 组件的属性
# 7.2.右侧按钮配置说明
collapseNode
开启展开隐藏与 folding
功能对应
# 7.3.事件
@submit="handleQuery"
/** 搜索按钮操作 */
handleQuery() {
this.xGrid.commitProxy("query");
},
2
3
4
@reset="resetQuery"
/** 重置按钮操作 */
resetQuery() {
this.xGrid.commitProxy("reload");
},
2
3
4
query
,reload
指令会自动的与表格关联并且自动查询表单,设置分页参数,重置表单以及重置分页参数,解放劳动力
# 8.开发表格
添加代码你将会得到如下功能页面,组件帮你自动实现了前端搜索,loading,分页,动态高度,全屏功能,列筛选等功能,回车搜索等这些近乎是0配置的
添加搜索组件
<vxe-grid ref="xGrid" v-bind="gridOptions" v-dynamicHeight :empty-render="{ name: 'emptyData' }">
<!-- 左侧工具栏操作按钮插槽 -->
<template #toolbar_buttons>
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:dict:create']"
>新增</el-button
>
<el-button
type="info"
icon="el-icon-download"
size="mini"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['system:dict:export']"
>导出</el-button
>
</template>
<!-- 操作列插槽 -->
<template #option_default="{ row }">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(row)"
v-hasPermi="['system:dict:update']"
>修改</el-button
>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(row)"
v-hasPermi="['system:dict:delete']"
>删除</el-button
>
</template>
</vxe-grid>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
更多 [vxe-grid](https://vxetable.cn/#/grid/api)
详细参数请自行查看文档 prop
gridOptions
配置如下具体使用请查看注释说明
gridOptions: {
// 列配置缓存等依赖调用
height: "300px",
// 功能按键配置,略过
keyboardConfig: {
isArrow: true,
},
// 本地缓存等其他应用需要设置,必填且唯一
id: "dict:index",
// 排序相关配置
sortConfig: {
trigger: "cell",
remote: true,
},
// 开启分页
pagerConfig: {
// 不允许删除,空配置会默认继承主配置默认主配置为10条/页,删掉会默认为不需要分页,query查询需要返回数组而不是对象
},
// 筛选相关配置
filterConfig: {
remote: false,
},
// 列配置保存本地
customConfig: {
storage: true,
},
// 右侧工具栏配置
toolbarConfig: {
tools: [
{
// 工具栏前端搜索配置
toolRender: {
name: "FontSearch",
// 需要搜索的字段对应columns中field并且相关类型设置为type: "html",
fields: ["id", "name"],
},
},
],
},
// 数据代理相关配置
proxyConfig: {
seq: false, // 启用动态序号代理,每一页的序号会根据当前页数变化
sort: false, // 启用排序代理,当点击排序时会自动触发 query 行为
filter: false, // 启用筛选代理,当点击筛选时会自动触发 query 行为
props: {
// 接口响应后赋值读取的字段,例如返回结果为:{list: [],total: 10}
result: "list", // 配置响应结果列表字段
total: "total", // 配置响应结果总页数字段
},
// 只接收Promise,具体实现自由发挥
ajax: {
// 当点击工具栏查询按钮或者手动提交指令 query或reload 时会被触发与this.xGrid.commitProxy("query")等关联
// 默认提供4种指令
/**
* reload刷新数据并清除所有状态;触发 ajax.query 方法
query刷新数据;会自动触发 ajax.query 方法
delete删除选中行;会自动触发 ajax.delete 方法 多选删除中会用到
save保存数据;会自动触发 ajax.save 方法,并且在 Promise 完成之后重新触发 ajax.query 方法
自定义单条删除指令singleDel 具体使用 this.$grid.commitProxy("singleDel", { row, api: deleteTenant }); row选中该行的数据,api删除接口
应用该指令会自动弹出询问提示,删除确认后自动查询并且提示删除成功
*/
query: ({ page, sorts, filters, form }) => {
// 处理查询参数
let params = {
...this.queryParams,
pageNo: page.currentPage,
pageSize: page.pageSize,
};
this.addBeginAndEndTime(
params,
"dateRangeCreateTime",
"createTime"
);
// // 执行查询
return listType(params).then((response) => {
return response.data;
});
},
},
},
columns: [
{
// 字段
field: "id",
// 如果需要在工具栏中被搜索到,需要设置html类型
type: "html",
title: "字典编号",
minWidth: 150,
},
{
field: "name",
type: "html",
title: "字典名称",
minWidth: 150,
},
{
field: "type",
type: "html",
title: "字典类型",
width: 150,
// 插槽功能,该处允许用jsx渲染任何内容
slots: {
// 使用 JSX 渲染
default: ({ row }) => {
return [
<router-link
to={"/dict/type/data/" + row.id}
class="link-type"
>
<span>{row.type}</span>
</router-link>,
];
},
},
},
{
field: "status",
title: "状态",
width: 150,
slots: {
// 使用 JSX 渲染
default: ({ row }) => {
return [
<dict-tag
type={this.DICT_TYPE.COMMON_STATUS}
value={row.status}
/>,
];
},
},
},
{
field: "remark",
title: "备注",
minWidth: 150,
},
{
field: "createTime",
title: "创建时间",
width: 180,
// 过滤器,很方便的转换原始数据并输出如时间12332232991=>2021-01-02
formatter: ({ cellValue }) => {
return this.parseTime(cellValue);
},
},
{
field: "操作",
title: "操作",
width: 150,
fixed: "right",
// 插槽功能,如果不习惯使用或者不会使用jsx可以在此开启插槽
/**
* <vxe-grid ref="xGrid" v-bind="gridOptions" v-dynamicHeight :empty-render="{ name: 'emptyData' }">
* <template #option_default="{ row }">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(row)"
v-hasPermi="['system:dict:update']"
>修改</el-button
>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(row)"
v-hasPermi="['system:dict:delete']"
>删除</el-button
>
</template>
</vxe-grid>
*/
slots: { default: "option_default" },
},
],
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# 9.完整功能
# 10.开发弹窗
Info
你只需要添加如下配置,即可得到一个集放大,拖动,记录拖动位置,双击放大等功能的弹窗并且可以跟任何组件集成.更多配置请参考vxe-model
(opens new window)