添加计量设备和测控点信息

main
suixy 3 weeks ago
parent 161c89a6a9
commit e9b5905117

@ -0,0 +1,178 @@
const { query, queryOne } = require('../../db');
const { nextId } = require('../../id');
const TABLE = 'measurement_control_point';
function pageParams(input = {}) {
const rawPageNum = Number(input.pageNum || 1);
const rawPageSize = Number(input.pageSize || 10);
const pageNum = Number.isFinite(rawPageNum) ? Math.max(Math.trunc(rawPageNum), 1) : 1;
const pageSize = Number.isFinite(rawPageSize) ? Math.max(Math.trunc(rawPageSize), 1) : 10;
return { pageNum, pageSize, offset: (pageNum - 1) * pageSize };
}
function tableData(rows, total) {
return { code: 200, msg: '查询成功', rows, total };
}
function mapRow(row) {
if (!row) return null;
return {
id: row.id,
pointCode: row.point_code,
pointName: row.point_name,
measuringDeviceId: row.measuring_device_id,
measuringDeviceName: row.measuring_device_name,
parameterName: row.parameter_name,
parameterNameLabel: row.parameter_name_label,
standardUnit: row.standard_unit,
conversionFactor: row.conversion_factor === null || row.conversion_factor === undefined ? null : Number(row.conversion_factor),
originalUnit: row.original_unit,
collectionCycle: row.collection_cycle,
dataType: row.data_type,
registerAddress: row.register_address,
status: row.status,
createTime: row.create_time,
updateTime: row.update_time,
delFlag: row.del_flag
};
}
function normalizeBody(body = {}) {
const conversionFactor = body.conversionFactor === '' || body.conversionFactor === undefined || body.conversionFactor === null
? null
: Number(body.conversionFactor);
if (conversionFactor !== null && !Number.isFinite(conversionFactor)) {
throw new Error('换算倍率必须是数字');
}
if (!body.measuringDeviceId) throw new Error('所属计量器具不能为空');
return {
pointCode: body.pointCode || null,
pointName: body.pointName || null,
measuringDeviceId: body.measuringDeviceId,
parameterName: body.parameterName || null,
standardUnit: body.standardUnit || null,
conversionFactor,
originalUnit: body.originalUnit || null,
collectionCycle: body.collectionCycle || null,
dataType: body.dataType || null,
registerAddress: body.registerAddress || null,
status: body.status || null
};
}
const selectSql = `
select mcp.*,
md.device_name as measuring_device_name,
em.metric_name as parameter_name_label
from ${TABLE} mcp
left join measuring_device md on md.id = mcp.measuring_device_id
left join (
select type,
collection_field,
substring_index(group_concat(metric_name order by id separator '||'), '||', 1) as metric_name
from energy_metric_library
where collection_field is not null
and collection_field <> ''
group by type, collection_field
) em on em.type collate utf8mb4_general_ci = md.device_type collate utf8mb4_general_ci
and em.collection_field collate utf8mb4_general_ci = mcp.parameter_name collate utf8mb4_general_ci
`;
async function list(params = {}) {
const page = pageParams(params);
const where = ["mcp.del_flag = '0'"];
const sqlParams = {};
if (params.pointCode) {
where.push('mcp.point_code like :pointCode');
sqlParams.pointCode = `%${String(params.pointCode).trim()}%`;
}
if (params.pointName) {
where.push('mcp.point_name like :pointName');
sqlParams.pointName = `%${String(params.pointName).trim()}%`;
}
if (params.measuringDeviceId) {
where.push('mcp.measuring_device_id = :measuringDeviceId');
sqlParams.measuringDeviceId = String(params.measuringDeviceId);
}
if (params.parameterName) {
where.push('mcp.parameter_name = :parameterName');
sqlParams.parameterName = String(params.parameterName);
}
const whereSql = `where ${where.join(' and ')}`;
const totalRow = await queryOne(`select count(*) as total from ${TABLE} mcp ${whereSql}`, sqlParams);
const rows = await query(
`${selectSql}
${whereSql}
order by mcp.create_time desc, mcp.id desc
limit ${page.pageSize} offset ${page.offset}`,
sqlParams
);
return tableData(rows.map(mapRow), Number(totalRow?.total || 0));
}
async function get(id) {
if (!id) throw new Error('ID不能为空');
return mapRow(await queryOne(
`${selectSql}
where mcp.id = :id and mcp.del_flag = '0'
limit 1`,
{ id }
));
}
async function add(body = {}) {
const id = body.id ? String(body.id) : nextId();
const data = normalizeBody(body);
await query(
`insert into ${TABLE}
(id, point_code, point_name, measuring_device_id, parameter_name, standard_unit, conversion_factor,
original_unit, collection_cycle, data_type, register_address, status, create_time, update_time, del_flag)
values
(:id, :pointCode, :pointName, :measuringDeviceId, :parameterName, :standardUnit, :conversionFactor,
:originalUnit, :collectionCycle, :dataType, :registerAddress, :status, now(), now(), '0')`,
{ id, ...data }
);
return id;
}
async function update(body = {}) {
if (!body.id) throw new Error('ID不能为空');
const data = normalizeBody(body);
await query(
`update ${TABLE}
set point_code = :pointCode,
point_name = :pointName,
measuring_device_id = :measuringDeviceId,
parameter_name = :parameterName,
standard_unit = :standardUnit,
conversion_factor = :conversionFactor,
original_unit = :originalUnit,
collection_cycle = :collectionCycle,
data_type = :dataType,
register_address = :registerAddress,
status = :status,
update_time = now()
where id = :id and del_flag = '0'`,
{ id: body.id, ...data }
);
}
async function remove(ids) {
const list = String(ids || '').split(',').map((item) => item.trim()).filter(Boolean);
if (!list.length) return;
const params = {};
const placeholders = list.map((id, index) => {
params[`id${index}`] = id;
return `:id${index}`;
});
await query(
`update ${TABLE}
set del_flag = '1',
update_time = now()
where id in (${placeholders.join(', ')})`,
params
);
}
module.exports = { list, get, add, update, remove };

@ -0,0 +1,423 @@
const { query, queryOne } = require('../../db');
const { nextId } = require('../../id');
function pageParams(input = {}) {
const rawPageNum = Number(input.pageNum || 1);
const rawPageSize = Number(input.pageSize || 10);
const pageNum = Number.isFinite(rawPageNum) ? Math.max(Math.trunc(rawPageNum), 1) : 1;
const pageSize = Number.isFinite(rawPageSize) ? Math.max(Math.trunc(rawPageSize), 1) : 10;
return {
pageNum,
pageSize,
offset: (pageNum - 1) * pageSize
};
}
function tableData(rows, total) {
return {
code: 200,
msg: '查询成功',
rows,
total
};
}
function mapRow(row) {
if (!row) return null;
return {
id: row.id,
deviceId: row.device_id,
deviceName: row.device_name,
deviceCode: row.device_code,
installPosition: row.install_position,
installPositionName: row.install_position_name,
deviceType: row.device_type,
measuringUnit: row.measuring_unit_summary || row.measuring_unit,
standardUnit: row.standard_unit,
standardUnitName: row.standard_unit_name_summary || row.standard_unit_name,
conversionFactor: row.conversion_factor === null || row.conversion_factor === undefined ? null : Number(row.conversion_factor),
units: row.units || [],
specificationModel: row.specification_model,
manufacturer: row.manufacturer,
factoryNo: row.factory_no,
accuracyLevel: row.accuracy_level,
measureRange: row.measure_range,
communicationProtocol: row.communication_protocol,
communicationAddress: row.communication_address,
collectionCycle: row.collection_cycle,
status: row.status,
lastVerificationDate: row.last_verification_date,
responsibleDept: row.responsible_dept,
responsiblePerson: row.responsible_person,
remark: row.remark,
createTime: row.create_time,
updateTime: row.update_time,
delFlag: row.del_flag
};
}
function normalizeUnits(body = {}) {
const source = Array.isArray(body.units) && body.units.length
? body.units
: [{
measuringUnit: body.measuringUnit,
standardUnit: body.standardUnit,
conversionFactor: body.conversionFactor
}];
return source
.map((item) => {
const conversionFactor = item.conversionFactor === '' || item.conversionFactor === undefined || item.conversionFactor === null
? null
: Number(item.conversionFactor);
if (conversionFactor !== null && !Number.isFinite(conversionFactor)) {
throw new Error('换算倍率必须是数字');
}
return {
id: item.id || nextId(),
measuringUnit: item.measuringUnit || null,
standardUnit: item.standardUnit || item.parameterName || null,
conversionFactor
};
})
.filter((item) => item.measuringUnit || item.standardUnit || item.conversionFactor !== null);
}
function normalizeBody(body = {}) {
const units = normalizeUnits(body);
const firstUnit = units[0] || {};
return {
deviceId: body.deviceId || null,
deviceName: body.deviceName || null,
deviceCode: body.deviceCode || null,
installPosition: body.installPosition || null,
deviceType: body.deviceType === undefined || body.deviceType === null || body.deviceType === '' ? null : String(body.deviceType),
measuringUnit: firstUnit.measuringUnit || null,
standardUnit: firstUnit.standardUnit || null,
conversionFactor: firstUnit.conversionFactor ?? null,
units,
specificationModel: body.specificationModel || null,
manufacturer: body.manufacturer || null,
factoryNo: body.factoryNo || null,
accuracyLevel: body.accuracyLevel || null,
measureRange: body.measureRange || null,
communicationProtocol: body.communicationProtocol || null,
communicationAddress: body.communicationAddress || null,
collectionCycle: body.collectionCycle || null,
status: body.status || null,
lastVerificationDate: body.lastVerificationDate || null,
responsibleDept: body.responsibleDept || null,
responsiblePerson: body.responsiblePerson || null,
remark: body.remark || null
};
}
const TABLE = 'measuring_device';
const selectSql = `select md.* from ${TABLE} md`;
async function loadFloorPathMap() {
const rows = await query(
`select id, pid, name
from floorInfo
where del_flag = '0'`
);
const byId = new Map(rows.map((row) => [String(row.id), row]));
const pathMap = new Map();
function pathOf(id) {
const key = String(id || '');
if (!key) return '';
if (pathMap.has(key)) return pathMap.get(key);
const names = [];
let current = byId.get(key);
const visited = new Set();
while (current && !visited.has(String(current.id))) {
visited.add(String(current.id));
if (current.name) names.unshift(current.name);
current = byId.get(String(current.pid));
}
const path = names.join(' / ');
pathMap.set(key, path);
return path;
}
rows.forEach((row) => pathOf(row.id));
return pathMap;
}
async function loadMetricNameMap() {
const rows = await query(
`select type, metric_name, collection_field, unit
from energy_metric_library`
);
return new Map(rows.map((row) => [
`${String(row.type)}:${row.collection_field}`,
`${row.metric_name || row.collection_field || ''}${row.unit ? `(${row.unit})` : ''}`
]));
}
function unitLabel(unit, metricNameMap, deviceType) {
const standardUnitName = metricNameMap.get(`${String(deviceType)}:${unit.standard_unit}`) || unit.standard_unit || '';
const measuringUnit = unit.measuring_unit || '';
const factor = unit.conversion_factor === null || unit.conversion_factor === undefined ? '' : Number(unit.conversion_factor);
return `${measuringUnit}${standardUnitName ? ` -> ${standardUnitName}` : ''}${factor !== '' ? ` x ${factor}` : ''}`;
}
async function loadUnitsMap(deviceIds, metricNameMap, deviceTypeMap) {
if (!deviceIds.length) return new Map();
const params = {};
const placeholders = deviceIds.map((id, index) => {
params[`id${index}`] = id;
return `:id${index}`;
});
const rows = await query(
`select id,
measuring_device_id,
measuring_unit,
standard_unit,
conversion_factor
from measuring_device_unit
where measuring_device_id in (${placeholders.join(', ')})
order by create_time asc, id asc`,
params
);
const map = new Map();
rows.forEach((row) => {
const deviceType = deviceTypeMap.get(String(row.measuring_device_id));
const unit = {
id: row.id,
parameterName: row.standard_unit,
measuringUnit: row.measuring_unit,
standardUnit: row.standard_unit,
standardUnitName: metricNameMap.get(`${String(deviceType)}:${row.standard_unit}`) || row.standard_unit,
conversionFactor: row.conversion_factor === null || row.conversion_factor === undefined ? null : Number(row.conversion_factor)
};
if (!map.has(String(row.measuring_device_id))) map.set(String(row.measuring_device_id), []);
map.get(String(row.measuring_device_id)).push({
raw: row,
unit,
label: unitLabel(row, metricNameMap, deviceType)
});
});
return map;
}
async function decorateRows(rows) {
const [floorPathMap, metricNameMap] = await Promise.all([loadFloorPathMap(), loadMetricNameMap()]);
const deviceTypeMap = new Map(rows.map((row) => [String(row.id), row.device_type]));
const unitsMap = await loadUnitsMap(rows.map((row) => row.id), metricNameMap, deviceTypeMap);
return rows.map((row) => ({
...row,
install_position_name: floorPathMap.get(String(row.install_position)) || '',
standard_unit_name: metricNameMap.get(`${String(row.device_type)}:${row.standard_unit}`) || row.standard_unit,
measuring_unit_summary: (unitsMap.get(String(row.id)) || []).map((item) => item.unit.measuringUnit).filter(Boolean).join('、'),
standard_unit_name_summary: (unitsMap.get(String(row.id)) || []).map((item) => item.label).filter(Boolean).join(''),
units: (unitsMap.get(String(row.id)) || []).map((item) => item.unit)
}));
}
async function saveUnits(deviceId, units = []) {
await query('delete from measuring_device_unit where measuring_device_id = :deviceId', { deviceId });
for (const unit of units) {
await query(
`insert into measuring_device_unit
(id, measuring_device_id, measuring_unit, standard_unit, conversion_factor, create_time, update_time)
values
(:id, :deviceId, :measuringUnit, :standardUnit, :conversionFactor, now(), now())`,
{
id: unit.id || nextId(),
deviceId,
measuringUnit: unit.measuringUnit || null,
standardUnit: unit.standardUnit || null,
conversionFactor: unit.conversionFactor
}
);
}
}
async function syncInstallPositionByDeviceId() {
const [deviceRows, floorRows] = await Promise.all([
query(
`select id, device_id, install_position
from ${TABLE}
where del_flag = '0'
and device_id is not null
and device_id <> ''`
),
query(
`select id,
pid,
device_id,
is_device,
is_device_group
from floorInfo
where del_flag = '0'`
)
]);
const floorById = new Map(floorRows.map((row) => [String(row.id), row]));
const deviceNodeByDeviceId = new Map(
floorRows
.filter((row) => row.is_device === '1' && row.device_id)
.map((row) => [String(row.device_id), row])
);
function nearestNormalNodeId(row) {
let current = row;
const visited = new Set();
while (current && !visited.has(String(current.id))) {
visited.add(String(current.id));
if (current.is_device !== '1' && current.is_device_group !== '1') {
return String(current.id);
}
current = floorById.get(String(current.pid));
}
return null;
}
for (const row of deviceRows) {
const deviceNode = deviceNodeByDeviceId.get(String(row.device_id));
const normalNodeId = deviceNode ? nearestNormalNodeId(deviceNode) : null;
if (normalNodeId && String(row.install_position || '') !== normalNodeId) {
await query(
`update ${TABLE}
set install_position = :installPosition,
update_time = now()
where id = :id`,
{
id: row.id,
installPosition: normalNodeId
}
);
}
}
}
async function list(params = {}) {
await syncInstallPositionByDeviceId();
const page = pageParams(params);
const where = ["md.del_flag = '0'"];
const sqlParams = {};
if (params.deviceName) {
where.push('md.device_name like :deviceName');
sqlParams.deviceName = `%${String(params.deviceName).trim()}%`;
}
if (params.deviceCode) {
where.push('md.device_code like :deviceCode');
sqlParams.deviceCode = `%${String(params.deviceCode).trim()}%`;
}
if (params.deviceId) {
where.push('md.device_id like :deviceId');
sqlParams.deviceId = `%${String(params.deviceId).trim()}%`;
}
if (params.deviceType !== undefined && params.deviceType !== '') {
where.push('md.device_type = :deviceType');
sqlParams.deviceType = String(params.deviceType);
}
if (params.installPosition) {
where.push('md.install_position = :installPosition');
sqlParams.installPosition = String(params.installPosition);
}
const whereSql = `where ${where.join(' and ')}`;
const totalRow = await queryOne(`select count(*) as total from ${TABLE} md ${whereSql}`, sqlParams);
const rows = await query(
`${selectSql}
${whereSql}
order by md.create_time desc, md.id desc
limit ${page.pageSize} offset ${page.offset}`,
sqlParams
);
return tableData((await decorateRows(rows)).map(mapRow), Number(totalRow?.total || 0));
}
async function get(id) {
if (!id) throw new Error('ID不能为空');
await syncInstallPositionByDeviceId();
const row = await queryOne(
`${selectSql}
where md.id = :id and md.del_flag = '0'
limit 1`,
{ id }
);
return mapRow((await decorateRows(row ? [row] : []))[0]);
}
async function add(body = {}) {
const id = body.id ? String(body.id) : nextId();
const data = normalizeBody(body);
await query(
`insert into ${TABLE}
(id, device_id, device_name, device_code, install_position, device_type, measuring_unit, standard_unit, conversion_factor,
specification_model, manufacturer, factory_no, accuracy_level, measure_range, communication_protocol, communication_address,
collection_cycle, status, last_verification_date, responsible_dept, responsible_person, remark, create_time, update_time, del_flag)
values
(:id, :deviceId, :deviceName, :deviceCode, :installPosition, :deviceType, :measuringUnit, :standardUnit, :conversionFactor,
:specificationModel, :manufacturer, :factoryNo, :accuracyLevel, :measureRange, :communicationProtocol, :communicationAddress,
:collectionCycle, :status, :lastVerificationDate, :responsibleDept, :responsiblePerson, :remark, now(), now(), '0')`,
{ id, ...data }
);
await saveUnits(id, data.units);
return id;
}
async function update(body = {}) {
if (!body.id) throw new Error('ID不能为空');
const data = normalizeBody(body);
await query(
`update ${TABLE}
set device_id = :deviceId,
device_name = :deviceName,
device_code = :deviceCode,
install_position = :installPosition,
device_type = :deviceType,
measuring_unit = :measuringUnit,
standard_unit = :standardUnit,
conversion_factor = :conversionFactor,
specification_model = :specificationModel,
manufacturer = :manufacturer,
factory_no = :factoryNo,
accuracy_level = :accuracyLevel,
measure_range = :measureRange,
communication_protocol = :communicationProtocol,
communication_address = :communicationAddress,
collection_cycle = :collectionCycle,
status = :status,
last_verification_date = :lastVerificationDate,
responsible_dept = :responsibleDept,
responsible_person = :responsiblePerson,
remark = :remark,
update_time = now()
where id = :id and del_flag = '0'`,
{ id: body.id, ...data }
);
await saveUnits(body.id, data.units);
}
async function remove(ids) {
const list = String(ids || '')
.split(',')
.map((item) => item.trim())
.filter(Boolean);
if (!list.length) return;
const params = {};
const placeholders = list.map((id, index) => {
params[`id${index}`] = id;
return `:id${index}`;
});
await query(
`update ${TABLE}
set del_flag = '1',
update_time = now()
where id in (${placeholders.join(', ')})`,
params
);
await query(`delete from measuring_device_unit where measuring_device_id in (${placeholders.join(', ')})`, params);
}
module.exports = {
list,
get,
add,
update,
remove
};
Loading…
Cancel
Save