声明:文章为稀土技能社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!
哈喽咱们好!这篇文章来到了发布渠道全栈开发的前端部分,总算回到咱们最熟悉的前端了!本文将接着前面三篇文章,翻开介绍发布渠道的前端实战!依然是熟悉的手把手,看完不懂你直接打我!
系列文章:
- 总览前端自动化布置流程,如何完结前端发布渠道?文章链接
- 前端发布渠道
node server
实战!文章链接 - 前端发布渠道
jenkins
实战!如何完结前端自动化布置?文章链接 - 前端发布渠道全栈实战(前后端开发完整篇)!开发一个前端发布渠道
-
websocket
全栈实战,完结仅有构建实例 + 日志同步。文章链接
回忆前面三篇文章,笔者分别介绍了:前端项目的发布全貌、node server实战开发、触发 jenkins 完结自动化布置。本文是第四篇「前端发布渠道全栈实战——前端篇」的实战记载共享,首要经过共享 Vue
+ Element-plus
+ Koa
完结一个发布渠道的前端。下面是本文需求完结的中心点:
- 前端后端数据分页展现完结
- 全栈增删改数据完结
就怕只写前端的实战对咱们来太没意思了,看都看不下去!那笔者就趁机在 demo项目 中运用最近比较火的 tailwindcss
来玩玩,因为真实不想再给需求设置款式的 dom
起类名了(就凭这一点仍是很香的)!这儿是 vue3
项目装置 tailwindcss
的 文档,假如你也想玩玩赶紧在项目里面装一个,合作插件运用更爽!下面进入文章主题。let’s go!!!
快速看源码
- 前端项目源码
一、构建装备前端显示
回忆榜首篇文章,那时分现已新建好了一个前端项目了,咱们接着之前的开干。在正式进入实战开发之前,准备工作仍是不能少的,前端项目仍是要装一些包来协助咱们的,比方 axios
、 element-plus
、 vue-router
这些,都是咱们十分熟悉的依靠包了,直接装置即可。笔者现已自己完结装置,直接从代码实战开端讲起。
1. 分页展现前端模板
之前在讲 实战Koa 的时分,咱们现已能够经过 postman 恳求后端接口完结装备数据的创立、保存。现在,咱们完结一下在前端将数据展现出来。因为装备数据可能有很多条,所以笔者计划经过 table
+ 分页 的方式展现数据。
首要先搞个简略的静态界面:
<!-- 写 tailwindcss 后再也不用想类名了! -->
<el-card class="w-screen">
<template #header>
<span class="font-bold">项目装备</span>
</template>
<!-- 筛选框部分 -->
<el-form inline>
<el-form-item label="项目名称"></el-form-item>
</el-form>
<!-- 表格部分 -->
<el-table>
<el-table-column label="项目名称" prop="projectName" />
...
</el-table>
<!-- 翻页 -->
<el-pagination ... />
</el-card>
ToB 的同学在哪里,这玩意很熟悉有木有?现在静态的前端界面就出来了,接下来便是要经过 axios
去服务端恳求装备数据,完结前端界面动态接入数据啦~
2. 后端完结分页查询
回忆之前的文章,笔者在后端实战中完结了装备的 创立 、 更新 、 删去 的接口,可是并没有完结 分页查询 的接口,所以在完结前端开发之前,首要需求完结分页接口。所以,笔者在之前的 route
中新建一个路由:
首要咱们需求完结 getConfigList
的接口,中心代码如下:
export async function getConfigList (ctx, next) {
try {
// 获取分页参数(由前端带上来)
const { pageNo: page, pageSize, projectName } = ctx.request.query
// 调用 services 层的 findJobPage 完结分页数据查询
const pageData = await services.findJobPage(page, pageSize, { projectName })
// 查询成功的回来
ctx.state.apiResponse = {
code: RESPONSE_CODE.SUC,
data: pageData
}
} catch (e) {
ctx.state.apiResponse = {
code: RESPONSE_CODE.ERR,
msg: '装备分页查询失利'
}
}
next()
}
很简略是吧,都是之前咱们搞过的。接下来具体看看 services.findJobPage
的代码完结:
export async function findJobPage (page, pageSize, params) {
// 过滤掉前端传操控的查找条件
Object.keys(params).forEach(key => {
if (!params[key]) Reflect.deleteProperty(params, key)
})
/**
* find() 查询数据
* skip() 故名思义越过:指定越过的文档条数
* limit() 最大条数
**/
const DocumentUserList = await JobModel.find(params)
.skip((page - 1) * pageSize)
.limit(pageSize)
// toObject() 将查询出来的 Document 目标转换成 js 目标
return DocumentUserList.map(_ => _.toObject())
}
其中的数据库交互都是直接调用 mongoose 供给的 api
,在运用层面对笔者这种后端菜鸟来说仍是相对简略的。想要了解更多 api
的能够戳 mongoose文档,需求什么接口尽管往里面找,完结 CRUD
,甚至更复杂的事务都彻底不在话下啦。
好了,这儿咱们现已完结完装备的分页查询接口了,咱们再接再励地到前端页面的开发中!首要咱们需求在前端中建议恳求,来验证一下咱们完结的接口能不能运转!接着往下看
3. 前端接入分页接口
前后端正式联调之前,咱们需求先把前端项目的 proxy
设置一下,在 vite.config
中:
proxy: {
'/api': {
target: 'http://localhost:3200/', // 代理到后端地址
changeOrigin: true,
rewrite: path => {
return path.replace(/^/api/, '')
}
}
}
接下来咱们经过 axios 完结对后端接口的恳求,代码如下:
export async function getConfig (params) {
return axios.get('/job', { params })
}
紧接着,笔者在 onMounted
阶段进行数据恳求,履行恳求函数,结果如图所示。可知,咱们现已能够从方才完结的接口中获取到对应的数据了。接下来只需求把数据信息跟前端的 table
组件接上去就能够完结数据展现了!
当然,到这一步的时分,笔者才发现忘记对 axios 的回来做阻拦了,导致在事务层中获取数据的时分需求经过 data.data
才能获取到,看起来真实是有点不雅,所以笔者决定补回 axios 的回来阻拦!依据 axios 的阻拦写法完结阻拦,代码如下:
axios.interceptors.response.use(function (response) {
const data = response.data
if (data.code === 0) {
return data.data // 这样在事务层就不需求两层 data 获取数据了
}
data.message = data.message || data.msg
return Promise.reject(data)
})
回到获取接口数据的代码中,事务层的完结其实十分简略,笔者经过一个名为 tableData
的 ref
响应式数据获取数据,然后传入到 el-table
的 data
属性中。具体的就不翻开了,仍是比较简略的,笔者这儿就贴个伪代码和终究的实际图吧:
// 获取数据
tableData.value = await getConfig(searchParams)
<el-table :data="tableData">
...
</el-table>
从上图中能够看出,整个 table
的数据接入现已完结,看起来现已有点容貌了。可是,功用并没有彻底完结,回想一下方才咱们完结分页查询的接口中有没有遗漏了哪一个过程!没错,便是漏了完结 total
这个字段,咱们方才只是完结了分页数据的查询,可是并没有管 total
字段~接下来咱们继续完善咱们的分页接口。
其实 total
更简略!咱们把相同的分页查询条件经过 mongoose 的 count()
函数履行一下就完结了~便是这么简略,直接看代码吧:
export function countJob (params) {
// 处理为空的查询条件
Object.keys(params).forEach(key => {
if (!params[key]) Reflect.deleteProperty(params, key)
})
// 经过 count 得到 total
return JobModel.count(params)
}
既然现在需求把 total
字段回来前端,那咱们的回来数据的格局就不能简略的回来一个 分页list 数据,所以笔者这儿经过目标把它们包起来,把数据一同回来去前端~稍微改造一下回来的代码,具体回来如下:
ctx.state.apiResponse = {
code: RESPONSE_CODE.SUC,
data: {
list: pageData,
page,
pageSize,
total
}
}
现在,再在前端经过接口查询,看看回来的数据!如下图所示:
嗯,有内味了。平时跟后端联调是不是经常能看到这一串!现在咱们自己也完结了,哈哈哈,全栈还挺好玩~那现在前端接入数据这部分现已完结了,接下来咱们快速把 装备新建、装备修正、装备删去的也一同完结了!
二、全栈开发完结 CRUD
1. 新建装备
新建的接口在之前的 Koa 实战中现已完结了,所以这儿咱们只需求完结前端界面并联调好后端的接口就好了,十分 easy ~既然是需求新增,笔者这儿决定选用弹窗的交互方式去完结。当用户点击一个“新增装备”的按钮时,弹起弹窗,弹窗的具体内容便是一个表单。事不宜迟,直接上代码:
-
首要要添加一个新建的按钮:
<el-button type="" @click="">新增装备</el-button>
作用如图所示:
-
新建一个新增、修正的弹窗(修正时默认回填数据):
<el-dialog v-model="dialogVisible" :title="dialogTitle"> <el-form :model="formData"> <el-form-item label="项目名称" prop="projectName"> <el-input v-model="formData.projectName" placeholder="输入项目名称" /> </el-form-item> ...... </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="onSubmit">承认</el-button> </span> </template> </el-dialog>
弹窗作用如图所示:
-
完结新增装备信息函数
onSubmit
(用户点击弹窗的“承认”时触发):// 响应式数据 formData ,现已绑定在装备弹窗对应表单控件的 v-model 中 const formData = reactive({ projectName: '', gitUrl: '', gitBranch: '', buildCommand: '', uploadPath: '' }) const onSubmit = async () => { try { // 调用保存函数,传入参数 formData await postSave(formData) // 保存成功提示 ElMessage.success('装备保存成功') // 保存成功后更新当时页面数据 await initData() // 关闭装备弹窗 dialogVisible.value = false } catch (e) { ElMessage.error('装备保存失利') } }
以上便是整个新增装备的前端代码完结了,接下来咱们就一同来看看作用。笔者点击 新建装备 按钮,并在弹窗中输入如下装备信息:
紧接着笔者翻开 操控台 ,点击承认按钮后查看 netWork 信息如下:
如图能够看到,这儿成功调用了 save
接口完结了数据的保存。并且在前端页面中,也现已呈现了咱们新增的内容。新增装备功用大功告成!咱们趁热打铁,接着完结修正功用!
2. 修正装备
完结修正装备的功用,咱们需求让后端知道咱们要修正的是哪一条数据,所以咱们最好是经过 id
(仅有) 去恳求后端,然后再带上咱们修正后的数据。所以按照这样的需求场景,最普遍的做法便是在表格中新增一列操作列,并把当时的修正的数据信息传入处理修正的函数中。接下来咱们经过代码把功用完结一下!
首要咱们在 el-table
中添加一列操作列,模板代码如下:
<el-table-column label="操作">
<template #default="scope">
<!-- 传入 scopr.row -->
<el-button type="primary" link @click="onEdit(scope.row)">修正</el-button>
</template>
</el-table-column>
当用户点击修正时,咱们需求做两件事:
- 翻开弹窗
- 回填数据
完结 onEdit
函数代码如下:
const onEdit = rowData => {
// 表示当时时修正状况
isEdit.value = true
// 翻开弹窗
dialogVisible.value = true
Object.keys(formData).forEach(key => {
// 依据 rowData 回填 formData 数据
formData[key] = rowData[key]
})
// 取得当时数据的 id
formData.id = rowData._id
}
因为咱们整个提交逻辑跟新增的时分是相同的,所以咱们只需求经过 isEdit
来判别一下现在是新增仍是修正,从而去调用不同的接口即可。所以这儿咱们对上文提到的 onSubmit
函数进行小修正,代码如下:
const onSubmit = async () => {
try {
// 经过 isEdit 判别调用新增仍是修正接口
isEdit.value
? await postUpdate(formData)
: await postSave(formData)
// 案牍依据 isEdit 进行调整
ElMessage.success(isEdit.value ? '装备修正成功' : '装备保存成功')
await initData()
dialogVisible.value = false
} catch (e) {
// 案牍依据 isEdit 进行调整
ElMessage.error(isEdit.value ? '装备修正失利' : '装备保存失利')
}
}
验证一下作用,找到一条数据,并在所有数据项后面添加 updata
字符串。然后点击承认按钮。
如图所示,调用了 update
接口且正确上传参数(多了个id的参数),并且成功修正数据库数据显示在当时界面中:
又搞定了一个功用,现在咱们把最终一个功用「删去」也一同完结了,咱们接着往下看!
3. 删去装备
删去装备跟修正相同,也是需求 id
(仅有标识) 传给后端,删去对应的装备数据。所以,咱们需求在 table
的操作列中新增一个删去的按钮。一般删去这种操作,都是需求二次承认的,所以笔者在这儿也应用上 Element-plus
的 comfirm
组件。
老样子,首要是 前端界面的代码完结:
<!-- 操作列中新增 删去 按钮 -->
<el-popconfirm title="承认删去该装备?" @confirm="onDel(scope.row)">
<template #reference>
<el-button type="danger" link>删去</el-button>
</template>
</el-popconfirm>
作用如图所示:
接着咱们完结删去函数 onDel
:
const onDel = async rowData => {
try {
// 调用删去恳求,传入参数 id
await postDelete({ id: rowData._id })
ElMessage.success('装备删去成功')
// 删去成功后更新当时界面数据
await initData()
} catch (e) {
ElMessage.error('装备删去失利')
}
}
删去函数的完结也是十分的简略!接下来,笔者就在界面中操作一下,看看删去是否成功完结!笔者在这儿就删去一条名为 test add 1
的装备数据,如图所示:
点击承认后,成功建议 del 接口的恳求,成功删去数据后刷新界面显示,作用如图所示:
好啦,到这儿整个 crud
的功用就搞定了,也算是体会一把全栈开发的感觉了有木有~在这儿,笔者带咱们进行简略的回忆本文的内容:
- 首要是完结分页数据显示,从前端界面到后端接口的完结
- 然后便是完结了装备信息的
crud
功用!
写在最终
经过本文后,整个专栏的文章编写现已挨近尾声了,回忆一下本专栏的内容,咱们从 前端 、 后端 、 jenkins 中现已逐步完结了发布渠道的功用了,现在仅剩最终一步:从前端建议构建、获取 jenkins 日志。没错,这一步笔者会在下一篇文章中进行解说,这儿列一下首要共享的内容:
- 运用
websocket
完结 jenkins 日志传输 - 后端完结当时构建项目仅有构建实例(多个用户翻开同个项目仅有一个构建状况)
咱们敬请期待!