@flexem/fc-gui 3.0.0-alpha.127 → 3.0.0-alpha.129

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,5 +3,11 @@ export declare class HistoryDataModel {
3
3
  readonly error: string;
4
4
  readonly isUnbind: boolean;
5
5
  readonly values: Array<HistoryDataValue>;
6
- constructor(error: string, isUnbind: boolean, values: Array<HistoryDataValue>);
6
+ readonly historyDataItems?: Array<HistoryDataItemModel>;
7
+ constructor(error: string, isUnbind: boolean, values: Array<HistoryDataValue>, historyDataItems?: Array<HistoryDataItemModel>);
8
+ }
9
+ export declare class HistoryDataItemModel {
10
+ readonly itemName: string;
11
+ readonly rows: Array<HistoryDataValue>;
12
+ constructor(itemName: string, rows: Array<HistoryDataValue>);
7
13
  }
@@ -1,7 +1,15 @@
1
1
  export class HistoryDataModel {
2
- constructor(error, isUnbind, values) {
2
+ constructor(error, isUnbind, values, historyDataItems // 新增:多条目独立数据
3
+ ) {
3
4
  this.error = error;
4
5
  this.isUnbind = isUnbind;
5
6
  this.values = values;
7
+ this.historyDataItems = historyDataItems;
8
+ }
9
+ }
10
+ export class HistoryDataItemModel {
11
+ constructor(itemName, rows) {
12
+ this.itemName = itemName;
13
+ this.rows = rows;
6
14
  }
7
15
  }
@@ -1 +1 @@
1
- [{"__symbolic":"module","version":4,"metadata":{"HistoryDataModel":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","name":"boolean"},{"__symbolic":"reference","name":"Array","arguments":[{"__symbolic":"reference","module":"./history-data-value","name":"HistoryDataValue","line":3,"character":91}]}]}]}}}}]
1
+ [{"__symbolic":"module","version":4,"metadata":{"HistoryDataModel":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","name":"boolean"},{"__symbolic":"reference","name":"Array","arguments":[{"__symbolic":"reference","module":"./history-data-value","name":"HistoryDataValue","line":6,"character":31}]},{"__symbolic":"reference","name":"Array","arguments":[{"__symbolic":"reference","module":"./history-data-value","name":"HistoryDataValue","line":6,"character":31}]}]}]}},"HistoryDataItemModel":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","name":"Array","arguments":[{"__symbolic":"reference","module":"./history-data-value","name":"HistoryDataValue","line":6,"character":31}]}]}]}}}}]
@@ -1,4 +1,4 @@
1
1
  export { HistoryDataStore } from './history-data.store';
2
- export { HistoryDataModel } from './history-data.model';
2
+ export { HistoryDataModel, HistoryDataItemModel } from './history-data.model';
3
3
  export { HistoryDataValue } from './history-data-value';
4
4
  export { GetHistoryDataArgs } from './get-history-data-args';
@@ -1,3 +1,3 @@
1
- export { HistoryDataModel } from './history-data.model';
1
+ export { HistoryDataModel, HistoryDataItemModel } from './history-data.model';
2
2
  export { HistoryDataValue } from './history-data-value';
3
3
  export { GetHistoryDataArgs } from './get-history-data-args';
