2025-12-11 09:17:16 +08:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<title>透传设置界面</title>
|
|
|
|
|
|
<style type="text/css">
|
|
|
|
|
|
*
|
|
|
|
|
|
{
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
:root
|
|
|
|
|
|
{
|
|
|
|
|
|
--primary-color: #4361ee;
|
|
|
|
|
|
--primary-hover: #3a56d4;
|
|
|
|
|
|
--success-color: #2ecc71;
|
|
|
|
|
|
--success-hover: #27ae60;
|
|
|
|
|
|
--warning-color: #f39c12;
|
|
|
|
|
|
--danger-color: #e74c3c;
|
|
|
|
|
|
--light-bg: #f8f9fa;
|
|
|
|
|
|
--card-bg: #ffffff;
|
|
|
|
|
|
--border-color: #e9ecef;
|
|
|
|
|
|
--text-primary: #2c3e50;
|
|
|
|
|
|
--text-secondary: #7f8c8d;
|
|
|
|
|
|
--shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
--radius: 10px;
|
|
|
|
|
|
--transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
body
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
font-family: 'Segoe UI' , 'PingFang SC' , 'Microsoft YaHei' , sans-serif;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
|
2026-01-09 14:52:58 +08:00
|
|
|
|
padding: 12px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.container
|
|
|
|
|
|
{
|
2026-01-09 14:52:58 +08:00
|
|
|
|
max-width: 1440px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background: var(--card-bg);
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
box-shadow: var(--shadow);
|
2026-01-09 14:52:58 +08:00
|
|
|
|
margin-bottom: 10px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
border: 1px solid var(--border-color);
|
|
|
|
|
|
transition: var(--transition);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
.card:hover
|
|
|
|
|
|
{
|
|
|
|
|
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
.card-header
|
|
|
|
|
|
{
|
2026-01-09 15:01:25 +08:00
|
|
|
|
background: linear-gradient(135deg, #24b6aa, #1ba59e);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
color: white;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
padding: 8px 12px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
font-weight: 600;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
font-size: 1rem;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-header i
|
|
|
|
|
|
{
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
font-size: 1.2rem;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-content
|
|
|
|
|
|
{
|
2026-01-09 14:52:58 +08:00
|
|
|
|
padding: 10px 12px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-row
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
flex-wrap: nowrap;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
overflow-x: auto;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
2026-01-09 14:52:58 +08:00
|
|
|
|
|
|
|
|
|
|
/* 使主机编号行内排列 */
|
|
|
|
|
|
.form-row > .form-group:first-child {
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 状态放最右 */
|
|
|
|
|
|
.form-row .status-indicator {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
align-self: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 单行显示单选项 */
|
|
|
|
|
|
.radio-options { flex-wrap: nowrap; gap: 8px; }
|
|
|
|
|
|
.checkbox-group label, .radio-option label { font-size: 0.85rem; margin-bottom: 0; }
|
2025-12-11 09:17:16 +08:00
|
|
|
|
|
|
|
|
|
|
.form-group
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
flex: 0 1 auto;
|
|
|
|
|
|
min-width: 0;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-row-inline
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
flex-wrap: nowrap;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
padding: 6px 8px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: #f8fafc;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
overflow-x: auto;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
label
|
|
|
|
|
|
{
|
2026-01-09 14:52:58 +08:00
|
|
|
|
font-size: 0.85rem;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
font-weight: 600;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
margin-bottom: 6px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.label-icon
|
|
|
|
|
|
{
|
|
|
|
|
|
margin-right: 6px;
|
|
|
|
|
|
color: var(--primary-color);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
input, textarea, select, button
|
2025-12-11 09:17:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
font-family: inherit;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
font-size: 0.95rem;
|
|
|
|
|
|
transition: var(--transition);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
input[type="text"], input[type="number"], textarea, select
|
2025-12-11 09:17:16 +08:00
|
|
|
|
{
|
2026-01-09 14:52:58 +08:00
|
|
|
|
padding: 6px 8px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
border: 2px solid #e0e6ef;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
border-radius: 6px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
transition: var(--transition);
|
2026-01-09 14:52:58 +08:00
|
|
|
|
height: 32px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
input[type="text"]:focus, input[type="number"]:focus, textarea:focus, select:focus
|
2025-12-11 09:17:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
outline: none;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
border-color: var(--primary-color);
|
|
|
|
|
|
box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.15);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
textarea
|
|
|
|
|
|
{
|
2026-01-09 14:52:58 +08:00
|
|
|
|
min-height: 64px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
resize: vertical;
|
|
|
|
|
|
width: 100%;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
line-height: 1.4;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
button
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: var(--primary-color);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
color: white;
|
|
|
|
|
|
border: none;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
border-radius: 8px;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
padding: 10px 16px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
cursor: pointer;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
transition: var(--transition);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
button:hover
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: var(--primary-hover);
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(67, 97, 238, 0.25);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
button:active
|
|
|
|
|
|
{
|
|
|
|
|
|
transform: translateY(0);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#send
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: var(--success-color);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#send:hover
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: var(--success-hover);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.checkbox-group, .radio-group
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-options
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin-bottom: 12px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-option
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
gap: 6px;
|
|
|
|
|
|
padding: 6px 8px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: #f8fafc;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
border-radius: 6px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
border: 2px solid #e0e6ef;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: var(--transition);
|
2026-01-09 14:52:58 +08:00
|
|
|
|
font-size: 0.92rem;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-option:hover
|
|
|
|
|
|
{
|
|
|
|
|
|
border-color: var(--primary-color);
|
|
|
|
|
|
background-color: #f0f4ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-option input[type="radio"]
|
|
|
|
|
|
{
|
|
|
|
|
|
margin-right: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.port-group
|
|
|
|
|
|
{
|
|
|
|
|
|
display: grid;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-bottom: 8px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.port-item
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
gap: 6px;
|
|
|
|
|
|
padding: 8px 10px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
background-color: #f8fafc;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
border-radius: 6px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
display: none; /* 默认隐藏 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.port-item.visible
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex; /* 显示时使用 flex 布局 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.port-item-header
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.port-item-content
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.inline-group
|
|
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
.input-with-label
|
2025-12-11 09:17:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
gap: 6px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
.input-with-label label
|
|
|
|
|
|
{
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
.message-container
|
|
|
|
|
|
{
|
2026-01-09 14:52:58 +08:00
|
|
|
|
max-height: 95vh;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
overflow-y: auto;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
border: 1px solid var(--border-color);
|
|
|
|
|
|
border-radius: 8px;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
padding: 8px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
background-color: #f8f9fa;
|
|
|
|
|
|
font-family: 'Courier New' , monospace;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
font-size: 0.9rem;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
2026-01-09 14:52:58 +08:00
|
|
|
|
|
|
|
|
|
|
.message-table
|
|
|
|
|
|
{
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
border-collapse: collapse;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-table th,
|
|
|
|
|
|
.message-table td
|
|
|
|
|
|
{
|
|
|
|
|
|
border-bottom: 1px solid #e9ecef;
|
|
|
|
|
|
padding: 6px 8px;
|
|
|
|
|
|
vertical-align: top;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-table th
|
|
|
|
|
|
{
|
|
|
|
|
|
position: sticky;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
|
z-index: 1;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-row-sent
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #e8f5e9;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-row-received
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #e3f2fd;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 紧凑布局样式 */
|
|
|
|
|
|
#btn_set { padding: 6px 10px; font-size: 0.92rem; height: 32px; }
|
|
|
|
|
|
#send { padding: 8px 12px; height: 34px; }
|
|
|
|
|
|
#txthostnumber { max-width: 300px; width: 300px; }
|
|
|
|
|
|
#protocoltype { width: 72px; }
|
|
|
|
|
|
#Port_2, #Byte_Speed, #moshi_id { width: 100px; }
|
|
|
|
|
|
#tm2, #tm4 { width: 100px; }
|
|
|
|
|
|
.form-row { gap: 8px; }
|
|
|
|
|
|
.form-row-inline { gap: 8px; }
|
|
|
|
|
|
/* 指定 port-group 内的 select 字体大小为 14px */
|
|
|
|
|
|
.port-group select, .port-item select { font-size: 12px; }
|
|
|
|
|
|
.port-group select option { font-size: 15px; }
|
2025-12-11 09:17:16 +08:00
|
|
|
|
|
|
|
|
|
|
.message-item
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
padding: 10px 12px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
border-bottom: 1px solid #e9ecef;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-item:last-child
|
|
|
|
|
|
{
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
.message-time
|
|
|
|
|
|
{
|
|
|
|
|
|
font-size: 0.8rem;
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
margin-right: 15px;
|
|
|
|
|
|
min-width: 120px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-delta
|
|
|
|
|
|
{
|
|
|
|
|
|
font-size: 0.75rem;
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
margin-top: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-content
|
|
|
|
|
|
{
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-sent
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #e8f5e9;
|
|
|
|
|
|
border-left: 4px solid var(--success-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-received
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #e3f2fd;
|
|
|
|
|
|
border-left: 4px solid var(--primary-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
#result
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
margin-top: 15px;
|
|
|
|
|
|
padding: 12px 15px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
font-size: 0.9rem;
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.success
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #d4edda;
|
|
|
|
|
|
color: #155724;
|
|
|
|
|
|
border-left: 4px solid var(--success-color);
|
|
|
|
|
|
display: block !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.error
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #f8d7da;
|
|
|
|
|
|
color: #721c24;
|
|
|
|
|
|
border-left: 4px solid var(--danger-color);
|
|
|
|
|
|
display: block !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.info-box
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #e7f3ff;
|
|
|
|
|
|
border-left: 4px solid var(--primary-color);
|
2026-01-09 14:52:58 +08:00
|
|
|
|
padding: 8px 10px;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
border-radius: 8px;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
font-size: 0.88rem;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-indicator
|
|
|
|
|
|
{
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
gap: 6px;
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
font-size: 0.82rem;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-connected
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #d4edda;
|
|
|
|
|
|
color: #155724;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-disconnected
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: #f8d7da;
|
|
|
|
|
|
color: #721c24;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-dot
|
|
|
|
|
|
{
|
|
|
|
|
|
width: 8px;
|
|
|
|
|
|
height: 8px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-connected .status-dot
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: var(--success-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-disconnected .status-dot
|
|
|
|
|
|
{
|
|
|
|
|
|
background-color: var(--danger-color);
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px)
|
|
|
|
|
|
{
|
2026-01-09 13:45:30 +08:00
|
|
|
|
.container
|
|
|
|
|
|
{
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-content
|
|
|
|
|
|
{
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-row, .port-group
|
2025-12-11 09:17:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
flex-direction: column;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
gap: 15px;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-group
|
|
|
|
|
|
{
|
|
|
|
|
|
width: 100%;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
min-width: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-options
|
|
|
|
|
|
{
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.port-item-content
|
|
|
|
|
|
{
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: flex-start;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
|
|
|
|
|
/* 自定义复选框和单选框样式 */
|
|
|
|
|
|
input[type="checkbox"], input[type="radio"]
|
|
|
|
|
|
{
|
|
|
|
|
|
width: 18px;
|
|
|
|
|
|
height: 18px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 滚动条样式 */
|
|
|
|
|
|
::-webkit-scrollbar
|
|
|
|
|
|
{
|
|
|
|
|
|
width: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::-webkit-scrollbar-track
|
|
|
|
|
|
{
|
|
|
|
|
|
background: #f1f1f1;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::-webkit-scrollbar-thumb
|
|
|
|
|
|
{
|
|
|
|
|
|
background: #c1c1c1;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::-webkit-scrollbar-thumb:hover
|
|
|
|
|
|
{
|
|
|
|
|
|
background: #a8a8a8;
|
|
|
|
|
|
}
|
2025-12-11 09:17:16 +08:00
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<div class="container">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<!-- 设置发送透传卡片(合并:设置透传 + 发送内容) -->
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<div class="card">
|
|
|
|
|
|
<div class="card-header">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<i class="fas fa-cogs"></i>设置发送透传
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-content">
|
|
|
|
|
|
<div class="info-box">
|
|
|
|
|
|
<i class="fas fa-info-circle"></i>请输入主机编号以建立透传连接。连接成功后,您可以发送和接收数据。
|
2025-12-11 09:17:16 +08:00
|
|
|
|
</div>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<div class="form-row">
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label for="txthostnumber">
|
|
|
|
|
|
<i class="fas fa-desktop label-icon"></i>主机编号:
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input id="txthostnumber" type="text" placeholder="请输入主机编号" required>
|
|
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<div class="form-group" style="align-self: center;">
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<button id="btn_set">
|
|
|
|
|
|
<i class="fas fa-plug"></i>连接设备
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<div class="status-indicator status-disconnected" id="connection-status" style="margin-left:auto;">
|
|
|
|
|
|
<span class="status-dot"></span><span></span>
|
|
|
|
|
|
</div>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<div id="result"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<div style="height: 12px;"></div>
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<div class="form-row-inline">
|
|
|
|
|
|
<div class="checkbox-group">
|
|
|
|
|
|
<input id="isprotocol" type="checkbox" checked>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label for="isprotocol" style="margin-bottom: 0;">自动加上协议头</label>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<div class="form-group" style="flex-direction: row; align-items: center; gap: 8px; flex: 0 1 auto;">
|
|
|
|
|
|
<label for="protocoltype" style="margin-bottom: 0;">协议类型:</label>
|
|
|
|
|
|
<input id="protocoltype" type="text" value="70" placeholder="默认是70" style="width: 72px;">
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<div class="radio-options" style="flex-wrap:nowrap; margin-left:8px;">
|
|
|
|
|
|
<div class="radio-option">
|
|
|
|
|
|
<input id="readmode" type="radio" name="mode" value="读取模式" checked>
|
|
|
|
|
|
<label for="readmode" style="margin-bottom: 0;">读取模式</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="radio-option">
|
|
|
|
|
|
<input id="setmode" type="radio" name="mode" value="设置模式">
|
|
|
|
|
|
<label for="setmode" style="margin-bottom: 0;">设置模式</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="radio-option">
|
|
|
|
|
|
<input id="sendmode" type="radio" name="mode" value="发送模式">
|
|
|
|
|
|
<label for="sendmode" style="margin-bottom: 0;">发送模式</label>
|
|
|
|
|
|
</div>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<div class="port-group">
|
|
|
|
|
|
<div class="port-item visible" id="p1">
|
|
|
|
|
|
<div class="port-item-header">
|
|
|
|
|
|
<span><strong>Port 1</strong></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="port-item-content">
|
|
|
|
|
|
<div class="input-with-label">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label>端口:</label>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<select id="Port_1">
|
|
|
|
|
|
<option value="01">轮询</option>
|
|
|
|
|
|
<option value="02">主动</option>
|
|
|
|
|
|
<option value="03">总线BUS</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="port-item" id="p2">
|
|
|
|
|
|
<div class="port-item-header">
|
|
|
|
|
|
<span><strong>Port 2</strong></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="port-item-content">
|
|
|
|
|
|
<div class="input-with-label">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label>模式:</label>
|
|
|
|
|
|
<select id="Port_2" style="width: 100px;">
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<option value="01">轮询</option>
|
|
|
|
|
|
<option value="02">主动</option>
|
|
|
|
|
|
<option value="03">总线BUS</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="input-with-label">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label>超时:</label>
|
|
|
|
|
|
<input type="text" name="timeout" id="tm2" placeholder="超时16进制" style="width: 100px;" />
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="port-item-content">
|
|
|
|
|
|
<div class="input-with-label">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label>波特率:</label>
|
|
|
|
|
|
<select id="Byte_Speed" style="width: 100px;">
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<option value="01">9600</option>
|
|
|
|
|
|
<option value="02">14400</option>
|
|
|
|
|
|
<option value="03">19200</option>
|
|
|
|
|
|
<option value="04">38400</option>
|
|
|
|
|
|
<option value="05">56000</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="input-with-label">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label>模式:</label>
|
|
|
|
|
|
<select id="moshi_id" style="width: 100px;">
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<option value="01">正常模式</option>
|
|
|
|
|
|
<option value="02">进入透传</option>
|
|
|
|
|
|
<option value="03">进入监控</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="port-item" id="p3">
|
|
|
|
|
|
<div class="port-item-header">
|
|
|
|
|
|
<span><strong>Port 4</strong></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="port-item-content">
|
|
|
|
|
|
<div class="input-with-label">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label>端口:</label>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<select id="Port_4">
|
|
|
|
|
|
<option value="01">轮询</option>
|
|
|
|
|
|
<option value="02">主动</option>
|
|
|
|
|
|
<option value="03">总线BUS</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="input-with-label">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<label>超时:</label>
|
|
|
|
|
|
<input type="text" name="timeout" id="tm4" placeholder="超时(16进制)" style="width: 100px;" />
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<div id="div_content">
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label for="content">
|
|
|
|
|
|
<i class="fas fa-code label-icon"></i>透传内容(16进制):
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<textarea id="content" placeholder="请输入16进制内容,例如: 01 02 03 0A 0B"></textarea>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-09 14:52:58 +08:00
|
|
|
|
|
|
|
|
|
|
<div style="display: flex; justify-content: flex-start; margin-top: 8px;">
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<button id="send">
|
|
|
|
|
|
<i class="fas fa-paper-plane"></i>发送内容
|
|
|
|
|
|
</button>
|
2025-12-11 09:17:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<!-- 接收数据卡片 -->
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
|
<div class="card-header">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<i class="fas fa-download"></i>下位机透传数据
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-content">
|
|
|
|
|
|
<div id="touchuan_content" class="message-container">
|
2026-01-09 14:52:58 +08:00
|
|
|
|
<table class="message-table">
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th style="width: 130px;">时间</th>
|
|
|
|
|
|
<th style="width: 70px;">间隔</th>
|
|
|
|
|
|
<th style="width: 90px;">设备</th>
|
|
|
|
|
|
<th style="width: 80px;">地址</th>
|
|
|
|
|
|
<th style="width: 90px;">设备类型</th>
|
|
|
|
|
|
<th style="width: 120px;">参数</th>
|
|
|
|
|
|
<th>原始数据</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody id="touchuan_tbody">
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div style="display: flex; justify-content: space-between; margin-top: 15px;">
|
|
|
|
|
|
<button id="clear-btn" style="background-color: var(--text-secondary);">
|
|
|
|
|
|
<i class="fas fa-trash"></i>清空记录
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
2025-12-11 09:17:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<script src="Scripts/jquery-1.8.3.min.js" type="text/javascript"></script>
|
|
|
|
|
|
<script src="Scripts/mqtt.min.js" type="text/javascript"></script>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
<script type="text/javascript">
|
|
|
|
|
|
// 连接状态
|
|
|
|
|
|
let isConnected = false;
|
|
|
|
|
|
let isPaused = false;
|
|
|
|
|
|
let mqttClient = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 上一条“接收(设备上报)”消息到达时间(用于计算时间差,毫秒)
|
|
|
|
|
|
let lastReceivedAtMs = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前时间
|
|
|
|
|
|
function getCurrentTime(date) {
|
|
|
|
|
|
const now = date || new Date();
|
|
|
|
|
|
return `${now.getHours().toString().padStart(2, '0')}:` +
|
|
|
|
|
|
`${now.getMinutes().toString().padStart(2, '0')}:` +
|
|
|
|
|
|
`${now.getSeconds().toString().padStart(2, '0')}.` +
|
|
|
|
|
|
`${now.getMilliseconds().toString().padStart(3, '0')}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MQTT 接收数据裁剪:去掉前 17 字节固定头、去掉末尾 2 字节 CRC,仅保留中间 payload
|
|
|
|
|
|
// 例:AA 55 ... 02 01 [payload...] 20 A9
|
|
|
|
|
|
function extractMiddlePayload(hexString) {
|
|
|
|
|
|
if (!hexString) return '';
|
|
|
|
|
|
|
|
|
|
|
|
// 提取 2位十六进制 token,忽略空格/其它分隔符
|
|
|
|
|
|
const tokens = (hexString.match(/[0-9a-fA-F]{2}/g) || []).map(t => t.toUpperCase());
|
|
|
|
|
|
if (tokens.length === 0) return '';
|
|
|
|
|
|
|
|
|
|
|
|
const headerLen = 17;
|
|
|
|
|
|
const crcLen = 2;
|
|
|
|
|
|
if (tokens.length <= headerLen + crcLen) {
|
|
|
|
|
|
return tokens.join(' ');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tokens.slice(headerLen, tokens.length - crcLen).join(' ');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加消息到显示区域
|
|
|
|
|
|
function addMessage(content,is_sent) {
|
|
|
|
|
|
if (isPaused) return;
|
|
|
|
|
|
|
|
|
|
|
|
const nowMs = Date.now();
|
|
|
|
|
|
const nowDate = new Date(nowMs);
|
|
|
|
|
|
|
2026-01-09 14:52:58 +08:00
|
|
|
|
let messageRowClass = 'message-row-received';
|
2026-01-09 13:45:30 +08:00
|
|
|
|
if (is_sent)
|
|
|
|
|
|
{
|
2026-01-09 14:52:58 +08:00
|
|
|
|
messageRowClass="message-row-sent";
|
2026-01-09 13:45:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 仅对“接收”消息计算与上一条接收消息的时间差(毫秒)
|
2026-01-09 14:52:58 +08:00
|
|
|
|
let deltaText = '-';
|
2026-01-09 13:45:30 +08:00
|
|
|
|
if (!is_sent) {
|
|
|
|
|
|
content = extractMiddlePayload(content);
|
|
|
|
|
|
if (lastReceivedAtMs !== null) {
|
|
|
|
|
|
const deltaMs = nowMs - lastReceivedAtMs;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
// 间隔列:仅显示毫秒数字,不带单位
|
|
|
|
|
|
deltaText = `${deltaMs}`;
|
2026-01-09 13:45:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
lastReceivedAtMs = nowMs;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 14:52:58 +08:00
|
|
|
|
let messageRow = `
|
|
|
|
|
|
<tr class="${messageRowClass}">
|
|
|
|
|
|
<td>${getCurrentTime(nowDate)}</td>
|
|
|
|
|
|
<td>${deltaText}</td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td>${content}</td>
|
|
|
|
|
|
</tr>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
`;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
|
|
|
|
|
|
$("#touchuan_tbody").append(messageRow);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
// 自动滚动到底部
|
|
|
|
|
|
$("#touchuan_content").scrollTop($("#touchuan_content")[0].scrollHeight);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 连接MQTT
|
2025-12-11 09:17:16 +08:00
|
|
|
|
function lianjie(hghg) {
|
|
|
|
|
|
const options = {
|
|
|
|
|
|
clientId: 'touchuan_' + Math.random().toString(16).substr(2, 8),
|
|
|
|
|
|
username: "blwws",
|
|
|
|
|
|
password: "E!9~3~H=M.&2STW",
|
|
|
|
|
|
protocolVersion: 5
|
|
|
|
|
|
};
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
|
|
|
|
|
mqttClient = mqtt.connect("wss://gua.blv-oa.com:8084/mqtt", options);
|
|
|
|
|
|
|
|
|
|
|
|
mqttClient.on("connect", (error) => {
|
|
|
|
|
|
console.log("连接成功");
|
|
|
|
|
|
lastReceivedAtMs = null;
|
|
|
|
|
|
$("#result").html('<i class="fas fa-check-circle"></i> 连接成功').removeClass("error").addClass("success");
|
|
|
|
|
|
$("#connection-status")
|
|
|
|
|
|
.removeClass("status-disconnected")
|
|
|
|
|
|
.addClass("status-connected")
|
|
|
|
|
|
.html('<span class="status-dot"></span><span>已连接: ' + hghg + '</span>');
|
|
|
|
|
|
isConnected = true;
|
|
|
|
|
|
|
|
|
|
|
|
mqttClient.unsubscribe("blw/touchuan/report" + hghg);
|
|
|
|
|
|
mqttClient.subscribe("blw/touchuan/report/" + hghg, (err) => {
|
|
|
|
|
|
if (err) {
|
|
|
|
|
|
console.error("订阅失败:", err);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-12-11 09:17:16 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-01-09 13:45:30 +08:00
|
|
|
|
mqttClient.on("message", (topic, message) => {
|
2025-12-11 09:17:16 +08:00
|
|
|
|
var data = message.toString();
|
|
|
|
|
|
console.log(data);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
addMessage(data, false);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
mqttClient.on("error", (error) => {
|
|
|
|
|
|
console.error("连接错误:", error);
|
|
|
|
|
|
lastReceivedAtMs = null;
|
|
|
|
|
|
$("#result").html('<i class="fas fa-exclamation-triangle"></i> 连接错误: ' + error).removeClass("success").addClass("error");
|
|
|
|
|
|
$("#connection-status")
|
|
|
|
|
|
.removeClass("status-connected")
|
|
|
|
|
|
.addClass("status-disconnected")
|
|
|
|
|
|
.html('<span class="status-dot"></span><span>连接失败</span>');
|
|
|
|
|
|
isConnected = false;
|
2025-12-11 09:17:16 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示/隐藏端口设置区域
|
|
|
|
|
|
function togglePortVisibility(selectedMode) {
|
|
|
|
|
|
// 隐藏所有端口设置区域
|
|
|
|
|
|
$(".port-item").removeClass("visible");
|
|
|
|
|
|
//$("#div_content").removeClass("visible");
|
|
|
|
|
|
$("#div_content").hide();
|
|
|
|
|
|
|
|
|
|
|
|
// 根据选择的模式显示对应的区域
|
|
|
|
|
|
if (selectedMode === "读取模式") {
|
|
|
|
|
|
$("#p1").addClass("visible");
|
|
|
|
|
|
} else if (selectedMode === "设置模式") {
|
|
|
|
|
|
$("#p2").addClass("visible");
|
|
|
|
|
|
} else if (selectedMode === "发送模式") {
|
|
|
|
|
|
$("#p3").addClass("visible");
|
|
|
|
|
|
$("#div_content").show();;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log("切换到模式:", selectedMode);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 页面加载完成后执行
|
2025-12-11 09:17:16 +08:00
|
|
|
|
$(function() {
|
2026-01-09 13:45:30 +08:00
|
|
|
|
// 初始化:根据默认选中的模式显示对应区域
|
|
|
|
|
|
const initialMode = $("input[name='mode']:checked").val();
|
|
|
|
|
|
togglePortVisibility(initialMode);
|
|
|
|
|
|
|
|
|
|
|
|
// 设置连接按钮点击事件
|
2025-12-11 09:17:16 +08:00
|
|
|
|
$("#btn_set").click(function() {
|
2026-01-09 13:45:30 +08:00
|
|
|
|
let hhh = $("#txthostnumber").val().trim();
|
|
|
|
|
|
|
|
|
|
|
|
if (!hhh) {
|
|
|
|
|
|
$("#result").html('<i class="fas fa-exclamation-circle"></i> 请输入主机编号').removeClass("success").addClass("error");
|
|
|
|
|
|
$("#txthostnumber").focus();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$("#result").html('<i class="fas fa-spinner fa-spin"></i> 正在连接...').removeClass("error success").show();
|
2026-01-09 14:52:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化记录:以“点击连接设备”的时间作为首条记录(不影响接收间隔计算)
|
|
|
|
|
|
$("#touchuan_tbody").append(`
|
|
|
|
|
|
<tr class="message-row-received">
|
|
|
|
|
|
<td>${getCurrentTime(new Date())}</td>
|
|
|
|
|
|
<td>-</td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td>连接设备</td>
|
|
|
|
|
|
<td>${hhh}</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
`);
|
|
|
|
|
|
$("#touchuan_content").scrollTop($("#touchuan_content")[0].scrollHeight);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
let mac = "";
|
|
|
|
|
|
let jjj = {
|
|
|
|
|
|
hostnumber: hhh,
|
|
|
|
|
|
mac: mac,
|
|
|
|
|
|
add_or_remove: "add"
|
|
|
|
|
|
};
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
$.ajax({
|
|
|
|
|
|
url: '/api/SetTouChuanData',
|
2026-01-09 13:45:30 +08:00
|
|
|
|
type: 'POST',
|
2025-12-11 09:17:16 +08:00
|
|
|
|
contentType: 'application/x-www-form-urlencoded',
|
|
|
|
|
|
data: jjj,
|
|
|
|
|
|
success: function(response) {
|
|
|
|
|
|
console.log(response);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
$("#result").html('<i class="fas fa-check-circle"></i> 设置成功: ' + response).removeClass("error").addClass("success");
|
2025-12-11 09:17:16 +08:00
|
|
|
|
lianjie(hhh);
|
|
|
|
|
|
},
|
|
|
|
|
|
error: function(xhr, status, error) {
|
|
|
|
|
|
console.log(error);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
$("#result").html('<i class="fas fa-times-circle"></i> 设置失败: ' + error).removeClass("success").addClass("error");
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 发送按钮点击事件
|
2025-12-11 09:17:16 +08:00
|
|
|
|
$("#send").click(function() {
|
|
|
|
|
|
let is_add_header = $("#isprotocol").prop("checked");
|
2026-01-09 13:45:30 +08:00
|
|
|
|
let ccc = $("#content").val().trim();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取选中的模式
|
|
|
|
|
|
let selectedMode = $("input[name='mode']:checked").val();
|
|
|
|
|
|
|
|
|
|
|
|
var listpwsh = [];
|
|
|
|
|
|
|
|
|
|
|
|
// 根据选择的模式处理数据
|
|
|
|
|
|
if (selectedMode === "读取模式") {
|
|
|
|
|
|
var port_1_val = $("#Port_1").val();
|
|
|
|
|
|
if (port_1_val) {
|
|
|
|
|
|
listpwsh.push("01");
|
|
|
|
|
|
listpwsh.push(port_1_val);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (selectedMode === "设置模式") {
|
|
|
|
|
|
var port_2_val = $("#Port_2").val();
|
|
|
|
|
|
var Byte_Speed_v = $("#Byte_Speed").val();
|
|
|
|
|
|
var MoshiID_v = $("#moshi_id").val();
|
|
|
|
|
|
var tm2_v = $("#tm2").val();
|
|
|
|
|
|
|
|
|
|
|
|
if (port_2_val && Byte_Speed_v && MoshiID_v && tm2_v) {
|
|
|
|
|
|
listpwsh.push("02");
|
|
|
|
|
|
listpwsh.push(port_2_val);
|
|
|
|
|
|
listpwsh.push(Byte_Speed_v);
|
|
|
|
|
|
listpwsh.push(tm2_v);
|
|
|
|
|
|
listpwsh.push(MoshiID_v);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (selectedMode === "发送模式") {
|
|
|
|
|
|
if (!ccc) {
|
|
|
|
|
|
$("#result").html('<i class="fas fa-exclamation-circle"></i> 请输入透传内容').removeClass("success").addClass("error");
|
|
|
|
|
|
$("#content").focus();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
var port_4_val = $("#Port_4").val();
|
|
|
|
|
|
var tm4_val = $("#tm4").val();
|
|
|
|
|
|
|
|
|
|
|
|
if (port_4_val && tm4_val && ccc) {
|
|
|
|
|
|
listpwsh.push("03");
|
|
|
|
|
|
listpwsh.push(port_4_val);
|
|
|
|
|
|
listpwsh.push(tm4_val);
|
|
|
|
|
|
listpwsh.push(ccc);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var finally_ccc = listpwsh.join(' ');
|
|
|
|
|
|
console.log(finally_ccc);
|
|
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
let hhh = $("#txthostnumber").val();
|
|
|
|
|
|
let mac = "";
|
2026-01-09 13:45:30 +08:00
|
|
|
|
let p_type = $("#protocoltype").val() || "70";
|
2025-12-11 09:17:16 +08:00
|
|
|
|
let jjj = {
|
|
|
|
|
|
hostnumber: hhh,
|
|
|
|
|
|
mac: mac,
|
2026-01-09 13:45:30 +08:00
|
|
|
|
bytelist: finally_ccc,
|
2025-12-11 09:17:16 +08:00
|
|
|
|
cmdtype: p_type,
|
|
|
|
|
|
isoriginal: is_add_header
|
|
|
|
|
|
};
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
2025-12-11 09:17:16 +08:00
|
|
|
|
$.ajax({
|
|
|
|
|
|
url: '/api/SendUDPPackage',
|
2026-01-09 13:45:30 +08:00
|
|
|
|
type: 'POST',
|
2025-12-11 09:17:16 +08:00
|
|
|
|
contentType: 'application/x-www-form-urlencoded',
|
|
|
|
|
|
data: jjj,
|
|
|
|
|
|
success: function(response) {
|
|
|
|
|
|
console.log(response);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
addMessage(ccc, true);
|
|
|
|
|
|
$("#result").html('<i class="fas fa-check-circle"></i> 发送成功').removeClass("error").addClass("success");
|
2025-12-11 09:17:16 +08:00
|
|
|
|
},
|
|
|
|
|
|
error: function(xhr, status, error) {
|
|
|
|
|
|
console.log(error);
|
2026-01-09 13:45:30 +08:00
|
|
|
|
$("#result").html('<i class="fas fa-times-circle"></i> 发送失败: ' + error).removeClass("success").addClass("error");
|
2025-12-11 09:17:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2026-01-09 13:45:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 清空记录按钮
|
|
|
|
|
|
$("#clear-btn").click(function() {
|
|
|
|
|
|
lastReceivedAtMs = null;
|
2026-01-09 14:52:58 +08:00
|
|
|
|
$("#touchuan_tbody").html(`
|
|
|
|
|
|
<tr class="message-row-received">
|
|
|
|
|
|
<td>${getCurrentTime()}</td>
|
|
|
|
|
|
<td>-</td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
<td>记录已清空</td>
|
|
|
|
|
|
<td></td>
|
|
|
|
|
|
</tr>
|
2026-01-09 13:45:30 +08:00
|
|
|
|
`);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 输入框回车键支持
|
|
|
|
|
|
$("#txthostnumber, #content").keypress(function(e) {
|
|
|
|
|
|
if (e.which === 13) { // 回车键
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
if ($(this).attr("id") === "txthostnumber") {
|
|
|
|
|
|
$("#btn_set").click();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$("#send").click();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 模式切换时显示/隐藏相关字段
|
|
|
|
|
|
$("input[name='mode']").change(function() {
|
|
|
|
|
|
const selectedMode = $(this).val();
|
|
|
|
|
|
togglePortVisibility(selectedMode);
|
|
|
|
|
|
});
|
2025-12-11 09:17:16 +08:00
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|