You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

595 lines
18 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:include="include :: header('车辆全生命周期')" />
<style>
.detail-shell {
padding: 15px;
}
.summary-card,
.info-card,
.timeline-card {
background: #fff;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
margin-bottom: 16px;
}
.summary-card {
padding: 20px 24px;
}
.summary-title {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 16px;
}
.summary-name {
font-size: 34px;
font-weight: 700;
color: #2f4050;
line-height: 1.2;
margin-bottom: 10px;
word-break: break-all;
}
.summary-meta {
color: #666;
font-size: 14px;
line-height: 1.9;
}
.summary-counts {
min-width: 360px;
display: grid;
grid-template-columns: repeat(2, minmax(130px, 1fr));
gap: 10px;
}
.count-item {
border: 1px solid #edf1f2;
border-radius: 8px;
padding: 10px 12px;
background: #fafbfc;
}
.count-value {
font-size: 22px;
font-weight: 700;
color: #1c84c6;
line-height: 1.2;
}
.count-label {
color: #7a8590;
font-size: 12px;
margin-top: 4px;
}
.info-card {
padding: 18px 20px 10px;
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #2f4050;
margin-bottom: 14px;
}
.section-title i {
margin-right: 6px;
color: #666;
}
.info-table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
margin-bottom: 16px;
}
.info-table th,
.info-table td {
border: 1px solid #edf1f2;
padding: 12px 14px;
font-size: 14px;
word-break: break-all;
}
.info-table th {
width: 28%;
color: #7a8590;
font-weight: 500;
background: #fafbfc;
}
.info-table td {
color: #2f4050;
background: #fff;
}
.tyre-block {
border: 1px solid #edf1f2;
border-radius: 8px;
padding: 12px 14px;
margin-bottom: 12px;
background: #fff;
}
.tyre-title {
display: flex;
justify-content: space-between;
gap: 10px;
color: #2f4050;
font-weight: 600;
margin-bottom: 8px;
}
.tyre-meta {
color: #666;
font-size: 13px;
line-height: 1.8;
word-break: break-all;
}
.timeline-card {
padding: 18px 18px 12px;
min-height: 520px;
}
.timeline-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18px;
}
.timeline-header .title {
font-size: 18px;
font-weight: 600;
color: #2f4050;
}
.mini-tip {
font-size: 12px;
color: #999;
}
.life-list {
list-style: none;
padding: 0;
margin: 0;
position: relative;
}
.life-list:before {
content: "";
position: absolute;
left: 22px;
top: 8px;
bottom: 8px;
width: 2px;
background: #e4e7ea;
}
.life-item {
position: relative;
padding-left: 58px;
margin-bottom: 22px;
}
.life-dot {
position: absolute;
left: 12px;
top: 4px;
width: 22px;
height: 22px;
border-radius: 50%;
border: 3px solid #d7ebf8;
background: #1c84c6;
text-align: center;
color: #fff;
line-height: 16px;
font-size: 11px;
}
.life-dot.install {
background: #1c84c6;
border-color: #d7ebf8;
}
.life-dot.maintenance {
background: #f8ac59;
border-color: #fde6c8;
}
.life-dot.check {
background: #1ab394;
border-color: #d7f0eb;
}
.life-dot.mileage {
background: #23c6c8;
border-color: #d7f4f4;
}
.life-time {
color: #909399;
font-size: 12px;
margin-bottom: 4px;
}
.life-title {
color: #2f4050;
font-weight: 600;
margin-bottom: 8px;
word-break: break-all;
}
.life-body {
color: #666;
line-height: 1.7;
font-size: 13px;
}
.life-detail-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 6px 14px;
}
.life-detail {
min-width: 0;
word-break: break-all;
}
.life-detail .label-title {
color: #8a929a;
}
.life-description {
margin-top: 8px;
padding: 8px 10px;
border-left: 3px solid #e4e7ea;
background: #fafbfc;
color: #666;
word-break: break-all;
}
.text-muted-dash {
color: #999;
}
@media (max-width: 991px) {
.summary-title {
flex-direction: column;
}
.summary-counts {
min-width: 0;
width: 100%;
}
}
@media (max-width: 640px) {
.summary-counts,
.life-detail-grid {
grid-template-columns: 1fr;
}
.summary-name {
font-size: 26px;
}
}
</style>
</head>
<body class="gray-bg">
<div class="wrapper wrapper-content detail-shell">
<input id="carNo" type="hidden" th:value="${carNo}"/>
<div class="summary-card">
<div class="summary-title">
<div>
<div class="summary-name" id="summaryName">车辆:-</div>
<div class="summary-meta" id="summaryMeta">正在加载...</div>
</div>
<div class="summary-counts" id="summaryCounts"></div>
</div>
</div>
<div class="row">
<div class="col-lg-4 col-md-5 col-sm-12">
<div class="info-card">
<div class="section-title"><i class="fa fa-bookmark"></i>基本信息</div>
<table class="info-table" id="vehicleInfo"></table>
</div>
<div class="info-card">
<div class="section-title"><i class="fa fa-truck"></i>当前装车轮胎</div>
<div id="mountedTyres">
<div class="text-center text-muted-dash" style="padding: 40px 0;">正在加载...</div>
</div>
</div>
</div>
<div class="col-lg-8 col-md-7 col-sm-12">
<div class="timeline-card">
<div class="timeline-header">
<span class="title">生命周期时间轴</span>
<span class="mini-tip">按时间倒序展示,包含装卸、维保、质检、里程记录</span>
</div>
<ul class="life-list" id="timelineList"></ul>
<div class="text-center text-muted-dash" id="emptyTimeline" style="display: none; padding: 80px 0;">
暂无生命周期记录
</div>
</div>
</div>
</div>
</div>
<th:block th:include="include :: footer" />
<script th:inline="javascript">
var prefix = ctx + "tyre/car";
var carNo = $("#carNo").val();
$(function () {
loadLifecycle();
// 兜底关闭父窗口 loading避免 iframe 加载时序导致遮罩残留。
if (window.parent && window.parent !== window && window.parent.$ && window.parent.$.modal) {
window.parent.$.modal.closeLoading();
}
});
function loadLifecycle() {
$.get(prefix + "/lifecycle/" + encodeURIComponent(carNo), function (result) {
if (result.code != web_status.SUCCESS) {
$.modal.alertError(result.msg);
return;
}
var data = result.data || {};
renderSummary(data);
renderVehicleInfo(data.car || {});
renderMountedTyres(data.mountedTyres || []);
renderTimeline(data.recentEvents || []);
});
}
function renderSummary(data) {
var car = data.car || {};
$("#summaryName").html("车辆:" + safeText(car.carNo));
$("#summaryMeta").html([
"所属车队:" + safeText(car.team),
"线路:" + safeText(car.line),
"车型:" + safeText(car.type),
// "当前里程:" + safeText(car.inputMileage)
].join("<br/>"));
$("#summaryCounts").html([
countItem("装卸记录", data.installCount),
countItem("维保工单", data.maintenanceCount),
countItem("质检记录", data.checkCount),
countItem("里程记录", data.mileageCount)
].join(""));
}
function renderVehicleInfo(car) {
$("#vehicleInfo").html([
tableRow("车牌", car.carNo),
tableRow("车队", car.team),
tableRow("线路", car.line),
tableRow("车型", car.type),
// tableRow("车辆主键", car.carId),
// tableRow("部门ID", car.deptId),
// tableRow("最近工单里程", car.inputMileage)
].join(""));
}
function renderMountedTyres(rows) {
if (!rows.length) {
$("#mountedTyres").html('<div class="text-center text-muted-dash" style="padding: 40px 0;">暂无当前装车轮胎</div>');
return;
}
var html = [];
$.each(rows, function (index, item) {
// 当前装车轮胎作为车辆当前状态展示,便于和时间轴历史装卸节点互相核对。
html.push('<div class="tyre-block">');
html.push('<div class="tyre-title"><span>' + safeText(item.tyreNo || item.selfNo || item.tyreEpc) + '</span><span>' + safeText(item.wheelPostion) + '</span></div>');
html.push('<div class="tyre-meta">');
html.push('自编号:' + safeText(item.selfNo) + '<br/>');
html.push('RFID' + safeText(item.tyreEpc) + '<br/>');
html.push('品牌/规格:' + safeText(joinText(item.tyreBrand, item.tyreModel)) + '<br/>');
html.push('花纹深度:' + safeText(item.patternDepth));
html.push('</div></div>');
});
$("#mountedTyres").html(html.join(""));
}
function renderTimeline(rows) {
if (!rows.length) {
$("#timelineList").empty();
$("#emptyTimeline").show();
return;
}
$("#emptyTimeline").hide();
var html = [];
$.each(rows, function (index, item) {
html.push('<li class="life-item">');
html.push('<span class="life-dot ' + eventClass(item.eventType) + '">' + eventIcon(item.eventType) + '</span>');
html.push('<div class="life-time">' + safeText(item.eventTime) + '</div>');
html.push('<div class="life-title">' + safeText(eventTitle(item)) + '</div>');
html.push('<div class="life-body">' + eventDetails(item) + '</div>');
html.push('</li>');
});
$("#timelineList").html(html.join(""));
}
function eventDetails(item) {
var details = [];
if (item.eventType == "INSTALL") {
// 装卸节点保留轮胎、轮位、里程和花纹深度,方便追溯“何时装到哪个轮位、卸下时状态如何”。
details.push(detail("胎号", item.tyreNo));
details.push(detail("自编号", item.selfNo));
details.push(detail("RFID", item.tyreRfid));
details.push(detail("品牌/规格", joinText(item.tyreBrand, item.tyreModel)));
details.push(detail("轮位", item.wheelPostion));
details.push(detail("里程", item.mileage));
details.push(detail("花纹深度", item.patternDepth));
details.push(detail("动作", installTypeFormatter(item.status)));
} else if (item.eventType == "MAINTENANCE") {
// 工单节点展示工单号和站点,排查车辆维保历史时不用再跳转列表反查。
details.push(detail("工单号", item.orderNo));
details.push(detail("维保类型", orderTypeFormatter(item.typeCode)));
details.push(detail("状态", statusFormatter(item.status)));
details.push(detail("维修站点", item.factoryName));
details.push(detail("录入里程", item.inputMileage));
details.push(detail("上次里程", item.lastMileage));
details.push(detail("维保日期", item.maintainDate));
} else if (item.eventType == "CHECK") {
// 质检节点通过曾装车轮胎间接归属车辆,页面上明确展示轮胎身份,避免误以为质检表直接有车牌。
details.push(detail("胎号", item.tyreNo));
details.push(detail("自编号", item.selfNo));
details.push(detail("RFID", item.tyreRfid));
details.push(detail("品牌/规格", joinText(item.tyreBrand, item.tyreModel)));
details.push(detail("保养类型", item.maintenanceType));
details.push(detail("车辆里程", item.mileage));
details.push(detail("花纹深度", item.patternDepth));
details.push(detail("处理意见", item.result));
} else if (item.eventType == "MILEAGE") {
// 里程节点展示安装/卸下时间窗,提醒用户该记录是按轮胎 RFID 间接关联车辆。
details.push(detail("胎号", item.tyreNo));
details.push(detail("自编号", item.selfNo));
details.push(detail("RFID", item.tyreRfid));
details.push(detail("品牌/规格", joinText(item.tyreBrand, item.tyreModel)));
details.push(detail("安装时间", item.startTime));
details.push(detail("卸下时间", item.endTime));
details.push(detail("记录里程", item.mileage));
details.push(detail("花纹深度", item.patternDepth));
}
var html = '<div class="life-detail-grid">' + details.join("") + '</div>';
if (item.description) {
html += '<div class="life-description">补充说明:' + safeText(item.description) + '</div>';
}
return html;
}
function eventTitle(item) {
if (item.eventType == "INSTALL") {
return installTypeFormatter(item.status) + "轮胎:" + displayValue(item.tyreNo || item.selfNo || item.tyreRfid);
}
if (item.eventType == "MAINTENANCE") {
return orderTypeFormatter(item.typeCode) + "" + displayValue(item.orderNo);
}
if (item.eventType == "CHECK") {
return "轮胎质检:" + displayValue(item.tyreNo || item.selfNo || item.tyreRfid);
}
if (item.eventType == "MILEAGE") {
return "轮胎里程:" + displayValue(item.tyreNo || item.selfNo || item.tyreRfid);
}
return displayValue(item.eventType);
}
function eventClass(type) {
if (type == "MAINTENANCE") {
return "maintenance";
}
if (type == "CHECK") {
return "check";
}
if (type == "MILEAGE") {
return "mileage";
}
return "install";
}
function eventIcon(type) {
if (type == "MAINTENANCE") {
return "维";
}
if (type == "CHECK") {
return "检";
}
if (type == "MILEAGE") {
return "里";
}
return "装";
}
function detail(name, value) {
return '<div class="life-detail"><span class="label-title">' + safeText(name) + '</span>' + safeText(value) + '</div>';
}
function tableRow(name, value) {
return '<tr><th>' + safeText(name) + '</th><td>' + safeText(value) + '</td></tr>';
}
function countItem(name, value) {
return '<div class="count-item"><div class="count-value">' + safeText(value) + '</div><div class="count-label">' + safeText(name) + '</div></div>';
}
function joinText(left, right) {
var first = displayValue(left);
var second = displayValue(right);
if (first == "-" && second == "-") {
return "-";
}
return (first == "-" ? "" : first) + (second == "-" ? "" : " / " + second);
}
function displayValue(value) {
var text = $.common.nullToStr(value);
return text === "" ? "-" : text;
}
function safeText(value) {
return escapeHtml(displayValue(value));
}
function escapeHtml(value) {
return String(value)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}
function installTypeFormatter(value) {
if (value == "0") {
return "安装";
}
if (value == "1") {
return "卸下";
}
return displayValue(value);
}
function orderTypeFormatter(value) {
if (value == "1") {
return "二级保养";
}
if (value == "4") {
return "月检";
}
return displayValue(value);
}
function statusFormatter(value) {
if (value == "UNSTARTED") {
return "未开始";
}
if (value == "PROCESSING") {
return "执行中";
}
if (value == "COMPLETED") {
return "已完成";
}
return displayValue(value);
}
</script>
</body>
</html>