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:
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