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>
|
||||
523
src/views/package-management/package-batch/index.vue
Normal file
523
src/views/package-management/package-batch/index.vue
Normal file
@@ -0,0 +1,523 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="package-batch-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="showImportDialog">导入</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="importDialogVisible"
|
||||
title="批量导入套餐"
|
||||
width="500px"
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<!-- 顶部下载模板按钮 -->
|
||||
<div class="template-section">
|
||||
<ElButton type="primary" @click="downloadTemplate" icon="Download"> 下载模板 </ElButton>
|
||||
<span class="template-tip">请先下载模板,按模板格式填写后上传</span>
|
||||
</div>
|
||||
|
||||
<ElDivider />
|
||||
|
||||
<ElForm
|
||||
ref="importFormRef"
|
||||
:model="importFormData"
|
||||
:rules="importRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="导入类型" prop="importType">
|
||||
<ElSelect
|
||||
v-model="importFormData.importType"
|
||||
placeholder="请选择导入类型"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="套餐批量导入" value="package_batch" />
|
||||
<ElOption label="套餐更新导入" value="package_update" />
|
||||
<ElOption label="套餐停用导入" value="package_disable" />
|
||||
<ElOption label="套餐启用导入" value="package_enable" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="上传Excel文件" prop="excelFile">
|
||||
<ElUpload
|
||||
ref="uploadRef"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
:before-upload="beforeUpload"
|
||||
:on-change="handleFileChange"
|
||||
:auto-upload="false"
|
||||
accept=".xlsx,.xls"
|
||||
drag
|
||||
>
|
||||
<ElIcon class="el-icon--upload"><UploadFilled /></ElIcon>
|
||||
<div class="el-upload__text"> 将文件拖到此处,或<em>点击上传</em> </div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip"> 只能上传 xlsx/xls 文件,且不超过 10MB </div>
|
||||
</template>
|
||||
</ElUpload>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="备注说明" prop="remark">
|
||||
<ElInput
|
||||
v-model="importFormData.remark"
|
||||
type="textarea"
|
||||
placeholder="请输入备注说明(可选)"
|
||||
:rows="3"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="importDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleImportSubmit" :loading="importLoading">
|
||||
确认导入
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ElTag, ElMessage, ElUpload, ElIcon, ElDivider } from 'element-plus'
|
||||
import { UploadFilled, Download } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, UploadInstance, UploadRawFile, UploadFile } from 'element-plus'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import { SearchChangeParams, SearchFormItem } from '@/types'
|
||||
|
||||
defineOptions({ name: 'PackageBatch' })
|
||||
|
||||
const importDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const importLoading = ref(false)
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
importType: ''
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
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 importFormRef = ref<FormInstance>()
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
|
||||
// 导入表单数据
|
||||
const importFormData = reactive({
|
||||
importType: '',
|
||||
excelFile: null as File | null,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
importTotal: 1000,
|
||||
success: 980,
|
||||
failed: 20,
|
||||
importType: '套餐批量导入',
|
||||
operator: '张若暄',
|
||||
operationTime: '2025-11-08 10:30:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
importTotal: 500,
|
||||
success: 500,
|
||||
failed: 0,
|
||||
importType: '套餐更新导入',
|
||||
operator: '孔丽娟',
|
||||
operationTime: '2025-11-07 14:15:00'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
importTotal: 300,
|
||||
success: 285,
|
||||
failed: 15,
|
||||
importType: '套餐停用导入',
|
||||
operator: '李佳音',
|
||||
operationTime: '2025-11-06 09:45:00'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
importTotal: 800,
|
||||
success: 795,
|
||||
failed: 5,
|
||||
importType: '套餐启用导入',
|
||||
operator: '赵强',
|
||||
operationTime: '2025-11-05 16:20:00'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
importTotal: 150,
|
||||
success: 145,
|
||||
failed: 5,
|
||||
importType: '套餐批量导入',
|
||||
operator: '张若暄',
|
||||
operationTime: '2025-11-04 11:30:00'
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getBatchImportList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getBatchImportList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '导入类型',
|
||||
prop: 'importType',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '套餐批量导入', value: 'package_batch' },
|
||||
{ label: '套餐更新导入', value: 'package_update' },
|
||||
{ label: '套餐停用导入', value: 'package_disable' },
|
||||
{ label: '套餐启用导入', value: 'package_enable' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: '导入总数', prop: 'importTotal' },
|
||||
{ label: '成功', prop: 'success' },
|
||||
{ label: '失败', prop: 'failed' },
|
||||
{ label: '导入类型', prop: 'importType' },
|
||||
{ label: '操作人', prop: 'operator' },
|
||||
{ label: '操作时间', prop: 'operationTime' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 获取导入类型标签类型
|
||||
const getImportTypeTagType = (type: string) => {
|
||||
switch (type) {
|
||||
case '套餐批量导入':
|
||||
return 'primary'
|
||||
case '套餐更新导入':
|
||||
return 'success'
|
||||
case '套餐停用导入':
|
||||
return 'danger'
|
||||
case '套餐启用导入':
|
||||
return 'warning'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 显示导入对话框
|
||||
const showImportDialog = () => {
|
||||
importDialogVisible.value = true
|
||||
// 重置表单
|
||||
if (importFormRef.value) {
|
||||
importFormRef.value.resetFields()
|
||||
}
|
||||
importFormData.importType = ''
|
||||
importFormData.excelFile = null
|
||||
importFormData.remark = ''
|
||||
}
|
||||
|
||||
// 下载模板
|
||||
const downloadTemplate = () => {
|
||||
ElMessage.success('正在下载批量导入模板...')
|
||||
// 这里可以实现实际的模板下载功能
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const viewDetails = (row: any) => {
|
||||
ElMessage.info(`查看导入详情: ${row.importType} - 导入总数:${row.importTotal}`)
|
||||
}
|
||||
|
||||
// 重新导入
|
||||
const retryImport = (row: any) => {
|
||||
ElMessage.info(`重新导入: ${row.importType}`)
|
||||
}
|
||||
|
||||
// 删除记录
|
||||
const deleteRecord = (row: any) => {
|
||||
ElMessage.info(`删除导入记录: ${row.id}`)
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'importTotal',
|
||||
label: '导入总数',
|
||||
formatter: (row) => `${row.importTotal} `
|
||||
},
|
||||
{
|
||||
prop: 'success',
|
||||
label: '成功',
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: 'success' }, () => `${row.success}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'failed',
|
||||
label: '失败',
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: row.failed > 0 ? 'danger' : 'success' }, () => `${row.failed}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'importType',
|
||||
label: '导入类型',
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getImportTypeTagType(row.importType) }, () => row.importType)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'operator',
|
||||
label: '操作人'
|
||||
},
|
||||
{
|
||||
prop: 'operationTime',
|
||||
label: '操作时间'
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 220,
|
||||
formatter: (row: any) => {
|
||||
return h('div', { class: 'operation-buttons' }, [
|
||||
h(ArtButtonTable, {
|
||||
text: '查看',
|
||||
onClick: () => viewDetails(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '重试',
|
||||
onClick: () => retryImport(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '删除',
|
||||
onClick: () => deleteRecord(row)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getBatchImportList()
|
||||
})
|
||||
|
||||
// 获取批量导入列表
|
||||
const getBatchImportList = 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 = () => {
|
||||
getBatchImportList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getBatchImportList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getBatchImportList()
|
||||
}
|
||||
|
||||
// 文件上传限制
|
||||
const handleExceed = () => {
|
||||
ElMessage.warning('最多只能上传一个文件')
|
||||
}
|
||||
|
||||
// 文件上传前检查
|
||||
const beforeUpload = (file: UploadRawFile) => {
|
||||
const isExcel =
|
||||
file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
|
||||
file.type === 'application/vnd.ms-excel'
|
||||
const isLt10M = file.size / 1024 / 1024 < 10
|
||||
|
||||
if (!isExcel) {
|
||||
ElMessage.error('只能上传 Excel 文件!')
|
||||
return false
|
||||
}
|
||||
if (!isLt10M) {
|
||||
ElMessage.error('上传文件大小不能超过 10MB!')
|
||||
return false
|
||||
}
|
||||
return false // 阻止自动上传
|
||||
}
|
||||
|
||||
// 文件变化处理
|
||||
const handleFileChange = (file: UploadFile) => {
|
||||
if (file.raw) {
|
||||
importFormData.excelFile = file.raw
|
||||
}
|
||||
}
|
||||
|
||||
// 导入表单验证规则
|
||||
const importRules = reactive<FormRules>({
|
||||
importType: [{ required: true, message: '请选择导入类型', trigger: 'change' }],
|
||||
excelFile: [{ required: true, message: '请上传Excel文件', trigger: 'change' }]
|
||||
})
|
||||
|
||||
// 提交导入
|
||||
const handleImportSubmit = async () => {
|
||||
if (!importFormRef.value) return
|
||||
|
||||
// 检查文件是否上传
|
||||
if (!importFormData.excelFile) {
|
||||
ElMessage.error('请先上传Excel文件')
|
||||
return
|
||||
}
|
||||
|
||||
await importFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
importLoading.value = true
|
||||
|
||||
// 模拟导入过程
|
||||
setTimeout(() => {
|
||||
ElMessage.success(`${importFormData.importType}批量导入提交成功!`)
|
||||
importDialogVisible.value = false
|
||||
importLoading.value = false
|
||||
getBatchImportList()
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.package-batch-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
|
||||
.template-section {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.template-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.operation-buttons) {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-upload-dragger) {
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
585
src/views/package-management/package-change/index.vue
Normal file
585
src/views/package-management/package-change/index.vue
Normal file
@@ -0,0 +1,585 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="package-change-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 @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="changeDialogVisible"
|
||||
title="套餐变更"
|
||||
width="600px"
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<ElForm
|
||||
ref="changeFormRef"
|
||||
:model="changeFormData"
|
||||
:rules="changeRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="当前套餐" prop="currentPackage">
|
||||
<ElInput
|
||||
v-model="changeFormData.currentPackage"
|
||||
placeholder="当前套餐"
|
||||
readonly
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="变更套餐" prop="newPackage">
|
||||
<ElSelect
|
||||
v-model="changeFormData.newPackage"
|
||||
placeholder="请选择要变更的套餐"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="随意联畅玩年卡套餐" value="changwan_yearly" />
|
||||
<ElOption label="如意包年3G流量包" value="ruyi_3g" />
|
||||
<ElOption label="Y-NB专享套餐" value="nb_special" />
|
||||
<ElOption label="100G全国流量月卡套餐" value="big_data_100g" />
|
||||
<ElOption label="广电飞悦卡无预存50G" value="gdtv_50g" />
|
||||
<ElOption label="联通大王卡" value="unicom_dawang" />
|
||||
<ElOption label="移动花卡宝藏版" value="mobile_huaka" />
|
||||
<ElOption label="电信星卡" value="telecom_star" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="变更原因" prop="changeReason">
|
||||
<ElSelect
|
||||
v-model="changeFormData.changeReason"
|
||||
placeholder="请选择变更原因"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
>
|
||||
<ElOption label="用户主动变更" value="user_request" />
|
||||
<ElOption label="套餐到期升级" value="package_upgrade" />
|
||||
<ElOption label="业务需求调整" value="business_adjustment" />
|
||||
<ElOption label="系统自动变更" value="system_auto" />
|
||||
<ElOption label="其他原因" value="other" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="备注说明" prop="remark">
|
||||
<ElInput
|
||||
v-model="changeFormData.remark"
|
||||
type="textarea"
|
||||
placeholder="请输入备注说明(可选)"
|
||||
:rows="3"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="changeDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleChangeSubmit" :loading="changeLoading">
|
||||
确认变更
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ElTag, ElMessage, ElMessageBox } 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: 'PackageChange' })
|
||||
|
||||
const changeDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const changeLoading = ref(false)
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
isDistribution: '',
|
||||
cardStatus: '',
|
||||
cardType: '',
|
||||
cardCompany: '',
|
||||
distributor: '',
|
||||
iccid: '',
|
||||
accessNumber: '',
|
||||
virtualNumber: ''
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
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 changeFormRef = ref<FormInstance>()
|
||||
|
||||
// 套餐变更表单数据
|
||||
const changeFormData = reactive({
|
||||
currentPackage: '',
|
||||
newPackage: '',
|
||||
changeReason: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 选中的行数据
|
||||
const selectedRowData = ref<any>({})
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
iccid: '89860621370079892035',
|
||||
accessNumber: '1440012345678',
|
||||
virtualNumber: '100001',
|
||||
cardCompany: '联通',
|
||||
expiryDate: '2025-12-31',
|
||||
packageName: '随意联畅玩年卡套餐',
|
||||
cardType: '2G/3G/4G',
|
||||
distributorName: '北京优享科技有限公司',
|
||||
cardStatus: '正常'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
iccid: '89860621370079892036',
|
||||
accessNumber: '1440012345679',
|
||||
virtualNumber: '100002',
|
||||
cardCompany: '移动',
|
||||
expiryDate: '2025-11-30',
|
||||
packageName: '如意包年3G流量包',
|
||||
cardType: 'NB-IoT',
|
||||
distributorName: '上海智联通信技术公司',
|
||||
cardStatus: '停机'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
iccid: '89860621370079892037',
|
||||
accessNumber: '1440012345680',
|
||||
virtualNumber: '100003',
|
||||
cardCompany: '电信',
|
||||
expiryDate: '2026-01-15',
|
||||
packageName: 'Y-NB专享套餐',
|
||||
cardType: '4G/5G',
|
||||
distributorName: '广州物联网络有限公司',
|
||||
cardStatus: '正常'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
iccid: '89860621370079892038',
|
||||
accessNumber: '1440012345681',
|
||||
virtualNumber: '100004',
|
||||
cardCompany: '联通',
|
||||
expiryDate: '2025-10-20',
|
||||
packageName: '100G全国流量月卡套餐',
|
||||
cardType: '2G/3G/4G',
|
||||
distributorName: '深圳云联科技股份公司',
|
||||
cardStatus: '欠费停机'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
iccid: '89860621370079892039',
|
||||
accessNumber: '1440012345682',
|
||||
virtualNumber: '100005',
|
||||
cardCompany: '广电',
|
||||
expiryDate: '2025-09-10',
|
||||
packageName: '广电飞悦卡无预存50G',
|
||||
cardType: '4G/5G',
|
||||
distributorName: '杭州通达网络服务公司',
|
||||
cardStatus: '正常'
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getPackageChangeList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getPackageChangeList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '是否分销',
|
||||
prop: 'isDistribution',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '是', value: 'yes' },
|
||||
{ label: '否', value: 'no' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '卡状态',
|
||||
prop: 'cardStatus',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '正常', value: 'normal' },
|
||||
{ label: '停机', value: 'suspended' },
|
||||
{ label: '欠费停机', value: 'overdue_suspended' },
|
||||
{ label: '已销户', value: 'closed' },
|
||||
{ label: '测试期', value: 'testing' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '卡片类型',
|
||||
prop: 'cardType',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '2G/3G/4G', value: '2g_3g_4g' },
|
||||
{ label: '4G/5G', value: '4g_5g' },
|
||||
{ label: 'NB-IoT', value: 'nb_iot' },
|
||||
{ label: 'eMTC', value: 'emtc' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '开卡公司',
|
||||
prop: 'cardCompany',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '联通', value: 'unicom' },
|
||||
{ label: '移动', value: 'mobile' },
|
||||
{ label: '电信', value: 'telecom' },
|
||||
{ label: '广电', value: 'gdtv' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '分销商',
|
||||
prop: 'distributor',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入分销商'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: 'ICCID号',
|
||||
prop: 'iccid',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入ICCID号'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '接入号',
|
||||
prop: 'accessNumber',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入接入号'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '虚拟号',
|
||||
prop: 'virtualNumber',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入虚拟号'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: 'ICCID号', prop: 'iccid' },
|
||||
{ label: '接入号码', prop: 'accessNumber' },
|
||||
{ label: '虚拟号', prop: 'virtualNumber' },
|
||||
{ label: '开卡公司', prop: 'cardCompany' },
|
||||
{ label: '到期时间', prop: 'expiryDate' },
|
||||
{ label: '套餐', prop: 'packageName' },
|
||||
{ label: '卡片类型', prop: 'cardType' },
|
||||
{ label: '分销商姓名', prop: 'distributorName' },
|
||||
{ label: '卡状态', prop: 'cardStatus' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 获取卡状态标签类型
|
||||
const getCardStatusType = (status: string) => {
|
||||
switch (status) {
|
||||
case '正常':
|
||||
return 'success'
|
||||
case '停机':
|
||||
return 'warning'
|
||||
case '欠费停机':
|
||||
return 'danger'
|
||||
case '已销户':
|
||||
return 'info'
|
||||
case '测试期':
|
||||
return 'primary'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 导出Excel
|
||||
const exportExcel = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要导出的数据')
|
||||
return
|
||||
}
|
||||
ElMessage.success(`导出 ${selectedRows.value.length} 条套餐变更记录`)
|
||||
}
|
||||
|
||||
// 显示套餐变更对话框
|
||||
const showChangeDialog = (row: any) => {
|
||||
changeDialogVisible.value = true
|
||||
selectedRowData.value = row
|
||||
// 重置表单
|
||||
if (changeFormRef.value) {
|
||||
changeFormRef.value.resetFields()
|
||||
}
|
||||
changeFormData.currentPackage = row.packageName
|
||||
changeFormData.newPackage = ''
|
||||
changeFormData.changeReason = ''
|
||||
changeFormData.remark = ''
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'iccid',
|
||||
label: 'ICCID号',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'accessNumber',
|
||||
label: '接入号码',
|
||||
width: 140
|
||||
},
|
||||
{
|
||||
prop: 'virtualNumber',
|
||||
label: '虚拟号',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'cardCompany',
|
||||
label: '开卡公司',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'expiryDate',
|
||||
label: '到期时间',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'packageName',
|
||||
label: '套餐',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'cardType',
|
||||
label: '卡片类型',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'distributorName',
|
||||
label: '分销商姓名',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'cardStatus',
|
||||
label: '卡状态',
|
||||
width: 100,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getCardStatusType(row.cardStatus) }, () => row.cardStatus)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 120,
|
||||
formatter: (row: any) => {
|
||||
return h('div', { class: 'operation-buttons' }, [
|
||||
h(ArtButtonTable, {
|
||||
text: '套餐变更',
|
||||
onClick: () => showChangeDialog(row)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getPackageChangeList()
|
||||
})
|
||||
|
||||
// 获取套餐变更列表
|
||||
const getPackageChangeList = 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 = () => {
|
||||
getPackageChangeList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getPackageChangeList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getPackageChangeList()
|
||||
}
|
||||
|
||||
// 套餐变更表单验证规则
|
||||
const changeRules = reactive<FormRules>({
|
||||
newPackage: [{ required: true, message: '请选择要变更的套餐', trigger: 'change' }],
|
||||
changeReason: [{ required: true, message: '请选择变更原因', trigger: 'change' }]
|
||||
})
|
||||
|
||||
// 提交套餐变更
|
||||
const handleChangeSubmit = async () => {
|
||||
if (!changeFormRef.value) return
|
||||
|
||||
await changeFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
changeLoading.value = true
|
||||
|
||||
// 模拟变更过程
|
||||
setTimeout(() => {
|
||||
ElMessage.success(
|
||||
`套餐变更成功!ICCID:${selectedRowData.value.iccid},从${changeFormData.currentPackage}变更为${changeFormData.newPackage}`
|
||||
)
|
||||
changeDialogVisible.value = false
|
||||
changeLoading.value = false
|
||||
getPackageChangeList()
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.package-change-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
|
||||
:deep(.operation-buttons) {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
452
src/views/package-management/package-commission/index.vue
Normal file
452
src/views/package-management/package-commission/index.vue
Normal file
@@ -0,0 +1,452 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="package-commission-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="showAddDialog">新增</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="addDialogVisible"
|
||||
title="新增套餐佣金网卡"
|
||||
width="500px"
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<ElForm ref="addFormRef" :model="addFormData" :rules="addRules" label-width="120px">
|
||||
<ElFormItem label="卡号" prop="cardNumber">
|
||||
<ElInput v-model="addFormData.cardNumber" placeholder="请输入卡号" clearable />
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="月份" prop="month">
|
||||
<ElDatePicker
|
||||
v-model="addFormData.month"
|
||||
type="month"
|
||||
placeholder="请选择月份"
|
||||
style="width: 100%"
|
||||
format="YYYY-MM"
|
||||
value-format="YYYY-MM"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="addDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleAddSubmit" :loading="addLoading">
|
||||
确认新增
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ElTag, ElMessage, ElMessageBox, ElDatePicker } 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: 'PackageCommission' })
|
||||
|
||||
const addDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const addLoading = ref(false)
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
cardNumber: '',
|
||||
virtualNumber: '',
|
||||
createDateRange: []
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
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 addFormRef = ref<FormInstance>()
|
||||
|
||||
// 新增表单数据
|
||||
const addFormData = reactive({
|
||||
cardNumber: '',
|
||||
month: ''
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
cardNumber: '89860621370079892035',
|
||||
accessNumber: '1440012345678',
|
||||
virtualNumber: '100001',
|
||||
cardCompany: '联通',
|
||||
month: '2025-11',
|
||||
createTime: '2025-11-08 10:30:00',
|
||||
creator: '张若暄'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
cardNumber: '89860621370079892036',
|
||||
accessNumber: '1440012345679',
|
||||
virtualNumber: '100002',
|
||||
cardCompany: '移动',
|
||||
month: '2025-11',
|
||||
createTime: '2025-11-07 14:15:00',
|
||||
creator: '孔丽娟'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
cardNumber: '89860621370079892037',
|
||||
accessNumber: '1440012345680',
|
||||
virtualNumber: '100003',
|
||||
cardCompany: '电信',
|
||||
month: '2025-11',
|
||||
createTime: '2025-11-06 09:45:00',
|
||||
creator: '李佳音'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
cardNumber: '89860621370079892038',
|
||||
accessNumber: '1440012345681',
|
||||
virtualNumber: '100004',
|
||||
cardCompany: '联通',
|
||||
month: '2025-10',
|
||||
createTime: '2025-10-20 16:20:00',
|
||||
creator: '赵强'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
cardNumber: '89860621370079892039',
|
||||
accessNumber: '1440012345682',
|
||||
virtualNumber: '100005',
|
||||
cardCompany: '广电',
|
||||
month: '2025-10',
|
||||
createTime: '2025-10-15 11:30:00',
|
||||
creator: '张若暄'
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getCommissionCardList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getCommissionCardList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '卡号',
|
||||
prop: 'cardNumber',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入卡号'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '虚拟号',
|
||||
prop: 'virtualNumber',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入虚拟号'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createDateRange',
|
||||
type: 'daterange',
|
||||
config: {
|
||||
type: 'daterange',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: '卡号', prop: 'cardNumber' },
|
||||
{ label: '接入号', prop: 'accessNumber' },
|
||||
{ label: '虚拟号', prop: 'virtualNumber' },
|
||||
{ label: '开卡公司', prop: 'cardCompany' },
|
||||
{ label: '月份', prop: 'month' },
|
||||
{ label: '创建时间', prop: 'createTime' },
|
||||
{ label: '创建人', prop: 'creator' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 导出Excel
|
||||
const exportExcel = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要导出的数据')
|
||||
return
|
||||
}
|
||||
ElMessage.success(`导出 ${selectedRows.value.length} 条套餐佣金网卡记录`)
|
||||
}
|
||||
|
||||
// 显示新增对话框
|
||||
const showAddDialog = () => {
|
||||
addDialogVisible.value = true
|
||||
// 重置表单
|
||||
if (addFormRef.value) {
|
||||
addFormRef.value.resetFields()
|
||||
}
|
||||
addFormData.cardNumber = ''
|
||||
addFormData.month = ''
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const viewDetails = (row: any) => {
|
||||
ElMessage.info(`查看详情: ${row.cardNumber}`)
|
||||
}
|
||||
|
||||
// 编辑记录
|
||||
const editRecord = (row: any) => {
|
||||
ElMessage.info(`编辑记录: ${row.cardNumber}`)
|
||||
}
|
||||
|
||||
// 删除记录
|
||||
const deleteRecord = (row: any) => {
|
||||
ElMessageBox.confirm(`确定要删除卡号为"${row.cardNumber}"的佣金记录吗?`, '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getCommissionCardList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消删除')
|
||||
})
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'cardNumber',
|
||||
label: '卡号',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'accessNumber',
|
||||
label: '接入号',
|
||||
width: 140
|
||||
},
|
||||
{
|
||||
prop: 'virtualNumber',
|
||||
label: '虚拟号',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'cardCompany',
|
||||
label: '开卡公司',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'month',
|
||||
label: '月份',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'createTime',
|
||||
label: '创建时间',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'creator',
|
||||
label: '创建人',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 220,
|
||||
formatter: (row: any) => {
|
||||
return h('div', { class: 'operation-buttons' }, [
|
||||
h(ArtButtonTable, {
|
||||
text: '查看',
|
||||
onClick: () => viewDetails(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '编辑',
|
||||
onClick: () => editRecord(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '删除',
|
||||
onClick: () => deleteRecord(row)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getCommissionCardList()
|
||||
})
|
||||
|
||||
// 获取套餐佣金网卡列表
|
||||
const getCommissionCardList = 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 = () => {
|
||||
getCommissionCardList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getCommissionCardList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getCommissionCardList()
|
||||
}
|
||||
|
||||
// 新增表单验证规则
|
||||
const addRules = reactive<FormRules>({
|
||||
cardNumber: [
|
||||
{ required: true, message: '请输入卡号', trigger: 'blur' },
|
||||
{ min: 15, max: 20, message: '卡号长度在 15 到 20 个字符', trigger: 'blur' }
|
||||
],
|
||||
month: [{ required: true, message: '请选择月份', trigger: 'change' }]
|
||||
})
|
||||
|
||||
// 提交新增
|
||||
const handleAddSubmit = async () => {
|
||||
if (!addFormRef.value) return
|
||||
|
||||
await addFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
addLoading.value = true
|
||||
|
||||
// 模拟新增过程
|
||||
setTimeout(() => {
|
||||
ElMessage.success(
|
||||
`新增套餐佣金网卡成功!卡号:${addFormData.cardNumber},月份:${addFormData.month}`
|
||||
)
|
||||
addDialogVisible.value = false
|
||||
addLoading.value = false
|
||||
getCommissionCardList()
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.package-commission-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
|
||||
:deep(.operation-buttons) {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
953
src/views/package-management/package-create/index.vue
Normal file
953
src/views/package-management/package-create/index.vue
Normal file
@@ -0,0 +1,953 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="package-create-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="formFilters"
|
||||
:items="formItems"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 数据视图组件 -->
|
||||
<ArtDataViewer
|
||||
ref="dataViewerRef"
|
||||
:data="tableData"
|
||||
:loading="loading"
|
||||
:table-columns="columns"
|
||||
:descriptions-fields="descriptionsFields"
|
||||
:descriptions-columns="2"
|
||||
:pagination="pagination"
|
||||
:label-width="'140px'"
|
||||
:field-columns="columnChecks"
|
||||
:show-card-actions="true"
|
||||
:show-card-selection="true"
|
||||
:default-view="currentView"
|
||||
@selection-change="handleSelectionChange"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@view-change="handleViewChange"
|
||||
>
|
||||
<template #header-left>
|
||||
<ElButton type="success" @click="showCreateDialog">新增套餐</ElButton>
|
||||
<ElButton @click="exportExcel">导出excel</ElButton>
|
||||
</template>
|
||||
|
||||
<template #header-right>
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
v-model:currentView="currentView"
|
||||
@refresh="handleRefresh"
|
||||
@viewChange="handleViewChange"
|
||||
:show-title="false"
|
||||
:show-view-toggle="true"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #card-actions="{ item }">
|
||||
<ElButton type="primary" size="small" @click="editPackage(item)">
|
||||
编辑
|
||||
</ElButton>
|
||||
<ElButton type="warning" size="small" @click="offlinePackage(item)">
|
||||
下架
|
||||
</ElButton>
|
||||
<ElButton type="success" size="small" @click="copyPackage(item)">
|
||||
复制套餐
|
||||
</ElButton>
|
||||
</template>
|
||||
</ArtDataViewer>
|
||||
|
||||
<!-- 新增套餐对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
title="新增套餐"
|
||||
width="800px"
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<ElForm ref="formRef" :model="formData" :rules="rules" label-width="140px">
|
||||
<ElRow :gutter="24">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="套餐系列" prop="series">
|
||||
<ElSelect
|
||||
v-model="formData.series"
|
||||
placeholder="请选择套餐系列"
|
||||
style="width: 100%"
|
||||
>
|
||||
<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>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="余额充值梯度" prop="balanceRechargeGradient">
|
||||
<ElSelect
|
||||
v-model="formData.balanceRechargeGradient"
|
||||
placeholder="请选择充值梯度"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="10,20,50,100" value="10,20,50,100" />
|
||||
<ElOption label="5,10,20,50" value="5,10,20,50" />
|
||||
<ElOption label="10,50,100" value="10,50,100" />
|
||||
<ElOption label="20,50,100,200" value="20,50,100,200" />
|
||||
<ElOption label="10,30,50" value="10,30,50" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="24">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="套餐名称" prop="name">
|
||||
<ElInput v-model="formData.name" placeholder="请输入套餐名称" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="套餐类型" prop="type">
|
||||
<ElSelect
|
||||
v-model="formData.type"
|
||||
placeholder="请选择套餐类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="月套餐" value="monthly" />
|
||||
<ElOption label="年套餐" value="yearly" />
|
||||
<ElOption label="流量包" value="data_package" />
|
||||
<ElOption label="季度套餐" value="quarterly" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="24">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="本月次月加餐包" prop="monthlyNextMonthAddon">
|
||||
<ElSelect
|
||||
v-model="formData.monthlyNextMonthAddon"
|
||||
placeholder="请选择加餐包支持"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="支持" value="support" />
|
||||
<ElOption label="不支持" value="not_support" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="本月最大充值数量" prop="maxMonthlyRecharge">
|
||||
<ElInputNumber
|
||||
v-model="formData.maxMonthlyRecharge"
|
||||
:min="1"
|
||||
:max="1000"
|
||||
placeholder="请输入本月最大充值数量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="24">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="次月最大充值数量" prop="maxNextMonthRecharge">
|
||||
<ElInputNumber
|
||||
v-model="formData.maxNextMonthRecharge"
|
||||
:min="1"
|
||||
:max="1000"
|
||||
placeholder="请输入次月最大充值数量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="套餐数量" prop="packageCount">
|
||||
<ElInputNumber
|
||||
v-model="formData.packageCount"
|
||||
:min="1"
|
||||
:max="999999"
|
||||
placeholder="请输入套餐数量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="24">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="成本价" prop="costPrice">
|
||||
<ElInputNumber
|
||||
v-model="formData.costPrice"
|
||||
:min="0"
|
||||
:max="9999"
|
||||
:precision="2"
|
||||
placeholder="请输入成本价"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="套餐金额" prop="packageAmount">
|
||||
<ElInputNumber
|
||||
v-model="formData.packageAmount"
|
||||
:min="0"
|
||||
:max="9999"
|
||||
:precision="2"
|
||||
placeholder="请输入套餐金额"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit" :loading="submitLoading">
|
||||
确认新增
|
||||
</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 ArtDataViewer from '@/components/core/views/ArtDataViewer.vue'
|
||||
import { SearchChangeParams, SearchFormItem } from '@/types'
|
||||
|
||||
defineOptions({ name: 'PackageCreate' })
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
|
||||
// 当前视图模式
|
||||
const currentView = ref('table')
|
||||
|
||||
// 数据视图组件引用
|
||||
const dataViewerRef = ref()
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
packageType: '',
|
||||
packageName: '',
|
||||
packageCode: '',
|
||||
status: '',
|
||||
packageSeries: '',
|
||||
levelOneMerge: '',
|
||||
levelTwoMerge: ''
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
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 formRef = ref<FormInstance>()
|
||||
|
||||
// 新增表单数据
|
||||
const formData = reactive({
|
||||
series: '',
|
||||
balanceRechargeGradient: '',
|
||||
name: '',
|
||||
type: '',
|
||||
monthlyNextMonthAddon: '',
|
||||
maxMonthlyRecharge: 0,
|
||||
maxNextMonthRecharge: 0,
|
||||
packageCount: 0,
|
||||
costPrice: 0,
|
||||
packageAmount: 0
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
packageSeries: '畅玩系列',
|
||||
packageName: '随意联畅玩年卡套餐',
|
||||
packageTraffic: 120,
|
||||
packageCount: 1000,
|
||||
packageCountType: '张',
|
||||
packageType: '年套餐',
|
||||
packageAmount: '168.00',
|
||||
description: '年卡套餐,含120GB流量',
|
||||
frontendSort: 1,
|
||||
sort: 1,
|
||||
maxMonthlyRecharge: 50,
|
||||
maxNextMonthRecharge: 50,
|
||||
monthlyNextMonthAddon: '支持',
|
||||
status: '启用',
|
||||
levelOneMerge: '是',
|
||||
levelOneMergeCode: 'L1_001',
|
||||
levelTwoMerge: '否',
|
||||
levelTwoMergeCode: '',
|
||||
isSpecial: '否',
|
||||
creator: '张若暄',
|
||||
modifier: '张若暄',
|
||||
addTime: '2025-11-08 10:30:00',
|
||||
balanceRechargeGradient: '10,20,50,100',
|
||||
packageCode: 'PKG_001'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
packageSeries: '如意系列',
|
||||
packageName: '如意包年3G流量包',
|
||||
packageTraffic: 36,
|
||||
packageCount: 800,
|
||||
packageCountType: '张',
|
||||
packageType: '年套餐',
|
||||
packageAmount: '98.00',
|
||||
description: '年包3GB月套餐',
|
||||
frontendSort: 2,
|
||||
sort: 2,
|
||||
maxMonthlyRecharge: 30,
|
||||
maxNextMonthRecharge: 30,
|
||||
monthlyNextMonthAddon: '支持',
|
||||
status: '启用',
|
||||
levelOneMerge: '是',
|
||||
levelOneMergeCode: 'L1_002',
|
||||
levelTwoMerge: '是',
|
||||
levelTwoMergeCode: 'L2_001',
|
||||
isSpecial: '否',
|
||||
creator: '孔丽娟',
|
||||
modifier: '孔丽娟',
|
||||
addTime: '2025-11-07 14:15:00',
|
||||
balanceRechargeGradient: '5,10,20,50',
|
||||
packageCode: 'PKG_002'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
packageSeries: 'NB专享',
|
||||
packageName: 'Y-NB专享套餐',
|
||||
packageTraffic: 24,
|
||||
packageCount: 500,
|
||||
packageCountType: '张',
|
||||
packageType: '月套餐',
|
||||
packageAmount: '25.00',
|
||||
description: 'NB-IoT专用套餐',
|
||||
frontendSort: 3,
|
||||
sort: 3,
|
||||
maxMonthlyRecharge: 100,
|
||||
maxNextMonthRecharge: 100,
|
||||
monthlyNextMonthAddon: '不支持',
|
||||
status: '停用',
|
||||
levelOneMerge: '否',
|
||||
levelOneMergeCode: '',
|
||||
levelTwoMerge: '否',
|
||||
levelTwoMergeCode: '',
|
||||
isSpecial: '是',
|
||||
creator: '李佳音',
|
||||
modifier: '李佳音',
|
||||
addTime: '2025-11-06 09:45:00',
|
||||
balanceRechargeGradient: '10,50,100',
|
||||
packageCode: 'PKG_003'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
packageSeries: '大流量系列',
|
||||
packageName: '100G全国流量月卡套餐',
|
||||
packageTraffic: 100,
|
||||
packageCount: 1200,
|
||||
packageCountType: '张',
|
||||
packageType: '月套餐',
|
||||
packageAmount: '59.00',
|
||||
description: '100GB大流量月卡',
|
||||
frontendSort: 4,
|
||||
sort: 4,
|
||||
maxMonthlyRecharge: 80,
|
||||
maxNextMonthRecharge: 80,
|
||||
monthlyNextMonthAddon: '支持',
|
||||
status: '启用',
|
||||
levelOneMerge: '是',
|
||||
levelOneMergeCode: 'L1_003',
|
||||
levelTwoMerge: '否',
|
||||
levelTwoMergeCode: '',
|
||||
isSpecial: '否',
|
||||
creator: '赵强',
|
||||
modifier: '赵强',
|
||||
addTime: '2025-11-05 16:20:00',
|
||||
balanceRechargeGradient: '20,50,100,200',
|
||||
packageCode: 'PKG_004'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
packageSeries: '广电系列',
|
||||
packageName: '广电飞悦卡无预存50G',
|
||||
packageTraffic: 50,
|
||||
packageCount: 600,
|
||||
packageCountType: '张',
|
||||
packageType: '月套餐',
|
||||
packageAmount: '39.00',
|
||||
description: '广电30天50GB流量',
|
||||
frontendSort: 5,
|
||||
sort: 5,
|
||||
maxMonthlyRecharge: 60,
|
||||
maxNextMonthRecharge: 60,
|
||||
monthlyNextMonthAddon: '支持',
|
||||
status: '启用',
|
||||
levelOneMerge: '否',
|
||||
levelOneMergeCode: '',
|
||||
levelTwoMerge: '是',
|
||||
levelTwoMergeCode: 'L2_002',
|
||||
isSpecial: '是',
|
||||
creator: '张若暄',
|
||||
modifier: '张若暄',
|
||||
addTime: '2025-11-04 11:30:00',
|
||||
balanceRechargeGradient: '10,30,50',
|
||||
packageCode: 'PKG_005'
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '套餐类型',
|
||||
prop: 'packageType',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '月套餐', value: 'monthly' },
|
||||
{ label: '年套餐', value: 'yearly' },
|
||||
{ label: '流量包', value: 'data_package' },
|
||||
{ label: '季度套餐', value: 'quarterly' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐名称',
|
||||
prop: 'packageName',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入套餐名称'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐编码',
|
||||
prop: 'packageCode',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入套餐编码'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '启用', value: 'active' },
|
||||
{ label: '停用', value: 'inactive' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐系列',
|
||||
prop: 'packageSeries',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入套餐系列'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '一级合并',
|
||||
prop: 'levelOneMerge',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '是', value: 'yes' },
|
||||
{ label: '否', value: 'no' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '二级合并',
|
||||
prop: 'levelTwoMerge',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '是', value: 'yes' },
|
||||
{ label: '否', value: 'no' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: '套餐系列', prop: 'packageSeries' },
|
||||
{ label: '套餐名称', prop: 'packageName' },
|
||||
{ label: '套餐流量(GB)', prop: 'packageTraffic' },
|
||||
{ label: '套餐数量', prop: 'packageCount' },
|
||||
{ label: '套餐数量类型', prop: 'packageCountType' },
|
||||
{ label: '套餐类型', prop: 'packageType' },
|
||||
{ label: '套餐金额', prop: 'packageAmount' },
|
||||
{ label: '描述', prop: 'description' },
|
||||
{ label: '前端排序', prop: 'frontendSort' },
|
||||
{ label: '排序', prop: 'sort' },
|
||||
{ label: '本月最大充值数量', prop: 'maxMonthlyRecharge' },
|
||||
{ label: '次月最大充值数量', prop: 'maxNextMonthRecharge' },
|
||||
{ label: '本月次月加餐包', prop: 'monthlyNextMonthAddon' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '一级是否合并', prop: 'levelOneMerge' },
|
||||
{ label: '一级合并编号', prop: 'levelOneMergeCode' },
|
||||
{ label: '二级是否合并', prop: 'levelTwoMerge' },
|
||||
{ label: '二级合并编号', prop: 'levelTwoMergeCode' },
|
||||
{ label: '是否特殊', prop: 'isSpecial' },
|
||||
{ label: '创建人', prop: 'creator' },
|
||||
{ label: '修改人', prop: 'modifier' },
|
||||
{ label: '添加时间', prop: 'addTime' },
|
||||
{ label: '余额充值梯度', prop: 'balanceRechargeGradient' },
|
||||
{ label: '套餐编码', prop: 'packageCode' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 描述字段配置(用于卡片视图)
|
||||
const descriptionsFields = [
|
||||
{ prop: 'packageName', label: '套餐名称', span: 2 },
|
||||
{ prop: 'packageSeries', label: '套餐系列' },
|
||||
{ prop: 'packageCode', label: '套餐编码' },
|
||||
{
|
||||
prop: 'packageTraffic',
|
||||
label: '套餐流量',
|
||||
formatter: (row: any) => `${row.packageTraffic}GB`
|
||||
},
|
||||
{
|
||||
prop: 'packageCount',
|
||||
label: '套餐数量',
|
||||
formatter: (row: any) => `${row.packageCount}${row.packageCountType}`
|
||||
},
|
||||
{ prop: 'packageType', label: '套餐类型' },
|
||||
{
|
||||
prop: 'packageAmount',
|
||||
label: '套餐金额',
|
||||
formatter: (row: any) => `¥${row.packageAmount}`
|
||||
},
|
||||
{ prop: 'description', label: '描述', span: 2 },
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
formatter: (row: any) => {
|
||||
const type = getStatusType(row.status)
|
||||
return `<el-tag type="${type}" size="small">${row.status}</el-tag>`
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'monthlyNextMonthAddon',
|
||||
label: '本月次月加餐包',
|
||||
formatter: (row: any) => {
|
||||
const type = row.monthlyNextMonthAddon === '支持' ? 'success' : 'info'
|
||||
return `<el-tag type="${type}" size="small">${row.monthlyNextMonthAddon}</el-tag>`
|
||||
}
|
||||
},
|
||||
{ prop: 'maxMonthlyRecharge', label: '本月最大充值数量' },
|
||||
{ prop: 'maxNextMonthRecharge', label: '次月最大充值数量' },
|
||||
{
|
||||
prop: 'levelOneMerge',
|
||||
label: '一级是否合并',
|
||||
formatter: (row: any) => {
|
||||
const type = getMergeType(row.levelOneMerge)
|
||||
return `<el-tag type="${type}" size="small">${row.levelOneMerge}</el-tag>`
|
||||
}
|
||||
},
|
||||
{ prop: 'levelOneMergeCode', label: '一级合并编号', formatter: (row: any) => row.levelOneMergeCode || '-' },
|
||||
{
|
||||
prop: 'levelTwoMerge',
|
||||
label: '二级是否合并',
|
||||
formatter: (row: any) => {
|
||||
const type = getMergeType(row.levelTwoMerge)
|
||||
return `<el-tag type="${type}" size="small">${row.levelTwoMerge}</el-tag>`
|
||||
}
|
||||
},
|
||||
{ prop: 'levelTwoMergeCode', label: '二级合并编号', formatter: (row: any) => row.levelTwoMergeCode || '-' },
|
||||
{
|
||||
prop: 'isSpecial',
|
||||
label: '是否特殊',
|
||||
formatter: (row: any) => {
|
||||
const type = getSpecialType(row.isSpecial)
|
||||
return `<el-tag type="${type}" size="small">${row.isSpecial}</el-tag>`
|
||||
}
|
||||
},
|
||||
{ prop: 'creator', label: '创建人' },
|
||||
{ prop: 'addTime', label: '添加时间', span: 2 },
|
||||
{ prop: 'balanceRechargeGradient', label: '余额充值梯度' },
|
||||
{ prop: 'frontendSort', label: '前端排序' },
|
||||
{ prop: 'sort', label: '排序' }
|
||||
]
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusType = (status: string) => {
|
||||
switch (status) {
|
||||
case '启用':
|
||||
return 'success'
|
||||
case '停用':
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取是否合并标签类型
|
||||
const getMergeType = (merge: string) => {
|
||||
switch (merge) {
|
||||
case '是':
|
||||
return 'success'
|
||||
case '否':
|
||||
return 'info'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取是否特殊标签类型
|
||||
const getSpecialType = (special: string) => {
|
||||
switch (special) {
|
||||
case '是':
|
||||
return 'warning'
|
||||
case '否':
|
||||
return 'info'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 导出Excel
|
||||
const exportExcel = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要导出的数据')
|
||||
return
|
||||
}
|
||||
ElMessage.success(`导出 ${selectedRows.value.length} 条套餐记录`)
|
||||
}
|
||||
|
||||
// 显示新增对话框
|
||||
const showCreateDialog = () => {
|
||||
dialogVisible.value = true
|
||||
// 重置表单
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields()
|
||||
}
|
||||
formData.series = ''
|
||||
formData.balanceRechargeGradient = ''
|
||||
formData.name = ''
|
||||
formData.type = ''
|
||||
formData.monthlyNextMonthAddon = ''
|
||||
formData.maxMonthlyRecharge = 0
|
||||
formData.maxNextMonthRecharge = 0
|
||||
formData.packageCount = 0
|
||||
formData.costPrice = 0
|
||||
formData.packageAmount = 0
|
||||
}
|
||||
|
||||
// 编辑套餐
|
||||
const editPackage = (row: any) => {
|
||||
ElMessage.info(`编辑套餐: ${row.packageName}`)
|
||||
}
|
||||
|
||||
// 下架套餐
|
||||
const offlinePackage = (row: any) => {
|
||||
ElMessageBox.confirm(`确定要下架套餐"${row.packageName}"吗?`, '下架确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('套餐下架成功')
|
||||
getPackageList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消下架')
|
||||
})
|
||||
}
|
||||
|
||||
// 复制套餐
|
||||
const copyPackage = (row: any) => {
|
||||
ElMessage.info(`复制套餐: ${row.packageName}`)
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
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: 'packageCount',
|
||||
label: '套餐数量',
|
||||
width: 100,
|
||||
formatter: (row) => `${row.packageCount}${row.packageCountType}`
|
||||
},
|
||||
{
|
||||
prop: 'packageType',
|
||||
label: '套餐类型',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'packageAmount',
|
||||
label: '套餐金额',
|
||||
width: 100,
|
||||
formatter: (row) => `¥${row.packageAmount}`
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 80,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getStatusType(row.status) }, () => row.status)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'levelOneMerge',
|
||||
label: '一级是否合并',
|
||||
width: 120,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getMergeType(row.levelOneMerge) }, () => row.levelOneMerge)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'levelOneMergeCode',
|
||||
label: '一级合并编号',
|
||||
width: 120,
|
||||
formatter: (row) => row.levelOneMergeCode || '-'
|
||||
},
|
||||
{
|
||||
prop: 'levelTwoMerge',
|
||||
label: '二级是否合并',
|
||||
width: 120,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getMergeType(row.levelTwoMerge) }, () => row.levelTwoMerge)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'levelTwoMergeCode',
|
||||
label: '二级合并编号',
|
||||
width: 120,
|
||||
formatter: (row) => row.levelTwoMergeCode || '-'
|
||||
},
|
||||
{
|
||||
prop: 'isSpecial',
|
||||
label: '是否特殊',
|
||||
width: 100,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getSpecialType(row.isSpecial) }, () => row.isSpecial)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'creator',
|
||||
label: '创建人',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'addTime',
|
||||
label: '添加时间',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'packageCode',
|
||||
label: '套餐编码',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 240,
|
||||
formatter: (row: any) => {
|
||||
return h('div', { class: 'operation-buttons' }, [
|
||||
h(ArtButtonTable, {
|
||||
text: '编辑',
|
||||
onClick: () => editPackage(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '下架',
|
||||
onClick: () => offlinePackage(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '复制套餐',
|
||||
onClick: () => copyPackage(row)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getPackageList()
|
||||
})
|
||||
|
||||
// 获取套餐列表
|
||||
const getPackageList = 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 = () => {
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
// 处理视图切换
|
||||
const handleViewChange = (view: string) => {
|
||||
console.log('视图切换到:', view)
|
||||
// 可以在这里添加视图切换的额外逻辑,比如保存用户偏好
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive<FormRules>({
|
||||
series: [{ required: true, message: '请选择套餐系列', trigger: 'change' }],
|
||||
balanceRechargeGradient: [{ required: true, message: '请选择余额充值梯度', trigger: 'change' }],
|
||||
name: [
|
||||
{ required: true, message: '请输入套餐名称', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '套餐名称长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
],
|
||||
type: [{ required: true, message: '请选择套餐类型', trigger: 'change' }],
|
||||
monthlyNextMonthAddon: [{ required: true, message: '请选择本月次月加餐包', trigger: 'change' }],
|
||||
maxMonthlyRecharge: [{ required: true, message: '请输入本月最大充值数量', trigger: 'blur' }],
|
||||
maxNextMonthRecharge: [{ required: true, message: '请输入次月最大充值数量', trigger: 'blur' }],
|
||||
packageCount: [{ required: true, message: '请输入套餐数量', trigger: 'blur' }],
|
||||
costPrice: [{ required: true, message: '请输入成本价', trigger: 'blur' }],
|
||||
packageAmount: [{ required: true, message: '请输入套餐金额', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
await formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true
|
||||
|
||||
// 模拟提交过程
|
||||
setTimeout(() => {
|
||||
ElMessage.success(
|
||||
`新增套餐成功!套餐名称:${formData.name},套餐系列:${formData.series}`
|
||||
)
|
||||
dialogVisible.value = false
|
||||
submitLoading.value = false
|
||||
getPackageList()
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.package-create-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
|
||||
:deep(.operation-buttons) {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
510
src/views/package-management/package-list/index.vue
Normal file
510
src/views/package-management/package-list/index.vue
Normal file
@@ -0,0 +1,510 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="package-list-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 @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>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ElTag, ElMessageBox, ElMessage } from 'element-plus'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import { SearchChangeParams, SearchFormItem } from '@/types'
|
||||
|
||||
defineOptions({ name: 'PackageList' })
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
agentName: '',
|
||||
packageType: '',
|
||||
status: '',
|
||||
packageName: '',
|
||||
category: '',
|
||||
agentAccount: '',
|
||||
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 mockData = [
|
||||
{
|
||||
id: 1,
|
||||
packageSeries: '畅玩系列',
|
||||
agentName: '北京优享科技有限公司',
|
||||
agentAccount: 'BJ_YXKJ_001',
|
||||
packageName: '随意联畅玩年卡套餐',
|
||||
packageTraffic: 120,
|
||||
packageType: '年套餐',
|
||||
costPrice: 120.0,
|
||||
officialSuggestedPrice: 168.0,
|
||||
mySalesAmount: 158.0,
|
||||
sort: 1,
|
||||
category: '物联网套餐',
|
||||
packageCode: 'PKG_001',
|
||||
status: '上架'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
packageSeries: '如意系列',
|
||||
agentName: '上海智联通信技术公司',
|
||||
agentAccount: 'SH_ZLTX_002',
|
||||
packageName: '如意包年3G流量包',
|
||||
packageTraffic: 36,
|
||||
packageType: '年套餐',
|
||||
costPrice: 80.0,
|
||||
officialSuggestedPrice: 98.0,
|
||||
mySalesAmount: 95.0,
|
||||
sort: 2,
|
||||
category: '流量套餐',
|
||||
packageCode: 'PKG_002',
|
||||
status: '下架'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
packageSeries: 'NB专享',
|
||||
agentName: '广州物联网络有限公司',
|
||||
agentAccount: 'GZ_WLWL_003',
|
||||
packageName: 'Y-NB专享套餐',
|
||||
packageTraffic: 24,
|
||||
packageType: '月套餐',
|
||||
costPrice: 20.0,
|
||||
officialSuggestedPrice: 25.0,
|
||||
mySalesAmount: 24.0,
|
||||
sort: 3,
|
||||
category: 'NB-IoT套餐',
|
||||
packageCode: 'PKG_003',
|
||||
status: '上架'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
packageSeries: '大流量系列',
|
||||
agentName: '深圳云联科技股份公司',
|
||||
agentAccount: 'SZ_YLKJ_004',
|
||||
packageName: '100G全国流量月卡套餐',
|
||||
packageTraffic: 100,
|
||||
packageType: '月套餐',
|
||||
costPrice: 45.0,
|
||||
officialSuggestedPrice: 59.0,
|
||||
mySalesAmount: 55.0,
|
||||
sort: 4,
|
||||
category: '大流量套餐',
|
||||
packageCode: 'PKG_004',
|
||||
status: '上架'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
packageSeries: '广电系列',
|
||||
agentName: '杭州通达网络服务公司',
|
||||
agentAccount: 'HZ_TDWL_005',
|
||||
packageName: '广电飞悦卡无预存50G',
|
||||
packageTraffic: 50,
|
||||
packageType: '月套餐',
|
||||
costPrice: 30.0,
|
||||
officialSuggestedPrice: 39.0,
|
||||
mySalesAmount: 36.0,
|
||||
sort: 5,
|
||||
category: '广电套餐',
|
||||
packageCode: 'PKG_005',
|
||||
status: '下架'
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '代理商名称',
|
||||
prop: 'agentName',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入代理商名称'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐类型',
|
||||
prop: 'packageType',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '月套餐', value: 'monthly' },
|
||||
{ label: '年套餐', value: 'yearly' },
|
||||
{ label: '流量包', value: 'data_package' },
|
||||
{ label: '季度套餐', value: 'quarterly' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '上架', value: 'online' },
|
||||
{ label: '下架', value: 'offline' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐名称',
|
||||
prop: 'packageName',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入套餐名称'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '类别',
|
||||
prop: 'category',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '物联网套餐', value: 'iot_package' },
|
||||
{ label: '流量套餐', value: 'data_package' },
|
||||
{ label: 'NB-IoT套餐', value: 'nb_iot_package' },
|
||||
{ label: '大流量套餐', value: 'big_data_package' },
|
||||
{ label: '广电套餐', value: 'gdtv_package' }
|
||||
],
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '代理商账号',
|
||||
prop: 'agentAccount',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入代理商账号'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '套餐系列',
|
||||
prop: 'packageSeries',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入套餐系列'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: '套餐系列', prop: 'packageSeries' },
|
||||
{ label: '代理商名称', prop: 'agentName' },
|
||||
{ label: '代理商账号', prop: 'agentAccount' },
|
||||
{ label: '套餐名称', prop: 'packageName' },
|
||||
{ label: '套餐流量(GB)', prop: 'packageTraffic' },
|
||||
{ label: '套餐类型', prop: 'packageType' },
|
||||
{ label: '套餐成本价', prop: 'costPrice' },
|
||||
{ label: '官方建议销售价格', prop: 'officialSuggestedPrice' },
|
||||
{ label: '我的销售金额', prop: 'mySalesAmount' },
|
||||
{ label: '排序', prop: 'sort' },
|
||||
{ label: '所属类别', prop: 'category' },
|
||||
{ label: '套餐编码', prop: 'packageCode' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusType = (status: string) => {
|
||||
switch (status) {
|
||||
case '上架':
|
||||
return 'success'
|
||||
case '下架':
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 导出Excel
|
||||
const exportExcel = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要导出的数据')
|
||||
return
|
||||
}
|
||||
ElMessage.success(`导出 ${selectedRows.value.length} 条套餐记录`)
|
||||
}
|
||||
|
||||
// 编辑套餐
|
||||
const editPackage = (row: any) => {
|
||||
ElMessage.info(`编辑套餐: ${row.packageName}`)
|
||||
}
|
||||
|
||||
// 上架套餐
|
||||
const onlinePackage = (row: any) => {
|
||||
if (row.status === '上架') {
|
||||
ElMessage.warning('该套餐已经上架')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(`确定要上架套餐"${row.packageName}"吗?`, '上架确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('套餐上架成功')
|
||||
getPackageList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消上架')
|
||||
})
|
||||
}
|
||||
|
||||
// 下架套餐
|
||||
const offlinePackage = (row: any) => {
|
||||
if (row.status === '下架') {
|
||||
ElMessage.warning('该套餐已经下架')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(`确定要下架套餐"${row.packageName}"吗?`, '下架确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('套餐下架成功')
|
||||
getPackageList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消下架')
|
||||
})
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'packageSeries',
|
||||
label: '套餐系列',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'agentName',
|
||||
label: '代理商名称',
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
prop: 'agentAccount',
|
||||
label: '代理商账号',
|
||||
width: 140
|
||||
},
|
||||
{
|
||||
prop: 'packageName',
|
||||
label: '套餐名称',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'packageTraffic',
|
||||
label: '套餐流量(GB)',
|
||||
width: 120,
|
||||
formatter: (row) => `${row.packageTraffic}GB`
|
||||
},
|
||||
{
|
||||
prop: 'packageType',
|
||||
label: '套餐类型',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'costPrice',
|
||||
label: '套餐成本价',
|
||||
width: 110,
|
||||
formatter: (row) => `¥${row.costPrice.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'officialSuggestedPrice',
|
||||
label: '官方建议销售价格',
|
||||
width: 150,
|
||||
formatter: (row) => `¥${row.officialSuggestedPrice.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'mySalesAmount',
|
||||
label: '我的销售金额',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.mySalesAmount.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'sort',
|
||||
label: '排序',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
prop: 'category',
|
||||
label: '所属类别',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'packageCode',
|
||||
label: '套餐编码',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 80,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getStatusType(row.status) }, () => row.status)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 150,
|
||||
formatter: (row: any) => {
|
||||
return h('div', { class: 'operation-buttons' }, [
|
||||
h(ArtButtonTable, {
|
||||
text: '编辑',
|
||||
onClick: () => editPackage(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: row.status === '上架' ? '下架' : '上架',
|
||||
onClick: () => (row.status === '上架' ? offlinePackage(row) : onlinePackage(row))
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getPackageList()
|
||||
})
|
||||
|
||||
// 获取套餐列表
|
||||
const getPackageList = 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 = () => {
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getPackageList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getPackageList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-template-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
</style>
|
||||
462
src/views/package-management/package-series/index.vue
Normal file
462
src/views/package-management/package-series/index.vue
Normal file
@@ -0,0 +1,462 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="package-series-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="showAddDialog">新增</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="addDialogVisible"
|
||||
title="新增套餐系列"
|
||||
width="500px"
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<ElForm ref="addFormRef" :model="addFormData" :rules="addRules" label-width="120px">
|
||||
<ElFormItem label="系列名称" prop="seriesName">
|
||||
<ElInput v-model="addFormData.seriesName" placeholder="请输入系列名称" clearable />
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="包含套餐" prop="packageNames">
|
||||
<ElSelect
|
||||
v-model="addFormData.packageNames"
|
||||
placeholder="请选择要包含的套餐"
|
||||
style="width: 100%"
|
||||
multiple
|
||||
clearable
|
||||
>
|
||||
<ElOption label="随意联畅玩年卡套餐" value="changwan_yearly" />
|
||||
<ElOption label="随意联畅玩月卡套餐" value="changwan_monthly" />
|
||||
<ElOption label="如意包年3G流量包" value="ruyi_3g" />
|
||||
<ElOption label="如意包月流量包" value="ruyi_monthly" />
|
||||
<ElOption label="Y-NB专享套餐" value="nb_special" />
|
||||
<ElOption label="NB-IoT基础套餐" value="nb_basic" />
|
||||
<ElOption label="100G全国流量月卡套餐" value="big_data_100g" />
|
||||
<ElOption label="200G超值流量包" value="big_data_200g" />
|
||||
<ElOption label="广电飞悦卡无预存50G" value="gdtv_50g" />
|
||||
<ElOption label="广电天翼卡" value="gdtv_tianyi" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="系列描述" prop="description">
|
||||
<ElInput
|
||||
v-model="addFormData.description"
|
||||
type="textarea"
|
||||
placeholder="请输入系列描述(可选)"
|
||||
:rows="3"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="addDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleAddSubmit" :loading="addLoading">
|
||||
确认新增
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ElTag, ElMessage, ElMessageBox } 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: 'PackageSeries' })
|
||||
|
||||
const addDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const addLoading = ref(false)
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
seriesName: ''
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
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 addFormRef = ref<FormInstance>()
|
||||
|
||||
// 新增表单数据
|
||||
const addFormData = reactive({
|
||||
seriesName: '',
|
||||
packageNames: [] as string[],
|
||||
description: ''
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
seriesName: '畅玩系列',
|
||||
operator: '张若暄',
|
||||
operationTime: '2025-11-08 10:30:00',
|
||||
status: '启用'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
seriesName: '如意系列',
|
||||
operator: '孔丽娟',
|
||||
operationTime: '2025-11-07 14:15:00',
|
||||
status: '启用'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
seriesName: 'NB专享',
|
||||
operator: '李佳音',
|
||||
operationTime: '2025-11-06 09:45:00',
|
||||
status: '禁用'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
seriesName: '大流量系列',
|
||||
operator: '赵强',
|
||||
operationTime: '2025-11-05 16:20:00',
|
||||
status: '启用'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
seriesName: '广电系列',
|
||||
operator: '张若暄',
|
||||
operationTime: '2025-11-04 11:30:00',
|
||||
status: '禁用'
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getPackageSeriesList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getPackageSeriesList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '系列名称',
|
||||
prop: 'seriesName',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入系列名称'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: '系列名称', prop: 'seriesName' },
|
||||
{ label: '操作人', prop: 'operator' },
|
||||
{ label: '操作时间', prop: 'operationTime' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusType = (status: string) => {
|
||||
switch (status) {
|
||||
case '启用':
|
||||
return 'success'
|
||||
case '禁用':
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 显示新增对话框
|
||||
const showAddDialog = () => {
|
||||
addDialogVisible.value = true
|
||||
// 重置表单
|
||||
if (addFormRef.value) {
|
||||
addFormRef.value.resetFields()
|
||||
}
|
||||
addFormData.seriesName = ''
|
||||
addFormData.packageNames = []
|
||||
addFormData.description = ''
|
||||
}
|
||||
|
||||
// 启用系列
|
||||
const enableSeries = (row: any) => {
|
||||
ElMessageBox.confirm(`确定要启用套餐系列"${row.seriesName}"吗?`, '启用确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('启用成功')
|
||||
getPackageSeriesList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消启用')
|
||||
})
|
||||
}
|
||||
|
||||
// 禁用系列
|
||||
const disableSeries = (row: any) => {
|
||||
ElMessageBox.confirm(`确定要禁用套餐系列"${row.seriesName}"吗?`, '禁用确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('禁用成功')
|
||||
getPackageSeriesList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消禁用')
|
||||
})
|
||||
}
|
||||
|
||||
// 删除系列
|
||||
const deleteSeries = (row: any) => {
|
||||
ElMessageBox.confirm(
|
||||
`确定要删除套餐系列"${row.seriesName}"吗?删除后将无法恢复。`,
|
||||
'删除确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getPackageSeriesList()
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消删除')
|
||||
})
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'seriesName',
|
||||
label: '系列名称',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'operator',
|
||||
label: '操作人',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'operationTime',
|
||||
label: '操作时间',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row) => {
|
||||
return h(ElTag, { type: getStatusType(row.status) }, () => row.status)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 180,
|
||||
formatter: (row: any) => {
|
||||
const buttons = []
|
||||
|
||||
if (row.status === '启用') {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
text: '禁用',
|
||||
onClick: () => disableSeries(row)
|
||||
})
|
||||
)
|
||||
} else {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
text: '启用',
|
||||
onClick: () => enableSeries(row)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
text: '删除',
|
||||
onClick: () => deleteSeries(row)
|
||||
})
|
||||
)
|
||||
|
||||
return h('div', { class: 'operation-buttons' }, buttons)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getPackageSeriesList()
|
||||
})
|
||||
|
||||
// 获取套餐系列列表
|
||||
const getPackageSeriesList = 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 = () => {
|
||||
getPackageSeriesList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getPackageSeriesList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getPackageSeriesList()
|
||||
}
|
||||
|
||||
// 新增表单验证规则
|
||||
const addRules = reactive<FormRules>({
|
||||
seriesName: [
|
||||
{ required: true, message: '请输入系列名称', trigger: 'blur' },
|
||||
{ min: 2, max: 20, message: '系列名称长度在 2 到 20 个字符', trigger: 'blur' }
|
||||
],
|
||||
packageNames: [{ required: true, message: '请选择要包含的套餐', trigger: 'change' }]
|
||||
})
|
||||
|
||||
// 提交新增
|
||||
const handleAddSubmit = async () => {
|
||||
if (!addFormRef.value) return
|
||||
|
||||
await addFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
addLoading.value = true
|
||||
|
||||
// 模拟新增过程
|
||||
setTimeout(() => {
|
||||
ElMessage.success(
|
||||
`新增套餐系列成功!系列名称:${addFormData.seriesName},包含套餐:${addFormData.packageNames.length} 个`
|
||||
)
|
||||
addDialogVisible.value = false
|
||||
addLoading.value = false
|
||||
getPackageSeriesList()
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.package-series-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