fetch(add): 运营商管理
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m23s

This commit is contained in:
sexygoat
2026-01-27 16:06:48 +08:00
parent c07e481b5b
commit 6127b21c2c
20 changed files with 1502 additions and 42 deletions

View File

@@ -0,0 +1,464 @@
<template>
<ArtTableFullScreen>
<div class="carrier-page" id="table-full-screen">
<!-- 搜索栏 -->
<ArtSearchBar
v-model:filter="searchForm"
:items="searchFormItems"
label-width="85"
:show-expand="false"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
<ElCard shadow="never" class="art-table-card">
<!-- 表格头部 -->
<ArtTableHeader
:columnList="columnOptions"
v-model:columns="columnChecks"
@refresh="handleRefresh"
>
<template #left>
<ElButton @click="showDialog('add')">新增运营商</ElButton>
</template>
</ArtTableHeader>
<!-- 表格 -->
<ArtTable
ref="tableRef"
row-key="id"
:loading="loading"
:data="carrierList"
:currentPage="pagination.page"
:pageSize="pagination.pageSize"
:total="pagination.total"
:marginTop="10"
@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="dialogVisible"
:title="dialogType === 'add' ? '新增运营商' : '编辑运营商'"
width="30%"
>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
<ElFormItem label="运营商编码" prop="carrier_code">
<ElInput
v-model="form.carrier_code"
placeholder="请输入运营商编码"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
<ElFormItem label="运营商名称" prop="carrier_name">
<ElInput v-model="form.carrier_name" placeholder="请输入运营商名称" />
</ElFormItem>
<ElFormItem label="运营商类型" prop="carrier_type">
<ElSelect
v-model="form.carrier_type"
placeholder="请选择运营商类型"
style="width: 100%"
:disabled="dialogType === 'edit'"
>
<ElOption
v-for="item in CARRIER_TYPE_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</ElFormItem>
<ElFormItem label="运营商描述" prop="description">
<ElInput
v-model="form.description"
type="textarea"
:rows="3"
placeholder="请输入运营商描述"
/>
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="handleSubmit(formRef)" :loading="submitLoading">
提交
</ElButton>
</div>
</template>
</ElDialog>
</ElCard>
</div>
</ArtTableFullScreen>
</template>
<script setup lang="ts">
import { h, watch, nextTick } from 'vue'
import { CarrierService } from '@/api/modules'
import { ElMessage, ElMessageBox, ElTag, ElSwitch } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import type { Carrier, CarrierType } from '@/types/api'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import { formatDateTime } from '@/utils/business/format'
import {
CommonStatus,
getStatusText,
CARRIER_TYPE_OPTIONS,
getCarrierTypeLabel,
getCarrierTypeColor
} from '@/config/constants'
defineOptions({ name: 'CarrierManagement' })
const dialogVisible = ref(false)
const loading = ref(false)
const submitLoading = ref(false)
const tableRef = ref()
// 搜索表单初始值
const initialSearchState = {
carrier_name: '',
carrier_type: null,
status: null
}
// 搜索表单
const searchForm = reactive({ ...initialSearchState })
// 搜索表单配置
const searchFormItems: SearchFormItem[] = [
{
label: '运营商名称',
prop: 'carrier_name',
type: 'input',
config: {
clearable: true,
placeholder: '请输入运营商名称'
}
},
{
label: '运营商类型',
prop: 'carrier_type',
type: 'select',
config: {
clearable: true,
placeholder: '请选择运营商类型'
},
options: () => [
{ label: '中国移动', value: 'CMCC' },
{ label: '中国联通', value: 'CUCC' },
{ label: '中国电信', value: 'CTCC' },
{ label: '中国广电', value: 'CBN' }
]
},
{
label: '状态',
prop: 'status',
type: 'select',
config: {
clearable: true,
placeholder: '请选择状态'
},
options: () => [
{ label: '启用', value: CommonStatus.ENABLED },
{ label: '禁用', value: CommonStatus.DISABLED }
]
}
]
// 分页
const pagination = reactive({
page: 1,
pageSize: 20,
total: 0
})
// 列配置
const columnOptions = [
{ label: '运营商编码', prop: 'carrier_code' },
{ label: '运营商名称', prop: 'carrier_name' },
{ label: '运营商类型', prop: 'carrier_type' },
{ label: '运营商描述', prop: 'description' },
{ label: '状态', prop: 'status' },
{ label: '创建时间', prop: 'created_at' },
{ label: '操作', prop: 'operation' }
]
const formRef = ref<FormInstance>()
const rules = reactive<FormRules>({
carrier_code: [
{ required: true, message: '请输入运营商编码', trigger: 'blur' },
{ min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' }
],
carrier_name: [
{ required: true, message: '请输入运营商名称', trigger: 'blur' },
{ min: 1, max: 100, message: '长度在 1 到 100 个字符', trigger: 'blur' }
],
carrier_type: [{ required: true, message: '请选择运营商类型', trigger: 'change' }],
description: [{ max: 500, message: '描述不能超过500个字符', trigger: 'blur' }]
})
const form = reactive<any>({
id: 0,
carrier_code: '',
carrier_name: '',
carrier_type: null,
description: ''
})
const carrierList = ref<Carrier[]>([])
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
prop: 'carrier_code',
label: '运营商编码',
minWidth: 160
},
{
prop: 'carrier_name',
label: '运营商名称',
minWidth: 150
},
{
prop: 'carrier_type',
label: '运营商类型',
width: 120,
formatter: (row: any) => {
const color = getCarrierTypeColor(row.carrier_type)
return h(
ElTag,
{ style: `background-color: ${color}; border-color: ${color}; color: #fff;` },
() => getCarrierTypeLabel(row.carrier_type)
)
}
},
{
prop: 'description',
label: '运营商描述',
minWidth: 200,
showOverflowTooltip: true
},
{
prop: 'status',
label: '状态',
width: 100,
formatter: (row: any) => {
return h(ElSwitch, {
modelValue: row.status,
activeValue: CommonStatus.ENABLED,
inactiveValue: CommonStatus.DISABLED,
activeText: getStatusText(CommonStatus.ENABLED),
inactiveText: getStatusText(CommonStatus.DISABLED),
inlinePrompt: true,
'onUpdate:modelValue': (val: string | number | boolean) =>
handleStatusChange(row, val as number)
})
}
},
{
prop: 'created_at',
label: '创建时间',
width: 180,
formatter: (row: any) => formatDateTime(row.created_at)
},
{
prop: 'operation',
label: '操作',
width: 150,
fixed: 'right',
formatter: (row: any) => {
return h('div', { style: 'display: flex; gap: 8px;' }, [
h(ArtButtonTable, {
type: 'edit',
onClick: () => showDialog('edit', row)
}),
h(ArtButtonTable, {
type: 'delete',
onClick: () => deleteCarrier(row)
})
])
}
}
])
onMounted(() => {
getTableData()
})
// 监听对话框关闭,清除验证状态
watch(dialogVisible, (val) => {
if (!val) {
nextTick(() => {
formRef.value?.clearValidate()
})
}
})
// 获取运营商列表
const getTableData = async () => {
loading.value = true
try {
const params = {
page: pagination.page,
page_size: pagination.pageSize,
carrier_name: searchForm.carrier_name || undefined,
carrier_type: searchForm.carrier_type || undefined,
status: searchForm.status !== null ? searchForm.status : undefined
}
const res = await CarrierService.getCarriers(params)
if (res.code === 0) {
carrierList.value = res.data.items || []
pagination.total = res.data.total || 0
}
} catch (error) {
console.error(error)
} finally {
loading.value = false
}
}
// 重置搜索
const handleReset = () => {
Object.assign(searchForm, { ...initialSearchState })
pagination.page = 1
getTableData()
}
// 搜索
const handleSearch = () => {
pagination.page = 1
getTableData()
}
// 刷新表格
const handleRefresh = () => {
getTableData()
}
// 处理表格分页变化
const handleSizeChange = (newPageSize: number) => {
pagination.pageSize = newPageSize
getTableData()
}
const handleCurrentChange = (newCurrentPage: number) => {
pagination.page = newCurrentPage
getTableData()
}
const dialogType = ref('add')
// 显示新增/编辑对话框
const showDialog = (type: string, row?: any) => {
dialogVisible.value = true
dialogType.value = type
if (type === 'edit' && row) {
form.id = row.id
form.carrier_code = row.carrier_code
form.carrier_name = row.carrier_name
form.carrier_type = row.carrier_type
form.description = row.description
} else {
form.id = 0
form.carrier_code = ''
form.carrier_name = ''
form.carrier_type = null
form.description = ''
}
// 清除表单验证状态
nextTick(() => {
formRef.value?.clearValidate()
})
}
// 删除运营商
const deleteCarrier = (row: any) => {
ElMessageBox.confirm(`确定删除运营商 ${row.carrier_name} 吗?`, '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
})
.then(async () => {
try {
await CarrierService.deleteCarrier(row.id)
ElMessage.success('删除成功')
await getTableData()
} catch (error) {
console.error(error)
}
})
.catch(() => {
// 用户取消删除
})
}
// 提交表单
const handleSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
submitLoading.value = true
try {
const data = {
carrier_code: form.carrier_code,
carrier_name: form.carrier_name,
carrier_type: form.carrier_type as CarrierType,
description: form.description || undefined
}
if (dialogType.value === 'add') {
await CarrierService.createCarrier(data)
ElMessage.success('新增成功')
} else {
const updateData = {
carrier_name: form.carrier_name,
description: form.description || undefined
}
await CarrierService.updateCarrier(form.id, updateData)
ElMessage.success('修改成功')
}
dialogVisible.value = false
formEl.resetFields()
await getTableData()
} catch (error) {
console.error(error)
} finally {
submitLoading.value = false
}
}
})
}
// 状态切换
const handleStatusChange = async (row: any, newStatus: number) => {
const oldStatus = row.status
// 先更新UI
row.status = newStatus
try {
await CarrierService.updateCarrierStatus(row.id, newStatus)
ElMessage.success('状态切换成功')
} catch (error) {
// 切换失败,恢复原状态
row.status = oldStatus
console.error(error)
}
}
</script>
<style scoped lang="scss">
.carrier-page {
height: 100%;
}
</style>