474 lines
15 KiB
Vue
474 lines
15 KiB
Vue
<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>
|