This commit is contained in:
2026-08-21 17:03:02 +08:00
commit f065129b20
2292 changed files with 666241 additions and 0 deletions
+633
View File
@@ -0,0 +1,633 @@
/* 基础样式 */
body {
font-family: "Microsoft YaHei", sans-serif;
background-color: #f5f7fa;
margin: 0;
padding: 0;
}
.container {
display: flex;
flex-direction: column;
height: 100vh;
background: white;
padding: 8px;
overflow: hidden !important;
}
.current-row {
background-color: #f5f7fa !important;
font-weight: bold;
border-left: 3px solid #409eff;
}
.el-table-v2__row.current-row {
background-color: #f5f7fa !important;
}
.el-table-v2__row {
cursor: pointer;
}
.toolbar {
margin-bottom: 8px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.toolbar-batch {
margin-top: 0;
margin-bottom: 8px;
}
.toolbar-batch-row {
display: flex;
gap: 8px;
flex-wrap: wrap;
align-items: center;
}
.table-container {
height: calc(100vh - 220px) !important;
padding: 0 !important;
display: flex;
flex-direction: column;
overflow: hidden !important;
flex: 1;
position: relative;
border: 1px solid #ebeef5;
border-radius: 8px;
background: white;
}
.el-table-v2 {
min-width: 1200px;
width: 100% !important;
height: 100% !important;
border-radius: 8px;
border: 1px solid #ebeef5;
overflow: auto !important;
display: flex;
flex-direction: column;
position: relative;
}
.el-table-v2__header-wrapper {
position: sticky !important;
top: 0 !important;
z-index: 10 !important;
background: #f8f9fa !important;
border-bottom: 1px solid #ebeef5 !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
overflow: hidden !important;
}
.el-table-v2__body-wrapper {
flex: 1 !important;
overflow: auto !important;
position: relative !important;
min-height: calc(100% - 42px);
overflow: hidden !important;
}
.el-table-v2::-webkit-scrollbar {
width: 8px;
height: 8px;
z-index: 20 !important;
}
.el-table-v2::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.el-table-v2::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
border: 1px solid #f1f1f1;
}
.el-table-v2::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
border: 1px solid #909090;
}
.el-table-v2__footer {
position: sticky !important;
bottom: 0 !important;
z-index: 5 !important;
background: #f8f9fa !important;
border-top: 1px solid #ebeef5 !important;
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1) !important;
overflow-x: auto !important;
min-height: 8px;
}
/* 表格内容区域的滚动条样式 */
.el-table-v2__body-wrapper::-webkit-scrollbar {
height: 8px !important;
}
.el-table-v2__body-wrapper::-webkit-scrollbar-thumb {
background: #c1c1c1 !important;
border-radius: 4px !important;
border: 1px solid #f1f1f1 !important;
}
.el-table-v2__body-wrapper::-webkit-scrollbar-thumb:hover {
background: #a8a8a8 !important;
border: 1px solid #909090 !important;
}
.el-table-v2__header th {
background-color: #f8f9fa;
font-weight: bold;
color: #606266;
}
/* 主表格单元格网格线(配合列 style 内联边框) */
#app .el-table-v2__header-cell,
#app .el-table-v2__row-cell {
border-right: 1px solid #dcdfe6 !important;
border-bottom: 1px solid #dcdfe6 !important;
box-sizing: border-box !important;
}
#app .el-table-v2__header {
border-bottom: 1px solid #dcdfe6 !important;
}
/* 表头列拖拽排序 / 列宽调整 */
.bjcpjxdr-header-cell {
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding: 0 6px;
box-sizing: border-box;
user-select: none;
position: relative;
}
.bjcpjxdr-header-pinned {
justify-content: center;
}
.bjcpjxdr-header-draggable {
cursor: grab;
}
.bjcpjxdr-header-draggable.is-dragging {
cursor: grabbing;
opacity: 0.55;
}
.bjcpjxdr-header-draggable.is-drag-over {
background-color: #ecf5ff !important;
outline: 2px dashed #409eff;
outline-offset: -2px;
}
.bjcpjxdr-header-grip {
flex-shrink: 0;
margin-right: 4px;
color: #c0c4cc;
font-size: 11px;
letter-spacing: -2px;
line-height: 1;
}
.bjcpjxdr-header-draggable:hover .bjcpjxdr-header-grip {
color: #409eff;
}
.bjcpjxdr-header-title {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 列宽拖拽热区(默认不显示竖线,仅拖动时出现全局指示线) */
.bjcpjxdr-col-resize-handle {
position: absolute;
top: 0;
right: -3px;
width: 6px;
height: 100%;
cursor: col-resize;
z-index: 3;
touch-action: none;
}
.bjcpjxdr-col-resize-guide {
display: none;
position: fixed;
width: 1px;
background: #c0c4cc;
z-index: 9999;
pointer-events: none;
}
body.bjcpjxdr-col-resizing {
cursor: col-resize !important;
user-select: none !important;
}
.el-table-v2__row:hover {
background-color: #f5f7fa !important;
}
.el-table-v2__row.current-row {
background-color: #f0f7ff !important;
}
.el-table-v2__row.current-row:hover {
background-color: #e6f7ff !important;
}
.rule-config-dialog {
width: 950px !important;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.rule-syntax-link {
cursor: pointer;
text-decoration: underline;
text-decoration-thickness: 1.8px;
text-underline-offset: 0.3em;
color: #409EFF;
font-weight: 500;
font-size: 14px;
transition: color 0.3s ease;
}
.rule-syntax-link:hover {
color: #66b1ff;
}
.rule-config-header {
background: #409EFF;
color: white;
padding: 6px 6px;
font-size: 18px;
font-weight: 600;
display: flex;
align-items: center;
}
.rule-config-header i {
margin-right: 10px;
font-size: 24px;
}
.rule-config-content {
padding: 10px;
background: #f8fafc;
}
.rule-string-section {
margin-bottom: 12px;
position: relative;
}
.rule-string-label {
font-weight: bold;
color: #606266;
margin-bottom: 8px;
}
.rule-string-textarea {
width: 75%;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 8px;
font-size: 14px;
min-height: 10px;
resize: vertical;
font-family: Consolas, Monaco, monospace;
}
.unmark-button {
position: absolute;
top: 40px;
right: 110px;
background: #67c23a;
color: white;
border: none;
padding: 4px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.unmark-button:hover {
background: #85ce61;
}
.rule-config-item {
margin-bottom: 10px;
border-bottom: 1px solid #ebeef5;
padding-bottom: 15px;
}
.rule-item-label {
font-weight: bold;
color: #606266;
margin-bottom: 10px;
font-size: 14px;
}
.rule-input-container {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.rule-input {
flex: 1;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 8px 12px;
font-size: 14px;
position: relative;
}
.rule-input-with-arrow {
padding-right: 30px;
}
.rule-input-arrow {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
color: #c0c4cc;
}
.rule-tags-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
}
.rule-tag {
display: inline-block;
padding: 3px 16px;
font-size: 13px;
border: 0.1px solid #dcdfe6;
border-radius: 4px;
cursor: pointer;
background: #ECF5FF;
border-color: #9ccaf7;
color: #409EFE;
letter-spacing: 3px;
font-weight: 500;
text-align: center;
}
.rule-tag:hover {
background: #409EFE;
border-color: #409EFF;
color: #ffffff;
}
.rule-value-display {
font-weight: bold;
color: #409EFF;
margin-top: 8px;
}
.maintain-info {
display: flex;
justify-content: space-between;
margin-top: 24px;
padding-top: 12px;
border-top: 1px dashed #dcdfe6;
font-size: 13px;
color: #909399;
}
.maintain-item span {
font-weight: bold;
color: #606266;
margin-right: 4px;
}
.import-dialog {
width: 800px !important;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.import-header {
background: #67C23A;
color: white;
padding: 16px 20px;
font-size: 18px;
font-weight: 600;
display: flex;
align-items: center;
}
.import-header i {
margin-right: 10px;
font-size: 24px;
}
.import-content {
padding: 20px;
background: #f8fafc;
}
.upload-section {
border: 2px dashed #d9d9d9;
border-radius: 8px;
padding: 25px;
text-align: center;
background: #f9f9f9;
margin-bottom: 20px;
transition: border-color 0.3s;
position: relative;
}
.upload-section:hover {
border-color: #67C23A;
}
.upload-icon {
font-size: 48px;
color: #67C23A;
margin-bottom: 15px;
}
.upload-text {
color: #606266;
font-size: 16px;
margin-bottom: 15px;
}
.file-info {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 15px;
}
.file-name {
font-weight: bold;
color: #303133;
margin-bottom: 5px;
}
.file-size {
color: #909399;
font-size: 14px;
}
.mapping-section {
margin: 25px 0;
}
.mapping-title {
font-weight: bold;
color: #606266;
margin-bottom: 15px;
font-size: 16px;
display: flex;
align-items: center;
}
.mapping-title i {
margin-right: 8px;
color: #409EFF;
}
.mapping-grid {
display: grid;
grid-template-columns: 140px 40px 1fr;
gap: 15px;
align-items: center;
}
.mapping-item {
display: contents;
}
.system-column {
font-weight: bold;
color: #606266;
padding: 8px 12px;
background: #f0f7ff;
border-radius: 4px;
}
.mapping-arrow {
text-align: center;
font-size: 20px;
color: #909399;
}
.column-select {
width: 100%;
}
.preview-section {
margin-top: 25px;
}
.preview-table {
max-height: 280px;
overflow: auto;
border: 1px solid #ebeef5;
border-radius: 4px;
margin-top: 15px;
}
.preview-table table {
width: 100%;
border-collapse: collapse;
}
.preview-table th {
background-color: #f8f9fa;
padding: 12px 15px;
font-weight: bold;
color: #606266;
border-bottom: 1px solid #ebeef5;
border-right: 1px solid #ebeef5;
position: sticky;
top: 0;
}
.preview-table td {
padding: 10px 15px;
border-bottom: 1px solid #ebeef5;
border-right: 1px solid #ebeef5;
}
.preview-table tr:hover {
background-color: #f5f7fa;
}
.import-progress {
margin-top: 25px;
}
.error-message {
margin-top: 15px;
background-color: #fef0f0;
border-radius: 4px;
padding: 12px;
color: #f56c6c;
font-size: 14px;
}
.success-message {
margin-top: 15px;
background-color: #f0f9eb;
border-radius: 4px;
padding: 12px;
color: #67c23a;
font-size: 14px;
}
.progress-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
pointer-events: all;
transform: none !important;
}
.progress-container {
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
text-align: center;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
border-radius: 8px;
z-index: 10000;
}
.progress-container .el-progress__text {
color: white !important;
font-size: 16px;
}
+3811
View File
File diff suppressed because it is too large Load Diff
+418
View File
@@ -0,0 +1,418 @@
/* 全局选择器,应用于所有元素 */
* {
margin: 0; /* 清除所有元素的外边距 */
padding: 0; /* 清除所有元素的内边距 */
box-sizing: border-box; /* 设置盒模型为border-box,使宽高包含边框和内边距[2](@ref) */
/* font-family: "Segoe UI", "Microsoft YaHei", sans-serif; 设置字体栈,优先使用Segoe UI,回退到微软雅黑和无衬线字体 */
}
/* 设置网页主体样式 */
body {
background-color: #f0f4f8; /* 浅蓝色背景 */
color: #2d3748; /* 深灰色文字 */
line-height: 1; /* 行高为字体大小的1倍 */
padding: 0px; /* 主体四周添加4px内边距 */
}
/* 主内容容器 */
.syntax-container {
max-width: 1300px; /* 最大宽度限制 */
margin: 0px auto; /* 上下10px外边距,水平居中 */
background: white; /* 白色背景 */
/* border-radius: 10px; 10px圆角 */
/* box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); 添加轻微阴影 */
overflow: hidden; /* 隐藏溢出内容 */
transition: transform 0.3s ease, box-shadow 0.3s ease; /* 添加过渡动画效果 */
}
/* 头部区域样式 */
.syntax-header {
background: #409EFF; /* 蓝色渐变背景 */
color: white; /* 白色文字 */
padding: 0px 0px; /* 无内边距 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: space-between; /* 两端对齐 */
position: relative; /* 相对定位 */
}
/* 头部底部的装饰线 */
.syntax-header::after {
content: ''; /* 伪元素内容 */
position: absolute; /* 绝对定位 */
bottom: 0; /* 定位到底部 */
left: 0; /* 定位到左侧 */
width: 100%; /* 宽度100% */
height: 0px; /* 高度3px */
background: linear-gradient(90deg, #43a047, #1e88e5, #e53935); /* 三色渐变 */
opacity: 0.7; /* 70%透明度 */
}
/* 头部左侧区域 */
.header-left {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 0px; /* 元素间无间隙 */
}
/* 应用图标样式 */
.app-icon {
width: 12px; /* 宽度12px */
height: 30px; /* 高度12px */
background-color: #409EFF; /* 半透明白色背景 */
/* border-radius: 6px; 圆形 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
font-size: 20px; /* 字体大小10px */
color: white; /* 白色文字 */
/* backdrop-filter: blur(2px); 背景模糊效果 */
/* box-shadow: 0 3px 5px rgba(0, 0, 0, 0.08); 轻微阴影 */
}
/* 应用标题样式 */
.app-title h1 {
font-size: 20px; /* 字体大小10px */
font-weight: 600; /* 中等加粗 */
letter-spacing: 0.4px; /* 字符间距0.4px */
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 主体内容区域 */
.syntax-body {
padding: 20px; /* 内边距10px */
}
/* 信息组容器 */
.info-group {
margin-bottom: 5px; /* 底部外边距20px */
background: #f9fafc; /* 浅灰色背景 */
border-radius: 8px; /* 8px圆角 */
padding: 5px; /* 内边距16px */
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.02); /* 轻微阴影 */
}
/* 信息组标题区域 */
.info-group-title {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
margin-bottom: 8px; /* 底部外边距14px */
padding-bottom: 8px; /* 底部内边距10px */
border-bottom: 1px solid #e2e8f0; /* 底部1px浅灰色边框 */
}
/* 信息组标题文字样式 */
.info-group-title h2 {
font-size: 16px; /* 字体大小16px */
color: #000000; /* 蓝色文字 */
font-weight: 600; /* 中等加粗 */
padding-left: 10px; /* 左侧内边距10px */
}
/* 输入组样式 */
.input-group {
margin-bottom: 4px; /* 底部外边距16px */
}
/* 输入标签样式 */
.input-group label {
display: block; /* 块级元素 */
margin-bottom: 4px; /* 底部外边距8px */
color: #4a5568; /* 深灰色文字 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 输入字段通用样式 */
.input-field {
width: 100%; /* 宽度100% */
padding: 2px 2px; /* 内边距 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
border-radius: 7px; /* 7px圆角 */
font-size: 14px; /* 字体大小14px */
transition: all 0.3s; /* 所有属性0.3秒过渡 */
background: white; /* 白色背景 */
color: #2d3748; /* 深灰色文字 */
}
/* 输入字段聚焦状态 */
.input-field:focus {
border-color: #1e88e5; /* 边框变为蓝色 */
outline: none; /* 移除默认轮廓线 */
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.12); /* 添加蓝色发光效果 */
}
/* 文本域特殊样式 */
.input-field.textarea {
min-height: 30px; /* 最小高度85px */
resize: vertical; /* 允许垂直调整大小 */
font-family: 'Consolas', monospace; /* 等宽字体 */
padding: 6px; /* 内边距14px */
line-height: 1.5; /* 行高1.6倍 */
font-size: 13.5px; /* 字体大小13.5px */
}
/* 结果显示区域 */
.result-display {
background: linear-gradient(to right, #f7fafc, #edf2f7); /* 左右渐变背景 */
border: 1px solid #e2e8f0; /* 1px浅灰色边框 */
border-radius: 8px; /* 8px圆角 */
padding: 18px; /* 内边距18px */
margin: 9px 0; /* 上下外边距18px */
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.03); /* 内阴影 */
}
/* 结果项样式 */
.result-item {
margin-bottom: 14px; /* 底部外边距14px */
padding-bottom: 14px; /* 底部内边距14px */
border-bottom: 1px dashed #e2e8f0; /* 底部1px虚线边框 */
}
/* 最后一个结果项特殊处理 */
.result-item:last-child {
margin-bottom: 0; /* 无底部外边距 */
padding-bottom: 0; /* 无底部内边距 */
border-bottom: none; /* 无底部边框 */
}
/* 结果标签样式 */
.result-label {
color: #718096; /* 中灰色文字 */
font-size: 14px; /* 字体大小14px */
margin-bottom: 6px; /* 底部外边距6px */
font-weight: 500; /* 中等加粗 */
}
/* 结果值样式 */
.result-value {
font-size: 16px; /* 字体大小16px */
font-weight: 600; /* 中等加粗 */
color: #2d3748; /* 深灰色文字 */
}
/* 结果值中的高亮部分 */
.result-value .highlight {
color: #1e88e5; /* 蓝色文字 */
font-weight: 700; /* 加粗 */
font-size: 16px; /* 字体大小16px */
letter-spacing: 0.4px; /* 字符间距0.4px */
}
/* 操作按钮容器 */
.action-buttons {
display: flex; /* 启用Flex布局 */
justify-content: center; /* 水平居中 */
align-items: center; /*垂直居中*/
margin-top: 10px; /* 顶部外边距20px */
gap: 15px; /* 按钮间距15px */
height: auto; /* 自适应高度 */
padding: 10px 0; /* 添加垂直内边距 */
}
/* 操作按钮通用样式 */
.action-btn {
padding: 6px 15px; /* 内边距 */
border: none; /* 无边框 */
border-radius: 4px; /* 7px圆角 */
font-size: 12px; /* 字体大小15px */
font-weight: 600; /* 中等加粗 */
cursor: pointer; /* 鼠标指针为手型 */
/* transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); 自定义缓动过渡 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
min-width: 120px; /* 最小宽度120px */
letter-spacing: 4px; /* 字符间距4px */
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.06); /* 轻微阴影 */
}
/* 操作按钮图标 */
.action-btn i {
margin-right: 8px; /* 右侧外边距8px */
font-size: 16px; /* 字体大小16px */
}
/* 主要按钮样式 */
.btn-primary {
background: linear-gradient(to right,#409EFF , #409EFF);
color: white; /* 白色文字 */
position: relative; /* 相对定位 */
overflow: hidden; /* 隐藏溢出内容 */
}
/* 主要按钮悬停效果 */
.btn-primary:hover {
background: linear-gradient(to right, #2196f3, #1565c0); /* 更亮的蓝色渐变 */
box-shadow: 0 5px 10px rgba(33, 150, 243, 0.25); /* 增加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 主要按钮悬停时伪元素动画 */
.btn-primary:hover::after {
left: 140%; /* 移动到右侧140%位置 */
}
/* 默认按钮样式 */
.btn-default {
background: #f7fafc; /* 浅灰色背景 */
color: #4a5568; /* 深灰色文字 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
}
/* 默认按钮悬停效果 */
.btn-default:hover {
background: white; /* 白色背景 */
border-color: #a0aec0; /* 边框颜色加深 */
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.06); /* 添加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 标记控制按钮容器 */
.mark-controls {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(4, minmax(140px, 1fr)); /* 自适应列 */
gap: 12px; /* 元素间距12px */
margin-top: 10px; /* 顶部外边距18px */
}
/* 标记按钮样式 */
.mark-btn {
display: inline-block;
padding: 4px 4px;
font-size: 13px;
border: 0.1px solid #dcdfe6;
border-radius: 4px;
cursor: pointer;
background: #ECF5FF;
border-color: #9ccaf7;
color: #409EFE;
letter-spacing: 3px; /* 添加微小间距 */
font-weight: 500; /* 加粗效果 */
text-align: center;
}
/* 标记按钮悬停效果 */
.mark-btn:hover {
background: #409EFE;
border-color: #409EFF;
color:#ffffff;
}
/* 标记按钮图标 */
.mark-btn i {
font-size: 13px; /* 字体大小16px */
}
/* 光标指示器样式 */
.cursor-indicator {
position: absolute; /* 绝对定位 */
width: 2px; /* 宽度2px */
height: 18px; /* 高度18px */
background-color: #e53935; /* 红色背景 */
pointer-events: none; /* 不响应鼠标事件 */
z-index: 100; /* 高z-index确保显示在最上层 */
border-radius: 1px; /* 轻微圆角 */
box-shadow: 0 0 2px rgba(229, 57, 53, 0.7); /* 红色发光效果 */
}
/* 标记对话框样式 */
.mark-dialog {
border-radius: 10px; /* 10px圆角 */
overflow: hidden; /* 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
.connector-dialog{
border-radius: 10px; /* 10px圆角 */
/* overflow: hidden; 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
/* 对话框头部样式 */
.mark-dialog-header, .connector-dialog-header {
background: linear-gradient(135deg, #1e88e5, #1565c0); /* 蓝色渐变背景 */
border:none !important;
color: white; /* 白色文字 */
padding: 5px 8px; /* 内边距 */
font-size: 18px; /* 字体大小18px */
font-weight: 600; /* 中等加粗 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 10px; /* 元素间距10px */
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 对话框头部图标 */
.mark-dialog-header i, .connector-dialog-header i {
font-size: 24px; /* 字体大小24px */
}
/* 对话框主体区域 */
.mark-dialog-body, .connector-dialog-body {
border:none !important;
padding: 0px 0px; /* 内边距20px */
background: #f8fafc; /* 浅灰色背景 */
}
/* 标记选项容器 */
.mark-options {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(auto-fit, minmax(18px, 1fr)); /* 自适应列 */
gap: 4px; /* 元素间距4px */
margin-top: 4px; /* 顶部外边距4px */
}
/* 标记选项按钮 */
.mark-option {
padding: 14px 8px; /* 内边距 */
background: #e3f2fd; /* 浅蓝色背景 */
border: 1px solid #bbdefb; /* 1px浅蓝色边框 */
border-radius: 7px; /* 7px圆角 */
color: #1976d2; /* 蓝色文字 */
cursor: pointer; /* 鼠标指针为手型 */
text-align: center; /* 文字居中 */
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); /* 自定义缓动过渡 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 标记选项悬停效果 */
.mark-option:hover {
background: #bbdefb; /* 加深背景色 */
border-color: #90caf9; /* 加深边框色 */
transform: translateY(-3px) scale(1.02); /* 上移并轻微放大 */
box-shadow: 0 6px 12px rgba(25, 118, 210, 0.15); /* 添加蓝色阴影 */
}
/* 响应式设计:屏幕宽度小于768px时的调整 */
@media (max-width: 768px) { /* 媒体查询,针对小屏幕设备[6](@ref) */
.syntax-container {
margin: 8px auto; /* 减小外边距 */
}
.syntax-body {
padding: 16px; /* 调整内边距 */
}
.action-buttons {
flex-direction: column; /* 垂直排列按钮 */
gap: 10px; /* 按钮间距10px */
}
.action-btn {
width: 100%; /* 按钮宽度100% */
padding: 12px; /* 调整内边距 */
}
}
+671
View File
@@ -0,0 +1,671 @@
const { createApp, ref, onMounted, nextTick } = Vue;
const { ElMessage } = ElementPlus;
const app = createApp({
setup() {
// 从URL获取参数的函数
function getParameterByName(name, url = window.location.href) {
debugger;
name = name.replace(/[\[\]]/g, '\\$&');
const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
const results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
// 当用户完成操作时调用此函数
function returnSyntaxResult(result) {
// 将结果存储到localStorage
const resultKey = `syntaxResult_${windowId}`;
localStorage.setItem(resultKey, JSON.stringify(result));
// 关闭窗口
window.close();
}
// 过滤标记串(只保留型号码、前缀码、后缀码)
const filterMarkString = (str) => {
if (!str) return '';
// 匹配所有标记
const regex = /\[([^\]]+)=([^\]]+)\]/g;
const matches = str.matchAll(regex);
let validTags = [];
debugger;
switch(title.value) {
case '线缆型号语法':
validTags = ['型号码', '前缀码', '后缀码'];
break;
case '线缆规格语法':
validTags = ['截面', '芯数', '线组数', '线对数'];
break;
case '电压等级语法':
validTags = ['相电压', '线电压', '电压单位'];
break;
case '线缆标准语法':
validTags = ['标准名'];
break;
default:
// 默认为线缆型号语法
validTags = ['型号码', '前缀码', '后缀码'];
}
const filtered = [];
for (const match of matches) {
const tag = match[1];
if (validTags.includes(tag)) {
filtered.push(`[${tag}=${match[2]}]`);
}
}
return filtered.join('');
};
// 获取URL传递的参数
const urlParams = {
title: getParameterByName('title') || '',
ruleString: getParameterByName('ruleString1') || '',
syntaxString: getParameterByName('syntaxString') || '',
connectors: getParameterByName('connectors') || ''
};
// 页面数据
const originalMarkString = ref(urlParams.ruleString);
const syntaxString = ref(urlParams.syntaxString); // 使用传递的语法串
const orgsyntaxString = ref(urlParams.syntaxString);
const cursorPosition = ref(-1);
const syntaxEditor = ref(null);
const actualValue = ref('');
const title = ref(urlParams.title);
const filteredMarkString = ref(filterMarkString(urlParams.ruleString));
// 对话框相关
const showMarkDialog = ref(false);
const showConnectorDialog = ref(false);
const selectedConnector = ref('');
const availableMarks = ref([]);
const predefinedConnectors = ref(urlParams.connectors.split(','));
const loadingConnectors = ref(false);
const customConnector = ref('');
// 更新光标位置
const updateCursorPosition = () => {
if (syntaxEditor.value) {
cursorPosition.value = syntaxEditor.value.selectionStart;
}
};
const updateActualValue = () => {
// 解析标记串中的所有标记(按顺序)
const markArray = [];
const markRegex = /\[([^\]]+)=([^\]]+)\]/g;
let markMatch;
while ((markMatch = markRegex.exec(filteredMarkString.value)) !== null) {
markArray.push({
tag: markMatch[1],
value: markMatch[2]
});
}
// 解析语法串
let result = '';
const syntaxRegex = /(\[[^\]]+\])|([^[]+)/g;
let syntaxMatch;
while ((syntaxMatch = syntaxRegex.exec(syntaxString.value)) !== null) {
if (syntaxMatch[1]) {
// 处理标记字部分
const innerRegex = /\[([^\]]+)([a-z])\]/;
const innerMatch = syntaxMatch[1].match(innerRegex);
if (innerMatch) {
const tag = innerMatch[1];
const char = innerMatch[2];
const index = char.charCodeAt(0) - 97; // a->0, b->1, etc.
// 检查索引是否在标记数组范围内
if (index < markArray.length) {
// 获取对应位置的标记
const mark = markArray[index];
// 检查标记类型是否匹配
if (mark.tag === tag) {
result += mark.value;
}
}
}
} else if (syntaxMatch[2]) {
// 处理普通文本(链接符)
result += syntaxMatch[2];
}
}
actualValue.value = result;
};
// 打开插入标记字对话框
const openInsertMarkDialog = () => {
// 解析语法串中的所有标记字
availableMarks.value = [];
const regex = /\[[^\]]+\]/g;
const matches = orgsyntaxString.value.match(regex) || [];
// 去重
const uniqueMarks = [...new Set(matches)];
if (uniqueMarks.length > 0) {
availableMarks.value = uniqueMarks;
showMarkDialog.value = true;
} else {
ElMessage.warning('语法串中没有可用的标记字');
}
};
// 插入选中的标记字
const insertSelectedMark = (mark) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showMarkDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入标记字
syntaxString.value = before + mark + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + mark.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showMarkDialog.value = false;
ElMessage.success(`已插入标记字: ${mark}`);
};
// 打开插入链接符对话框
const openInsertConnectorDialog = () => {
showConnectorDialog.value = true;
selectedConnector.value = ''; // 清空前一次选择
customConnector.value = ''; // 清空前一次自定义输入
};
// 处理选择变化
const handleConnectorChange = (value) => {
// 如果是自定义输入且不在预定义列表中
if (value && !predefinedConnectors.value.includes(value)) {
customConnector.value = value;
}
};
// 插入选中的链接符
const insertSelectedConnector = (connector) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showConnectorDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入链接符
syntaxString.value = before + connector + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + connector.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showConnectorDialog.value = false;
ElMessage.success(`已插入链接符: ${connector}`);
};
// 删除链接符
const deleteConnector = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
if (text.trim() === '') {
return;
}
// 初始化起始和结束位置
let iStart = cursorPos;
let iEnd = cursorPos;
// 向左查找
let i = cursorPos;
if (i >= 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
iStart = i;
break;
}
if (char === '[') {
ElMessage.warning('请将光标置于语法串中的连接符位置');
return;
}
i--;
}
if (i === 0) {
iStart = 0;
}
}
// 向右查找
i = cursorPos;
if (i >= 0) {
while (i < text.length) {
const char = text.charAt(i);
if (char === '[') {
iEnd = i;
break;
}
i++;
}
if (i === text.length) {
iEnd = text.length;
}
}
// 构建新字符串
let newText = '';
if (iStart === 0) {
newText = text.substring(iEnd);
} else {
newText = text.substring(0, iStart) + text.substring(iEnd);
}
syntaxString.value = newText;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(iStart, iStart);
cursorPosition.value = iStart;
});
ElMessage.info('已删除链接符');
};
// 获取当前标记字内容
const getCurrentBracketContent = (text, cursorPos) => {
let startIndex = -1;
let endIndex = -1;
// 查找当前标记字的起始位置
let i = 1;
while (i <= cursorPos) {
if (text.charAt(i - 1) === '[') {
startIndex = i - 1;
}
i++;
}
// 查找当前标记字的结束位置
i = cursorPos;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取下一个标记字内容
const getNextBracketContent = (text, afterIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找下一个标记字的起始位置
let i = afterIndex + 1;
while (i < text.length) {
if (text.charAt(i) === '[') {
startIndex = i;
break;
}
i++;
}
// 查找下一个标记字的结束位置
if (startIndex !== -1) {
i = startIndex;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取前一个标记字内容
const getPreviousBracketContent = (text, beforeIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找前一个标记字的起始位置
let i = 1;
let lastStart = -1;
while (i < beforeIndex) {
if (text.charAt(i - 1) === '[') {
lastStart = i - 1;
}
i++;
}
if (lastStart !== -1) {
startIndex = lastStart;
// 查找前一个标记字的结束位置
i = lastStart;
while (i < beforeIndex) {
if (text.charAt(i) === ']') {
endIndex = i;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 后移标记字
const moveMarkBackward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取下一个标记字
const nextMark = getNextBracketContent(text, currentMark.end);
if (!nextMark) {
ElMessage.warning('后面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, currentMark.start);
const between = text.substring(currentMark.end + 1, nextMark.start);
const after = text.substring(nextMark.end + 1);
syntaxString.value = before + nextMark.content + between + currentMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length + nextMark.content.length + between.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 前移标记字
const moveMarkForward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取前一个标记字
const previousMark = getPreviousBracketContent(text, currentMark.start);
if (!previousMark) {
ElMessage.warning('前面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, previousMark.start);
const between = text.substring(previousMark.end + 1, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + currentMark.content + between + previousMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 删除标记字
const deleteMark = () => {
if (!syntaxEditor.value || !syntaxString.value) {
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要删除的标记字内');
return;
}
// 删除标记字
const before = text.substring(0, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + after;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(currentMark.start, currentMark.start);
cursorPosition.value = currentMark.start;
});
ElMessage.info('已删除标记字');
};
// 保存语法设置
const saveSyntax = () => {
const result = {
type: title.value,
Value: syntaxString.value,
ActualValue: actualValue.value
};
window.parent.postMessage({
type: 'SAVE_SYNTAX_RESULT',
payload: result
}, '*');
ElMessage.success('语法规则已保存');
};
// 应用语法设置
const applySyntax = () => {
ElMessage.success('语法规则已成功应用');
setTimeout(() => {
window.close();
}, 1000);
};
// 重置表单
const resetForm = () => {
syntaxString.value = urlParams.syntaxString; // 重置为初始传递的值
actualValue.value = '';
cursorPosition.value = -1;
updateActualValue(); // 重新计算实际值
};
// 关闭窗口
const closeWindow = () => {
window.close();
};
// 初始化
onMounted(() => {
updateActualValue();
});
return {
filteredMarkString,
syntaxString,
cursorPosition,
syntaxEditor,
actualValue,
showMarkDialog,
showConnectorDialog,
availableMarks,
predefinedConnectors,
updateCursorPosition,
openInsertMarkDialog,
insertSelectedMark,
openInsertConnectorDialog,
insertSelectedConnector,
selectedConnector,
deleteConnector,
moveMarkForward,
moveMarkBackward,
deleteMark,
saveSyntax,
applySyntax,
resetForm,
closeWindow,
handleConnectorChange,
title
};
}
});
app.use(ElementPlus);
app.mount('#app');
+418
View File
@@ -0,0 +1,418 @@
/* 全局选择器,应用于所有元素 */
* {
margin: 0; /* 清除所有元素的外边距 */
padding: 0; /* 清除所有元素的内边距 */
box-sizing: border-box; /* 设置盒模型为border-box,使宽高包含边框和内边距[2](@ref) */
/* font-family: "Segoe UI", "Microsoft YaHei", sans-serif; 设置字体栈,优先使用Segoe UI,回退到微软雅黑和无衬线字体 */
}
/* 设置网页主体样式 */
body {
background-color: #f0f4f8; /* 浅蓝色背景 */
color: #2d3748; /* 深灰色文字 */
line-height: 1; /* 行高为字体大小的1倍 */
padding: 0px; /* 主体四周添加4px内边距 */
}
/* 主内容容器 */
.syntax-container {
max-width: 1300px; /* 最大宽度限制 */
margin: 0px auto; /* 上下10px外边距,水平居中 */
background: white; /* 白色背景 */
/* border-radius: 10px; 10px圆角 */
/* box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); 添加轻微阴影 */
overflow: hidden; /* 隐藏溢出内容 */
transition: transform 0.3s ease, box-shadow 0.3s ease; /* 添加过渡动画效果 */
}
/* 头部区域样式 */
.syntax-header {
background: #409EFF; /* 蓝色渐变背景 */
color: white; /* 白色文字 */
padding: 0px 0px; /* 无内边距 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: space-between; /* 两端对齐 */
position: relative; /* 相对定位 */
}
/* 头部底部的装饰线 */
.syntax-header::after {
content: ''; /* 伪元素内容 */
position: absolute; /* 绝对定位 */
bottom: 0; /* 定位到底部 */
left: 0; /* 定位到左侧 */
width: 100%; /* 宽度100% */
height: 0px; /* 高度3px */
background: linear-gradient(90deg, #43a047, #1e88e5, #e53935); /* 三色渐变 */
opacity: 0.7; /* 70%透明度 */
}
/* 头部左侧区域 */
.header-left {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 0px; /* 元素间无间隙 */
}
/* 应用图标样式 */
.app-icon {
width: 12px; /* 宽度12px */
height: 30px; /* 高度12px */
background-color: #409EFF; /* 半透明白色背景 */
/* border-radius: 6px; 圆形 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
font-size: 20px; /* 字体大小10px */
color: white; /* 白色文字 */
/* backdrop-filter: blur(2px); 背景模糊效果 */
/* box-shadow: 0 3px 5px rgba(0, 0, 0, 0.08); 轻微阴影 */
}
/* 应用标题样式 */
.app-title h1 {
font-size: 20px; /* 字体大小10px */
font-weight: 600; /* 中等加粗 */
letter-spacing: 0.4px; /* 字符间距0.4px */
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 主体内容区域 */
.syntax-body {
padding: 20px; /* 内边距10px */
}
/* 信息组容器 */
.info-group {
margin-bottom: 5px; /* 底部外边距20px */
background: #f9fafc; /* 浅灰色背景 */
border-radius: 8px; /* 8px圆角 */
padding: 5px; /* 内边距16px */
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.02); /* 轻微阴影 */
}
/* 信息组标题区域 */
.info-group-title {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
margin-bottom: 8px; /* 底部外边距14px */
padding-bottom: 8px; /* 底部内边距10px */
border-bottom: 1px solid #e2e8f0; /* 底部1px浅灰色边框 */
}
/* 信息组标题文字样式 */
.info-group-title h2 {
font-size: 16px; /* 字体大小16px */
color: #000000; /* 蓝色文字 */
font-weight: 600; /* 中等加粗 */
padding-left: 10px; /* 左侧内边距10px */
}
/* 输入组样式 */
.input-group {
margin-bottom: 4px; /* 底部外边距16px */
}
/* 输入标签样式 */
.input-group label {
display: block; /* 块级元素 */
margin-bottom: 4px; /* 底部外边距8px */
color: #4a5568; /* 深灰色文字 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 输入字段通用样式 */
.input-field {
width: 100%; /* 宽度100% */
padding: 2px 2px; /* 内边距 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
border-radius: 7px; /* 7px圆角 */
font-size: 14px; /* 字体大小14px */
transition: all 0.3s; /* 所有属性0.3秒过渡 */
background: white; /* 白色背景 */
color: #2d3748; /* 深灰色文字 */
}
/* 输入字段聚焦状态 */
.input-field:focus {
border-color: #1e88e5; /* 边框变为蓝色 */
outline: none; /* 移除默认轮廓线 */
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.12); /* 添加蓝色发光效果 */
}
/* 文本域特殊样式 */
.input-field.textarea {
min-height: 30px; /* 最小高度85px */
resize: vertical; /* 允许垂直调整大小 */
font-family: 'Consolas', monospace; /* 等宽字体 */
padding: 6px; /* 内边距14px */
line-height: 1.5; /* 行高1.6倍 */
font-size: 13.5px; /* 字体大小13.5px */
}
/* 结果显示区域 */
.result-display {
background: linear-gradient(to right, #f7fafc, #edf2f7); /* 左右渐变背景 */
border: 1px solid #e2e8f0; /* 1px浅灰色边框 */
border-radius: 8px; /* 8px圆角 */
padding: 18px; /* 内边距18px */
margin: 9px 0; /* 上下外边距18px */
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.03); /* 内阴影 */
}
/* 结果项样式 */
.result-item {
margin-bottom: 14px; /* 底部外边距14px */
padding-bottom: 14px; /* 底部内边距14px */
border-bottom: 1px dashed #e2e8f0; /* 底部1px虚线边框 */
}
/* 最后一个结果项特殊处理 */
.result-item:last-child {
margin-bottom: 0; /* 无底部外边距 */
padding-bottom: 0; /* 无底部内边距 */
border-bottom: none; /* 无底部边框 */
}
/* 结果标签样式 */
.result-label {
color: #718096; /* 中灰色文字 */
font-size: 14px; /* 字体大小14px */
margin-bottom: 6px; /* 底部外边距6px */
font-weight: 500; /* 中等加粗 */
}
/* 结果值样式 */
.result-value {
font-size: 16px; /* 字体大小16px */
font-weight: 600; /* 中等加粗 */
color: #2d3748; /* 深灰色文字 */
}
/* 结果值中的高亮部分 */
.result-value .highlight {
color: #1e88e5; /* 蓝色文字 */
font-weight: 700; /* 加粗 */
font-size: 16px; /* 字体大小16px */
letter-spacing: 0.4px; /* 字符间距0.4px */
}
/* 操作按钮容器 */
.action-buttons {
display: flex; /* 启用Flex布局 */
justify-content: center; /* 水平居中 */
align-items: center; /*垂直居中*/
margin-top: 10px; /* 顶部外边距20px */
gap: 15px; /* 按钮间距15px */
height: auto; /* 自适应高度 */
padding: 10px 0; /* 添加垂直内边距 */
}
/* 操作按钮通用样式 */
.action-btn {
padding: 6px 15px; /* 内边距 */
border: none; /* 无边框 */
border-radius: 4px; /* 7px圆角 */
font-size: 12px; /* 字体大小15px */
font-weight: 600; /* 中等加粗 */
cursor: pointer; /* 鼠标指针为手型 */
/* transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); 自定义缓动过渡 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
min-width: 120px; /* 最小宽度120px */
letter-spacing: 4px; /* 字符间距4px */
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.06); /* 轻微阴影 */
}
/* 操作按钮图标 */
.action-btn i {
margin-right: 8px; /* 右侧外边距8px */
font-size: 16px; /* 字体大小16px */
}
/* 主要按钮样式 */
.btn-primary {
background: linear-gradient(to right,#409EFF , #409EFF);
color: white; /* 白色文字 */
position: relative; /* 相对定位 */
overflow: hidden; /* 隐藏溢出内容 */
}
/* 主要按钮悬停效果 */
.btn-primary:hover {
background: linear-gradient(to right, #2196f3, #1565c0); /* 更亮的蓝色渐变 */
box-shadow: 0 5px 10px rgba(33, 150, 243, 0.25); /* 增加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 主要按钮悬停时伪元素动画 */
.btn-primary:hover::after {
left: 140%; /* 移动到右侧140%位置 */
}
/* 默认按钮样式 */
.btn-default {
background: #f7fafc; /* 浅灰色背景 */
color: #4a5568; /* 深灰色文字 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
}
/* 默认按钮悬停效果 */
.btn-default:hover {
background: white; /* 白色背景 */
border-color: #a0aec0; /* 边框颜色加深 */
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.06); /* 添加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 标记控制按钮容器 */
.mark-controls {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(4, minmax(140px, 1fr)); /* 自适应列 */
gap: 12px; /* 元素间距12px */
margin-top: 10px; /* 顶部外边距18px */
}
/* 标记按钮样式 */
.mark-btn {
display: inline-block;
padding: 4px 4px;
font-size: 13px;
border: 0.1px solid #dcdfe6;
border-radius: 4px;
cursor: pointer;
background: #ECF5FF;
border-color: #9ccaf7;
color: #409EFE;
letter-spacing: 3px; /* 添加微小间距 */
font-weight: 500; /* 加粗效果 */
text-align: center;
}
/* 标记按钮悬停效果 */
.mark-btn:hover {
background: #409EFE;
border-color: #409EFF;
color:#ffffff;
}
/* 标记按钮图标 */
.mark-btn i {
font-size: 13px; /* 字体大小16px */
}
/* 光标指示器样式 */
.cursor-indicator {
position: absolute; /* 绝对定位 */
width: 2px; /* 宽度2px */
height: 18px; /* 高度18px */
background-color: #e53935; /* 红色背景 */
pointer-events: none; /* 不响应鼠标事件 */
z-index: 100; /* 高z-index确保显示在最上层 */
border-radius: 1px; /* 轻微圆角 */
box-shadow: 0 0 2px rgba(229, 57, 53, 0.7); /* 红色发光效果 */
}
/* 标记对话框样式 */
.mark-dialog {
border-radius: 10px; /* 10px圆角 */
overflow: hidden; /* 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
.connector-dialog{
border-radius: 10px; /* 10px圆角 */
/* overflow: hidden; 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
/* 对话框头部样式 */
.mark-dialog-header, .connector-dialog-header {
background: linear-gradient(135deg, #1e88e5, #1565c0); /* 蓝色渐变背景 */
border:none !important;
color: white; /* 白色文字 */
padding: 5px 8px; /* 内边距 */
font-size: 18px; /* 字体大小18px */
font-weight: 600; /* 中等加粗 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 10px; /* 元素间距10px */
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 对话框头部图标 */
.mark-dialog-header i, .connector-dialog-header i {
font-size: 24px; /* 字体大小24px */
}
/* 对话框主体区域 */
.mark-dialog-body, .connector-dialog-body {
border:none !important;
padding: 0px 0px; /* 内边距20px */
background: #f8fafc; /* 浅灰色背景 */
}
/* 标记选项容器 */
.mark-options {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(auto-fit, minmax(18px, 1fr)); /* 自适应列 */
gap: 4px; /* 元素间距4px */
margin-top: 4px; /* 顶部外边距4px */
}
/* 标记选项按钮 */
.mark-option {
padding: 14px 8px; /* 内边距 */
background: #e3f2fd; /* 浅蓝色背景 */
border: 1px solid #bbdefb; /* 1px浅蓝色边框 */
border-radius: 7px; /* 7px圆角 */
color: #1976d2; /* 蓝色文字 */
cursor: pointer; /* 鼠标指针为手型 */
text-align: center; /* 文字居中 */
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); /* 自定义缓动过渡 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 标记选项悬停效果 */
.mark-option:hover {
background: #bbdefb; /* 加深背景色 */
border-color: #90caf9; /* 加深边框色 */
transform: translateY(-3px) scale(1.02); /* 上移并轻微放大 */
box-shadow: 0 6px 12px rgba(25, 118, 210, 0.15); /* 添加蓝色阴影 */
}
/* 响应式设计:屏幕宽度小于768px时的调整 */
@media (max-width: 768px) { /* 媒体查询,针对小屏幕设备[6](@ref) */
.syntax-container {
margin: 8px auto; /* 减小外边距 */
}
.syntax-body {
padding: 16px; /* 调整内边距 */
}
.action-buttons {
flex-direction: column; /* 垂直排列按钮 */
gap: 10px; /* 按钮间距10px */
}
.action-btn {
width: 100%; /* 按钮宽度100% */
padding: 12px; /* 调整内边距 */
}
}
+671
View File
@@ -0,0 +1,671 @@
const { createApp, ref, onMounted, nextTick } = Vue;
const { ElMessage } = ElementPlus;
const app = createApp({
setup() {
// 从URL获取参数的函数
function getParameterByName(name, url = window.location.href) {
debugger;
name = name.replace(/[\[\]]/g, '\\$&');
const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
const results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
// 当用户完成操作时调用此函数
function returnSyntaxResult(result) {
// 将结果存储到localStorage
const resultKey = `syntaxResult_${windowId}`;
localStorage.setItem(resultKey, JSON.stringify(result));
// 关闭窗口
window.close();
}
// 过滤标记串(只保留型号码、前缀码、后缀码)
const filterMarkString = (str) => {
if (!str) return '';
// 匹配所有标记
const regex = /\[([^\]]+)=([^\]]+)\]/g;
const matches = str.matchAll(regex);
let validTags = [];
debugger;
switch(title.value) {
case '线缆型号语法':
validTags = ['型号码', '前缀码', '后缀码'];
break;
case '线缆规格语法':
validTags = ['截面', '芯数', '线组数', '线对数'];
break;
case '电压等级语法':
validTags = ['相电压', '线电压', '电压单位'];
break;
case '线缆标准语法':
validTags = ['标准名'];
break;
default:
// 默认为线缆型号语法
validTags = ['型号码', '前缀码', '后缀码'];
}
const filtered = [];
for (const match of matches) {
const tag = match[1];
if (validTags.includes(tag)) {
filtered.push(`[${tag}=${match[2]}]`);
}
}
return filtered.join('');
};
// 获取URL传递的参数
const urlParams = {
title: getParameterByName('title') || '',
ruleString: getParameterByName('ruleString1') || '',
syntaxString: getParameterByName('syntaxString') || '',
connectors: getParameterByName('connectors') || ''
};
// 页面数据
const originalMarkString = ref(urlParams.ruleString);
const syntaxString = ref(urlParams.syntaxString); // 使用传递的语法串
const orgsyntaxString = ref(urlParams.syntaxString);
const cursorPosition = ref(-1);
const syntaxEditor = ref(null);
const actualValue = ref('');
const title = ref(urlParams.title);
const filteredMarkString = ref(filterMarkString(urlParams.ruleString));
// 对话框相关
const showMarkDialog = ref(false);
const showConnectorDialog = ref(false);
const selectedConnector = ref('');
const availableMarks = ref([]);
const predefinedConnectors = ref(urlParams.connectors.split(','));
const loadingConnectors = ref(false);
const customConnector = ref('');
// 更新光标位置
const updateCursorPosition = () => {
if (syntaxEditor.value) {
cursorPosition.value = syntaxEditor.value.selectionStart;
}
};
const updateActualValue = () => {
// 解析标记串中的所有标记(按顺序)
const markArray = [];
const markRegex = /\[([^\]]+)=([^\]]+)\]/g;
let markMatch;
while ((markMatch = markRegex.exec(filteredMarkString.value)) !== null) {
markArray.push({
tag: markMatch[1],
value: markMatch[2]
});
}
// 解析语法串
let result = '';
const syntaxRegex = /(\[[^\]]+\])|([^[]+)/g;
let syntaxMatch;
while ((syntaxMatch = syntaxRegex.exec(syntaxString.value)) !== null) {
if (syntaxMatch[1]) {
// 处理标记字部分
const innerRegex = /\[([^\]]+)([a-z])\]/;
const innerMatch = syntaxMatch[1].match(innerRegex);
if (innerMatch) {
const tag = innerMatch[1];
const char = innerMatch[2];
const index = char.charCodeAt(0) - 97; // a->0, b->1, etc.
// 检查索引是否在标记数组范围内
if (index < markArray.length) {
// 获取对应位置的标记
const mark = markArray[index];
// 检查标记类型是否匹配
if (mark.tag === tag) {
result += mark.value;
}
}
}
} else if (syntaxMatch[2]) {
// 处理普通文本(链接符)
result += syntaxMatch[2];
}
}
actualValue.value = result;
};
// 打开插入标记字对话框
const openInsertMarkDialog = () => {
// 解析语法串中的所有标记字
availableMarks.value = [];
const regex = /\[[^\]]+\]/g;
const matches = orgsyntaxString.value.match(regex) || [];
// 去重
const uniqueMarks = [...new Set(matches)];
if (uniqueMarks.length > 0) {
availableMarks.value = uniqueMarks;
showMarkDialog.value = true;
} else {
ElMessage.warning('语法串中没有可用的标记字');
}
};
// 插入选中的标记字
const insertSelectedMark = (mark) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showMarkDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入标记字
syntaxString.value = before + mark + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + mark.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showMarkDialog.value = false;
ElMessage.success(`已插入标记字: ${mark}`);
};
// 打开插入链接符对话框
const openInsertConnectorDialog = () => {
showConnectorDialog.value = true;
selectedConnector.value = ''; // 清空前一次选择
customConnector.value = ''; // 清空前一次自定义输入
};
// 处理选择变化
const handleConnectorChange = (value) => {
// 如果是自定义输入且不在预定义列表中
if (value && !predefinedConnectors.value.includes(value)) {
customConnector.value = value;
}
};
// 插入选中的链接符
const insertSelectedConnector = (connector) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showConnectorDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入链接符
syntaxString.value = before + connector + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + connector.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showConnectorDialog.value = false;
ElMessage.success(`已插入链接符: ${connector}`);
};
// 删除链接符
const deleteConnector = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
if (text.trim() === '') {
return;
}
// 初始化起始和结束位置
let iStart = cursorPos;
let iEnd = cursorPos;
// 向左查找
let i = cursorPos;
if (i >= 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
iStart = i;
break;
}
if (char === '[') {
ElMessage.warning('请将光标置于语法串中的连接符位置');
return;
}
i--;
}
if (i === 0) {
iStart = 0;
}
}
// 向右查找
i = cursorPos;
if (i >= 0) {
while (i < text.length) {
const char = text.charAt(i);
if (char === '[') {
iEnd = i;
break;
}
i++;
}
if (i === text.length) {
iEnd = text.length;
}
}
// 构建新字符串
let newText = '';
if (iStart === 0) {
newText = text.substring(iEnd);
} else {
newText = text.substring(0, iStart) + text.substring(iEnd);
}
syntaxString.value = newText;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(iStart, iStart);
cursorPosition.value = iStart;
});
ElMessage.info('已删除链接符');
};
// 获取当前标记字内容
const getCurrentBracketContent = (text, cursorPos) => {
let startIndex = -1;
let endIndex = -1;
// 查找当前标记字的起始位置
let i = 1;
while (i <= cursorPos) {
if (text.charAt(i - 1) === '[') {
startIndex = i - 1;
}
i++;
}
// 查找当前标记字的结束位置
i = cursorPos;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取下一个标记字内容
const getNextBracketContent = (text, afterIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找下一个标记字的起始位置
let i = afterIndex + 1;
while (i < text.length) {
if (text.charAt(i) === '[') {
startIndex = i;
break;
}
i++;
}
// 查找下一个标记字的结束位置
if (startIndex !== -1) {
i = startIndex;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取前一个标记字内容
const getPreviousBracketContent = (text, beforeIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找前一个标记字的起始位置
let i = 1;
let lastStart = -1;
while (i < beforeIndex) {
if (text.charAt(i - 1) === '[') {
lastStart = i - 1;
}
i++;
}
if (lastStart !== -1) {
startIndex = lastStart;
// 查找前一个标记字的结束位置
i = lastStart;
while (i < beforeIndex) {
if (text.charAt(i) === ']') {
endIndex = i;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 后移标记字
const moveMarkBackward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取下一个标记字
const nextMark = getNextBracketContent(text, currentMark.end);
if (!nextMark) {
ElMessage.warning('后面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, currentMark.start);
const between = text.substring(currentMark.end + 1, nextMark.start);
const after = text.substring(nextMark.end + 1);
syntaxString.value = before + nextMark.content + between + currentMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length + nextMark.content.length + between.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 前移标记字
const moveMarkForward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取前一个标记字
const previousMark = getPreviousBracketContent(text, currentMark.start);
if (!previousMark) {
ElMessage.warning('前面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, previousMark.start);
const between = text.substring(previousMark.end + 1, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + currentMark.content + between + previousMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 删除标记字
const deleteMark = () => {
if (!syntaxEditor.value || !syntaxString.value) {
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要删除的标记字内');
return;
}
// 删除标记字
const before = text.substring(0, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + after;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(currentMark.start, currentMark.start);
cursorPosition.value = currentMark.start;
});
ElMessage.info('已删除标记字');
};
// 保存语法设置
const saveSyntax = () => {
const result = {
type: title.value,
Value: syntaxString.value,
ActualValue: actualValue.value
};
window.parent.postMessage({
type: 'SAVE_SYNTAX_RESULT',
payload: result
}, '*');
ElMessage.success('语法规则已保存');
};
// 应用语法设置
const applySyntax = () => {
ElMessage.success('语法规则已成功应用');
setTimeout(() => {
window.close();
}, 1000);
};
// 重置表单
const resetForm = () => {
syntaxString.value = urlParams.syntaxString; // 重置为初始传递的值
actualValue.value = '';
cursorPosition.value = -1;
updateActualValue(); // 重新计算实际值
};
// 关闭窗口
const closeWindow = () => {
window.close();
};
// 初始化
onMounted(() => {
updateActualValue();
});
return {
filteredMarkString,
syntaxString,
cursorPosition,
syntaxEditor,
actualValue,
showMarkDialog,
showConnectorDialog,
availableMarks,
predefinedConnectors,
updateCursorPosition,
openInsertMarkDialog,
insertSelectedMark,
openInsertConnectorDialog,
insertSelectedConnector,
selectedConnector,
deleteConnector,
moveMarkForward,
moveMarkBackward,
deleteMark,
saveSyntax,
applySyntax,
resetForm,
closeWindow,
handleConnectorChange,
title
};
}
});
app.use(ElementPlus);
app.mount('#app');
+418
View File
@@ -0,0 +1,418 @@
/* 全局选择器,应用于所有元素 */
* {
margin: 0; /* 清除所有元素的外边距 */
padding: 0; /* 清除所有元素的内边距 */
box-sizing: border-box; /* 设置盒模型为border-box,使宽高包含边框和内边距[2](@ref) */
/* font-family: "Segoe UI", "Microsoft YaHei", sans-serif; 设置字体栈,优先使用Segoe UI,回退到微软雅黑和无衬线字体 */
}
/* 设置网页主体样式 */
body {
background-color: #f0f4f8; /* 浅蓝色背景 */
color: #2d3748; /* 深灰色文字 */
line-height: 1; /* 行高为字体大小的1倍 */
padding: 0px; /* 主体四周添加4px内边距 */
}
/* 主内容容器 */
.syntax-container {
max-width: 1300px; /* 最大宽度限制 */
margin: 0px auto; /* 上下10px外边距,水平居中 */
background: white; /* 白色背景 */
/* border-radius: 10px; 10px圆角 */
/* box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); 添加轻微阴影 */
overflow: hidden; /* 隐藏溢出内容 */
transition: transform 0.3s ease, box-shadow 0.3s ease; /* 添加过渡动画效果 */
}
/* 头部区域样式 */
.syntax-header {
background: #409EFF; /* 蓝色渐变背景 */
color: white; /* 白色文字 */
padding: 0px 0px; /* 无内边距 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: space-between; /* 两端对齐 */
position: relative; /* 相对定位 */
}
/* 头部底部的装饰线 */
.syntax-header::after {
content: ''; /* 伪元素内容 */
position: absolute; /* 绝对定位 */
bottom: 0; /* 定位到底部 */
left: 0; /* 定位到左侧 */
width: 100%; /* 宽度100% */
height: 0px; /* 高度3px */
background: linear-gradient(90deg, #43a047, #1e88e5, #e53935); /* 三色渐变 */
opacity: 0.7; /* 70%透明度 */
}
/* 头部左侧区域 */
.header-left {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 0px; /* 元素间无间隙 */
}
/* 应用图标样式 */
.app-icon {
width: 12px; /* 宽度12px */
height: 30px; /* 高度12px */
background-color: #409EFF; /* 半透明白色背景 */
/* border-radius: 6px; 圆形 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
font-size: 20px; /* 字体大小10px */
color: white; /* 白色文字 */
/* backdrop-filter: blur(2px); 背景模糊效果 */
/* box-shadow: 0 3px 5px rgba(0, 0, 0, 0.08); 轻微阴影 */
}
/* 应用标题样式 */
.app-title h1 {
font-size: 20px; /* 字体大小10px */
font-weight: 600; /* 中等加粗 */
letter-spacing: 0.4px; /* 字符间距0.4px */
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 主体内容区域 */
.syntax-body {
padding: 20px; /* 内边距10px */
}
/* 信息组容器 */
.info-group {
margin-bottom: 5px; /* 底部外边距20px */
background: #f9fafc; /* 浅灰色背景 */
border-radius: 8px; /* 8px圆角 */
padding: 5px; /* 内边距16px */
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.02); /* 轻微阴影 */
}
/* 信息组标题区域 */
.info-group-title {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
margin-bottom: 8px; /* 底部外边距14px */
padding-bottom: 8px; /* 底部内边距10px */
border-bottom: 1px solid #e2e8f0; /* 底部1px浅灰色边框 */
}
/* 信息组标题文字样式 */
.info-group-title h2 {
font-size: 16px; /* 字体大小16px */
color: #000000; /* 蓝色文字 */
font-weight: 600; /* 中等加粗 */
padding-left: 10px; /* 左侧内边距10px */
}
/* 输入组样式 */
.input-group {
margin-bottom: 4px; /* 底部外边距16px */
}
/* 输入标签样式 */
.input-group label {
display: block; /* 块级元素 */
margin-bottom: 4px; /* 底部外边距8px */
color: #4a5568; /* 深灰色文字 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 输入字段通用样式 */
.input-field {
width: 100%; /* 宽度100% */
padding: 2px 2px; /* 内边距 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
border-radius: 7px; /* 7px圆角 */
font-size: 14px; /* 字体大小14px */
transition: all 0.3s; /* 所有属性0.3秒过渡 */
background: white; /* 白色背景 */
color: #2d3748; /* 深灰色文字 */
}
/* 输入字段聚焦状态 */
.input-field:focus {
border-color: #1e88e5; /* 边框变为蓝色 */
outline: none; /* 移除默认轮廓线 */
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.12); /* 添加蓝色发光效果 */
}
/* 文本域特殊样式 */
.input-field.textarea {
min-height: 30px; /* 最小高度85px */
resize: vertical; /* 允许垂直调整大小 */
font-family: 'Consolas', monospace; /* 等宽字体 */
padding: 6px; /* 内边距14px */
line-height: 1.5; /* 行高1.6倍 */
font-size: 13.5px; /* 字体大小13.5px */
}
/* 结果显示区域 */
.result-display {
background: linear-gradient(to right, #f7fafc, #edf2f7); /* 左右渐变背景 */
border: 1px solid #e2e8f0; /* 1px浅灰色边框 */
border-radius: 8px; /* 8px圆角 */
padding: 18px; /* 内边距18px */
margin: 9px 0; /* 上下外边距18px */
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.03); /* 内阴影 */
}
/* 结果项样式 */
.result-item {
margin-bottom: 14px; /* 底部外边距14px */
padding-bottom: 14px; /* 底部内边距14px */
border-bottom: 1px dashed #e2e8f0; /* 底部1px虚线边框 */
}
/* 最后一个结果项特殊处理 */
.result-item:last-child {
margin-bottom: 0; /* 无底部外边距 */
padding-bottom: 0; /* 无底部内边距 */
border-bottom: none; /* 无底部边框 */
}
/* 结果标签样式 */
.result-label {
color: #718096; /* 中灰色文字 */
font-size: 14px; /* 字体大小14px */
margin-bottom: 6px; /* 底部外边距6px */
font-weight: 500; /* 中等加粗 */
}
/* 结果值样式 */
.result-value {
font-size: 16px; /* 字体大小16px */
font-weight: 600; /* 中等加粗 */
color: #2d3748; /* 深灰色文字 */
}
/* 结果值中的高亮部分 */
.result-value .highlight {
color: #1e88e5; /* 蓝色文字 */
font-weight: 700; /* 加粗 */
font-size: 16px; /* 字体大小16px */
letter-spacing: 0.4px; /* 字符间距0.4px */
}
/* 操作按钮容器 */
.action-buttons {
display: flex; /* 启用Flex布局 */
justify-content: center; /* 水平居中 */
align-items: center; /*垂直居中*/
margin-top: 10px; /* 顶部外边距20px */
gap: 15px; /* 按钮间距15px */
height: auto; /* 自适应高度 */
padding: 10px 0; /* 添加垂直内边距 */
}
/* 操作按钮通用样式 */
.action-btn {
padding: 6px 15px; /* 内边距 */
border: none; /* 无边框 */
border-radius: 4px; /* 7px圆角 */
font-size: 12px; /* 字体大小15px */
font-weight: 600; /* 中等加粗 */
cursor: pointer; /* 鼠标指针为手型 */
/* transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); 自定义缓动过渡 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
min-width: 120px; /* 最小宽度120px */
letter-spacing: 4px; /* 字符间距4px */
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.06); /* 轻微阴影 */
}
/* 操作按钮图标 */
.action-btn i {
margin-right: 8px; /* 右侧外边距8px */
font-size: 16px; /* 字体大小16px */
}
/* 主要按钮样式 */
.btn-primary {
background: linear-gradient(to right,#409EFF , #409EFF);
color: white; /* 白色文字 */
position: relative; /* 相对定位 */
overflow: hidden; /* 隐藏溢出内容 */
}
/* 主要按钮悬停效果 */
.btn-primary:hover {
background: linear-gradient(to right, #2196f3, #1565c0); /* 更亮的蓝色渐变 */
box-shadow: 0 5px 10px rgba(33, 150, 243, 0.25); /* 增加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 主要按钮悬停时伪元素动画 */
.btn-primary:hover::after {
left: 140%; /* 移动到右侧140%位置 */
}
/* 默认按钮样式 */
.btn-default {
background: #f7fafc; /* 浅灰色背景 */
color: #4a5568; /* 深灰色文字 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
}
/* 默认按钮悬停效果 */
.btn-default:hover {
background: white; /* 白色背景 */
border-color: #a0aec0; /* 边框颜色加深 */
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.06); /* 添加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 标记控制按钮容器 */
.mark-controls {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(4, minmax(140px, 1fr)); /* 自适应列 */
gap: 12px; /* 元素间距12px */
margin-top: 10px; /* 顶部外边距18px */
}
/* 标记按钮样式 */
.mark-btn {
display: inline-block;
padding: 4px 4px;
font-size: 13px;
border: 0.1px solid #dcdfe6;
border-radius: 4px;
cursor: pointer;
background: #ECF5FF;
border-color: #9ccaf7;
color: #409EFE;
letter-spacing: 3px; /* 添加微小间距 */
font-weight: 500; /* 加粗效果 */
text-align: center;
}
/* 标记按钮悬停效果 */
.mark-btn:hover {
background: #409EFE;
border-color: #409EFF;
color:#ffffff;
}
/* 标记按钮图标 */
.mark-btn i {
font-size: 13px; /* 字体大小16px */
}
/* 光标指示器样式 */
.cursor-indicator {
position: absolute; /* 绝对定位 */
width: 2px; /* 宽度2px */
height: 18px; /* 高度18px */
background-color: #e53935; /* 红色背景 */
pointer-events: none; /* 不响应鼠标事件 */
z-index: 100; /* 高z-index确保显示在最上层 */
border-radius: 1px; /* 轻微圆角 */
box-shadow: 0 0 2px rgba(229, 57, 53, 0.7); /* 红色发光效果 */
}
/* 标记对话框样式 */
.mark-dialog {
border-radius: 10px; /* 10px圆角 */
overflow: hidden; /* 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
.connector-dialog{
border-radius: 10px; /* 10px圆角 */
/* overflow: hidden; 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
/* 对话框头部样式 */
.mark-dialog-header, .connector-dialog-header {
background: linear-gradient(135deg, #1e88e5, #1565c0); /* 蓝色渐变背景 */
border:none !important;
color: white; /* 白色文字 */
padding: 5px 8px; /* 内边距 */
font-size: 18px; /* 字体大小18px */
font-weight: 600; /* 中等加粗 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 10px; /* 元素间距10px */
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 对话框头部图标 */
.mark-dialog-header i, .connector-dialog-header i {
font-size: 24px; /* 字体大小24px */
}
/* 对话框主体区域 */
.mark-dialog-body, .connector-dialog-body {
border:none !important;
padding: 0px 0px; /* 内边距20px */
background: #f8fafc; /* 浅灰色背景 */
}
/* 标记选项容器 */
.mark-options {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(auto-fit, minmax(18px, 1fr)); /* 自适应列 */
gap: 4px; /* 元素间距4px */
margin-top: 4px; /* 顶部外边距4px */
}
/* 标记选项按钮 */
.mark-option {
padding: 14px 8px; /* 内边距 */
background: #e3f2fd; /* 浅蓝色背景 */
border: 1px solid #bbdefb; /* 1px浅蓝色边框 */
border-radius: 7px; /* 7px圆角 */
color: #1976d2; /* 蓝色文字 */
cursor: pointer; /* 鼠标指针为手型 */
text-align: center; /* 文字居中 */
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); /* 自定义缓动过渡 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 标记选项悬停效果 */
.mark-option:hover {
background: #bbdefb; /* 加深背景色 */
border-color: #90caf9; /* 加深边框色 */
transform: translateY(-3px) scale(1.02); /* 上移并轻微放大 */
box-shadow: 0 6px 12px rgba(25, 118, 210, 0.15); /* 添加蓝色阴影 */
}
/* 响应式设计:屏幕宽度小于768px时的调整 */
@media (max-width: 768px) { /* 媒体查询,针对小屏幕设备[6](@ref) */
.syntax-container {
margin: 8px auto; /* 减小外边距 */
}
.syntax-body {
padding: 16px; /* 调整内边距 */
}
.action-buttons {
flex-direction: column; /* 垂直排列按钮 */
gap: 10px; /* 按钮间距10px */
}
.action-btn {
width: 100%; /* 按钮宽度100% */
padding: 12px; /* 调整内边距 */
}
}
+671
View File
@@ -0,0 +1,671 @@
const { createApp, ref, onMounted, nextTick } = Vue;
const { ElMessage } = ElementPlus;
const app = createApp({
setup() {
// 从URL获取参数的函数
function getParameterByName(name, url = window.location.href) {
debugger;
name = name.replace(/[\[\]]/g, '\\$&');
const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
const results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
// 当用户完成操作时调用此函数
function returnSyntaxResult(result) {
// 将结果存储到localStorage
const resultKey = `syntaxResult_${windowId}`;
localStorage.setItem(resultKey, JSON.stringify(result));
// 关闭窗口
window.close();
}
// 过滤标记串(只保留型号码、前缀码、后缀码)
const filterMarkString = (str) => {
if (!str) return '';
// 匹配所有标记
const regex = /\[([^\]]+)=([^\]]+)\]/g;
const matches = str.matchAll(regex);
let validTags = [];
debugger;
switch(title.value) {
case '线缆型号语法':
validTags = ['型号码', '前缀码', '后缀码'];
break;
case '线缆规格语法':
validTags = ['截面', '芯数', '线组数', '线对数'];
break;
case '电压等级语法':
validTags = ['相电压', '线电压', '电压单位'];
break;
case '线缆标准语法':
validTags = ['标准名'];
break;
default:
// 默认为线缆型号语法
validTags = ['型号码', '前缀码', '后缀码'];
}
const filtered = [];
for (const match of matches) {
const tag = match[1];
if (validTags.includes(tag)) {
filtered.push(`[${tag}=${match[2]}]`);
}
}
return filtered.join('');
};
// 获取URL传递的参数
const urlParams = {
title: getParameterByName('title') || '',
ruleString: getParameterByName('ruleString1') || '',
syntaxString: getParameterByName('syntaxString') || '',
connectors: getParameterByName('connectors') || ''
};
// 页面数据
const originalMarkString = ref(urlParams.ruleString);
const syntaxString = ref(urlParams.syntaxString); // 使用传递的语法串
const orgsyntaxString = ref(urlParams.syntaxString);
const cursorPosition = ref(-1);
const syntaxEditor = ref(null);
const actualValue = ref('');
const title = ref(urlParams.title);
const filteredMarkString = ref(filterMarkString(urlParams.ruleString));
// 对话框相关
const showMarkDialog = ref(false);
const showConnectorDialog = ref(false);
const selectedConnector = ref('');
const availableMarks = ref([]);
const predefinedConnectors = ref(urlParams.connectors.split(','));
const loadingConnectors = ref(false);
const customConnector = ref('');
// 更新光标位置
const updateCursorPosition = () => {
if (syntaxEditor.value) {
cursorPosition.value = syntaxEditor.value.selectionStart;
}
};
const updateActualValue = () => {
// 解析标记串中的所有标记(按顺序)
const markArray = [];
const markRegex = /\[([^\]]+)=([^\]]+)\]/g;
let markMatch;
while ((markMatch = markRegex.exec(filteredMarkString.value)) !== null) {
markArray.push({
tag: markMatch[1],
value: markMatch[2]
});
}
// 解析语法串
let result = '';
const syntaxRegex = /(\[[^\]]+\])|([^[]+)/g;
let syntaxMatch;
while ((syntaxMatch = syntaxRegex.exec(syntaxString.value)) !== null) {
if (syntaxMatch[1]) {
// 处理标记字部分
const innerRegex = /\[([^\]]+)([a-z])\]/;
const innerMatch = syntaxMatch[1].match(innerRegex);
if (innerMatch) {
const tag = innerMatch[1];
const char = innerMatch[2];
const index = char.charCodeAt(0) - 97; // a->0, b->1, etc.
// 检查索引是否在标记数组范围内
if (index < markArray.length) {
// 获取对应位置的标记
const mark = markArray[index];
// 检查标记类型是否匹配
if (mark.tag === tag) {
result += mark.value;
}
}
}
} else if (syntaxMatch[2]) {
// 处理普通文本(链接符)
result += syntaxMatch[2];
}
}
actualValue.value = result;
};
// 打开插入标记字对话框
const openInsertMarkDialog = () => {
// 解析语法串中的所有标记字
availableMarks.value = [];
const regex = /\[[^\]]+\]/g;
const matches = orgsyntaxString.value.match(regex) || [];
// 去重
const uniqueMarks = [...new Set(matches)];
if (uniqueMarks.length > 0) {
availableMarks.value = uniqueMarks;
showMarkDialog.value = true;
} else {
ElMessage.warning('语法串中没有可用的标记字');
}
};
// 插入选中的标记字
const insertSelectedMark = (mark) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showMarkDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入标记字
syntaxString.value = before + mark + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + mark.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showMarkDialog.value = false;
ElMessage.success(`已插入标记字: ${mark}`);
};
// 打开插入链接符对话框
const openInsertConnectorDialog = () => {
showConnectorDialog.value = true;
selectedConnector.value = ''; // 清空前一次选择
customConnector.value = ''; // 清空前一次自定义输入
};
// 处理选择变化
const handleConnectorChange = (value) => {
// 如果是自定义输入且不在预定义列表中
if (value && !predefinedConnectors.value.includes(value)) {
customConnector.value = value;
}
};
// 插入选中的链接符
const insertSelectedConnector = (connector) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showConnectorDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入链接符
syntaxString.value = before + connector + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + connector.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showConnectorDialog.value = false;
ElMessage.success(`已插入链接符: ${connector}`);
};
// 删除链接符
const deleteConnector = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
if (text.trim() === '') {
return;
}
// 初始化起始和结束位置
let iStart = cursorPos;
let iEnd = cursorPos;
// 向左查找
let i = cursorPos;
if (i >= 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
iStart = i;
break;
}
if (char === '[') {
ElMessage.warning('请将光标置于语法串中的连接符位置');
return;
}
i--;
}
if (i === 0) {
iStart = 0;
}
}
// 向右查找
i = cursorPos;
if (i >= 0) {
while (i < text.length) {
const char = text.charAt(i);
if (char === '[') {
iEnd = i;
break;
}
i++;
}
if (i === text.length) {
iEnd = text.length;
}
}
// 构建新字符串
let newText = '';
if (iStart === 0) {
newText = text.substring(iEnd);
} else {
newText = text.substring(0, iStart) + text.substring(iEnd);
}
syntaxString.value = newText;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(iStart, iStart);
cursorPosition.value = iStart;
});
ElMessage.info('已删除链接符');
};
// 获取当前标记字内容
const getCurrentBracketContent = (text, cursorPos) => {
let startIndex = -1;
let endIndex = -1;
// 查找当前标记字的起始位置
let i = 1;
while (i <= cursorPos) {
if (text.charAt(i - 1) === '[') {
startIndex = i - 1;
}
i++;
}
// 查找当前标记字的结束位置
i = cursorPos;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取下一个标记字内容
const getNextBracketContent = (text, afterIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找下一个标记字的起始位置
let i = afterIndex + 1;
while (i < text.length) {
if (text.charAt(i) === '[') {
startIndex = i;
break;
}
i++;
}
// 查找下一个标记字的结束位置
if (startIndex !== -1) {
i = startIndex;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取前一个标记字内容
const getPreviousBracketContent = (text, beforeIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找前一个标记字的起始位置
let i = 1;
let lastStart = -1;
while (i < beforeIndex) {
if (text.charAt(i - 1) === '[') {
lastStart = i - 1;
}
i++;
}
if (lastStart !== -1) {
startIndex = lastStart;
// 查找前一个标记字的结束位置
i = lastStart;
while (i < beforeIndex) {
if (text.charAt(i) === ']') {
endIndex = i;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 后移标记字
const moveMarkBackward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取下一个标记字
const nextMark = getNextBracketContent(text, currentMark.end);
if (!nextMark) {
ElMessage.warning('后面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, currentMark.start);
const between = text.substring(currentMark.end + 1, nextMark.start);
const after = text.substring(nextMark.end + 1);
syntaxString.value = before + nextMark.content + between + currentMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length + nextMark.content.length + between.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 前移标记字
const moveMarkForward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取前一个标记字
const previousMark = getPreviousBracketContent(text, currentMark.start);
if (!previousMark) {
ElMessage.warning('前面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, previousMark.start);
const between = text.substring(previousMark.end + 1, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + currentMark.content + between + previousMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 删除标记字
const deleteMark = () => {
if (!syntaxEditor.value || !syntaxString.value) {
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要删除的标记字内');
return;
}
// 删除标记字
const before = text.substring(0, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + after;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(currentMark.start, currentMark.start);
cursorPosition.value = currentMark.start;
});
ElMessage.info('已删除标记字');
};
// 保存语法设置
const saveSyntax = () => {
const result = {
type: title.value,
Value: syntaxString.value,
ActualValue: actualValue.value
};
window.parent.postMessage({
type: 'SAVE_SYNTAX_RESULT',
payload: result
}, '*');
ElMessage.success('语法规则已保存');
};
// 应用语法设置
const applySyntax = () => {
ElMessage.success('语法规则已成功应用');
setTimeout(() => {
window.close();
}, 1000);
};
// 重置表单
const resetForm = () => {
syntaxString.value = urlParams.syntaxString; // 重置为初始传递的值
actualValue.value = '';
cursorPosition.value = -1;
updateActualValue(); // 重新计算实际值
};
// 关闭窗口
const closeWindow = () => {
window.close();
};
// 初始化
onMounted(() => {
updateActualValue();
});
return {
filteredMarkString,
syntaxString,
cursorPosition,
syntaxEditor,
actualValue,
showMarkDialog,
showConnectorDialog,
availableMarks,
predefinedConnectors,
updateCursorPosition,
openInsertMarkDialog,
insertSelectedMark,
openInsertConnectorDialog,
insertSelectedConnector,
selectedConnector,
deleteConnector,
moveMarkForward,
moveMarkBackward,
deleteMark,
saveSyntax,
applySyntax,
resetForm,
closeWindow,
handleConnectorChange,
title
};
}
});
app.use(ElementPlus);
app.mount('#app');
+418
View File
@@ -0,0 +1,418 @@
/* 全局选择器,应用于所有元素 */
* {
margin: 0; /* 清除所有元素的外边距 */
padding: 0; /* 清除所有元素的内边距 */
box-sizing: border-box; /* 设置盒模型为border-box,使宽高包含边框和内边距[2](@ref) */
/* font-family: "Segoe UI", "Microsoft YaHei", sans-serif; 设置字体栈,优先使用Segoe UI,回退到微软雅黑和无衬线字体 */
}
/* 设置网页主体样式 */
body {
background-color: #f0f4f8; /* 浅蓝色背景 */
color: #2d3748; /* 深灰色文字 */
line-height: 1; /* 行高为字体大小的1倍 */
padding: 0px; /* 主体四周添加4px内边距 */
}
/* 主内容容器 */
.syntax-container {
max-width: 1300px; /* 最大宽度限制 */
margin: 0px auto; /* 上下10px外边距,水平居中 */
background: white; /* 白色背景 */
/* border-radius: 10px; 10px圆角 */
/* box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); 添加轻微阴影 */
overflow: hidden; /* 隐藏溢出内容 */
transition: transform 0.3s ease, box-shadow 0.3s ease; /* 添加过渡动画效果 */
}
/* 头部区域样式 */
.syntax-header {
background: #409EFF; /* 蓝色渐变背景 */
color: white; /* 白色文字 */
padding: 0px 0px; /* 无内边距 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: space-between; /* 两端对齐 */
position: relative; /* 相对定位 */
}
/* 头部底部的装饰线 */
.syntax-header::after {
content: ''; /* 伪元素内容 */
position: absolute; /* 绝对定位 */
bottom: 0; /* 定位到底部 */
left: 0; /* 定位到左侧 */
width: 100%; /* 宽度100% */
height: 0px; /* 高度3px */
background: linear-gradient(90deg, #43a047, #1e88e5, #e53935); /* 三色渐变 */
opacity: 0.7; /* 70%透明度 */
}
/* 头部左侧区域 */
.header-left {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 0px; /* 元素间无间隙 */
}
/* 应用图标样式 */
.app-icon {
width: 12px; /* 宽度12px */
height: 30px; /* 高度12px */
background-color: #409EFF; /* 半透明白色背景 */
/* border-radius: 6px; 圆形 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
font-size: 20px; /* 字体大小10px */
color: white; /* 白色文字 */
/* backdrop-filter: blur(2px); 背景模糊效果 */
/* box-shadow: 0 3px 5px rgba(0, 0, 0, 0.08); 轻微阴影 */
}
/* 应用标题样式 */
.app-title h1 {
font-size: 20px; /* 字体大小10px */
font-weight: 600; /* 中等加粗 */
letter-spacing: 0.4px; /* 字符间距0.4px */
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 主体内容区域 */
.syntax-body {
padding: 20px; /* 内边距10px */
}
/* 信息组容器 */
.info-group {
margin-bottom: 5px; /* 底部外边距20px */
background: #f9fafc; /* 浅灰色背景 */
border-radius: 8px; /* 8px圆角 */
padding: 5px; /* 内边距16px */
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.02); /* 轻微阴影 */
}
/* 信息组标题区域 */
.info-group-title {
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
margin-bottom: 8px; /* 底部外边距14px */
padding-bottom: 8px; /* 底部内边距10px */
border-bottom: 1px solid #e2e8f0; /* 底部1px浅灰色边框 */
}
/* 信息组标题文字样式 */
.info-group-title h2 {
font-size: 16px; /* 字体大小16px */
color: #000000; /* 蓝色文字 */
font-weight: 600; /* 中等加粗 */
padding-left: 10px; /* 左侧内边距10px */
}
/* 输入组样式 */
.input-group {
margin-bottom: 4px; /* 底部外边距16px */
}
/* 输入标签样式 */
.input-group label {
display: block; /* 块级元素 */
margin-bottom: 4px; /* 底部外边距8px */
color: #4a5568; /* 深灰色文字 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 输入字段通用样式 */
.input-field {
width: 100%; /* 宽度100% */
padding: 2px 2px; /* 内边距 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
border-radius: 7px; /* 7px圆角 */
font-size: 14px; /* 字体大小14px */
transition: all 0.3s; /* 所有属性0.3秒过渡 */
background: white; /* 白色背景 */
color: #2d3748; /* 深灰色文字 */
}
/* 输入字段聚焦状态 */
.input-field:focus {
border-color: #1e88e5; /* 边框变为蓝色 */
outline: none; /* 移除默认轮廓线 */
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.12); /* 添加蓝色发光效果 */
}
/* 文本域特殊样式 */
.input-field.textarea {
min-height: 30px; /* 最小高度85px */
resize: vertical; /* 允许垂直调整大小 */
font-family: 'Consolas', monospace; /* 等宽字体 */
padding: 6px; /* 内边距14px */
line-height: 1.5; /* 行高1.6倍 */
font-size: 13.5px; /* 字体大小13.5px */
}
/* 结果显示区域 */
.result-display {
background: linear-gradient(to right, #f7fafc, #edf2f7); /* 左右渐变背景 */
border: 1px solid #e2e8f0; /* 1px浅灰色边框 */
border-radius: 8px; /* 8px圆角 */
padding: 18px; /* 内边距18px */
margin: 9px 0; /* 上下外边距18px */
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.03); /* 内阴影 */
}
/* 结果项样式 */
.result-item {
margin-bottom: 14px; /* 底部外边距14px */
padding-bottom: 14px; /* 底部内边距14px */
border-bottom: 1px dashed #e2e8f0; /* 底部1px虚线边框 */
}
/* 最后一个结果项特殊处理 */
.result-item:last-child {
margin-bottom: 0; /* 无底部外边距 */
padding-bottom: 0; /* 无底部内边距 */
border-bottom: none; /* 无底部边框 */
}
/* 结果标签样式 */
.result-label {
color: #718096; /* 中灰色文字 */
font-size: 14px; /* 字体大小14px */
margin-bottom: 6px; /* 底部外边距6px */
font-weight: 500; /* 中等加粗 */
}
/* 结果值样式 */
.result-value {
font-size: 16px; /* 字体大小16px */
font-weight: 600; /* 中等加粗 */
color: #2d3748; /* 深灰色文字 */
}
/* 结果值中的高亮部分 */
.result-value .highlight {
color: #1e88e5; /* 蓝色文字 */
font-weight: 700; /* 加粗 */
font-size: 16px; /* 字体大小16px */
letter-spacing: 0.4px; /* 字符间距0.4px */
}
/* 操作按钮容器 */
.action-buttons {
display: flex; /* 启用Flex布局 */
justify-content: center; /* 水平居中 */
align-items: center; /*垂直居中*/
margin-top: 10px; /* 顶部外边距20px */
gap: 15px; /* 按钮间距15px */
height: auto; /* 自适应高度 */
padding: 10px 0; /* 添加垂直内边距 */
}
/* 操作按钮通用样式 */
.action-btn {
padding: 6px 15px; /* 内边距 */
border: none; /* 无边框 */
border-radius: 4px; /* 7px圆角 */
font-size: 12px; /* 字体大小15px */
font-weight: 600; /* 中等加粗 */
cursor: pointer; /* 鼠标指针为手型 */
/* transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); 自定义缓动过渡 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
min-width: 120px; /* 最小宽度120px */
letter-spacing: 4px; /* 字符间距4px */
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.06); /* 轻微阴影 */
}
/* 操作按钮图标 */
.action-btn i {
margin-right: 8px; /* 右侧外边距8px */
font-size: 16px; /* 字体大小16px */
}
/* 主要按钮样式 */
.btn-primary {
background: linear-gradient(to right,#409EFF , #409EFF);
color: white; /* 白色文字 */
position: relative; /* 相对定位 */
overflow: hidden; /* 隐藏溢出内容 */
}
/* 主要按钮悬停效果 */
.btn-primary:hover {
background: linear-gradient(to right, #2196f3, #1565c0); /* 更亮的蓝色渐变 */
box-shadow: 0 5px 10px rgba(33, 150, 243, 0.25); /* 增加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 主要按钮悬停时伪元素动画 */
.btn-primary:hover::after {
left: 140%; /* 移动到右侧140%位置 */
}
/* 默认按钮样式 */
.btn-default {
background: #f7fafc; /* 浅灰色背景 */
color: #4a5568; /* 深灰色文字 */
border: 1px solid #cbd5e0; /* 1px浅灰色边框 */
}
/* 默认按钮悬停效果 */
.btn-default:hover {
background: white; /* 白色背景 */
border-color: #a0aec0; /* 边框颜色加深 */
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.06); /* 添加阴影 */
/* transform: translateY(-2px); 向上移动2px */
}
/* 标记控制按钮容器 */
.mark-controls {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(4, minmax(140px, 1fr)); /* 自适应列 */
gap: 12px; /* 元素间距12px */
margin-top: 10px; /* 顶部外边距18px */
}
/* 标记按钮样式 */
.mark-btn {
display: inline-block;
padding: 4px 4px;
font-size: 13px;
border: 0.1px solid #dcdfe6;
border-radius: 4px;
cursor: pointer;
background: #ECF5FF;
border-color: #9ccaf7;
color: #409EFE;
letter-spacing: 3px; /* 添加微小间距 */
font-weight: 500; /* 加粗效果 */
text-align: center;
}
/* 标记按钮悬停效果 */
.mark-btn:hover {
background: #409EFE;
border-color: #409EFF;
color:#ffffff;
}
/* 标记按钮图标 */
.mark-btn i {
font-size: 13px; /* 字体大小16px */
}
/* 光标指示器样式 */
.cursor-indicator {
position: absolute; /* 绝对定位 */
width: 2px; /* 宽度2px */
height: 18px; /* 高度18px */
background-color: #e53935; /* 红色背景 */
pointer-events: none; /* 不响应鼠标事件 */
z-index: 100; /* 高z-index确保显示在最上层 */
border-radius: 1px; /* 轻微圆角 */
box-shadow: 0 0 2px rgba(229, 57, 53, 0.7); /* 红色发光效果 */
}
/* 标记对话框样式 */
.mark-dialog {
border-radius: 10px; /* 10px圆角 */
overflow: hidden; /* 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
.connector-dialog{
border-radius: 10px; /* 10px圆角 */
/* overflow: hidden; 隐藏溢出内容 */
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); /* 明显阴影 */
border: none; /* 无边框 */
}
/* 对话框头部样式 */
.mark-dialog-header, .connector-dialog-header {
background: linear-gradient(135deg, #1e88e5, #1565c0); /* 蓝色渐变背景 */
border:none !important;
color: white; /* 白色文字 */
padding: 5px 8px; /* 内边距 */
font-size: 18px; /* 字体大小18px */
font-weight: 600; /* 中等加粗 */
display: flex; /* 启用Flex布局 */
align-items: center; /* 垂直居中 */
gap: 10px; /* 元素间距10px */
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); /* 文字阴影 */
}
/* 对话框头部图标 */
.mark-dialog-header i, .connector-dialog-header i {
font-size: 24px; /* 字体大小24px */
}
/* 对话框主体区域 */
.mark-dialog-body, .connector-dialog-body {
border:none !important;
padding: 0px 0px; /* 内边距20px */
background: #f8fafc; /* 浅灰色背景 */
}
/* 标记选项容器 */
.mark-options {
display: grid; /* 启用Grid布局 */
grid-template-columns: repeat(auto-fit, minmax(18px, 1fr)); /* 自适应列 */
gap: 4px; /* 元素间距4px */
margin-top: 4px; /* 顶部外边距4px */
}
/* 标记选项按钮 */
.mark-option {
padding: 14px 8px; /* 内边距 */
background: #e3f2fd; /* 浅蓝色背景 */
border: 1px solid #bbdefb; /* 1px浅蓝色边框 */
border-radius: 7px; /* 7px圆角 */
color: #1976d2; /* 蓝色文字 */
cursor: pointer; /* 鼠标指针为手型 */
text-align: center; /* 文字居中 */
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); /* 自定义缓动过渡 */
font-size: 14px; /* 字体大小14px */
font-weight: 500; /* 中等加粗 */
}
/* 标记选项悬停效果 */
.mark-option:hover {
background: #bbdefb; /* 加深背景色 */
border-color: #90caf9; /* 加深边框色 */
transform: translateY(-3px) scale(1.02); /* 上移并轻微放大 */
box-shadow: 0 6px 12px rgba(25, 118, 210, 0.15); /* 添加蓝色阴影 */
}
/* 响应式设计:屏幕宽度小于768px时的调整 */
@media (max-width: 768px) { /* 媒体查询,针对小屏幕设备[6](@ref) */
.syntax-container {
margin: 8px auto; /* 减小外边距 */
}
.syntax-body {
padding: 16px; /* 调整内边距 */
}
.action-buttons {
flex-direction: column; /* 垂直排列按钮 */
gap: 10px; /* 按钮间距10px */
}
.action-btn {
width: 100%; /* 按钮宽度100% */
padding: 12px; /* 调整内边距 */
}
}
+671
View File
@@ -0,0 +1,671 @@
const { createApp, ref, onMounted, nextTick } = Vue;
const { ElMessage } = ElementPlus;
const app = createApp({
setup() {
// 从URL获取参数的函数
function getParameterByName(name, url = window.location.href) {
debugger;
name = name.replace(/[\[\]]/g, '\\$&');
const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
const results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
// 当用户完成操作时调用此函数
function returnSyntaxResult(result) {
// 将结果存储到localStorage
const resultKey = `syntaxResult_${windowId}`;
localStorage.setItem(resultKey, JSON.stringify(result));
// 关闭窗口
window.close();
}
// 过滤标记串(只保留型号码、前缀码、后缀码)
const filterMarkString = (str) => {
if (!str) return '';
// 匹配所有标记
const regex = /\[([^\]]+)=([^\]]+)\]/g;
const matches = str.matchAll(regex);
let validTags = [];
debugger;
switch(title.value) {
case '线缆型号语法':
validTags = ['型号码', '前缀码', '后缀码'];
break;
case '线缆规格语法':
validTags = ['截面', '芯数', '线组数', '线对数'];
break;
case '电压等级语法':
validTags = ['相电压', '线电压', '电压单位'];
break;
case '线缆标准语法':
validTags = ['标准名'];
break;
default:
// 默认为线缆型号语法
validTags = ['型号码', '前缀码', '后缀码'];
}
const filtered = [];
for (const match of matches) {
const tag = match[1];
if (validTags.includes(tag)) {
filtered.push(`[${tag}=${match[2]}]`);
}
}
return filtered.join('');
};
// 获取URL传递的参数
const urlParams = {
title: getParameterByName('title') || '',
ruleString: getParameterByName('ruleString1') || '',
syntaxString: getParameterByName('syntaxString') || '',
connectors: getParameterByName('connectors') || ''
};
// 页面数据
const originalMarkString = ref(urlParams.ruleString);
const syntaxString = ref(urlParams.syntaxString); // 使用传递的语法串
const orgsyntaxString = ref(urlParams.syntaxString);
const cursorPosition = ref(-1);
const syntaxEditor = ref(null);
const actualValue = ref('');
const title = ref(urlParams.title);
const filteredMarkString = ref(filterMarkString(urlParams.ruleString));
// 对话框相关
const showMarkDialog = ref(false);
const showConnectorDialog = ref(false);
const selectedConnector = ref('');
const availableMarks = ref([]);
const predefinedConnectors = ref(urlParams.connectors.split(','));
const loadingConnectors = ref(false);
const customConnector = ref('');
// 更新光标位置
const updateCursorPosition = () => {
if (syntaxEditor.value) {
cursorPosition.value = syntaxEditor.value.selectionStart;
}
};
const updateActualValue = () => {
// 解析标记串中的所有标记(按顺序)
const markArray = [];
const markRegex = /\[([^\]]+)=([^\]]+)\]/g;
let markMatch;
while ((markMatch = markRegex.exec(filteredMarkString.value)) !== null) {
markArray.push({
tag: markMatch[1],
value: markMatch[2]
});
}
// 解析语法串
let result = '';
const syntaxRegex = /(\[[^\]]+\])|([^[]+)/g;
let syntaxMatch;
while ((syntaxMatch = syntaxRegex.exec(syntaxString.value)) !== null) {
if (syntaxMatch[1]) {
// 处理标记字部分
const innerRegex = /\[([^\]]+)([a-z])\]/;
const innerMatch = syntaxMatch[1].match(innerRegex);
if (innerMatch) {
const tag = innerMatch[1];
const char = innerMatch[2];
const index = char.charCodeAt(0) - 97; // a->0, b->1, etc.
// 检查索引是否在标记数组范围内
if (index < markArray.length) {
// 获取对应位置的标记
const mark = markArray[index];
// 检查标记类型是否匹配
if (mark.tag === tag) {
result += mark.value;
}
}
}
} else if (syntaxMatch[2]) {
// 处理普通文本(链接符)
result += syntaxMatch[2];
}
}
actualValue.value = result;
};
// 打开插入标记字对话框
const openInsertMarkDialog = () => {
// 解析语法串中的所有标记字
availableMarks.value = [];
const regex = /\[[^\]]+\]/g;
const matches = orgsyntaxString.value.match(regex) || [];
// 去重
const uniqueMarks = [...new Set(matches)];
if (uniqueMarks.length > 0) {
availableMarks.value = uniqueMarks;
// showMarkDialog.value = true;
} else {
ElMessage.warning('语法串中没有可用的标记字');
}
};
// 插入选中的标记字
const insertSelectedMark = (mark) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showMarkDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入标记字
syntaxString.value = before + mark + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + mark.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showMarkDialog.value = false;
ElMessage.success(`已插入标记字: ${mark}`);
};
// 打开插入链接符对话框
const openInsertConnectorDialog = () => {
showConnectorDialog.value = true;
selectedConnector.value = ''; // 清空前一次选择
customConnector.value = ''; // 清空前一次自定义输入
};
// 处理选择变化
const handleConnectorChange = (value) => {
// 如果是自定义输入且不在预定义列表中
if (value && !predefinedConnectors.value.includes(value)) {
customConnector.value = value;
}
};
// 插入选中的链接符
const insertSelectedConnector = (connector) => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 检查光标位置是否在标记字内
let i = cursorPos;
let insideBracket = false;
if (i > 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
break;
}
if (char === '[') {
insideBracket = true;
break;
}
i--;
}
}
if (insideBracket) {
ElMessage.warning('请将光标置于标记字[]之外');
showConnectorDialog.value = false;
return;
}
// 分割字符串
const before = text.substring(0, cursorPos);
const after = text.substring(cursorPos);
// 插入链接符
syntaxString.value = before + connector + after;
// 更新实际值
updateActualValue();
// 设置光标位置到插入内容之后
nextTick(() => {
const newCursorPos = cursorPos + connector.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
showConnectorDialog.value = false;
ElMessage.success(`已插入链接符: ${connector}`);
};
// 删除链接符
const deleteConnector = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
if (text.trim() === '') {
return;
}
// 初始化起始和结束位置
let iStart = cursorPos;
let iEnd = cursorPos;
// 向左查找
let i = cursorPos;
if (i >= 0) {
while (i > 0) {
const char = text.charAt(i - 1);
if (char === ']') {
iStart = i;
break;
}
if (char === '[') {
ElMessage.warning('请将光标置于语法串中的连接符位置');
return;
}
i--;
}
if (i === 0) {
iStart = 0;
}
}
// 向右查找
i = cursorPos;
if (i >= 0) {
while (i < text.length) {
const char = text.charAt(i);
if (char === '[') {
iEnd = i;
break;
}
i++;
}
if (i === text.length) {
iEnd = text.length;
}
}
// 构建新字符串
let newText = '';
if (iStart === 0) {
newText = text.substring(iEnd);
} else {
newText = text.substring(0, iStart) + text.substring(iEnd);
}
syntaxString.value = newText;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(iStart, iStart);
cursorPosition.value = iStart;
});
ElMessage.info('已删除链接符');
};
// 获取当前标记字内容
const getCurrentBracketContent = (text, cursorPos) => {
let startIndex = -1;
let endIndex = -1;
// 查找当前标记字的起始位置
let i = 1;
while (i <= cursorPos) {
if (text.charAt(i - 1) === '[') {
startIndex = i - 1;
}
i++;
}
// 查找当前标记字的结束位置
i = cursorPos;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取下一个标记字内容
const getNextBracketContent = (text, afterIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找下一个标记字的起始位置
let i = afterIndex + 1;
while (i < text.length) {
if (text.charAt(i) === '[') {
startIndex = i;
break;
}
i++;
}
// 查找下一个标记字的结束位置
if (startIndex !== -1) {
i = startIndex;
while (i < text.length) {
if (text.charAt(i) === ']') {
endIndex = i;
break;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 获取前一个标记字内容
const getPreviousBracketContent = (text, beforeIndex) => {
let startIndex = -1;
let endIndex = -1;
// 查找前一个标记字的起始位置
let i = 1;
let lastStart = -1;
while (i < beforeIndex) {
if (text.charAt(i - 1) === '[') {
lastStart = i - 1;
}
i++;
}
if (lastStart !== -1) {
startIndex = lastStart;
// 查找前一个标记字的结束位置
i = lastStart;
while (i < beforeIndex) {
if (text.charAt(i) === ']') {
endIndex = i;
}
i++;
}
}
if (startIndex !== -1 && endIndex !== -1) {
return {
content: text.substring(startIndex, endIndex + 1),
start: startIndex,
end: endIndex
};
}
return null;
};
// 后移标记字
const moveMarkBackward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取下一个标记字
const nextMark = getNextBracketContent(text, currentMark.end);
if (!nextMark) {
ElMessage.warning('后面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, currentMark.start);
const between = text.substring(currentMark.end + 1, nextMark.start);
const after = text.substring(nextMark.end + 1);
syntaxString.value = before + nextMark.content + between + currentMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length + nextMark.content.length + between.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 前移标记字
const moveMarkForward = () => {
if (!syntaxEditor.value || !syntaxString.value) {
ElMessage.warning('语法串为空');
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要移动的标记字内');
return;
}
// 获取前一个标记字
const previousMark = getPreviousBracketContent(text, currentMark.start);
if (!previousMark) {
ElMessage.warning('前面没有可交换的标记字');
return;
}
// 交换两个标记字
const before = text.substring(0, previousMark.start);
const between = text.substring(previousMark.end + 1, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + currentMark.content + between + previousMark.content + after;
// 更新实际值
updateActualValue();
// 设置光标位置到移动后的标记字起始位置
nextTick(() => {
const newCursorPos = before.length;
syntaxEditor.value.setSelectionRange(newCursorPos, newCursorPos);
cursorPosition.value = newCursorPos;
});
};
// 删除标记字
const deleteMark = () => {
if (!syntaxEditor.value || !syntaxString.value) {
return;
}
const text = syntaxString.value;
const cursorPos = cursorPosition.value;
// 获取当前标记字
const currentMark = getCurrentBracketContent(text, cursorPos);
if (!currentMark) {
ElMessage.warning('请将光标置于需要删除的标记字内');
return;
}
// 删除标记字
const before = text.substring(0, currentMark.start);
const after = text.substring(currentMark.end + 1);
syntaxString.value = before + after;
// 更新实际值
updateActualValue();
// 设置光标位置
nextTick(() => {
syntaxEditor.value.setSelectionRange(currentMark.start, currentMark.start);
cursorPosition.value = currentMark.start;
});
ElMessage.info('已删除标记字');
};
// 保存语法设置
const saveSyntax = () => {
const result = {
type: title.value,
Value: syntaxString.value,
ActualValue: actualValue.value
};
window.parent.postMessage({
type: 'SAVE_SYNTAX_RESULT',
payload: result
}, '*');
ElMessage.success('语法规则已保存');
};
// 应用语法设置
const applySyntax = () => {
ElMessage.success('语法规则已成功应用');
setTimeout(() => {
window.close();
}, 1000);
};
// 重置表单
const resetForm = () => {
syntaxString.value = urlParams.syntaxString; // 重置为初始传递的值
actualValue.value = '';
cursorPosition.value = -1;
updateActualValue(); // 重新计算实际值
};
// 关闭窗口
const closeWindow = () => {
window.close();
};
// 初始化
onMounted(() => {
updateActualValue();
});
return {
filteredMarkString,
syntaxString,
cursorPosition,
syntaxEditor,
actualValue,
showMarkDialog,
showConnectorDialog,
availableMarks,
predefinedConnectors,
updateCursorPosition,
openInsertMarkDialog,
insertSelectedMark,
openInsertConnectorDialog,
insertSelectedConnector,
selectedConnector,
deleteConnector,
moveMarkForward,
moveMarkBackward,
deleteMark,
saveSyntax,
applySyntax,
resetForm,
closeWindow,
handleConnectorChange,
title,
updateActualValue
};
}
});
app.use(ElementPlus);
app.mount('#app');
+526
View File
@@ -0,0 +1,526 @@
/* 批量调价页面样式 */
#app {
padding: 20px;
font-family: 'Helvetica Neue', Arial, sans-serif;
height: 100vh;
display: flex;
flex-direction: column;
}
.page-container {
display: flex;
flex-direction: column;
height: 100%;
}
/* 工具栏样式 */
.toolbar {
margin-bottom: 15px;
padding: 15px;
background: #f5f7fa;
border-radius: 4px;
border: 1px solid #ebeef5;
display: flex;
align-items: center;
gap: 10px;
}
.toolbar .el-button {
margin-right: 10px;
}
.close-btn {
margin-left: auto !important;
font-weight: bold !important;
}
.close-btn:hover {
background-color: #f56c6c !important;
border-color: #f56c6c !important;
color: #fff !important;
}
/* 表格容器 */
.table-container {
flex: 1;
overflow: auto;
border: 1px solid #ebeef5;
border-radius: 4px;
background: #fff;
min-height: 0;
position: relative;
width: 100%;
min-width: 0;
}
/* 确保表格不会被压缩 */
.table-container .el-table {
flex-shrink: 0 !important;
min-width: max-content !important;
}
/* Element Plus 表格样式 */
.table-container .el-table {
font-size: 14px;
}
/* 禁用表格内部的滚动,让容器控制滚动 */
.table-container .el-table__body-wrapper {
overflow: visible !important;
max-height: none !important;
}
.table-container .el-table__header-wrapper {
overflow: visible !important;
}
/* 禁用Element Plus内部的滚动条组件,但确保内容可见 */
/* 不隐藏el-scrollbar,而是让它显示内容但禁用滚动 */
.table-container .el-table__body-wrapper .el-scrollbar {
display: block !important;
height: auto !important;
}
.table-container .el-table__body-wrapper .el-scrollbar__wrap {
overflow: visible !important;
display: block !important;
height: auto !important;
max-height: none !important;
}
.table-container .el-table__body-wrapper .el-scrollbar__view {
display: block !important;
overflow: visible !important;
width: 100% !important;
height: auto !important;
}
/* 隐藏滚动条,但保留内容显示 */
.table-container .el-table__body-wrapper .el-scrollbar__bar {
display: none !important;
}
/* 确保表格body直接显示,不通过scrollbar包装 */
.table-container .el-table__body-wrapper > .el-scrollbar {
display: block !important;
height: auto !important;
}
.table-container .el-table__body-wrapper > .el-scrollbar__wrap {
overflow: visible !important;
height: auto !important;
max-height: none !important;
}
/* 确保表格body table直接可见 */
.table-container .el-table__body-wrapper table {
display: table !important;
visibility: visible !important;
width: 100% !important;
}
/* 确保表格行可见 */
.table-container .el-table__body-wrapper tbody {
display: table-row-group !important;
visibility: visible !important;
}
.table-container .el-table__body-wrapper tr {
display: table-row !important;
visibility: visible !important;
}
.table-container .el-table__body-wrapper td {
display: table-cell !important;
visibility: visible !important;
}
/* 确保表格body区域可见 */
.table-container .el-table__body {
display: block !important;
height: auto !important;
}
.table-container .el-table__body table {
display: table !important;
width: 100% !important;
}
/* 确保表格body-wrapper有高度和可见性,但不设置最小高度,让行高自适应 */
.table-container .el-table__body-wrapper {
height: auto !important;
overflow: visible !important;
}
/* 确保表格行完全可见,行高自适应内容 */
.table-container .el-table__row {
display: table-row !important;
visibility: visible !important;
height: auto !important;
}
/* 确保表格单元格行高正常 */
.table-container .el-table__cell {
height: auto !important;
line-height: normal !important;
}
/* 确保表头和表体宽度一致,一起滚动 */
.table-container .el-table__body {
width: max-content !important;
min-width: 100%;
}
.table-container .el-table__header {
width: max-content !important;
min-width: 100%;
}
/* 确保表格内容区域不限制高度和宽度 */
.table-container .el-table__inner-wrapper {
overflow: visible !important;
}
/* 确保表格列能够正确计算宽度 */
.table-container .el-table__header-wrapper .el-table__header,
.table-container .el-table__body-wrapper .el-table__body {
table-layout: auto !important;
}
/* 确保表格单元格宽度正确 */
.table-container .el-table th,
.table-container .el-table td {
white-space: nowrap;
}
/* 确保每列之间有边框 */
.table-container .el-table th,
.table-container .el-table td {
border-right: 1px solid #ebeef5 !important;
}
.table-container .el-table th:last-child,
.table-container .el-table td:last-child {
border-right: none !important;
}
/* 确保表头文字居中 */
.table-container .el-table th {
text-align: center !important;
}
.table-container .el-table th .cell {
text-align: center !important;
justify-content: center !important;
}
/* 确保表头和表体都有边框 */
.table-container .el-table--border th,
.table-container .el-table--border td {
border-right: 1px solid #ebeef5 !important;
}
.table-container .el-table--border th:last-child,
.table-container .el-table--border td:last-child {
border-right: none !important;
}
/* 确保带边框的表头文字居中 */
.table-container .el-table--border th {
text-align: center !important;
}
.table-container .el-table--border th .cell {
text-align: center !important;
justify-content: center !important;
}
/* 确保表格能够根据内容自动扩展 */
.table-container .el-table {
width: max-content !important;
min-width: max-content !important;
flex-shrink: 0 !important;
}
/* 滚动条样式 */
.table-container::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.table-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.table-container::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
}
.table-container::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* 确保表头文字居中,参考TBBJKSLR样式 */
.el-table th {
background-color: #f8f9fa !important;
font-weight: 600 !important;
color: #303133 !important;
text-align: center !important;
height: 40px !important; /* 表头高度 */
line-height: 40px !important; /* 垂直居中 */
}
.el-table th .cell {
text-align: center !important;
justify-content: center !important;
line-height: 40px !important; /* 垂直居中 */
}
/* 表头底部边框,参考TBBJKSLR */
.el-table__header-wrapper {
border-bottom: 2px solid #409eff !important;
}
/* 序号列表头特殊样式,参考TBBJKSLR */
.table-container .el-table th.serial-column,
.el-table th.serial-column {
background-color: #f0f2f5 !important;
font-weight: 600 !important;
text-align: center !important;
border-right: 2px solid #d0d0d0 !important;
}
/* 序号列数据单元格样式 */
.table-container .el-table td.serial-column,
.el-table td.serial-column {
background-color: #f8f9fa !important;
font-weight: bold !important;
text-align: center !important;
border-right: 2px solid #d0d0d0 !important;
color: #303133 !important;
user-select: none !important;
}
.el-table td,
.el-table th {
padding: 8px 0;
}
.el-table--border {
border: 1px solid #ebeef5;
}
.el-table--border::after,
.el-table--border::before {
background-color: #ebeef5;
}
/* 确保每列之间有清晰的边框 */
.el-table--border th,
.el-table--border td {
border-right: 1px solid #ebeef5 !important;
}
.el-table--border th:last-child,
.el-table--border td:last-child {
border-right: none !important;
}
/* 确保表头单元格有边框 */
.el-table__header th {
border-right: 1px solid #ebeef5 !important;
text-align: center !important;
}
.el-table__header th:last-child {
border-right: none !important;
}
/* 启用列宽调整功能,参考TBBJKSLR */
.el-table__column-resize-proxy {
display: block !important;
background-color: #409eff;
width: 2px;
z-index: 10;
}
/* 启用列分隔线的拖拽功能 */
.el-table th.is-resizing {
cursor: ew-resize !important;
}
/* 列边框可拖拽调整,参考TBBJKSLR */
.table-container .el-table th,
.el-table th {
position: relative;
}
/* 序号列不可调整列宽,参考TBBJKSLR */
.table-container .el-table th.serial-column,
.table-container .el-table th.el-table-column--selection,
.el-table th.serial-column,
.el-table th.el-table-column--selection { /* 选择列也禁用调整 */
position: relative;
}
.table-container .el-table th.serial-column .column-resize-handle,
.table-container .el-table th.el-table-column--selection .column-resize-handle,
.el-table th.serial-column .column-resize-handle,
.el-table th.el-table-column--selection .column-resize-handle {
display: none !important;
}
/* 可调整列宽的列,鼠标悬停在边框时显示调整光标 */
.table-container .el-table th:not(.serial-column):not(.el-table-column--selection) .column-resize-handle,
.el-table th:not(.serial-column):not(.el-table-column--selection) .column-resize-handle {
position: absolute;
right: -2px; /* 调整到列边框上 */
top: 0;
bottom: 0;
width: 4px;
cursor: ew-resize;
z-index: 5;
background: transparent;
}
.table-container .el-table th:not(.serial-column):not(.el-table-column--selection) .column-resize-handle:hover,
.el-table th:not(.serial-column):not(.el-table-column--selection) .column-resize-handle:hover {
background-color: #409eff;
opacity: 0.3;
}
/* 列标题内容区域不显示调整光标,禁用点击效果 */
.table-container .el-table th,
.el-table th {
cursor: default !important;
}
.table-container .el-table th .cell,
.el-table th .cell {
cursor: default !important;
user-select: none; /* 禁止文本选择 */
}
/* 隐藏排序图标,因为不允许排序 */
.table-container .el-table th .caret-wrapper,
.el-table th .caret-wrapper {
display: none !important;
}
/* 确保列宽调整手柄可以正常工作 */
.table-container .el-table th .column-resize-handle,
.el-table th .column-resize-handle {
pointer-events: auto !important;
cursor: ew-resize !important;
}
/* 确保表头单元格内容居中 */
.el-table__header th .cell {
text-align: center !important;
justify-content: center !important;
}
/* 确保表体单元格有边框 */
.el-table__body td {
border-right: 1px solid #ebeef5 !important;
}
.el-table__body td:last-child {
border-right: none !important;
}
.el-table--striped .el-table__body tr.el-table__row--striped td {
background-color: #fafafa;
}
.el-table__row:hover > td {
background-color: #f5f7fa !important;
}
/* 数据统计样式 */
.data-count-footer {
margin-top: 15px;
text-align: center;
font-size: 14px;
color: #606266;
font-weight: bold;
padding: 10px;
background: #f5f7fa;
border-radius: 4px;
border: 1px solid #ebeef5;
}
/* 对话框样式 */
.el-dialog {
border-radius: 4px;
}
.el-dialog__header {
padding: 20px 20px 10px;
border-bottom: 1px solid #ebeef5;
background: #f5f7fa;
}
.el-dialog__title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.el-dialog__body {
padding: 20px;
}
.el-form-item {
margin-bottom: 20px;
}
.el-form-item__label {
font-weight: 500;
color: #606266;
}
/* 加载状态 */
.el-loading-mask {
background-color: rgba(255, 255, 255, 0.9);
}
/* 响应式设计 */
@media (max-width: 768px) {
.toolbar {
flex-direction: column;
align-items: flex-start;
}
.toolbar .el-button {
margin-bottom: 10px;
margin-right: 0;
width: 100%;
}
.close-btn {
margin-left: 0 !important;
}
.table-container {
height: 400px !important;
}
}
/* 序号列样式 */
.el-table .el-table__cell:first-child {
background-color: #f8f9fa !important;
font-weight: bold;
}
/* 数字列右对齐 */
.el-table .el-table__cell[class*="is-right"] {
text-align: right;
}
/* 选择列样式 */
.el-table .el-table__cell[class*="selection"] {
text-align: center;
}
+4104
View File
File diff suppressed because it is too large Load Diff
View File
+925
View File
@@ -0,0 +1,925 @@
const { createApp, ref, reactive, computed, onMounted, onBeforeUnmount } = Vue;
function getControlValue(controlId) {
const exact = document.getElementById(controlId);
if (exact && typeof exact.value !== 'undefined') {
return exact.value || '';
}
const bySuffix = document.querySelector(`[id$="${controlId}"]`);
if (bySuffix && typeof bySuffix.value !== 'undefined') {
return bySuffix.value || '';
}
return '';
}
const BJU061 = getControlValue('txtBJU061');
const app = createApp({
setup() {
/* ===== 基础状态 ===== */
const loading = ref(false);
const enableSJDC = ref(false);
const queryDrawerVisible = ref(false);
const tableContainer = ref(null);
const detailDialogVisible = ref(false);
const detailBasicInfo = ref({});
const detailMaterialList = ref([]);
/* ===== 表格 ===== */
const tableWidth = ref(1600);
const tableHeight = ref(800);
const tableVersion = ref(0);
const dicCLMC = ref({});
const dicCLJG = ref({});
const dicCLWL = ref({});
const items = ref([]);
const filteredItems = ref([]);
/* ===== 分页 ===== */
const currentPage = ref(1);
const pageSize = ref(5000);
const total = computed(() => filteredItems.value.length);
const pagedData = computed(() => {
const start = (currentPage.value - 1) * pageSize.value;
const end = start + pageSize.value;
return filteredItems.value.slice(start, end);
});
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1;
};
const calcTableSize = () => {
const container = tableContainer.value;
if (!container) return;
tableWidth.value = container.clientWidth;
tableHeight.value = container.clientHeight;
console.log('calcTableSize', tableWidth.value, tableHeight.value);
};
const handleCurrentChange = (val) => {
currentPage.value = val;
};
/* ===== 动态列 ===== */
const COLUMN_MIN_WIDTH_MAP = {
};
const dynamicWidths = reactive({});
const dynamicColumns = ref([]);
const columns = computed(() => {
return dynamicColumns.value.map(col => ({
key: col.prop,
dataKey: col.prop,
title: col.label,
width:
dynamicWidths[col.prop] ||
COLUMN_MIN_WIDTH_MAP[col.prop] ||
120
}));
});
const generateColumns = () => {
const cols = [];
// ===== 固定基础列 =====
cols.push(
{ label: '型号', prop: 'XLXSCLQD_XLXHID', width: 120 },
{ label: '规格', prop: 'XLXSCLQD_XLGGID', width: 120 },
{ label: '标准', prop: 'XLBZ', width: 60 },
{ label: '电压等级', prop: 'XLXSCLQD_DYDJID', width: 80 },
{ label: '物料编码', prop: 'WLID', width: 80 },
{ label: '物料信息', prop: 'WLXX', width: 180 },
{ label: '计量单位', prop: 'JLDW', width: 60 },
{ label: '材料重量', prop: 'XLXSCLQD_CLZL', width: 80 },
{ label: '材料成本', prop: 'CLCB', width: 80 }
);
// ===== 动态 01~10 列 =====
for (let i = 1; i <= 80; i++) {
const index = i.toString().padStart(2, '0');
cols.push(
{ label: `第${index}列`, prop: `XLXSCLQD_SL${index}`, width: 80 },
{ label: `第${index}列价格`, prop: `CLJG${index}`, width: 100 },
{ label: '材料物料', prop: `XLXSCLWL${index}`, width: 100 },
{ label: '物料价格(元/Kg)', prop: `XLXSCLWLJG${index}`, width: 120 },
{ label: '物料成本', prop: `XLXSCLWLCB${index}`, width: 100 }
);
}
// ===== 尾部列 =====
cols.push(
{ label: '备注', prop: 'XLXSCLQD_BZ', width: 150 },
{ label: '维护人', prop: 'XLXSCLQD_WHR', width: 80 },
{ label: '维护时间', prop: 'XLXSCLQD_WHSJ', width: 150 }
);
dynamicColumns.value = cols;
tableVersion.value++;
};
const buildDynamicMaterialColumns = () => {
const cols = [];
// ===== 固定基础列 =====
cols.push(
{ label: '型号', prop: 'XLXSCLQD_XLXHID', width: 120 },
{ label: '规格', prop: 'XLXSCLQD_XLGGID', width: 120 },
{ label: '标准', prop: 'XLBZ', width: 60 },
{ label: '电压等级', prop: 'XLXSCLQD_DYDJID', width: 80 },
{ label: '物料编码', prop: 'WLID', width: 80 },
{ label: '物料信息', prop: 'WLXX', width: 180 },
{ label: '计量单位', prop: 'JLDW', width: 60 },
{ label: '材料重量', prop: 'XLXSCLQD_CLZL', width: 80 },
{ label: '材料成本', prop: 'CLCB', width: 80 }
);
// ===== 动态 01~10 列 =====
for (let i = 1; i <= 80; i++) {
const index = i.toString().padStart(2, '0');
const key = `第${index}列`;
const hasCLMC = dicCLMC.value[key] && dicCLMC.value[key].trim() !== '';
const hasCLWL = dicCLWL.value[key];
// ===== 如果 CLMC 不存在 → 整组隐藏 =====
if (!hasCLMC) continue;
// ===== 1️⃣ 材料数量列 =====
cols.push({
label: dicCLMC.value[key] || `第${index}列`,
prop: `XLXSCLQD_SL${index}`,
width: 80
});
// ===== 2️⃣ 材料价格列 =====
if (!hasCLWL) {
cols.push({
label: dicCLJG.value[key] || `价格`,
prop: `CLJG${index}`,
width: 100
});
}
// ===== 3️⃣ 物料列 =====
if (hasCLWL) {
cols.push(
{
label: dicCLWL.value[key] || '材料物料',
prop: `XLXSCLWL${index}`,
width: 100
},
{
label: '物料价格(元/Kg)',
prop: `XLXSCLWLJG${index}`,
width: 120
},
{
label: '物料成本',
prop: `XLXSCLWLCB${index}`,
width: 100
}
);
}
}
// ===== 尾部列 =====
cols.push(
{ label: '备注', prop: 'XLXSCLQD_BZ', width: 150 },
{ label: '维护人', prop: 'XLXSCLQD_WHR', width: 80 },
{ label: '维护时间', prop: 'XLXSCLQD_WHSJ', width: 150 }
);
dynamicColumns.value = cols;
tableVersion.value++;
};
const handleRowDblClick = (row) => {
//查询条件尺重表号为空
if (!queryConditions.structureWeightTableCode) return;
GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'GetCLCBMX',
false,
{
sXLXHID: row.XLXSCLQD_XLXHID,
sXLGGID: row.XLXSCLQD_XLGGID,
sXLBZID: row.XLBZ ? row.XLBZ.split('|')[0] : '',
sDYDJID: row.XLXSCLQD_DYDJID,
sHSJGBZ: queryConditions.iSHSJGCheck ? 'Y' : 'N',
sJGBID:queryConditions.jgbid
},
(result) => {
if (!result) return;
/* ========= 基本信息 ========= */
detailBasicInfo.value = {
型号: result.Model,
规格: result.Specification,
标准: row.XLBZ,
电压等级: result.VoltageLevel,
计量单位: result.Unit,
材料重量: result.MaterialWeight,
材料成本: result.MaterialCost,
结构尺重表: jgczbOptions.value.find(
                                                    item => item.value === queryConditions.structureWeightTableValue
                                                )?.label || '',
备注: result.Remark,
维护人: result.Maintainer,
维护时间: result.MaintainTime
};
/* ========= 明细表 ========= */
detailMaterialList.value = result.Materials.map(item => ({
材料编码: item.MaterialCode,
材料名称: item.MaterialName,
物料信息: item.MaterialInfo,
材料用量: item.MaterialUsage,
材料比例: item.MaterialUsageRatio,
材料损耗率: item.MaterialLossRate,
材料价格: item.MaterialPrice,
材料成本: item.MaterialCost
}));
detailDialogVisible.value = true;
}
);
};
const rowEventHandlers = {
onDblclick: ({ rowData }) => {
handleRowDblClick(rowData);
}
};
const getDic = () => {
const condition = {
StructureWeightTableCode: queryConditions.structureWeightTableCode || '',
StructureWeightTableVersion: queryConditions.structureWeightTableVersion || '',
Models: Array.isArray(queryConditions.models)
? queryConditions.models.join(',')
: (queryConditions.models || ''),
VoltageLevel: queryConditions.voltageLevel || '',
Standard: queryConditions.standard || '',
Specification: queryConditions.specification || '',
ISHSJGCheck: queryConditions.iSHSJGCheck ? 'Y' : 'N',
ISWLCBCheck: queryConditions.iSWLCBCheck ? 'Y' : 'N',
OrderOption: queryConditions.orderOption || '',
PageSize: queryConditions.pageSize || 5000,
PageNum: queryConditions.pageNum || 0,
JGBID: queryConditions.jgbid || '',
ISDRCX:queryConditions.iSDRCX,
FileContent:queryConditions.fileContent,
FileName:queryConditions.fileName
};
GThinking.Web.AjaxServiceProxy.servicePath =
'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'GetDic',
false,
{ condition: condition },
(result) => {
dicCLMC.value = result.CLMC || {};
dicCLJG.value = result.CLJG || {};
dicCLWL.value = result.CLWL || {};
console.log(dicCLMC);
console.log(dicCLJG);
console.log(dicCLWL);
buildDynamicMaterialColumns(); // 字典拿到后重新生成列
}
);
};
const getCLCBResults = () => {
const condition = {
StructureWeightTableCode: queryConditions.structureWeightTableCode || '',
StructureWeightTableVersion: queryConditions.structureWeightTableVersion || '',
Models: Array.isArray(queryConditions.models)
? queryConditions.models.join(',')
: (queryConditions.models || ''),
VoltageLevel: queryConditions.voltageLevel || '',
Standard: queryConditions.standard || '',
Specification: queryConditions.specification || '',
ISHSJGCheck: queryConditions.iSHSJGCheck ? 'Y' : 'N',
ISWLCBCheck: queryConditions.iSWLCBCheck ? 'Y' : 'N',
OrderOption: queryConditions.orderOption || '',
PageSize: queryConditions.pageSize || 5000,
PageNum: queryConditions.pageNum || 0,
JGBID: queryConditions.jgbid || '',
ISDRCX:queryConditions.iSDRCX,
FileContent:queryConditions.fileContent,
FileName:queryConditions.fileName
};
loading.value = true;
console.log('helloworld');
GThinking.Web.AjaxServiceProxy.servicePath =
'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'GetCLCBResults',
false,
{ condition: condition },
(result) => {
console.log(result);
loading.value = false;
if (!result || result.length === 0) {
items.value = [];
filteredItems.value = [];
return;
}
// 现在 result 本身就是数组
items.value = result;
filteredItems.value = result;
currentPage.value = 1;
}
);
};
/* ===== 查询条件 ===== */
const queryConditions = reactive({
structureWeightTableValue: '',
structureWeightTableCode: '',
structureWeightTableVersion: '',
models: [],
specification: '',
standard: '',
voltageLevel: '',
iSHSJGCheck: true,
iSWLCBCheck: false,
orderOption: '型号+序号',
pageSize: 5000,
pageNum: 0,
jgbid:'',
fileContent: '',
fileName: '',
iSDRCX: 'N',
iSDRCXChecked: false
});
const handleResetFilter = () => {
Object.keys(queryConditions).forEach(k => {
if (Array.isArray(queryConditions[k])) {
queryConditions[k] = [];
} else if (typeof queryConditions[k] === 'boolean') {
queryConditions[k] = false;
} else {
queryConditions[k] = '';
}
});
queryConditions.iSDRCX = 'N';
queryConditions.iSDRCXChecked = false;
uploadRef.value?.clearFiles();
};
const confirmQueryDrawer = () => {
queryConditions.iSDRCX = queryConditions.iSDRCXChecked ? 'Y' : 'N';
queryDrawerVisible.value = false;
getDic();
buildDynamicMaterialColumns();
getCLCBResults();
};
const openQueryDrawer = () => {
queryDrawerVisible.value = true;
};
const sjdc = () => {
const condition = {
StructureWeightTableCode: queryConditions.structureWeightTableCode || '',
StructureWeightTableVersion: queryConditions.structureWeightTableVersion || '',
Models: Array.isArray(queryConditions.models)
? queryConditions.models.join(',')
: (queryConditions.models || ''),
VoltageLevel: queryConditions.voltageLevel || '',
Standard: queryConditions.standard || '',
Specification: queryConditions.specification || '',
ISHSJGCheck: queryConditions.iSHSJGCheck ? 'Y' : 'N',
ISWLCBCheck: queryConditions.iSWLCBCheck ? 'Y' : 'N',
OrderOption: queryConditions.orderOption || '',
PageSize: queryConditions.pageSize || 5000,
PageNum: queryConditions.pageNum || 0,
JGBID: queryConditions.jgbid || '',
ISDRCX:queryConditions.iSDRCX,
FileContent:queryConditions.fileContent,
FileName:queryConditions.fileName
};
GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'SJDC',
false,
{ condition: condition },
(result) => {
if (!result) {
alert("导出失败或没有数据");
return;
}
// 🔥 直接下载
const a = document.createElement("a");
a.href = result;
a.download = ""; // 让浏览器自动用服务器文件名
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
);
};
/* ===== 下拉 ===== */
const jgbOptions = ref([]);
const jgczbOptions = ref([]);
const xhOptions = ref([]);
const filteredXhOptions = ref([]);
const modelLoading = ref(false);
const standardOptions = ref([]);
const dydjOptions = ref([]);
const pxfsOptions = ref([
{ label: '型号+序号', value: '型号+序号' },
{ label: '尺重表内容导入行号', value: '尺重表内容导入行号' }
]);
const uploadRef = ref(null);
const readExcelAsBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
const base64 = e.target.result.split(',')[1];
resolve(base64);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
};
const validateExcelHeaders = async (file) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
if (jsonData.length === 0) {
resolve({ valid: false, message: 'Excel文件为空' });
return;
}
const headers = jsonData[0].map(h => String(h).trim());
const requiredHeaders = ['型号', '规格', '标准', '电压等级'];
const missingHeaders = requiredHeaders.filter(h => !headers.includes(h));
if (missingHeaders.length > 0) {
resolve({ valid: false, message: `缺少必要栏目:${missingHeaders.join(', ')}` });
return;
}
resolve({ valid: true });
} catch (err) {
resolve({ valid: false, message: '读取Excel文件失败' });
}
};
reader.onerror = () => resolve({ valid: false, message: '读取文件失败' });
reader.readAsArrayBuffer(file);
});
};
const handleFileChange = async (file, fileList) => {
if (!file || !file.raw) return;
const fileName = file.raw.name;
const extension = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
if (extension !== '.xlsx' && extension !== '.xls') {
ElMessage.error('只能上传Excel文件(.xlsx, .xls)');
uploadRef.value?.clearFiles();
return;
}
const validation = await validateExcelHeaders(file.raw);
if (!validation.valid) {
ElMessage.error(validation.message);
uploadRef.value?.clearFiles();
return;
}
queryConditions.fileName = fileName;
const base64 = await readExcelAsBase64(file.raw);
queryConditions.fileContent = base64;
ElMessage.success('文件上传成功');
};
const handleFileRemove = () => {
queryConditions.fileName = '';
queryConditions.fileContent = '';
};
const initOptionsData = () => {
GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'GetJGBOptions',
false,
'',
(result) => {
if (!result || result.length === 0) {
jgbOptions.value = [];
queryConditions.jgbid = '';
const condition = {
StructureWeightTableCode: queryConditions.structureWeightTableCode || '',
StructureWeightTableVersion: queryConditions.structureWeightTableVersion || '',
Models: Array.isArray(queryConditions.models)
? queryConditions.models.join(',')
: (queryConditions.models || ''),
VoltageLevel: queryConditions.voltageLevel || '',
Standard: queryConditions.standard || '',
Specification: queryConditions.specification || '',
ISHSJGCheck: queryConditions.iSHSJGCheck ? 'Y' : 'N',
ISWLCBCheck: queryConditions.iSWLCBCheck ? 'Y' : 'N',
OrderOption: queryConditions.orderOption || '',
PageSize: queryConditions.pageSize || 5000,
PageNum: queryConditions.pageNum || 0,
JGBID: queryConditions.jgbid || '',
ISDRCX:queryConditions.iSDRCX,
FileContent:queryConditions.fileContent,
FileName:queryConditions.fileName
};
loadOtherOptions(condition);
return;
}
jgbOptions.value = result.map(item => ({
value: item.Code, // 注意大小写
label: item.Name
}));
queryConditions.jgbid = result[0].Code;
console.log(result[0].Code)
const condition = {
StructureWeightTableCode: queryConditions.structureWeightTableCode || '',
StructureWeightTableVersion: queryConditions.structureWeightTableVersion || '',
Models: Array.isArray(queryConditions.models)
? queryConditions.models.join(',')
: (queryConditions.models || ''),
VoltageLevel: queryConditions.voltageLevel || '',
Standard: queryConditions.standard || '',
Specification: queryConditions.specification || '',
ISHSJGCheck: queryConditions.iSHSJGCheck ? 'Y' : 'N',
ISWLCBCheck: queryConditions.iSWLCBCheck ? 'Y' : 'N',
OrderOption: queryConditions.orderOption || '',
PageSize: queryConditions.pageSize || 5000,
PageNum: queryConditions.pageNum || 0,
JGBID: queryConditions.jgbid || '',
ISDRCX:queryConditions.iSDRCX,
FileContent:queryConditions.fileContent,
FileName:queryConditions.fileName
};
loadOtherOptions(condition);
}
);
};
const loadOtherOptions = (condition) => {
GThinking.Web.AjaxServiceProxy.invoke(
'GetStructureWeightTableOptions',
false,
{ conditon: condition },
(result) => {
const allowedCodes = new Set(BJU061.split(',').map(code => code.trim()));
// 2. 过滤结果:排除Code不在允许列表中的项,得到过滤后的有效数据
const filteredResult =BJU061==''?result: result ? result.filter(item => allowedCodes.has(item.Code.split('|')[0])) : [];
if (!filteredResult) {
jgczbOptions.value = [];
return;
}
jgczbOptions.value = filteredResult.map(item => ({
value: item.Code, // 注意大小写
label: item.Name
}));
}
);
GThinking.Web.AjaxServiceProxy.invoke(
'GetStandardOptions',
false,
false,
(result) => {
if (!result) {
standardOptions.value = [];
return;
}
standardOptions.value = result.map(item => ({
value: item.Code, // 注意大小写
label: item.Name
}));
}
);
xhOptions.value = [];
filteredXhOptions.value = [];
GThinking.Web.AjaxServiceProxy.invoke(
'GetVoltageLevelOptions',
false,
{ conditon: condition },
(result) => {
if (!result) {
dydjOptions.value = [];
return;
}
dydjOptions.value = result.map(item => ({
value: item.Code, // 注意大小写
label: item.Name
}));
}
);
};
const remoteSearchModel = (query) => {
if (!query) {
filteredXhOptions.value = [];
xhOptions.value = [];
return;
}
modelLoading.value = true;
const condition = {
StructureWeightTableCode: queryConditions.structureWeightTableCode || '',
StructureWeightTableVersion: queryConditions.structureWeightTableVersion || '',
Models: query,
VoltageLevel: '',
Standard: '',
Specification: '',
ISHSJGCheck: queryConditions.iSHSJGCheck ? 'Y' : 'N',
ISWLCBCheck: queryConditions.iSWLCBCheck ? 'Y' : 'N',
OrderOption: '',
PageSize: 100,
PageNum: 0,
JGBID: queryConditions.jgbid || '',
ISDRCX:queryConditions.iSDRCX,
FileContent:queryConditions.fileContent,
FileName:queryConditions.fileName
};
GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'GetModelOptions',
false,
{ conditon: condition },
(result) => {
modelLoading.value = false;
if (!result) {
filteredXhOptions.value = [];
return;
}
const options = result.map(item => ({
value: item.Code,
label: item.Name
}));
filteredXhOptions.value = options;
xhOptions.value = [...options];
}
);
};
const handleStructureWeightChange = (val) => {
if (!val) return;
const arr = val.split('|');
queryConditions.structureWeightTableCode = arr[0] || '';
queryConditions.structureWeightTableVersion = arr[1] || '';
const condition = {
StructureWeightTableCode: queryConditions.structureWeightTableCode || '',
StructureWeightTableVersion: queryConditions.structureWeightTableVersion || '',
Models: Array.isArray(queryConditions.models)
? queryConditions.models.join(',')
: (queryConditions.models || ''),
VoltageLevel: queryConditions.voltageLevel || '',
Standard: queryConditions.standard || '',
Specification: queryConditions.specification || '',
ISHSJGCheck: queryConditions.iSHSJGCheck ? 'Y' : 'N',
ISWLCBCheck: queryConditions.iSWLCBCheck ? 'Y' : 'N',
OrderOption: queryConditions.orderOption || '',
PageSize: queryConditions.pageSize || 5000,
PageNum: queryConditions.pageNum || 0,
JGBID: queryConditions.jgbid || '',
ISDRCX:queryConditions.iSDRCX,
FileContent:queryConditions.fileContent,
FileName:queryConditions.fileName
};
GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373017.ashx';
xhOptions.value = [];
filteredXhOptions.value = [];
GThinking.Web.AjaxServiceProxy.invoke(
'GetVoltageLevelOptions',
false,
{ conditon: condition },
(result) => {
if (!result) {
dydjOptions.value = [];
return;
}
dydjOptions.value = result.map(item => ({
value: item.Code, // 注意大小写
label: item.Name
}));
}
);
};
const loadStructureWeightTableOptions = () => {
const condition = {
Models: Array.isArray(queryConditions.models)
? queryConditions.models.join(',')
: (queryConditions.models || ''),
VoltageLevel: queryConditions.voltageLevel || ''
};
GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'GetStructureWeightTableOptions',
false,
{ conditon: condition },
(result) => {
const allowedCodes = new Set(BJU061.split(',').map(code => code.trim()));
// 2. 过滤结果:排除Code不在允许列表中的项,得到过滤后的有效数据
const filteredResult =BJU061==''?result:result ? result.filter(item => allowedCodes.has(item.Code.split('|')[0])) : [];
if (!filteredResult || filteredResult.length === 0) {
jgczbOptions.value = [];
queryConditions.structureWeightTableValue = '';
queryConditions.structureWeightTableCode = '';
queryConditions.structureWeightTableVersion = '';
return;
}
jgczbOptions.value = filteredResult.map(item => ({
value: item.Code,
label: item.Name
}));
if (filteredResult.length === 1) {
queryConditions.structureWeightTableValue = filteredResult[0].Code;
const arr = filteredResult[0].Code.split('|');
queryConditions.structureWeightTableCode = arr[0] || '';
queryConditions.structureWeightTableVersion = arr[1] || '';
} else {
queryConditions.structureWeightTableValue = '';
queryConditions.structureWeightTableCode = '';
queryConditions.structureWeightTableVersion = '';
}
}
);
};
const handleModelChange = () => {
loadStructureWeightTableOptions();
};
const handleVoltageLevelChange = () => {
loadStructureWeightTableOptions();
};
/* ===== 自适应 ===== */
const checkEnableSJDC = () => {
GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373017.ashx';
GThinking.Web.AjaxServiceProxy.invoke(
'EnableSJDC',
false,
'',
(result) => {
enableSJDC.value = result === true;
}
);
};
onMounted(() => {
calcTableSize();
generateColumns();
checkEnableSJDC();
initOptionsData();
});
onBeforeUnmount(() => {
});
return {
loading,
enableSJDC,
queryDrawerVisible,
tableContainer,
jgbOptions,
tableWidth,
tableHeight,
tableVersion,
columns,
sjdc,
handleRowDblClick,
detailDialogVisible,
detailBasicInfo,
detailMaterialList,
rowEventHandlers,
currentPage,
pageSize,
total,
pagedData,
handleSizeChange,
handleCurrentChange,
dicCLMC,
dicCLJG,
dicCLWL,
buildDynamicMaterialColumns,
queryConditions,
jgczbOptions,
xhOptions,
filteredXhOptions,
modelLoading,
standardOptions,
dydjOptions,
pxfsOptions,
handleStructureWeightChange,
handleModelChange,
handleVoltageLevelChange,
remoteSearchModel,
getDic,
calcTableSize,
handleResetFilter,
confirmQueryDrawer,
openQueryDrawer,
uploadRef,
handleFileChange,
handleFileRemove
};
}
});
app.use(ElementPlus);
app.mount('#app');
+2033
View File
File diff suppressed because it is too large Load Diff
+1890
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+1
View File
File diff suppressed because one or more lines are too long
+360
View File
@@ -0,0 +1,360 @@
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3GUBGEe.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3iUBGEe.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3CUBGEe.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3-UBGEe.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* math */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMawCUBGEe.woff2) format('woff2');
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMaxKUBGEe.woff2) format('woff2');
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3OUBGEe.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3GUBGEe.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3iUBGEe.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3CUBGEe.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3-UBGEe.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* math */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMawCUBGEe.woff2) format('woff2');
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMaxKUBGEe.woff2) format('woff2');
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3OUBGEe.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3GUBGEe.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3iUBGEe.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3CUBGEe.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3-UBGEe.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* math */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMawCUBGEe.woff2) format('woff2');
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMaxKUBGEe.woff2) format('woff2');
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3OUBGEe.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3GUBGEe.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3iUBGEe.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3CUBGEe.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3-UBGEe.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* math */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMawCUBGEe.woff2) format('woff2');
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMaxKUBGEe.woff2) format('woff2');
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3OUBGEe.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
File diff suppressed because one or more lines are too long
+7135
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+317
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

