使用Vue Antd开发门户

最近工作需要,把我当做专业前端使用了,让我开发配合后端开发一个门户项目,其实之前做过很多管理类的系统和平台,有基于JQuery和纯原生JS开发的,也有基于Vue开发是,但是还没有用过Ant Design of Vue,在开始开发之前,我先和需求人员通过清楚项目的背景和项目需要,然后与公司专业前端沟通了一下他们使用的技术栈,最后确定了用ANTD PRO VUE,所以就有了这篇文章。

开始 ANTD PRO VUE

我们首先来看看ANTD PRO VUE现成的模版效果,

我们大概可以看到ANTD PRO VUE为我们提供较全的后端管理组件示例和自定义的一些组件,另外大家也可以自行访问https://preview.pro.loacg.com查看

安装 ANTD PRO VUE

首先需要安装Node,然后就是copy项目,如果安装了git工具的话,可以使用git clone --depth=1 https://github.com/sendya/ant-design-pro-vue.git your-project,如果暂时没有安装也没关系,直接到github进行下载,这里我是选择的下载的方式,然后进入到对应的目录执行npm install或者cnpm install进行安装。安装成功后执行npm run serve命令运行该项目,会出现以下文字提示:

1
2
3
4
5
> vue-antd-pro@2.1.0 serve F:\WorkAbout\product\ant-design-pro-vue-master
> vue-cli-service serve

VUE_APP_PREVIEW true
INFO Starting development server...

启动完成后会有这样的信息提示:

1
2
3
4
5
6
DONE  Compiled successfully in 56924ms                                                                      下午1:34:03


App running at:
- Local: http://localhost:8000/
- Network: http://172.20.156.196:8000/

这时候,我们就可以访问本地的ANTD PRO VUE了。接下来,我们的任务是要做个这样的页面
,这样一来,我们先分析一下页面的结构,我们可以把Header和左边的菜单作为模版共用,空间为内容页面填充。

新增页面

我这里新建了一个名为AdminLayout.vue的模版页面。这里的布局主要用到了a-layout组件

1
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
<template>

<a-layout>
<a-layout-header style="background:linear-gradient(307deg,rgba(145,89,255,1) 0%,rgba(54,146,255,1) 100%);">
<a-row style="margin:0px -46px ;padding:0px;">
<a-col :span="8"> <div class="logo">
<span><img :src="IndexLogo"></span><span class="split"></span><span class="title">快速智能B报</span>
</div></a-col>
<a-col :span="8"> </a-col>
<a-col :span="8" style="text-align:right;">

<user-settings></user-settings>
</a-col>
</a-row>
</a-layout-header>
<a-layout-content style="padding: 0 20px">
<a-layout style="padding: 24px 0;">
<a-layout-sider style="background:transparent;">
<a-layout-sider>
<a-card hoverable>
<div id="user-info">
<a-avatar
:size="64"
slot="avatar"
src="/avatar2.png"
/>
<div class="name">Amy3053
</div>
<div class="address">
广东 深圳
</div>
</div>
<template class="ant-card-actions" slot="actions">
<a-button type="primary" icon="plus" @click="goToCreateReport">创建报告</a-button>
</template>

</a-card>
</a-layout-sider>
<a-layout-sider width="200" theme="light" style=";margin-top:20px; height:440px;;text-align:center;font-size:14px;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;">

<a-menu
mode="inline"
:defaultSelectedKeys="['admin/index']"
:defaultOpenKeys="['sub1']"
style="height: 100% "
>
<a-menu-item key="admin/index">
<router-link to="/admin/index">
个人中心
</router-link>

</a-menu-item>
<a-menu-item key="admin/template">
<router-link to="/admin/template">
模版管理
</router-link>
</a-menu-item>
<a-menu-item key="admin/label">
<router-link to="/admin/label">
标签管理
</router-link>
</a-menu-item>
<a-menu-item key="admin/report">
<router-link to="/admin/report">
报告管理
</router-link>
</a-menu-item>
</a-menu>

</a-layout-sider>
</a-layout-sider>
<a-layout-content :style="{ padding: '0 24px', minHeight: '280px' }">
<transition name="page-transition">
<route-view />
</transition>
</a-layout-content>
</a-layout>
</a-layout-content>
<a-layout-footer style="text-align: center">

</a-layout-footer>
</a-layout>
</template>

<script>
import { triggerWindowResizeEvent } from '@/utils/util'
import { mapState, mapActions } from 'vuex'
import { mixin, mixinDevice } from '@/utils/mixin'
import config from '@/config/defaultSettings'

