fetch(add): 运营商管理
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m23s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m23s
This commit is contained in:
208
src/views/asset-management/card-search/index.vue
Normal file
208
src/views/asset-management/card-search/index.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div class="card-search-page">
|
||||
<!-- 搜索区域 -->
|
||||
<ElCard shadow="never" class="search-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>单卡查询</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="search-content">
|
||||
<ElForm :model="searchForm" label-width="100px">
|
||||
<ElFormItem label="ICCID">
|
||||
<ElInput
|
||||
v-model="searchForm.iccid"
|
||||
placeholder="请输入ICCID"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<template #append>
|
||||
<ElButton type="primary" :loading="loading" @click="handleSearch">
|
||||
查询
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
</div>
|
||||
</ElCard>
|
||||
|
||||
<!-- 卡片详情区域 -->
|
||||
<ElCard v-if="cardDetail" shadow="never" class="detail-card" style="margin-top: 16px">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>卡片详情</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ElDescriptions :column="3" border>
|
||||
<ElDescriptionsItem label="卡ID">{{ cardDetail.id }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="ICCID" :span="2">{{ cardDetail.iccid }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="IMSI">{{ cardDetail.imsi || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="卡接入号">{{ cardDetail.msisdn || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="运营商">{{ cardDetail.carrier_name }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="运营商类型">{{ getCarrierTypeText(cardDetail.carrier_type) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="卡类型">{{ cardDetail.card_type }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="卡业务类型">{{ getCardCategoryText(cardDetail.card_category) }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="状态">
|
||||
<ElTag :type="getStatusTagType(cardDetail.status)">
|
||||
{{ getStatusText(cardDetail.status) }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="激活状态">
|
||||
<ElTag :type="cardDetail.activation_status === 1 ? 'success' : 'info'">
|
||||
{{ cardDetail.activation_status === 1 ? '已激活' : '未激活' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="网络状态">
|
||||
<ElTag :type="cardDetail.network_status === 1 ? 'success' : 'danger'">
|
||||
{{ cardDetail.network_status === 1 ? '开机' : '停机' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="实名状态">
|
||||
<ElTag :type="cardDetail.real_name_status === 1 ? 'success' : 'warning'">
|
||||
{{ cardDetail.real_name_status === 1 ? '已实名' : '未实名' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="批次号">{{ cardDetail.batch_no }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="供应商">{{ cardDetail.supplier || '--' }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="店铺名称">{{ cardDetail.shop_name || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="成本价">{{ formatPrice(cardDetail.cost_price) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="分销价">{{ formatPrice(cardDetail.distribute_price) }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="累计流量使用">{{ cardDetail.data_usage_mb }} MB</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="激活时间">{{ cardDetail.activated_at || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="创建时间">{{ cardDetail.created_at }}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</ElCard>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<ElEmpty v-if="searched && !cardDetail && !loading" description="未找到相关卡片信息" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { CardService } from '@/api/modules/card'
|
||||
|
||||
defineOptions({ name: 'CardSearch' })
|
||||
|
||||
const loading = ref(false)
|
||||
const searched = ref(false)
|
||||
const searchForm = reactive({
|
||||
iccid: ''
|
||||
})
|
||||
const cardDetail = ref<any>(null)
|
||||
|
||||
// 查询卡片详情
|
||||
const handleSearch = async () => {
|
||||
if (!searchForm.iccid.trim()) {
|
||||
ElMessage.warning('请输入ICCID')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
searched.value = true
|
||||
cardDetail.value = null
|
||||
|
||||
try {
|
||||
const res = await CardService.getIotCardDetailByIccid(searchForm.iccid.trim())
|
||||
if (res.code === 0 && res.data) {
|
||||
cardDetail.value = res.data
|
||||
ElMessage.success('查询成功')
|
||||
} else {
|
||||
ElMessage.error(res.message || '查询失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('查询卡片详情失败:', error)
|
||||
ElMessage.error(error?.message || '查询失败,请检查ICCID是否正确')
|
||||
} finally {
|
||||
loading.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 getStatusText = (status: number) => {
|
||||
const statusMap: Record<number, string> = {
|
||||
1: '在库',
|
||||
2: '已分销',
|
||||
3: '已激活',
|
||||
4: '已停用'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusTagType = (status: number) => {
|
||||
const typeMap: Record<number, any> = {
|
||||
1: 'info',
|
||||
2: 'warning',
|
||||
3: 'success',
|
||||
4: 'danger'
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 格式化价格(分转元)
|
||||
const formatPrice = (price: number) => {
|
||||
return `¥${(price / 100).toFixed(2)}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-search-page {
|
||||
padding: 16px;
|
||||
|
||||
.card-header {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.search-content {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
animation: fadeIn 0.3s ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -258,14 +258,14 @@
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请选择状态',
|
||||
options: [
|
||||
{ label: '在库', value: 1 },
|
||||
{ label: '已分销', value: 2 },
|
||||
{ label: '已激活', value: 3 },
|
||||
{ label: '已停用', value: 4 }
|
||||
]
|
||||
}
|
||||
placeholder: '请选择状态'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '在库', value: 1 },
|
||||
{ label: '已分销', value: 2 },
|
||||
{ label: '已激活', value: 3 },
|
||||
{ label: '已停用', value: 4 }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '批次号',
|
||||
|
||||
152
src/views/asset-management/device-search/index.vue
Normal file
152
src/views/asset-management/device-search/index.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div class="device-search-page">
|
||||
<!-- 搜索区域 -->
|
||||
<ElCard shadow="never" class="search-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>设备查询</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="search-content">
|
||||
<ElForm :model="searchForm" label-width="100px">
|
||||
<ElFormItem label="设备号(IMEI)">
|
||||
<ElInput
|
||||
v-model="searchForm.imei"
|
||||
placeholder="请输入设备号(IMEI)"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<template #append>
|
||||
<ElButton type="primary" :loading="loading" @click="handleSearch">
|
||||
查询
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
</div>
|
||||
</ElCard>
|
||||
|
||||
<!-- 设备详情区域 -->
|
||||
<ElCard v-if="deviceDetail" shadow="never" class="detail-card" style="margin-top: 16px">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>设备详情</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ElDescriptions :column="3" border>
|
||||
<ElDescriptionsItem label="设备ID">{{ deviceDetail.id }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="设备号" :span="2">{{ deviceDetail.device_no }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="设备名称">{{ deviceDetail.device_name || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="设备型号">{{ deviceDetail.device_model || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="设备类型">{{ deviceDetail.device_type || '--' }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="制造商">{{ deviceDetail.manufacturer || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="最大插槽数">{{ deviceDetail.max_sim_slots }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="已绑定卡数量">{{ deviceDetail.bound_card_count }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="状态">
|
||||
<ElTag :type="getStatusTagType(deviceDetail.status)">
|
||||
{{ deviceDetail.status_name }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="店铺名称">{{ deviceDetail.shop_name || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="批次号">{{ deviceDetail.batch_no }}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="激活时间">{{ deviceDetail.activated_at || '--' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="创建时间">{{ deviceDetail.created_at }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="更新时间">{{ deviceDetail.updated_at }}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</ElCard>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<ElEmpty v-if="searched && !deviceDetail && !loading" description="未找到相关设备信息" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { DeviceService } from '@/api/modules/device'
|
||||
|
||||
defineOptions({ name: 'DeviceSearch' })
|
||||
|
||||
const loading = ref(false)
|
||||
const searched = ref(false)
|
||||
const searchForm = reactive({
|
||||
imei: ''
|
||||
})
|
||||
const deviceDetail = ref<any>(null)
|
||||
|
||||
// 查询设备详情
|
||||
const handleSearch = async () => {
|
||||
if (!searchForm.imei.trim()) {
|
||||
ElMessage.warning('请输入设备号(IMEI)')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
searched.value = true
|
||||
deviceDetail.value = null
|
||||
|
||||
try {
|
||||
const res = await DeviceService.getDeviceByImei(searchForm.imei.trim())
|
||||
if (res.code === 0 && res.data) {
|
||||
deviceDetail.value = res.data
|
||||
ElMessage.success('查询成功')
|
||||
} else {
|
||||
ElMessage.error(res.message || '查询失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('查询设备详情失败:', error)
|
||||
ElMessage.error(error?.message || '查询失败,请检查设备号是否正确')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusTagType = (status: number) => {
|
||||
const typeMap: Record<number, any> = {
|
||||
1: 'info', // 在库
|
||||
2: 'warning', // 已分销
|
||||
3: 'success', // 已激活
|
||||
4: 'danger' // 已停用
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.device-search-page {
|
||||
padding: 16px;
|
||||
|
||||
.card-header {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.search-content {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
animation: fadeIn 0.3s ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -140,18 +140,15 @@
|
||||
const contextMenuItems: MenuItemType[] = [
|
||||
{
|
||||
key: 'cardOperation',
|
||||
label: '卡务操作',
|
||||
icon: ''
|
||||
label: '卡务操作'
|
||||
},
|
||||
{
|
||||
key: 'download',
|
||||
label: '下载',
|
||||
icon: ''
|
||||
label: '下载'
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
label: '删除',
|
||||
icon: '',
|
||||
showLine: true
|
||||
}
|
||||
]
|
||||
|
||||
464
src/views/finance/carrier-management/index.vue
Normal file
464
src/views/finance/carrier-management/index.vue
Normal file
@@ -0,0 +1,464 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="carrier-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
label-width="85"
|
||||
:show-expand="false"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<ElButton @click="showDialog('add')">新增运营商</ElButton>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="carrierList"
|
||||
:currentPage="pagination.page"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增运营商' : '编辑运营商'"
|
||||
width="30%"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||
<ElFormItem label="运营商编码" prop="carrier_code">
|
||||
<ElInput
|
||||
v-model="form.carrier_code"
|
||||
placeholder="请输入运营商编码"
|
||||
:disabled="dialogType === 'edit'"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="运营商名称" prop="carrier_name">
|
||||
<ElInput v-model="form.carrier_name" placeholder="请输入运营商名称" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="运营商类型" prop="carrier_type">
|
||||
<ElSelect
|
||||
v-model="form.carrier_type"
|
||||
placeholder="请选择运营商类型"
|
||||
style="width: 100%"
|
||||
:disabled="dialogType === 'edit'"
|
||||
>
|
||||
<ElOption
|
||||
v-for="item in CARRIER_TYPE_OPTIONS"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="运营商描述" prop="description">
|
||||
<ElInput
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入运营商描述"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)" :loading="submitLoading">
|
||||
提交
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h, watch, nextTick } from 'vue'
|
||||
import { CarrierService } from '@/api/modules'
|
||||
import { ElMessage, ElMessageBox, ElTag, ElSwitch } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { Carrier, CarrierType } from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import {
|
||||
CommonStatus,
|
||||
getStatusText,
|
||||
CARRIER_TYPE_OPTIONS,
|
||||
getCarrierTypeLabel,
|
||||
getCarrierTypeColor
|
||||
} from '@/config/constants'
|
||||
|
||||
defineOptions({ name: 'CarrierManagement' })
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const tableRef = ref()
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
carrier_name: '',
|
||||
carrier_type: null,
|
||||
status: null
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({ ...initialSearchState })
|
||||
|
||||
// 搜索表单配置
|
||||
const searchFormItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '运营商名称',
|
||||
prop: 'carrier_name',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入运营商名称'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '运营商类型',
|
||||
prop: 'carrier_type',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请选择运营商类型'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '中国移动', value: 'CMCC' },
|
||||
{ label: '中国联通', value: 'CUCC' },
|
||||
{ label: '中国电信', value: 'CTCC' },
|
||||
{ label: '中国广电', value: 'CBN' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请选择状态'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '启用', value: CommonStatus.ENABLED },
|
||||
{ label: '禁用', value: CommonStatus.DISABLED }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '运营商编码', prop: 'carrier_code' },
|
||||
{ label: '运营商名称', prop: 'carrier_name' },
|
||||
{ label: '运营商类型', prop: 'carrier_type' },
|
||||
{ label: '运营商描述', prop: 'description' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '创建时间', prop: 'created_at' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
carrier_code: [
|
||||
{ required: true, message: '请输入运营商编码', trigger: 'blur' },
|
||||
{ min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' }
|
||||
],
|
||||
carrier_name: [
|
||||
{ required: true, message: '请输入运营商名称', trigger: 'blur' },
|
||||
{ min: 1, max: 100, message: '长度在 1 到 100 个字符', trigger: 'blur' }
|
||||
],
|
||||
carrier_type: [{ required: true, message: '请选择运营商类型', trigger: 'change' }],
|
||||
description: [{ max: 500, message: '描述不能超过500个字符', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const form = reactive<any>({
|
||||
id: 0,
|
||||
carrier_code: '',
|
||||
carrier_name: '',
|
||||
carrier_type: null,
|
||||
description: ''
|
||||
})
|
||||
|
||||
const carrierList = ref<Carrier[]>([])
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'carrier_code',
|
||||
label: '运营商编码',
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
prop: 'carrier_name',
|
||||
label: '运营商名称',
|
||||
minWidth: 150
|
||||
},
|
||||
{
|
||||
prop: 'carrier_type',
|
||||
label: '运营商类型',
|
||||
width: 120,
|
||||
formatter: (row: any) => {
|
||||
const color = getCarrierTypeColor(row.carrier_type)
|
||||
return h(
|
||||
ElTag,
|
||||
{ style: `background-color: ${color}; border-color: ${color}; color: #fff;` },
|
||||
() => getCarrierTypeLabel(row.carrier_type)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'description',
|
||||
label: '运营商描述',
|
||||
minWidth: 200,
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: any) => {
|
||||
return h(ElSwitch, {
|
||||
modelValue: row.status,
|
||||
activeValue: CommonStatus.ENABLED,
|
||||
inactiveValue: CommonStatus.DISABLED,
|
||||
activeText: getStatusText(CommonStatus.ENABLED),
|
||||
inactiveText: getStatusText(CommonStatus.DISABLED),
|
||||
inlinePrompt: true,
|
||||
'onUpdate:modelValue': (val: string | number | boolean) =>
|
||||
handleStatusChange(row, val as number)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 180,
|
||||
formatter: (row: any) => formatDateTime(row.created_at)
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 150,
|
||||
fixed: 'right',
|
||||
formatter: (row: any) => {
|
||||
return h('div', { style: 'display: flex; gap: 8px;' }, [
|
||||
h(ArtButtonTable, {
|
||||
type: 'edit',
|
||||
onClick: () => showDialog('edit', row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
type: 'delete',
|
||||
onClick: () => deleteCarrier(row)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
})
|
||||
|
||||
// 监听对话框关闭,清除验证状态
|
||||
watch(dialogVisible, (val) => {
|
||||
if (!val) {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 获取运营商列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
page_size: pagination.pageSize,
|
||||
carrier_name: searchForm.carrier_name || undefined,
|
||||
carrier_type: searchForm.carrier_type || undefined,
|
||||
status: searchForm.status !== null ? searchForm.status : undefined
|
||||
}
|
||||
const res = await CarrierService.getCarriers(params)
|
||||
if (res.code === 0) {
|
||||
carrierList.value = res.data.items || []
|
||||
pagination.total = res.data.total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const handleReset = () => {
|
||||
Object.assign(searchForm, { ...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 dialogType = ref('add')
|
||||
|
||||
// 显示新增/编辑对话框
|
||||
const showDialog = (type: string, row?: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogType.value = type
|
||||
|
||||
if (type === 'edit' && row) {
|
||||
form.id = row.id
|
||||
form.carrier_code = row.carrier_code
|
||||
form.carrier_name = row.carrier_name
|
||||
form.carrier_type = row.carrier_type
|
||||
form.description = row.description
|
||||
} else {
|
||||
form.id = 0
|
||||
form.carrier_code = ''
|
||||
form.carrier_name = ''
|
||||
form.carrier_type = null
|
||||
form.description = ''
|
||||
}
|
||||
|
||||
// 清除表单验证状态
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
// 删除运营商
|
||||
const deleteCarrier = (row: any) => {
|
||||
ElMessageBox.confirm(`确定删除运营商 ${row.carrier_name} 吗?`, '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
await CarrierService.deleteCarrier(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消删除
|
||||
})
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const data = {
|
||||
carrier_code: form.carrier_code,
|
||||
carrier_name: form.carrier_name,
|
||||
carrier_type: form.carrier_type as CarrierType,
|
||||
description: form.description || undefined
|
||||
}
|
||||
|
||||
if (dialogType.value === 'add') {
|
||||
await CarrierService.createCarrier(data)
|
||||
ElMessage.success('新增成功')
|
||||
} else {
|
||||
const updateData = {
|
||||
carrier_name: form.carrier_name,
|
||||
description: form.description || undefined
|
||||
}
|
||||
await CarrierService.updateCarrier(form.id, updateData)
|
||||
ElMessage.success('修改成功')
|
||||
}
|
||||
|
||||
dialogVisible.value = false
|
||||
formEl.resetFields()
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 状态切换
|
||||
const handleStatusChange = async (row: any, newStatus: number) => {
|
||||
const oldStatus = row.status
|
||||
// 先更新UI
|
||||
row.status = newStatus
|
||||
try {
|
||||
await CarrierService.updateCarrierStatus(row.id, newStatus)
|
||||
ElMessage.success('状态切换成功')
|
||||
} catch (error) {
|
||||
// 切换失败,恢复原状态
|
||||
row.status = oldStatus
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.carrier-page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -177,16 +177,32 @@
|
||||
<div class="operation-group primary-operations">
|
||||
<h4 class="group-title">主要操作</h4>
|
||||
<div class="operation-buttons">
|
||||
<ElButton @click="handleOperation('recharge')" class="operation-btn">
|
||||
<ElButton
|
||||
@click="handleOperation('recharge')"
|
||||
:loading="operationLoading"
|
||||
class="operation-btn"
|
||||
>
|
||||
套餐充值
|
||||
</ElButton>
|
||||
<ElButton @click="handleOperation('activate')" class="operation-btn">
|
||||
<ElButton
|
||||
@click="handleOperation('activate')"
|
||||
:loading="operationLoading"
|
||||
class="operation-btn"
|
||||
>
|
||||
激活
|
||||
</ElButton>
|
||||
<ElButton @click="handleOperation('suspend')" class="operation-btn">
|
||||
<ElButton
|
||||
@click="handleOperation('suspend')"
|
||||
:loading="operationLoading"
|
||||
class="operation-btn"
|
||||
>
|
||||
保号停机
|
||||
</ElButton>
|
||||
<ElButton @click="handleOperation('resume')" class="operation-btn">
|
||||
<ElButton
|
||||
@click="handleOperation('resume')"
|
||||
:loading="operationLoading"
|
||||
class="operation-btn"
|
||||
>
|
||||
保号复机
|
||||
</ElButton>
|
||||
</div>
|
||||
@@ -293,20 +309,39 @@
|
||||
ElEmpty,
|
||||
ElSkeleton,
|
||||
ElDescriptions,
|
||||
ElDescriptionsItem
|
||||
ElDescriptionsItem,
|
||||
ElMessageBox
|
||||
} from 'element-plus'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { EnterpriseService } from '@/api/modules/enterprise'
|
||||
|
||||
defineOptions({ name: 'SingleCard' })
|
||||
|
||||
const route = useRoute()
|
||||
const loading = ref(true)
|
||||
const operationLoading = ref(false)
|
||||
|
||||
// 从 URL 获取参数
|
||||
const enterpriseId = computed(() => {
|
||||
const id = route.query.enterpriseId || route.query.enterprise_id
|
||||
return id ? Number(id) : null
|
||||
})
|
||||
|
||||
const cardId = computed(() => {
|
||||
const urlId = route.query.cardId || route.query.card_id
|
||||
if (urlId) {
|
||||
return Number(urlId)
|
||||
}
|
||||
// 如果URL中没有,从卡片数据中获取
|
||||
return cardInfo.value?.id ? Number(cardInfo.value.id) : null
|
||||
})
|
||||
|
||||
// 卡片信息
|
||||
const cardInfo = ref<any>(null)
|
||||
|
||||
// 模拟卡片数据
|
||||
const mockCardData = {
|
||||
id: 1, // 卡片ID
|
||||
iccid: '8986062357007989203',
|
||||
accessNumber: '1440012345678',
|
||||
imei: '860123456789012',
|
||||
@@ -411,7 +446,7 @@
|
||||
}
|
||||
|
||||
// 处理操作按钮点击
|
||||
const handleOperation = (operation: string) => {
|
||||
const handleOperation = async (operation: string) => {
|
||||
if (!cardInfo.value) {
|
||||
ElMessage.warning('请先查询卡片信息')
|
||||
return
|
||||
@@ -439,6 +474,75 @@
|
||||
deviceOperation: '设备操作'
|
||||
}
|
||||
|
||||
// 保号停机
|
||||
if (operation === 'suspend') {
|
||||
// 检查必需的参数
|
||||
if (!enterpriseId.value || !cardId.value) {
|
||||
ElMessage.error('缺少必需的参数:企业ID或卡片ID')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确认要对卡片 ${cardInfo.value.iccid} 进行保号停机操作吗?`,
|
||||
'保号停机确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
|
||||
operationLoading.value = true
|
||||
await EnterpriseService.suspendCard(enterpriseId.value, cardId.value)
|
||||
ElMessage.success('保号停机操作成功')
|
||||
// 刷新卡片信息
|
||||
await fetchCardDetail()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error?.message || '保号停机操作失败')
|
||||
}
|
||||
} finally {
|
||||
operationLoading.value = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 保号复机
|
||||
if (operation === 'resume') {
|
||||
// 检查必需的参数
|
||||
if (!enterpriseId.value || !cardId.value) {
|
||||
ElMessage.error('缺少必需的参数:企业ID或卡片ID')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确认要对卡片 ${cardInfo.value.iccid} 进行保号复机操作吗?`,
|
||||
'保号复机确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
|
||||
operationLoading.value = true
|
||||
await EnterpriseService.resumeCard(enterpriseId.value, cardId.value)
|
||||
ElMessage.success('保号复机操作成功')
|
||||
// 刷新卡片信息
|
||||
await fetchCardDetail()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error?.message || '保号复机操作失败')
|
||||
}
|
||||
} finally {
|
||||
operationLoading.value = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 其他操作暂时只显示提示
|
||||
ElMessage.info(`执行${operationNames[operation] || operation}操作`)
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user