✍此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版,拥抱Vue3.0将前端框架替换成字节最新开源的arco.design,其中约60%重构和20%新增内容,定位为从
0-1手把手实现简单的测试平台开发教程,内容将囊括基础、扩展和实战,由浅入深带你实现测试开发岗位中平台工具技术能力入门和提升。
1.优化TPMService结构
之前实现的接口代码全部写在主运行文件中,随着业务接口的增多这显示是不合理,所以这里利用上篇学到的 Blueprint 来进行优化,使其模块化的管理和开发。
1.1 迁移登录代码
在项目初始化的文章里。我们已经在TPMService项目跟目录创建了apis包文件夹,用于所有分业务接口管理,因此对于用于接口创建一个命名为user.py
的Python文件,并将之前 run.py
中登录、获取用户信息、登出的代码剪切到 user.py,另外需要从flask中import blueprint,并注册一个对象,重点实现给出标记使用的新的接口类/apis/user.py
和蓝图对象优化后的完整代码参考如下:
python
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from flask import request
import json
from flask import Blueprint
'''
@Author: Zhang Qi
@Copyright: 博客&公众号《大奇测试开发》
@Describe: 用户登录接口
'''
app_user = Blueprint("app_user", __name__)
@app_user.route("/api/user/login",methods=['POST'])
def login():
data = request.get_data() # 获取post请求body数据
js_data = json.loads(data) # 将字符串转成json
if 'username' in js_data and js_data['username'] == 'admin':
result_success = {"code":20000,"data":{"":""}}
return result_success
else:
result_error = {"code":60204,"message":"账号密码错误"}
return result_error
@app_user.route("/api/user/info",methods=['GET'])
def info():
# 获取GET中请求token参数值
token = request.args.get('token')
if token == 'admin-token':
result_success = {
"code":20000,
"data":{
"roles":["admin"],
"role":"admin", # 兼容Aroc前端框架
"introduction":"I am a super administrator",
"avatar":"https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
"name":"大奇",
"jobName": '非典型程序员',
}
}
return result_success
else:
result_error = {"code": 60204, "message": "用户信息获取错误"}
return result_error
@app_user.route("/api/user/logout", methods=['POST'])
def logout():
result_success = {
"status": 'ok',
"msg": '请求成功',
"code": 20000,
}
return result_success
然后就是在app.py
进行Blueprint的注册,重新运行做以下接口请求验证(测试略)是否均正常响应
2.产品管理之展示
我们接下来将正式开始实现产品管理页面的交互逻辑,因为涉及到很多新内容,也是全系列的基础,所以会通过较多几篇分享来讲解。
2.1 产品列表接口
按照上边的优化结构练习,我们创建一个硬编码的一个产品线模块 /apis/product.py
,来配合实现一个"产品列表"vue页面,直接给出核心代码:
python
# -*- coding:utf-8 -*-
from flask import Blueprint
app_product = Blueprint("app_product", __name__)
@app_product.route("/api/product/list",methods=['GET'])
def product_list():
# 硬编码返回list
data = [
{"id":1, "keyCode":"project1", "title":"项目一", "desc":"这是项目1描述", "operator":"admin","update":"2020-04-06"},
{"id":2, "keyCode": "project2", "title": "项目二", "desc": "这是项目2描述", "operator": "user", "update": "2020-04-03"}
]
# 按返回模版格式进行json结果返回
resp_data = {
"code": 20000,
"data": data
}
return resp_data
不要忘记 app.py
中 register_blueprint
注册
python
# -*- coding:utf-8 -*-
from flask import Flask
from apis.user import app_user
from apis.product import app_product
from flask_cors import CORS
app = Flask(__name__)
CORS(app, supports_credentials=True)
app.register_blueprint(app_user)
app.register_blueprint(app_product)
if __name__ == '__main__':
app.run(debug=True)
2.2 搭建第一Arco Vue页
在路径TPMArco/src/views/
下创建个文件夹product
, 接着右键 New Vue Compoent,命名为 index.vue
,在自动生成的模版页面代码
要想页面展示还需要配置路由菜单,在Acro Pro的经过验证是src/router/routes/modules
创建对应的路有来实现,这里我给出正确的配置,以便先实现第一个页面的搭建,具体 菜单和路由 后边拎出个小节点单独说
还有最后一个配置,需要在 src/locale/zh-CN.ts
增加locale的定义,因为目前的脚手架是多语言的,菜单这块需要使用 语言包键名 才能正确展示。
typescript
import localeSettings from './zh-CN/settings';
export default {
'menu.config': '基础管理',
'menu.config.product': '产品线管理',
...
};
2.3 使用第一组件
利用上边的页面和接口,我们通过一个Table组件来实现产品列表展示,所谓万事开通难,先看下官方<a-table>
的基础使用
点击</>按钮展开参考代码,将其对应和
typescript
<template>
<a-table :columns="columns" :data="data" />
</template>
<script>
// reactive是 Vue3 中提供的实现响应式数据的方法
import { reactive } from 'vue';
export default {
name: "Product",
setup() {
// 定义表格列
const columns = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Salary',
dataIndex: 'salary',
},
{
title: 'Address',
dataIndex: 'address',
},
{
title: 'Email',
dataIndex: 'email',
},
];
// 表格数据,这里先不请求后端写死模拟
const data = reactive([{
key: '1',
name: 'Jane Doe',
salary: 23000,
address: '32 Park Road, London',
email: 'jane.doe@example.com'
}, {
key: '2',
name: 'Alisa Ross',
salary: 25000,
address: '35 Park Road, London',
email: 'alisa.ross@example.com'
}, {
key: '3',
name: 'Kevin Sandra',
salary: 22000,
address: '31 Park Road, London',
email: 'kevin.sandra@example.com'
}, {
key: '4',
name: 'Ed Hellen',
salary: 17000,
address: '42 Park Road, London',
email: 'ed.hellen@example.com'
}, {
key: '5',
name: 'William Smith',
salary: 27000,
address: '62 Park Road, London',
email: 'william.smith@example.com'
}]);
return {
columns,
data
}
},
}
</script>
<style scoped>
</style>
通过 command(ctrl)+ s 保存代码,如果是IDE在npm run dev 会自动编译渲染,如果没有请重新运行命令,最终看到上述给定的表格(写死在前端的数据)正常显示,至此第一个组件使用完成。
2.4 使用后端接口
1)配置查询查询API
在 src/api/product.ts
创建一个接口配置文件,配置上边服务的get请求地址,其中定义方法名为apiProductList()
, 具体代码如下:
typescript
# src/api/product.ts
import axios from 'axios';
import type { TableData } from '@arco-design/web-vue/es/table/interface';
export function apiProductList() {
return axios.get<TableData[]>('/api/product/list');
}
特别说明:由于Acro拥抱typescript,所有组件的pro的例子代码都是,所以为了拿来即用,后续的前端js部分代码也会沿用,好在如果会javacript过渡不会很难,笔者也是第一次使用,从照葫芦画瓢的基础上会帮助先趟坑,因此完全不用但心,拥抱技术,也是一种全新的尝试。
2)Table远程数据绑定
这块笔者首次接触折腾了一上午,Vue3.0语法使用上对比2.0还是有不少不同,其中<script lang="ts" setup>
语法糖就是新的变化,本篇先不过多说明,有兴趣可以提前看引用中文章。
Vue3之script-setup解析 www.jianshu.com/p/5096bfb42...
如果你曾经写习惯了vue2.0中
methods:{}
、data()
、create ()
,就像电影里张无忌学习太极时候一样暂时忘掉,以下是完整可运行代码:
typescript
<template>
<a-table
:columns="columns"
:data="renderList"
:pagination="false"
/>
</template>
<script lang="ts" setup>
// 引用接口方法
import { apiProductList } from '@/api/product';
// vue ref获取组件
import { ref } from "vue";
import { TableData } from "@arco-design/web-vue/es/table/interface";
// 表格列属性
const columns = [
{
title: 'ID',
dataIndex: 'id',
},
{
title: '标识码',
dataIndex: 'keyCode',
},
{
title: '标题',
dataIndex: 'title',
},
{
title: '描述',
dataIndex: 'desc',
},
{
title: '操作者',
dataIndex: 'operator',
},
{
title: '更新时间',
dataIndex: 'update',
}
]
// 定义指定标准表返回格式变量,并通过async箭头函数异步请求接口方法
const renderList = ref<TableData[]>();
const fetchData = async () => {
try {
const { data } = await apiProductList();
renderList.value = data;
} catch (err) {
console.log(err);
}
};
fetchData();
</script>
<script lang="ts">
export default {
name: 'Product',
};
</script>
此内容中我们还是需要了解一下几点
- vue 是一套响应式框架,一般组件、方法和样式在一个页面中集中实现
- 模块 组件UI实现区域
- 模块 业务实现的区域
3)运行测试
以上如果没有错误的话,我们再重新运行后端服务,
shell
python app.py # 或PyCharm 配自run config直接运行
nmp run dev # 或WebStorm 配自run config直接运行
前端服务看下效果,接口正确请求,数据正确渲染到table组件上。
3.菜单和路由
路由通常都和菜单绑定在一起,为了减少维护的量,我们直接通过路由表生成了菜单,以下内容均来在官方文档。
3.1 路由
首先,需要先了解一下路由表的配置。基本的路由配置请参阅 Vue-Router 官方文档
typescript
// const DEFAULT_LAYOUT = () => import('@/layout/default-layout.vue');
// 在本例子中,页面最终路径为 /dashboard/workplace
export default {
path: 'dashboard', // 路由路径
name: 'Dashboard', // 路由名称
component: () => import('@/views/dashboard/index.vue'), // 跳转的组件页面
// component: DEFAULT_LAYOUT, // Aroc pro 一级菜单用默认布局包裹
meta: {
locale: 'menu.dashboard',
requiresAuth: true,
icon: 'icon-dashboard',
order: 0,
},
children: [ // 子菜单
{
path: 'workplace',
name: 'Workplace',
component: () => import('@/views/dashboard/workplace/index.vue'),
meta: {
locale: 'menu.dashboard.workplace',
requiresAuth: true,
roles: ['admin'],
hideInMenu: false,
},
},
],
};
路由 Meta
元信息(官方还有一些其他几个参数,目前用不到就不罗列了)
- roles : 配置能访问该页面的角色,如果不匹配,则会被禁止访问该路由页面
- requiresAuth: 是否需要登录鉴权
- locale:一级菜单名(语言包键名)
- icon:菜单配置icon
- hideInMenu:是否在左侧菜单中隐藏该项
- order:排序路由菜单项。如果设置该值,值越高,越靠前
这里想要说下Acro Pro模版项目如何设置一级菜单,笔者大奇尝试了一些配置,以及搜索了一番均无果,如果大家对这块熟悉有配置方式请告诉我,如果后续我发现了解决办法也会第一时间分享出来。
3.2 菜单
前端菜单生成过程:
- 通过 appRoute 计算属性,得到带有路由信息的路由树。
- 使用上一步获取的路由信息进行权限过滤,生成用于渲染的 菜单树。
- 通过 渲染 菜单树,递归生成菜单。
服务端菜单生成过程:
- 在Store中增加api请求的 action,用于获取服务端的路由配置。
- 发起请求,将服务端的路由配置结果存储在Store中。
- 通过 appRoute 计算属性,得到带有路由信息的路由树。
- 使用上一步获取的路由信息进行权限过滤,生成用于渲染的 菜单树。
- 通过 渲染 菜单树,递归生成菜单。
遇到的问题
笔者在编程过程中遇到了大量如下的警告报错,经查询是 ts格式的检查和eslint一样,如果里边没有对应的error是不会出现如下页面报错,只会在控制台输出警告,但如果确实烦可以在 .eslintrc.js
的rules配置注释掉它,或者进行标准格式化 (Alt-Shift-Cmd-P on macOS or Alt-Shift-Ctrl-P on Windows and Linux)、或IDE配置保存后自动格式化均可。
本篇最后来个回顾,主要有了好多的第一次:
- 后端接口路由的分类优化
- 一个Acro vue 新页面的诞生
- Acro design 第一个组件使用
- 实现接口请求和数据绑定
- 菜单\路由配置和扩展参数说明
由于是再版整理,我一开始以为会很快,但实际上这里涉及了新风格框架,及vue3、typescript新内容,实现和验证以上所有内容的时候还是花了近一天多的时间,这里想说的是在互联网快速发展的今天,接触的新的东西不可避免,要保持好奇、敢尝试的一种精神不断的充实自己,当然这个精力和度要自己把握好。