File diff suppressed because one or more lines are too long
+1344
View File
File diff suppressed because one or more lines are too long
+78
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

+4602
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

+7
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+6
View File
File diff suppressed because one or more lines are too long
+20
View File
File diff suppressed because one or more lines are too long
+22
View File
File diff suppressed because one or more lines are too long
+180
View File
@@ -0,0 +1,180 @@
/*! Element Plus v2.8.6 */
var zhCn = {
name: "zh-cn",
el: {
breadcrumb: {
label: "\u9762\u5305\u5C51"
},
colorpicker: {
confirm: "\u786E\u5B9A",
clear: "\u6E05\u7A7A",
defaultLabel: "\u989C\u8272\u9009\u62E9\u5668",
description: "\u5F53\u524D\u989C\u8272 {color}\uFF0C\u6309 Enter \u952E\u9009\u62E9\u65B0\u989C\u8272",
alphaLabel: "\u9009\u62E9\u900F\u660E\u5EA6\u7684\u503C"
},
datepicker: {
now: "\u6B64\u523B",
today: "\u4ECA\u5929",
cancel: "\u53D6\u6D88",
clear: "\u6E05\u7A7A",
confirm: "\u786E\u5B9A",
dateTablePrompt: "\u4F7F\u7528\u65B9\u5411\u952E\u4E0E Enter \u952E\u53EF\u9009\u62E9\u65E5\u671F",
monthTablePrompt: "\u4F7F\u7528\u65B9\u5411\u952E\u4E0E Enter \u952E\u53EF\u9009\u62E9\u6708\u4EFD",
yearTablePrompt: "\u4F7F\u7528\u65B9\u5411\u952E\u4E0E Enter \u952E\u53EF\u9009\u62E9\u5E74\u4EFD",
selectedDate: "\u5DF2\u9009\u65E5\u671F",
selectDate: "\u9009\u62E9\u65E5\u671F",
selectTime: "\u9009\u62E9\u65F6\u95F4",
startDate: "\u5F00\u59CB\u65E5\u671F",
startTime: "\u5F00\u59CB\u65F6\u95F4",
endDate: "\u7ED3\u675F\u65E5\u671F",
endTime: "\u7ED3\u675F\u65F6\u95F4",
prevYear: "\u524D\u4E00\u5E74",
nextYear: "\u540E\u4E00\u5E74",
prevMonth: "\u4E0A\u4E2A\u6708",
nextMonth: "\u4E0B\u4E2A\u6708",
year: "\u5E74",
month1: "1 \u6708",
month2: "2 \u6708",
month3: "3 \u6708",
month4: "4 \u6708",
month5: "5 \u6708",
month6: "6 \u6708",
month7: "7 \u6708",
month8: "8 \u6708",
month9: "9 \u6708",
month10: "10 \u6708",
month11: "11 \u6708",
month12: "12 \u6708",
weeks: {
sun: "\u65E5",
mon: "\u4E00",
tue: "\u4E8C",
wed: "\u4E09",
thu: "\u56DB",
fri: "\u4E94",
sat: "\u516D"
},
weeksFull: {
sun: "\u661F\u671F\u65E5",
mon: "\u661F\u671F\u4E00",
tue: "\u661F\u671F\u4E8C",
wed: "\u661F\u671F\u4E09",
thu: "\u661F\u671F\u56DB",
fri: "\u661F\u671F\u4E94",
sat: "\u661F\u671F\u516D"
},
months: {
jan: "\u4E00\u6708",
feb: "\u4E8C\u6708",
mar: "\u4E09\u6708",
apr: "\u56DB\u6708",
may: "\u4E94\u6708",
jun: "\u516D\u6708",
jul: "\u4E03\u6708",
aug: "\u516B\u6708",
sep: "\u4E5D\u6708",
oct: "\u5341\u6708",
nov: "\u5341\u4E00\u6708",
dec: "\u5341\u4E8C\u6708"
}
},
inputNumber: {
decrease: "\u51CF\u5C11\u6570\u503C",
increase: "\u589E\u52A0\u6570\u503C"
},
select: {
loading: "\u52A0\u8F7D\u4E2D",
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
noData: "\u65E0\u6570\u636E",
placeholder: "\u8BF7\u9009\u62E9"
},
dropdown: {
toggleDropdown: "\u5207\u6362\u4E0B\u62C9\u9009\u9879"
},
mention: {
loading: "\u52A0\u8F7D\u4E2D"
},
cascader: {
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
loading: "\u52A0\u8F7D\u4E2D",
placeholder: "\u8BF7\u9009\u62E9",
noData: "\u6682\u65E0\u6570\u636E"
},
pagination: {
goto: "\u8F6C\u5230",
pagesize: "\u6761/\u9875",
total: "\u5171 {total} \u6761",
pageClassifier: "\u9875",
page: "\u9875",
prev: "\u4E0A\u4E00\u9875",
next: "\u4E0B\u4E00\u9875",
currentPage: "\u7B2C {pager} \u9875",
prevPages: "\u5411\u524D {pager} \u9875",
nextPages: "\u5411\u540E {pager} \u9875",
deprecationWarning: "\u4F60\u4F7F\u7528\u4E86\u4E00\u4E9B\u5DF2\u88AB\u5E9F\u5F03\u7684\u7528\u6CD5\uFF0C\u8BF7\u53C2\u8003 el-pagination \u7684\u5B98\u65B9\u6587\u6863"
},
dialog: {
close: "\u5173\u95ED\u6B64\u5BF9\u8BDD\u6846"
},
drawer: {
close: "\u5173\u95ED\u6B64\u5BF9\u8BDD\u6846"
},
messagebox: {
title: "\u63D0\u793A",
confirm: "\u786E\u5B9A",
cancel: "\u53D6\u6D88",
error: "\u8F93\u5165\u7684\u6570\u636E\u4E0D\u5408\u6CD5!",
close: "\u5173\u95ED\u6B64\u5BF9\u8BDD\u6846"
},
upload: {
deleteTip: "\u6309 delete \u952E\u53EF\u5220\u9664",
delete: "\u5220\u9664",
preview: "\u67E5\u770B\u56FE\u7247",
continue: "\u7EE7\u7EED\u4E0A\u4F20"
},
slider: {
defaultLabel: "\u6ED1\u5757\u4ECB\u4E8E {min} \u81F3 {max}",
defaultRangeStartLabel: "\u9009\u62E9\u8D77\u59CB\u503C",
defaultRangeEndLabel: "\u9009\u62E9\u7ED3\u675F\u503C"
},
table: {
emptyText: "\u6682\u65E0\u6570\u636E",
confirmFilter: "\u7B5B\u9009",
resetFilter: "\u91CD\u7F6E",
clearFilter: "\u5168\u90E8",
sumText: "\u5408\u8BA1"
},
tour: {
next: "\u4E0B\u4E00\u6B65",
previous: "\u4E0A\u4E00\u6B65",
finish: "\u7ED3\u675F\u5BFC\u89C8"
},
tree: {
emptyText: "\u6682\u65E0\u6570\u636E"
},
transfer: {
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
noData: "\u65E0\u6570\u636E",
titles: ["\u5217\u8868 1", "\u5217\u8868 2"],
filterPlaceholder: "\u8BF7\u8F93\u5165\u641C\u7D22\u5185\u5BB9",
noCheckedFormat: "\u5171 {total} \u9879",
hasCheckedFormat: "\u5DF2\u9009 {checked}/{total} \u9879"
},
image: {
error: "\u52A0\u8F7D\u5931\u8D25"
},
pageHeader: {
title: "\u8FD4\u56DE"
},
popconfirm: {
confirmButtonText: "\u786E\u5B9A",
cancelButtonText: "\u53D6\u6D88"
},
carousel: {
leftArrow: "\u4E0A\u4E00\u5F20\u5E7B\u706F\u7247",
rightArrow: "\u4E0B\u4E00\u5F20\u5E7B\u706F\u7247",
indicator: "\u5E7B\u706F\u7247\u5207\u6362\u81F3\u7D22\u5F15 {index}"
}
}
};