fetch(add): 分配记录,批量分配/回收, 单卡列表, 任务列表, 导入ICCID
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m21s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m21s
This commit is contained in:
916
src/views/asset-management/card-list/index.vue
Normal file
916
src/views/asset-management/card-list/index.vue
Normal file
@@ -0,0 +1,916 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="standalone-card-list-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="formFilters"
|
||||
:items="formItems"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<ElButton type="primary" @click="showImportDialog">导入ICCID</ElButton>
|
||||
<ElButton type="success" :disabled="selectedCards.length === 0" @click="showAllocateDialog">
|
||||
批量分配
|
||||
</ElButton>
|
||||
<ElButton type="warning" :disabled="selectedCards.length === 0" @click="showRecallDialog">
|
||||
批量回收
|
||||
</ElButton>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="cardList"
|
||||
:currentPage="pagination.page"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn type="selection" width="55" />
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</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=".xlsx,.xls"
|
||||
>
|
||||
<template #trigger>
|
||||
<ElButton type="primary">选择文件</ElButton>
|
||||
</template>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">只能上传xlsx/xls文件,且不超过10MB</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
|
||||
v-model="allocateDialogVisible"
|
||||
title="批量分配"
|
||||
width="600px"
|
||||
@close="handleAllocateDialogClose"
|
||||
>
|
||||
<ElForm ref="allocateFormRef" :model="allocateForm" :rules="allocateRules" label-width="120px">
|
||||
<ElFormItem label="目标店铺" prop="to_shop_id">
|
||||
<ElSelect v-model="allocateForm.to_shop_id" placeholder="请选择目标店铺" style="width: 100%">
|
||||
<ElOption label="店铺A" :value="1" />
|
||||
<ElOption label="店铺B" :value="2" />
|
||||
<ElOption label="店铺C" :value="3" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="选卡方式" prop="selection_type">
|
||||
<ElRadioGroup v-model="allocateForm.selection_type">
|
||||
<ElRadio label="list">ICCID列表</ElRadio>
|
||||
<ElRadio label="range">号段范围</ElRadio>
|
||||
<ElRadio label="filter">筛选条件</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="allocateForm.selection_type === 'list'" label="ICCID列表">
|
||||
<div>已选择 {{ selectedCards.length }} 张卡</div>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="allocateForm.selection_type === 'range'" label="起始ICCID" prop="iccid_start">
|
||||
<ElInput v-model="allocateForm.iccid_start" placeholder="请输入起始ICCID" />
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="allocateForm.selection_type === 'range'" label="结束ICCID" prop="iccid_end">
|
||||
<ElInput v-model="allocateForm.iccid_end" placeholder="请输入结束ICCID" />
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="allocateForm.selection_type === 'filter'" label="运营商">
|
||||
<ElSelect v-model="allocateForm.carrier_id" placeholder="请选择运营商" clearable style="width: 100%">
|
||||
<ElOption label="中国移动" :value="1" />
|
||||
<ElOption label="中国联通" :value="2" />
|
||||
<ElOption label="中国电信" :value="3" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="allocateForm.selection_type === 'filter'" label="卡状态">
|
||||
<ElSelect v-model="allocateForm.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="allocateForm.selection_type === 'filter'" label="批次号">
|
||||
<ElInput v-model="allocateForm.batch_no" placeholder="请输入批次号" />
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="备注">
|
||||
<ElInput v-model="allocateForm.remark" type="textarea" :rows="3" placeholder="请输入备注信息" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="allocateDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleAllocate" :loading="allocateLoading">
|
||||
确认分配
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 批量回收对话框 -->
|
||||
<ElDialog
|
||||
v-model="recallDialogVisible"
|
||||
title="批量回收"
|
||||
width="600px"
|
||||
@close="handleRecallDialogClose"
|
||||
>
|
||||
<ElForm ref="recallFormRef" :model="recallForm" :rules="recallRules" label-width="120px">
|
||||
<ElFormItem label="来源店铺" prop="from_shop_id">
|
||||
<ElSelect v-model="recallForm.from_shop_id" placeholder="请选择来源店铺" style="width: 100%">
|
||||
<ElOption label="店铺A" :value="1" />
|
||||
<ElOption label="店铺B" :value="2" />
|
||||
<ElOption label="店铺C" :value="3" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="选卡方式" prop="selection_type">
|
||||
<ElRadioGroup v-model="recallForm.selection_type">
|
||||
<ElRadio label="list">ICCID列表</ElRadio>
|
||||
<ElRadio label="range">号段范围</ElRadio>
|
||||
<ElRadio label="filter">筛选条件</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="recallForm.selection_type === 'list'" label="ICCID列表">
|
||||
<div>已选择 {{ selectedCards.length }} 张卡</div>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="recallForm.selection_type === 'range'" label="起始ICCID" prop="iccid_start">
|
||||
<ElInput v-model="recallForm.iccid_start" placeholder="请输入起始ICCID" />
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="recallForm.selection_type === 'range'" label="结束ICCID" prop="iccid_end">
|
||||
<ElInput v-model="recallForm.iccid_end" placeholder="请输入结束ICCID" />
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="recallForm.selection_type === 'filter'" label="运营商">
|
||||
<ElSelect v-model="recallForm.carrier_id" placeholder="请选择运营商" clearable style="width: 100%">
|
||||
<ElOption label="中国移动" :value="1" />
|
||||
<ElOption label="中国联通" :value="2" />
|
||||
<ElOption label="中国电信" :value="3" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="recallForm.selection_type === 'filter'" label="批次号">
|
||||
<ElInput v-model="recallForm.batch_no" placeholder="请输入批次号" />
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="备注">
|
||||
<ElInput v-model="recallForm.remark" type="textarea" :rows="3" placeholder="请输入备注信息" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="recallDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleRecall" :loading="recallLoading">
|
||||
确认回收
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 分配结果对话框 -->
|
||||
<ElDialog
|
||||
v-model="resultDialogVisible"
|
||||
:title="resultTitle"
|
||||
width="700px"
|
||||
>
|
||||
<ElDescriptions :column="2" border>
|
||||
<ElDescriptionsItem label="操作单号">{{ allocationResult.allocation_no }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="待处理总数">{{ allocationResult.total_count }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="成功数">
|
||||
<ElTag type="success">{{ allocationResult.success_count }}</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="失败数">
|
||||
<ElTag type="danger">{{ allocationResult.fail_count }}</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
|
||||
<div v-if="allocationResult.failed_items && allocationResult.failed_items.length > 0" style="margin-top: 20px">
|
||||
<ElDivider content-position="left">失败项详情</ElDivider>
|
||||
<ElTable :data="allocationResult.failed_items" border max-height="300">
|
||||
<ElTableColumn prop="iccid" label="ICCID" width="180" />
|
||||
<ElTableColumn prop="reason" label="失败原因" />
|
||||
</ElTable>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton type="primary" @click="resultDialogVisible = false">确定</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { CardService } from '@/api/modules'
|
||||
import { ElMessage, ElTag, ElUpload } from 'element-plus'
|
||||
import type { FormInstance, FormRules, UploadProps, UploadUserFile } from 'element-plus'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import type {
|
||||
StandaloneIotCard,
|
||||
StandaloneCardStatus,
|
||||
AllocateStandaloneCardsRequest,
|
||||
RecallStandaloneCardsRequest,
|
||||
AllocateStandaloneCardsResponse
|
||||
} from '@/types/api/card'
|
||||
|
||||
defineOptions({ name: 'StandaloneCardList' })
|
||||
|
||||
const loading = ref(false)
|
||||
const importDialogVisible = ref(false)
|
||||
const importLoading = ref(false)
|
||||
const allocateDialogVisible = ref(false)
|
||||
const allocateLoading = ref(false)
|
||||
const recallDialogVisible = ref(false)
|
||||
const recallLoading = ref(false)
|
||||
const resultDialogVisible = ref(false)
|
||||
const resultTitle = ref('')
|
||||
const tableRef = ref()
|
||||
const importFormRef = ref<FormInstance>()
|
||||
const allocateFormRef = ref<FormInstance>()
|
||||
const recallFormRef = ref<FormInstance>()
|
||||
const uploadRef = ref()
|
||||
const fileList = ref<UploadUserFile[]>([])
|
||||
const selectedCards = ref<StandaloneIotCard[]>([])
|
||||
const allocationResult = ref<AllocateStandaloneCardsResponse>({
|
||||
allocation_no: '',
|
||||
total_count: 0,
|
||||
success_count: 0,
|
||||
fail_count: 0,
|
||||
failed_items: null
|
||||
})
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
status: undefined,
|
||||
carrier_id: undefined,
|
||||
shop_id: undefined,
|
||||
iccid: '',
|
||||
msisdn: '',
|
||||
batch_no: '',
|
||||
package_id: undefined,
|
||||
is_distributed: undefined,
|
||||
is_replaced: undefined,
|
||||
iccid_start: '',
|
||||
iccid_end: ''
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
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>>({
|
||||
selection_type: 'list',
|
||||
to_shop_id: undefined,
|
||||
iccids: [],
|
||||
iccid_start: '',
|
||||
iccid_end: '',
|
||||
carrier_id: undefined,
|
||||
status: undefined,
|
||||
batch_no: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 批量分配表单验证规则
|
||||
const allocateRules = reactive<FormRules>({
|
||||
to_shop_id: [{ required: true, message: '请选择目标店铺', trigger: 'change' }],
|
||||
selection_type: [{ required: true, message: '请选择选卡方式', trigger: 'change' }],
|
||||
iccid_start: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (allocateForm.selection_type === 'range' && !value) {
|
||||
callback(new Error('请输入起始ICCID'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
iccid_end: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (allocateForm.selection_type === 'range' && !value) {
|
||||
callback(new Error('请输入结束ICCID'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 批量回收表单
|
||||
const recallForm = reactive<Partial<RecallStandaloneCardsRequest>>({
|
||||
selection_type: 'list',
|
||||
from_shop_id: undefined,
|
||||
iccids: [],
|
||||
iccid_start: '',
|
||||
iccid_end: '',
|
||||
carrier_id: undefined,
|
||||
batch_no: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 批量回收表单验证规则
|
||||
const recallRules = reactive<FormRules>({
|
||||
from_shop_id: [{ required: true, message: '请选择来源店铺', trigger: 'change' }],
|
||||
selection_type: [{ required: true, message: '请选择选卡方式', trigger: 'change' }],
|
||||
iccid_start: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (recallForm.selection_type === 'range' && !value) {
|
||||
callback(new Error('请输入起始ICCID'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
iccid_end: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (recallForm.selection_type === 'range' && !value) {
|
||||
callback(new Error('请输入结束ICCID'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 搜索表单配置
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '在库', value: 1 },
|
||||
{ label: '已分销', value: 2 },
|
||||
{ label: '已激活', value: 3 },
|
||||
{ label: '已停用', value: 4 }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '运营商',
|
||||
prop: 'carrier_id',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '中国移动', value: 1 },
|
||||
{ label: '中国联通', value: 2 },
|
||||
{ label: '中国电信', value: 3 }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'ICCID',
|
||||
prop: 'iccid',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入ICCID'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '卡接入号',
|
||||
prop: 'msisdn',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入卡接入号'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '批次号',
|
||||
prop: 'batch_no',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入批次号'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '是否已分销',
|
||||
prop: 'is_distributed',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: 'ICCID', prop: 'iccid' },
|
||||
{ label: 'IMSI', prop: 'imsi' },
|
||||
{ label: '卡接入号', prop: 'msisdn' },
|
||||
{ label: '运营商', prop: 'carrier_name' },
|
||||
{ label: '卡类型', prop: 'card_type' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '批次号', prop: 'batch_no' },
|
||||
{ label: '店铺名称', prop: 'shop_name' },
|
||||
{ label: '激活时间', prop: 'activated_at' },
|
||||
{ label: '创建时间', prop: 'created_at' }
|
||||
]
|
||||
|
||||
const cardList = ref<StandaloneIotCard[]>([])
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusType = (status: StandaloneCardStatus) => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return 'info'
|
||||
case 2:
|
||||
return 'warning'
|
||||
case 3:
|
||||
return 'success'
|
||||
case 4:
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: StandaloneCardStatus) => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return '在库'
|
||||
case 2:
|
||||
return '已分销'
|
||||
case 3:
|
||||
return '已激活'
|
||||
case 4:
|
||||
return '已停用'
|
||||
default:
|
||||
return '未知'
|
||||
}
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'iccid',
|
||||
label: 'ICCID',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'imsi',
|
||||
label: 'IMSI',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
prop: 'msisdn',
|
||||
label: '卡接入号',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'carrier_name',
|
||||
label: '运营商',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'card_type',
|
||||
label: '卡类型',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: StandaloneIotCard) => {
|
||||
return h(ElTag, { type: getStatusType(row.status) }, () => getStatusText(row.status))
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'batch_no',
|
||||
label: '批次号',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'shop_name',
|
||||
label: '店铺名称',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
prop: 'activated_at',
|
||||
label: '激活时间',
|
||||
width: 160,
|
||||
formatter: (row: StandaloneIotCard) => (row.activated_at ? formatDateTime(row.activated_at) : '-')
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 160,
|
||||
formatter: (row: StandaloneIotCard) => formatDateTime(row.created_at)
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
})
|
||||
|
||||
// 获取单卡列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
page_size: pagination.pageSize,
|
||||
...formFilters
|
||||
}
|
||||
// 清理空值
|
||||
Object.keys(params).forEach((key) => {
|
||||
if (params[key] === '' || params[key] === undefined) {
|
||||
delete params[key]
|
||||
}
|
||||
})
|
||||
|
||||
const res = await CardService.getStandaloneIotCards(params)
|
||||
if (res.code === 0) {
|
||||
cardList.value = res.data.list || []
|
||||
pagination.total = res.data.total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('获取单卡列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.page = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 刷新表格
|
||||
const handleRefresh = () => {
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getTableData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.page = newCurrentPage
|
||||
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 {
|
||||
const res = await CardService.importIotCards(
|
||||
importForm.file,
|
||||
importForm.carrier_id!,
|
||||
importForm.batch_no || undefined
|
||||
)
|
||||
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('导入任务已创建,请到任务管理页面查看导入进度')
|
||||
importDialogVisible.value = false
|
||||
getTableData()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('导入失败,请重试')
|
||||
} finally {
|
||||
importLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 表格选择变化
|
||||
const handleSelectionChange = (selection: StandaloneIotCard[]) => {
|
||||
selectedCards.value = selection
|
||||
}
|
||||
|
||||
// 显示批量分配对话框
|
||||
const showAllocateDialog = () => {
|
||||
if (selectedCards.value.length === 0) {
|
||||
ElMessage.warning('请先选择要分配的卡')
|
||||
return
|
||||
}
|
||||
allocateDialogVisible.value = true
|
||||
Object.assign(allocateForm, {
|
||||
selection_type: 'list',
|
||||
to_shop_id: undefined,
|
||||
iccids: selectedCards.value.map((card) => card.iccid),
|
||||
iccid_start: '',
|
||||
iccid_end: '',
|
||||
carrier_id: undefined,
|
||||
status: undefined,
|
||||
batch_no: '',
|
||||
remark: ''
|
||||
})
|
||||
if (allocateFormRef.value) {
|
||||
allocateFormRef.value.resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
// 显示批量回收对话框
|
||||
const showRecallDialog = () => {
|
||||
if (selectedCards.value.length === 0) {
|
||||
ElMessage.warning('请先选择要回收的卡')
|
||||
return
|
||||
}
|
||||
recallDialogVisible.value = true
|
||||
Object.assign(recallForm, {
|
||||
selection_type: 'list',
|
||||
from_shop_id: undefined,
|
||||
iccids: selectedCards.value.map((card) => card.iccid),
|
||||
iccid_start: '',
|
||||
iccid_end: '',
|
||||
carrier_id: undefined,
|
||||
batch_no: '',
|
||||
remark: ''
|
||||
})
|
||||
if (recallFormRef.value) {
|
||||
recallFormRef.value.resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭批量分配对话框
|
||||
const handleAllocateDialogClose = () => {
|
||||
if (allocateFormRef.value) {
|
||||
allocateFormRef.value.resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭批量回收对话框
|
||||
const handleRecallDialogClose = () => {
|
||||
if (recallFormRef.value) {
|
||||
recallFormRef.value.resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
// 执行批量分配
|
||||
const handleAllocate = async () => {
|
||||
if (!allocateFormRef.value) return
|
||||
|
||||
await allocateFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
// 根据选卡方式构建请求参数
|
||||
const params: Partial<AllocateStandaloneCardsRequest> = {
|
||||
selection_type: allocateForm.selection_type!,
|
||||
to_shop_id: allocateForm.to_shop_id!,
|
||||
remark: allocateForm.remark
|
||||
}
|
||||
|
||||
if (allocateForm.selection_type === 'list') {
|
||||
params.iccids = selectedCards.value.map((card) => card.iccid)
|
||||
if (params.iccids.length === 0) {
|
||||
ElMessage.warning('请先选择要分配的卡')
|
||||
return
|
||||
}
|
||||
} else if (allocateForm.selection_type === 'range') {
|
||||
params.iccid_start = allocateForm.iccid_start
|
||||
params.iccid_end = allocateForm.iccid_end
|
||||
} else if (allocateForm.selection_type === 'filter') {
|
||||
if (allocateForm.carrier_id) params.carrier_id = allocateForm.carrier_id
|
||||
if (allocateForm.status) params.status = allocateForm.status
|
||||
if (allocateForm.batch_no) params.batch_no = allocateForm.batch_no
|
||||
}
|
||||
|
||||
allocateLoading.value = true
|
||||
try {
|
||||
const res = await CardService.allocateStandaloneCards(params)
|
||||
|
||||
if (res.code === 0) {
|
||||
allocationResult.value = res.data
|
||||
resultTitle.value = '批量分配结果'
|
||||
allocateDialogVisible.value = false
|
||||
resultDialogVisible.value = true
|
||||
// 清空选择
|
||||
if (tableRef.value) {
|
||||
tableRef.value.clearSelection()
|
||||
}
|
||||
selectedCards.value = []
|
||||
// 刷新列表
|
||||
getTableData()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('批量分配失败,请重试')
|
||||
} finally {
|
||||
allocateLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 执行批量回收
|
||||
const handleRecall = async () => {
|
||||
if (!recallFormRef.value) return
|
||||
|
||||
await recallFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
// 根据选卡方式构建请求参数
|
||||
const params: Partial<RecallStandaloneCardsRequest> = {
|
||||
selection_type: recallForm.selection_type!,
|
||||
from_shop_id: recallForm.from_shop_id!,
|
||||
remark: recallForm.remark
|
||||
}
|
||||
|
||||
if (recallForm.selection_type === 'list') {
|
||||
params.iccids = selectedCards.value.map((card) => card.iccid)
|
||||
if (params.iccids.length === 0) {
|
||||
ElMessage.warning('请先选择要回收的卡')
|
||||
return
|
||||
}
|
||||
} else if (recallForm.selection_type === 'range') {
|
||||
params.iccid_start = recallForm.iccid_start
|
||||
params.iccid_end = recallForm.iccid_end
|
||||
} else if (recallForm.selection_type === 'filter') {
|
||||
if (recallForm.carrier_id) params.carrier_id = recallForm.carrier_id
|
||||
if (recallForm.batch_no) params.batch_no = recallForm.batch_no
|
||||
}
|
||||
|
||||
recallLoading.value = true
|
||||
try {
|
||||
const res = await CardService.recallStandaloneCards(params)
|
||||
|
||||
if (res.code === 0) {
|
||||
allocationResult.value = res.data
|
||||
resultTitle.value = '批量回收结果'
|
||||
recallDialogVisible.value = false
|
||||
resultDialogVisible.value = true
|
||||
// 清空选择
|
||||
if (tableRef.value) {
|
||||
tableRef.value.clearSelection()
|
||||
}
|
||||
selectedCards.value = []
|
||||
// 刷新列表
|
||||
getTableData()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('批量回收失败,请重试')
|
||||
} finally {
|
||||
recallLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.standalone-card-list-page {
|
||||
// Card list page styles
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user