# 7.5 组件样例
# 文件概览
├── cards // 固定目录
└── cardName // 组件名称
└── panel // 组件自定义配置面板
├── Config.vue // 组件配置内容
├── index.js // 组件配置入口
├── static // 组件静态资源
├── card.json // 组件元数据文件
├── Card.vue // 组件vue代码
├── index.js // 组件入口
├── README.md // 组件介绍文档
├── manifest.json // 资源包元数据文件
└── README.md // 资源包内容介绍文件
# 图表类规范示例(曲线图为例)
# 样例1:新增组件交互
下面以新增标题的点击事件为例,点击后将标题内容作为入参,朝指定url跳转
# 1、在card.json中配置交互事件
找到cardEvents数组,可以看到组件已经有一个交互事件了,为图表点击,其中包含有两个可传递参数的变量,分别是x和y。于是在cardEvents中新增一个对象
"cardEvents": [ // 组件交互配置
{
"name": "图表点击", // 交互事件名称
"id": "event-one", // 交互事件id, 同一组件内唯一
"variable": [ // 交互事件参数列表, 自定义字段名称/类型
{
"field": "x", // 交互事件参数字段, 自定义
"type": "string" // 交互事件参数类型, 自定义
},
{
"field": "y",
"type": "number"
}
]
}
]
"cardEvents": [
{
... // 图表点击
},
// 新增如下内容
{
"name": "标题点击",
"id": "click-title",
"variable": [
{
"field": "param",
"type": "string"
}
]
}
]
# 2、在Card.vue中通过message消息发布,传递参数
2.1、找到卡片标题的DOM结构
<div class="wemax-card-container">
<div class="inner">
<CardTitle :options="options"/>
<div ref="chartRef" class="weMax-container"></div>
</div>
</div>
新增click点击事件,使用native是防止点击无效,代码如下所示
<CardTitle :options="options" @click.native="handleTitleClick"/>
2.2、在methods中,新增标题点击函数handleTitleClick的处理逻辑
前面说到,该点击事件需要传入当前卡片标题的内容,由于之前考虑国际化差异,原先在card.json的配置如下
"i18n": {
"messages": {
"zh_CN": {
"cardTitle": "曲线图",
"rightTitle": ""
},
"en_US": {
"cardTitle": "Line Chart",
"rightTitle": ""
}
}
},
可以得到卡片标题的字段为 cardTitle,WeMax平台插件中,已经将卡片标题等文本进行了国际化处理,都包含在textContentObj对象中,可以使用该字段获得标题,代码如下
handleTitleClick(){
const cardEvent = this.options.cardEvents[1] // 获取card.json文件中新增的标题点击事件对象
const publishParam = {
i: this.options.i || '', // 组件唯一标识i -- 固定值, 不可修改
id: cardEvent.id, // 交互唯一标识id
param: { // 交互参数
[cardEvent.variable[0].field]: this.textContentObj.cardTitle // 即对象key为param
},
interactionList: this.options.interactionList || [] // 独立运行wemax卡片交互必传参数
}
this.$service.message.publish({ // 发送message消息
topic: 'cardEventDistribution', // cardEventDistribution消息名称 -- 固定值, 不可修改
data: publishParam // 交互参数,按照实际情况修改
})
},
2.3 在mouted中订阅消息
若该卡片card.json中已有事件列表cardEvents,则Card.vue中应该有订阅消息的函数了,此步骤则可跳过。若卡片是第一次设置事件交互或vue文件中没有该类函数,则需要添加消息订阅,代码如下
// 在Card.vue中订阅message事件,刷新数据
// subscribeMessageFun 和 handlerSubscribeMsg 均为EventMixin 混合内方法, 使用时需提前从公共插件引入
this.subscribeMessageFun(topic, data => {
if (topic === 'variablesSubscribption') { // 订阅全局变量。variablesSubscribption名称为固定值,修改无效
this.handlerSubscribeMsg(data, this.options.apis)
}
})
至此,代码部分就全部完结。此时需要将卡片版本号加1,并上传到WeMax平台,具体上传步骤可参考。
# 3、在WeMax平台上配置跳转交互
在平台右边配置项中找到 交互--标题点击--设置变量,可以看到动态变量下面有个字段param,这跟卡片代码中写相吻合,此时可按如下步骤操作。
a.在绑定变量那一列填入param,表示将该动态变量绑定到param
b.将绑定变量的开关打开,表示向全局暴露
然后在交互--标题点击--图形交互设置成下图,具体步骤如下:
a.交互方式有关联显示/隐藏、跳转、弹出窗口等,此处选择跳转
b.打开方式可选新窗口
c.跳转到,选择目标地址,如百度地址
d.在参数一栏,需要设置入参,点击+号,弹出参数选择表,设置如下
此时WeMax平台上配置完毕,可点击右上角的保存,再点击预览,则会看到曲线图的预览效果
此时点击曲线图左上角的标题,则会跳转前往新窗口,地址显示如下
至此,交互功能完成。
# 样例2:新增系列1配置项
新增需求,给曲线图系列1--系列类型配置项下面,加一个线类型的配置项,具体步骤如下:
# 1、在SeriesItem.vue中新增配置项
由于卡片工程中图表类配置都很常用,因此此类配置一般都在公共组件中,并不属于该卡片私有。为了找到配置线类型的地方,可选择该面板中一个比较独特的字段,比如默认边框宽度,然后去编辑器中,搜索该字段,即可找到SeriesItem.vue文件,若搜索出多个文件,则需要排除,确认后才可进去修改。
a.先在文件的HTML中找到系列类型的配置代码,如下所示
<aui-form-item label="系列类型">
<aui-select v-model="seriesType">
<aui-option
v-for="item in typeOp"
:key="item.value"
:label="item.text"
:value="item.value"
>
</aui-option>
</aui-select>
</aui-form-item>
b.然后按照上述代码的格式,在它下面加入线类型的配置代码,从echarts官网得到线类型的表示方法为series.itemStyle.normal.lineStyle.type,于是用v-model绑定如下
<aui-form-item label="线类型">
<aui-select v-model="data.itemStyle.normal.lineStyle.type">
<aui-option
v-for="item in lineTypeOp"
:key="item.value"
:label="item.text"
:value="item.value"
>
</aui-option>
</aui-select>
</aui-form-item>
其中data是该文件的父组件传过来的表示系列的对象。
c.将lineTypeOp定义如下
lineTypeOp: [
{ value: 'dotted', text: '点线' },
{ value: 'solid', text: '实线' },
{ value: 'dashed', text: '虚线' }
],
d.引入AUI组件Select和Option
import { Select, Option} from '@aurora/vue'
export default {
components: {
AuiSelect: Select,
AuiOption: Option,()
},
# 2、在card.json中配置series属性
大多数的卡片工程的图表类代码中,这些series默认配置项都是公共的,其对应的控制字段都统一放在插件中,所以card.json中series属性一般是空数组,如果想要设置不一样的效果,只需在series中设置对应的字段即可,如果它的配置和插件中的配置有重复,则会以card.json中的为主,因此此处可设置为
series: [
{
itemStyle: {
normal: {
lineStyle: {
type: 'solid'
}
}
}
}
]
至此,新增线类型配置项的功能开发完成,该功能不需要上传到WeMax平台,在本地即可验证,效果如下
# 样例3、新增api服务
如需新增一个数据服务,将返回的文本内容显示到标题下面,则可按以下步骤
# 1、在card.json中新增服务设置
"apis": [
{
...之前的服务设置
},
// 新增服务
{
"id": "top-text",
"name": "文本数据服务",
"title": "文本数据服务",
"refreshSwitch": false,
"refreshTime": 60,
"variables": {},
"showAggregation": false,
"type": "static",
"supportTypes": ["static", "api"],
"isInItGetData": true,
"isInitServeI18n": false,
"fields": [
{
"id": "text-name",
"field": "text",
"mapField": "text",
"desc": "文本数据服务",
"type": "string",
"category": "dimension"
}
],
"source": [
{
"text": ""
}
]
}
]
# 2、在card.vue中配置
a.在计算属性中新增该api
optionsApi1() {
return this.options.apis[1]
},
b.将该服务加入监听,如果该服务有变化,便会重新获取服务数据。
const watchers = {
{
...
},
optionsApi1: {
deep: true,
handler(val) {
if (val) {
this.getTextData()
this.isRefresh(this.getTextData, val.refreshSwitch, val.refreshTime)
}
}
},
c.,定义变量,初始化时调用服务获取数据
data() {
text: ""
},
mounted() {
this.getTextData()
}
d.在DOM结构中加入需要展示的结构,样式自写。
<div>{{text}}</div>
e.编写服务数据获取函数
async getTextData(){
const textData = await this.getDataByID('top-text') // 根据JSON文件的api字段定义的ID获取数据,其中getDataByID来自ApiMixin混合
const fields = this.apis[1].fields
const res = this.buildRemodelData(textData, fields) // 将数据转换处理,来自ApiMixin混合
if (res.length) {
this.text = res[0].text // 固定格式,从定义的source中取出text字段
}
},
最终面板如下,只需将数据源类型由静态数据改为REST URL,就可以填入服务地址了
# 表格类规范示例(表格组件为例)
# 文件概览
├── cards // 固定目录
└── cardName // 组件名称
└── panel // 组件自定义配置面板
├── Config.vue // 组件配置内容
├── index.js // 组件配置入口
├── components // 组件配置文件夹
├── columnConfig // 列配置文件夹
├── ColumnConfig.vue // 列总的配置文件
├── ColumnSettingItem.vue // 各列设置项
├── ColumnSettings.vue // 列设置
├── SelfHeadItem.vue // 自定义表头具体各项
├── SeqConfig.vue // 序号列配置
├── TableSelfHead.vue // 自定义表头
├── conditionConfig // 列条件配置项文件夹
├── ColumnConditionConfig.vue // 列条件总配置
├── ColumnTextStySetting.vue // 列文本样式配置
├── ConditionConfig.vue // 列条件配置
├── ConditionItem.vue // 各列的条件配置
├── DialogSetting.vue // 对话框配置
├── ImageSetting.vue // 图片项配置
├── LinkTextSetting.vue // 链接项配置
├── ProgressStySetting.vue // 进度条样式设置
├── RowConditionConfig.vue // 行条件配置
├── RowConditionItem.vue // 各行的条件配置
├── RowConditionList.vue // 行条件配置
├── RowConditionPanel.vue // 行条件面板
├── RowConditions.vue
├── rowConfig // 行配置文件夹
├── IconConfig.vue // 图标配置
├── RowConfig.vue // 行配置
├── TableHeadConfig.vue // 表头配置
├── TableRowConfig.vue // 表行配置
├── rowConfig // 分组行设置
├── BorderConfig.vue // 边框配置文件
├── EventConfig.vue // 事件配置文件
├── EventStyleConfig.vue // 事件样式配置文件
├── FontConfig.vue // 字体配置文件
├── PagerConfig.vue // 页面配置文件
├── TableConfig.vue // 表格配置文件
├── static // 组件静态资源
├── compontents // 组件文件
├── ConditionedCell.vue // 单元格组件
├── PageSizeSetting.vue // 分页页码设置
├── Sorter.vue // 排序组件
├── TableDialog.vue // 表格弹窗组件
├── TablePager.vue // 分页组件
├── card.json // 组件元数据文件
├── Card.vue // 组件vue代码
├── index.js // 组件入口
├── README.md // 组件介绍文档
├── manifest.json // 资源包元数据文件
└── README.md // 资源包内容介绍文件
# index.js规范
输出入口文件为Card.vue。
import Card from './Card.vue'
export default Card
# card.json规范
# 总体描述
属性 | 类型 | 必填 | 描述 |
---|---|---|---|
name | string | 是 | 组件名称,在资源包内唯一,必须使用英文,数字和连字符。 |
code | string | 是 | 组件编码,要求全局唯一,{组件name} |
title | string | 是 | 组件标题 |
version | string | 是 | 组件版本号 |
main | string | 是 | 组件运行代码路径 |
initProps | object | 是 | 组件初始化时加载参数 |
dnd | object | 是 | 组件默认大小配置 |
description | string | 否 | 组件功能描述 |
keywords | string[] | 否 | 组件资源标签,可以设置多个 |
customPanel | string | 否 | 组件自定义面板路径 |
apis | object | 否 | 组件数据接入配置 |
cardEvents | object | 否 | 组件交互配置 |
alarmMsgConfig | object | 否 | 组件消息预警配置 |
# 组件元数据规范示例
{
"code": "wemax.template.table",
"name": "wemax.template.table",
"title": "表格",
"description": "表格",
"version": "1.0.0",
"type": "create:card",
"category": "组件",
"keywords": ["wemax"],
"icon": {
"default": "./static/default.svg",
"preview": "./static/preview.svg"
},
"customPanel": "./panel/index.js",
"initProps": {
"options": {
"alarmMsgConfig": { // 消息预警配置, 不必填
"conditionConfig": false, // 消息预警开关
"messageList": [ // 消息预警列表,最多可配置5条
{
"conditionCode": "item.column1 > 8000", // 消息预警条件
"messageTitle": "表格预警消息", // 消息推送标题
"messageContent": "警告信息", // 消息推动内容
"warnStyle": [ // 组件预警样式
{
"color": "#FFFFFF", // 预警时的文字颜色
"des": "文字颜色" // 对应预警的描述
},
{
"cellColor": "#FF171A",
"des": "单元格填充"
}
]
}
]
},
// weMax平台提供的公共插件 @aurora/wemax-card-plugin 已提供国际化组件I18nInput,可以直接引入使用,i18n配置如下:
"i18n": { // 国际化配置,不必填
"messages": {
"zh_CN": {
"cardTitle": "表格",
"rightTitle": ""
},
"en_US": {
"cardTitle": "WeMax table",
"rightTitle": ""
}
}
},
"isUsePager": false, // 是否使用分页
"pagerStyleConfig": { // 分页样式
"iconbtnColor": "#000000", // 翻页图标颜色
"pagerDataColor": "#000000" // 页签颜色
},
"cardTitle": { // 卡片标题
"isShow": true,
"contentConfig": true,
"textContent": "cardTitle",
"color": "transparent",
"themeColor": "var(--wemax-base-color-info-normal, #fff)",
"fontSize": 16,
"scale": true,
"fontWeight": 400
},
"rightTitle": { // 右侧标题
"isShow": false,
"contentConfig": true,
"textContent": "rightTitle",
"color": "transparent",
"themeColor": "var(--wemax-base-color-gray-normal, #999)",
"fontSize": 14,
"scale": true,
"fontWeight": 400
},
"sortConfig": { // 表格排序设置
"order": "", // 降序还是升序
"field": "" // 排序的列
},
"seqConfig": { // 第一列序号列配置
"name": "序号",
"show": true,
"backgroundColor": "transparent",
"scale": true,
"fontSize": 12,
"color": "transparent",
"themeColor": "var(--wemax-table-tbody-color, #ffffff)",
"fontWeight": 400,
"borderRadius": 10,
"size": 12,
"width": 10
},
"eventStyleConfig": { // 行样式
"isUsed": false, // 是否启用样式
"click": { // 点击时
"rowBgColor": "transparent", // 行背景颜色
"rowColor": "#ffffff", // 行字体颜色
"cellBgColor": "transparent", // 单元格背景颜色
"cellColor": "#ffffff" // 单元格字体颜色
},
"hover": { // 鼠标悬浮样式
"rowBgColor": "transparent",
"rowColor": "#ffffff",
"cellBgColor": "transparent",
"cellColor": "#ffffff"
}
},
"tableConfig": { // 表格外边距
"top": "0%",
"bottom": "0%",
"left": "1%",
"right": "1%"
},
"tableHeadConfig": { // 表头样式配置
"show": true,
"backgroundColor": "transparent",
"themeBgColor": "var(--wemax-table-thead-bg-color, #1C61C1)",
"gradientBackground": "",
"gradientFlag": false, // 开启渐变
"gradientDirection": 0, // 渐变角度
"gradientStartColor": "transparent",
"gradientStopColor": "transparent",
"fontSize": 12,
"color": "transparent",
"themeColor": "var(--wemax-table-thead-color, #ffffff)",
"scale": true,
"fontWeight": 400,
"height": 30,
"align": "center",
"borderWidth": 1,
"borderColor": "transparent",
"themeBorderColor": "var(--wemax-table-thead-border-color, #0C5092)",
"borderStyle": "solid",
"selfDefineHeads": [], // 自定义表头
"icon": {
"size": 16,
"color": "#ffffff"
}
},
"tableRowConfig": { // 行样式配置
"oddRowBackground": "transparent", // 奇数行背景色
"themeOddBgColor": "var(--wemax-table-tbody-odd-col-bg-color, #0E2B5A)",
"evenRowBackground": "transparent", // 偶数行背景色
"themeEvenBgColor": "var(--wemax-table-tbody-even-col-bg-color, #0F214E)",
"fontSize": 12,
"color": "transparent",
"themeColor": "var(--wemax-table-tbody-color, #ffffff)",
"scale": true,
"fontWeight": 400,
"height": 30,
"align": "center",
"borderWidth": 1,
"borderColor": "transparent",
"themeBorderColor": "var(--wemax-table-tbody-col-border-color, #0C5092)",
"borderStyle": "solid"
},
"columnSettings": [], // 列配置
"pageSize": 5, // 分页条数
"apis": [ // 组件数据接入配置,不必填,可配置多条
{
"id": "table-data", // 数据接入id, 同一组件内唯一
"name": "表格数据", // 数据接入名称
"title": "表格数据", // 数据接入名称
"showAggregation": true, // 是否展示聚合开关(用于数据模型方式接入)
"defaultAggregation": false, // 聚合开关(用于数据模型方式接入)
"type": "static", // 数据接入类型
"params": [], // 数据获取时查询参数
"supportTypes": ["static", "api"], // 默认支持的数据接入类型
"refreshSwitch": false, // 定时调度开关
"refreshTime": 60, // 定时调度时间
"isInItGetData": true, // 是否初始时请求表格数据
"isInitServeI18n": false, // 是否国际化
"fields": [ // 组件数据字段映射 -- 用于转换真实数据字段关联当前组件代码中使用字段
{
"id": "table-column-1", // 字段定义唯一标识
"field": "column1", // 字段名
"mapField": "", // 数据映射字段名, 如未选择默认取field字段
"desc": "列1", // 字段分类描述 列1
"type": "string", // 字段类型 string number
"category": "dimension" // 维度dimension/度量measure 用于数据模型接入时, 拖入字段类型识别
},
...... // 省略类似结构
{
"id": "table-column-20",
"field": "column20",
"mapField": "",
"desc": "列20",
"type": "string",
"category": "dimension"
}
],
"source": [ // 组件初始化静态数据, 自定义
{
"column1": 800,
"column2": "福州",
"column3": "2015-04-30 00:56:12",
"column4": "1"
},
...... // 省略类似结构
{
"column1": 952,
"column2": "上海",
"column3": "2018-04-30 00:56:13",
"column4": "8"
}
]
}
],
"cardEvents": [ // 组件交互配置,不必填,可配置多条
{
"name": "表格点击", // 交互事件名称
"id": "event-table-click", // 交互事件id, 同一组件内唯一
"variable": [ // 交互事件参数列表, 自定义字段名称/类型
{
"field": "column1", // 交互事件参数字段, 自定义
"type": "string" // 交互事件参数类型, 自定义
},
...... // 省略类似结构
{
"field": "column20",
"type": "string"
}
]
}
],
"eventConfig": { // 行点击是发送单元格的值还是行字段
"isPublishCellValue": true // 为true,表示发送单元格的值
},
"colHeads": [], // 列头配置
"rowConditions": [ // 给行设置条件,满足时触发样式
{
"bgColor": "transparent",
"color": "#ffffff",
"conditionArr": [ // 多个条件组成的数组
{
"logical": "&&", // 逻辑运算符
"colName": "", // 当前设置条件的列名
"operator": "=", // 比较运算符
"colVal": "" // 拿来比较的列的值
}
]
}
],
"columnConditionSetting": [] // 给列设置条件,满足时触发样式
}
},
"main": "./index.js", // 组件运行路径
"dnd": { // 组件拖入容器**初始化时默认大小**
"height": 12, // 高度
"width": 10, // 宽度
"minHeight": 12, // 最小高度
"minWidth": 8 // 最小宽度
}
}
# Card.vue规范
# html模板规范
<template>
<div class="wemax-component-container">
<div class="inner">
<CardTitle :options="options" />
<div
:style="[paddingStyl]"
class="table-wrapper"
>
<table
ref="wemaxTable"
v-clickoutside="handleOutsideClick"
class="wemax-table"
@mouseover="handleTableHover"
@mouseout="handleTableHoverEnd"
>
<thead
v-show="tableHeadConfig.show"
class="wemax-table-thead"
>
// 自定义表头
<tr
v-if="selfDefineHeads.length"
class="wemax-table-tr"
>
<th
v-show="seqConfig.show"
:style="[headerStyle, seqWidth]"
class="wemax-thead-th"
></th>
<th
v-for="(head, index) in selfDefineHeads"
:key="index"
:colspan="head.colspan"
:style="[headerStyle, getColColumnWidth(index, head)]"
class="wemax-thead-th"
>
{{ head.name }}
</th>
</tr>
// 表格数据的表头
<tr
v-if="tableColumns.length"
class="wemax-table-tr"
>
<th
v-show="seqConfig.show"
:style="[headerStyle, seqWidth]"
class="wemax-thead-th"
>
{{ seqConfig.name }}
</th>
<th
v-for="(item, index) in tableColumns"
:key="item.field + (Math.random() + 1)"
:style="[headerStyle, getColumnWidth(index)]"
class="table-head wemax-thead-th"
>
{{ getColumnName(index) }}
<sorter
v-show="getColumnSortable(index)"
v-if="!isSqlModel && hasTableData"
:sortObj="item"
:styleObj="tableHeadConfig"
class="head-sorter"
@setSort="
(obj) => {
getSortingData(obj, index)
}
"
>
</sorter>
</th>
</tr>
</thead>
// 表格主体
<tbody
class="wemax-table-tbody"
:style="tbodyStyle"
>
// 表格行
<tr
v-for="(data, index) in tableData"
:key="index + (Math.random() + 1)"
:style="[getRowBackground(index), getRowConditionStyle(data)]"
class="wemax-table-tbody-tr"
@click="setClickStyle($event)"
>
// 序号列
<td
v-show="seqConfig.show"
:style="[rowStyle, seqWidth]"
class="wemax-table-tbody-td-seq"
>
<span
:style="transStyleObj('seqConfig')"
class="wemax-table-sequence"
>{{ getSeq(index) }}</span>
</td>
// 数据列
<td
v-for="(item, colIndex) in tableColumns"
:key="item.field + (Math.random() + 1)"
:style="[rowStyle, getColumnWidth(colIndex), showAlarmStyle(index)]"
:field="item.field"
class="wemax-table-tbody-td"
@click="colClickStyle(data, item.field, colIndex)"
>
// 单元格
<conditioned-cell
:cellVal="data[item.field]"
:endUnit="getColumnEndUnit(colIndex)"
:field="item.field"
:type="getConditonType(item.field, data[item.field])"
:cellStyle="
getColConditionStyle(item.field, data[item.field])
"
@handleCellClick="
handleCellClick(item.field, data[item.field])
"
/>
</td>
</tr>
</tbody>
</table>
</div>
// 分页器
<TablePager
v-if="isUsePager"
:curPage="curPage"
:pageSize="pageSize"
:total="totalRows"
:options="options"
@pageSizeChange="currentChange"
/>
</div>
<TableDialog
ref="tableDialog"
:iframeUrl="iframeUrl"
/>
</div>
</template>
# js脚本规范
import cardMeta from './card.json'
import {
ApiMixin,
EventMixin,
ClickoutsideMixin,
Watcher
} from '@aurora/wemax-card-plugin' // 引入公共插件
import Sorter from './components/Sorter.vue'
import ConditionedCell from './components/ConditionedCell.vue'
import getDefaultColumnSetting from './static/columnConfig.js'
import TablePager from './components/TablePager.vue'
import TableDialog from './components/TableDialog.vue'
import _ from 'lodash'
import CardTitle from '@/components/CardTitle'
// 设计时和运行时watch分离
const watchers = {
apis: { // 组件数据监听, 包含定时调度设置
deep: true,
handler(val) {
if (val) {
this.fetchTableData() // 获取表格数据
const { refreshSwitch, refreshTime } = val[0]
this.isRefresh(this.fetchTableData, refreshSwitch, refreshTime)
}
}
}
}
const designWatchers = {
isUsePager(val, oldVal) { // 分页获取数据
if (val !== oldVal) {
this.berforeGetTableData()
}
},
'options.alarmMsgConfig': { // 预警配置有变化,将重新渲染表格
handler(val) {
this.berforeGetTableData()
},
deep: true
},
'options.pageSize'(val, oldVal) { // 分页条数有变化,重新获取数据
if (val !== oldVal) {
this.pageSize = val
this.curPage = 1
this.berforeGetTableData()
}
}
}
Watcher.init(watchers, designWatchers)
export default {
name: 'WeMaxTable',
components: {
Sorter,
ConditionedCell,
CardTitle,
TablePager,
TableDialog
},
mixins: [ApiMixin, EventMixin, ClickoutsideMixin], // 使用插件内混合方法
props: {
options: { // 固定使用方式
type: Object,
default: () => cardMeta.initProps.options
}
},
data() {
return {
tableColumns: [], // 包含每一列的映射字段、列名和排序标识
tableData: [], // 服务获取的表格数据
tableDataBackup: [], // 排序后的表格数据
curPage: 1, // 分页时的当前页码
totalRows: 0, // 数据总数目
pageSize: 10, // 每页的分页条目
curSortIndex: 0, // 当前使用排序的列索引
curClickTarget: null, // 当前点击目标
curHoverTarget: null, // 当前鼠标悬浮的目标
originalStyle: null, // 原始样式
fieldsObj: {}, // 列映射
rowItemObj: {},
iframeUrl: ''
}
},
computed: {
tbodyStyle() { // 表行样式
if (!this._isMounted) {
return
}
const { clientHeight } = this.$refs.wemaxTable
const { height } = this.tableHeadConfig
return {
height: clientHeight - height + 'px'
}
},
hasTableData() { // 表格是否有数据
return this.tableData && this.tableData.length && this.tableData.length > 1
},
seqConfig() {
return this.options.seqConfig
},
seqWidth() { // 序号列的宽度
const { width } = this.seqConfig
return {
width: width + '%'
}
},
apis() {
return this.options.apis // 组件服务数据配置
},
isUsePager() { // 是否使用分页
return this.options.isUsePager
},
tableHeadConfig() { // 表头配置
return this.options.tableHeadConfig
},
headerStyle() { // 表头样式
return {
...this.transStyleObj('tableHeadConfig'),
...this.getBorderStyle('tableHeadConfig')
}
},
rowStyle() { // 行样式
return {
...this.transStyleObj('tableRowConfig'),
...this.getBorderStyle('tableRowConfig')
}
},
paddingStyl() { // 页面内边距
const { top, bottom, left, right } = this.options.tableConfig
return {
'padding-top': top,
'padding-bottom': bottom,
'padding-left': left,
'padding-right': right
}
},
selfDefineHeads() { // 自定义列头
return this.tableHeadConfig.selfDefineHeads
},
selfDefineHeadsTotal() { // 自定义列头的总宽度
let total = 0
this.selfDefineHeads &&
this.selfDefineHeads.forEach((el) => {
total += el.colspan
})
return total
},
apiType() { // 第一个服务的数据接入类型
return this.apis[0].type
},
isSqlModel() { // 是否是sql模型
return this.apiType === 'sqlmodel'
},
columnSettings() { // 列配置,包含是否显示,分组列、排序、排名、列宽等功能
return this.options.columnSettings
}
},
watch: watchers,
created() {
this.pageSize = this.options.pageSize // 从配置项里得到分页条数
const { refreshSwitch, refreshTime, isInItGetData = null } = this.apis[0]
isInItGetData && this.fetchTableData() // 是否初始化时获取表格数据
this.isRefresh(this.fetchTableData, refreshSwitch, refreshTime)
if (Watcher.isDesignMode()) { // 组件修改属性时 添加防抖. 降低刷新频率
this.setColumnSettings = _.debounce(this.setColumnSettings, 300)
}
},
mounted() {
this.subscribe('variablesSubscribption') // 订阅全局变量
},
methods: {
/**
* @description 获取二级表头宽度
* @param {Number} index 列下标
* @param {Object} obj 配置项
* @returns {Object}
*/
getColColumnWidth(index, obj) {
const itemCol = this.columnSettings[index]
const styleObj = {
width: itemCol && itemCol.width + '%' // 初始默认列宽
}
let total = 0
for (let k = 0; k <= index; k++) { // 计算所有自定义列头所占的列数,colspan表示几列,默认是1,表示一列
total += this.selfDefineHeads[k].colspan
}
let totalWidth = 0
// 根据列数和列宽,计算该表头的宽度
this.columnSettings.forEach((el, inx) => {
if (inx >= total - obj.colspan && inx < total) {
totalWidth += el.width
}
})
styleObj.width = totalWidth + '%'
// 当自定义表头的总列数超过原有表头的列数时,样式不再变化
total >= this.columnSettings.length && (styleObj['flex-grow'] = 1)
return styleObj
},
/**
* @description 展示预警样式
* @param {Number } index 行的索引
*/
showAlarmStyle(index){
if(this.getAlertStyle && this.getAlertStyle[0]){ // getAlertStyle为插件中的方法,可得到满足alarmMsgConfig预警条件的表格行及该条件下对应的预警样式
const el = this.getAlertStyle && Object.values(this.getAlertStyle)[0] // 取出里面的预警对象el,包含index和style字段,index是一个满足预警条件的行索引的数组,style是该行对应的样式
if(el.index.includes(index)){ // 如果表格行在满足预警条件的索引数组中,则添加预警样式
const { color } = el.style[index].filter((item)=>item.color)[0] // 取出该行对应的预警样式
const { cellColor } = el.style[index].filter((item)=>item.cellColor)[0]
const obj = {
color,
"background-color": cellColor
}
return obj
}
}
},
/**
* @description 获取列宽度
* @param {Number} index 列下标
* @returns {Object}
*/
getColumnWidth(index) {
const itemCol = this.columnSettings[index]
const styleObj = {
width: itemCol && itemCol.width + '%' // 初始默认列宽
}
// 索引过界,样式不再变化
index + 1 === this.columnSettings.length && (styleObj['flex-grow'] = 1)
return styleObj
},
getColumnEndUnit(index) { // 从列配置项中获取单位
const itemCol = this.columnSettings[index]
return itemCol && itemCol.endUnit || ''
},
/**
* @description 获取列可排序设置参数
* @param {Number} index 列下标
* @returns {Boolean}
*/
getColumnSortable(index) { // 是否开启排序功能
const itemCol = this.columnSettings[index]
return itemCol ? itemCol.sortable : false
},
/**
* @description 获取列头名称
* @param {Number} index 列下标
* @returns {String}
*/
getColumnName(index) { // 从列配置项中获取列名
const itemCol = this.columnSettings[index]
const { title } = this.tableColumns[index]
const name = itemCol ? itemCol.name : ''
return this.apis[0].isInitServeI18n // 根据国际化场景显示
? this.$t(name || title)
: name || title
},
/**
* @description 获取条件类型,一共有text|progress|image三种
* @param {String} colName 添加条件的列名
* @param {String | Number} val 单元格的值
* @returns {String}
*/
getConditonType(colName, val) {
const conditions = this.options.columnConditionSetting
if (!conditions.length) {
return 'text' // 单元格内默认是文本格式
}
let conditionType = ''
const fitteds = conditions.filter((condition) => {
return condition.colName === colName // 根据列名定位到当前列
})
if (!fitteds.length) {
return 'text'
}
fitteds.forEach((fitObj) => {
const isSatisfied = this.checkColumnCondition(fitObj, val)
if (!isSatisfied) { // 判断该单元格是否满足条件
conditionType = 'text'
return
}
conditionType = fitObj.type
})
return conditionType
},
/**
* @description 点击事件,如果设置了列条件并且类型为link,点击会跳转
* @param {String} colName 列名
* @param {String} val 单元格的值
*/
handleCellClick(colName, val) {
const conditions = this.options.columnConditionSetting
if (!conditions.length) {
return
}
let res = null
const fitteds = conditions.filter((condition) => {
return condition.colName === colName // 根据列名定位到当前列
})
fitteds.forEach((fitObj) => {
const isSatisfied = this.checkColumnCondition(fitObj, val)
if (!isSatisfied) {
return // 当前值不满足条件,返回
}
res = fitObj
})
if (res.operator === '--') { // 运算符默认是--
res.colVal = val
}
if (res.type === 'link') { // 若列条件设置为a链接
this.openLink(res)
} else {
this.openDialogBox(res) // 否则是对话框
}
},
openDialogBox(obj) {
const { dialogUrl } = obj
if (!dialogUrl) {
return
}
this.iframeUrl = this.getOpenLinkUrl(obj)
this.$refs.tableDialog.openDialog() // 打开对话框
},
openLink(res) {
const { linkType, linkUrl } = res
if (linkType === 'none' || !linkUrl) {
return
}
const openLinkUrl = this.getOpenLinkUrl(res)
window.open(openLinkUrl, linkType) // 打开链接
},
getOpenLinkUrl(obj) { // 获取链接的url
const { type, linkUrl, dialogUrl, colName, colVal } = obj
const urlParam = `${colName}=${colVal}` // 默认将当前值作为url参数
let url = type === 'link' ? linkUrl : dialogUrl
url += (url.indexOf('?') === -1 ? '?' : '&') + urlParam
return url
},
/**
* @description 获取列条件配置中的样式
* @param {String} colName 列名
* @param {String | Number} val 单元格的值
* @returns {Object}
*/
getColConditionStyle(colName, val) {
const conditions = this.options.columnConditionSetting
if (!conditions.length) {
return
}
let res = null
const fitteds = conditions.filter((condition) => {
return condition.colName === colName
})
fitteds.forEach((fitObj) => {
const isSatisfied = this.checkColumnCondition(fitObj, val)
if (!isSatisfied) {
return
}
res = this.getFittedStyle(fitObj)
})
return res
},
/**
* @description 获取匹配的列条件样式
* @param {Object} fitObj 匹配的列条件配置对象
* @returns {Object}
*/
getFittedStyle(fitObj) {
let res = null
if (fitObj.type === 'text') {
res = this.transToTextStyle(fitObj)
} else if (fitObj.type === 'link' || fitObj.type === 'dialogBox') {
res = this.transToLinkStyle(fitObj)
} else if (fitObj.type === 'progress') {
res = this.transToProgressStyle(fitObj)
} else {
res = this.transToImageStyle(fitObj)
}
return res
},
/**
* @description 转换为进度条样式
* @param {Object} fitObj 匹配的列条件配置对象
* @returns {Object}
*/
transToProgressStyle(fitObj) {
const { progressWidth, progressLength, progressBg } = fitObj
return { progressWidth, progressLength, progressBg }
},
/**
* @description 转换为图片样式
* @param {Object} fitObj 匹配的列条件配置对象
* @returns {Object}
*/
transToImageStyle(fitObj) {
const { imageUrl, imageSize, borderRadius, position, hideText } = fitObj
return { imageUrl, imageSize, borderRadius, position, hideText }
},
/**
* @description 转换为文字样式
* @param {Object} fitObj 匹配的列条件配置对象
* @returns {Object}
*/
transToTextStyle(fitObj) {
const { color, fontSize, fontWeight, useUnderLine, useItalic } = fitObj
return {
color,
'font-size': fontSize + 'px',
'font-weight': fontWeight,
'text-decoration': useUnderLine ? 'underline' : 'unset',
'font-style': useItalic ? 'italic' : 'unset'
}
},
/**
* @description 转换为链接样式
* @param {Object} fitObj 匹配的列条件配置对象
* @returns {Object}
*/
transToLinkStyle(obj) {
const { color, fontSize, fontWeight, useItalic } = obj
return {
color,
'font-size': fontSize + 'px',
'font-weight': fontWeight,
'text-decoration': 'underline',
cursor: 'pointer',
'font-style': useItalic ? 'italic' : 'unset'
}
},
/**
* @description 将单元格的值与条件做比较,检测是否满足列条件
* @param {Object} condition 列条件对象
* @param {String | Number} columnVal 单元格的值
* @returns {Boolean}
*/
checkColumnCondition(condition, columnVal) {
let result = false
const { operator, colVal } = condition // 从条件配置中取出运算符和被比较的列值
const checkVal = String(columnVal)
if (checkVal) {
switch (operator) {
case '>':
result = checkVal > colVal
break
case '>=':
result = checkVal >= colVal
break
case '!=':
result = checkVal != colVal
break
case '<=':
result = checkVal <= colVal
break
case '<':
result = checkVal < colVal
break
case '=':
result = checkVal === colVal
break
default:
result = true
break
}
}
return result
},
/**
* @description 获取行条件配置样式
* @param {Object} rowData 行的值
* @returns {Object}
*/
getRowConditionStyle(rowData) {
const fitIndex = this.getFitConditionIndex(rowData)
const fitCondition = this.options.rowConditions[fitIndex]
if (fitCondition) {
const { bgColor, color } = fitCondition
return {
'background-color': bgColor,
color: color
}
}
},
/**
* @description 获取匹配条件的行下标
* @param {Object} rowVal 行值
* @returns {Number}
*/
getFitConditionIndex(rowVal) {
let fitIndex = -1
const { rowConditions } = this.options
for (let i = 0, len = rowConditions.length; i < len; i++) {
const { conditionArr } = rowConditions[i]
const isSatisfied = this.checkRowConditions(conditionArr, rowVal)
if (isSatisfied) {
fitIndex = i
break
}
}
return fitIndex
},
/**
* @description 获取匹配条件的行下标
* @param {Array} conditions 行条件数组
* @param {Object} rowVal 单元格的值
* @returns {boolean}
*/
checkRowConditions(conditions, rowVal) {
let isFitted = true
if (!conditions.length) {
return !isFitted
}
conditions.forEach((item) => { // 分别比较该行中选中的几列是否符合条件,再将结果进行逻辑与、或
const { colName, operator, colVal, logical } = item
const stringedVal = String(rowVal[colName])
const isOk = this.checkItemCondition(stringedVal, operator, colVal)
isFitted = this.getFittedByLogical(logical, isFitted, isOk)
})
return isFitted
},
// 将每个列是否满足条件的结果进行逻辑与、或,得到该行是否满足条件
getFittedByLogical(logical, boolVal1, boolVal2) {
switch (logical) {
case '&&':
return boolVal1 && boolVal2
case '||':
return boolVal1 || boolVal2
default:
return false
}
},
/**
* @description 将单元格的值与条件做比较,检测是否满足列条件
* @param {String | Number} realVal 单元格的值
* @param {String | Number} operator 运算符
* @param {String | Number} conditionVal 条件中要比较的值
* @returns {Boolean}
*/
checkItemCondition(realVal, operator, conditionVal) {
let result = true
switch (operator) {
case '>':
result = realVal > conditionVal
break
case '>=':
result = realVal >= conditionVal
break
case '!=':
result = realVal != conditionVal
break
case '<=':
result = realVal <= conditionVal
break
case '<':
result = realVal < conditionVal
break
default:
result = realVal === conditionVal
break
}
return result
},
/**
* @description 表格外点击处理
*/
handleOutsideClick() {
this.removePreTargetStyle() // 去除上一个被点击dom元素的事件样式
this.removePreHoverTargetStyle() // 去除上一个被hover的dom元素的事件样式
},
/**
* @description 获取第一列-序列号
* @param {Number} index 列数据下标
*/
getSeq(index) {
return index + 1 + (this.curPage - 1) * this.pageSize
},
/**
* @description 点击发送表格单元格或者行字段
* @param {Object} event 点击事件对象
*/
publishValue(event) {
const isSeqCell = this.hasClassName( // 序号列的类名
event.target,
'wemax-table-tbody-td-seq'
)
const isCell = this.hasClassName(event.target, 'conditioned-cell') // 单元格的类名
const { isPublishCellValue } = this.options.eventConfig
// 当点击了序号列或者不在单元格中点击,则返回
if (isSeqCell && isPublishCellValue || !isCell) {
return
}
const publishParam = this.getPublishParam(event) // 获取发送参数
this.publishEvent(publishParam) // 发布消息
},
/**
* @description 获取发送参数
* @param {Object} event 点击事件对象
* @returns {Object}
*/
getPublishParam(event) {
const { isPublishCellValue } = this.options.eventConfig
const realTarget = isPublishCellValue
? event.target // 行的类名
: this.filterDomFromPath(this.getPath(event), 'wemax-table-tbody-tr')
const cardEvent = this.options.cardEvents[0] // 对应json文件中第一个事件(表格点击)
return {
i: this.options.i || '', // 组件唯一标识i
id: cardEvent.id, // 交互唯一标识id
screenId: this.options.screenId || '',
param: this.getParam(realTarget), // 具体交互参数
interactionList: this.options.interactionList || [] // 独立运行wemax卡片交互必传参数
}
},
/**
* @description 获取点击事件对象中path字段
* event.composedPath是为了兼容firefox与safari浏览器
* @param {Object} event 点击事件对象
*/
getPath(event) {
return event.path || event.composedPath && event.composedPath()
},
/**
* @description 从点击事件对象path字段中获取具有className的dom元素
* @param {Array} path 点击事件对象中的path字段
* @param {String} className 类名
* @returns {Object}
*/
filterDomFromPath(path, className) {
let targetDom = null
if (!className) {
return
}
for (let i = 0, len = path.length; i < len; i++) {
const dom = path[i]
if (!dom.className) {
continue
}
if (this.hasClassName(dom, className)) {
targetDom = dom
break
}
}
return targetDom
},
/**
* @description 获取param字段的值
* @param {Object}
*/
getParam(target) {
const { isPublishCellValue } = this.options.eventConfig
if (isPublishCellValue) {
return this.getCellParam(target) // 得到单元格的参数
}
return this.getRowParam(target) // 得到行的参数
},
/**
* @description 获取单元格中的值
* @param {Object} target 单元格dom元素对象
* @returns {Object}
*/
getCellParam(target) {
const targetField = target.getAttribute('field')
const targetVal = target.innerText
let valField = ''
Object.keys(this.fieldsObj).forEach((key) => {
// key为initprops内的options中定义的apis中的fields字段的值,如column1
const tempField = this.fieldsObj[key]
if (targetField && tempField === targetField) {
valField = key
}
})
return { [valField]: targetVal }
},
/**
* @description 获取行中的值
* @param {Object} target 行dom元素对象
* @returns {Object}
*/
getRowParam(rowEl) {
const res = {}
const cellArr = Array.prototype.slice.call(rowEl.children)
cellArr.forEach((cell) => {
if (this.hasClassName(cell, 'wemax-table-tbody-td-seq')) {
return
}
Object.assign(res, this.getCellParam(cell)) // 将每个单元格的值拼成一个对象
})
return res
},
/**
* @description 表格点击发布事件
* @param {String} value 发布消息数据
*/
publishEvent(param) {
this.$service.message.publish({ // 发送message消息
topic: 'cardEventDistribution', // message消息名称 -- 固定值, 不可修改
data: param // 消息参数,按照实际情况修改
})
},
/**
* @description 设置点击后效果
* @param {Object} event 事件对象
*/
setClickStyle(event) {
if (!this.options.eventStyleConfig.isUsed) {
return // 是否启用了事件效果的开关
}
this.removePreHoverTargetStyle() // 去除上一个被hover的dom元素的事件样式
const clickTarget = this.filterDomFromPath( // 从点击事件对象path字段中获取行的列元素
this.getPath(event),
'wemax-table-tbody-td'
)
if (this.curClickTarget === clickTarget) {
return
}
if (this.curClickTarget !== clickTarget) {
this.removePreTargetStyle() // 去除上一个被点击dom元素的事件样式
}
this.setClickTargetStyle(event) // 否则去设置该dom元素的事件样式
},
/**
* @description 列点击事件
* @param {Object} rowObj 行数据
* @param {Object} field 服务中映射的字段名,这里就是列名
* @param {Number} index 列索引
*/
colClickStyle(rowObj, field, index) {
const { isPublishCellValue } = this.options.eventConfig // 从options设置中确定当前点击是行点击还是单元格点击
const cardEvent = this.options.cardEvents[0]
let param = {}
if (isPublishCellValue) { // 如果是单元格点击
param = {
[cardEvent.variable[index].field]: rowObj[field] // 将当前单元格的值传给事件变量
}
} else { // 否则是行点击,将整行的值都传过去
Object.values(rowObj).forEach((el, index) => {
param[cardEvent.variable[index].field] = el
})
}
const publishParam = {
i: this.options.i || '', // 组件唯一标识i -- 固定值, 不可修改
id: cardEvent.id, // 交互唯一标识id
param: param,
screenId: this.options.screenId || '',
interactionList: this.options.interactionList || [] // 独立运行wemax卡片交互必传参数
}
this.publishEvent(publishParam) // 发送消息
},
/**
* @description 判断dom元素是否具有某个类名
* @param {Object} target dom元素
* @param {String} name 类名
* @returns {Boolean}
*/
hasClassName(target, name) {
return target.className && target.className.indexOf(name) !== -1
},
/**
* @description 设置被点击对象的样式
* @param {Object} event 点击事件对象
*/
setClickTargetStyle(event) {
const { rowBgColor, rowColor, cellBgColor, cellColor } =
this.options.eventStyleConfig.click
const parentEl = this.filterDomFromPath(
this.getPath(event),
'wemax-table-tbody-tr'
)
const realTarget = this.filterDomFromPath(
this.getPath(event),
'wemax-table-tbody-td'
)
this.saveOriStyle(realTarget, parentEl)
realTarget.style.backgroundColor = cellBgColor
realTarget.style.color = cellColor
parentEl.style.backgroundColor = rowBgColor
parentEl.style.color = rowColor
this.curClickTarget = realTarget
},
/**
* @description 缓存样式
* @param {Object} 点击或hover事件对象
* @param {Object} 点击或hover事件对象的父级dome元素
*/
saveOriStyle(target, parentEl) {
this.originalStyle = {
targetBgColor: target.style.backgroundColor,
targetColor: target.style.color,
parentBgColor: parentEl.style.backgroundColor,
parentColor: parentEl.style.color
}
},
/**
* @description 去除上一个被点击dom元素的事件样式
*/
removePreTargetStyle() {
if (!this.curClickTarget) {
return
}
const { targetBgColor, targetColor, parentBgColor, parentColor } =
this.originalStyle
this.curClickTarget.style.backgroundColor = targetBgColor
this.curClickTarget.style.color = targetColor
this.curClickTarget.parentElement.style.backgroundColor = parentBgColor
this.curClickTarget.parentElement.style.color = parentColor
this.curClickTarget = null
},
/**
* @description 去除上一个被hover的dom元素的事件样式
*/
removePreHoverTargetStyle() {
if (!this.curHoverTarget) {
return
}
const { targetBgColor, targetColor, parentBgColor, parentColor } =
this.originalStyle
this.curHoverTarget.style.backgroundColor = targetBgColor
this.curHoverTarget.style.color = targetColor
this.curHoverTarget.parentElement.style.backgroundColor = parentBgColor
this.curHoverTarget.parentElement.style.color = parentColor
this.curHoverTarget = null
},
/**
* @description 表格的mouseout事件处理回调方法
* @param {Obejct} event mouseout事件对象
*/
handleTableHoverEnd(event) {
this.removePreHoverTargetStyle()
},
/**
* @description 表格的mouseover事件处理回调方法
* @param {Object} event mouseover事件对象
*/
handleTableHover(event) {
if (!this.options.eventStyleConfig.isUsed) {
return
}
const hoverTarget = this.filterDomFromPath(
this.getPath(event),
'wemax-table-tbody-td'
)
if (this.curHoverTarget === hoverTarget) {
return
}
if (this.curHoverTarget !== hoverTarget) {
this.removePreHoverTargetStyle()
}
this.setHoverTargetStyle(event)
},
/**
* @description 设置被hover元素效果样式
* @param {Object} event hover事件对象
*/
setHoverTargetStyle(event) {
const { rowBgColor, rowColor, cellBgColor, cellColor } =
this.options.eventStyleConfig.hover
const parentEl = this.filterDomFromPath(
this.getPath(event),
'wemax-table-tbody-tr'
)
const realTarget = this.filterDomFromPath(
this.getPath(event),
'wemax-table-tbody-td'
)
this.saveOriStyle(realTarget, parentEl)
realTarget.style.backgroundColor = cellBgColor
realTarget.style.color = cellColor
parentEl.style.backgroundColor = rowBgColor
parentEl.style.color = rowColor
this.curHoverTarget = realTarget
},
/**
* @description 订阅消息
* @param {String} topic 被订阅的消息名称
*/
subscribe(topic) {
this.subscribeMessageFun(topic, (msgData) => {
if (topic === 'variablesSubscribption') {
this.handlerSubscribeMsg(msgData, this.options.apis)
}
})
},
/**
* @description sorter组件向上emit的setSort事件
* @param {Object} sortObj 排序对象
* @param {Number} index 排序字段下标
*/
getSortingData(sortObj, index) {
this.options.sortConfig = sortObj
this.curSortIndex = index
this.berforeGetTableData()
},
/**
* @description 设置边框样式
* @param {String} type 设置类型
* @returns {Object}
*/
getBorderStyle(type) {
const { borderWidth, borderColor, themeBorderColor, borderStyle } = this.options[type]
return {
'border-width': borderWidth + 'px',
'border-color':
borderColor === 'transparent' ? themeBorderColor : borderColor,
'border-style': borderStyle
}
},
/**
* @description 设置奇偶行背景色
* @param {Number} index 行下标
* @returns {Object}
*/
getRowBackground(index) {
const rowIndex = index + 1
const isEvenCol = rowIndex % 2 === 0
const colBgColor = isEvenCol
? this.getEvenColBgColor()
: this.getOddColBgColor()
return {
'background-color': colBgColor
}
},
getEvenColBgColor() {
const { evenRowBackground, themeEvenBgColor } =
this.options.tableRowConfig
return evenRowBackground === 'transparent'
? themeEvenBgColor
: evenRowBackground
},
getOddColBgColor() {
const { oddRowBackground, themeOddBgColor } = this.options.tableRowConfig
return oddRowBackground === 'transparent'
? themeOddBgColor
: oddRowBackground
},
/**
* @description 转换样式对象
* @param {String} type 要转换的类型
* @returns {Object}
*/
transStyleObj(type) {
return {}
},
getBgColor(type) {
const { backgroundColor, themeBgColor } = this.options[type]
if (!backgroundColor) {
return
}
return backgroundColor === 'transparent' ? themeBgColor : backgroundColor
},
/**
* @description 页码改变
* @param {Number} val 当前页码
*/
currentChange(val) {
this.curPage = val
this.berforeGetTableData()
},
/**
* @description 表格排序
* @param {Array} data 需要排序的数据
* @returns {Array}
*/
sortData(data) {
if (!data || data.length === 0) {
return []
}
const { order, field } = this.options.sortConfig
if (!field || !order) {
return data
}
const filterWord = this.getFilterWord(field)
data.sort(function (a, b) {
if (order === 'asc') {
return a[filterWord] > b[filterWord] ? 1 : -1
}
return b[filterWord] > a[filterWord] ? 1 : -1
})
return data
},
/**
* @description 获取排序的表头名称
* @param {String} field 排序字段
* @returns {String}
*/
getFilterWord(field) {
const filtered = this.tableColumns.filter((column) => {
return column.title.indexOf(field) > -1
})[0]
return filtered ? filtered.field : ''
},
berforeGetTableData() {
// 设计时或者sql模型
if (Watcher.isDesignMode() || this.isSqlModel) {
this.fetchTableData()
return
}
// 静态 rest 类型 使用了分页
if (this.isUsePager) {
this.setTableColumns()
const sortData = this.sortData(this.tableDataBackup)
this.tableData = this.getResultByPager(sortData)
return
}
this.fetchTableData() // 获取数据
},
/**
* @description 获取新的apis配置对象
* @returns {Object}
*/
getNewApis() {
const newApis = _.cloneDeep(this.apis)
if (this.isUsePager) {
// returnAll设置为true 让sql模型返回分页字段pageVO
newApis[0].returnAll = true
newApis[0].source.pager = {
curPage: this.curPage,
pageSize: this.pageSize
}
}
return newApis
},
/**
* @description 获取服务数据
* @param {Object} apis apis配置对象
* @param {Function} callBack 回调函数
*/
fetchTableData() {
const apis = this.isSqlModel ? this.getNewApis() : this.apis
this.getData(apis, res => {
this.getAlarmStatus(res.tableData)
const type = Object.prototype.toString.call(res).slice(8, -1)
if (type === 'Object') {
this.totalRows = res.totalRows
if (this.isSqlModel) {
this.tableData = res.tableData
return
}
const sortData = this.sortData(res.tableData)
this.tableDataBackup = sortData
this.tableData = this.getResultByPager(sortData)
return
}
this.tableData = []
})
},
/**
* @description 获取分页之后的数据
* @param {Array} data 原始数据
* @returns {Array}
*/
getResultByPager(data) {
const offset = (this.curPage - 1) * this.pageSize
return this.isUsePager ? data.slice(offset, offset + this.pageSize) : data
},
/**
* @description 通过数据映射构建各个系列所需要的数据
* @param {Array|Object} data 需要进行数据映射处理的原始数据
* @param {Object} fields 数据源中fields对象
* @returns {Array}
*/
buildSeriesData(res, fields, isInitServeI18n) {
let data = res
if (this.isSqlModel && this.isUsePager) {
this.totalRows = res.pageVO.totalRows || 0
data = res.result
}
const fieldsObj = this.getFieldMap(fields)
let datas = []
if (Array.isArray(data) && data.length) {
datas = data.map(item => {
return this.buildNewData(item, fieldsObj)
})
this.rowItemObj = datas[0] || {}
this.fieldsObj = fieldsObj
this.setTableColumns()
this.setColHeads()
this.setColumnSettings()
}
return {
totalRows: this.isSqlModel && this.isUsePager ? res.pageVO.totalRows || 0 : datas.length,
tableData: datas
}
},
buildNewData(item, fieldsObj) {
const newItem = {}
Object.keys(fieldsObj).forEach((key) => {
const realKey = fieldsObj[key]
const hasKey = Object.prototype.hasOwnProperty.call(item, realKey)
if (hasKey) {
newItem[realKey] = item[realKey]
}
})
return newItem
},
/**
* 设置表格列配置项,包括标题、映射后的字段、排序标识
*/
setTableColumns() {
const res = []
Object.keys(this.fieldsObj).forEach((key) => {
const realKey = this.fieldsObj[key]
const hasKey =
realKey !== key || Object.prototype.hasOwnProperty.call(this.rowItemObj, key)
if (hasKey) {
res.push({
title: realKey,
field: realKey,
order: this.getOrder(realKey)
})
}
})
this.tableColumns = res
},
/**
* 从行数据里拿到映射的列名
*/
setColHeads() {
this.options.colHeads = Object.keys(this.rowItemObj).map((key) => {
return {
text: key,
value: key
}
})
},
/**
* @description 配置列设置columnSettings的值
*/
setColumnSettings() {
const list = []
const { columnSettings } = this.options
this.tableColumns.forEach((col, index) => {
const defaultConf = getDefaultColumnSetting() // 获取一部分默认的配置项
const curConfig = columnSettings.length && columnSettings[index]
defaultConf.name = col.field
if (curConfig) {
Object.assign(defaultConf, curConfig) // 若有配置项,则覆盖默认的
}
list.push(defaultConf)
})
this.options.columnSettings = list
},
/**
* @description 获取列头排序类型
* @param {String} name 列名
* @returns {String}
*/
getOrder(name) {
const { field, order } = this.options.sortConfig
return name === field ? order : ''
}
}
}
# 配置项详解
下面根据面板配置项来专项讲解表格,表格面板配置项跟图表类有相似之处,其中的数据服务、属性配置中的标题和全局都很类似,因此下面重点讲解不同之处
# 行--表头
表格组件的表头配置项是TableHeadConfig.vue文件,
<template>
<aui-form> // 表单组件
<aui-form-item label="显示"> // 表单项
// 复选框
<aui-checkbox v-model="options.tableHeadConfig.show"></aui-checkbox>
</aui-form-item>
<aui-form-item label="背景颜色">
// 颜色选择器
<color-picker
v-if="!gradientFlag"
v-model="options.tableHeadConfig.backgroundColor"
:color="options.tableHeadConfig.backgroundColor"
></color-picker>
</aui-form-item>
// 渐变组件,包含渐变角度、起始颜色、结束颜色
<GradientConfig
:data="options.tableHeadConfig"
:isChartGradient="false"
defaultBgColorField="gradientBackground"></GradientConfig>
<aui-form-item label="行高">
// 计数器
<aui-numeric
v-model="options.tableHeadConfig.height"
:min="0"
:max="100"
size="normal"
>
</aui-numeric>
</aui-form-item>
<aui-form-item label="水平对齐">
// 下拉选择器
<aui-select
v-model="options.tableHeadConfig.align">
<aui-option
v-for="item in alignList"
:key="item.value"
:label="item.text"
:value="item.value"
></aui-option>
</aui-select>
</aui-form-item>
// 通用字体设置组件,包含字号同步、字号大小、字体颜色、字体粗细
<FontConfig :options="options.tableHeadConfig" />
// 通用边框组件,包括边框宽度、边框颜色、边框样式
<BorderConfig :options="options.tableHeadConfig" />
<div class="wemax-config-subtitle">排序图标</div>
// 排序图标组件,包括排序图标的尺寸和颜色
<IconConfig :options="options.tableHeadConfig" />
</aui-form>
</template>
<script>
import { Form, FormItem, Checkbox, Select, Option, Numeric } from '@aurora/vue' // 引入AUI组件
import BorderConfig from '../BorderConfig' // 边框设置
import FontConfig from '../FontConfig.vue' // 字体设置
import IconConfig from './IconConfig.vue' // 图标设置
import GradientConfig from '@/components/echarts/GradientConfig' // 渐变设置
import { ColorPicker } from '@aurora/wemax-card-plugin' // 颜色选择器
export default {
name: 'TableHeadConfig',
components: {
AuiForm: Form,
AuiFormItem: FormItem,
AuiCheckbox: Checkbox,
AuiSelect: Select,
AuiOption: Option,
AuiNumeric: Numeric,
ColorPicker,
BorderConfig,
FontConfig,
GradientConfig,
IconConfig
},
props: {
options: Object
},
data() {
return {
alignList: [ // 水平对齐方式
{ text: '左对齐', value: 'left' },
{ text: '居中', value: 'center' },
{ text: '右对齐', value: 'right' }
]
}
},
computed: {
gradientFlag: { // 控制背景颜色的显隐,如果开启了渐变开关,则需关闭背景颜色选择器,防止两者冲突
get() {
return this.options.tableHeadConfig.gradientFlag
}
}
}
}
</script>
<style lang="less" scoped>
.wemax-config-subtitle {
font-weight: bold;
font-size: 14px;
margin-bottom: 0.3rem;
}
</style>
# 行-表行
表行配置项对应的组件为TableRowConfig.vue文件,由于该面板和表头的面板大为相似,因此不做重复讲解,重点讲解一下添加行条件这个配置项,该项对应的文件为RowConditionConfig.vue
<template>
<div>
<AuiButton @click="showConditionPanel">添加行条件</AuiButton>
<RowConditionPanel :isShow="isShowPanel" :options="options" @closePanel="closeConditionPanel"></RowConditionPanel>
</div>
</template>
该文件中引入按钮组件AuiButton和条件面板组件RowConditionPanel,接下来讲解后者
代码如下。
<template>
// aui弹框组件
<aui-dialog-box
v-model="showDialog"
draggable
title="新增行条件"
:close-on-click-modal="false"
width="950px"
class="rowConditionDialog"
>
// 页签组件,可新增多个条件
<aui-tabs
v-if="rowConditionList.length"
v-model="activeName"
:with-add="true"
:with-close="true"
@add="addCondition"
@close="deleteCondition"
>
// 每个页签项的配置
<aui-tab-item
v-for="(item, index) in rowConditionList"
:key="index"
:title="'条件' + (index + 1)"
:name="String(index)"
>
// 行条件配置组件
<RowConditions
:rowTabConditionObj="item"
:colHeads="colHeads"
>
</RowConditions>
</aui-tab-item>
</aui-tabs>
<template #footer> // 底部的确认和取消按钮
<aui-button @click="showDialog = false">取消</aui-button>
<aui-button
type="primary"
@click="setRowConditions"
>确定</aui-button>
</template>
</aui-dialog-box>
</template>
点击添加行条件,弹出如下面板,该面板展示的条件为:当column1的值等于800并且column2的值等600时,这一行的文字颜色为#ffffff,背景颜色为transparent,该样式可以自行设置。
,
具体行条件配置的代码如下
<template>
<div class="condition-row">
<div class="item-condition-col handle-icons">
// 对应上图左边的加号图标,可新加条件
<IconPlusCircle
class="aui-svg-icon icon-plus-circle"
@click="addRow"
></IconPlusCircle>
// 对应上图左边的减号图标,可删除条件
<IconMinusCircle
class="aui-svg-icon icon-minus-circle"
@click="deleteRow"
></IconMinusCircle>
</div>
<div class="item-condition-col relation">
// 一个值不存在逻辑运算,需两个及以上
<aui-select
v-show="criteriaIndex !== 0"
v-model="conditionItem.logical"
>
// 条件的逻辑运算,包括与、或
<aui-option
v-for="item in logicalOp"
:key="item.value"
:label="item.label"
:value="item.value"
>
</aui-option>
</aui-select>
</div>
<div class="item-condition-col filedName">
<aui-select
v-model="conditionItem.colName"
filterable
>
// 在字段中选择列名
<aui-option
v-for="item in colHeads"
:key="item.value"
:label="item.label"
:value="item.value"
>
</aui-option>
</aui-select>
</div>
<div class="item-condition-col operation-symbol">
<aui-select
v-model="conditionItem.operator"
filterable
>
// 运算符,包括大于、等于、小于等常用运算符
<aui-option
v-for="item in operators"
:key="item.value"
:label="item.text"
:value="item.value"
>
</aui-option>
</aui-select>
</div>
<div class="item-condition-col operation-value">
// 输入框组件,输入一个值与列值进行比较
<aui-input
v-model="conditionItemValue"
clearable
></aui-input>
</div>
// 只当第一个条件生成时才出现颜色选择器,最终颜色由多个条件进行逻辑运算后决定
<div class="item-condition-col text-color">
// 文字颜色选择器
<color-picker
v-if="criteriaIndex === 0"
v-model="rowTabConditionObj.color"
:color="rowTabConditionObj.color"
></color-picker>
</div>
<div class="item-condition-col background-color">
// 背景颜色选择器
<color-picker
v-if="criteriaIndex === 0"
v-model="rowTabConditionObj.bgColor"
:color="rowTabConditionObj.bgColor"
></color-picker>
</div>
</div>
</template>
<script>
import { Select, Option, Input } from '@aurora/vue' // 引入aui组件
import { IconPlusCircle, IconMinusCircle } from '@aurora/vue-icon' // 引入加号、减号图标
import { ColorPicker, $xss } from '@aurora/wemax-card-plugin' // 引入颜色选择器以及XSS攻击输出控制
export default {
name: 'RowConditionItem',
components: {
AuiSelect: Select,
AuiOption: Option,
AuiInput: Input,
IconPlusCircle: IconPlusCircle(),
IconMinusCircle: IconMinusCircle(),
ColorPicker
},
props: {
conditionItem: Object,
rowTabConditionObj: Object,
colHeads: Array,
criteriaIndex: {
type: Number,
default: -1
}
},
data() {
return {
logicalOp: [ // 逻辑运算符,用于各个条件间的运算
{ label: '与', value: '&&' },
{ label: '或', value: '||' }
],
operators: [ // 运算符,用于判断输入的值与列值的比较关系
{
text: '大于', value: '>'
},
{
text: '大于等于', value: '>='
},
{
text: '等于', value: '='
},
{
text: '小于等于', value: '<='
},
{
text: '小于', value: '<'
},
{
text: '不等于', value: '!='
}
]
}
},
computed: {
conditionItemValue: {
get() {
return this.conditionItem.colVal
},
set(val) {
this.conditionItem.colVal = $xss.process(val)
}
}
},
methods: {
/**
* @description 新增行
*/
addRow() {
this.$emit('addRow', this.criteriaIndex)
},
/**
* @description 移除行
*/
deleteRow() {
this.$emit('deleteRow', this.criteriaIndex)
}
}
}
</script>
# 行-触发样式
行的触发样式配置面板如下
(1)当点击表格时,提供了两种选择,一种是可发送单元格的值,另一种点击可发送一整行的值。具体区别体现在:当在WeMax平台上选择交互选项时,若选择了前者,则当点击第二列的某一单元格时,就只有column2变量会有值,其他变量为空;若选择发送一整行的值时,当点击第二列的某一单元格时,则下图存在的column系列变量都会接收到值。
(2)事件效果的开关默认关闭,当打开该开关时,此时表格点击或者划过便会出现背景颜色和文字颜色的变化,文件为EventStyleConfig.vue,如下为鼠标滑过单元格的效果图
代码如下
<template>
<aui-form>
<aui-form-item size="mini">
<template #label>
<span>启用</span>
</template>
<aui-switch v-model="options.eventStyleConfig.isUsed"></aui-switch>
</aui-form-item>
<div v-if="options.eventStyleConfig.isUsed">
<div class="wemax-config-subtitle">行点击效果</div>
<aui-form-item label="背景颜色">
<color-picker
v-model="options.eventStyleConfig.click.rowBgColor"
:color="options.eventStyleConfig.click.rowBgColor"
>
</color-picker>
</aui-form-item>
<aui-form-item label="字体颜色">
<color-picker
v-model="options.eventStyleConfig.click.rowColor"
:color="options.eventStyleConfig.click.rowColor"
>
</color-picker>
</aui-form-item>
<div class="wemax-config-subtitle">单元格点击效果</div>
<aui-form-item label="背景颜色">
<color-picker
v-model="options.eventStyleConfig.click.cellBgColor"
:color="options.eventStyleConfig.click.cellBgColor"
>
</color-picker>
</aui-form-item>
<aui-form-item label="字体颜色">
<color-picker
v-model="options.eventStyleConfig.click.cellColor"
:color="options.eventStyleConfig.click.cellColor"
>
</color-picker>
</aui-form-item>
<div class="wemax-config-subtitle">行滑过效果</div>
<aui-form-item label="背景颜色">
<color-picker
v-model="options.eventStyleConfig.hover.rowBgColor"
:color="options.eventStyleConfig.hover.rowBgColor"
>
</color-picker>
</aui-form-item>
<aui-form-item label="字体颜色">
<color-picker
v-model="options.eventStyleConfig.hover.rowColor"
:color="options.eventStyleConfig.hover.rowColor"
>
</color-picker>
</aui-form-item>
<div class="wemax-config-subtitle">单元格滑过效果</div>
<aui-form-item label="背景颜色">
<color-picker
v-model="options.eventStyleConfig.hover.cellBgColor"
:color="options.eventStyleConfig.hover.cellBgColor"
>
</color-picker>
</aui-form-item>
<aui-form-item label="字体颜色">
<color-picker
v-model="options.eventStyleConfig.hover.cellColor"
:color="options.eventStyleConfig.hover.cellColor"
>
</color-picker>
</aui-form-item>
</div>
</aui-form>
</template>
<script>
import { Form, FormItem, Switch } from '@aurora/vue'
import { ColorPicker } from '@aurora/wemax-card-plugin'
export default {
name: 'EventStyleConfig',
components: {
AuiForm: Form,
AuiFormItem: FormItem,
AuiSwitch: Switch,
ColorPicker
},
props: {
options: Object
}
}
</script>
<style lang="less" scoped>
.wemax-config-subtitle {
font-weight: bold;
font-size: 14px;
margin-bottom: 0.3rem;
&:not(:first-child) {
margin-top: 0.8rem;
}
}
</style>
相关的card.json配置如下
"eventStyleConfig": {
"isUsed": false,
"click": {
"rowBgColor": "transparent",
"rowColor": "#ffffff",
"cellBgColor": "transparent",
"cellColor": "#ffffff"
},
"hover": {
"rowBgColor": "transparent",
"rowColor": "#ffffff",
"cellBgColor": "transparent",
"cellColor": "#ffffff"
}
},
card.vue中,hover状态的样式代码如下
/**
* @description 设置被hover元素效果样式
* @param {Object} event hover事件对象
*/
setHoverTargetStyle(event) {
const { rowBgColor, rowColor, cellBgColor, cellColor } =
this.options.eventStyleConfig.hover // 从option配置项中得到hover状态的样式字段
// 获取点击事件所在的行
const parentEl = this.filterDomFromPath(
this.getPath(event),
'wemax-table-tbody-tr'
)
// 获取点击事件所在的单元格
const realTarget = this.filterDomFromPath(
this.getPath(event),
'wemax-table-tbody-td'
)
this.saveOriStyle(realTarget, parentEl) // 保存原始的样式
// 设置hover样式
realTarget.style.backgroundColor = cellBgColor
realTarget.style.color = cellColor
parentEl.style.backgroundColor = rowBgColor
parentEl.style.color = rowColor
this.curHoverTarget = realTarget // 保存当前事件所在的单元格
},
# 列-基础
列配置项的基础栏包括序号以及各列具体的配置,包括修改列名、列宽,显示或隐藏该列等。文件为ColumnSettingItem.vue
代码为
<template>
<div>
// 序号列不用排序
<aui-form-item
v-if="hasSortableAttr"
label="可排序"
>
</aui-checkbox>
</aui-form-item>
<aui-form-item label="列名">
<aui-input
v-model="columnName"
type="text"
>
</aui-input>
</aui-form-item>
<aui-form-item
v-if="notSeqCol"
label="后缀"
>
<aui-input
v-model="endUnit"
type="text"
>
</aui-input>
</aui-form-item>
<aui-form-item label="列宽(%)">
<aui-numeric
v-model="config.width"
:min="1"
:max="100"
:precision="0"
>
</aui-numeric>
</aui-form-item>
</div>
</template>
<script>
import { Input, FormItem, Numeric, Checkbox } from '@aurora/vue'
import { $xss } from '@aurora/wemax-card-plugin'
import _ from 'lodash'
export default {
name: 'ColumnSettingItem',
components: {
AuiInput: Input,
AuiFormItem: FormItem,
AuiNumeric: Numeric,
AuiCheckbox: Checkbox
},
props: {
config: Object,
colIndex: Number,
columns: Array,
seqCol: Object
},
data() {
return {
columnName: '',
endUnit: '',
columnWidth: 0
}
},
computed: {
hasSortableAttr() { // 序号列不用排序
const hasOwnProperty = Object.prototype.hasOwnProperty
return hasOwnProperty.call(this.config, 'sortable')
},
notSeqCol() { // 不是序号列
return typeof this.colIndex === 'number'
}
},
watch: {
columnName(value) {
this.setColumnName(value)
},
endUnit(val) {
this.setColumnUnit(val)
}
},
mounted() {
this.setColumnName = _.debounce(this.setColumnName, 500)
this.setColumnUnit = _.debounce(this.setColumnUnit, 500)
this.columnName = this.config.name
this.endUnit = this.config.endUnit
},
methods: {
checkIfLastColumn() {
const isSeq = typeof this.colIndex !== 'number'
return !isSeq && this.colIndex === this.columns.length - 1
},
setColumnName(val) {
this.config.name = $xss.process(val)
},
setColumnUnit(val) {
this.config.endUnit = $xss.process(val)
}
}
}
</script>
# 列-列头合并
列头合并这一项,可以添加列头。点击添加列头,在左边表头之上便会新增一个列头,可以配置名称以及所占的列数。文件为SelfHeadItem.vue。此处配置简单,代码不做详细讲解。
# 列-条件
该配置项可以给每一列添加条件,如下图所示,该条件表示,当column1的值大于800、效果类型是文字时,对应的单元格的字号、颜色、粗细等就会如配置所示,其中,效果类型还可以选链接、图片、弹框等。
#
其中条件的代码如下
<template>
<aui-form class="column-condition-list">
<div
class="add-condition"
@click="addCondition"
>添加条件</div>
// columnConditions为条件列表,可设置多个条件
<template v-for="(condition,index) in columnConditions">
<div
:key="index"
class="list-item"
>
<div>
<span class="item-title">
{{`条件${index + 1}`}} // 条件名称:条件1、条件2
<icon-close-square
class="remove-condition"
title="删除条件"
@click="removeCondition(index)"
></icon-close-square>
</span>
<condition-item
:config="condition"
:operators="operators"
></condition-item>
<aui-form-item label="效果类型">
<aui-select v-model="condition.type">
<aui-option
v-for="item in styleTypes"
:key="item.value"
:label="item.text"
:value="item.value"
>
</aui-option>
</aui-select>
</aui-form-item>
<column-text-sty-setting
v-if="condition.type === 'text'" // 文本
:options="condition"
>
</column-text-sty-setting>
<link-text-setting
v-else-if="condition.type === 'link'" // 链接
:options="condition"
>
</link-text-setting>
<dialog-setting
v-else-if="condition.type === 'dialogBox'" // 弹框
:options="condition"
>
</dialog-setting>
<progress-sty-setting
v-else-if="condition.type === 'progress'" // 进度条
:options="condition"
>
</progress-sty-setting>
<image-setting // 图片
v-else
:options="condition"
@changePosType="(val) => changePos(val, index)"
></image-setting>
</div>
</div>
</template>
</aui-form>
</template>
<script>
import { Form, FormItem, Select, Option } from '@aurora/vue'
import ColumnTextStySetting from './ColumnTextStySetting.vue'
import ConditionItem from './ConditionItem.vue'
import ProgressStySetting from './ProgressStySetting.vue'
import ImageSetting from './ImageSetting.vue'
import LinkTextSetting from './LinkTextSetting.vue'
import DialogSetting from './DialogSetting.vue'
import { IconCloseSquare } from '@aurora/vue-icon'
export default {
name: 'ColumnConditionConfig',
components: {
AuiForm: Form,
AuiFormItem: FormItem,
AuiSelect: Select,
AuiOption: Option,
ConditionItem,
IconCloseSquare: IconCloseSquare(),
ColumnTextStySetting,
ProgressStySetting,
ImageSetting,
LinkTextSetting,
DialogSetting
},
props: {
options: Object
},
data() {
return {
columnConditions: [],
operators: [
{
text: '无', value: '--'
},
{
text: '大于', value: '>'
},
{
text: '大于等于', value: '>='
},
{
text: '等于', value: '='
},
{
text: '小于等于', value: '<='
},
{
text: '小于', value: '<'
},
{
text: '不等于', value: '!='
}
],
styleTypes: [
{
text: '文字', value: 'text'
},
{
text: '链接', value: 'link'
},
{
text: '弹窗', value: 'dialogBox'
},
{
text: '图片', value: 'image'
},
{
text: '进度条', value: 'progress'
}
]
}
},
watch: {
columnConditions: { // 条件有变化,及时更新option中的条件列表,保持两者相同
deep: true,
handler(value) {
if (value) {
this.options.columnConditionSetting = this.columnConditions
}
}
}
},
mounted() {
this.init()
},
methods: {
changePos(val, index) {
this.columnConditions[index].position = val
},
/**
* @description 初始化列条件
*/
init() {
const { columnConditionSetting } = this.options
this.columnConditions = JSON.parse(JSON.stringify(columnConditionSetting))
},
/**
* @description 添加新条件,条件的默认配置
*/
addCondition() {
const newCondition = {
colName: '',
operator: '--',
colVal: '',
type: 'text',
color: "#ffffff",
fontSize: 16,
fontWeight: 400,
useItalic: false,
useUnderLine: false,
imageUrl: "",
imageSize: 10,
position: 'row',
hideText: false,
borderRadius: 5,
progressWidth: 5,
progressLength: 1000,
progressBg: "transparent",
dialogUrl: '',
linkUrl: '',
linkType: '_blank'
}
this.columnConditions.push(newCondition)
},
/**
* @description 移除对应下标条件
* @param {Number} index 条件下标
*/
removeCondition(index) {
this.columnConditions.splice(index, 1)
}
}
}
</script>
# 实操讲解(新增列显隐)
在列-基础栏中,在每一列的配置项里加一个显示的选项,表示该列是否隐藏,原型图如下,默认勾选。当取消勾选时该列隐藏
具体步骤为:
# 1.新增配置项
在ColumnSettingItem.vue文件中,找到可排序配置项的上方,新增一个aui-form-item标签如下
<aui-form-item label="显示">
<aui-checkbox v-model="config.show"></aui-checkbox>
</aui-form-item>
# 2.在columnSettings数组中,新增show属性
在card.vue文件中,找到setColumnSettings函数,该函数是设置columnSettings的值
setColumnSettings() {
const list = []
const { columnSettings } = this.options
this.tableColumns.forEach((col, index) => {
const defaultConf = getDefaultColumnSetting()
const curConfig = columnSettings.length && columnSettings[index]
defaultConf.name = col.field
// 重点:新增显隐控制属性
defaultConf.show = true // 默认为true,显示列
if (curConfig) {
Object.assign(defaultConf, curConfig)
}
list.push(defaultConf)
})
this.options.columnSettings = list
},
# 3.card.vue文件中修改DOM和新增对应函数
在card.vue文件的DOM结构中,找到设置列的标签元素,它是包括列头和列普通单元格,下面是列头的对应标签。
<th
v-for="(item, index) in tableColumns"
:key="item.field + (Math.random() + 1)"
:style="[headerStyle, getColumnWidth(index)]"
class="table-head wemax-thead-th"
>
由此可以看出只需要在tableColumns数组的每一项中加入一个控制显隐的show字段就行了,这个show字段需来源于columnSettings,即列条件数组。而且当columnSettings变化时,应及时更新,因此需新增监听如下
columnSettings: {
deep: true,
handler(val) {
this.updateTableColumns()
}
}
updateTableColumns函数如下
updateTableColumns() {
this.tableColumns = this.tableColumns.map((item,index) => {
item.show = this.columnSettings[index].show
return item
})
}
于是在列头标签处新增v-show
// 列头新增显隐控制
<th
v-for="(item, index) in tableColumns"
v-show="item.show"
:key="item.field + (Math.random() + 1)"
:style="[headerStyle, getColumnWidth(index)]"
class="table-head wemax-thead-th"
>
然后在列单元格标签处新增v-show
// 列单元格新增显隐控制
<td
v-for="(item, colIndex) in tableColumns"
v-show="item.show"
:key="item.field + (Math.random() + 1)"
:style="[rowStyle, getColumnWidth(colIndex)]"
:field="item.field"
class="wemax-table-tbody-td"
@click="colClickStyle(data, item.field, colIndex)"
>
至此,列控制显隐的需求就全部完成,当点击去掉勾选的列配置中的显示复选框时,表格该列便会隐藏。