This commit is contained in:
@@ -403,7 +403,14 @@
|
||||
</div>
|
||||
<div v-else>
|
||||
<ElTable :data="deviceCards" border style="width: 100%">
|
||||
<ElTableColumn prop="slot_position" label="插槽位置" width="100" align="center" />
|
||||
<ElTableColumn prop="slot_position" label="插槽位置" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<div style="display: flex; align-items: center; justify-content: center; gap: 4px">
|
||||
<span>{{ row.slot_position }}</span>
|
||||
<ElTag v-if="row.is_current" type="success" size="small">当前</ElTag>
|
||||
</div>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="iccid" label="ICCID" min-width="180" />
|
||||
<ElTableColumn prop="msisdn" label="接入号" width="140" />
|
||||
<ElTableColumn prop="status" label="状态" width="100" align="center">
|
||||
@@ -524,7 +531,7 @@
|
||||
<ElOption
|
||||
v-for="card in deviceBindingCards"
|
||||
:key="card.iccid"
|
||||
:label="`${card.iccid} - 插槽${card.slot_position} - ${card.carrier_name}`"
|
||||
:label="`${card.iccid} - 插槽${card.slot_position} - ${card.carrier_name}${card.is_current ? ' (当前)' : ''}`"
|
||||
:value="card.iccid"
|
||||
>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
@@ -858,6 +865,11 @@
|
||||
{ label: '最大插槽数', prop: 'max_sim_slots' },
|
||||
{ label: '已绑定卡数', prop: 'bound_card_count' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '在线状态', prop: 'online_status' },
|
||||
{ label: '固件版本', prop: 'software_version' },
|
||||
{ label: '切卡模式', prop: 'switch_mode' },
|
||||
{ label: '最后在线时间', prop: 'last_online_time' },
|
||||
{ label: '最后同步时间', prop: 'last_gateway_sync_at' },
|
||||
{ label: '批次号', prop: 'batch_no' },
|
||||
{ label: '创建时间', prop: 'created_at' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
@@ -914,6 +926,14 @@
|
||||
const res = await DeviceService.getDeviceCards(deviceId)
|
||||
if (res.code === 0 && res.data) {
|
||||
deviceCards.value = res.data.bindings || []
|
||||
console.log('设备绑定的卡列表:', deviceCards.value)
|
||||
|
||||
// 🔧 临时调试:强制第一张卡显示为当前卡(方便测试UI效果)
|
||||
// 测试完成后请删除此代码
|
||||
if (deviceCards.value.length > 0) {
|
||||
deviceCards.value[0].is_current = true
|
||||
console.log('🧪 测试模式:已将第一张卡标记为当前卡')
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取设备绑定的卡列表失败:', error)
|
||||
@@ -1135,6 +1155,50 @@
|
||||
return h(ElTag, { type: status.type }, () => status.text)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'online_status',
|
||||
label: '在线状态',
|
||||
width: 100,
|
||||
formatter: (row: Device) => {
|
||||
const onlineStatusMap: Record<number, { text: string; type: any }> = {
|
||||
0: { text: '未知', type: 'info' },
|
||||
1: { text: '在线', type: 'success' },
|
||||
2: { text: '离线', type: 'danger' }
|
||||
}
|
||||
const status = onlineStatusMap[row.online_status ?? 0] || { text: '未知', type: 'info' }
|
||||
return h(ElTag, { type: status.type }, () => status.text)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'software_version',
|
||||
label: '固件版本',
|
||||
width: 120,
|
||||
formatter: (row: Device) => row.software_version || '-'
|
||||
},
|
||||
{
|
||||
prop: 'switch_mode',
|
||||
label: '切卡模式',
|
||||
width: 100,
|
||||
formatter: (row: Device) => {
|
||||
const modeMap: Record<string, string> = {
|
||||
'0': '自动',
|
||||
'1': '手动'
|
||||
}
|
||||
return modeMap[row.switch_mode || ''] || '-'
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'last_online_time',
|
||||
label: '最后在线时间',
|
||||
width: 180,
|
||||
formatter: (row: Device) => row.last_online_time ? formatDateTime(row.last_online_time) : '-'
|
||||
},
|
||||
{
|
||||
prop: 'last_gateway_sync_at',
|
||||
label: '最后同步时间',
|
||||
width: 180,
|
||||
formatter: (row: Device) => row.last_gateway_sync_at ? formatDateTime(row.last_gateway_sync_at) : '-'
|
||||
},
|
||||
{
|
||||
prop: 'batch_no',
|
||||
label: '批次号',
|
||||
@@ -1717,6 +1781,14 @@
|
||||
const res = await DeviceService.getDeviceCards(device.id)
|
||||
if (res.code === 0 && res.data) {
|
||||
deviceBindingCards.value = res.data.bindings || []
|
||||
|
||||
// 🔧 临时调试:强制第一张卡显示为当前卡(方便测试UI效果)
|
||||
// 测试完成后请删除此代码
|
||||
if (deviceBindingCards.value.length > 0) {
|
||||
deviceBindingCards.value[0].is_current = true
|
||||
console.log('🧪 切换SIM卡测试模式:已将第一张卡标记为当前卡')
|
||||
}
|
||||
|
||||
if (deviceBindingCards.value.length === 0) {
|
||||
ElMessage.warning('该设备暂无绑定的SIM卡')
|
||||
}
|
||||
|
||||
@@ -63,16 +63,36 @@
|
||||
{{ deviceDetail.status_name }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="在线状态">
|
||||
<ElTag :type="getOnlineStatusTagType(deviceDetail.online_status)">
|
||||
{{ getOnlineStatusText(deviceDetail.online_status) }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="店铺名称">{{
|
||||
deviceDetail.shop_name || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="固件版本">{{
|
||||
deviceDetail.software_version || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="切卡模式">{{
|
||||
getSwitchModeText(deviceDetail.switch_mode)
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="批次号">{{ deviceDetail.batch_no }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="最后在线时间">{{
|
||||
deviceDetail.last_online_time || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="最后同步时间">{{
|
||||
deviceDetail.last_gateway_sync_at || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="激活时间">{{
|
||||
deviceDetail.activated_at || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="创建时间">{{ deviceDetail.created_at }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="更新时间">{{ deviceDetail.updated_at }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem></ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</ElCard>
|
||||
|
||||
@@ -131,6 +151,35 @@
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 获取在线状态标签类型
|
||||
const getOnlineStatusTagType = (status?: number) => {
|
||||
const typeMap: Record<number, any> = {
|
||||
0: 'info', // 未知
|
||||
1: 'success', // 在线
|
||||
2: 'danger' // 离线
|
||||
}
|
||||
return typeMap[status ?? 0] || 'info'
|
||||
}
|
||||
|
||||
// 获取在线状态文本
|
||||
const getOnlineStatusText = (status?: number) => {
|
||||
const textMap: Record<number, string> = {
|
||||
0: '未知',
|
||||
1: '在线',
|
||||
2: '离线'
|
||||
}
|
||||
return textMap[status ?? 0] || '未知'
|
||||
}
|
||||
|
||||
// 获取切卡模式文本
|
||||
const getSwitchModeText = (mode?: string) => {
|
||||
const modeMap: Record<string, string> = {
|
||||
'0': '自动',
|
||||
'1': '手动'
|
||||
}
|
||||
return modeMap[mode || ''] || '--'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
<p>3. 列格式请设置为文本格式,避免长数字被转为科学计数法</p>
|
||||
<p
|
||||
>4.
|
||||
必填列:virtual_no(设备号)、device_name(设备名称)、device_model(设备型号)、device_type(设备类型)</p
|
||||
必填列:virtual_no(设备号)、device_name(设备名称)、device_model(设备型号)、device_type(设备类型)、imei(设备IMEI号)</p
|
||||
>
|
||||
<p
|
||||
>5. 可选列:manufacturer(制造商)、max_sim_slots(最大插槽数,默认4)、iccid_1 ~
|
||||
@@ -445,6 +445,7 @@
|
||||
device_name: '智能水表01',
|
||||
device_model: 'WM-2000',
|
||||
device_type: '智能水表',
|
||||
imei: '860123456789012',
|
||||
manufacturer: '华为',
|
||||
max_sim_slots: 4,
|
||||
iccid_1: '89860123456789012345',
|
||||
@@ -457,6 +458,7 @@
|
||||
device_name: 'GPS定位器01',
|
||||
device_model: 'GPS-3000',
|
||||
device_type: '定位设备',
|
||||
imei: '860123456789013',
|
||||
manufacturer: '小米',
|
||||
max_sim_slots: 2,
|
||||
iccid_1: '89860123456789012346',
|
||||
@@ -476,6 +478,7 @@
|
||||
{ wch: 20 }, // device_name
|
||||
{ wch: 15 }, // device_model
|
||||
{ wch: 15 }, // device_type
|
||||
{ wch: 18 }, // imei
|
||||
{ wch: 15 }, // manufacturer
|
||||
{ wch: 15 }, // max_sim_slots
|
||||
{ wch: 22 }, // iccid_1
|
||||
|
||||
@@ -1715,16 +1715,13 @@
|
||||
// 通过 ICCID 解析获取资产信息,resolveAsset 接口已包含所有需要的数据
|
||||
const res = await AssetService.resolveAsset(iccid)
|
||||
if (res.code === 0 && res.data) {
|
||||
// 直接使用 resolveAsset 返回的实名状态,real_name_status: 0未实名 1实名中 2已实名
|
||||
// 直接使用 resolveAsset 返回的实名状态,real_name_status: 0未实名 1已实名
|
||||
let statusText = '未知'
|
||||
switch (res.data.real_name_status) {
|
||||
case 0:
|
||||
statusText = '未实名'
|
||||
break
|
||||
case 1:
|
||||
statusText = '实名中'
|
||||
break
|
||||
case 2:
|
||||
statusText = '已实名'
|
||||
break
|
||||
}
|
||||
|
||||
@@ -64,11 +64,20 @@
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||
<ElFormItem label="运营商编码" prop="carrier_code">
|
||||
<ElInput
|
||||
v-model="form.carrier_code"
|
||||
placeholder="请输入运营商编码"
|
||||
:disabled="dialogType === 'edit'"
|
||||
/>
|
||||
<div style="display: flex; gap: 8px">
|
||||
<ElInput
|
||||
v-model="form.carrier_code"
|
||||
placeholder="请输入运营商编码或点击生成"
|
||||
:disabled="dialogType === 'edit'"
|
||||
clearable
|
||||
style="flex: 1"
|
||||
/>
|
||||
<CodeGeneratorButton
|
||||
v-if="dialogType === 'add'"
|
||||
code-type="carrier"
|
||||
@generated="handleCodeGenerated"
|
||||
/>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="运营商名称" prop="carrier_name">
|
||||
<ElInput v-model="form.carrier_name" placeholder="请输入运营商名称" />
|
||||
@@ -150,6 +159,7 @@
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
import CodeGeneratorButton from '@/components/business/CodeGeneratorButton.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import {
|
||||
@@ -441,6 +451,15 @@
|
||||
})
|
||||
}
|
||||
|
||||
// 处理编码生成
|
||||
const handleCodeGenerated = (code: string) => {
|
||||
form.carrier_code = code
|
||||
// 清除该字段的验证错误提示
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate('carrier_code')
|
||||
})
|
||||
}
|
||||
|
||||
// 删除运营商
|
||||
const deleteCarrier = (row: any) => {
|
||||
ElMessageBox.confirm(`确定删除运营商 ${row.carrier_name} 吗?`, '删除确认', {
|
||||
|
||||
@@ -151,6 +151,23 @@
|
||||
{{ formatDateTime(scope.row.created_at) }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="操作" width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.status === 99" style="display: flex; gap: 8px">
|
||||
<ArtButtonTable
|
||||
text="入账"
|
||||
iconColor="#67C23A"
|
||||
@click="handleResolveCommission(scope.row, 'release')"
|
||||
/>
|
||||
<ArtButtonTable
|
||||
text="作废"
|
||||
iconColor="#F56C6C"
|
||||
@click="handleResolveCommission(scope.row, 'invalidate')"
|
||||
/>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</ElTabPane>
|
||||
@@ -233,6 +250,69 @@
|
||||
</ElTabPane>
|
||||
</ElTabs>
|
||||
</ElDrawer>
|
||||
|
||||
<!-- 佣金修正对话框 -->
|
||||
<ElDialog
|
||||
v-model="resolveDialogVisible"
|
||||
:title="resolveAction === 'release' ? '佣金入账' : '佣金作废'"
|
||||
width="500px"
|
||||
>
|
||||
<ElAlert
|
||||
:title="
|
||||
resolveAction === 'release'
|
||||
? '确认将该笔待审佣金记录入账'
|
||||
: '确认将该笔待审佣金记录作废'
|
||||
"
|
||||
:type="resolveAction === 'release' ? 'success' : 'warning'"
|
||||
style="margin-bottom: 16px"
|
||||
:closable="false"
|
||||
/>
|
||||
|
||||
<ElForm
|
||||
ref="resolveFormRef"
|
||||
:model="resolveForm"
|
||||
:rules="resolveRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<ElFormItem v-if="resolveAction === 'release'" label="入账金额" prop="amount">
|
||||
<ElInputNumber
|
||||
v-model="resolveForm.amount"
|
||||
:min="0"
|
||||
:step="100"
|
||||
:precision="0"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
placeholder="请输入入账金额(分)"
|
||||
/>
|
||||
<div style="color: var(--el-text-color-secondary); font-size: 12px; margin-top: 4px">
|
||||
金额单位为分,例如:100元 = 10000分
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注" prop="remark">
|
||||
<ElInput
|
||||
v-model="resolveForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注(可选,最多500字符)"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="resolveDialogVisible = false">取消</ElButton>
|
||||
<ElButton
|
||||
:type="resolveAction === 'release' ? 'success' : 'warning'"
|
||||
@click="handleResolveSubmit"
|
||||
:loading="resolveSubmitLoading"
|
||||
>
|
||||
确认
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -240,11 +320,13 @@
|
||||
import { h, watch, onBeforeUnmount } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { CommissionService } from '@/api/modules'
|
||||
import { ElMessage, ElTag } from 'element-plus'
|
||||
import { ElMessage, ElMessageBox, ElTag } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
ShopCommissionSummaryItem,
|
||||
ShopCommissionRecordItem,
|
||||
WithdrawalRequestItem
|
||||
WithdrawalRequestItem,
|
||||
CommissionResolveAction
|
||||
} from '@/types/api/commission'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
@@ -321,6 +403,34 @@
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 佣金修正对话框状态
|
||||
const resolveDialogVisible = ref(false)
|
||||
const resolveFormRef = ref<FormInstance>()
|
||||
const resolveSubmitLoading = ref(false)
|
||||
const resolveAction = ref<CommissionResolveAction>('release')
|
||||
const currentCommissionId = ref<number>(0)
|
||||
const resolveForm = reactive({
|
||||
amount: undefined as number | undefined,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 佣金修正表单验证规则
|
||||
const resolveRules = computed<FormRules>(() => ({
|
||||
amount:
|
||||
resolveAction.value === 'release'
|
||||
? [
|
||||
{ required: true, message: '请输入入账金额', trigger: 'blur' },
|
||||
{
|
||||
type: 'number',
|
||||
min: 1,
|
||||
message: '入账金额必须大于0',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
: [],
|
||||
remark: [{ max: 500, message: '备注最多500字符', trigger: 'blur' }]
|
||||
}))
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '店铺编码', prop: 'shop_code' },
|
||||
@@ -624,6 +734,68 @@
|
||||
|
||||
// 暂无其他菜单项
|
||||
}
|
||||
|
||||
// 处理佣金修正
|
||||
const handleResolveCommission = (row: ShopCommissionRecordItem, action: CommissionResolveAction) => {
|
||||
currentCommissionId.value = row.id
|
||||
resolveAction.value = action
|
||||
resolveForm.amount = undefined
|
||||
resolveForm.remark = ''
|
||||
resolveDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 提交佣金修正
|
||||
const handleResolveSubmit = async () => {
|
||||
if (!resolveFormRef.value) return
|
||||
|
||||
await resolveFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const actionText = resolveAction.value === 'release' ? '入账' : '作废'
|
||||
const confirmText =
|
||||
resolveAction.value === 'release'
|
||||
? `确认将该笔佣金记录入账 ${formatMoney(resolveForm.amount || 0)} 吗?`
|
||||
: '确认将该笔佣金记录作废吗?'
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(confirmText, '确认操作', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
|
||||
resolveSubmitLoading.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
action: resolveAction.value
|
||||
}
|
||||
|
||||
if (resolveAction.value === 'release' && resolveForm.amount) {
|
||||
params.amount = resolveForm.amount
|
||||
}
|
||||
|
||||
if (resolveForm.remark) {
|
||||
params.remark = resolveForm.remark
|
||||
}
|
||||
|
||||
await CommissionService.resolveCommissionRecord(currentCommissionId.value, params)
|
||||
ElMessage.success(`${actionText}成功`)
|
||||
resolveDialogVisible.value = false
|
||||
resolveFormRef.value?.resetFields()
|
||||
|
||||
// 刷新佣金明细列表
|
||||
loadCommissionRecords()
|
||||
} catch (error: any) {
|
||||
console.error(error)
|
||||
ElMessage.error(error?.message || `${actionText}失败`)
|
||||
} finally {
|
||||
resolveSubmitLoading.value = false
|
||||
}
|
||||
} catch {
|
||||
// 用户取消
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -201,6 +201,9 @@
|
||||
const rejectRules = reactive<FormRules>({
|
||||
reject_reason: [
|
||||
{ required: true, message: t('commission.validation.rejectReasonRequired'), trigger: 'blur' }
|
||||
],
|
||||
remark: [
|
||||
{ required: true, message: t('commission.validation.remarkRequired'), trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
|
||||
@@ -402,7 +405,7 @@
|
||||
try {
|
||||
await CommissionService.rejectWithdrawal(currentWithdrawalId.value, {
|
||||
reject_reason: rejectForm.reject_reason,
|
||||
remark: rejectForm.remark || undefined
|
||||
remark: rejectForm.remark
|
||||
})
|
||||
ElMessage.success(t('commission.messages.rejectSuccess'))
|
||||
rejectDialogVisible.value = false
|
||||
|
||||
@@ -156,6 +156,28 @@
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="实名时间">暂未接入</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="信号强度">暂未接入</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="在线状态">
|
||||
<ElTag :type="getOnlineStatusType(cardInfo?.online_status)" size="small">
|
||||
{{ getOnlineStatusName(cardInfo?.online_status) }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="固件版本">{{
|
||||
cardInfo?.software_version || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="切卡模式">{{
|
||||
getSwitchModeName(cardInfo?.switch_mode)
|
||||
}}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="最后在线时间">{{
|
||||
formatDateTime(cardInfo?.last_online_time) || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="最后同步时间">{{
|
||||
formatDateTime(cardInfo?.last_gateway_sync_at) || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="制造商">{{
|
||||
cardInfo?.manufacturer || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<!--<ElDescriptionsItem label="制造商">{{-->
|
||||
<!-- cardInfo?.manufacturer || '--'-->
|
||||
<!--}}</ElDescriptionsItem>-->
|
||||
@@ -187,7 +209,16 @@
|
||||
>
|
||||
<ElTableColumn prop="iccid" label="ICCID" min-width="180" />
|
||||
<ElTableColumn prop="msisdn" label="MSISDN" min-width="120" />
|
||||
<ElTableColumn prop="slot_position" label="卡槽位置" width="100" align="center" />
|
||||
<ElTableColumn prop="slot_position" label="卡槽位置" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<div
|
||||
style="display: flex; align-items: center; justify-content: center; gap: 4px"
|
||||
>
|
||||
<span>{{ scope.row.slot_position }}</span>
|
||||
<ElTag v-if="scope.row.is_current" type="success" size="small">当前</ElTag>
|
||||
</div>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="网络状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElTag
|
||||
@@ -207,6 +238,163 @@
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
<ElEmpty v-else description="暂无绑定卡" :image-size="80" style="margin-top: 16px" />
|
||||
|
||||
<!-- 设备实时信息 -->
|
||||
<ElDivider content-position="left">设备实时信息</ElDivider>
|
||||
<div v-if="deviceRealtime" style="margin-top: 16px">
|
||||
<ElDescriptions :column="3" border size="small">
|
||||
<!-- 基本状态 -->
|
||||
<ElDescriptionsItem label="在线状态">
|
||||
<ElTag
|
||||
:type="deviceRealtime.online_status === 1 ? 'success' : 'danger'"
|
||||
size="small"
|
||||
>
|
||||
{{ deviceRealtime.online_status === 1 ? '在线' : '离线' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="设备状态">
|
||||
<ElTag :type="deviceRealtime.status === 1 ? 'success' : 'info'" size="small">
|
||||
{{ deviceRealtime.status === 1 ? '正常' : '禁用' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="电量">
|
||||
{{
|
||||
deviceRealtime.battery_level !== null &&
|
||||
deviceRealtime.battery_level !== undefined
|
||||
? `${deviceRealtime.battery_level}%`
|
||||
: '--'
|
||||
}}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- 时间信息 -->
|
||||
<ElDescriptionsItem label="本次开机时长">
|
||||
{{ formatDuration(deviceRealtime.run_time) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="本次联网时长">
|
||||
{{ formatDuration(deviceRealtime.connect_time) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="最后在线时间">
|
||||
{{ formatDateTime(deviceRealtime.last_online_time) || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- 信号信息 -->
|
||||
<ElDescriptionsItem label="信号强度(RSSI)">
|
||||
{{ deviceRealtime.rssi || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="接收功率(RSRP)">
|
||||
{{ deviceRealtime.rsrp ? `${deviceRealtime.rsrp} dBm` : '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="接收质量(RSRQ)">
|
||||
{{ deviceRealtime.rsrq ? `${deviceRealtime.rsrq} dB` : '--' }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="信噪比(SINR)">
|
||||
{{ deviceRealtime.sinr ? `${deviceRealtime.sinr} dB` : '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="最大客户端数">
|
||||
{{ deviceRealtime.max_clients || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="当前使用ICCID">
|
||||
<span
|
||||
v-if="deviceRealtime.current_iccid"
|
||||
style="
|
||||
color: var(--el-color-primary);
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
"
|
||||
@click="handleViewCardDetail(deviceRealtime.current_iccid)"
|
||||
>
|
||||
{{ deviceRealtime.current_iccid }}
|
||||
</span>
|
||||
<span v-else>--</span>
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- WiFi 信息 -->
|
||||
<ElDescriptionsItem label="WiFi 状态">
|
||||
<ElTag :type="deviceRealtime.wifi_enabled ? 'success' : 'info'" size="small">
|
||||
{{ deviceRealtime.wifi_enabled ? '已开启' : '已关闭' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="WiFi 名称">
|
||||
{{ deviceRealtime.ssid || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="WiFi 密码">
|
||||
{{ deviceRealtime.wifi_password || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- 网络信息 -->
|
||||
<ElDescriptionsItem label="IP 地址">
|
||||
{{ deviceRealtime.ip_address || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="WAN IP">
|
||||
{{ deviceRealtime.wan_ip || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="LAN IP">
|
||||
{{ deviceRealtime.lan_ip || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="MAC 地址">
|
||||
{{ deviceRealtime.mac_address || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="IMEI">
|
||||
{{ deviceRealtime.imei || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="IMSI">
|
||||
{{ deviceRealtime.imsi || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- 流量信息 -->
|
||||
<ElDescriptionsItem label="今日流量">
|
||||
{{ formatDataSize(Number(deviceRealtime.daily_usage || 0) / (1024 * 1024)) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="本次下载">
|
||||
{{ formatDataSize(Number(deviceRealtime.dl_stats || 0) / (1024 * 1024)) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="本次上传">
|
||||
{{ formatDataSize(Number(deviceRealtime.ul_stats || 0) / (1024 * 1024)) }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- 设备配置 -->
|
||||
<ElDescriptionsItem label="限速">
|
||||
{{
|
||||
deviceRealtime.limit_speed ? `${deviceRealtime.limit_speed} KB/s` : '不限速'
|
||||
}}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="固件版本">
|
||||
{{ deviceRealtime.software_version || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="切卡模式">
|
||||
{{
|
||||
deviceRealtime.switch_mode === '0'
|
||||
? '自动'
|
||||
: deviceRealtime.switch_mode === '1'
|
||||
? '手动'
|
||||
: '--'
|
||||
}}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="上报周期">
|
||||
{{ deviceRealtime.sync_interval ? `${deviceRealtime.sync_interval} 秒` : '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="设备ID">
|
||||
{{ deviceRealtime.device_id || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="信息更新时间">
|
||||
{{ formatDateTime(deviceRealtime.last_update_time) || '--' }}
|
||||
</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</div>
|
||||
<ElAlert
|
||||
v-else
|
||||
title="设备实时信息不可用"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
style="margin-top: 16px"
|
||||
>
|
||||
<template #default>
|
||||
<div>Gateway 不可达或设备离线,无法获取实时信息</div>
|
||||
</template>
|
||||
</ElAlert>
|
||||
</template>
|
||||
|
||||
<!-- IoT卡操作按钮 -->
|
||||
@@ -1154,6 +1342,9 @@
|
||||
// 卡片信息 - 默认为null,等待查询
|
||||
const cardInfo = ref<any>(null)
|
||||
|
||||
// 设备实时信息
|
||||
const deviceRealtime = ref<any>(null)
|
||||
|
||||
// 当前套餐错误信息
|
||||
const currentPackageErrorMsg = ref<string>('')
|
||||
|
||||
@@ -1237,6 +1428,11 @@
|
||||
bound_card_count: data.bound_card_count || 0,
|
||||
cards: data.cards || [],
|
||||
device_protect_status: data.device_protect_status,
|
||||
online_status: data.online_status,
|
||||
last_online_time: data.last_online_time,
|
||||
software_version: data.software_version,
|
||||
switch_mode: data.switch_mode,
|
||||
last_gateway_sync_at: data.last_gateway_sync_at,
|
||||
|
||||
// 流量/套餐信息
|
||||
current_package: data.current_package || '',
|
||||
@@ -1284,10 +1480,13 @@
|
||||
// 加载套餐列表
|
||||
const loadPackageList = async (assetType: string, assetId: number) => {
|
||||
try {
|
||||
const response = await AssetService.getAssetPackages(assetType, assetId)
|
||||
const response = await AssetService.getAssetPackages(assetType, assetId, {
|
||||
page: 1,
|
||||
page_size: 50
|
||||
})
|
||||
if (response.code === 0 && response.data) {
|
||||
// 直接使用API返回的数据结构
|
||||
cardInfo.value.packageList = response.data
|
||||
// 使用分页响应中的 items 数组
|
||||
cardInfo.value.packageList = response.data.items || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取套餐列表失败:', error)
|
||||
@@ -1301,38 +1500,43 @@
|
||||
currentPackageErrorMsg.value = ''
|
||||
|
||||
const response = await AssetService.getCurrentPackage(assetType, assetId)
|
||||
if (response.code === 0 && response.data) {
|
||||
const pkg = response.data
|
||||
// 保存完整的当前套餐数据
|
||||
cardInfo.value.currentPackageDetail = {
|
||||
package_usage_id: pkg.package_usage_id,
|
||||
package_id: pkg.package_id,
|
||||
package_name: pkg.package_name,
|
||||
package_type: pkg.package_type,
|
||||
status: pkg.status,
|
||||
status_name: pkg.status_name,
|
||||
data_limit_mb: pkg.data_limit_mb,
|
||||
data_usage_mb: pkg.data_usage_mb,
|
||||
virtual_limit_mb: pkg.virtual_limit_mb,
|
||||
virtual_used_mb: pkg.virtual_used_mb,
|
||||
virtual_remain_mb: pkg.virtual_remain_mb,
|
||||
virtual_ratio: pkg.virtual_ratio,
|
||||
activated_at: pkg.activated_at,
|
||||
expires_at: pkg.expires_at,
|
||||
created_at: pkg.created_at,
|
||||
master_usage_id: pkg.master_usage_id,
|
||||
priority: pkg.priority,
|
||||
usage_type: pkg.usage_type
|
||||
if (response.code === 0) {
|
||||
if (response.data) {
|
||||
const pkg = response.data
|
||||
// 保存完整的当前套餐数据
|
||||
cardInfo.value.currentPackageDetail = {
|
||||
package_usage_id: pkg.package_usage_id,
|
||||
package_id: pkg.package_id,
|
||||
package_name: pkg.package_name,
|
||||
package_type: pkg.package_type,
|
||||
status: pkg.status,
|
||||
status_name: pkg.status_name,
|
||||
data_limit_mb: pkg.data_limit_mb,
|
||||
data_usage_mb: pkg.data_usage_mb,
|
||||
virtual_limit_mb: pkg.virtual_limit_mb,
|
||||
virtual_used_mb: pkg.virtual_used_mb,
|
||||
virtual_remain_mb: pkg.virtual_remain_mb,
|
||||
virtual_ratio: pkg.virtual_ratio,
|
||||
activated_at: pkg.activated_at,
|
||||
expires_at: pkg.expires_at,
|
||||
created_at: pkg.created_at,
|
||||
master_usage_id: pkg.master_usage_id,
|
||||
priority: pkg.priority,
|
||||
usage_type: pkg.usage_type
|
||||
}
|
||||
// 同时更新流量显示信息
|
||||
cardInfo.value.current_package = pkg.package_name
|
||||
cardInfo.value.packageTotalFlow = formatDataSize(pkg.virtual_limit_mb)
|
||||
cardInfo.value.usedFlow = formatDataSize(pkg.virtual_used_mb)
|
||||
cardInfo.value.remainFlow = formatDataSize(pkg.virtual_remain_mb)
|
||||
cardInfo.value.usedFlowPercentage =
|
||||
pkg.virtual_limit_mb > 0
|
||||
? `${((pkg.virtual_used_mb / pkg.virtual_limit_mb) * 100).toFixed(2)}%`
|
||||
: '0.00%'
|
||||
} else {
|
||||
// code 为 0 但 data 为空,表示暂无当前生效套餐(正常情况)
|
||||
currentPackageErrorMsg.value = '暂无当前生效套餐'
|
||||
}
|
||||
// 同时更新流量显示信息
|
||||
cardInfo.value.current_package = pkg.package_name
|
||||
cardInfo.value.packageTotalFlow = formatDataSize(pkg.virtual_limit_mb)
|
||||
cardInfo.value.usedFlow = formatDataSize(pkg.virtual_used_mb)
|
||||
cardInfo.value.remainFlow = formatDataSize(pkg.virtual_remain_mb)
|
||||
cardInfo.value.usedFlowPercentage =
|
||||
pkg.virtual_limit_mb > 0
|
||||
? `${((pkg.virtual_used_mb / pkg.virtual_limit_mb) * 100).toFixed(2)}%`
|
||||
: '0.00%'
|
||||
} else {
|
||||
// 接口返回 code 不为 0,保存错误信息
|
||||
currentPackageErrorMsg.value = response.msg || '获取当前套餐失败'
|
||||
@@ -1377,6 +1581,26 @@
|
||||
if (data.cards && data.cards.length > 0) {
|
||||
cardInfo.value.cards = data.cards
|
||||
}
|
||||
if (data.online_status !== undefined) {
|
||||
cardInfo.value.online_status = data.online_status
|
||||
}
|
||||
if (data.last_online_time !== undefined) {
|
||||
cardInfo.value.last_online_time = data.last_online_time
|
||||
}
|
||||
if (data.software_version !== undefined) {
|
||||
cardInfo.value.software_version = data.software_version
|
||||
}
|
||||
if (data.switch_mode !== undefined) {
|
||||
cardInfo.value.switch_mode = data.switch_mode
|
||||
}
|
||||
if (data.last_gateway_sync_at !== undefined) {
|
||||
cardInfo.value.last_gateway_sync_at = data.last_gateway_sync_at
|
||||
}
|
||||
// 设备实时信息(Gateway 数据)
|
||||
if (data.device_realtime !== undefined) {
|
||||
deviceRealtime.value = data.device_realtime
|
||||
console.log('设备实时信息:', deviceRealtime.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -1455,8 +1679,7 @@
|
||||
const getRealNameStatusName = (status: number) => {
|
||||
const statusMap: Record<number, string> = {
|
||||
0: '未实名',
|
||||
1: '实名中',
|
||||
2: '已实名'
|
||||
1: '已实名'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
@@ -1465,8 +1688,7 @@
|
||||
const getRealNameStatusType = (status: number) => {
|
||||
const map: Record<number, any> = {
|
||||
0: 'info',
|
||||
1: 'warning',
|
||||
2: 'success'
|
||||
1: 'success'
|
||||
}
|
||||
return map[status] || 'info'
|
||||
}
|
||||
@@ -1503,6 +1725,65 @@
|
||||
return map[status || 'none'] || 'info'
|
||||
}
|
||||
|
||||
// 获取在线状态标签类型
|
||||
const getOnlineStatusType = (status?: number) => {
|
||||
const map: Record<number, any> = {
|
||||
0: 'info', // 未知
|
||||
1: 'success', // 在线
|
||||
2: 'danger' // 离线
|
||||
}
|
||||
return map[status ?? 0] || 'info'
|
||||
}
|
||||
|
||||
// 获取在线状态名称
|
||||
const getOnlineStatusName = (status?: number) => {
|
||||
const map: Record<number, string> = {
|
||||
0: '未知',
|
||||
1: '在线',
|
||||
2: '离线'
|
||||
}
|
||||
return map[status ?? 0] || '未知'
|
||||
}
|
||||
|
||||
// 获取切卡模式名称
|
||||
const getSwitchModeName = (mode?: string) => {
|
||||
const map: Record<string, string> = {
|
||||
'0': '自动',
|
||||
'1': '手动'
|
||||
}
|
||||
return map[mode || ''] || '--'
|
||||
}
|
||||
|
||||
// 格式化时长(秒转为时分秒)
|
||||
const formatDuration = (seconds?: string) => {
|
||||
if (!seconds) return '--'
|
||||
const sec = Number(seconds)
|
||||
if (isNaN(sec)) return '--'
|
||||
|
||||
const hours = Math.floor(sec / 3600)
|
||||
const minutes = Math.floor((sec % 3600) / 60)
|
||||
const secs = sec % 60
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}小时${minutes}分${secs}秒`
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}分${secs}秒`
|
||||
} else {
|
||||
return `${secs}秒`
|
||||
}
|
||||
}
|
||||
|
||||
// 点击ICCID查看卡详情
|
||||
const handleViewCardDetail = (iccid: string) => {
|
||||
if (!iccid) return
|
||||
// 在新标签页打开卡详情
|
||||
const route = router.resolve({
|
||||
path: '/asset-management/single-card',
|
||||
query: { iccid }
|
||||
})
|
||||
window.open(route.href, '_blank')
|
||||
}
|
||||
|
||||
// 获取保护期状态名称
|
||||
const getProtectStatusName = (status?: string) => {
|
||||
const map: Record<string, string> = {
|
||||
|
||||
@@ -100,9 +100,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '启用实名激活',
|
||||
label: '到期计时基准',
|
||||
formatter: (_, data) => {
|
||||
return data.enable_realname_activation ? '是' : '否'
|
||||
if (!data.expiry_base) return '--'
|
||||
return data.expiry_base === 'from_activation' ? '实名后开始计时' : '购买即开始计时'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -108,6 +108,11 @@
|
||||
:label="series.series_name"
|
||||
:value="series.id"
|
||||
/>
|
||||
<template #empty>
|
||||
<div style="padding: 10px; text-align: center; color: #909399">
|
||||
暂无套餐系列,请先创建套餐系列
|
||||
</div>
|
||||
</template>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
@@ -131,6 +136,38 @@
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="有效期(月)" prop="duration_months">
|
||||
<ElInputNumber
|
||||
v-model="form.duration_months"
|
||||
:min="1"
|
||||
:max="120"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入有效期(月)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 流量重置周期和套餐周期类型 -->
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="流量重置周期" prop="data_reset_cycle">
|
||||
<ElSelect
|
||||
v-model="form.data_reset_cycle"
|
||||
placeholder="请选择流量重置周期"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="每日" value="daily" />
|
||||
<ElOption label="每月" value="monthly" />
|
||||
<ElOption label="每年" value="yearly" />
|
||||
<ElOption label="不重置" value="none" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<!-- 只有流量重置周期为每月时才显示套餐周期类型 -->
|
||||
<ElCol :span="12" v-if="form.data_reset_cycle === 'monthly'">
|
||||
<ElFormItem label="套餐周期类型" prop="calendar_type">
|
||||
<ElSelect
|
||||
v-model="form.calendar_type"
|
||||
@@ -145,78 +182,24 @@
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20">
|
||||
<!-- 流量重置天数(calendar_type为by_day时显示) -->
|
||||
<ElRow :gutter="20" v-if="form.calendar_type === 'by_day'">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="有效期(月)" prop="duration_months">
|
||||
<ElInputNumber
|
||||
v-model="form.duration_months"
|
||||
:min="1"
|
||||
:max="120"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入有效期(月)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12" v-if="form.calendar_type === 'by_day'">
|
||||
<ElFormItem label="套餐天数" prop="duration_days">
|
||||
<ElFormItem label="流量重置天数" prop="duration_days">
|
||||
<ElInputNumber
|
||||
v-model="form.duration_days"
|
||||
:min="1"
|
||||
:max="3650"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入套餐天数"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12" v-if="form.calendar_type !== 'by_day'">
|
||||
<ElFormItem label="流量重置周期" prop="data_reset_cycle">
|
||||
<ElSelect
|
||||
v-model="form.data_reset_cycle"
|
||||
placeholder="请选择流量重置周期"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="每日" value="daily" />
|
||||
<ElOption label="每月" value="monthly" />
|
||||
<ElOption label="每年" value="yearly" />
|
||||
<ElOption label="不重置" value="none" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.calendar_type === 'by_day'">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="流量重置周期" prop="data_reset_cycle">
|
||||
<ElSelect
|
||||
v-model="form.data_reset_cycle"
|
||||
placeholder="请选择流量重置周期"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="每日" value="daily" />
|
||||
<ElOption label="每月" value="monthly" />
|
||||
<ElOption label="每年" value="yearly" />
|
||||
<ElOption label="不重置" value="none" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="真流量额度(MB)" prop="real_data_mb">
|
||||
<ElInputNumber
|
||||
v-model="form.real_data_mb"
|
||||
:min="0"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入真流量额度"
|
||||
placeholder="请输入流量重置天数"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.calendar_type !== 'by_day'">
|
||||
<!-- 真流量额度 -->
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="真流量额度(MB)" prop="real_data_mb">
|
||||
<ElInputNumber
|
||||
@@ -239,16 +222,8 @@
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.calendar_type === 'by_day'">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="启用虚流量">
|
||||
<ElSwitch
|
||||
v-model="form.enable_virtual_data"
|
||||
active-text="启用"
|
||||
inactive-text="不启用"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<!-- 虚流量额度和到期计时基准 -->
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12" v-if="form.enable_virtual_data">
|
||||
<ElFormItem label="虚流量额度(MB)" prop="virtual_data_mb">
|
||||
<ElInputNumber
|
||||
@@ -260,97 +235,23 @@
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12" v-if="!form.enable_virtual_data">
|
||||
<ElFormItem label="启用实名激活">
|
||||
<ElSwitch
|
||||
v-model="form.enable_realname_activation"
|
||||
active-text="启用"
|
||||
inactive-text="不启用"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.calendar_type !== 'by_day' && form.enable_virtual_data">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="虚流量额度(MB)" prop="virtual_data_mb">
|
||||
<ElInputNumber
|
||||
v-model="form.virtual_data_mb"
|
||||
:min="0"
|
||||
:controls="false"
|
||||
<ElFormItem label="到期计时基准" prop="expiry_base">
|
||||
<ElSelect
|
||||
v-model="form.expiry_base"
|
||||
placeholder="请选择到期计时基准"
|
||||
style="width: 100%"
|
||||
placeholder="请输入虚流量额度"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="启用实名激活">
|
||||
<ElSwitch
|
||||
v-model="form.enable_realname_activation"
|
||||
active-text="启用"
|
||||
inactive-text="不启用"
|
||||
/>
|
||||
clearable
|
||||
>
|
||||
<ElOption label="实名后开始计时" value="from_activation" />
|
||||
<ElOption label="购买即开始计时" value="from_purchase" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.calendar_type !== 'by_day' && !form.enable_virtual_data">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="启用实名激活">
|
||||
<ElSwitch
|
||||
v-model="form.enable_realname_activation"
|
||||
active-text="启用"
|
||||
inactive-text="不启用"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="成本价(元)" prop="cost_price">
|
||||
<ElInputNumber
|
||||
v-model="form.cost_price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入成本价"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.calendar_type === 'by_day' && form.enable_virtual_data">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="启用实名激活">
|
||||
<ElSwitch
|
||||
v-model="form.enable_realname_activation"
|
||||
active-text="启用"
|
||||
inactive-text="不启用"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="成本价(元)" prop="cost_price">
|
||||
<ElInputNumber
|
||||
v-model="form.cost_price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入成本价"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow
|
||||
:gutter="20"
|
||||
v-if="
|
||||
(form.calendar_type !== 'by_day' && form.enable_virtual_data) ||
|
||||
(form.calendar_type === 'by_day' && !form.enable_virtual_data)
|
||||
"
|
||||
>
|
||||
<!-- 成本价和建议零售价 -->
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="成本价(元)" prop="cost_price">
|
||||
<ElInputNumber
|
||||
@@ -365,7 +266,7 @@
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="建议售价(元)" prop="suggested_retail_price">
|
||||
<ElFormItem label="建议零售价(元)" prop="suggested_retail_price">
|
||||
<ElInputNumber
|
||||
v-model="form.suggested_retail_price"
|
||||
:min="0"
|
||||
@@ -373,23 +274,7 @@
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入建议售价(可选)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.calendar_type === 'by_day' && form.enable_virtual_data">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="建议售价(元)" prop="suggested_retail_price">
|
||||
<ElInputNumber
|
||||
v-model="form.suggested_retail_price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入建议售价(可选)"
|
||||
placeholder="请输入建议零售价"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
@@ -690,7 +575,7 @@
|
||||
duration_months: 1,
|
||||
data_reset_cycle: undefined,
|
||||
enable_virtual_data: false,
|
||||
enable_realname_activation: false,
|
||||
expiry_base: 'from_activation',
|
||||
real_data_mb: 0,
|
||||
virtual_data_mb: 0,
|
||||
cost_price: 0,
|
||||
@@ -870,6 +755,27 @@
|
||||
}
|
||||
)
|
||||
|
||||
// 监听流量重置周期变化,不是每月时清空套餐周期类型
|
||||
watch(
|
||||
() => form.data_reset_cycle,
|
||||
(cycle) => {
|
||||
if (cycle !== 'monthly') {
|
||||
form.calendar_type = undefined
|
||||
form.duration_days = undefined
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 监听套餐周期类型变化,不是按天时清空套餐天数
|
||||
watch(
|
||||
() => form.calendar_type,
|
||||
(type) => {
|
||||
if (type !== 'by_day') {
|
||||
form.duration_days = undefined
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadSeriesOptions()
|
||||
loadSearchSeriesOptions()
|
||||
@@ -1008,7 +914,7 @@
|
||||
form.duration_months = row.duration_months
|
||||
form.data_reset_cycle = row.data_reset_cycle || undefined
|
||||
form.enable_virtual_data = row.enable_virtual_data || false
|
||||
form.enable_realname_activation = row.enable_realname_activation || false
|
||||
form.expiry_base = row.expiry_base || 'from_activation'
|
||||
form.real_data_mb = row.real_data_mb || 0
|
||||
form.virtual_data_mb = row.virtual_data_mb || 0
|
||||
form.cost_price = row.cost_price / 100 // 分转换为元显示
|
||||
@@ -1027,7 +933,7 @@
|
||||
form.duration_months = 1
|
||||
form.data_reset_cycle = undefined
|
||||
form.enable_virtual_data = false
|
||||
form.enable_realname_activation = false
|
||||
form.expiry_base = 'from_activation'
|
||||
form.real_data_mb = 0
|
||||
form.virtual_data_mb = 0
|
||||
form.cost_price = 0
|
||||
@@ -1066,7 +972,7 @@
|
||||
form.duration_months = 1
|
||||
form.data_reset_cycle = undefined
|
||||
form.enable_virtual_data = false
|
||||
form.enable_realname_activation = false
|
||||
form.expiry_base = 'from_activation'
|
||||
form.real_data_mb = 0
|
||||
form.virtual_data_mb = 0
|
||||
form.cost_price = 0
|
||||
@@ -1116,22 +1022,23 @@
|
||||
duration_months: form.duration_months,
|
||||
cost_price: costPriceInCents,
|
||||
enable_virtual_data: form.enable_virtual_data || false,
|
||||
enable_realname_activation: form.enable_realname_activation || false
|
||||
expiry_base: form.expiry_base || 'from_activation'
|
||||
}
|
||||
|
||||
// 可选字段
|
||||
if (form.series_id) {
|
||||
data.series_id = form.series_id
|
||||
}
|
||||
if (form.calendar_type) {
|
||||
if (form.data_reset_cycle) {
|
||||
data.data_reset_cycle = form.data_reset_cycle
|
||||
}
|
||||
// 只有流量重置周期为 monthly 时,才传递 calendar_type
|
||||
if (form.data_reset_cycle === 'monthly' && form.calendar_type) {
|
||||
data.calendar_type = form.calendar_type
|
||||
}
|
||||
if (form.calendar_type === 'by_day' && form.duration_days) {
|
||||
data.duration_days = form.duration_days
|
||||
}
|
||||
if (form.data_reset_cycle) {
|
||||
data.data_reset_cycle = form.data_reset_cycle
|
||||
}
|
||||
if (suggestedRetailPriceInCents !== undefined) {
|
||||
data.suggested_retail_price = suggestedRetailPriceInCents
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user