fetch(modify):修改原来的bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m53s

This commit is contained in:
sexygoat
2026-01-31 11:18:37 +08:00
parent 8a1388608c
commit 31440b2904
62 changed files with 3025 additions and 1421 deletions

View File

@@ -19,13 +19,25 @@
>
<template #left>
<ElButton type="primary" @click="showImportDialog">导入ICCID</ElButton>
<ElButton type="success" :disabled="selectedCards.length === 0" @click="showAllocateDialog">
<ElButton
type="success"
:disabled="selectedCards.length === 0"
@click="showAllocateDialog"
>
批量分配
</ElButton>
<ElButton type="warning" :disabled="selectedCards.length === 0" @click="showRecallDialog">
<ElButton
type="warning"
:disabled="selectedCards.length === 0"
@click="showRecallDialog"
>
批量回收
</ElButton>
<ElButton type="info" :disabled="selectedCards.length === 0" @click="showSeriesBindingDialog">
<ElButton
type="info"
:disabled="selectedCards.length === 0"
@click="showSeriesBindingDialog"
>
批量设置套餐系列
</ElButton>
<ElButton type="primary" @click="cardDistribution">网卡分销</ElButton>
@@ -65,7 +77,11 @@
>
<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%">
<ElSelect
v-model="importForm.carrier_id"
placeholder="请选择运营商"
style="width: 100%"
>
<ElOption label="中国移动" :value="1" />
<ElOption label="中国联通" :value="2" />
<ElOption label="中国电信" :value="3" />
@@ -91,7 +107,7 @@
<template #tip>
<div class="el-upload__tip">
<div>只支持上传CSV文件且不超过10MB</div>
<div style="color: var(--el-color-info); margin-top: 4px">
<div style="margin-top: 4px; color: var(--el-color-info)">
CSV格式ICCID,MSISDN两列逗号分隔每行一条记录
</div>
</div>
@@ -116,9 +132,18 @@
width="600px"
@close="handleAllocateDialogClose"
>
<ElForm ref="allocateFormRef" :model="allocateForm" :rules="allocateRules" label-width="120px">
<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%">
<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" />
@@ -136,22 +161,40 @@
<div>已选择 {{ selectedCards.length }} 张卡</div>
</ElFormItem>
<ElFormItem v-if="allocateForm.selection_type === 'range'" label="起始ICCID" prop="iccid_start">
<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">
<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%">
<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%">
<ElSelect
v-model="allocateForm.status"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<ElOption label="在库" :value="1" />
<ElOption label="已分销" :value="2" />
<ElOption label="已激活" :value="3" />
@@ -163,7 +206,12 @@
</ElFormItem>
<ElFormItem label="备注">
<ElInput v-model="allocateForm.remark" type="textarea" :rows="3" placeholder="请输入备注信息" />
<ElInput
v-model="allocateForm.remark"
type="textarea"
:rows="3"
placeholder="请输入备注信息"
/>
</ElFormItem>
</ElForm>
<template #footer>
@@ -185,7 +233,11 @@
>
<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%">
<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" />
@@ -203,15 +255,28 @@
<div>已选择 {{ selectedCards.length }} 张卡</div>
</ElFormItem>
<ElFormItem v-if="recallForm.selection_type === 'range'" label="起始ICCID" prop="iccid_start">
<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">
<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%">
<ElSelect
v-model="recallForm.carrier_id"
placeholder="请选择运营商"
clearable
style="width: 100%"
>
<ElOption label="中国移动" :value="1" />
<ElOption label="中国联通" :value="2" />
<ElOption label="中国电信" :value="3" />
@@ -222,7 +287,12 @@
</ElFormItem>
<ElFormItem label="备注">
<ElInput v-model="recallForm.remark" type="textarea" :rows="3" placeholder="请输入备注信息" />
<ElInput
v-model="recallForm.remark"
type="textarea"
:rows="3"
placeholder="请输入备注信息"
/>
</ElFormItem>
</ElForm>
<template #footer>
@@ -236,14 +306,14 @@
</ElDialog>
<!-- 分配结果对话框 -->
<ElDialog
v-model="resultDialogVisible"
:title="resultTitle"
width="700px"
>
<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="操作单号">{{
allocationResult.allocation_no
}}</ElDescriptionsItem>
<ElDescriptionsItem label="待处理总数">{{
allocationResult.total_count
}}</ElDescriptionsItem>
<ElDescriptionsItem label="成功数">
<ElTag type="success">{{ allocationResult.success_count }}</ElTag>
</ElDescriptionsItem>
@@ -252,7 +322,10 @@
</ElDescriptionsItem>
</ElDescriptions>
<div v-if="allocationResult.failed_items && allocationResult.failed_items.length > 0" style="margin-top: 20px">
<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" />
@@ -274,7 +347,12 @@
width="600px"
@close="handleSeriesBindingDialogClose"
>
<ElForm ref="seriesBindingFormRef" :model="seriesBindingForm" :rules="seriesBindingRules" label-width="120px">
<ElForm
ref="seriesBindingFormRef"
:model="seriesBindingForm"
:rules="seriesBindingRules"
label-width="120px"
>
<ElFormItem label="已选择卡数">
<div>已选择 {{ selectedCards.length }} 张卡</div>
</ElFormItem>
@@ -307,11 +385,7 @@
</ElDialog>
<!-- 套餐系列绑定结果对话框 -->
<ElDialog
v-model="seriesBindingResultDialogVisible"
title="设置结果"
width="700px"
>
<ElDialog v-model="seriesBindingResultDialogVisible" title="设置结果" width="700px">
<ElDescriptions :column="2" border>
<ElDescriptionsItem label="成功数">
<ElTag type="success">{{ seriesBindingResult.success_count }}</ElTag>
@@ -321,7 +395,10 @@
</ElDescriptionsItem>
</ElDescriptions>
<div v-if="seriesBindingResult.failed_items && seriesBindingResult.failed_items.length > 0" style="margin-top: 20px">
<div
v-if="seriesBindingResult.failed_items && seriesBindingResult.failed_items.length > 0"
style="margin-top: 20px"
>
<ElDivider content-position="left">失败项详情</ElDivider>
<ElTable :data="seriesBindingResult.failed_items" border max-height="300">
<ElTableColumn prop="iccid" label="ICCID" width="180" />
@@ -331,11 +408,99 @@
<template #footer>
<div class="dialog-footer">
<ElButton type="primary" @click="seriesBindingResultDialogVisible = false">确定</ElButton>
<ElButton type="primary" @click="seriesBindingResultDialogVisible = false"
>确定</ElButton
>
</div>
</template>
</ElDialog>
<!-- 卡详情对话框 -->
<ElDialog v-model="cardDetailDialogVisible" title="卡片详情" width="900px">
<div v-if="cardDetailLoading" style="text-align: center; padding: 40px">
<ElIcon class="is-loading" :size="40"><Loading /></ElIcon>
<div style="margin-top: 16px">加载中...</div>
</div>
<ElDescriptions v-else-if="currentCardDetail" :column="3" border>
<ElDescriptionsItem label="卡ID">{{ currentCardDetail.id }}</ElDescriptionsItem>
<ElDescriptionsItem label="ICCID" :span="2">{{
currentCardDetail.iccid
}}</ElDescriptionsItem>
<ElDescriptionsItem label="卡接入号">{{
currentCardDetail.msisdn || '--'
}}</ElDescriptionsItem>
<ElDescriptionsItem label="运营商">{{
currentCardDetail.carrier_name || '--'
}}</ElDescriptionsItem>
<ElDescriptionsItem label="运营商类型">{{
getCarrierTypeText(currentCardDetail.carrier_type)
}}</ElDescriptionsItem>
<ElDescriptionsItem label="卡类型">{{
currentCardDetail.card_type || '--'
}}</ElDescriptionsItem>
<ElDescriptionsItem label="卡业务类型">{{
getCardCategoryText(currentCardDetail.card_category)
}}</ElDescriptionsItem>
<ElDescriptionsItem label="成本价">{{
formatCardPrice(currentCardDetail.cost_price)
}}</ElDescriptionsItem>
<ElDescriptionsItem label="分销价">{{
formatCardPrice(currentCardDetail.distribute_price)
}}</ElDescriptionsItem>
<ElDescriptionsItem label="状态">
<ElTag :type="getCardDetailStatusTagType(currentCardDetail.status)">
{{ getCardDetailStatusText(currentCardDetail.status) }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="激活状态">
<ElTag :type="currentCardDetail.activation_status === 1 ? 'success' : 'info'">
{{ currentCardDetail.activation_status === 1 ? '已激活' : '未激活' }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="实名状态">
<ElTag :type="currentCardDetail.real_name_status === 1 ? 'success' : 'warning'">
{{ currentCardDetail.real_name_status === 1 ? '已实名' : '未实名' }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="网络状态">
<ElTag :type="currentCardDetail.network_status === 1 ? 'success' : 'danger'">
{{ currentCardDetail.network_status === 1 ? '开机' : '停机' }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="累计流量使用"
>{{ currentCardDetail.data_usage_mb }} MB</ElDescriptionsItem
>
<ElDescriptionsItem label="首次佣金">
<ElTag :type="currentCardDetail.first_commission_paid ? 'success' : 'info'">
{{ currentCardDetail.first_commission_paid ? '已支付' : '未支付' }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="累计充值">{{
formatCardPrice(currentCardDetail.accumulated_recharge)
}}</ElDescriptionsItem>
<ElDescriptionsItem label="创建时间">{{
formatDateTime(currentCardDetail.created_at)
}}</ElDescriptionsItem>
<ElDescriptionsItem label="更新时间" :span="2">{{
formatDateTime(currentCardDetail.updated_at)
}}</ElDescriptionsItem>
</ElDescriptions>
<ElEmpty v-else description="未找到卡片信息" />
<template #footer>
<div class="dialog-footer">
<ElButton type="primary" @click="cardDetailDialogVisible = false">关闭</ElButton>
</div>
</template>
</ElDialog>
</ElCard>
</div>
</ArtTableFullScreen>
@@ -343,9 +508,11 @@
<script setup lang="ts">
import { h } from 'vue'
import { useRouter } from 'vue-router'
import { CardService, StorageService } from '@/api/modules'
import { ShopSeriesAllocationService } from '@/api/modules/shopSeriesAllocation'
import { ElMessage, ElTag, ElUpload } from 'element-plus'
import { ElMessage, ElTag, ElUpload, ElIcon } from 'element-plus'
import { Loading } from '@element-plus/icons-vue'
import type { FormInstance, FormRules, UploadProps, UploadUserFile } from 'element-plus'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
@@ -362,6 +529,7 @@
defineOptions({ name: 'StandaloneCardList' })
const router = useRouter()
const loading = ref(false)
const importDialogVisible = ref(false)
const importLoading = ref(false)
@@ -405,13 +573,17 @@
failed_items: null
})
// 卡详情弹窗相关
const cardDetailDialogVisible = ref(false)
const cardDetailLoading = ref(false)
const currentCardDetail = ref<any>(null)
// 搜索表单初始值
const initialSearchState = {
status: undefined,
carrier_id: undefined,
iccid: '',
msisdn: '',
batch_no: '',
is_distributed: undefined
}
@@ -576,15 +748,6 @@
placeholder: '请输入卡接入号'
}
},
{
label: '批次号',
prop: 'batch_no',
type: 'input',
config: {
clearable: true,
placeholder: '请输入批次号'
}
},
{
label: '是否已分销',
prop: 'is_distributed',
@@ -653,12 +816,88 @@
}
}
// 打开卡详情弹窗
const goToCardDetail = async (iccid: string) => {
cardDetailDialogVisible.value = true
cardDetailLoading.value = true
currentCardDetail.value = null
try {
const res = await CardService.getIotCardDetailByIccid(iccid)
if (res.code === 0 && res.data) {
currentCardDetail.value = res.data
} else {
ElMessage.error(res.message || '查询失败')
cardDetailDialogVisible.value = false
}
} catch (error: any) {
console.error('查询卡片详情失败:', error)
ElMessage.error(error?.message || '查询失败请检查ICCID是否正确')
cardDetailDialogVisible.value = false
} finally {
cardDetailLoading.value = false
}
}
// 卡详情辅助函数
const getCarrierTypeText = (type: string) => {
const typeMap: Record<string, string> = {
CMCC: '中国移动',
CUCC: '中国联通',
CTCC: '中国电信',
CBN: '中国广电'
}
return typeMap[type] || type
}
const getCardCategoryText = (category: string) => {
const categoryMap: Record<string, string> = {
normal: '普通卡',
industry: '行业卡'
}
return categoryMap[category] || category
}
const getCardDetailStatusText = (status: number) => {
const statusMap: Record<number, string> = {
1: '在库',
2: '已分销',
3: '已激活',
4: '已停用'
}
return statusMap[status] || '未知'
}
const getCardDetailStatusTagType = (status: number) => {
const typeMap: Record<number, any> = {
1: 'info',
2: 'warning',
3: 'success',
4: 'danger'
}
return typeMap[status] || 'info'
}
const formatCardPrice = (price: number) => {
return `¥${(price / 100).toFixed(2)}`
}
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
prop: 'iccid',
label: 'ICCID',
minWidth: 190
minWidth: 200,
formatter: (row: StandaloneIotCard) => {
return h(
'span',
{
style: { color: 'var(--el-color-primary)', cursor: 'pointer' },
onClick: () => goToCardDetail(row.iccid)
},
row.iccid
)
}
},
{
prop: 'msisdn',
@@ -754,7 +993,7 @@
{
prop: 'created_at',
label: '创建时间',
width: 160,
width: 180,
formatter: (row: StandaloneIotCard) => formatDateTime(row.created_at)
}
])
@@ -897,7 +1136,9 @@
})
if (importRes.code === 0) {
ElMessage.success(importRes.data.message || '导入任务已创建,请到任务管理页面查看导入进度')
ElMessage.success(
importRes.data.message || '导入任务已创建,请到任务管理页面查看导入进度'
)
importDialogVisible.value = false
getTableData()
}
@@ -1167,7 +1408,9 @@
} else if (res.data.success_count === 0) {
ElMessage.error('套餐系列绑定设置失败')
} else {
ElMessage.warning(`部分设置成功:成功 ${res.data.success_count} 项,失败 ${res.data.fail_count}`)
ElMessage.warning(
`部分设置成功:成功 ${res.data.success_count} 项,失败 ${res.data.fail_count}`
)
}
}
} catch (error) {