mac地址,推送调整

This commit is contained in:
sjl
2025-10-20 09:42:01 +08:00
parent 448d450936
commit 177e50de75
3 changed files with 117 additions and 186 deletions

View File

@@ -1,25 +1,22 @@
<template> <template>
<div class="mac-address-input" :class="{ disabled: disabled }"> <div class="mac-address-input" :class="{ disabled: disabled }">
<template v-for="n in 6" :key="n">
<el-input <el-input
ref="inputRefs" ref="inputRef"
v-model="segments[n - 1]" v-model="macValue"
type="text" type="text"
maxlength="2" maxlength="17"
:disabled="disabled" :disabled="disabled"
@input="handleInput(n - 1)" @input="handleInput"
@keydown="handleKeydown(n - 1,$event)" @keydown="handleKeydown"
@focus="handleFocus(n - 1)" @focus="handleFocus"
@blur="handleBlur" @blur="handleBlur"
@paste="handlePaste(n - 1, $event)" @paste="handlePaste"
/> />
<span v-if="n < 6" class="separator">:</span>
</template>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch, nextTick } from 'vue' import { ref, watch } from 'vue'
interface Props { interface Props {
modelValue?: string modelValue?: string
@@ -37,117 +34,85 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<Emits>() const emit = defineEmits<Emits>()
// 创建6个输入框的引用 // 创建个输入框的引用
const inputRefs = ref<InstanceType<typeof import('element-plus').ElInput>[]>([]) const inputRef = ref<InstanceType<typeof import('element-plus').ElInput> | null>(null)
// MAC地址的6个段 // MAC地址
const segments = ref<string[]>(Array(6).fill('')) const macValue = ref<string>('')
// 解析传入的MAC地址 // 解析传入的MAC地址
const parseMacAddress = (mac: string): string[] => { const parseMacAddress = (mac: string): string => {
if (!mac) return Array(6).fill('') if (!mac) return ''
// 移除非十六进制字符并转为大写 // 移除非十六进制字符并转为大写
const cleanMac = mac.replace(/[^0-9a-fA-F]/g, '').toUpperCase() const cleanMac = mac.replace(/[^0-9a-fA-F]/g, '').toUpperCase()
// 分割成6段每段2个字符 // 按每2个字符分割并用冒号连接
const result: string[] = [] let result = ''
for (let i = 0; i < 6; i++) { for (let i = 0; i < cleanMac.length; i += 2) {
result.push(cleanMac.substr(i * 2, 2)) if (i > 0) result += ':'
result += cleanMac.substr(i, 2)
} }
return result return result.substring(0, 17) // 最多17个字符 (12个数字+5个冒号)
} }
// 格式化MAC地址 // 格式化MAC地址 - 改进版
const formatSegment = (value: string): string => { const formatMac = (value: string): string => {
// 只保留前两个十六进制字符并转为大写 // 移除所有冒号
return value.replace(/[^0-9a-fA-F]/g, '').toUpperCase().substr(0, 2) const cleanValue = value.replace(/:/g, '')
// 只保留十六进制字符并转为大写
const hexOnly = cleanValue.replace(/[^0-9a-fA-F]/g, '').toUpperCase()
// 按每两个字符添加冒号最多6段
let formatted = ''
for (let i = 0; i < Math.min(hexOnly.length, 12); i += 2) {
if (i > 0) formatted += ':'
formatted += hexOnly.substr(i, 2)
}
return formatted
} }
// 当前聚焦的输入框索引 // 当前聚焦的输入框索引
const focusedIndex = ref<number | null>(null) const focusedIndex = ref<number | null>(null)
// 处理输入事件 // 处理输入事件
const handleInput = (index: number) => { const handleInput = (value: string) => {
// 格式化输入值 const formatted = formatMac(value)
const formatted = formatSegment(segments.value[index]) macValue.value = formatted
segments.value[index] = formatted // 发出不带冒号的纯净值
emit('update:modelValue', formatted.replace(/:/g, ''))
// 如果当前段已满2个字符且不是最后一段自动跳转到下一个输入框
if (formatted.length === 2 && index < 5) {
// 获取下一个输入框的DOM元素
setTimeout(() => {
const nextInput = inputRefs.value[index + 1]
if (nextInput) {
const inputEl = nextInput.$el.querySelector('input')
if (inputEl) {
inputEl.focus()
inputEl.select()
}
}
}, 0)
}
// 更新v-model值
updateModelValue()
} }
// 处理键盘事件 // 处理键盘事件
const handleKeydown = (index: number, event: KeyboardEvent) => { const handleKeydown = (event: KeyboardEvent) => {
const target = event.target as HTMLInputElement const target = event.target as HTMLInputElement
// 处理退格键 // 处理退格键
if (event.key === 'Backspace' && target.selectionStart === 0 && target.selectionEnd === 0) { if (event.key === 'Backspace') {
if (segments.value[index] === '' && index > 0) { // 处理在冒号前删除的情况
// 如果当前段为空,跳转到前一个输入框 const cursorPos = target.selectionStart || 0
if (cursorPos > 0 && macValue.value[cursorPos - 1] === ':' &&
target.selectionStart === target.selectionEnd) {
event.preventDefault() event.preventDefault()
const prevInput = inputRefs.value[index - 1] // 删除冒号前的两个字符
if (prevInput) { const newValue = macValue.value.substring(0, cursorPos - 3) +
const inputEl = prevInput.$el.querySelector('input') macValue.value.substring(cursorPos)
if (inputEl) { macValue.value = newValue
inputEl.focus() // 设置光标位置
// 将光标移到末尾
setTimeout(() => { setTimeout(() => {
inputEl.selectionStart = inputEl.value.length if (target.setSelectionRange) {
inputEl.selectionEnd = inputEl.value.length target.setSelectionRange(cursorPos - 3, cursorPos - 3)
}
}, 0) }, 0)
} emit('update:modelValue', newValue.replace(/:/g, ''))
}
}
}
// 处理左箭头键
if (event.key === 'ArrowLeft' && target.selectionStart === 0) {
if (index > 0) {
event.preventDefault()
const prevInput = inputRefs.value[index - 1]
if (prevInput) {
const inputEl = prevInput.$el.querySelector('input')
if (inputEl) {
inputEl.focus()
}
}
}
}
// 处理右箭头键和制表符
if ((event.key === 'ArrowRight' && target.selectionStart === target.value.length) || event.key === 'Tab') {
if (index < 5) {
event.preventDefault()
const nextInput = inputRefs.value[index + 1]
if (nextInput) {
const inputEl = nextInput.$el.querySelector('input')
if (inputEl) {
inputEl.focus()
}
}
} }
} }
} }
// 处理焦点事件 // 处理焦点事件
const handleFocus = (index: number) => { const handleFocus = () => {
focusedIndex.value = index focusedIndex.value = 0
} }
// 处理失焦事件 // 处理失焦事件
@@ -156,56 +121,26 @@ const handleBlur = () => {
} }
// 处理粘贴事件 // 处理粘贴事件
const handlePaste = (index: number, event: ClipboardEvent) => { const handlePaste = (event: ClipboardEvent) => {
event.preventDefault() event.preventDefault()
const pastedText = event.clipboardData?.getData('text') || '' const pastedText = event.clipboardData?.getData('text') || ''
// 清理粘贴的文本 // 清理粘贴的文本
const cleanText = parseMacAddress(pastedText) const cleanPastedText = pastedText.replace(/[^0-9a-fA-F]/g, '').toUpperCase()
const formatted = formatMac(cleanPastedText)
// 填充各段 macValue.value = formatted
for (let i = 0; i < 6; i++) { emit('update:modelValue', formatted.replace(/:/g, ''))
segments.value[i] = cleanText[i] || ''
}
// 更新v-model值
updateModelValue()
// 聚焦到最后一个非空段或最后一个段
setTimeout(() => {
let focusIndex = 5
for (let i = 5; i >= 0; i--) {
if (segments.value[i] !== '') {
focusIndex = i
break
}
}
const inputToFocus = inputRefs.value[focusIndex]
if (inputToFocus) {
const inputEl = inputToFocus.$el.querySelector('input')
if (inputEl) {
inputEl.focus()
inputEl.select()
}
}
}, 0)
}
// 更新v-model值
const updateModelValue = () => {
// 过滤掉空段,然后用冒号连接
const nonEmptySegments = segments.value.filter(s => s !== '')
const mac = nonEmptySegments.join(':')
emit('update:modelValue', mac)
} }
// 监听modelValue变化 // 监听modelValue变化
watch( watch(
() => props.modelValue, () => props.modelValue,
(newVal) => { (newVal) => {
if (newVal !== segments.value.filter(s => s !== '').join(':')) { const cleanNewVal = (newVal || '').replace(/[^0-9a-fA-F]/g, '').toUpperCase()
segments.value = parseMacAddress(newVal || '') const currentCleanValue = macValue.value.replace(/:/g, '')
if (cleanNewVal !== currentCleanValue) {
macValue.value = parseMacAddress(cleanNewVal)
} }
}, },
{ immediate: true } { immediate: true }
@@ -214,37 +149,17 @@ watch(
<style scoped lang="scss"> <style scoped lang="scss">
.mac-address-input { .mac-address-input {
display: flex; width: 100%;
align-items: center;
gap: 4px;
&.disabled { &.disabled {
opacity: 0.7; opacity: 0.7;
} }
:deep(.el-input__wrapper) {
input { input {
width: 40px;
height: 32px;
text-align: center;
border: 1px solid #dcdfe6;
border-radius: 4px;
outline: none;
font-size: 14px;
text-transform: uppercase; text-transform: uppercase;
font-family: inherit; // 使用继承的字体而不是等宽字体
&:focus {
border-color: #409eff;
} }
&:disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.separator {
user-select: none;
font-weight: 500;
} }
} }
</style> </style>

View File

@@ -309,6 +309,7 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
class="form-item" class="form-item"
label="装置mac地址:" label="装置mac地址:"
:rules="{ required: true, message: '请输入装置mac地址', trigger: 'blur' }" :rules="{ required: true, message: '请输入装置mac地址', trigger: 'blur' }"
@@ -694,7 +695,7 @@ interface DeviceInfo {
nodeId: string nodeId: string
cntractNo: string cntractNo: string
sort: number sort: number
nodeProcess:number nodeProcess:string
} }
// 设备信息列表 // 设备信息列表
const deviceInfoList = ref<DeviceInfo[]>([]) const deviceInfoList = ref<DeviceInfo[]>([])
@@ -841,7 +842,6 @@ const handleDialogClose = () => {
countdown.value = 0 countdown.value = 0
} }
//台账推送
const onAdd = async () => { const onAdd = async () => {
resultDialogVisible.value = true resultDialogVisible.value = true
pushResult.value = null pushResult.value = null
@@ -859,8 +859,23 @@ const onAdd = async () => {
try { try {
// 调用推送日志接口 // 调用推送日志接口
await pushLog() const pushLogResponse = await pushLog()
// 检查返回的data是否为"暂无需要推送的数据"
if (pushLogResponse.data != "成功") {
// 直接提示用户没有数据推送
pushResult.value = {
success: false,
message: '暂无需要推送的数据',
logs: [{
message: '暂无需要推送的数据'
}]
}
return;
}
// 如果data不是"暂无需要推送的数据",则继续执行
if (pushLogResponse.data === "成功") {
// 等待30秒 // 等待30秒
await new Promise(resolve => setTimeout(resolve, 30000)) await new Promise(resolve => setTimeout(resolve, 30000))
@@ -878,6 +893,7 @@ const onAdd = async () => {
message: item.message || JSON.stringify(item) message: item.message || JSON.stringify(item)
})) }))
} }
}
} catch (error: any) { } catch (error: any) {
pushResult.value = { pushResult.value = {
success: false, success: false,
@@ -1028,7 +1044,7 @@ const add = () => {
nodeId: '', nodeId: '',
cntractNo: '', cntractNo: '',
sort: 0, sort: 0,
nodeProcess: 1, nodeProcess: '自动分配',
}) })
busBarIndex.value = (deviceInfoList.value.length - 1).toString() busBarIndex.value = (deviceInfoList.value.length - 1).toString()
// 清理监测点数据 // 清理监测点数据
@@ -1381,7 +1397,7 @@ const next = async () => {
nodeId: '', nodeId: '',
cntractNo: '', cntractNo: '',
sort: 0, sort: 0,
nodeProcess: 1, nodeProcess: '自动分配',
}) })
busBarIndex.value = (deviceInfoList.value.length - 1).toString() busBarIndex.value = (deviceInfoList.value.length - 1).toString()
nextfalg.value = false nextfalg.value = false
@@ -2080,7 +2096,7 @@ const handleBusBarTabsEdit = (targetName: any, action: any) => {
nodeId: '', nodeId: '',
cntractNo: '', cntractNo: '',
sort: 0, sort: 0,
nodeProcess: 1, nodeProcess: '自动分配',
}) })
busBarIndex.value = (deviceInfoList.value.length - 1).toString() busBarIndex.value = (deviceInfoList.value.length - 1).toString()
} else if (action === 'remove') { } else if (action === 'remove') {

View File

@@ -61,7 +61,7 @@
<span v-if="data.processState != null"> <span v-if="data.processState != null">
{{ node.label }} {{ node.label }}
</span> </span>
<span v-else>{{ data.subName }}_{{ data.name }}</span> <span v-else>{{ data.name }}</span>
<span <span
v-if="data.processState != null" v-if="data.processState != null"
class="iconSpan" class="iconSpan"