Files
one-pipe-system/src/views/product/sim-card-assign/index.vue
2026-01-23 17:18:24 +08:00

474 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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="margin-top: 4px; font-size: 12px; color: var(--el-text-color-secondary)">
当前库存{{ 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; font-size: 12px; color: var(--el-text-color-secondary)">
{{ 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="margin-top: 4px; font-size: 12px; color: var(--el-text-color-secondary)">
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.0,
stock: 1000,
assignedCount: 500
},
{
id: '2',
productName: '联通5G流量卡-季包300GB',
operator: 'CUCC',
packageSpec: '300GB/季有效期1年',
price: 220.0,
stock: 500,
assignedCount: 200
},
{
id: '3',
productName: '电信物联网卡-年包1TB',
operator: 'CTCC',
packageSpec: '1TB/年有效期2年',
price: 800.0,
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>