File Coverage

blib/lib/Data/Terminal/Scoring.pm
Criterion Covered Total %
statement 12 91 13.1
branch 0 62 0.0
condition 0 11 0.0
subroutine 4 14 28.5
pod 3 3 100.0
total 19 181 10.5


line stmt bran cond sub pod time code
1             package Data::Terminal::Scoring;
2              
3 1     1   151586 use strict;
  1         2  
  1         67  
4 1     1   6 use warnings;
  1         11  
  1         70  
5 1     1   7 use Carp;
  1         2  
  1         74  
6 1     1   754 use utf8;
  1         357  
  1         10  
7              
8             our $VERSION = '0.01';
9              
10              
11             # 构造函数
12             sub new {
13 0     0 1   my $class = shift;
14 0           my $self = {};
15 0           bless $self, $class;
16 0           return $self;
17             }
18              
19             # 主要计算函数 - 计算终端最终得分
20             sub calculate_score {
21 0     0 1   my ($self, %params) = @_;
22            
23             # 验证输入参数
24 0           $self->_validate_params(%params);
25            
26             # 提取参数
27 0           my $service_years = $params{service_years}; # 服役年限
28 0           my $online_rate = $params{online_rate}; # 在线率(百分比)
29 0   0       my $remote_control_failures = $params{remote_control_failures} || 0; # 遥控失败次数
30 0   0       my $morning_check_failures = $params{morning_check_failures} || 0; # 晨操失败次数
31 0   0       my $abnormal_soe_signals = $params{abnormal_soe_signals} || 0; # 异常SOE信号数量
32 0   0       my $device_alarms = $params{device_alarms} || []; # 本体信号告警数组
33            
34             # 计算各项扣分
35 0           my $service_years_deduction = $self->_calculate_service_years_deduction($service_years);
36 0           my $online_rate_deduction = $self->_calculate_online_rate_deduction($online_rate);
37 0           my $remote_control_deduction = $self->_calculate_remote_control_deduction($remote_control_failures);
38 0           my $morning_check_deduction = $self->_calculate_morning_check_deduction($morning_check_failures);
39 0           my $soe_signal_deduction = $self->_calculate_soe_signal_deduction($abnormal_soe_signals);
40            
41             # 计算总扣分
42 0           my $total_deduction = $service_years_deduction + $online_rate_deduction +
43             $remote_control_deduction + $morning_check_deduction +
44             $soe_signal_deduction;
45            
46             # 计算开关系数
47 0           my $switch_coefficient = $self->_calculate_switch_coefficient($device_alarms);
48            
49             # 计算最终得分: 满分100 - 总扣分数 * 开关系数
50 0           my $final_score = 100 - ($total_deduction * $switch_coefficient);
51            
52             # 异常处理:确保得分在0-100范围内
53 0 0         $final_score = 0 if $final_score < 0;
54 0 0         $final_score = 100 if $final_score > 100;
55            
56             # 返回详细结果
57             return {
58 0           final_score => sprintf("%.2f", $final_score),
59             service_years_deduction => $service_years_deduction,
60             online_rate_deduction => $online_rate_deduction,
61             remote_control_deduction => $remote_control_deduction,
62             morning_check_deduction => $morning_check_deduction,
63             soe_signal_deduction => $soe_signal_deduction,
64             total_deduction => $total_deduction,
65             switch_coefficient => $switch_coefficient
66             };
67             }
68              
69             # 验证输入参数
70             sub _validate_params {
71 0     0     my ($self, %params) = @_;
72            
73             # 检查必要参数
74 0 0         croak "服役年限(service_years)是必需参数" unless defined $params{service_years};
75 0 0         croak "在线率(online_rate)是必需参数" unless defined $params{online_rate};
76            
77             # 检查参数范围
78 0 0         croak "服役年限必须大于等于0" if $params{service_years} < 0;
79 0 0 0       croak "在线率必须在0-100之间" if $params{online_rate} < 0 || $params{online_rate} > 100;
80            
81             # 检查可选参数
82 0 0         if (defined $params{remote_control_failures}) {
83 0 0         croak "遥控失败次数必须大于等于0" if $params{remote_control_failures} < 0;
84             }
85            
86 0 0         if (defined $params{morning_check_failures}) {
87 0 0         croak "晨操失败次数必须大于等于0" if $params{morning_check_failures} < 0;
88             }
89            
90 0 0         if (defined $params{abnormal_soe_signals}) {
91 0 0         croak "异常SOE信号数量必须大于等于0" if $params{abnormal_soe_signals} < 0;
92             }
93            
94 0 0         if (defined $params{device_alarms}) {
95 0 0         croak "设备告警必须是数组引用" unless ref $params{device_alarms} eq 'ARRAY';
96             }
97             }
98              
99             # 计算服役年限扣分 (共10分)
100             sub _calculate_service_years_deduction {
101 0     0     my ($self, $years) = @_;
102            
103 0 0         if ($years > 8) {
    0          
    0          
    0          
104 0           return 10; # 服役年限 > 8年 扣10分
105             } elsif ($years > 5) {
106 0           return 8; # 5年 < 运行年限 <= 8年 扣8分
107             } elsif ($years > 3) {
108 0           return 6; # 3年 < 运行年限 <= 5年 扣6分
109             } elsif ($years > 1) {
110 0           return 2; # 1年 < 运行年限 <= 3年 扣2分
111             } else {
112 0           return 0; # 运行年限<=1年 扣0分
113             }
114             }
115              
116             # 计算在线率扣分 (共30分)
117             sub _calculate_online_rate_deduction {
118 0     0     my ($self, $rate) = @_;
119            
120 0 0         if ($rate <= 70) {
    0          
    0          
    0          
121 0           return 30; # 终端在线率<=70% 扣30分
122             } elsif ($rate <= 80) {
123 0           return 20; # 终端在线率>70%, <=80% 扣20分
124             } elsif ($rate <= 90) {
125 0           return 10; # 终端在线率>80%, <=90% 扣10分
126             } elsif ($rate <= 95) {
127 0           return 5; # 终端在线率>90%, <=95% 扣5分
128             } else {
129 0           return 0; # 终端在线率> 95% 扣0分
130             }
131             }
132              
133             # 计算遥控扣分 (共30分)
134             sub _calculate_remote_control_deduction {
135 0     0     my ($self, $failures) = @_;
136            
137 0 0         if ($failures >= 3) {
    0          
    0          
138 0           return 30; # 指定周期内发生三次及以上遥控不成功 扣30分
139             } elsif ($failures == 2) {
140 0           return 20; # 指定周期内发生二次遥控不成功 扣20分
141             } elsif ($failures == 1) {
142 0           return 10; # 指定周期内发生一次遥控不成功 扣10分
143             } else {
144 0           return 0; # 指定周期内遥控全部正确或未发生遥控 扣0分
145             }
146             }
147              
148             # 计算晨操扣分 (共10分)
149             sub _calculate_morning_check_deduction {
150 0     0     my ($self, $failures) = @_;
151            
152 0 0         if ($failures >= 3) {
    0          
    0          
153 0           return 10; # 指定周期内发生三次及以上晨操不成功 扣10分
154             } elsif ($failures == 2) {
155 0           return 5; # 指定周期内发生二次晨操不成功 扣5分
156             } elsif ($failures == 1) {
157 0           return 2; # 指定周期内发生一次晨操不成功 扣2分
158             } else {
159 0           return 0; # 指定周期内晨操都正确 扣0分
160             }
161             }
162              
163             # 计算SOE信号扣分 (共20分)
164             sub _calculate_soe_signal_deduction {
165 0     0     my ($self, $abnormal_count) = @_;
166            
167 0 0         if ($abnormal_count > 25) {
168             # 超出25个的部分每一条扣1分,最多扣20分
169 0           my $excess = $abnormal_count - 25;
170 0 0         return $excess > 20 ? 20 : $excess;
171             } else {
172 0           return 0; # SOE信号数量不超过25个不扣分
173             }
174             }
175              
176             # 计算开关系数
177             sub _calculate_switch_coefficient {
178 0     0     my ($self, $alarms) = @_;
179            
180             # 定义本体信号告警类型
181 0           my %alarm_types = (
182             'power_module_outage' => '电源模块失电信号',
183             'power_module_battery_low' => '电源模块电池欠压告警',
184             'power_module_battery_fault' => '电源模块电池故障告警',
185             'device_abnormal_alarm' => '装置异常告警/控制器异常告警',
186             'charging_module_abnormal' => '充电模块异常',
187             'power_module_status_abnormal' => '电源模块运行状态异常',
188             'frequency_abnormal' => '频率异常',
189             'pt_disconnection' => 'pt断线',
190             'ct_disconnection' => 'ct断线',
191             'switch_input_abnormal' => '开入异常',
192             'reclosing_abnormal' => '重合闸异常',
193             'terminal_fault_alarm' => '终端故障告警',
194             'terminal_battery_low' => '终端电池欠压',
195             'control_circuit_disconnection' => '控制回路断线',
196             'control_circuit_status_abnormal' => '控制回路状态异常',
197             'ad_abnormal' => 'ad异常',
198             'digital_board_abnormal' => '数字板卡异常',
199             'analog_board_abnormal' => '模拟板卡异常',
200             'close_abnormal_flag' => '合异常标志',
201             'open_abnormal_flag' => '分异常标志',
202             'operation_circuit_abnormal' => '操作回路异常',
203             'complete_device_status_abnormal' => '成套装置运行状态异常',
204             'spring_not_charged' => '弹簧未储能'
205             );
206            
207             # 基础系数为1
208 0           my $coefficient = 1.0;
209            
210             # 统计有效告警数量(去重)
211 0           my %unique_alarms;
212 0           for my $alarm (@$alarms) {
213 0 0         if (exists $alarm_types{$alarm}) {
214 0           $unique_alarms{$alarm} = 1;
215             }
216             }
217            
218             # 每个有效告警增加0.1系数
219 0           my $alarm_count = scalar keys %unique_alarms;
220 0           $coefficient += ($alarm_count * 0.1);
221            
222 0           return $coefficient;
223             }
224              
225             # 获取支持的告警类型列表
226             sub get_supported_alarm_types {
227 0     0 1   my $self = shift;
228            
229             return [
230 0           'power_module_outage', # 电源模块失电信号
231             'power_module_battery_low', # 电源模块电池欠压告警
232             'power_module_battery_fault', # 电源模块电池故障告警
233             'device_abnormal_alarm', # 装置异常告警/控制器异常告警
234             'charging_module_abnormal', # 充电模块异常
235             'power_module_status_abnormal', # 电源模块运行状态异常
236             'frequency_abnormal', # 频率异常
237             'pt_disconnection', # pt断线
238             'ct_disconnection', # ct断线
239             'switch_input_abnormal', # 开入异常
240             'reclosing_abnormal', # 重合闸异常
241             'terminal_fault_alarm', # 终端故障告警
242             'terminal_battery_low', # 终端电池欠压
243             'control_circuit_disconnection', # 控制回路断线
244             'control_circuit_status_abnormal', # 控制回路状态异常
245             'ad_abnormal', # ad异常
246             'digital_board_abnormal', # 数字板卡异常
247             'analog_board_abnormal', # 模拟板卡异常
248             'close_abnormal_flag', # 合异常标志
249             'open_abnormal_flag', # 分异常标志
250             'operation_circuit_abnormal', # 操作回路异常
251             'complete_device_status_abnormal', # 成套装置运行状态异常
252             'spring_not_charged' # 弹簧未储能
253             ];
254             }
255              
256             1;
257              
258             __END__