This commit is contained in:
@@ -33,7 +33,9 @@
|
||||
|
||||
<!-- 操作按钮组 -->
|
||||
<div v-if="hasCardInfo" class="operation-button-group">
|
||||
<ElButton @click="handleRefresh" type="primary" :icon="Refresh" :disabled="refreshDisabled"> 刷新 </ElButton>
|
||||
<ElButton @click="handleRefresh" type="primary" :icon="Refresh" :disabled="refreshDisabled">
|
||||
刷新
|
||||
</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
|
||||
@@ -166,7 +166,10 @@
|
||||
<div class="flow-progress-bar" style="margin-top: 16px">
|
||||
<ElProgress
|
||||
:percentage="
|
||||
getUsageProgress(getDisplayedUsedMb(currentPackage), getDisplayedTotalMb(currentPackage))
|
||||
getUsageProgress(
|
||||
getDisplayedUsedMb(currentPackage),
|
||||
getDisplayedTotalMb(currentPackage)
|
||||
)
|
||||
"
|
||||
:color="
|
||||
getProgressColorByPercentage(
|
||||
|
||||
@@ -145,23 +145,13 @@
|
||||
<template v-else>
|
||||
<div class="progress-text">
|
||||
<span class="used"
|
||||
>已使用:
|
||||
{{
|
||||
formatDataSize(
|
||||
getDisplayedUsedMb(scope.row)
|
||||
)
|
||||
}}</span
|
||||
>已使用: {{ formatDataSize(getDisplayedUsedMb(scope.row)) }}</span
|
||||
>
|
||||
<span class="total"
|
||||
>总量: {{ formatDataSize(scope.row.real_total_mb || 0) }}</span
|
||||
>
|
||||
<span class="remaining"
|
||||
>剩余:
|
||||
{{
|
||||
formatDataSize(
|
||||
getDisplayedRemainingMb(scope.row)
|
||||
)
|
||||
}}</span
|
||||
>剩余: {{ formatDataSize(getDisplayedRemainingMb(scope.row)) }}</span
|
||||
>
|
||||
</div>
|
||||
<ElProgress
|
||||
|
||||
@@ -390,7 +390,6 @@
|
||||
color: var(--el-text-color-primary, #374151);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
|
||||
@@ -146,9 +146,7 @@
|
||||
set: (value) => emit('update:modelValue', value)
|
||||
})
|
||||
|
||||
const currentModeValue = computed<0 | 1>(() =>
|
||||
Number(props.currentMode) === 1 ? 1 : 0
|
||||
)
|
||||
const currentModeValue = computed<0 | 1>(() => (Number(props.currentMode) === 1 ? 1 : 0))
|
||||
|
||||
const availableCards = computed(() => props.cards || [])
|
||||
|
||||
@@ -157,7 +155,9 @@
|
||||
const syncFormState = () => {
|
||||
form.switch_mode = currentModeValue.value
|
||||
|
||||
const selectedStillExists = availableCards.value.some((card) => card.iot_card_id === form.iot_card_id)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
<ElButton
|
||||
type="info"
|
||||
@click="handleBatchSetSeries"
|
||||
:disabled="!selectedDevices.length"
|
||||
v-permission="'device:batch_set_series'"
|
||||
>
|
||||
批量设置套餐系列
|
||||
@@ -200,6 +199,7 @@
|
||||
v-model="seriesBindingDialogVisible"
|
||||
title="批量设置设备套餐系列绑定"
|
||||
width="600px"
|
||||
@close="handleCloseSeriesBindingDialog"
|
||||
>
|
||||
<ElForm
|
||||
ref="seriesBindingFormRef"
|
||||
@@ -210,7 +210,167 @@
|
||||
<ElFormItem label="已选设备数">
|
||||
<span style="font-weight: bold; color: #409eff">{{ selectedDevices.length }}</span> 台
|
||||
</ElFormItem>
|
||||
<ElFormItem label="套餐系列" prop="series_id">
|
||||
<ElFormItem label="选设备方式" prop="selection_type">
|
||||
<ElRadioGroup v-model="seriesBindingForm.selection_type">
|
||||
<ElRadio label="list">设备ID列表</ElRadio>
|
||||
<ElRadio label="range">设备号范围</ElRadio>
|
||||
<ElRadio label="filter">筛选条件</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.LIST"
|
||||
label="设备列表"
|
||||
>
|
||||
<div>已选择 {{ selectedDevices.length }} 台设备</div>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.RANGE"
|
||||
label="起始设备号"
|
||||
prop="virtual_no_start"
|
||||
>
|
||||
<ElInput
|
||||
v-model="seriesBindingForm.virtual_no_start"
|
||||
placeholder="请输入起始设备号"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.RANGE"
|
||||
label="结束设备号"
|
||||
prop="virtual_no_end"
|
||||
>
|
||||
<ElInput v-model="seriesBindingForm.virtual_no_end" placeholder="请输入结束设备号" />
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="设备号"
|
||||
>
|
||||
<ElInput
|
||||
v-model="seriesBindingForm.virtual_no"
|
||||
placeholder="请输入设备号"
|
||||
clearable
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="设备名称"
|
||||
>
|
||||
<ElInput
|
||||
v-model="seriesBindingForm.device_name"
|
||||
placeholder="请输入设备名称"
|
||||
clearable
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="设备类型"
|
||||
>
|
||||
<ElInput
|
||||
v-model="seriesBindingForm.device_type"
|
||||
placeholder="请输入设备类型"
|
||||
clearable
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="制造商"
|
||||
>
|
||||
<ElInput
|
||||
v-model="seriesBindingForm.manufacturer"
|
||||
placeholder="请输入制造商"
|
||||
clearable
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="状态"
|
||||
>
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.status"
|
||||
placeholder="请选择状态"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="在库" :value="1" />
|
||||
<ElOption label="已分销" :value="2" />
|
||||
<ElOption label="已激活" :value="3" />
|
||||
<ElOption label="已停用" :value="4" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="批次号"
|
||||
>
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.batch_no"
|
||||
placeholder="请选择或搜索批次号"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleSearchBatchNo"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption
|
||||
v-for="item in searchBatchNoOptions"
|
||||
:key="item.id"
|
||||
:label="item.batch_no"
|
||||
:value="item.batch_no"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="店铺名称"
|
||||
>
|
||||
<ElCascader
|
||||
v-model="seriesBindingForm.shop_id_path"
|
||||
:options="seriesBindingShopCascadeOptions"
|
||||
:props="seriesBindingShopCascadeProps"
|
||||
placeholder="请选择店铺名称"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="当前套餐系列"
|
||||
>
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.filter_series_id"
|
||||
placeholder="请选择或搜索当前套餐系列"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="searchSeries"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption
|
||||
v-for="series in searchSeriesOptions"
|
||||
:key="series.id"
|
||||
:label="series.series_name"
|
||||
:value="series.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === DeviceSelectionType.FILTER"
|
||||
label="创建设备时间"
|
||||
>
|
||||
<ElDatePicker
|
||||
v-model="seriesBindingForm.created_at_range"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="目标套餐系列" prop="series_id">
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.series_id"
|
||||
placeholder="请选择或搜索套餐系列"
|
||||
@@ -517,6 +677,7 @@
|
||||
AssetService,
|
||||
CarrierService
|
||||
} from '@/api/modules'
|
||||
import { DeviceSelectionType } from '@/types/api'
|
||||
import { ElMessage, ElMessageBox, ElTag, ElIcon, ElRadioGroup, ElRadio } from 'element-plus'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
@@ -527,6 +688,7 @@
|
||||
DeviceStatus,
|
||||
AllocateDevicesResponse,
|
||||
RecallDevicesResponse,
|
||||
BatchSetDeviceSeriesBindingRequest,
|
||||
BatchSetDeviceSeriesBindingResponse
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
@@ -593,6 +755,38 @@
|
||||
label: 'label',
|
||||
children: 'children'
|
||||
}
|
||||
const seriesBindingShopCascadeOptions = ref<any[]>([])
|
||||
const seriesBindingShopCascadeProps = {
|
||||
lazy: true,
|
||||
checkStrictly: true,
|
||||
lazyLoad: async (node: any, resolve: any) => {
|
||||
const { level, value } = node
|
||||
const parentId = level === 0 ? undefined : value
|
||||
|
||||
try {
|
||||
const res = await ShopService.getShopsCascade({
|
||||
parent_id: parentId,
|
||||
exclude_self: true
|
||||
})
|
||||
if (res.code === 0) {
|
||||
const nodes = (res.data || []).map((item: any) => ({
|
||||
value: item.id,
|
||||
label: item.shop_name,
|
||||
leaf: !item.has_children
|
||||
}))
|
||||
resolve(nodes)
|
||||
} else {
|
||||
resolve([])
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载批量设置套餐系列店铺级联数据失败:', error)
|
||||
resolve([])
|
||||
}
|
||||
},
|
||||
value: 'value',
|
||||
label: 'label',
|
||||
children: 'children'
|
||||
}
|
||||
const allocateResult = ref<AllocateDevicesResponse | null>(null)
|
||||
const recallResult = ref<RecallDevicesResponse | null>(null)
|
||||
|
||||
@@ -602,11 +796,53 @@
|
||||
const seriesBindingFormRef = ref<FormInstance>()
|
||||
const seriesLoading = ref(false)
|
||||
const packageSeriesList = ref<PackageSeriesResponse[]>([])
|
||||
const seriesBindingForm = reactive({
|
||||
series_id: undefined as number | undefined
|
||||
const createInitialSeriesBindingState = () => ({
|
||||
selection_type: DeviceSelectionType.LIST,
|
||||
series_id: undefined as number | undefined,
|
||||
virtual_no_start: '',
|
||||
virtual_no_end: '',
|
||||
virtual_no: '',
|
||||
device_name: '',
|
||||
device_type: '',
|
||||
manufacturer: '',
|
||||
batch_no: '',
|
||||
status: undefined as DeviceStatus | undefined,
|
||||
shop_id_path: undefined as number[] | undefined,
|
||||
filter_series_id: undefined as number | undefined,
|
||||
created_at_range: [] as string[],
|
||||
created_at_start: '',
|
||||
created_at_end: ''
|
||||
})
|
||||
const seriesBindingForm = reactive(createInitialSeriesBindingState())
|
||||
const seriesBindingRules = reactive<FormRules>({
|
||||
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }]
|
||||
selection_type: [{ required: true, message: '请选择选设备方式', trigger: 'change' }],
|
||||
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }],
|
||||
virtual_no_start: [
|
||||
{
|
||||
required: true,
|
||||
validator: (_rule, value, callback) => {
|
||||
if (seriesBindingForm.selection_type === DeviceSelectionType.RANGE && !value) {
|
||||
callback(new Error('请输入起始设备号'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
virtual_no_end: [
|
||||
{
|
||||
required: true,
|
||||
validator: (_rule, value, callback) => {
|
||||
if (seriesBindingForm.selection_type === DeviceSelectionType.RANGE && !value) {
|
||||
callback(new Error('请输入结束设备号'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
const seriesBindingResult = ref<BatchSetDeviceSeriesBindingResponse | null>(null)
|
||||
|
||||
@@ -1427,6 +1663,7 @@
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await DeviceService.batchSetDeviceSeriesBinding({
|
||||
selection_type: DeviceSelectionType.LIST,
|
||||
device_ids: [device.id],
|
||||
series_id: 0
|
||||
})
|
||||
@@ -1558,14 +1795,18 @@
|
||||
|
||||
// 批量设置套餐系列
|
||||
const handleBatchSetSeries = async () => {
|
||||
if (selectedDevices.value.length === 0) {
|
||||
ElMessage.warning('请先选择要设置的设备')
|
||||
return
|
||||
}
|
||||
seriesBindingForm.series_id = undefined
|
||||
seriesBindingResult.value = null
|
||||
await loadPackageSeriesList()
|
||||
Object.assign(seriesBindingForm, createInitialSeriesBindingState(), {
|
||||
selection_type:
|
||||
selectedDevices.value.length > 0 ? DeviceSelectionType.LIST : DeviceSelectionType.FILTER
|
||||
})
|
||||
await Promise.all([
|
||||
loadPackageSeriesList(),
|
||||
loadSearchBatchNoOptions(),
|
||||
loadSeriesBindingShopCascadeOptions()
|
||||
])
|
||||
seriesBindingDialogVisible.value = true
|
||||
seriesBindingFormRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
// 加载套餐系列列表(支持名称搜索,默认20条)
|
||||
@@ -1596,6 +1837,66 @@
|
||||
await loadPackageSeriesList(query || undefined)
|
||||
}
|
||||
|
||||
const loadSeriesBindingShopCascadeOptions = async () => {
|
||||
try {
|
||||
const res = await ShopService.getShopsCascade({
|
||||
parent_id: undefined,
|
||||
exclude_self: true
|
||||
})
|
||||
if (res.code === 0) {
|
||||
seriesBindingShopCascadeOptions.value = (res.data || []).map((item: any) => ({
|
||||
value: item.id,
|
||||
label: item.shop_name,
|
||||
leaf: !item.has_children
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载批量设置套餐系列根级店铺失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const buildSeriesBindingRequest = (): BatchSetDeviceSeriesBindingRequest | null => {
|
||||
const request: BatchSetDeviceSeriesBindingRequest = {
|
||||
selection_type: seriesBindingForm.selection_type,
|
||||
series_id: seriesBindingForm.series_id!
|
||||
}
|
||||
|
||||
if (seriesBindingForm.selection_type === DeviceSelectionType.LIST) {
|
||||
const deviceIds = selectedDevices.value.map((device) => device.id)
|
||||
if (deviceIds.length === 0) {
|
||||
ElMessage.warning('列表模式下请先选择要设置的设备')
|
||||
return null
|
||||
}
|
||||
request.device_ids = deviceIds
|
||||
return request
|
||||
}
|
||||
|
||||
if (seriesBindingForm.selection_type === DeviceSelectionType.RANGE) {
|
||||
request.virtual_no_start = seriesBindingForm.virtual_no_start
|
||||
request.virtual_no_end = seriesBindingForm.virtual_no_end
|
||||
return request
|
||||
}
|
||||
|
||||
if (seriesBindingForm.virtual_no) request.virtual_no = seriesBindingForm.virtual_no
|
||||
if (seriesBindingForm.device_name) request.device_name = seriesBindingForm.device_name
|
||||
if (seriesBindingForm.device_type) request.device_type = seriesBindingForm.device_type
|
||||
if (seriesBindingForm.manufacturer) request.manufacturer = seriesBindingForm.manufacturer
|
||||
if (seriesBindingForm.batch_no) request.batch_no = seriesBindingForm.batch_no
|
||||
if (seriesBindingForm.status !== undefined) request.status = seriesBindingForm.status
|
||||
if (seriesBindingForm.shop_id_path?.length) {
|
||||
request.shop_id = seriesBindingForm.shop_id_path[seriesBindingForm.shop_id_path.length - 1]
|
||||
}
|
||||
if (seriesBindingForm.filter_series_id !== undefined) {
|
||||
request.filter_series_id = seriesBindingForm.filter_series_id
|
||||
}
|
||||
if (seriesBindingForm.created_at_range.length === 2) {
|
||||
request.created_at_start = seriesBindingForm.created_at_range[0]
|
||||
request.created_at_end = seriesBindingForm.created_at_range[1]
|
||||
}
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
// 确认设置套餐系列绑定
|
||||
const handleConfirmSeriesBinding = async () => {
|
||||
if (!seriesBindingFormRef.value) return
|
||||
@@ -1604,9 +1905,9 @@
|
||||
if (valid) {
|
||||
seriesBindingLoading.value = true
|
||||
try {
|
||||
const data = {
|
||||
device_ids: selectedDevices.value.map((d) => d.id),
|
||||
series_id: seriesBindingForm.series_id!
|
||||
const data = buildSeriesBindingRequest()
|
||||
if (!data) {
|
||||
return
|
||||
}
|
||||
const res = await DeviceService.batchSetDeviceSeriesBinding(data)
|
||||
if (res.code === 0) {
|
||||
@@ -1634,6 +1935,7 @@
|
||||
const handleCloseSeriesBindingDialog = () => {
|
||||
seriesBindingDialogVisible.value = false
|
||||
seriesBindingResult.value = null
|
||||
Object.assign(seriesBindingForm, createInitialSeriesBindingState())
|
||||
if (seriesBindingFormRef.value) {
|
||||
seriesBindingFormRef.value.resetFields()
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
:disabled="selectedCards.length === 0"
|
||||
@click="showSeriesBindingDialog"
|
||||
v-permission="'iot_card:batch_setting'"
|
||||
>
|
||||
@@ -351,11 +350,97 @@
|
||||
ref="seriesBindingFormRef"
|
||||
:model="seriesBindingForm"
|
||||
:rules="seriesBindingRules"
|
||||
label-width="120px"
|
||||
label-width="100"
|
||||
>
|
||||
<ElFormItem label="已选择卡数">
|
||||
<ElFormItem label="选卡方式" prop="selection_type">
|
||||
<ElRadioGroup v-model="seriesBindingForm.selection_type">
|
||||
<ElRadio label="list">ICCID列表</ElRadio>
|
||||
<ElRadio label="range">号段范围</ElRadio>
|
||||
<ElRadio label="filter">筛选条件</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === CardSelectionType.LIST"
|
||||
label="ICCID列表"
|
||||
>
|
||||
<div>已选择 {{ selectedCards.length }} 张卡</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === CardSelectionType.RANGE"
|
||||
label="起始ICCID"
|
||||
prop="iccid_start"
|
||||
>
|
||||
<ElInput v-model="seriesBindingForm.iccid_start" placeholder="请输入起始ICCID" />
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === CardSelectionType.RANGE"
|
||||
label="结束ICCID"
|
||||
prop="iccid_end"
|
||||
>
|
||||
<ElInput v-model="seriesBindingForm.iccid_end" placeholder="请输入结束ICCID" />
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === CardSelectionType.FILTER"
|
||||
label="运营商"
|
||||
>
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.carrier_id"
|
||||
placeholder="请选择或搜索运营商"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleSearchAllocateCarrier"
|
||||
:loading="allocateCarrierLoading"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption
|
||||
v-for="item in allocateCarrierOptions"
|
||||
:key="item.id"
|
||||
:label="item.carrier_name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="seriesBindingForm.selection_type === CardSelectionType.FILTER"
|
||||
label="卡状态"
|
||||
>
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.status"
|
||||
placeholder="请选择状态"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="在库" :value="1" />
|
||||
<ElOption label="已分销" :value="2" />
|
||||
<ElOption label="已激活" :value="3" />
|
||||
<ElOption label="已停用" :value="4" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="
|
||||
seriesBindingForm.selection_type === CardSelectionType.FILTER &&
|
||||
userInfo.user_type !== 3
|
||||
"
|
||||
label="批次号"
|
||||
>
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.batch_no"
|
||||
placeholder="请选择或搜索批次号"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleSearchAllocateBatchNo"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption
|
||||
v-for="item in allocateBatchNoOptions"
|
||||
:key="item.id"
|
||||
:label="item.batch_no"
|
||||
:value="item.batch_no"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="套餐系列" prop="series_id">
|
||||
<ElSelect
|
||||
v-model="seriesBindingForm.series_id"
|
||||
@@ -550,6 +635,7 @@
|
||||
AllocateStandaloneCardsRequest,
|
||||
RecallStandaloneCardsRequest,
|
||||
AllocateStandaloneCardsResponse,
|
||||
BatchSetCardSeriesBindingRequest,
|
||||
BatchSetCardSeriesBindingResponse
|
||||
} from '@/types/api/card'
|
||||
import { CardSelectionType } from '@/types/api/card'
|
||||
@@ -593,11 +679,45 @@
|
||||
const seriesBindingFormRef = ref<FormInstance>()
|
||||
const seriesLoading = ref(false)
|
||||
const packageSeriesList = ref<PackageSeriesResponse[]>([])
|
||||
const seriesBindingForm = reactive({
|
||||
series_id: undefined as number | undefined
|
||||
const createInitialSeriesBindingState = () => ({
|
||||
selection_type: CardSelectionType.LIST,
|
||||
series_id: undefined as number | undefined,
|
||||
iccid_start: '',
|
||||
iccid_end: '',
|
||||
carrier_id: undefined as number | undefined,
|
||||
status: undefined as StandaloneCardStatus | undefined,
|
||||
batch_no: ''
|
||||
})
|
||||
const seriesBindingForm = reactive(createInitialSeriesBindingState())
|
||||
const seriesBindingRules = reactive<FormRules>({
|
||||
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }]
|
||||
selection_type: [{ required: true, message: '请选择选卡方式', trigger: 'change' }],
|
||||
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }],
|
||||
iccid_start: [
|
||||
{
|
||||
required: true,
|
||||
validator: (_rule, value, callback) => {
|
||||
if (seriesBindingForm.selection_type === CardSelectionType.RANGE && !value) {
|
||||
callback(new Error('请输入起始ICCID'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
iccid_end: [
|
||||
{
|
||||
required: true,
|
||||
validator: (_rule, value, callback) => {
|
||||
if (seriesBindingForm.selection_type === CardSelectionType.RANGE && !value) {
|
||||
callback(new Error('请输入结束ICCID'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
const seriesBindingResult = ref<BatchSetCardSeriesBindingResponse>({
|
||||
success_count: 0,
|
||||
@@ -1127,7 +1247,6 @@
|
||||
{ label: '最后实名检查时间', prop: 'last_real_name_check_at' },
|
||||
{ label: '启用轮询', prop: 'enable_polling' },
|
||||
{ label: '批次号', prop: 'batch_no' },
|
||||
{ label: '供应商', prop: 'supplier' },
|
||||
{ label: '创建时间', prop: 'created_at' },
|
||||
{ label: '更新时间', prop: 'updated_at' }
|
||||
]
|
||||
@@ -1274,12 +1393,14 @@
|
||||
prop: 'shop_name',
|
||||
label: '店铺名称',
|
||||
minWidth: 150,
|
||||
showOverflowTooltip: true,
|
||||
formatter: (row: StandaloneIotCard) => row.shop_name || '-'
|
||||
},
|
||||
{
|
||||
prop: 'series_name',
|
||||
label: '套餐系列',
|
||||
width: 150,
|
||||
width: 180,
|
||||
showOverflowTooltip: true,
|
||||
formatter: (row: StandaloneIotCard) => row.series_name || '-'
|
||||
},
|
||||
{
|
||||
@@ -1393,12 +1514,6 @@
|
||||
width: 200,
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'supplier',
|
||||
label: '供应商',
|
||||
width: 150,
|
||||
formatter: (row: StandaloneIotCard) => row.supplier || '-'
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
@@ -1707,19 +1822,17 @@
|
||||
|
||||
// 显示套餐系列绑定对话框
|
||||
const showSeriesBindingDialog = async () => {
|
||||
if (selectedCards.value.length === 0) {
|
||||
ElMessage.warning('请先选择要设置的卡')
|
||||
return
|
||||
}
|
||||
|
||||
// 加载套餐系列列表
|
||||
await loadPackageSeriesList()
|
||||
|
||||
Object.assign(seriesBindingForm, createInitialSeriesBindingState(), {
|
||||
selection_type:
|
||||
selectedCards.value.length > 0 ? CardSelectionType.LIST : CardSelectionType.FILTER
|
||||
})
|
||||
await Promise.all([
|
||||
loadPackageSeriesList(),
|
||||
loadAllocateCarrierOptions(),
|
||||
loadAllocateBatchNoOptions()
|
||||
])
|
||||
seriesBindingDialogVisible.value = true
|
||||
seriesBindingForm.series_id = undefined
|
||||
if (seriesBindingFormRef.value) {
|
||||
seriesBindingFormRef.value.resetFields()
|
||||
}
|
||||
seriesBindingFormRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
// 加载套餐系列列表(支持名称搜索,默认20条)
|
||||
@@ -1752,6 +1865,7 @@
|
||||
|
||||
// 关闭套餐系列绑定对话框
|
||||
const handleSeriesBindingDialogClose = () => {
|
||||
Object.assign(seriesBindingForm, createInitialSeriesBindingState())
|
||||
if (seriesBindingFormRef.value) {
|
||||
seriesBindingFormRef.value.resetFields()
|
||||
}
|
||||
@@ -1769,19 +1883,30 @@
|
||||
|
||||
await seriesBindingFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const iccids = selectedCards.value.map((card) => card.iccid)
|
||||
|
||||
if (iccids.length === 0) {
|
||||
ElMessage.warning('请先选择要设置的卡')
|
||||
return
|
||||
}
|
||||
|
||||
seriesBindingLoading.value = true
|
||||
try {
|
||||
const res = await CardService.batchSetCardSeriesBinding({
|
||||
iccids,
|
||||
const request: BatchSetCardSeriesBindingRequest = {
|
||||
selection_type: seriesBindingForm.selection_type,
|
||||
series_id: seriesBindingForm.series_id!
|
||||
})
|
||||
}
|
||||
|
||||
if (seriesBindingForm.selection_type === CardSelectionType.LIST) {
|
||||
const iccids = selectedCards.value.map((card) => card.iccid)
|
||||
if (iccids.length === 0) {
|
||||
ElMessage.warning('列表模式下请先选择要设置的卡')
|
||||
return
|
||||
}
|
||||
request.iccids = iccids
|
||||
} else if (seriesBindingForm.selection_type === CardSelectionType.RANGE) {
|
||||
request.iccid_start = seriesBindingForm.iccid_start
|
||||
request.iccid_end = seriesBindingForm.iccid_end
|
||||
} else {
|
||||
if (seriesBindingForm.carrier_id) request.carrier_id = seriesBindingForm.carrier_id
|
||||
if (seriesBindingForm.status) request.status = seriesBindingForm.status
|
||||
if (seriesBindingForm.batch_no) request.batch_no = seriesBindingForm.batch_no
|
||||
}
|
||||
|
||||
const res = await CardService.batchSetCardSeriesBinding(request)
|
||||
|
||||
if (res.code === 0) {
|
||||
seriesBindingResult.value = res.data
|
||||
@@ -1833,6 +1958,7 @@
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await CardService.batchSetCardSeriesBinding({
|
||||
selection_type: CardSelectionType.LIST,
|
||||
iccids: selectedCards.value.map((card) => card.iccid),
|
||||
series_id: 0
|
||||
})
|
||||
@@ -1885,6 +2011,7 @@
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await CardService.batchSetCardSeriesBinding({
|
||||
selection_type: CardSelectionType.LIST,
|
||||
iccids: [iccid],
|
||||
series_id: 0
|
||||
})
|
||||
|
||||
@@ -126,8 +126,16 @@
|
||||
if (!data.card_category) return h('span', '-')
|
||||
return h(
|
||||
ElTag,
|
||||
{ type: data.card_category === 'industry' ? 'warning' : 'success', size: 'small' },
|
||||
() => (data.card_category === 'normal' ? '普通卡' : data.card_category === 'industry' ? '行业卡' : data.card_category)
|
||||
{
|
||||
type: data.card_category === 'industry' ? 'warning' : 'success',
|
||||
size: 'small'
|
||||
},
|
||||
() =>
|
||||
data.card_category === 'normal'
|
||||
? '普通卡'
|
||||
: data.card_category === 'industry'
|
||||
? '行业卡'
|
||||
: data.card_category
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +456,8 @@
|
||||
if (entityName.value || !accountList.value.length) return
|
||||
const firstAccount = accountList.value[0]
|
||||
if (firstAccount) {
|
||||
entityName.value = (firstAccount as any).shop_name || (firstAccount as any).enterprise_name || ''
|
||||
entityName.value =
|
||||
(firstAccount as any).shop_name || (firstAccount as any).enterprise_name || ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,10 +123,7 @@
|
||||
}
|
||||
|
||||
// 获取佣金流程状态文本
|
||||
const getCommissionStatusText = (
|
||||
status?: OrderCommissionStatus,
|
||||
statusName?: string
|
||||
): string => {
|
||||
const getCommissionStatusText = (status?: OrderCommissionStatus, statusName?: string): string => {
|
||||
if (statusName) return statusName
|
||||
if (status === undefined) return '-'
|
||||
|
||||
@@ -139,10 +136,7 @@
|
||||
}
|
||||
|
||||
// 获取佣金业务结果文本
|
||||
const getCommissionResultText = (
|
||||
result?: OrderCommissionResult,
|
||||
resultName?: string
|
||||
): string => {
|
||||
const getCommissionResultText = (result?: OrderCommissionResult, resultName?: string): string => {
|
||||
if (resultName) return resultName
|
||||
if (result === undefined) return '-'
|
||||
|
||||
|
||||
@@ -463,7 +463,9 @@
|
||||
|
||||
if (value > retailPriceUpperLimit.value) {
|
||||
callback(
|
||||
new Error(`零售价不能大于建议售价 * 2 = ${formatRetailPriceYuan(retailPriceUpperLimit.value)}`)
|
||||
new Error(
|
||||
`零售价不能大于建议售价 * 2 = ${formatRetailPriceYuan(retailPriceUpperLimit.value)}`
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -263,8 +263,9 @@
|
||||
placeholder="请输入成本价"
|
||||
/>
|
||||
<div v-if="packageForm.original_cost_price" class="form-tip">
|
||||
请参考{{ packageForm.package_name || '套餐' }} - 套餐成本价:
|
||||
¥{{ packageForm.original_cost_price.toFixed(2) }}
|
||||
请参考{{ packageForm.package_name || '套餐' }} - 套餐成本价: ¥{{
|
||||
packageForm.original_cost_price.toFixed(2)
|
||||
}}
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
@@ -1992,5 +1992,4 @@
|
||||
font-weight: 500;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -107,8 +107,9 @@
|
||||
placeholder="请输入成本价"
|
||||
/>
|
||||
<div v-if="packageForm.original_cost_price" class="form-tip">
|
||||
请参考{{ packageForm.package_name || '套餐' }} - 套餐成本价:
|
||||
¥{{ packageForm.original_cost_price.toFixed(2) }}
|
||||
请参考{{ packageForm.package_name || '套餐' }} - 套餐成本价: ¥{{
|
||||
packageForm.original_cost_price.toFixed(2)
|
||||
}}
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
@@ -202,7 +203,8 @@
|
||||
? pkgOption.cost_price / 100
|
||||
: currentCostPrice,
|
||||
suggested_retail_price:
|
||||
pkgOption?.suggested_retail_price !== undefined && pkgOption?.suggested_retail_price !== null
|
||||
pkgOption?.suggested_retail_price !== undefined &&
|
||||
pkgOption?.suggested_retail_price !== null
|
||||
? pkgOption.suggested_retail_price / 100
|
||||
: undefined
|
||||
}
|
||||
|
||||
@@ -794,7 +794,12 @@
|
||||
const isMaskedData = (value: string | undefined | null): boolean => {
|
||||
if (!value) return false
|
||||
// 检查是否包含脱敏标记:纯星号、已配置标记、或包含连续星号(脱敏数据如Wuha***1218)
|
||||
return value === '***' || value.includes('[已配置]') || value.includes('[未配置]') || /\*{2,}/.test(value)
|
||||
return (
|
||||
value === '***' ||
|
||||
value.includes('[已配置]') ||
|
||||
value.includes('[未配置]') ||
|
||||
/\*{2,}/.test(value)
|
||||
)
|
||||
}
|
||||
|
||||
// 显示编辑对话框
|
||||
@@ -906,7 +911,8 @@
|
||||
description: form.description || undefined
|
||||
}
|
||||
// 只有填写了有效的新值才更新敏感字段(不是空值且不是脱敏数据)
|
||||
if (isValidFieldValue(form.miniapp_app_secret)) data.miniapp_app_secret = form.miniapp_app_secret
|
||||
if (isValidFieldValue(form.miniapp_app_secret))
|
||||
data.miniapp_app_secret = form.miniapp_app_secret
|
||||
if (isValidFieldValue(form.oa_app_secret)) data.oa_app_secret = form.oa_app_secret
|
||||
if (isValidFieldValue(form.oa_token)) data.oa_token = form.oa_token
|
||||
if (isValidFieldValue(form.oa_aes_key)) data.oa_aes_key = form.oa_aes_key
|
||||
|
||||
Reference in New Issue
Block a user