fetch(modify):完善ioT卡管理
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m37s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m37s
This commit is contained in:
@@ -198,23 +198,23 @@
|
|||||||
<ElFormItem label="已选设备数">
|
<ElFormItem label="已选设备数">
|
||||||
<span style="font-weight: bold; color: #409eff">{{ selectedDevices.length }}</span> 台
|
<span style="font-weight: bold; color: #409eff">{{ selectedDevices.length }}</span> 台
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem label="套餐系列分配" prop="series_allocation_id">
|
<ElFormItem label="套餐系列" prop="series_id">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="seriesBindingForm.series_allocation_id"
|
v-model="seriesBindingForm.series_id"
|
||||||
placeholder="请选择或搜索套餐系列分配(支持系列名称搜索)"
|
placeholder="请选择或搜索套餐系列"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
filterable
|
filterable
|
||||||
remote
|
remote
|
||||||
reserve-keyword
|
reserve-keyword
|
||||||
:remote-method="searchSeriesAllocations"
|
:remote-method="searchPackageSeries"
|
||||||
:loading="seriesLoading"
|
:loading="seriesLoading"
|
||||||
clearable
|
clearable
|
||||||
>
|
>
|
||||||
<ElOption label="清除关联" :value="0" />
|
<ElOption label="清除关联" :value="0" />
|
||||||
<ElOption
|
<ElOption
|
||||||
v-for="series in seriesAllocationList"
|
v-for="series in packageSeriesList"
|
||||||
:key="series.id"
|
:key="series.id"
|
||||||
:label="`${series.series_name} (${series.shop_name})`"
|
:label="series.series_name"
|
||||||
:value="series.id"
|
:value="series.id"
|
||||||
:disabled="series.status !== 1"
|
:disabled="series.status !== 1"
|
||||||
/>
|
/>
|
||||||
@@ -317,7 +317,7 @@
|
|||||||
<!-- 绑定卡片列表弹窗 -->
|
<!-- 绑定卡片列表弹窗 -->
|
||||||
<ElDialog v-model="deviceCardsDialogVisible" title="绑定的卡片" width="900px">
|
<ElDialog v-model="deviceCardsDialogVisible" title="绑定的卡片" width="900px">
|
||||||
<div style="margin-bottom: 10px; text-align: right">
|
<div style="margin-bottom: 10px; text-align: right">
|
||||||
<ElButton type="primary" size="small" @click="handleBindCard">绑定新卡</ElButton>
|
<ElButton type="primary" @click="handleBindCard">绑定新卡</ElButton>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="deviceCardsLoading" style="text-align: center; padding: 40px 0">
|
<div v-if="deviceCardsLoading" style="text-align: center; padding: 40px 0">
|
||||||
<ElIcon class="is-loading" :size="40"><Loading /></ElIcon>
|
<ElIcon class="is-loading" :size="40"><Loading /></ElIcon>
|
||||||
@@ -402,8 +402,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { DeviceService, ShopService, CardService } from '@/api/modules'
|
import { DeviceService, ShopService, CardService, PackageSeriesService } from '@/api/modules'
|
||||||
import { ShopSeriesAllocationService } from '@/api/modules/shopSeriesAllocation'
|
|
||||||
import { ElMessage, ElMessageBox, ElTag, ElSwitch, ElIcon, ElTreeSelect } from 'element-plus'
|
import { ElMessage, ElMessageBox, ElTag, ElSwitch, ElIcon, ElTreeSelect } from 'element-plus'
|
||||||
import { Loading } from '@element-plus/icons-vue'
|
import { Loading } from '@element-plus/icons-vue'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
@@ -419,7 +418,7 @@
|
|||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
import { CommonStatus, getStatusText } from '@/config/constants'
|
import { CommonStatus, getStatusText } from '@/config/constants'
|
||||||
import type { ShopSeriesAllocationResponse } from '@/types/api'
|
import type { PackageSeriesResponse } from '@/types/api'
|
||||||
|
|
||||||
defineOptions({ name: 'DeviceList' })
|
defineOptions({ name: 'DeviceList' })
|
||||||
|
|
||||||
@@ -442,12 +441,12 @@
|
|||||||
const seriesBindingLoading = ref(false)
|
const seriesBindingLoading = ref(false)
|
||||||
const seriesBindingFormRef = ref<FormInstance>()
|
const seriesBindingFormRef = ref<FormInstance>()
|
||||||
const seriesLoading = ref(false)
|
const seriesLoading = ref(false)
|
||||||
const seriesAllocationList = ref<ShopSeriesAllocationResponse[]>([])
|
const packageSeriesList = ref<PackageSeriesResponse[]>([])
|
||||||
const seriesBindingForm = reactive({
|
const seriesBindingForm = reactive({
|
||||||
series_allocation_id: undefined as number | undefined
|
series_id: undefined as number | undefined
|
||||||
})
|
})
|
||||||
const seriesBindingRules = reactive<FormRules>({
|
const seriesBindingRules = reactive<FormRules>({
|
||||||
series_allocation_id: [{ required: true, message: '请选择套餐系列分配', trigger: 'change' }]
|
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }]
|
||||||
})
|
})
|
||||||
const seriesBindingResult = ref<BatchSetDeviceSeriesBindingResponse | null>(null)
|
const seriesBindingResult = ref<BatchSetDeviceSeriesBindingResponse | null>(null)
|
||||||
|
|
||||||
@@ -1144,14 +1143,14 @@
|
|||||||
ElMessage.warning('请先选择要设置的设备')
|
ElMessage.warning('请先选择要设置的设备')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
seriesBindingForm.series_allocation_id = undefined
|
seriesBindingForm.series_id = undefined
|
||||||
seriesBindingResult.value = null
|
seriesBindingResult.value = null
|
||||||
await loadSeriesAllocationList()
|
await loadPackageSeriesList()
|
||||||
seriesBindingDialogVisible.value = true
|
seriesBindingDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载套餐系列分配列表(默认加载20条)
|
// 加载套餐系列列表(支持名称搜索,默认20条)
|
||||||
const loadSeriesAllocationList = async (seriesName?: string) => {
|
const loadPackageSeriesList = async (seriesName?: string) => {
|
||||||
seriesLoading.value = true
|
seriesLoading.value = true
|
||||||
try {
|
try {
|
||||||
const params: any = {
|
const params: any = {
|
||||||
@@ -1162,21 +1161,21 @@
|
|||||||
if (seriesName) {
|
if (seriesName) {
|
||||||
params.series_name = seriesName
|
params.series_name = seriesName
|
||||||
}
|
}
|
||||||
const res = await ShopSeriesAllocationService.getShopSeriesAllocations(params)
|
const res = await PackageSeriesService.getPackageSeries(params)
|
||||||
if (res.code === 0 && res.data.items) {
|
if (res.code === 0 && res.data.items) {
|
||||||
seriesAllocationList.value = res.data.items
|
packageSeriesList.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取套餐系列分配列表失败:', error)
|
console.error('获取套餐系列列表失败:', error)
|
||||||
ElMessage.error('获取套餐系列分配列表失败')
|
ElMessage.error('获取套餐系列列表失败')
|
||||||
} finally {
|
} finally {
|
||||||
seriesLoading.value = false
|
seriesLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索套餐系列分配(根据系列名称)
|
// 搜索套餐系列
|
||||||
const searchSeriesAllocations = async (query: string) => {
|
const searchPackageSeries = async (query: string) => {
|
||||||
await loadSeriesAllocationList(query || undefined)
|
await loadPackageSeriesList(query || undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确认设置套餐系列绑定
|
// 确认设置套餐系列绑定
|
||||||
@@ -1189,7 +1188,7 @@
|
|||||||
try {
|
try {
|
||||||
const data = {
|
const data = {
|
||||||
device_ids: selectedDevices.value.map((d) => d.id),
|
device_ids: selectedDevices.value.map((d) => d.id),
|
||||||
series_allocation_id: seriesBindingForm.series_allocation_id!
|
series_allocation_id: seriesBindingForm.series_id! // 注意:API参数名仍是series_allocation_id,但前端使用series_id
|
||||||
}
|
}
|
||||||
const res = await DeviceService.batchSetDeviceSeriesBinding(data)
|
const res = await DeviceService.batchSetDeviceSeriesBinding(data)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
@@ -1206,7 +1205,6 @@
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
ElMessage.error('设置套餐系列绑定失败')
|
|
||||||
} finally {
|
} finally {
|
||||||
seriesBindingLoading.value = false
|
seriesBindingLoading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
@refresh="handleRefresh"
|
@refresh="handleRefresh"
|
||||||
>
|
>
|
||||||
<template #left>
|
<template #left>
|
||||||
<ElButton type="primary" @click="showImportDialog">导入ICCID</ElButton>
|
|
||||||
<ElButton
|
<ElButton
|
||||||
type="success"
|
type="success"
|
||||||
:disabled="selectedCards.length === 0"
|
:disabled="selectedCards.length === 0"
|
||||||
@@ -33,6 +32,13 @@
|
|||||||
>
|
>
|
||||||
批量回收
|
批量回收
|
||||||
</ElButton>
|
</ElButton>
|
||||||
|
<ElButton
|
||||||
|
type="primary"
|
||||||
|
:disabled="selectedCards.length === 0"
|
||||||
|
@click="showSeriesBindingDialog"
|
||||||
|
>
|
||||||
|
批量设置套餐系列
|
||||||
|
</ElButton>
|
||||||
<ElButton type="info" @contextmenu.prevent="showMoreMenu">更多操作</ElButton>
|
<ElButton type="info" @contextmenu.prevent="showMoreMenu">更多操作</ElButton>
|
||||||
</template>
|
</template>
|
||||||
</ArtTableHeader>
|
</ArtTableHeader>
|
||||||
@@ -57,63 +63,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
<!-- 导入ICCID对话框 -->
|
|
||||||
<ElDialog
|
|
||||||
v-model="importDialogVisible"
|
|
||||||
title="导入ICCID"
|
|
||||||
width="500px"
|
|
||||||
@close="handleImportDialogClose"
|
|
||||||
>
|
|
||||||
<ElForm ref="importFormRef" :model="importForm" :rules="importRules" label-width="100px">
|
|
||||||
<ElFormItem label="运营商" prop="carrier_id">
|
|
||||||
<ElSelect
|
|
||||||
v-model="importForm.carrier_id"
|
|
||||||
placeholder="请选择运营商"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<ElOption label="中国移动" :value="1" />
|
|
||||||
<ElOption label="中国联通" :value="2" />
|
|
||||||
<ElOption label="中国电信" :value="3" />
|
|
||||||
</ElSelect>
|
|
||||||
</ElFormItem>
|
|
||||||
<ElFormItem label="批次号" prop="batch_no">
|
|
||||||
<ElInput v-model="importForm.batch_no" placeholder="请输入批次号(可选)" />
|
|
||||||
</ElFormItem>
|
|
||||||
<ElFormItem label="上传文件" prop="file">
|
|
||||||
<ElUpload
|
|
||||||
ref="uploadRef"
|
|
||||||
class="upload-demo"
|
|
||||||
:auto-upload="false"
|
|
||||||
:limit="1"
|
|
||||||
:on-change="handleFileChange"
|
|
||||||
:on-exceed="handleExceed"
|
|
||||||
:file-list="fileList"
|
|
||||||
accept=".csv"
|
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<ElButton type="primary">选择文件</ElButton>
|
|
||||||
</template>
|
|
||||||
<template #tip>
|
|
||||||
<div class="el-upload__tip">
|
|
||||||
<div>只支持上传CSV文件,且不超过10MB</div>
|
|
||||||
<div style="margin-top: 4px; color: var(--el-color-info)">
|
|
||||||
CSV格式:ICCID,MSISDN(两列,逗号分隔,每行一条记录)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</ElUpload>
|
|
||||||
</ElFormItem>
|
|
||||||
</ElForm>
|
|
||||||
<template #footer>
|
|
||||||
<div class="dialog-footer">
|
|
||||||
<ElButton @click="importDialogVisible = false">取消</ElButton>
|
|
||||||
<ElButton type="primary" @click="handleImport" :loading="importLoading">
|
|
||||||
开始导入
|
|
||||||
</ElButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</ElDialog>
|
|
||||||
|
|
||||||
<!-- 批量分配对话框 -->
|
<!-- 批量分配对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="allocateDialogVisible"
|
v-model="allocateDialogVisible"
|
||||||
@@ -130,12 +79,21 @@
|
|||||||
<ElFormItem label="目标店铺" prop="to_shop_id">
|
<ElFormItem label="目标店铺" prop="to_shop_id">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="allocateForm.to_shop_id"
|
v-model="allocateForm.to_shop_id"
|
||||||
placeholder="请选择目标店铺"
|
placeholder="请选择或搜索目标店铺"
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
reserve-keyword
|
||||||
|
:remote-method="searchTargetShops"
|
||||||
|
:loading="targetShopLoading"
|
||||||
|
clearable
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
<ElOption label="店铺A" :value="1" />
|
<ElOption
|
||||||
<ElOption label="店铺B" :value="2" />
|
v-for="shop in targetShopList"
|
||||||
<ElOption label="店铺C" :value="3" />
|
:key="shop.id"
|
||||||
|
:label="shop.shop_name"
|
||||||
|
:value="shop.id"
|
||||||
|
/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem label="选卡方式" prop="selection_type">
|
<ElFormItem label="选卡方式" prop="selection_type">
|
||||||
@@ -224,12 +182,21 @@
|
|||||||
<ElFormItem label="来源店铺" prop="from_shop_id">
|
<ElFormItem label="来源店铺" prop="from_shop_id">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="recallForm.from_shop_id"
|
v-model="recallForm.from_shop_id"
|
||||||
placeholder="请选择来源店铺"
|
placeholder="请选择或搜索来源店铺"
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
reserve-keyword
|
||||||
|
:remote-method="searchFromShops"
|
||||||
|
:loading="fromShopLoading"
|
||||||
|
clearable
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
<ElOption label="店铺A" :value="1" />
|
<ElOption
|
||||||
<ElOption label="店铺B" :value="2" />
|
v-for="shop in fromShopList"
|
||||||
<ElOption label="店铺C" :value="3" />
|
:key="shop.id"
|
||||||
|
:label="shop.shop_name"
|
||||||
|
:value="shop.id"
|
||||||
|
/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem label="选卡方式" prop="selection_type">
|
<ElFormItem label="选卡方式" prop="selection_type">
|
||||||
@@ -345,18 +312,23 @@
|
|||||||
<ElFormItem label="已选择卡数">
|
<ElFormItem label="已选择卡数">
|
||||||
<div>已选择 {{ selectedCards.length }} 张卡</div>
|
<div>已选择 {{ selectedCards.length }} 张卡</div>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem label="套餐系列分配" prop="series_allocation_id">
|
<ElFormItem label="套餐系列" prop="series_id">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="seriesBindingForm.series_allocation_id"
|
v-model="seriesBindingForm.series_id"
|
||||||
placeholder="请选择套餐系列分配(选择清除关联将解除绑定)"
|
placeholder="请选择或搜索套餐系列"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
reserve-keyword
|
||||||
|
:remote-method="searchPackageSeries"
|
||||||
:loading="seriesLoading"
|
:loading="seriesLoading"
|
||||||
|
clearable
|
||||||
>
|
>
|
||||||
<ElOption label="清除关联" :value="0" />
|
<ElOption label="清除关联" :value="0" />
|
||||||
<ElOption
|
<ElOption
|
||||||
v-for="series in seriesAllocationList"
|
v-for="series in packageSeriesList"
|
||||||
:key="series.id"
|
:key="series.id"
|
||||||
:label="`${series.series_name} (${series.shop_name})`"
|
:label="series.series_name"
|
||||||
:value="series.id"
|
:value="series.id"
|
||||||
:disabled="series.status !== 1"
|
:disabled="series.status !== 1"
|
||||||
/>
|
/>
|
||||||
@@ -506,11 +478,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { CardService, StorageService } from '@/api/modules'
|
import { CardService, ShopService, PackageSeriesService } from '@/api/modules'
|
||||||
import { ShopSeriesAllocationService } from '@/api/modules/shopSeriesAllocation'
|
import { ElMessage, ElTag, ElIcon } from 'element-plus'
|
||||||
import { ElMessage, ElTag, ElUpload, ElIcon } from 'element-plus'
|
|
||||||
import { Loading } from '@element-plus/icons-vue'
|
import { Loading } from '@element-plus/icons-vue'
|
||||||
import type { FormInstance, FormRules, UploadProps, UploadUserFile } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import type { SearchFormItem } from '@/types'
|
import type { SearchFormItem } from '@/types'
|
||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
@@ -524,14 +495,12 @@
|
|||||||
AllocateStandaloneCardsResponse,
|
AllocateStandaloneCardsResponse,
|
||||||
BatchSetCardSeriesBindingResponse
|
BatchSetCardSeriesBindingResponse
|
||||||
} from '@/types/api/card'
|
} from '@/types/api/card'
|
||||||
import type { ShopSeriesAllocationResponse } from '@/types/api'
|
import type { PackageSeriesResponse } from '@/types/api'
|
||||||
|
|
||||||
defineOptions({ name: 'StandaloneCardList' })
|
defineOptions({ name: 'StandaloneCardList' })
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const importDialogVisible = ref(false)
|
|
||||||
const importLoading = ref(false)
|
|
||||||
const allocateDialogVisible = ref(false)
|
const allocateDialogVisible = ref(false)
|
||||||
const allocateLoading = ref(false)
|
const allocateLoading = ref(false)
|
||||||
const recallDialogVisible = ref(false)
|
const recallDialogVisible = ref(false)
|
||||||
@@ -539,11 +508,8 @@
|
|||||||
const resultDialogVisible = ref(false)
|
const resultDialogVisible = ref(false)
|
||||||
const resultTitle = ref('')
|
const resultTitle = ref('')
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const importFormRef = ref<FormInstance>()
|
|
||||||
const allocateFormRef = ref<FormInstance>()
|
const allocateFormRef = ref<FormInstance>()
|
||||||
const recallFormRef = ref<FormInstance>()
|
const recallFormRef = ref<FormInstance>()
|
||||||
const uploadRef = ref()
|
|
||||||
const fileList = ref<UploadUserFile[]>([])
|
|
||||||
const selectedCards = ref<StandaloneIotCard[]>([])
|
const selectedCards = ref<StandaloneIotCard[]>([])
|
||||||
const allocationResult = ref<AllocateStandaloneCardsResponse>({
|
const allocationResult = ref<AllocateStandaloneCardsResponse>({
|
||||||
allocation_no: '',
|
allocation_no: '',
|
||||||
@@ -559,12 +525,12 @@
|
|||||||
const seriesBindingResultDialogVisible = ref(false)
|
const seriesBindingResultDialogVisible = ref(false)
|
||||||
const seriesBindingFormRef = ref<FormInstance>()
|
const seriesBindingFormRef = ref<FormInstance>()
|
||||||
const seriesLoading = ref(false)
|
const seriesLoading = ref(false)
|
||||||
const seriesAllocationList = ref<ShopSeriesAllocationResponse[]>([])
|
const packageSeriesList = ref<PackageSeriesResponse[]>([])
|
||||||
const seriesBindingForm = reactive({
|
const seriesBindingForm = reactive({
|
||||||
series_allocation_id: undefined as number | undefined
|
series_id: undefined as number | undefined
|
||||||
})
|
})
|
||||||
const seriesBindingRules = reactive<FormRules>({
|
const seriesBindingRules = reactive<FormRules>({
|
||||||
series_allocation_id: [{ required: true, message: '请选择套餐系列分配', trigger: 'change' }]
|
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }]
|
||||||
})
|
})
|
||||||
const seriesBindingResult = ref<BatchSetCardSeriesBindingResponse>({
|
const seriesBindingResult = ref<BatchSetCardSeriesBindingResponse>({
|
||||||
success_count: 0,
|
success_count: 0,
|
||||||
@@ -580,6 +546,12 @@
|
|||||||
// 更多操作右键菜单
|
// 更多操作右键菜单
|
||||||
const moreMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
const moreMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
|
||||||
|
// 店铺相关
|
||||||
|
const targetShopLoading = ref(false)
|
||||||
|
const fromShopLoading = ref(false)
|
||||||
|
const targetShopList = ref<any[]>([])
|
||||||
|
const fromShopList = ref<any[]>([])
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
status: undefined,
|
status: undefined,
|
||||||
@@ -592,19 +564,6 @@
|
|||||||
// 搜索表单
|
// 搜索表单
|
||||||
const formFilters = reactive({ ...initialSearchState })
|
const formFilters = reactive({ ...initialSearchState })
|
||||||
|
|
||||||
// 导入表单
|
|
||||||
const importForm = reactive({
|
|
||||||
carrier_id: undefined as number | undefined,
|
|
||||||
batch_no: '',
|
|
||||||
file: null as File | null
|
|
||||||
})
|
|
||||||
|
|
||||||
// 导入表单验证规则
|
|
||||||
const importRules = reactive<FormRules>({
|
|
||||||
carrier_id: [{ required: true, message: '请选择运营商', trigger: 'change' }],
|
|
||||||
file: [{ required: true, message: '请选择上传文件', trigger: 'change' }]
|
|
||||||
})
|
|
||||||
|
|
||||||
// 批量分配表单
|
// 批量分配表单
|
||||||
const allocateForm = reactive<Partial<AllocateStandaloneCardsRequest>>({
|
const allocateForm = reactive<Partial<AllocateStandaloneCardsRequest>>({
|
||||||
selection_type: 'list',
|
selection_type: 'list',
|
||||||
@@ -1062,103 +1021,66 @@
|
|||||||
getTableData()
|
getTableData()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示导入对话框
|
|
||||||
const showImportDialog = () => {
|
|
||||||
importDialogVisible.value = true
|
|
||||||
importForm.carrier_id = undefined
|
|
||||||
importForm.batch_no = ''
|
|
||||||
importForm.file = null
|
|
||||||
fileList.value = []
|
|
||||||
if (importFormRef.value) {
|
|
||||||
importFormRef.value.resetFields()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件变化处理
|
|
||||||
const handleFileChange: UploadProps['onChange'] = (file) => {
|
|
||||||
importForm.file = file.raw as File
|
|
||||||
if (importFormRef.value) {
|
|
||||||
importFormRef.value.clearValidate('file')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件超出限制处理
|
|
||||||
const handleExceed: UploadProps['onExceed'] = () => {
|
|
||||||
ElMessage.warning('最多只能上传1个文件')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭导入对话框
|
|
||||||
const handleImportDialogClose = () => {
|
|
||||||
if (uploadRef.value) {
|
|
||||||
uploadRef.value.clearFiles()
|
|
||||||
}
|
|
||||||
fileList.value = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行导入
|
|
||||||
const handleImport = async () => {
|
|
||||||
if (!importFormRef.value) return
|
|
||||||
|
|
||||||
await importFormRef.value.validate(async (valid) => {
|
|
||||||
if (valid) {
|
|
||||||
if (!importForm.file) {
|
|
||||||
ElMessage.warning('请选择上传文件')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
importLoading.value = true
|
|
||||||
try {
|
|
||||||
// 确保 Content-Type 在获取 URL 和上传时完全一致
|
|
||||||
const contentType = importForm.file.type || 'text/csv'
|
|
||||||
|
|
||||||
// 1. 获取上传 URL
|
|
||||||
const uploadUrlRes = await StorageService.getUploadUrl({
|
|
||||||
file_name: importForm.file.name,
|
|
||||||
content_type: contentType,
|
|
||||||
purpose: 'iot_import'
|
|
||||||
})
|
|
||||||
|
|
||||||
if (uploadUrlRes.code !== 0) {
|
|
||||||
ElMessage.error('获取上传地址失败')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 上传文件到对象存储
|
|
||||||
await StorageService.uploadFile(
|
|
||||||
uploadUrlRes.data.upload_url,
|
|
||||||
importForm.file,
|
|
||||||
contentType
|
|
||||||
)
|
|
||||||
|
|
||||||
// 3. 调用导入接口
|
|
||||||
const importRes = await CardService.importIotCards({
|
|
||||||
carrier_id: importForm.carrier_id!,
|
|
||||||
file_key: uploadUrlRes.data.file_key,
|
|
||||||
batch_no: importForm.batch_no || undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (importRes.code === 0) {
|
|
||||||
ElMessage.success(
|
|
||||||
importRes.data.message || '导入任务已创建,请到任务管理页面查看导入进度'
|
|
||||||
)
|
|
||||||
importDialogVisible.value = false
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
ElMessage.error('导入失败,请重试')
|
|
||||||
} finally {
|
|
||||||
importLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 表格选择变化
|
// 表格选择变化
|
||||||
const handleSelectionChange = (selection: StandaloneIotCard[]) => {
|
const handleSelectionChange = (selection: StandaloneIotCard[]) => {
|
||||||
selectedCards.value = selection
|
selectedCards.value = selection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载目标店铺列表
|
||||||
|
const loadTargetShops = async (shopName?: string) => {
|
||||||
|
targetShopLoading.value = true
|
||||||
|
try {
|
||||||
|
const params: any = {
|
||||||
|
page: 1,
|
||||||
|
page_size: 20
|
||||||
|
}
|
||||||
|
if (shopName) {
|
||||||
|
params.shop_name = shopName
|
||||||
|
}
|
||||||
|
const res = await ShopService.getShops(params)
|
||||||
|
if (res.code === 0) {
|
||||||
|
targetShopList.value = res.data.items || []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取目标店铺列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
targetShopLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索目标店铺
|
||||||
|
const searchTargetShops = async (query: string) => {
|
||||||
|
await loadTargetShops(query || undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载来源店铺列表
|
||||||
|
const loadFromShops = async (shopName?: string) => {
|
||||||
|
fromShopLoading.value = true
|
||||||
|
try {
|
||||||
|
const params: any = {
|
||||||
|
page: 1,
|
||||||
|
page_size: 20
|
||||||
|
}
|
||||||
|
if (shopName) {
|
||||||
|
params.shop_name = shopName
|
||||||
|
}
|
||||||
|
const res = await ShopService.getShops(params)
|
||||||
|
if (res.code === 0) {
|
||||||
|
fromShopList.value = res.data.items || []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取来源店铺列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
fromShopLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索来源店铺
|
||||||
|
const searchFromShops = async (query: string) => {
|
||||||
|
await loadFromShops(query || undefined)
|
||||||
|
}
|
||||||
|
|
||||||
// 显示批量分配对话框
|
// 显示批量分配对话框
|
||||||
const showAllocateDialog = () => {
|
const showAllocateDialog = () => {
|
||||||
if (selectedCards.value.length === 0) {
|
if (selectedCards.value.length === 0) {
|
||||||
@@ -1177,6 +1099,8 @@
|
|||||||
batch_no: '',
|
batch_no: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
// 加载默认店铺列表
|
||||||
|
loadTargetShops()
|
||||||
if (allocateFormRef.value) {
|
if (allocateFormRef.value) {
|
||||||
allocateFormRef.value.resetFields()
|
allocateFormRef.value.resetFields()
|
||||||
}
|
}
|
||||||
@@ -1199,6 +1123,8 @@
|
|||||||
batch_no: '',
|
batch_no: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
// 加载默认店铺列表
|
||||||
|
loadFromShops()
|
||||||
if (recallFormRef.value) {
|
if (recallFormRef.value) {
|
||||||
recallFormRef.value.resetFields()
|
recallFormRef.value.resetFields()
|
||||||
}
|
}
|
||||||
@@ -1334,35 +1260,45 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载套餐系列分配列表
|
// 加载套餐系列列表
|
||||||
await loadSeriesAllocationList()
|
await loadPackageSeriesList()
|
||||||
|
|
||||||
seriesBindingDialogVisible.value = true
|
seriesBindingDialogVisible.value = true
|
||||||
seriesBindingForm.series_allocation_id = undefined
|
seriesBindingForm.series_id = undefined
|
||||||
if (seriesBindingFormRef.value) {
|
if (seriesBindingFormRef.value) {
|
||||||
seriesBindingFormRef.value.resetFields()
|
seriesBindingFormRef.value.resetFields()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载套餐系列分配列表
|
// 加载套餐系列列表(支持名称搜索,默认20条)
|
||||||
const loadSeriesAllocationList = async () => {
|
const loadPackageSeriesList = async (seriesName?: string) => {
|
||||||
seriesLoading.value = true
|
seriesLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await ShopSeriesAllocationService.getShopSeriesAllocations({
|
const params: any = {
|
||||||
page: 1,
|
page: 1,
|
||||||
page_size: 1000 // 获取所有可用的套餐系列分配
|
page_size: 20,
|
||||||
})
|
status: 1 // 只获取启用的
|
||||||
if (res.code === 0 && res.data.list) {
|
}
|
||||||
seriesAllocationList.value = res.data.list
|
if (seriesName) {
|
||||||
|
params.series_name = seriesName
|
||||||
|
}
|
||||||
|
const res = await PackageSeriesService.getPackageSeries(params)
|
||||||
|
if (res.code === 0 && res.data.items) {
|
||||||
|
packageSeriesList.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error('获取套餐系列列表失败:', error)
|
||||||
ElMessage.error('获取套餐系列分配列表失败')
|
ElMessage.error('获取套餐系列列表失败')
|
||||||
} finally {
|
} finally {
|
||||||
seriesLoading.value = false
|
seriesLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 搜索套餐系列
|
||||||
|
const searchPackageSeries = async (query: string) => {
|
||||||
|
await loadPackageSeriesList(query || undefined)
|
||||||
|
}
|
||||||
|
|
||||||
// 关闭套餐系列绑定对话框
|
// 关闭套餐系列绑定对话框
|
||||||
const handleSeriesBindingDialogClose = () => {
|
const handleSeriesBindingDialogClose = () => {
|
||||||
if (seriesBindingFormRef.value) {
|
if (seriesBindingFormRef.value) {
|
||||||
@@ -1387,7 +1323,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await CardService.batchSetCardSeriesBinding({
|
const res = await CardService.batchSetCardSeriesBinding({
|
||||||
iccids,
|
iccids,
|
||||||
series_allocation_id: seriesBindingForm.series_allocation_id!
|
series_allocation_id: seriesBindingForm.series_id! // 注意:API参数名仍是series_allocation_id,但前端使用series_id
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
@@ -1417,7 +1353,6 @@
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
ElMessage.error('套餐系列绑定设置失败,请重试')
|
|
||||||
} finally {
|
} finally {
|
||||||
seriesBindingLoading.value = false
|
seriesBindingLoading.value = false
|
||||||
}
|
}
|
||||||
@@ -1427,12 +1362,6 @@
|
|||||||
|
|
||||||
// 更多操作菜单项配置
|
// 更多操作菜单项配置
|
||||||
const moreMenuItems = computed((): MenuItemType[] => [
|
const moreMenuItems = computed((): MenuItemType[] => [
|
||||||
{
|
|
||||||
key: 'seriesBinding',
|
|
||||||
label: '批量设置套餐系列',
|
|
||||||
icon: '',
|
|
||||||
disabled: selectedCards.value.length === 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'distribution',
|
key: 'distribution',
|
||||||
label: '网卡分销',
|
label: '网卡分销',
|
||||||
@@ -1470,9 +1399,6 @@
|
|||||||
// 处理更多操作菜单选择
|
// 处理更多操作菜单选择
|
||||||
const handleMoreMenuSelect = (item: MenuItemType) => {
|
const handleMoreMenuSelect = (item: MenuItemType) => {
|
||||||
switch (item.key) {
|
switch (item.key) {
|
||||||
case 'seriesBinding':
|
|
||||||
showSeriesBindingDialog()
|
|
||||||
break
|
|
||||||
case 'distribution':
|
case 'distribution':
|
||||||
cardDistribution()
|
cardDistribution()
|
||||||
break
|
break
|
||||||
|
|||||||
Reference in New Issue
Block a user