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:
611
src/views/package-management/package-assign/index.vue
Normal file
611
src/views/package-management/package-assign/index.vue
Normal file
@@ -0,0 +1,611 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="package-assign-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="formFilters"
|
||||
:items="formItems"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<ElButton type="primary" @click="handleSearch">查询</ElButton>
|
||||
<ElButton type="success" @click="showAssignDialog">分配套餐</ElButton>
|
||||
<ElButton @click="exportExcel">导出excel</ElButton>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
@selection-change="handleSelectionChange"
|
||||
@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="assignDialogVisible"
|
||||
title="分配套餐"
|
||||
width="600px"
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<ElForm
|
||||
ref="assignFormRef"
|
||||
:model="assignFormData"
|
||||
:rules="assignRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="分销商" prop="distributor">
|
||||
<ElSelect
|
||||
v-model="assignFormData.distributor"
|
||||
placeholder="请选择分销商"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="北京优享科技有限公司" value="beijing_youxiang" />
|
||||
<ElOption label="上海智联通信技术公司" value="shanghai_zhilian" />
|
||||
<ElOption label="广州物联网络有限公司" value="guangzhou_wulian" />
|
||||
<ElOption label="深圳云联科技股份公司" value="shenzhen_yunlian" />
|
||||
<ElOption label="杭州通达网络服务公司" value="hangzhou_tongda" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="套餐系列" prop="packageSeries">
|
||||
<ElSelect
|
||||
v-model="assignFormData.packageSeries"
|
||||
placeholder="请选择套餐系列"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="畅玩系列" value="changwan" />
|
||||
<ElOption label="如意系列" value="ruyi" />
|
||||
<ElOption label="NB专享" value="nb_special" />
|
||||
<ElOption label="大流量系列" value="big_data" />
|
||||
<ElOption label="广电系列" value="gdtv" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="套餐名称" prop="packageName">
|
||||
<ElSelect
|
||||
v-model="assignFormData.packageName"
|
||||
placeholder="请选择套餐名称"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="随意联畅玩年卡套餐" value="changwan_yearly" />
|
||||
<ElOption label="如意包年3G流量包" value="ruyi_3g" />
|
||||
<ElOption label="Y-NB专享套餐" value="nb_special_package" />
|
||||
<ElOption label="100G全国流量月卡套餐" value="big_data_100g" />
|
||||
<ElOption label="广电飞悦卡无预存50G" value="gdtv_50g" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="分销金额" prop="distributionAmount">
|
||||
<ElInputNumber
|
||||
v-model="assignFormData.distributionAmount"
|
||||
:min="0"
|
||||
:max="9999"
|
||||
:precision="2"
|
||||
placeholder="请输入分销金额"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="分销比例" prop="distributionRatio">
|
||||
<ElInputNumber
|
||||
v-model="assignFormData.distributionRatio"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:precision="1"
|
||||
placeholder="请输入分销比例"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<span style="margin-left: 8px">%</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="备注说明" prop="remark">
|
||||
<ElInput
|
||||
v-model="assignFormData.remark"
|
||||
type="textarea"
|
||||
placeholder="请输入备注说明(可选)"
|
||||
:rows="3"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="assignDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleAssignSubmit" :loading="assignLoading">
|
||||
确认分配
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ElTag, ElMessage, ElMessageBox, ElInputNumber } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import { SearchChangeParams, SearchFormItem } from '@/types'
|
||||
|
||||
defineOptions({ name: 'PackageAssign' })
|
||||
|
||||
const assignDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const assignLoading = ref(false)
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
distributor: '',
|
||||
assignStatus: '',
|
||||
packageName: '',
|
||||
packageSeries: ''
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
const formFilters = reactive({ ...initialSearchState })
|
||||
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref<any[]>([])
|
||||
|
||||
// 表格实例引用
|
||||
const tableRef = ref()
|
||||
|
||||
// 选中的行数据
|
||||
const selectedRows = ref<any[]>([])
|
||||
|
||||
// 分配表单实例
|
||||
const assignFormRef = ref<FormInstance>()
|
||||
|
||||
// 分配表单数据
|
||||
const assignFormData = reactive({
|
||||
distributor: '',
|
||||
packageSeries: '',
|
||||
packageName: '',
|
||||
distributionAmount: 0,
|
||||
distributionRatio: 0,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
packageSeries: '畅玩系列',
|
||||
packageName: '随意联畅玩年卡套餐',
|
||||
packageTraffic: 120,
|
||||
packageType: '年套餐',
|
||||
salesAmount: 168.0,
|
||||
distributionAmount: 150.0,
|
||||
distributionRatio: 10.7,
|
||||
costPrice: 120.0,
|
||||
assignStatus: '已分配',
|
||||
distributorName: '北京优享科技有限公司'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
packageSeries: '如意系列',
|
||||
packageName: '如意包年3G流量包',
|
||||
packageTraffic: 36,
|
||||
packageType: '年套餐',
|
||||
salesAmount: 98.0,
|
||||
distributionAmount: 85.0,
|
||||
distributionRatio: 13.3,
|
||||
costPrice: 80.0,
|
||||
assignStatus: '未分配',
|
||||
distributorName: ''
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
packageSeries: 'NB专享',
|
||||
packageName: 'Y-NB专享套餐',
|
||||
packageTraffic: 24,
|
||||
packageType: '月套餐',
|
||||
salesAmount: 25.0,
|
||||
distributionAmount: 22.0,
|
||||
distributionRatio: 12.0,
|
||||
costPrice: 20.0,
|
||||
assignStatus: '已分配',
|
||||
distributorName: '广州物联网络有限公司'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
packageSeries: '大流量系列',
|
||||
packageName: '100G全国流量月卡套餐',
|
||||
packageTraffic: 100,
|
||||
packageType: '月套餐',
|
||||
salesAmount: 59.0,
|
||||
distributionAmount: 50.0,
|
||||
distributionRatio: 15.3,
|
||||
costPrice: 45.0,
|
||||
assignStatus: '已分配',
|
||||
distributorName: '深圳云联科技股份公司'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
packageSeries: '广电系列',
|
||||
packageName: '广电飞悦卡无预存50G',
|
||||
packageTraffic: 50,
|
||||
packageType: '月套餐',
|
||||
salesAmount: 39.0,
|
||||
distributionAmount: 33.0,
|
||||
distributionRatio: 15.4,
|
||||
costPrice: 30.0,
|
||||
assignStatus: '未分配',
|
||||
distributorName: ''
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getPackageAssignList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getPackageAssignList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '分销商',
|
||||
prop: 'distributor',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '北京优享科技有限公司', value: 'beijing_youxiang' },
|
||||
{ label: '上海智联通信技术公司', value: 'shanghai_zhilian' },
|
||||
{ label: '广州物联网络有限公司', value: 'guangzhou_wulian' },
|
||||
{ label: '深圳云联科技股份公司', value: 'shenzhen_yunlian' },
|
||||
{ label: '杭州通达网络服务公司', value: 'hangzhou_tongda' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '分配状态',
|
||||
prop: 'assignStatus',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '已分配', value: 'assigned' },
|
||||
{ label: '未分配', value: 'unassigned' },
|
||||
{ label: '分配中', value: 'assigning' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐名称',
|
||||
prop: 'packageName',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入套餐名称'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐系列',
|
||||
prop: 'packageSeries',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '畅玩系列', value: 'changwan' },
|
||||
{ label: '如意系列', value: 'ruyi' },
|
||||
{ label: 'NB专享', value: 'nb_special' },
|
||||
{ label: '大流量系列', value: 'big_data' },
|
||||
{ label: '广电系列', value: 'gdtv' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: '套餐系列', prop: 'packageSeries' },
|
||||
{ label: '套餐名称', prop: 'packageName' },
|
||||
{ label: '套餐流量(GB)', prop: 'packageTraffic' },
|
||||
{ label: '套餐类型', prop: 'packageType' },
|
||||
{ label: '套餐销售金额', prop: 'salesAmount' },
|
||||
{ label: '套餐分销金额', prop: 'distributionAmount' },
|
||||
{ label: '分销比例', prop: 'distributionRatio' },
|
||||
{ label: '成本价', prop: 'costPrice' },
|
||||
{ label: '分配状态', prop: 'assignStatus' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 获取分配状态标签类型
|
||||
const getAssignStatusType = (status: string) => {
|
||||
switch (status) {
|
||||
case '已分配':
|
||||
return 'success'
|
||||
case '未分配':
|
||||
return 'warning'
|
||||
case '分配中':
|
||||
return 'primary'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 导出Excel
|
||||
const exportExcel = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要导出的数据')
|
||||
return
|
||||
}
|
||||
ElMessage.success(`导出 ${selectedRows.value.length} 条套餐分配记录`)
|
||||
}
|
||||
|
||||
// 显示分配对话框
|
||||
const showAssignDialog = () => {
|
||||
assignDialogVisible.value = true
|
||||
// 重置表单
|
||||
if (assignFormRef.value) {
|
||||
assignFormRef.value.resetFields()
|
||||
}
|
||||
assignFormData.distributor = ''
|
||||
assignFormData.packageSeries = ''
|
||||
assignFormData.packageName = ''
|
||||
assignFormData.distributionAmount = 0
|
||||
assignFormData.distributionRatio = 0
|
||||
assignFormData.remark = ''
|
||||
}
|
||||
|
||||
// 编辑分配
|
||||
const editAssign = (row: any) => {
|
||||
ElMessage.info(`编辑分配: ${row.packageName}`)
|
||||
}
|
||||
|
||||
// 取消分配
|
||||
const cancelAssign = (row: any) => {
|
||||
ElMessageBox.confirm(`确定要取消分配套餐"${row.packageName}"吗?`, '取消分配确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('取消分配成功')
|
||||
getPackageAssignList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消操作')
|
||||
})
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'packageSeries',
|
||||
label: '套餐系列',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'packageName',
|
||||
label: '套餐名称',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'packageTraffic',
|
||||
label: '套餐流量(GB)',
|
||||
width: 120,
|
||||
formatter: (row) => `${row.packageTraffic}GB`
|
||||
},
|
||||
{
|
||||
prop: 'packageType',
|
||||
label: '套餐类型',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'salesAmount',
|
||||
label: '套餐销售金额',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.salesAmount.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'distributionAmount',
|
||||
label: '套餐分销金额',
|
||||
width: 120,
|
||||
formatter: (row) => (row.distributionAmount ? `¥${row.distributionAmount.toFixed(2)}` : '-')
|
||||
},
|
||||
{
|
||||
prop: 'distributionRatio',
|
||||
label: '分销比例',
|
||||
width: 100,
|
||||
formatter: (row) => (row.distributionRatio ? `${row.distributionRatio}%` : '-')
|
||||
},
|
||||
{
|
||||
prop: 'costPrice',
|
||||
label: '成本价',
|
||||
width: 100,
|
||||
formatter: (row) => `¥${row.costPrice.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'assignStatus',
|
||||
label: '分配状态',
|
||||
width: 100,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getAssignStatusType(row.assignStatus) }, () => row.assignStatus)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 180,
|
||||
formatter: (row: any) => {
|
||||
const buttons = []
|
||||
|
||||
if (row.assignStatus === '已分配') {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
text: '编辑',
|
||||
onClick: () => editAssign(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '取消分配',
|
||||
onClick: () => cancelAssign(row)
|
||||
})
|
||||
)
|
||||
} else {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
text: '分配',
|
||||
onClick: () => showAssignDialog()
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return h('div', { class: 'operation-buttons' }, buttons)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getPackageAssignList()
|
||||
})
|
||||
|
||||
// 获取套餐分配列表
|
||||
const getPackageAssignList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 模拟API调用
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
const startIndex = (pagination.currentPage - 1) * pagination.pageSize
|
||||
const endIndex = startIndex + pagination.pageSize
|
||||
const paginatedData = mockData.slice(startIndex, endIndex)
|
||||
|
||||
tableData.value = paginatedData
|
||||
pagination.total = mockData.length
|
||||
loading.value = false
|
||||
} catch (error) {
|
||||
console.error('获取套餐分配列表失败:', error)
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
getPackageAssignList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getPackageAssignList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getPackageAssignList()
|
||||
}
|
||||
|
||||
// 分配表单验证规则
|
||||
const assignRules = reactive<FormRules>({
|
||||
distributor: [{ required: true, message: '请选择分销商', trigger: 'change' }],
|
||||
packageSeries: [{ required: true, message: '请选择套餐系列', trigger: 'change' }],
|
||||
packageName: [{ required: true, message: '请选择套餐名称', trigger: 'change' }],
|
||||
distributionAmount: [{ required: true, message: '请输入分销金额', trigger: 'blur' }],
|
||||
distributionRatio: [{ required: true, message: '请输入分销比例', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
// 提交分配
|
||||
const handleAssignSubmit = async () => {
|
||||
if (!assignFormRef.value) return
|
||||
|
||||
await assignFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
assignLoading.value = true
|
||||
|
||||
// 模拟分配过程
|
||||
setTimeout(() => {
|
||||
ElMessage.success(
|
||||
`套餐分配成功!分销商:${assignFormData.distributor},套餐:${assignFormData.packageName}`
|
||||
)
|
||||
assignDialogVisible.value = false
|
||||
assignLoading.value = false
|
||||
getPackageAssignList()
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.package-assign-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
|
||||
:deep(.operation-buttons) {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user