Commit 9d8acd40 authored by wanghao's avatar wanghao

1 托盘信息 预计老化结束时间 由之前的根据配置实时读取,改成单独存取,因为之前确认的是每次上料都是上同一类型的板子,老化时间是一样的,现在改成了可以随意老化不同类型的板子,所以时间显示不一样了。

parent 914df7d6
......@@ -74,3 +74,6 @@ WHERE
) OR
JOB_NAME LIKE 'COMM_%' OR -- 确保清理所有旧的通信任务
JOB_NAME LIKE 'FINAL_%'; -- 确保清理所有旧的最终任务
ALTER TABLE `t_storey_info`
ADD COLUMN `f_estimated_end_time` datetime DEFAULT NULL COMMENT '预计老化结束时间';
......@@ -12,7 +12,7 @@ import com.zehong.common.core.domain.BaseEntity;
/**
* 老化层信息对象 t_storey_info
*
*
* @author zehong
* @date 2025-05-29
*/
......@@ -91,6 +91,11 @@ public class TStoreyInfo extends BaseEntity
@Excel(name = "报警时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date fAlarmTime;
/** 预计结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "预计结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date estimatedEndTime;
/** 投料指令 */
private String feedingCommand;
......@@ -110,44 +115,44 @@ public class TStoreyInfo extends BaseEntity
this.fStoreyId = fStoreyId;
}
public Long getfStoreyId()
public Long getfStoreyId()
{
return fStoreyId;
}
public void setfEquipmentId(Long fEquipmentId)
public void setfEquipmentId(Long fEquipmentId)
{
this.fEquipmentId = fEquipmentId;
}
public Long getfEquipmentId()
public Long getfEquipmentId()
{
return fEquipmentId;
}
public void setfStoreyCode(String fStoreyCode)
public void setfStoreyCode(String fStoreyCode)
{
this.fStoreyCode = fStoreyCode;
}
public String getfStoreyCode()
public String getfStoreyCode()
{
return fStoreyCode;
}
public void setfIp(String fIp)
public void setfIp(String fIp)
{
this.fIp = fIp;
}
public String getfIp()
public String getfIp()
{
return fIp;
}
public void setfStatus(String fStatus)
public void setfStatus(String fStatus)
{
this.fStatus = fStatus;
}
public String getfStatus()
public String getfStatus()
{
return fStatus;
}
......@@ -183,25 +188,25 @@ public class TStoreyInfo extends BaseEntity
this.fUpdateTime = fUpdateTime;
}
public Date getfUpdateTime()
public Date getfUpdateTime()
{
return fUpdateTime;
}
public void setfCreateTime(Date fCreateTime)
public void setfCreateTime(Date fCreateTime)
{
this.fCreateTime = fCreateTime;
}
public Date getfCreateTime()
public Date getfCreateTime()
{
return fCreateTime;
}
public void setfAlarmTime(Date fAlarmTime)
public void setfAlarmTime(Date fAlarmTime)
{
this.fAlarmTime = fAlarmTime;
}
public Date getfAlarmTime()
public Date getfAlarmTime()
{
return fAlarmTime;
}
......@@ -238,6 +243,14 @@ public class TStoreyInfo extends BaseEntity
this.fAgingEndTime = fAgingEndTime;
}
public Date getEstimatedEndTime() {
return estimatedEndTime;
}
public void setEstimatedEndTime(Date estimatedEndTime) {
this.estimatedEndTime = estimatedEndTime;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
......@@ -251,6 +264,7 @@ public class TStoreyInfo extends BaseEntity
.append("fUpdateTime", getfUpdateTime())
.append("fCreateTime", getfCreateTime())
.append("fAlarmTime", getfAlarmTime())
.append("estimatedEndTime", getEstimatedEndTime())
.toString();
}
}
......@@ -9,7 +9,7 @@ import com.zehong.common.core.domain.BaseEntity;
/**
* 托盘信息对象 t_tray_info
*
*
* @author zehong
* @date 2025-06-06
*/
......@@ -54,66 +54,72 @@ public class TTrayInfo extends BaseEntity
@Excel(name = "老化开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date fAgingStartTime;
public void setfTrayId(Long fTrayId)
/** 预计结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "预计结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date estimatedEndTime;
public void setfTrayId(Long fTrayId)
{
this.fTrayId = fTrayId;
}
public Long getfTrayId()
public Long getfTrayId()
{
return fTrayId;
}
public void setfTrayCode(String fTrayCode)
public void setfTrayCode(String fTrayCode)
{
this.fTrayCode = fTrayCode;
}
public String getfTrayCode()
public String getfTrayCode()
{
return fTrayCode;
}
public void setfStoreyCode(String fStoreyCode)
public void setfStoreyCode(String fStoreyCode)
{
this.fStoreyCode = fStoreyCode;
}
public String getfStoreyCode()
public String getfStoreyCode()
{
return fStoreyCode;
}
public void setfStatus(String fStatus)
public void setfStatus(String fStatus)
{
this.fStatus = fStatus;
}
public String getfStatus()
public String getfStatus()
{
return fStatus;
}
public void setfBindingTime(Date fBindingTime)
public void setfBindingTime(Date fBindingTime)
{
this.fBindingTime = fBindingTime;
}
public Date getfBindingTime()
public Date getfBindingTime()
{
return fBindingTime;
}
public void setfUnbindingTime(Date fUnbindingTime)
public void setfUnbindingTime(Date fUnbindingTime)
{
this.fUnbindingTime = fUnbindingTime;
}
public Date getfUnbindingTime()
public Date getfUnbindingTime()
{
return fUnbindingTime;
}
public void setfCreateTime(Date fCreateTime)
public void setfCreateTime(Date fCreateTime)
{
this.fCreateTime = fCreateTime;
}
public Date getfCreateTime()
public Date getfCreateTime()
{
return fCreateTime;
}
......@@ -134,6 +140,14 @@ public class TTrayInfo extends BaseEntity
this.fAgingStartTime = fAgingStartTime;
}
public Date getEstimatedEndTime() {
return estimatedEndTime;
}
public void setEstimatedEndTime(Date estimatedEndTime) {
this.estimatedEndTime = estimatedEndTime;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
......@@ -145,6 +159,7 @@ public class TTrayInfo extends BaseEntity
.append("fUnbindingTime", getfUnbindingTime())
.append("fCreateTime", getfCreateTime())
.append("fAgingStartTime", getfAgingStartTime())
.append("estimatedEndTime", getEstimatedEndTime())
.toString();
}
}
......@@ -6,15 +6,15 @@ import org.apache.ibatis.annotations.Param;
/**
* 老化层信息Mapper接口
*
*
* @author zehong
* @date 2025-05-28
*/
public interface TStoreyInfoMapper
public interface TStoreyInfoMapper
{
/**
* 查询老化层信息
*
*
* @param fStoreyId 老化层信息ID
* @return 老化层信息
*/
......@@ -38,7 +38,7 @@ public interface TStoreyInfoMapper
public TStoreyInfo selectNearestFreeStorey();
/**
* 查询老化层信息列表
*
*
* @param tStoreyInfo 老化层信息
* @return 老化层信息集合
*/
......@@ -50,7 +50,7 @@ public interface TStoreyInfoMapper
/**
* 新增老化层信息
*
*
* @param tStoreyInfo 老化层信息
* @return 结果
*/
......@@ -60,19 +60,21 @@ public interface TStoreyInfoMapper
/**
* 修改老化层信息
*
*
* @param tStoreyInfo 老化层信息
* @return 结果
*/
public int updateTStoreyInfo(TStoreyInfo tStoreyInfo);
public int setStartRunningByCode(TStoreyInfo tStoreyInfo);
public int updateAllStatusAndAgingStartTime(TStoreyInfo tStoreyInfo);
public int updateBatch(@Param("storeyInfos") List<TStoreyInfo> storeyInfos);
/**
* 删除老化层信息
*
*
* @param fStoreyId 老化层信息ID
* @return 结果
*/
......@@ -80,7 +82,7 @@ public interface TStoreyInfoMapper
/**
* 批量删除老化层信息
*
*
* @param fStoreyIds 需要删除的数据ID
* @return 结果
*/
......
......@@ -203,6 +203,7 @@ public class TStoreyInfoServiceImpl implements ITStoreyInfoService
TStoreyInfo tStoreyInfo = new TStoreyInfo();
tStoreyInfo.setfStatus("0");
tStoreyInfo.setfAgingStartTime(null);
tStoreyInfo.setfAgingEndTime(null);
tStoreyInfoMapper.updateAllStatusAndAgingStartTime(tStoreyInfo);
}).join(); // 阻塞等待所有操作完成
}
......@@ -787,6 +788,7 @@ public class TStoreyInfoServiceImpl implements ITStoreyInfoService
tStoreyInfo.setfStatus("0");
tStoreyInfo.setfAgingStartTime(null);
tStoreyInfo.setfAgingEndTime(null);
tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);
}
return AjaxResult.success();
......
......@@ -4,21 +4,28 @@ import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.common.utils.DateUtils;
import com.zehong.system.domain.SysConfig;
import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.domain.TTrayInfo;
import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.ISysConfigService;
import com.zehong.system.service.ITEquipmentAlarmDataService;
import com.zehong.system.service.ITStoreyInfoService;
import com.zehong.system.service.ITTrayInfoService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
* @author lenovo
......@@ -44,6 +51,12 @@ public class AllCommandHandler {
@Resource
private DeviceTaskScheduler deviceTaskScheduler;
@Autowired
private ISysConfigService configService;
// 使用常量定义索引,避免魔法数字
private static final int AGING_STAGE_INDEX = 3;
private static final int DEFAULT_HOURS = 72;
/**
* check是否启动 ,没启动就启动下 开始老化
*
......@@ -72,9 +85,13 @@ public class AllCommandHandler {
if (!aBoolean) {
Modbus4jUtils.writeCoil(master, 1, registerOffset, true);
// 把预计老化结束时间保存到数据库中,因为可能会不同的老化时间
Date estimatedEndTime = getAgingEndTime();
TStoreyInfo tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoByCode(storeyCode);
tStoreyInfo.setfStatus("1");
tStoreyInfo.setfAgingStartTime(new Date());
tStoreyInfo.setEstimatedEndTime(estimatedEndTime);
tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);
// 同时 把 托盘的 状态更新
......@@ -96,7 +113,29 @@ public class AllCommandHandler {
}
}
public Date getAgingEndTime() {
List<SysConfig> sysConfigs = configService.selectAgingStageTime();
int milliseconds = getAgingMilliseconds(sysConfigs);
return DateUtils.addMilliseconds(new Date(), milliseconds);
}
private int getAgingMilliseconds(List<SysConfig> sysConfigs) {
try {
if (CollectionUtils.isNotEmpty(sysConfigs) &&
sysConfigs.size() > AGING_STAGE_INDEX) {
SysConfig config = sysConfigs.get(AGING_STAGE_INDEX);
if (config != null && StringUtils.isNotBlank(config.getConfigValue())) {
return Integer.parseInt(config.getConfigValue());
}
}
} catch (NumberFormatException e) {
log.warn("老化时间配置解析异常,使用默认值", e);
}
// 返回默认值(72小时转换为毫秒)
return DEFAULT_HOURS * 60 * 60 * 1000;
}
@Async // 异步执行
@EventListener(PowerOffCommandEvent.class)
public void handlePowerOffCommand(PowerOffCommandEvent event) {
......
......@@ -3,7 +3,7 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zehong.system.mapper.TStoreyInfoMapper">
<resultMap type="TStoreyInfo" id="TStoreyInfoResult">
<result property="fStoreyId" column="f_storey_id" />
<result property="fEquipmentId" column="f_equipment_id" />
......@@ -21,6 +21,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="blankingCommand" column="f_blanking_command" />
<result property="feedingCommand" column="f_feeding_command" />
<result property="estimatedEndTime" column="f_estimated_end_time" />
</resultMap>
<sql id="selectTStoreyInfoVo">
......@@ -32,6 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
storeyInfo.f_port,
storeyInfo.f_aging_start_time,
storeyInfo.f_aging_end_time,
storeyInfo.f_estimated_end_time,
storeyInfo.f_update_time,
storeyInfo.f_create_time,
storeyInfo.f_alarm_time,
......@@ -71,7 +74,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where storeyInfo.f_equipment_id = #{fEquipmentId}
order by storeyInfo.f_storey_id asc
</select>
<select id="selectTStoreyInfoById" parameterType="Long" resultMap="TStoreyInfoResult">
<include refid="selectTStoreyInfoVo"/>
where f_storey_id = #{fStoreyId}
......@@ -96,6 +99,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
f_port,
f_aging_start_time,
f_aging_end_time,
f_estimated_end_time,
f_update_time,
f_create_time,
f_alarm_time,
......@@ -147,6 +151,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="blankingCommand != null">f_blanking_command,</if>
<if test="feedingCommand != null">f_feeding_command,</if>
<if test="estimatedEndTime != null">f_estimated_end_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="fStoreyId != null">#{fStoreyId},</if>
......@@ -161,6 +166,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="blankingCommand != null">#{blankingCommand},</if>
<if test="feedingCommand != null">#{feedingCommand},</if>
<if test="estimatedEndTime != null">#{estimatedEndTime},</if>
</trim>
</insert>
......@@ -193,6 +199,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="blankingCommand != null">f_blanking_command = #{blankingCommand},</if>
<if test="feedingCommand != null">f_feeding_command = #{feedingCommand},</if>
<if test="estimatedEndTime != null">f_estimated_end_time = #{estimatedEndTime},</if>
</trim>
where f_storey_id = #{fStoreyId}
</update>
......@@ -204,13 +211,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="fAgingStartTime == null">f_aging_start_time = null,</if>
<if test="fAgingEndTime != null">f_aging_end_time = #{fAgingEndTime},</if>
<if test="fAgingEndTime == null">f_aging_end_time = null,</if>
<if test="estimatedEndTime != null">f_estimated_end_time = #{estimatedEndTime},</if>
<if test="estimatedEndTime == null">f_estimated_end_time = null,</if>
</trim>
where f_storey_id = #{fStoreyId}
</update>
<update id="setStartRunningByCode" parameterType="TStoreyInfo">
update t_storey_info
<trim prefix="SET" suffixOverrides=",">
<if test="fStatus != null">f_status = #{fStatus},</if>
<if test="fAgingStartTime != null">f_aging_start_time = #{fAgingStartTime},</if>
<if test="fAgingEndTime != null">f_aging_end_time = #{fAgingEndTime},</if>
<if test="estimatedEndTime != null">f_estimated_end_time = #{estimatedEndTime},</if>
</trim>
</update>
<update id="unbindByCode" parameterType="TStoreyInfo">
update t_storey_info
set f_status = '0', f_aging_start_time = null,f_aging_end_time = null
set f_status = '0', f_aging_start_time = null,f_aging_end_time = null,f_estimated_end_time = null
where f_storey_code = #{fStoreyCode}
</update>
<update id="updateStatusByCode" parameterType="TStoreyInfo">
......@@ -226,9 +244,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<delete id="deleteTStoreyInfoByIds" parameterType="String">
delete from t_storey_info where f_storey_id in
delete from t_storey_info where f_storey_id in
<foreach item="fStoreyId" collection="array" open="(" separator="," close=")">
#{fStoreyId}
</foreach>
</delete>
</mapper>
\ No newline at end of file
</mapper>
......@@ -3,7 +3,7 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zehong.system.mapper.TTrayInfoMapper">
<resultMap type="TTrayInfo" id="TTrayInfoResult">
<result property="fTrayId" column="f_tray_id" />
<result property="fTrayCode" column="f_tray_code" />
......@@ -13,6 +13,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="fUnbindingTime" column="f_unbinding_time" />
<result property="fCreateTime" column="f_create_time" />
<result property="fAgingStartTime" column="f_aging_start_time" />
<result property="estimatedEndTime" column="f_estimated_end_time" />
</resultMap>
<sql id="selectTTrayInfoVo">
......@@ -25,7 +26,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
trayInfo.f_unbinding_time,
trayInfo.f_create_time,
( SELECT count( 1 ) FROM t_pallet_device_binding WHERE f_tray_id = trayInfo.f_tray_id AND ( f_device_code != '' ) AND f_unbinding_time IS NULL ) AS boardCount ,
storeyInfo.f_aging_start_time
storeyInfo.f_aging_start_time,
storeyInfo.f_estimated_end_time
FROM
t_tray_info trayInfo
LEFT JOIN t_storey_info storeyInfo ON trayInfo.f_storey_code = storeyInfo.f_storey_code
......@@ -33,7 +35,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectTTrayInfoList" parameterType="TTrayInfo" resultMap="TTrayInfoResult">
<include refid="selectTTrayInfoVo"/>
<where>
<where>
<if test="fTrayCode != null and fTrayCode != ''"> and trayInfo.f_tray_code like concat('%',#{fTrayCode},'%')</if>
<if test="fStoreyCode != null and fStoreyCode != ''"> and trayInfo.f_storey_code = #{fStoreyCode}</if>
<if test="fStatus != null and fStatus != ''"> and trayInfo.f_status = #{fStatus}</if>
......@@ -43,7 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where>
ORDER BY trayInfo.f_tray_id
</select>
<select id="selectTTrayInfoById" parameterType="Long" resultMap="TTrayInfoResult">
<include refid="selectTTrayInfoVo"/>
where trayInfo.f_tray_id = #{fTrayId}
......@@ -56,7 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectTTrayInfoVo"/>
where trayInfo.f_storey_code = #{fStoreyCode}
</select>
<insert id="insertTTrayInfo" parameterType="TTrayInfo" useGeneratedKeys="true" keyProperty="fTrayId">
insert into t_tray_info
<trim prefix="(" suffix=")" suffixOverrides=",">
......@@ -140,9 +142,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<delete id="deleteTTrayInfoByIds" parameterType="String">
delete from t_tray_info where f_tray_id in
delete from t_tray_info where f_tray_id in
<foreach item="fTrayId" collection="array" open="(" separator="," close=")">
#{fTrayId}
</foreach>
</delete>
</mapper>
\ No newline at end of file
</mapper>
......@@ -85,7 +85,7 @@
<!-- 可滚动列:预计老化结束时间 -->
<el-table-column prop="fAgingEndTime" label="预计老化结束时间" align="center" width="200">
<template slot-scope="scope">
<div class="device-code">{{ scope.row.fAgingEndTime ? formatDate(scope.row.fAgingEndTime) : '-' }}</div>
<div class="device-code">{{ scope.row.estimatedEndTime ? formatDate(scope.row.estimatedEndTime) : '-' }}</div>
</template>
</el-table-column>
<!-- 可滚动列:主板数量 -->
......@@ -146,7 +146,8 @@ export default {
// 动态列宽
boardCountWidth: '150',
locationWidth: '150',
agingStage4Time: 0,
// // 把预计老化结束时间保存到数据库中,因为可能会不同的老化时间
// agingStage4Time: 0,
};
},
created() {
......@@ -159,7 +160,8 @@ export default {
this.$nextTick(() => {
this.adjustTableLayout();
});
this.initAgingStage4Time();
//// 把预计老化结束时间保存到数据库中,因为可能会不同的老化时间
// this.initAgingStage4Time();
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
......@@ -217,26 +219,28 @@ export default {
// 获取托盘数据
fetchTrays() {
listTray(this.queryParams).then(response => {
this.trays = response.rows.map(item => {
// 如果是运行中状态且有老化开始时间,计算预计老化结束时间
if (item.fStatus === '1' && item.fAgingStartTime) {
try {
// 将开始时间转换为Date对象
const startTime = new Date(item.fAgingStartTime);
// 加上配置的分钟数(agingStage3Time以分钟为单位)
const endTime = new Date(startTime.getTime() + this.agingStage4Time * 60 * 1000);
// 添加到item对象中
item.fAgingEndTime = endTime;
} catch (e) {
console.error('计算预计老化结束时间失败:', e);
item.fAgingEndTime = null;
}
} else {
item.fAgingEndTime = null;
item.fAgingStartTime = null;
}
return item;
});
// // 把预计老化结束时间保存到数据库中,因为可能会不同的老化时间
// this.trays = response.rows.map(item => {
// // 如果是运行中状态且有老化开始时间,计算预计老化结束时间
// if (item.fStatus === '1' && item.fAgingStartTime) {
// try {
// // 将开始时间转换为Date对象
// const startTime = new Date(item.fAgingStartTime);
// // 加上配置的分钟数(agingStage3Time以分钟为单位)
// const endTime = new Date(startTime.getTime() + this.agingStage4Time * 60 * 1000);
// // 添加到item对象中
// item.fAgingEndTime = endTime;
// } catch (e) {
// console.error('计算预计老化结束时间失败:', e);
// item.fAgingEndTime = null;
// }
// } else {
// item.fAgingEndTime = null;
// item.fAgingStartTime = null;
// }
// return item;
// });
this.trays = response.rows;
this.total = response.total;
this.loading = false;
// 数据加载完成后调整表格布局
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment