相关介绍
我们的业务组件中已经实现了通用查询的功能,现在需要在该功能的基础上能够动态的去修改查询条件/工具栏/展示的结果等组件。 因此在原有的通用查询的基础上添加了能够扩展的功能,这篇文档主要是介绍如何基于通用查询模板去写报表
# 查询条件扩展
# Case1,重写查询条件展示
内置的查询条件展示形式有:text-input / number-input / select / date-picker / datetime-picker / switch,<query>组件使用查询模板配置的展示组件(不配置时根据条件的数据类型选用合适的展示组件)。如果业务需要其他的展示形式,则需要手写代码重写查询条件的展示。请看以下示例:
# 重写前的截图
# 重新【车型】条件
<template>
<query
ref="query"
<!-- 查询模板code -->
custom-template-code="nio_part_project_QT_list"
<!-- 条件初始化函数 -->
:condition-init-fun="conditionInitFunc"
>
<!-- 通过作用域插槽暴露query内部的条件定义数据给业务页面使用 -->
<template v-slot:condition="{ item }">
<!-- 自定义的车型选择组件 -->
<tag-list v-if="item.alias==='model'" v-model="item.value" :list="item.selectList"
@on-change="onSelectedModelChanged"
/>
</template>
</query>
</template>
<script>
import TagList from './tagList.vue'
export default {
components: {
TagList
},
methods: {
// 条件初始化方法
conditionInitFunc (current, conditions) {
// 是车型条件时
if (current.alias === 'model') {
// 不使用默认条件(原始的输入框);如果为true,则同时显示默认展示和自定义展示。
current.useDefaultSlot = false
// selectList是下拉框的选项定义,实际项目中可通过接口获取等。
current.selectList = [{ label: 'ES1', value: 'ES1' }, { label: 'ES8', value: 'ES8' }]
}
},
// 车型选中事件的处理函数
onSelectedModelChanged () {
// 调用query内部的refresh方法刷新数据---已经使用了选中的车型作为查询条件
this.$refs.query.refresh()
}
}
}
</script>
代码说明
<query>是查询模板的前端实现组件,它通过Vue的作用域插槽(scoped slot)将查询模板中的条件定义暴露给query的调用者,使其能在具体的业务场景中对条件做个性化展示。如图所示,我们自定义了一个tag-list组件,替代默认的车型输入框。
同时还要传入 condition-init-fun 定义,即组件的初始化函数。
车型选中改变时,需要调用组件内部的刷新方法刷新表格
tag-list组件定义
<template>
<ul class="tag-list">
<li v-for="option in list" :key="option.value"
:class="['tag', {'tag__checked': value === option.value}]"
@click="chooseTag(option.value)"
>{{option.label}}</li>
</ul>
</template>
<script>
export default {
name: 'tag-list',
props: {
disabled: Boolean,
list: { type: Array, default: () => ([]) },
value: String
},
methods: {
chooseTag (value) {
this.$emit('input', value)
this.$emit('on-change', value)
}
}
}
</script>
代码说明
需要注意 chooseTag 方法的写法,这样写可以将选择的车型更新到组件内部的条件数据,方便调用组件内部的刷新方法刷新表格,而无需关注车型如何传值。
# 重写后的截图
# Case2,重设条件宽度
场景说明
继续使用Case1的场景说明问题,如果车型选项较多,默认的宽度展示不全,会导致条件换行显示。见下图
# 重设前的截图
# 宽度设置代码
<template>
<query
...
:condition-item-col="conditionItemCol"
/>
</template>
<script>
export default {
...
data () {
return {
conditionItemCol: {
// 条件区域宽度采用24等分,每个条件默认宽度为 6,以下代码将车型条件的宽度增加到12,即占行宽的50%
model: 12
}
}
}
}
</script>
# 工具栏扩展
# 结果展示为报表
# 截图示例

# 操作步骤及规范
# 1. 通用查询模板配置
注意:
红色框为必填项

