遥控配置中心功能代码分析
软件概述
遥控配置中心是遥控自动化处理软件平台中的一个软件配置项。该配置项接收人工操作命令,调用遥控处理方法库中的方法加工各类遥控信息,生成遥控数据块,并将生成的数据块存入数据库中,完成各种遥控指令及注入数据的加工。支持遥控信息编辑,具备新建、打开、编辑、保存等操作,实现遥控信息反编和比对等功能。
页面功能点实现
-
如果忘记某个指令配置怎么办?
遥控配置中心需要懂遥控大纲的人使用对遥控指令进行配置,忘了某个指令配置时,给出提示配置信息。具体实现方法为封装一个组件点击[查看帮助],以 Drawer抽屉的形式,从屏幕边缘滑出浮层面板,结合Anchor 锚点选择指令跳转到页面指定位置 ,根据遥控大纲对指令长度、字节、注入数据等遥控帧格式进行填写参考,方便指令配置。
-
如何对指令进行排序?
点击上移/下移对指令进行排序,确定排序后更新orderNum字段及其指令排序后位置传参给后端。
/**
* 移动模式
* @param data - 单条数据
* @param index - 索引
* @param step - 上移-1 下移1
*/
handleMove(record, index, step) {
this.data.splice(index, 1);
this.data.splice(index + step, 0, record);
// this.move.isMoveMode = true;
this.table.selectedList[0] += step;
},
//确定排序
sumbitMove() {
this.data.forEach((e, index) => {
e.orderNum = index + 1;
});
this.requestPut(this.data);
},
-
动态导出Excel指令模板,并添加表头标注
单元格注释 :
单元格注释是对象,被存储在单元格对象的
c数组内。实际上注释的内容根据注释的作者被分成了小块。每一个注释对象的a字段存储注释的作者,t字段是注释的纯文字展示。注意:XLSB对作者的名字施加54个字符的限制。名字的长度超过54个字符可能造成其他的格式问题。
把注释标记为普通的隐藏,只需设置
hidden属性,例如下面的片段在单元格A1内添加了单元格注释:if(!ws.A1.c) ws.A1.c = []; ws.A1.c.push({a:"SheetJS", t:"This comment is visible"}); if(!ws.A2.c) ws.A2.c = []; ws.A2.c.hidden = true; ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"});单元格对象:c表示与单元格关联的注释,其他对象不逐一列举。
软件中实现:
选择导出指令的名称,获取所有指令配置导出为Excel表头。需求为指令代号/名称/类型为列表前三列,指令码为最后一列,中间动态添加表头名称,其中方式字、通过标识、APID等几个特殊的指令帧格式配置条目为表头时,需要添加填表标注提示用户。
async exportModal() {
await this.getTcConfig();
this.defaultHreadName.splice(3, 0, this.headNameList);
var aoa = [this.defaultHreadName.flat(1)];
let _name = this.wholeData[this.selectConfig].name;
const filename = _name + ".xlsx";
// Excel第一个sheet的名称
const ws_name = "Sheet1";
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(aoa);
/** 表头添加标注 */
// if (!ws.A1.c) ws.A1.c = [];
// ws.D1.c.hidden = true;
// ws.A1.c.push({ a: "Sheet1", t: "This comment is visible" });
// console.log(ws);
const txt = `1、二进制输入需以B结尾,填写样例:010101B
2、十六进制输入需以0x开头或H结尾,填写样例:0x475或475H
3、十进制输入无需前后缀,填写样例:61`;
if (Object.keys(ws).length > 5) {
let headComments = Object.keys(ws).slice(3, Object.keys(ws).length - 2);
headComments.forEach((it) => {
if (!ws[it].c) ws[it].c = [];
ws[it].c.hidden = true;
ws[it].c.autoSize = true;
ws[it].c.push({
a: "Sheet1",
t: txt,
});
});
}
//这个是修改格式的代码 (目前不生效)
for (const key in ws) {
if (key.indexOf("!") === -1 && ws[key].v) {
ws[key].s = {
font: {
name: "宋体", // 字体
sz: 14, // 字体大小
bold: true, // 加粗
},
alignment: {
horizontal: "center",
vertical: "center",
wrap_text: true,
},
};
}
}
//控制单元格宽度
ws["!cols"] = [];
Object.keys(ws).forEach((_, index) => {
ws["!cols"][index] = { wpx: 110 };
});
// ws["!cols"] = [
// { wpx: 70 },
// { wpx: 110 },
// { wpx: 70 },
// { wpx: 110 },
// { wpx: 110 },
// { wpx: 110 },
// { wpx: 110 },
// { wpx: 110 },
// { wpx: 110 },
// ];
// ws["!merges"] = sheet["!merges"];
XLSX.utils.book_append_sheet(wb, ws, ws_name); // 将数据添加到工作薄
XLSX.writeFile(wb, filename); // 导出Excel
},
备注:表头标注文字以字符串模板的方式,直接换行写入描述信息,有空格或者其他标志符导出表格无法识别及其解析,不能实现换行。
更改表头字体需要配合 xlsx-js-style使用
实现结果:
excel表头批注
组件封装技术点分析
-
列表复用
各种指令配置列表大同小异,没有太多区别,整体封装一个组件,动态显示各种指令配置列表。 组件见代码展示。
<div> <common-list :columns_tran="columns" //表头 :url_tran="url" //接口 request_key="oid" //指令类型 delete_key="oid" detail_link="delay-detail" //指令详情相关操作 :options_tran="option" //功能键显示与否 > <common-form ref="form" type_tran="oid" /> </common-list> </div> -
组件封装复用
在封装的组件中点击添加/修改按钮,运用ref打开弹窗,同时使用插槽,获取父组件中内容,动态显示不同指令的配置信息。结合get(),set()方法获取和设置值,达到组件复用
添加
openModal() { this.$refs.modal.openModal("add"); return; },修改
handleEdit(record, index) { this.$refs.modal.openModal("edit"); this.$nextTick(() => { if (this.isShow("import")) { this.$parent.$refs.form.set(record, this.$refs.sat.get()); } else { this.$parent.$refs.form.set(record); } }); },openModal(type) { this.visible = true; this.type = type; this.title = type === "add" ? "添加" : "修改"; },get()
get() { const res = Object.assign( { sat_id: this.getSat(), }, this.form ); let flag = this.$rules(rule, res); if (flag) { return res; } else { return false; } },set()
set(source) { const { base, data, id, length, name, type, } = source; Object.assign(this.form, { id, length, name, type ,base,data}); },点击确定按钮
async updateList(type) { let data = await this.$parent.$refs.form.get(); if (!data) return this.stopModalLoading(false); if (type === "add") { if (this.multi.isMultiMode) { this.data.unshift(data); } else { this.requestPost([data]); } } else if (type === "edit") { if (data.id) { this.requestPut([data]); } else { this.data.splice(this.currentEditIndex, 1, data); this.stopModalLoading(); } } }, -
规则校验
封装一个检验规则的方法,提交表单时检验是否有未填项目
/** * * @param {Array} rule [{name:"",message:""}] * @param {Object} obj {} * @returns Boolean */ Vue.prototype.$rules = (rule, obj) => { let msg = '' let flag = rule.every(i => { let k = obj[i.name] if (i.second) { msg = i.msg return k || obj[i.second] } if (!k) msg = i.msg return k } ) if (!flag) { message.warning(msg) } return flag }let flag = this.$rules(rule, obj); if (flag) { return res; } else { return false; }
代码维护复杂程度
公用组件里面有很多方法及其数据处理都在组件内,由于各种指令配置的类型、数据格式、请求传参等存在差异,使得一个方法需要做很多判断。例如基本的查询列表参数,首先要区分是外层数据、底层详情数据,其次请求的数据源是否是midware表做校验,然后对是否有分页做区分,最后就是一般请求,可以看出逻辑功能比较复杂。
async getList(page) {
this.multi.isMultiMode = false;
this.data.splice(0);
page = page || this.table.page;
const { pagerow } = this.table;
let sat_id = this.$refs.sat.get();
let isPageMode = this.isShow("sat");
const params = this.$route.params;
this.table.loading = true;
try {
let res;
// 区分请求详情
if (this.detailMode) {
this.table.page = 1;
this.table.pagination.defaultPageSize = 9999;
res = await request({
url: this.url,
params: {
page,
pagerow: 9999,
...params,
},
});
if (this.isShow("sort")) {
res.list.sort((a, b) => a.orderNum - b.orderNum);
}
this.data.push(...res.list);
} else if (this.url === urls.group) {
// 数据源是否是midware表
res = await request({
url: this.url,
params: {
sat_id,
type: this.request_key,
},
});
if (res) {
res.sort((a, b) => a.orderNum - b.orderNum);
this.table.pagination.total = res.length;
this.data.push(...res);
}
} else if (isPageMode) {
// 区分是否分页
res = await request({
url: this.url,
params: {
isall: true,
sat_id,
page,
pagerow,
},
});
if (res) {
this.table.pagination.total = res.totalRows;
this.data.push(...res.list);
}
} else {
res = await request({
url: this.url,
});
if (res) {
this.table.pagination.total = res.length;
this.data.push(...res);
}
}
} catch (error) {
message.error(error);
} finally {
this.table.selectedList.splice(0);
this.multi.isMultiMode = false;
this.move.isMoveMode = false;
this.table.loading = false;
}
},
其余逻辑见线下代码演示
目前该项目为二期开发,比较不好维护