import RouteView from './RouteView'
import SideMenu from '@/components/Menu/SideMenu'
import CommonHeader from '@/components/GlobalHeader/CommonHeader'
import GlobalFooter from '@/components/GlobalFooter'
import SettingDrawer from '@/components/SettingDrawer'
import IndexLogo from '@/assets/chinamobile.png'
import UserSettings from '@/components/tools/UserSettings'

export default {
name: 'BasicLayout',
mixins: [mixin, mixinDevice],
components: {
RouteView,
SideMenu,
CommonHeader,
GlobalFooter,
SettingDrawer,
UserSettings
},
data () {
return {
production: config.production,
collapsed: false,
menus: [],
IndexLogo: IndexLogo
}
},
computed: {
...mapState({
// 动态主路由
mainMenu: state => state.permission.addRouters
}),
contentPaddingLeft () {
if (!this.fixSidebar || this.isMobile()) {
return '0'
}
if (this.sidebarOpened) {
return '256px'
}
return '80px'
}
},
watch: {
sidebarOpened (val) {
this.collapsed = !val
}
},
created () {
this.menus = this.mainMenu.find(item => item.path === '/').children
this.collapsed = !this.sidebarOpened
},
mounted () {
const userAgent = navigator.userAgent
if (userAgent.indexOf('Edge') > -1) {
this.$nextTick(() => {
this.collapsed = !this.collapsed
setTimeout(() => {
this.collapsed = !this.collapsed
}, 16)
})
}
},
methods: {
...mapActions(['setSidebar']),
toggle () {
this.collapsed = !this.collapsed
this.setSidebar(!this.collapsed)
triggerWindowResizeEvent()
},
paddingCalc () {
let left = ''
if (this.sidebarOpened) {
left = this.isDesktop() ? '256px' : '80px'
} else {
left = (this.isMobile() && '0') || (this.fixSidebar && '80px') || '0'
}
return left
},
menuSelect () {},
drawerClose () {
this.collapsed = false
},
goToCreateReport () {
this.$router.push('/template/select')
}
}
}
</script>

<style lang="less">
/*
* The following styles are auto-applied to elements with
* transition="page-transition" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the page transition by editing
* these styles.
*/

.page-transition-enter {
opacity: 0;
}

.page-transition-leave-active {
opacity: 0;
}

.page-transition-enter .page-transition-container,
.page-transition-leave-active .page-transition-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
#components-layout-demo-fixed-sider .logo {
height: 32px;
background: rgba(255, 255, 255, 0.2);
margin: 16px;
}
#user-info{
text-align: center;
}
#user-info .name{
margin: 10px 0px;
height:24px;
font-size:18px;
font-family:PingFangSC-Medium,PingFang SC;
font-weight:500;
color:rgba(0,0,0,0.85);
line-height:24px;text-align: center;
}
#user-info .address{

height:24px;
font-size:12px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(153,153,153,1);
line-height:24px;text-align: center;
}
.login{
.title{
width:114px;
height:24px;
font-size:20px;
font-family:PingFangSC-Semibold,PingFang SC;
font-weight:600;
color:rgba(255,255,255,1);
line-height:24px;
}
}
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected
{
font-size:14px;
font-family:PingFangSC-Medium,PingFang SC;
font-weight:500;
color:rgba(24,144,255,1) !important;
}
</style>

页面里面的无用代码还没来得及删除,先也不管了。这样一来模版就有了。接下来我在views文件夹下面新建了一个admin的文件夹,再新建一个Index.vue文件,这个页面就根据自己的业务来进行布局处理