配置切换组件的信息json字段如下:
{
"templateReplace": {
"condition": "", // 用来替换查询条件翻译组件的全局组件名称,为空时使用通用查询内置的转换组件
"toolBar": "", // 用来替换工具栏的全局组件名称;如果不填时,默认使用 src/common/components/query/reportToolbarTemplate.vue注册的全局组件,ReportToolbarTemplate进行翻译
"resultDisplay": "resultDisplay1", // 查询结果展示组件,默认是table,只有指定了这个报表的功能才能实现
"queryConditionAreaComp": "" // 替换整个查询区域的全局组件名称
},
"appendConditions": [ // 针对toolBar实现动态可配置逻辑,即作为参数信息结合ReportToolbarTemplate动态逻辑生成第二行查询条件
{ // 以下是一个简单的例子,你可以针参数信息据自己补充其中的逻辑
"key": "user", // 注意:value为默认显示的值,且必须
"label": {
"zh_CN": "用户名",
"en_US": "Username"
},
"component": "radio-button",
"options": [
{
"option_key": "张三",
"option_desc": "张三"
},
{
"option_key": "李四",
"option_desc": "李四"
}
],
"value": ""
},
{
"key": "tag",
"label": {
"zh_CN": "标签",
"en_US": "Tag"
},
"component": "radio-button",
"value": "工作日",
"options": [
{
"option_key": "工作日",
"option_desc": "工作日"
},
{
"option_key": "周末",
"option_desc": "周末"
}
]
},
{
"key": "date",
"label": {
"zh_CN": "时间段",
"en_US": "Date Period"
},
"component": "daterange",
"value": "lastWeek",
"options": [
{
"option_key": "工作日",
"option_desc": "工作日"
},
{
"option_key": "周末",
"option_desc": "周末"
}
]
}
]
}
# 2. toolBar组件配置
注意:
每一个form-item上需要绑定一个值改变时的事件changeConditions,从而通过this.$emit('append-conditions', {user, date, tag})将改变的值通知给query组件,进而达到刷新的效果;
append-conditions:这个事件名称固定,且不可变;用来toolbar组件与query组件的通信
conditions:用来接收第一行查询条件的搜索结果集,从而处理动态逻辑
<template>
<div class="toolBar1 row">
<div class="item" v-show="userList.length > 0">
<RadioGroup v-model="user" type="button" @on-change="changeConditions">
<Radio :label="item" :key="item" v-for="item in userList"></Radio>
</RadioGroup>
</div>
<div class="item">
<RadioGroup v-model="tag" type="button" @on-change="changeConditions">
<Radio :label="item" :key="item" v-for="item in tagLists"></Radio>
</RadioGroup>
</div>
<div class="item">
<DatePicker placeholder="时间段" v-model="date" type="daterange" placement="bottom-end" style="width: 200px" @on-change="changeConditions"></DatePicker>
</div>
</div>
</template>
<script>
import dateUtil from 'UTILS/dateUtil'
export default {
name: 'toolBar1',
props: {
conditions: Object // 接收查询条件的动态输入或者选择值
},
watch: {
conditions: {
handler (val) {
let depObj = val.find(item => item.key === 'department') // 监听有用的值,然后与本组件动态联动
if (depObj) {
this.dep = depObj.value[0]
}
},
deep: true
}
},
data () {
return {
dep: '',
user: '',
tag: '工作日',
date: [],
userLists: {
OD: ['张三', '李四'],
SD: ['王五']
},
tagLists: ['工作日', '周末']
}
},
computed: {
userList () {
return this.userLists[this.dep] || []
}
},
methods: {
changeConditions () {
let {user, date, tag} = this
let formated = date.map(d => d ? dateUtil.format(new Date(d), 'yyyy-MM-dd') : '').join('~')
date = formated === '~' ? '' : formated
this.$emit('append-conditions', {user, date, tag}) // 通过事件append-conditions通知query组件去将这些数据拼接到查询通用查询的查询条件中去,并且发出请求功能
}
},
mounted () {
this.changeConditions()
}
}
</script>
# 3. resultDisplay组件配置
注意:
参数options用来接收通用查询的相关信息,包括列的定义,查询的结果数据;你需要用到的就是options.cData,即查询出来的最新数据来渲染你的报表
<template>
<div class="query-bar-wrapper">
<v-chart :options="chartOpt" ref="echarts" auto-resize></v-chart>
</div>
</template>
<script>
import ECharts from 'vue-echarts/components/ECharts'
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/toolbox'
import 'echarts/lib/component/title'
export default {
// 柱状图
name: 'resultDisplay1',
components: {
'v-chart': ECharts
},
props: {
options: { // 接收query组件返回的一些参数,包括cData(即后台返回的查询结果)
type: Object,
default: () => {}
}
},
mounted () {
this.resetOptions(this.options)
},
watch: {
options: {
handler (opts) {
this.resetOptions(opts)
if (this.$refs.echarts) {
opts.loadingSpinner ? this.$refs.echarts.showLoading() : this.$refs.echarts.hideLoading()
}
},
immediate: true,
deep: true
}
},
data () {
return {
chartOpt: {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
title: {
text: '',
x: 'center'
},
legend: {
data: [],
top: 30
},
toolbox: {
show: true,
orient: 'vertical',
left: 'right',
top: 'center',
feature: {
mark: {show: true},
dataView: {show: true, readOnly: false},
magicType: {show: true, type: ['stack', 'tiled', 'pie']},
restore: {show: true},
saveAsImage: {show: true}
}
},
calculable: true,
xAxis: [
{
type: 'category',
axisTick: {show: false},
data: []
}
],
yAxis: [
{
type: 'value'
}
],
series: []
}
}
},
methods: {
resetOptions (opts) {
let legendData = []
let xAxisData = []
let series = []
const {cCols, cData} = opts
cCols.forEach((col) => {
if (!['selection', 'radio', 'index'].includes(col.type)) {
// 排除特殊类型
legendData.push(col.title)
if (col.groupby) {
xAxisData = cData.map(row => row[col.key])
} else {
series.push({
name: col.title,
type: 'bar',
data: cData.map(row => row[col.key])
})
}
}
})
if (this.chartOpt) {
this.chartOpt.legend.data = legendData
this.chartOpt.xAxis[0].data = xAxisData
this.chartOpt.series = series
// this.chartOpt.title.text = i18nName
}
}
}
}
</script>
# 4. query组件demo实例
在目录下src/modules/demo/query-report-extend有demo例子[只需要简单的指定code就行]
<template>
<div slot="work-area" class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<query
:customTemplateCode="customTemplateCode"
:conditionsDefaultValue="conditionsDefaultValue"
:showOperation="false"
:contextPath="contextPath">
</query>
</div>
</div>
</template>
<script>
export default {
name: '问题统计报表',
data () {
return {
customTemplateCode: 'apiindex561-433', // 配置的code参数
conditionsDefaultValue: { // 查询条件的默认初始值
issueSource: 'Body_CQA',
vehicleModelId: 9
},
contextPath: 'cqa.report-service' // 替换掉通用查询默认的查询数据接口地址前缀
}
},
methods: {
},
computed: {
}
}
</script>
← 通用查询用法示例