245 lines
5.9 KiB
Vue
245 lines
5.9 KiB
Vue
<template>
|
||
<ElDialog v-model="visible" title="设置切卡模式" width="500px">
|
||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="96px">
|
||
<ElFormItem label="设备标识">
|
||
<span class="device-identifier">{{ deviceIdentifier || '-' }}</span>
|
||
</ElFormItem>
|
||
|
||
<ElFormItem label="当前模式">
|
||
<ElTag :type="currentModeValue === 0 ? 'success' : 'warning'">
|
||
{{ currentModeValue === 0 ? '自动切卡' : '手动切卡' }}
|
||
</ElTag>
|
||
</ElFormItem>
|
||
|
||
<ElAlert
|
||
v-if="!hasImei"
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
title="设备未配置 IMEI,无法设置切卡模式"
|
||
style="margin-bottom: 16px"
|
||
/>
|
||
<ElAlert
|
||
v-else-if="availableCards.length === 0"
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
title="暂无绑定卡,无法设置切卡模式"
|
||
style="margin-bottom: 16px"
|
||
/>
|
||
|
||
<ElFormItem label="绑定卡" prop="iot_card_id">
|
||
<ElSelect
|
||
v-model="form.iot_card_id"
|
||
style="width: 100%"
|
||
placeholder="请选择绑定卡"
|
||
:disabled="!canSubmit"
|
||
>
|
||
<ElOption
|
||
v-for="card in availableCards"
|
||
:key="card.iot_card_id"
|
||
:label="getCardLabel(card)"
|
||
:value="card.iot_card_id"
|
||
/>
|
||
</ElSelect>
|
||
<div class="field-tip">请选择一张绑定卡</div>
|
||
</ElFormItem>
|
||
|
||
<ElFormItem label="切卡模式" prop="switch_mode">
|
||
<ElRadioGroup v-model="form.switch_mode">
|
||
<ElRadio :value="0">自动切卡</ElRadio>
|
||
<ElRadio :value="1">手动切卡</ElRadio>
|
||
</ElRadioGroup>
|
||
</ElFormItem>
|
||
|
||
<ElFormItem>
|
||
<div class="mode-description">
|
||
<p>说明:</p>
|
||
<p>• <strong>自动切卡</strong>:设备根据信号强度自动切换到最优的 SIM 卡</p>
|
||
<p>• <strong>手动切卡</strong>:需要手动触发切换 SIM 卡操作</p>
|
||
</div>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
|
||
<template #footer>
|
||
<ElButton @click="handleCancel">取消</ElButton>
|
||
<ElButton
|
||
type="primary"
|
||
@click="handleConfirm"
|
||
:loading="confirmLoading"
|
||
:disabled="!canSubmit"
|
||
>
|
||
确认设置
|
||
</ElButton>
|
||
</template>
|
||
</ElDialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, reactive, ref, watch } from 'vue'
|
||
import {
|
||
ElAlert,
|
||
ElButton,
|
||
ElDialog,
|
||
ElForm,
|
||
ElFormItem,
|
||
ElOption,
|
||
ElRadio,
|
||
ElRadioGroup,
|
||
ElSelect,
|
||
ElTag
|
||
} from 'element-plus'
|
||
import type { FormInstance, FormRules } from 'element-plus'
|
||
|
||
interface SwitchModeCardOption {
|
||
iot_card_id: number
|
||
iccid: string
|
||
slot_position?: number
|
||
carrier_name?: string
|
||
msisdn?: string
|
||
network_status?: number
|
||
real_name_status?: number
|
||
is_current?: boolean
|
||
}
|
||
|
||
interface SwitchModeForm {
|
||
iot_card_id?: number
|
||
switch_mode: 0 | 1
|
||
}
|
||
|
||
interface Props {
|
||
modelValue: boolean
|
||
deviceIdentifier: string
|
||
currentMode?: number | string
|
||
cards?: SwitchModeCardOption[]
|
||
hasImei?: boolean
|
||
confirmLoading?: boolean
|
||
}
|
||
|
||
interface Emits {
|
||
(e: 'update:modelValue', value: boolean): void
|
||
(e: 'confirm', data: { iot_card_id: number; switch_mode: 0 | 1 }): void
|
||
}
|
||
|
||
const props = withDefaults(defineProps<Props>(), {
|
||
currentMode: 0,
|
||
cards: () => [],
|
||
hasImei: false,
|
||
confirmLoading: false
|
||
})
|
||
const emit = defineEmits<Emits>()
|
||
|
||
const formRef = ref<FormInstance>()
|
||
|
||
const form = reactive<SwitchModeForm>({
|
||
iot_card_id: undefined,
|
||
switch_mode: 0
|
||
})
|
||
|
||
const rules: FormRules<SwitchModeForm> = {
|
||
iot_card_id: [{ required: true, message: '请选择绑定卡', trigger: 'change' }],
|
||
switch_mode: [{ required: true, message: '请选择切卡模式', trigger: 'change' }]
|
||
}
|
||
|
||
const visible = computed({
|
||
get: () => props.modelValue,
|
||
set: (value) => emit('update:modelValue', value)
|
||
})
|
||
|
||
const currentModeValue = computed<0 | 1>(() => (Number(props.currentMode) === 1 ? 1 : 0))
|
||
|
||
const availableCards = computed(() => props.cards || [])
|
||
|
||
const canSubmit = computed(() => props.hasImei && availableCards.value.length > 0)
|
||
|
||
const syncFormState = () => {
|
||
form.switch_mode = currentModeValue.value
|
||
|
||
const selectedStillExists = availableCards.value.some(
|
||
(card) => card.iot_card_id === form.iot_card_id
|
||
)
|
||
if (!selectedStillExists) {
|
||
form.iot_card_id = availableCards.value[0]?.iot_card_id
|
||
}
|
||
}
|
||
|
||
watch(
|
||
() => props.modelValue,
|
||
(newValue) => {
|
||
if (newValue) {
|
||
syncFormState()
|
||
return
|
||
}
|
||
|
||
formRef.value?.clearValidate()
|
||
}
|
||
)
|
||
|
||
watch(
|
||
() => [props.cards, props.currentMode] as const,
|
||
() => {
|
||
if (visible.value) {
|
||
syncFormState()
|
||
}
|
||
},
|
||
{ deep: true }
|
||
)
|
||
|
||
const getCardLabel = (card: SwitchModeCardOption) => {
|
||
const parts = [`卡槽 ${card.slot_position ?? '-'}`, card.iccid]
|
||
|
||
if (card.carrier_name) {
|
||
parts.push(card.carrier_name)
|
||
}
|
||
|
||
if (card.is_current) {
|
||
parts.push('当前使用')
|
||
}
|
||
|
||
return parts.join(' / ')
|
||
}
|
||
|
||
const handleCancel = () => {
|
||
visible.value = false
|
||
}
|
||
|
||
const handleConfirm = async () => {
|
||
if (!formRef.value || !canSubmit.value) return
|
||
|
||
try {
|
||
await formRef.value.validate()
|
||
|
||
emit('confirm', {
|
||
iot_card_id: form.iot_card_id!,
|
||
switch_mode: form.switch_mode
|
||
})
|
||
} catch {
|
||
// Element Plus validation rejection is expected when required fields are missing.
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.device-identifier {
|
||
font-weight: 600;
|
||
color: var(--el-color-primary);
|
||
}
|
||
|
||
.field-tip {
|
||
margin-top: 6px;
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
|
||
.mode-description {
|
||
font-size: 12px;
|
||
line-height: 1.6;
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
|
||
.mode-description p {
|
||
margin: 0;
|
||
}
|
||
</style>
|