第四次编程记录
4.1 报警列表点击已处理按钮切换状态
问题:报警列表点击已处理按钮要变成黑色文字一行,要求默认颜色都是红色,点击按钮后变成相应的一行变为黑色
解决:
如何设置默认列表展示文字都是红色-customRow返回样式或者样式类名
如何点击按钮后不需要重新调用列表接口直接页面自动进行样式更新-找到当前点击行更新其样式
<a-table
size="small"
:columns="alarmColumns"
:data-source="alarmData"
:pagination="false"
:scroll="{ y: 550 }"
:customRow="handleCustomRow"><template slot="serial" #bodyCell="{ column, record, index }"><template v-if="column.dataIndex === 'serialNumber'"><span>{{ index + 1 }}</span></template><template v-else-if="column.dataIndex === 'action'"><span v-if="record.handle !== 1" class="table-btn" @click="handleSolve(record)">已处理</span><span v-else class="table-btn-disabled">已处理</span></template></template></a-table>
。。。。。。。。。
。。。。。。。。// 4. 自定义行样式:控制字体颜色const handleCustomRow = (record) => {return {style: {color: record.handle === 1 ? '#000000' : '#f5222d', // 1=黑色(已处理),0=红色(未处理)fontSize: '14px', // 可选:统一字体大小},};};
。。。。。。
。。。。。。const handleSolve = async (record) => {try {// 调用处理报警接口await handleSystemWarnApi({ warnInfoId: record.warnInfoId });// 找到当前行在响应式数组中的索引const targetIndex = alarmData.value.findIndex((item) => item.warnInfoId === record.warnInfoId,);if (targetIndex !== -1) {// 响应式更新当前行的 handle 字段为 1(触发样式重算)alarmData.value[targetIndex] = {...alarmData.value[targetIndex],handle: 1,};}} catch (error) {console.error('处理报警失败:', error);}
};
4.2 自定义table显示数据
问题:后端传递数据值为0,1,前端需要转换为未处理和已处理
解决:方法还挺多的,column里面加customRender,或者加插槽,或者使用计算属性,或者在获取数据时候直接转换。
// 报警信息表格列定义const alarmColumns = [{title: '序号',dataIndex: 'serialNumber',width: 70,scopedSlots: { customRender: 'bodyCell' },},{title: '处理状态',dataIndex: 'handle',ellipsis: true,customRender: ({ text }) => {return Number(text) === 1 ? '已处理' : '未处理';},},{title: '操作',dataIndex: 'action',ellipsis: true,},];
customRender
属性
- 这是 Ant Design Vue 表格列配置中的一个属性
- 用于自定义该列数据的显示方式,当表格需要渲染这一列时,会调用这个函数
函数参数 { text }
text
是该列当前行的数据值- 对于
handle
列,text
就是record.handle
的值 - 使用了解构赋值语法,等价于
(params) => { const text = params.text; ... }
除了使用 customRender
,还有多种方法可以实现相同的效果。几种替代方案:
方法1:在模板中使用计算属性或方法
1.1 使用计算属性
// 在 script 中定义计算属性
const getHandleStatus = (handle) => {return Number(handle) === 1 ? '已处理' : '未处理';
};
然后在模板中:
<template slot="serial" #bodyCell="{ column, record, index }"><template v-if="column.dataIndex === 'serialNumber'"><span>{{ index + 1 }}</span></template><template v-else-if="column.dataIndex === 'handle'"><span>{{ getHandleStatus(record.handle) }}</span></template><template v-else-if="column.dataIndex === 'action'"><span v-if="Number(record.handle) !== 1" class="table-btn" @click="handleSolve(record)">消除报警</span><span v-else class="table-btn-disabled">已处理</span></template>
</template>
1.2 使用内联表达式
<template v-else-if="column.dataIndex === 'handle'"><span>{{ record.handle === 1 ? '已处理' : '未处理' }}</span>
</template>
方法2:在数据处理阶段转换
在获取数据后,直接转换数据格式:
// 在 initAlarmData 函数中
async function initAlarmData() {try {const params = {warnType: 0,warnDeviceCode: route.query.id as string,machCabinetInfoId: route.query.machCabinetInfoId as string,};const res = await querySystemWarnInfoApi(params);// 转换数据格式alarmData.value = (res || []).map(item => ({...item,handleText: Number(item.handle) === 1 ? '已处理' : '未处理'}));} catch (error) {console.error('获取报警信息失败:', error);alarmData.value = [];}
}
然后在列定义中:
{title: '处理状态',dataIndex: 'handleText', // 直接使用转换后的字段ellipsis: true,
},
方法3:使用自定义插槽
首先,定义表格列时,使用 scopedSlots
来指定自定义插槽的名称。
const alarmColumns = [{title: '序号',dataIndex: 'serialNumber',width: 70,scopedSlots: { customRender: 'serialNumber' }, // 自定义插槽名称},{title: '处理状态',dataIndex: 'handle',ellipsis: true,scopedSlots: { customRender: 'handle' }, // 自定义插槽名称},{title: '操作',dataIndex: 'action',ellipsis: true,scopedSlots: { customRender: 'action' }, // 自定义插槽名称},
];
<template><a-table :columns="alarmColumns" :dataSource="dataSource"><!-- 自定义插槽:序号 --><template v-slot:serialNumber="{ text, record }"><span>{{ text }}</span></template><!-- 自定义插槽:处理状态 --><template v-slot:handle="{ text, record }"><span>{{ Number(text) === 1 ? '已处理' : '未处理' }}</span></template><!-- 自定义插槽:操作 --><template v-slot:action="{ text, record }"><a-button type="link" @click="handleAction(record)">操作</a-button></template></a-table>
</template>
4.3 antv x6数据同步问题
问题:前端保存画布布局作为json格式传递给后端,下一次进入页面渲染默认先根据后端返回的json来绘制画布,如果后端返回了json,那么我就按照json加载,但是还有问题,就是后端会有时候修改画布上机柜属性mcc的值,那此时我只加载json就不是最新的了,但是用户会在画布上面摆放线的位置,我如果不读取json就会把线丢掉
解决:智能合并策略,既要保持用户的布局(线条位置),又要更新后端的最新数据(如mcc值)。
先绘制json数据的图,然后获取后端数据之后根据此时画布节点来更新画布节点的数据,获取全部节点,然后筛选出机柜的,然后根据机柜唯一的id来区分每一个机柜
//这里的graphData存放的就是后端返回的json格式的画布数据
if (Object.keys(graphData).length === 0) {// 没有保存的布局,直接根据后端数据绘制a();
} else {// 有保存的布局,需要智能合并try {// 1. 先加载保存的布局(包含用户绘制的线条和位置)graph.fromJSON(graphData);// 2. 获取后端最新的机柜数据const latestCabinetData = {PCS: props.res['机柜信息'].PCS || [],ESD: props.res['机柜信息'].ESD || [],FGS: props.res['机柜信息'].FGS || [],};// 3. 遍历画布上的所有机柜节点,更新它们的数据graph.getNodes().forEach((node) => {const nodeData = node.getData();if (nodeData?.type === 'cabinet' && nodeData.machCabinetInfoId) {// 根据机柜类型和ID找到对应的最新数据const cabinetType = nodeData.sysType;const cabinetId = nodeData.machCabinetInfoId;let latestCabinet = null;if (cabinetType && latestCabinetData[cabinetType]) {latestCabinet = latestCabinetData[cabinetType].find((cabinet) => cabinet.machCabinetInfoId === cabinetId,);}if (latestCabinet) {// 4. 合并最新数据到节点(保持位置不变)const mergedData = { ...nodeData, ...latestCabinet };node.setData(mergedData);// 5. 检查是否需要更新图片(只在数据真正变化时更新)if ((nodeData as any)?.mcc !== (latestCabinet as any)?.mcc ||(nodeData as any)?.wrong !== (latestCabinet as any)?.wrong) {updateCabinetImage(node, latestCabinet); //触发数据更改时候的函数}}}});console.log('智能合并完成:保持了用户布局,更新了后端最新数据');} catch (error) {console.error('智能合并失败,回退到重新绘制:', error);// 如果合并失败,回退到重新绘制a();}
}