Initial commit: One Pipe System

完整的管理系统,包含账户管理、卡片管理、套餐管理、财务管理等功能模块。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sexygoat
2026-01-22 16:35:33 +08:00
commit 222e5bb11a
495 changed files with 145440 additions and 0 deletions

View File

@@ -0,0 +1,468 @@
<template>
<ArtTableFullScreen>
<div class="single-card-page" id="table-full-screen">
<!-- 网卡信息卡片 -->
<ElCard shadow="never" class="card-info-card" style="margin-bottom: 16px">
<template #header>
<span>网卡信息</span>
</template>
<ElForm :model="cardInfo" label-width="120px" :inline="false">
<ElRow :gutter="24">
<ElCol :span="8">
<ElFormItem label="ICCID:">
<span>{{ cardInfo.iccid }}</span>
</ElFormItem>
</ElCol>
<ElCol :span="8">
<ElFormItem label="IMSI:">
<span>{{ cardInfo.imsi }}</span>
</ElFormItem>
</ElCol>
<ElCol :span="8">
<ElFormItem label="手机号码:">
<span>{{ cardInfo.msisdn }}</span>
</ElFormItem>
</ElCol>
</ElRow>
<ElRow :gutter="24">
<ElCol :span="8">
<ElFormItem label="运营商:">
<ElTag :type="getOperatorTagType(cardInfo.operator)">{{
cardInfo.operatorName
}}</ElTag>
</ElFormItem>
</ElCol>
<ElCol :span="8">
<ElFormItem label="网络类型:">
<span>{{ cardInfo.networkType }}</span>
</ElFormItem>
</ElCol>
<ElCol :span="8">
<ElFormItem label="状态:">
<ElTag :type="getStatusTagType(cardInfo.status)">{{ cardInfo.statusName }}</ElTag>
</ElFormItem>
</ElCol>
</ElRow>
</ElForm>
</ElCard>
<!-- 操作区域 -->
<ElCard shadow="never" class="operation-card" style="margin-bottom: 16px">
<template #header>
<span>操作区域</span>
</template>
<div class="operation-buttons">
<ElButton type="primary" @click="activateCard" :disabled="cardInfo.status === '1'"
>激活网卡</ElButton
>
<ElButton type="warning" @click="suspendCard" :disabled="cardInfo.status === '2'"
>停用网卡</ElButton
>
<ElButton type="success" @click="showRechargeDialog">充值</ElButton>
<ElButton type="info" @click="queryTraffic">流量查询</ElButton>
<ElButton type="danger" @click="resetCard">重置网卡</ElButton>
<ElButton @click="diagnoseCard">网卡诊断</ElButton>
</div>
</ElCard>
<!-- 流量信息 -->
<ElCard shadow="never" class="traffic-card" style="margin-bottom: 16px">
<template #header>
<span>流量信息</span>
</template>
<ElRow :gutter="24">
<ElCol :span="6">
<div class="traffic-item">
<div class="traffic-value">{{ trafficInfo.totalTraffic }}</div>
<div class="traffic-label">总流量</div>
</div>
</ElCol>
<ElCol :span="6">
<div class="traffic-item">
<div class="traffic-value used">{{ trafficInfo.usedTraffic }}</div>
<div class="traffic-label">已用流量</div>
</div>
</ElCol>
<ElCol :span="6">
<div class="traffic-item">
<div class="traffic-value remaining">{{ trafficInfo.remainingTraffic }}</div>
<div class="traffic-label">剩余流量</div>
</div>
</ElCol>
<ElCol :span="6">
<div class="traffic-item">
<div class="traffic-value percentage">{{ trafficInfo.usagePercentage }}%</div>
<div class="traffic-label">使用率</div>
</div>
</ElCol>
</ElRow>
<ElProgress :percentage="parseInt(trafficInfo.usagePercentage)" style="margin-top: 16px" />
</ElCard>
<!-- 使用记录 -->
<ElCard shadow="never" class="art-table-card">
<template #header>
<span>使用记录</span>
<ElButton style="float: right" @click="refreshUsageRecords">刷新</ElButton>
</template>
<ArtTable
ref="tableRef"
row-key="id"
:loading="loading"
:data="usageRecords"
:currentPage="pagination.currentPage"
:pageSize="pagination.pageSize"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<template #default>
<ElTableColumn v-for="col in usageColumns" :key="col.prop || col.type" v-bind="col" />
</template>
</ArtTable>
</ElCard>
<!-- 充值对话框 -->
<ElDialog v-model="rechargeDialogVisible" title="网卡充值" width="400px" align-center>
<ElForm
ref="rechargeFormRef"
:model="rechargeForm"
:rules="rechargeRules"
label-width="100px"
>
<ElFormItem label="充值金额" prop="amount">
<ElInput v-model="rechargeForm.amount" placeholder="请输入充值金额">
<template #append></template>
</ElInput>
</ElFormItem>
<ElFormItem label="充值方式" prop="method">
<ElSelect v-model="rechargeForm.method" placeholder="请选择充值方式">
<ElOption label="支付宝" value="alipay" />
<ElOption label="微信支付" value="wechat" />
<ElOption label="银联支付" value="unionpay" />
</ElSelect>
</ElFormItem>
</ElForm>
<template #footer>
<ElButton @click="rechargeDialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="handleRecharge">确认充值</ElButton>
</template>
</ElDialog>
</div>
</ArtTableFullScreen>
</template>
<script setup lang="ts">
import { h } from 'vue'
import { ElTag, ElMessageBox, ElMessage, FormInstance } from 'element-plus'
import { useRoute } from 'vue-router'
import type { FormRules } from 'element-plus'
defineOptions({ name: 'SingleCard' })
const loading = ref(false)
const rechargeDialogVisible = ref(false)
const route = useRoute()
// 网卡信息
const cardInfo = reactive({
iccid: '89860123456789012345',
imsi: '460012345678901',
msisdn: '13800138001',
operator: 'mobile',
operatorName: '中国移动',
networkType: '4G',
status: '1',
statusName: '激活',
activatedDate: '2024-01-15',
expiryDate: '2025-01-15'
})
// 流量信息
const trafficInfo = reactive({
totalTraffic: '10GB',
usedTraffic: '2.5GB',
remainingTraffic: '7.5GB',
usagePercentage: '25'
})
const pagination = reactive({
currentPage: 1,
pageSize: 10,
total: 0
})
// 使用记录
const usageRecords = ref([
{
id: 1,
date: '2024-11-07',
time: '14:30:25',
dataUsage: '125.6MB',
fee: '0.12',
location: '北京市朝阳区'
},
{
id: 2,
date: '2024-11-07',
time: '13:45:12',
dataUsage: '256.8MB',
fee: '0.26',
location: '北京市朝阳区'
}
])
// 充值表单
const rechargeForm = reactive({
amount: '',
method: ''
})
const rechargeFormRef = ref<FormInstance>()
// 表格列配置
const usageColumns = [
{
prop: 'date',
label: '日期',
width: 120
},
{
prop: 'time',
label: '时间',
width: 100
},
{
prop: 'dataUsage',
label: '流量使用量',
width: 120
},
{
prop: 'fee',
label: '费用(元)',
width: 100,
formatter: (row: any) => `¥${row.fee}`
},
{
prop: 'location',
label: '位置',
minWidth: 140
}
]
// 获取运营商标签类型
const getOperatorTagType = (operator: string) => {
switch (operator) {
case 'mobile':
return 'success'
case 'unicom':
return 'primary'
case 'telecom':
return 'warning'
default:
return 'info'
}
}
// 获取状态标签类型
const getStatusTagType = (status: string) => {
switch (status) {
case '1':
return 'success'
case '2':
return 'danger'
case '3':
return 'warning'
case '4':
return 'info'
default:
return 'info'
}
}
// 激活网卡
const activateCard = () => {
ElMessageBox.confirm('确定要激活该网卡吗?', '激活网卡', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}).then(() => {
cardInfo.status = '1'
cardInfo.statusName = '激活'
ElMessage.success('网卡激活成功')
})
}
// 停用网卡
const suspendCard = () => {
ElMessageBox.confirm('确定要停用该网卡吗?', '停用网卡', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
cardInfo.status = '2'
cardInfo.statusName = '停用'
ElMessage.success('网卡停用成功')
})
}
// 显示充值对话框
const showRechargeDialog = () => {
rechargeDialogVisible.value = true
if (rechargeFormRef.value) {
rechargeFormRef.value.resetFields()
}
}
// 流量查询
const queryTraffic = () => {
ElMessage.info('正在查询流量信息...')
// 这里可以调用API查询最新的流量信息
}
// 重置网卡
const resetCard = () => {
ElMessageBox.confirm('确定要重置该网卡吗?重置后网卡需要重新激活。', '重置网卡', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
}).then(() => {
ElMessage.success('网卡重置成功')
})
}
// 网卡诊断
const diagnoseCard = () => {
ElMessage.info('正在进行网卡诊断...')
setTimeout(() => {
ElMessage.success('网卡诊断完成,网卡状态正常')
}, 2000)
}
// 充值验证规则
const rechargeRules: FormRules = {
amount: [
{ required: true, message: '请输入充值金额', trigger: 'blur' },
{ pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的金额格式', trigger: 'blur' }
],
method: [{ required: true, message: '请选择充值方式', trigger: 'change' }]
}
// 处理充值
const handleRecharge = async () => {
if (!rechargeFormRef.value) return
await rechargeFormRef.value.validate((valid) => {
if (valid) {
ElMessage.success('充值成功')
rechargeDialogVisible.value = false
}
})
}
// 刷新使用记录
const refreshUsageRecords = () => {
ElMessage.info('正在刷新使用记录...')
// 这里可以调用API获取最新的使用记录
}
// 处理表格分页变化
const handleSizeChange = (newPageSize: number) => {
pagination.pageSize = newPageSize
// 重新获取数据
}
const handleCurrentChange = (newCurrentPage: number) => {
pagination.currentPage = newCurrentPage
// 重新获取数据
}
onMounted(() => {
// 检查是否有传递的ICCID参数
const iccidFromQuery = route.query.iccid as string
if (iccidFromQuery) {
// 如果有ICCID参数更新卡片信息
cardInfo.iccid = iccidFromQuery
// 可以在这里根据ICCID获取完整的卡片信息
console.log('从网卡明细跳转ICCID:', iccidFromQuery)
// 模拟根据ICCID获取卡片详细信息
loadCardInfoByIccid(iccidFromQuery)
}
// 初始化数据
pagination.total = usageRecords.value.length
})
// 根据ICCID加载卡片信息
const loadCardInfoByIccid = async (iccid: string) => {
loading.value = true
try {
// 这里应该调用API根据ICCID获取卡片详细信息
// 模拟API调用
await new Promise((resolve) => setTimeout(resolve, 500))
// 模拟更新卡片信息实际应该从API获取
Object.assign(cardInfo, {
iccid: iccid,
imsi: '460012345678901',
msisdn: '13800138001',
operator: 'mobile',
operatorName: '中国移动',
networkType: '4G',
status: '1',
statusName: '激活',
activatedDate: '2024-01-15',
expiryDate: '2025-01-15'
})
ElMessage.success(`已加载ICCID ${iccid} 的详细信息`)
} catch (error) {
console.error('获取卡片信息失败:', error)
ElMessage.error('获取卡片信息失败')
} finally {
loading.value = false
}
}
</script>
<style lang="scss" scoped>
.single-card-page {
.operation-buttons {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.traffic-card {
.traffic-item {
padding: 16px;
text-align: center;
.traffic-value {
font-size: 24px;
font-weight: bold;
color: var(--el-color-primary);
&.used {
color: var(--el-color-warning);
}
&.remaining {
color: var(--el-color-success);
}
&.percentage {
color: var(--el-color-info);
}
}
.traffic-label {
margin-top: 8px;
font-size: 14px;
color: var(--el-text-color-regular);
}
}
}
}
</style>