@@ -1 +1 @@
1
- [{"__symbolic":"module","version":4,"metadata":{},"exports":[{"from":"./history-data.store","export":["HistoryDataStore"]},{"from":"./history-data.model","export":["HistoryDataModel"]},{"from":"./history-data-value","export":["HistoryDataValue"]},{"from":"./get-history-data-args","export":["GetHistoryDataArgs"]}]}]
1
+ [{"__symbolic":"module","version":4,"metadata":{},"exports":[{"from":"./history-data.store","export":["HistoryDataStore"]},{"from":"./history-data.model","export":["HistoryDataModel","HistoryDataItemModel"]},{"from":"./history-data-value","export":["HistoryDataValue"]},{"from":"./get-history-data-args","export":["GetHistoryDataArgs"]}]}]
@@ -13,7 +13,7 @@ export declare class AlarmElement extends ConditionalDisplayElement {
13
13
  readonly model: AlarmModel;
14
14
  private readonly logger;
15
15
  readonly variableCommunicator: VariableCommunicator;
16
- private readonly timePeriods;
16
+ private timePeriods;
17
17
  private languageChangeSubscription?;
18
18
  private elementStatus;
19
19
  private element;
@@ -41,7 +41,6 @@ export class AlarmElement extends ConditionalDisplayElement {
41
41
  this.setStatusAsLoading();
42
42
  this.logger = injector.get(LOGGER_SERVICE_TOKEN);
43
43
  this.variableCommunicator = variableCommunicator;
44
- this.timePeriods = this.getValidTimePeriods();
45
44
  this.pageSize = this.model.generalSetting.pageSize;
46
45
  localStorage.setItem('simulate-time', moment().valueOf() + '');
47
46
  // 订阅语种变化事件
@@ -113,6 +112,7 @@ export class AlarmElement extends ConditionalDisplayElement {
113
112
  if (!selectElement.empty()) {
114
113
  // 重新生成时间段数据
115
114
  const updatedTimePeriods = this.getValidTimePeriods();
115
+ this.timePeriods = updatedTimePeriods;
116
116
  // 更新选项文本
117
117
  const options = selectElement.selectAll('option');
118
118
  options.each(function (_d, i) {
@@ -203,6 +203,7 @@ export class AlarmElement extends ConditionalDisplayElement {
203
203
  this.setStatusAsLoading();
204
204
  clearTimeout(this.getAlarmDataId);
205
205
  this.getAlarmDataId = setTimeout(() => {
206
+ this.timePeriods = this.getValidTimePeriods();
206
207
  if (this.model.filterSetting.alarmType) {
207
208
  this.updateQueryTimeRange();
208
209
  const input = new GetAlarmsArgs(this.alarmNames, this.startTime, this.endTime, this.pageSize, this.page * this.pageSize);
@@ -13,7 +13,7 @@ export declare class HistoricalCurveElement extends ConditionalDisplayElement {
13
13
  readonly model: HistoricalCurveModel;
14
14
  private readonly logger;
15
15
  private readonly localization;
16
- private readonly timePeriods;
16
+ private timePeriods;
17
17
  private languageChangeSubscription?;
18
18
  private readonly displayOption;
19
19
  /**
@@ -70,6 +70,11 @@ export declare class HistoricalCurveElement extends ConditionalDisplayElement {
70
70
  private handleQueryResult;
71
71
  setupTooltipAutoHide(chart: any): void;
72
72
  private renderChart;
73
+ /**
74
+ * 【新格式】多条目独立数据的曲线渲染
75
+ * 每个条目独立保持自己的时间戳,不会出现时间戳混乱的问题
76
+ */
77
+ private renderChartWithMultiItems;
73
78
  initPoint(): void;
74
79
  private getLineChart;
75
80
  private getMultiBarWithFocusChart;
@@ -41,7 +41,6 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
41
41
  };
42
42
  this.logger = injector.get(LOGGER_SERVICE_TOKEN);
43
43
  this.localization = injector.get(LOCALIZATION);
44
- this.timePeriods = this.getValidTimePeriods();
45
44
  this.updateTimeRange(this.model.displaySetting.displayTimePeriod);
46
45
  this.refreshIntervalId = setInterval(() => {
47
46
  this.loadFirstPage();
@@ -108,6 +107,7 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
108
107
  if (!selectElement.empty()) {
109
108
  // 重新生成时间段数据
110
109
  const updatedTimePeriods = this.getValidTimePeriods();
110
+ this.timePeriods = updatedTimePeriods;
111
111
  // 更新选项文本
112
112
  const options = selectElement.selectAll('option');
113
113
  options.each(function (_d, i) {
@@ -232,7 +232,51 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
232
232
  }
233
233
  }
234
234
  handleQueryResult(result) {
235
- if (result.error) {
235
+ this.timePeriods = this.getValidTimePeriods();
236
+ // 【新格式】多条目模式下的错误处理
237
+ if (result.historyDataItems && result.historyDataItems.length > 0) {
238
+ // 只要有条目正常返回(即使没有数据),就走正常逻辑
239
+ // 这样可以确保即使部分条目失败,只要有条目成功返回,就显示正常状态
240
+ this.clearStatus();
241
+ if (result.isUnbind) {
242
+ this.updateElementStatus(HistoricalCurveElementStatus.Unbound);
243
+ }
244
+ else {
245
+ this.updateElementStatus(HistoricalCurveElementStatus.Normal);
246
+ }
247
+ // 如果有错误信息,在控制台输出警告
248
+ if (result.error) {
249
+ this.logger.warn(`[历史曲线] 部分条目查询失败: ${result.error}`);
250
+ }
251
+ // 检查是否有任何条目有数据
252
+ const hasAnyData = result.historyDataItems.some(item => item.rows && item.rows.length > 0);
253
+ if (hasAnyData) {
254
+ // 有数据,计算所有条目的最小和最大时间,确保时间轴覆盖所有数据
255
+ let globalMinTime = null;
256
+ let globalMaxTime = null;
257
+ result.historyDataItems.forEach(item => {
258
+ if (item.rows && item.rows.length > 0) {
259
+ const itemMinTime = moment(first(item.rows).time);
260
+ const itemMaxTime = moment(last(item.rows).time);
261
+ if (!globalMinTime || itemMinTime.isBefore(globalMinTime)) {
262
+ globalMinTime = itemMinTime;
263
+ }
264
+ if (!globalMaxTime || itemMaxTime.isAfter(globalMaxTime)) {
265
+ globalMaxTime = itemMaxTime;
266
+ }
267
+ }
268
+ });
269
+ // 设置全局时间范围
270
+ if (globalMinTime && globalMaxTime) {
271
+ this.currentStartTime = globalMinTime;
272
+ this.currentEndTime = globalMaxTime;
273
+ }
274
+ }
275
+ // 无论是否有数据,都渲染曲线(没有数据会显示空曲线)
276
+ this.chartElement = this.renderChartWithMultiItems(result.historyDataItems);
277
+ }
278
+ // 【旧格式】单条目模式的错误处理
279
+ else if (result.error) {
236
280
  this.updateElementStatus(HistoricalCurveElementStatus.LoadFailed, result.error);
237
281
  }
238
282
  else {
@@ -243,6 +287,7 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
243
287
  else {
244
288
  this.updateElementStatus(HistoricalCurveElementStatus.Normal);
245
289
  }
290
+ // 【旧格式】单条目数据,使用原有渲染方式
246
291
  if (result.values.length) {
247
292
  this.currentStartTime = moment(first(result.values).time);
248
293
  this.currentEndTime = moment(last(result.values).time);
@@ -276,31 +321,61 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
276
321
  const chartWidth = this.model.displaySetting.size.width;
277
322
  const chartHeight = this.model.displaySetting.size.height - this.displayOption.operationAreaHeight - this.displayOption.operationAreaMarginTop;
278
323
  const data = new Array();
279
- // 【新格式】多条目模式:曲线名称使用"条目名-通道名"格式
280
- if (this.model.dataSetting.dataItems && this.model.dataSetting.dataItems.length > 0) {
281
- let channelIndex = 0;
282
- each(this.model.dataSetting.dataItems, dataItem => {
283
- each(dataItem.channels, channel => {
284
- const values = new Array();
285
- each(result, v => values.push({ x: moment(v.time).local().toDate().valueOf(), y: v.values[channelIndex] }));
286
- // 使用"条目名-通道名"格式
287
- const displayName = `${dataItem.dataName}-${channel.name}`;
288
- data.push({ key: displayName, area: channel.projectEnabled, values: values });
289
- channelIndex++;
290
- });
291
- });
292
- }
293
- // 【旧格式】单条目模式:同样使用"条目名-通道名"格式
294
- else {
295
- const dataItemName = this.model.dataSetting.dataName;
296
- each(this.model.dataSetting.channels, (channel, key) => {
324
+ // 【旧格式】单条目模式:只显示通道名
325
+ each(this.model.dataSetting.channels, (channel, key) => {
326
+ const values = new Array();
327
+ each(result, v => values.push({ x: moment(v.time).local().toDate().valueOf(), y: v.values[key] }));
328
+ const displayName = channel.name;
329
+ data.push({ key: displayName, area: channel.projectEnabled, values: values });
330
+ });
331
+ this.data = data;
332
+ nv.addGraph(() => {
333
+ let chart;
334
+ if (this.model.displaySetting.curveType === CurveType.BarGroup || this.model.displaySetting.curveType === CurveType.BarStack) {
335
+ chart = this.getMultiBarWithFocusChart(chartWidth, chartHeight, data);
336
+ }
337
+ else {
338
+ chart = this.getLineChart(chartWidth, chartHeight, data);
339
+ }
340
+ // 设置 tooltip 自动隐藏逻辑
341
+ this.setupTooltipAutoHide(chart);
342
+ return chart;
343
+ });
344
+ }
345
+ /**
346
+ * 【新格式】多条目独立数据的曲线渲染
347
+ * 每个条目独立保持自己的时间戳,不会出现时间戳混乱的问题
348
+ */
349
+ renderChartWithMultiItems(historyDataItems) {
350
+ const chartWidth = this.model.displaySetting.size.width;
351
+ const chartHeight = this.model.displaySetting.size.height - this.displayOption.operationAreaHeight - this.displayOption.operationAreaMarginTop;
352
+ const data = new Array();
353
+ // 创建一个 Map 用于快速查找条目数据
354
+ const itemDataMap = new Map();
355
+ each(historyDataItems, item => {
356
+ if (item && item.itemName) {
357
+ itemDataMap.set(item.itemName, item.rows || []);
358
+ }
359
+ });
360
+ // 判断是否只有一个条目
361
+ const isSingleItem = this.model.dataSetting.dataItems && this.model.dataSetting.dataItems.length === 1;
362
+ // 为每个条目的每个通道创建独立的曲线
363
+ each(this.model.dataSetting.dataItems, (dataItem) => {
364
+ const itemName = dataItem.dataName;
365
+ // 通过 itemName 匹配数据,而不是通过索引
366
+ const itemRows = itemDataMap.get(itemName) || [];
367
+ each(dataItem.channels, (channel, channelIdx) => {
297
368
  const values = new Array();
298
- each(result, v => values.push({ x: moment(v.time).local().toDate().valueOf(), y: v.values[key] }));
299
- // 使用"条目名-通道名"格式
300
- const displayName = `${dataItemName}-${channel.name}`;
369
+ // 每个条目使用自己的时间戳和数据
370
+ each(itemRows, row => {
371
+ const value = row.values && row.values[channelIdx] !== undefined ? row.values[channelIdx] : null;
372
+ values.push({ x: moment(row.time).local().toDate().valueOf(), y: value });
373
+ });
374
+ // 只有多个条目时才使用"条目名-通道名"格式,单条目时只显示通道名
375
+ const displayName = isSingleItem ? channel.name : `${itemName}-${channel.name}`;
301
376
  data.push({ key: displayName, area: channel.projectEnabled, values: values });
302
377
  });
303
- }
378
+ });
304
379
  this.data = data;
305
380
  nv.addGraph(() => {
306
381
  let chart;
@@ -1 +1 @@
1
- [{"__symbolic":"module","version":4,"metadata":{"HistoricalCurveElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":23,"character":44},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":71,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":72,"character":18},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":73,"character":27},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":74,"character":30},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":75,"character":23},{"__symbolic":"reference","module":"../../config","name":"HistoryDataStore","line":76,"character":43},{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","module":"../../service","name":"SystemTextLibraryService","line":78,"character":52},{"__symbolic":"reference","module":"../../service","name":"LanguageService","line":79,"character":43},{"__symbolic":"reference","module":"../../gui/gui-context","name":"GuiContext","line":80,"character":38}]}],"dispose":[{"__symbolic":"method"}],"initKeyboardListener":[{"__symbolic":"method"}],"subscribeLanguageChange":[{"__symbolic":"method"}],"updateLanguageTexts":[{"__symbolic":"method"}],"getCurrentCulture":[{"__symbolic":"method"}],"getValidTimePeriods":[{"__symbolic":"method"}],"getTimePeriodText":[{"__symbolic":"method"}],"updateTimeRange":[{"__symbolic":"method"}],"updateQueryTimeRange":[{"__symbolic":"method"}],"reRenderElement":[{"__symbolic":"method"}],"renderElement":[{"__symbolic":"method"}],"handleQueryResult":[{"__symbolic":"method"}],"setupTooltipAutoHide":[{"__symbolic":"method"}],"renderChart":[{"__symbolic":"method"}],"initPoint":[{"__symbolic":"method"}],"getLineChart":[{"__symbolic":"method"}],"getMultiBarWithFocusChart":[{"__symbolic":"method"}],"renderCommonProperty":[{"__symbolic":"method"}],"renderOperationArea":[{"__symbolic":"method"}],"timeFormat":[{"__symbolic":"method"}],"loadFirstPage":[{"__symbolic":"method"}],"loadNextPage":[{"__symbolic":"method"}],"loadPreviousPage":[{"__symbolic":"method"}],"loadLastPage":[{"__symbolic":"method"}],"initElementStatus":[{"__symbolic":"method"}],"updateElementStatus":[{"__symbolic":"method"}],"setStatusAsUnbound":[{"__symbolic":"method"}],"setStatusAsLoading":[{"__symbolic":"method"}],"setStatusAsLoadFailed":[{"__symbolic":"method"}],"renderStatus":[{"__symbolic":"method"}],"clearStatus":[{"__symbolic":"method"}]}}}}]
1
+ [{"__symbolic":"module","version":4,"metadata":{"HistoricalCurveElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":23,"character":44},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":71,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":72,"character":18},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":73,"character":27},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":74,"character":30},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":75,"character":23},{"__symbolic":"reference","module":"../../config","name":"HistoryDataStore","line":76,"character":43},{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","module":"../../service","name":"SystemTextLibraryService","line":78,"character":52},{"__symbolic":"reference","module":"../../service","name":"LanguageService","line":79,"character":43},{"__symbolic":"reference","module":"../../gui/gui-context","name":"GuiContext","line":80,"character":38}]}],"dispose":[{"__symbolic":"method"}],"initKeyboardListener":[{"__symbolic":"method"}],"subscribeLanguageChange":[{"__symbolic":"method"}],"updateLanguageTexts":[{"__symbolic":"method"}],"getCurrentCulture":[{"__symbolic":"method"}],"getValidTimePeriods":[{"__symbolic":"method"}],"getTimePeriodText":[{"__symbolic":"method"}],"updateTimeRange":[{"__symbolic":"method"}],"updateQueryTimeRange":[{"__symbolic":"method"}],"reRenderElement":[{"__symbolic":"method"}],"renderElement":[{"__symbolic":"method"}],"handleQueryResult":[{"__symbolic":"method"}],"setupTooltipAutoHide":[{"__symbolic":"method"}],"renderChart":[{"__symbolic":"method"}],"renderChartWithMultiItems":[{"__symbolic":"method"}],"initPoint":[{"__symbolic":"method"}],"getLineChart":[{"__symbolic":"method"}],"getMultiBarWithFocusChart":[{"__symbolic":"method"}],"renderCommonProperty":[{"__symbolic":"method"}],"renderOperationArea":[{"__symbolic":"method"}],"timeFormat":[{"__symbolic":"method"}],"loadFirstPage":[{"__symbolic":"method"}],"loadNextPage":[{"__symbolic":"method"}],"loadPreviousPage":[{"__symbolic":"method"}],"loadLastPage":[{"__symbolic":"method"}],"initElementStatus":[{"__symbolic":"method"}],"updateElementStatus":[{"__symbolic":"method"}],"setStatusAsUnbound":[{"__symbolic":"method"}],"setStatusAsLoading":[{"__symbolic":"method"}],"setStatusAsLoadFailed":[{"__symbolic":"method"}],"renderStatus":[{"__symbolic":"method"}],"clearStatus":[{"__symbolic":"method"}]}}}}]
@@ -213,6 +213,14 @@ export class NumericalDisplayElement extends ReadableElement {
213
213
  this.recordValue = result.value;
214
214
  const writeValue = this.dataTypeService.formatToDecimal(this.model.version, result.value, this.model.dataType);
215
215
  this.showValue = result.showValue;
216
+ // 如果是系统变量"当前语种ID",只更新显示,不执行变量写入和操作记录
217
+ if (this.writeVariableName === '当前语种ID') {
218
+ // 直接更新显示值
219
+ this.displayText = this.showValue;
220
+ this.updateDisplayText(this.formatDisplayTextUnit(this.displayText));
221
+ this.writeValueMmodalRef.hide();
222
+ return;
223
+ }
216
224
  if (this.displayText !== this.showValue || result.variableRwType === variableRwTypeEnum.witer) {
217
225
  if (this.numericalOperation || result.enableNumericalOperation || result.isNumericalOperation || result.variableRwType === variableRwTypeEnum.witer) {
218
226
  this.recordOperation(result.value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "main": "bundles/fc-gui.umd.js",
3
- "version": "3.0.0-alpha.127",
3
+ "version": "3.0.0-alpha.129",
4
4
  "module": "public_api.js",
5
5
  "typings": "public_api.d.ts",
6
6
  "license": "UNLICENSED",