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:
430
src/views/product/sim-card-assign/index.vue
Normal file
430
src/views/product/sim-card-assign/index.vue
Normal file
@@ -0,0 +1,430 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<!-- 搜索和操作区 -->
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElInput v-model="searchQuery" placeholder="产品名称/ICCID" clearable />
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElSelect v-model="operatorFilter" placeholder="运营商筛选" clearable style="width: 100%">
|
||||
<ElOption label="全部" value="" />
|
||||
<ElOption label="中国移动" value="CMCC" />
|
||||
<ElOption label="中国联通" value="CUCC" />
|
||||
<ElOption label="中国电信" value="CTCC" />
|
||||
</ElSelect>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElSelect v-model="statusFilter" placeholder="分配状态" clearable style="width: 100%">
|
||||
<ElOption label="全部" value="" />
|
||||
<ElOption label="已分配" value="assigned" />
|
||||
<ElOption label="未分配" value="unassigned" />
|
||||
</ElSelect>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton v-ripple @click="handleSearch">搜索</ElButton>
|
||||
<ElButton v-ripple type="primary" @click="showAssignDialog">批量分配</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 号卡产品列表 -->
|
||||
<ArtTable :data="filteredData" index style="margin-top: 20px" @selection-change="handleSelectionChange">
|
||||
<template #default>
|
||||
<ElTableColumn type="selection" width="55" />
|
||||
<ElTableColumn label="产品名称" prop="productName" min-width="180" show-overflow-tooltip />
|
||||
<ElTableColumn label="运营商" prop="operator" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag :type="getOperatorTagType(scope.row.operator)">
|
||||
{{ getOperatorText(scope.row.operator) }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="套餐规格" prop="packageSpec" min-width="150" />
|
||||
<ElTableColumn label="产品价格" prop="price" width="120">
|
||||
<template #default="scope"> ¥{{ scope.row.price.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="库存数量" prop="stock" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<span :style="{ color: scope.row.stock < 100 ? 'var(--el-color-danger)' : '' }">
|
||||
{{ scope.row.stock }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="已分配数量" prop="assignedCount" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-primary)">{{ scope.row.assignedCount }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="分配状态" prop="assignStatus" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.assignedCount > 0" type="success">已分配</ElTag>
|
||||
<ElTag v-else type="info">未分配</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn fixed="right" label="操作" width="200">
|
||||
<template #default="scope">
|
||||
<el-button link :icon="View" @click="viewAssignDetail(scope.row)">分配记录</el-button>
|
||||
<el-button link type="primary" @click="assignToAgent(scope.row)">分配</el-button>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 分配对话框 -->
|
||||
<ElDialog v-model="assignDialogVisible" title="分配号卡产品" width="600px" align-center>
|
||||
<ElForm ref="formRef" :model="assignForm" :rules="assignRules" label-width="120px">
|
||||
<ElFormItem label="选择代理商" prop="agentId">
|
||||
<ElSelect
|
||||
v-model="assignForm.agentId"
|
||||
placeholder="请选择代理商"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
@change="handleAgentChange"
|
||||
>
|
||||
<ElOption
|
||||
v-for="agent in agentList"
|
||||
:key="agent.id"
|
||||
:label="`${agent.agentName} (${agent.phone})`"
|
||||
:value="agent.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="分配数量" prop="quantity">
|
||||
<ElInputNumber
|
||||
v-model="assignForm.quantity"
|
||||
:min="1"
|
||||
:max="currentProduct.stock"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div style="color: var(--el-text-color-secondary); font-size: 12px; margin-top: 4px">
|
||||
当前库存:{{ currentProduct.stock }} 张
|
||||
</div>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="分佣模式" prop="commissionMode">
|
||||
<ElRadioGroup v-model="assignForm.commissionMode">
|
||||
<ElRadio value="fixed">固定佣金</ElRadio>
|
||||
<ElRadio value="percent">比例佣金</ElRadio>
|
||||
<ElRadio value="template">使用模板</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="assignForm.commissionMode === 'fixed'" label="固定金额" prop="fixedAmount">
|
||||
<ElInputNumber v-model="assignForm.fixedAmount" :min="0" :precision="2" style="width: 100%" />
|
||||
<span style="margin-left: 8px">元/张</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="assignForm.commissionMode === 'percent'" label="佣金比例" prop="percent">
|
||||
<ElInputNumber v-model="assignForm.percent" :min="0" :max="100" :precision="2" style="width: 100%" />
|
||||
<span style="margin-left: 8px">%</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="assignForm.commissionMode === 'template'" label="分佣模板" prop="templateId">
|
||||
<ElSelect v-model="assignForm.templateId" placeholder="请选择分佣模板" style="width: 100%">
|
||||
<ElOption
|
||||
v-for="template in commissionTemplates"
|
||||
:key="template.id"
|
||||
:label="template.templateName"
|
||||
:value="template.id"
|
||||
>
|
||||
<span>{{ template.templateName }}</span>
|
||||
<span style="float: right; color: var(--el-text-color-secondary); font-size: 12px">
|
||||
{{ template.mode === 'fixed' ? `¥${template.value}元/张` : `${template.value}%` }}
|
||||
</span>
|
||||
</ElOption>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="特殊折扣" prop="discount">
|
||||
<ElInputNumber v-model="assignForm.discount" :min="0" :max="100" :precision="2" style="width: 100%" />
|
||||
<span style="margin-left: 8px">%</span>
|
||||
<div style="color: var(--el-text-color-secondary); font-size: 12px; margin-top: 4px">
|
||||
0表示无折扣,设置后代理商可以此折扣价格销售
|
||||
</div>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="备注" prop="remark">
|
||||
<ElInput v-model="assignForm.remark" type="textarea" :rows="3" placeholder="请输入备注信息" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="assignDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleAssignSubmit">确认分配</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 分配记录对话框 -->
|
||||
<ElDialog v-model="detailDialogVisible" title="分配记录" width="900px" align-center>
|
||||
<ArtTable :data="assignRecords" index>
|
||||
<template #default>
|
||||
<ElTableColumn label="代理商名称" prop="agentName" min-width="150" />
|
||||
<ElTableColumn label="分配数量" prop="quantity" width="100" align="center" />
|
||||
<ElTableColumn label="分佣模式" prop="commissionMode" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.commissionMode === 'fixed'" type="warning">固定佣金</ElTag>
|
||||
<ElTag v-else-if="scope.row.commissionMode === 'percent'" type="success">比例佣金</ElTag>
|
||||
<ElTag v-else>模板佣金</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="佣金规则" prop="commissionRule" width="150" />
|
||||
<ElTableColumn label="特殊折扣" prop="discount" width="100">
|
||||
<template #default="scope">
|
||||
{{ scope.row.discount > 0 ? `${scope.row.discount}%` : '无' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="分配时间" prop="assignTime" width="180" />
|
||||
<ElTableColumn label="操作人" prop="operator" width="100" />
|
||||
<ElTableColumn fixed="right" label="操作" width="120">
|
||||
<template #default="scope">
|
||||
<el-button link type="danger" @click="handleCancelAssign(scope.row)">取消分配</el-button>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<template #footer>
|
||||
<ElButton @click="detailDialogVisible = false">关闭</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { View } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'SimCardAssign' })
|
||||
|
||||
interface SimCardProduct {
|
||||
id: string
|
||||
productName: string
|
||||
operator: string
|
||||
packageSpec: string
|
||||
price: number
|
||||
stock: number
|
||||
assignedCount: number
|
||||
}
|
||||
|
||||
const searchQuery = ref('')
|
||||
const operatorFilter = ref('')
|
||||
const statusFilter = ref('')
|
||||
const assignDialogVisible = ref(false)
|
||||
const detailDialogVisible = ref(false)
|
||||
const formRef = ref<FormInstance>()
|
||||
const selectedRows = ref<SimCardProduct[]>([])
|
||||
|
||||
const currentProduct = ref<SimCardProduct>({
|
||||
id: '',
|
||||
productName: '',
|
||||
operator: '',
|
||||
packageSpec: '',
|
||||
price: 0,
|
||||
stock: 0,
|
||||
assignedCount: 0
|
||||
})
|
||||
|
||||
const assignForm = reactive({
|
||||
agentId: '',
|
||||
quantity: 1,
|
||||
commissionMode: 'percent',
|
||||
fixedAmount: 0,
|
||||
percent: 10,
|
||||
templateId: '',
|
||||
discount: 0,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const assignRules = reactive<FormRules>({
|
||||
agentId: [{ required: true, message: '请选择代理商', trigger: 'change' }],
|
||||
quantity: [{ required: true, message: '请输入分配数量', trigger: 'blur' }],
|
||||
commissionMode: [{ required: true, message: '请选择分佣模式', trigger: 'change' }]
|
||||
})
|
||||
|
||||
const agentList = ref([
|
||||
{ id: '1', agentName: '华东区总代理', phone: '13800138000', level: 1 },
|
||||
{ id: '2', agentName: '华南区代理', phone: '13900139000', level: 2 },
|
||||
{ id: '3', agentName: '华北区代理', phone: '13700137000', level: 1 }
|
||||
])
|
||||
|
||||
const commissionTemplates = ref([
|
||||
{ id: '1', templateName: '标准代理商佣金', mode: 'percent', value: 10 },
|
||||
{ id: '2', templateName: '特殊套餐固定佣金', mode: 'fixed', value: 50 },
|
||||
{ id: '3', templateName: '高端代理商佣金', mode: 'percent', value: 15 }
|
||||
])
|
||||
|
||||
const mockData = ref<SimCardProduct[]>([
|
||||
{
|
||||
id: '1',
|
||||
productName: '移动4G流量卡-月包100GB',
|
||||
operator: 'CMCC',
|
||||
packageSpec: '100GB/月,有效期1年',
|
||||
price: 80.00,
|
||||
stock: 1000,
|
||||
assignedCount: 500
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
productName: '联通5G流量卡-季包300GB',
|
||||
operator: 'CUCC',
|
||||
packageSpec: '300GB/季,有效期1年',
|
||||
price: 220.00,
|
||||
stock: 500,
|
||||
assignedCount: 200
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
productName: '电信物联网卡-年包1TB',
|
||||
operator: 'CTCC',
|
||||
packageSpec: '1TB/年,有效期2年',
|
||||
price: 800.00,
|
||||
stock: 80,
|
||||
assignedCount: 0
|
||||
}
|
||||
])
|
||||
|
||||
const assignRecords = ref([
|
||||
{
|
||||
id: '1',
|
||||
agentName: '华东区总代理',
|
||||
quantity: 200,
|
||||
commissionMode: 'percent',
|
||||
commissionRule: '10%',
|
||||
discount: 5,
|
||||
assignTime: '2026-01-08 10:00:00',
|
||||
operator: 'admin'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
agentName: '华南区代理',
|
||||
quantity: 150,
|
||||
commissionMode: 'fixed',
|
||||
commissionRule: '¥5.00/张',
|
||||
discount: 0,
|
||||
assignTime: '2026-01-07 14:30:00',
|
||||
operator: 'admin'
|
||||
}
|
||||
])
|
||||
|
||||
const filteredData = computed(() => {
|
||||
let data = mockData.value
|
||||
|
||||
if (searchQuery.value) {
|
||||
data = data.filter((item) => item.productName.includes(searchQuery.value))
|
||||
}
|
||||
|
||||
if (operatorFilter.value) {
|
||||
data = data.filter((item) => item.operator === operatorFilter.value)
|
||||
}
|
||||
|
||||
if (statusFilter.value) {
|
||||
if (statusFilter.value === 'assigned') {
|
||||
data = data.filter((item) => item.assignedCount > 0)
|
||||
} else if (statusFilter.value === 'unassigned') {
|
||||
data = data.filter((item) => item.assignedCount === 0)
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
})
|
||||
|
||||
const getOperatorText = (operator: string) => {
|
||||
const map: Record<string, string> = {
|
||||
CMCC: '中国移动',
|
||||
CUCC: '中国联通',
|
||||
CTCC: '中国电信'
|
||||
}
|
||||
return map[operator] || operator
|
||||
}
|
||||
|
||||
const getOperatorTagType = (operator: string) => {
|
||||
const map: Record<string, any> = {
|
||||
CMCC: 'success',
|
||||
CUCC: 'primary',
|
||||
CTCC: 'warning'
|
||||
}
|
||||
return map[operator] || ''
|
||||
}
|
||||
|
||||
const handleSearch = () => {}
|
||||
|
||||
const handleSelectionChange = (rows: SimCardProduct[]) => {
|
||||
selectedRows.value = rows
|
||||
}
|
||||
|
||||
const showAssignDialog = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要分配的产品')
|
||||
return
|
||||
}
|
||||
if (selectedRows.value.length > 1) {
|
||||
ElMessage.warning('批量分配功能开发中,请单个选择')
|
||||
return
|
||||
}
|
||||
currentProduct.value = selectedRows.value[0]
|
||||
assignDialogVisible.value = true
|
||||
}
|
||||
|
||||
const assignToAgent = (row: SimCardProduct) => {
|
||||
currentProduct.value = row
|
||||
assignDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleAgentChange = () => {
|
||||
// 可以根据代理商自动填充默认佣金设置
|
||||
}
|
||||
|
||||
const handleAssignSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
await formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (assignForm.quantity > currentProduct.value.stock) {
|
||||
ElMessage.error('分配数量不能超过库存数量')
|
||||
return
|
||||
}
|
||||
|
||||
// 更新分配数量
|
||||
currentProduct.value.assignedCount += assignForm.quantity
|
||||
currentProduct.value.stock -= assignForm.quantity
|
||||
|
||||
assignDialogVisible.value = false
|
||||
formRef.value.resetFields()
|
||||
ElMessage.success('分配成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const viewAssignDetail = (row: SimCardProduct) => {
|
||||
currentProduct.value = row
|
||||
detailDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleCancelAssign = (row: any) => {
|
||||
ElMessageBox.confirm('取消分配后,该代理商将无法继续销售此产品,确定取消吗?', '取消分配', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
// 恢复库存
|
||||
currentProduct.value.stock += row.quantity
|
||||
currentProduct.value.assignedCount -= row.quantity
|
||||
|
||||
const index = assignRecords.value.findIndex((item) => item.id === row.id)
|
||||
if (index !== -1) assignRecords.value.splice(index, 1)
|
||||
ElMessage.success('取消分配成功')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
:deep(.el-select-dropdown__item) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user