1
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
<template>
<div>
<a-row :gutter="24">
<a-col :xl="16" :lg="24" :md="24" :sm="24" :xs="24">
<a-card
class="project-list report-left"
:loading="loading"
style="margin-bottom: 24px;"
:bordered="false"
title="报告情况"
:body-style="{ padding: 0 }">
<div class="none-report" style="display:none">
<div class="content">暂无数据,先去制作一个</div>
<div><a-button type="primary">选择模版制作</a-button></div>
</div>
<div class="has-report">
<a-row>
<a-col :span="7"><div class="content">我创建的报告</div></a-col>
<a-col :span="2"><span></span><a-icon type="right" style="float:left; line-height:90px;" /><span class="split-line"></span></a-col>
<a-col :span="5">
<div class="report-num first-div">30</div>
<div class="desc">已定制的报告总数</div>
</a-col>
<a-col :span="5">
<div class="report-num first-div">6</div>
<div class="desc">已下载</div>
</a-col>
<a-col :span="5">
<div class="report-num first-div">20</div>
<div class="desc">已完成</div>
</a-col>
</a-row>
</div>
</a-card></a-col>
<a-col
style="padding: 0 12px"
:xl="8"
:lg="24"
:md="24"
:sm="24"
:xs="24">
<a-card title="待审核报告" style="margin-bottom: 24px" class="right-report" :bordered="false" :body-style="{padding: 0}">
<div style="text-align: center;align-items: center; width:100%; ">
<a-row>
<a-col :span="12">
<div class="report-num first-div">6</div>
<div class="desc">待审核报告</div>
</a-col>
<a-col :span="12">
<div class="create-report first-div"><a-button type="primary">创建报告</a-button></div>
<div class="desc">明细 ></div>
</a-col>

</a-row>
</div>
</a-card></a-col>
</a-row>
<a-card
style="margin-top: 24px"
:bordered="false"
title="进行中的项目"
:body-style="{ padding: 1 }"
>
<a-table
:columns="operationColumns"
:dataSource="operation1"
:pagination="false"
>
<template
slot="status"
slot-scope="status">
<a-progress :percent="status" style="width: 180px" />
<span v-if="status==100" class="status-complete">100%&nbsp;&nbsp;完成</span>
<span v-if="status==0" class="status-audit">&nbsp;&nbsp;待审核</span>
</template>
<span slot="action" slot-scope="text, record">
<template>
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical" />
</template>
<template>
<a @click="handleEdit(record)">删除</a>
<a-divider type="vertical" />
</template>
</span>
</a-table>

</a-card>

</div>
</template>

<script>
import { timeFix } from '@/utils/util'
import { mapState } from 'vuex'

import { PageView } from '@/layouts'
import HeadInfo from '@/components/tools/HeadInfo'
import { Radar, STable } from '@/components'

import { getRoleList, getServiceList } from '@/api/manage'

const DataSet = require('@antv/data-set')

export default {
name: 'Workplace',
components: {
PageView,
HeadInfo,
Radar,
STable
},
data () {
return {
timeFix: timeFix(),
avatar: '',
user: {},
operationColumns: [
{
title: '报告名称',
dataIndex: 'type',
key: 'type'
},
{
title: '提交报告时间',
dataIndex: 'updatedAt',
key: 'updatedAt'
},
{
title: '报告进度',
dataIndex: 'status',
key: 'status',
scopedSlots: { customRender: 'status' }
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
scopedSlots: { customRender: 'action' }
}
],
operation1: [
{
key: 'op1',
type: '面向人口调查的政府行业模版',
name: '曲丽丽',
status: 100,
updatedAt: '2017-10-03 19:23:12'
},
{
key: 'op2',
type: '面向人口调查的政府行业模版',
name: '付小小',
status: 0,
updatedAt: '2017-10-03 19:23:12'
},
{
key: 'op3',
type: '面向人口调查的政府行业模版',
name: '周毛毛',
status: 0,
updatedAt: '2017-10-03 19:23:12'
},
{
key: 'op4',
type: '面向人口调查的政府行业模版',
name: '林东东',
status: 80,
updatedAt: '2017-10-03 19:23:12'
},
{
key: 'op5',
type: '面向人口调查的政府行业模版',
name: '汗牙牙',
status: 80,
updatedAt: '2017-10-03 19:23:12'
}
],

loadData: parameter => {
console.log('loadData.parameter', parameter)
return getServiceList(Object.assign(parameter, this.queryParam))
.then(res => {
return res.result
})
},
options: {
alert: { show: true, clear: () => { this.selectedRowKeys = [] } },
rowSelection: {
selectedRowKeys: this.selectedRowKeys,
onChange: this.onSelectChange
}
},
optionAlertShow: false,
projects: [],
loading: true,
radarLoading: true,
activities: [],
teams: [],
radarData: []
}
},
computed: {
...mapState({
nickname: (state) => state.user.nickname,
welcome: (state) => state.user.welcome
}),
userInfo () {
return this.$store.getters.userInfo
}
},
created () {
this.user = this.userInfo
this.avatar = this.userInfo.avatar

getRoleList().then(res => {
// console.log('workplace -> call getRoleList()', res)
})

getServiceList().then(res => {
// console.log('workplace -> call getServiceList()', res)
})
},
mounted () {

},
methods: {

}
}
</script>

<style lang="less" scoped>
.project-list {

.card-title {
font-size: 0;

a {
color: rgba(0, 0, 0, 0.85);
margin-left: 12px;
line-height: 24px;
height: 24px;
display: inline-block;
vertical-align: top;
font-size: 14px;

&:hover {
color: #1890ff;
}
}
}
.card-description {
color: rgba(0, 0, 0, 0.45);
height: 44px;
line-height: 22px;
overflow: hidden;
}
.project-item {
display: flex;
margin-top: 8px;
overflow: hidden;
font-size: 12px;
height: 20px;
line-height: 20px;
a {
color: rgba(0, 0, 0, 0.45);
display: inline-block;
flex: 1 1 0;

&:hover {
color: #1890ff;
}
}
.datetime {
color: rgba(0, 0, 0, 0.25);
flex: 0 0 auto;
float: right;
}
}
.ant-card-meta-description {
color: rgba(0, 0, 0, 0.45);
height: 44px;
line-height: 22px;
overflow: hidden;
}
}

.item-group {
padding: 20px 0 8px 24px;
font-size: 0;
a {
color: rgba(0, 0, 0, 0.65);
display: inline-block;
font-size: 14px;
margin-bottom: 13px;
width: 25%;
}
}

.members {
a {
display: block;
margin: 12px 0;
line-height: 24px;
height: 24px;
.member {
font-size: 14px;
color: rgba(0, 0, 0, .65);
line-height: 24px;
max-width: 100px;
vertical-align: top;
margin-left: 12px;
transition: all 0.3s;
display: inline-block;
}
&:hover {
span {
color: #1890ff;
}
}
}
}

.mobile {

.project-list {

.project-card-grid {
width: 100%;
}
}

.more-info {
border: 0;
padding-top: 16px;
margin: 16px 0 16px;
}

.headerContent .title .welcome-text {
display: none;
}
}

.right-report{
height:181px;
background:rgba(255,255,255,1);
border-radius:3px;
.desc{

margin-top: 5px;
height:25px;
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(136,136,136,1);
line-height:25px;
}
.report-num{

height:59px;
font-size:42px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(58,58,58,1);
line-height:59px;
}
.create-report{
height:59px;
line-height:59px;
}
.first-div{
margin-top: 15px;
}
.second-div{
margin-top: 20px;
}
}

.report-left{
height:181px;background:rgba(255,255,255,1);border-radius:3px;
.none-report{
width:100%;
text-align:center;
.content{
height:22px;
font-size:16px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(153,153,153,1);
line-height:22px;
}

div{
text-align:center;
margin-top: 15px;
}
}
.has-report{
margin-top: 20px;
flex-direction: column;
align-items: center;
div{
text-align:center;
}

.report-num{

height:59px;
font-size:42px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(58,58,58,1);
line-height:59px;
}
.content{
height:25px;
font-size:16px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(51,51,51,1);
line-height:90px;
}
.split-line{
display:block;
width:1px;
height:90px;
background:rgba(228,231,237,1);
float: right;
}
}

}

.status-complete{
font-size:12px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:#32BA39;
}
.status-audit{
font-size:12px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:#ED2626;
}
</style>

如果需要用到分页组件的话,还需要引入Pagination组件

1
2
import { Pagination } from 'ant-design-vue'
Vue.use(Pagination)

配置路由

我们需要访问刚才开发好的页面,需要在config\router.config.js配置好新页面的路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
path: '/admin',
name: 'admin',
component: AdminLayout,
meta: { title: '个人中心' },
redirect: '/admin/index',
children: [
// dashboard
{
path: '/admin',
name: 'admin',
redirect: '/admin/index',
component: RouteView,
meta: { title: '个人中心', keepAlive: true, icon: bxAnaalyse, permission: [ 'dashboard' ] },
children: [

{
path: '/admin/index',
name: 'Index',
component: () => import('@/views/admin/Index'),
meta: { title: '个人中心', keepAlive: true, permission: [ 'dashboard' ] }
},
]
}]
}

这时候就可以执行npm run serve来看看效果

这篇文章没有实际性的意义,只是我自己把这个过程给记录下来,对你们无益。需要了解更多信息,大家都去官网学习吧
https://pro.loacg.com/docs/getting-started
https://vue.ant.design

作者

eyiadmin

发布于

2020-02-12

更新于

2024-05-31

许可协议

评论