ether-admin/src/views/energy/MeterList.vue

380 lines
11 KiB
Vue

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { Button, Select, Space, message, Tag, Modal, Form, Input, InputNumber, Popconfirm } from 'ant-design-vue'
import type { ColumnsType } from 'ant-design-vue/es/table'
import {
SearchOutlined,
ReloadOutlined,
PlusOutlined
} from '@ant-design/icons-vue'
import {
getEnergyMeters,
createEnergyMeter,
updateEnergyMeter,
deleteEnergyMeter,
type EnergyMeter
} from '@/api/energy'
import { getProjectSelectorList } from '@/api/project'
import { TableActions, Pagination } from '@/components'
// 能源类型映射
const energyTypeMap: Record<string, { color: string; text: string }> = {
ELECTRICITY: { color: 'gold', text: '电力' },
WATER: { color: 'blue', text: '水' },
GAS: { color: 'orange', text: '燃气' },
CENTRAL_HEATING: { color: 'red', text: '集中供热' },
CENTRAL_COOLING: { color: 'cyan', text: '集中供冷' }
}
// 表格列定义
const columns: ColumnsType = [
{ title: '计量点编码', dataIndex: 'meterCode', key: 'meterCode', width: 150 },
{ title: '计量点名称', dataIndex: 'meterName', key: 'meterName', width: 180 },
{ title: '能源类型', dataIndex: 'energyType', key: 'energyType', width: 100 },
{ title: '安装位置', dataIndex: 'installationLocation', key: 'installationLocation', width: 150 },
{ title: '额定容量', dataIndex: 'ratedCapacity', key: 'ratedCapacity', width: 100 },
{ title: '单价(元)', dataIndex: 'unitPrice', key: 'unitPrice', width: 100 },
{ title: '状态', dataIndex: 'status', key: 'status', width: 80 },
{ title: '操作', key: 'action', width: 120, fixed: 'right' as const }
]
// 项目选择选项
const projectOptions = ref<{ value: string; label: string }[]>([])
// 能源类型选项
const energyTypeOptions = [
{ value: 'ELECTRICITY', label: '电力' },
{ value: 'WATER', label: '水' },
{ value: 'GAS', label: '燃气' },
{ value: 'CENTRAL_HEATING', label: '集中供热' },
{ value: 'CENTRAL_COOLING', label: '集中供冷' }
]
// 查询参数
const queryParams = reactive({
projectId: '',
energyType: undefined as string | undefined
})
// 数据状态
const loading = ref(false)
const tableData = ref<EnergyMeter[]>([])
const pagination = reactive({
current: 1,
pageSize: 10,
total: 0
})
// 新建/编辑 Modal
const modalVisible = ref(false)
const modalTitle = ref('新建计量点')
const modalLoading = ref(false)
const editingRecord = ref<EnergyMeter | null>(null)
const formState = reactive<EnergyMeter>({
meterCode: '',
meterName: '',
energyType: 'ELECTRICITY',
installationLocation: '',
ratedCapacity: undefined,
unitPrice: undefined,
status: 'ACTIVE'
})
// 表单验证
const rules = {
meterCode: [{ required: true, message: '请输入计量点编码' }],
meterName: [{ required: true, message: '请输入计量点名称' }],
energyType: [{ required: true, message: '请选择能源类型' }]
}
// 获取项目列表
const fetchProjects = async () => {
try {
const res = await getProjectSelectorList()
projectOptions.value = (res.data.data || []).map((item: any) => ({
value: item.id,
label: item.name
}))
} catch {
message.error('获取项目列表失败')
}
}
// 获取计量点列表
const fetchMeterList = async () => {
if (!queryParams.projectId) {
message.warning('请先选择项目')
return
}
loading.value = true
try {
const res = await getEnergyMeters(queryParams.projectId, queryParams.energyType)
const data = res.data.data
tableData.value = data.content || data || []
pagination.total = data.totalElements || (Array.isArray(data) ? data.length : 0)
} catch {
message.error('获取计量点列表失败')
} finally {
loading.value = false
}
}
// 搜索
const handleSearch = () => {
pagination.current = 1
fetchMeterList()
}
// 重置
const handleReset = () => {
queryParams.projectId = ''
queryParams.energyType = undefined
pagination.current = 1
tableData.value = []
}
// 分页变化
const handlePageChange = (page: number, pageSize: number) => {
pagination.current = page
pagination.pageSize = pageSize
fetchMeterList()
}
// 打开新建 Modal
const handleAdd = () => {
editingRecord.value = null
modalTitle.value = '新建计量点'
Object.assign(formState, {
id: undefined,
meterCode: '',
meterName: '',
energyType: 'ELECTRICITY',
installationLocation: '',
ratedCapacity: undefined,
unitPrice: undefined,
status: 'ACTIVE'
})
modalVisible.value = true
}
// 打开编辑 Modal
const handleEdit = (record: EnergyMeter) => {
editingRecord.value = record
modalTitle.value = '编辑计量点'
Object.assign(formState, {
id: record.id,
meterCode: record.meterCode,
meterName: record.meterName,
energyType: record.energyType,
installationLocation: record.installationLocation || '',
ratedCapacity: record.ratedCapacity,
unitPrice: record.unitPrice,
status: record.status || 'ACTIVE'
})
modalVisible.value = true
}
// 删除计量点
const handleDelete = async (id: string) => {
try {
await deleteEnergyMeter(id)
message.success('删除成功')
fetchMeterList()
} catch {
message.error('删除失败')
}
}
// 提交表单
const handleSubmit = async () => {
modalLoading.value = true
try {
if (editingRecord.value) {
await updateEnergyMeter(editingRecord.value.id!, formState)
message.success('更新成功')
} else {
await createEnergyMeter({ ...formState, status: 'ACTIVE' } as EnergyMeter)
message.success('创建成功')
}
modalVisible.value = false
fetchMeterList()
} catch {
message.error(editingRecord.value ? '更新失败' : '创建失败')
} finally {
modalLoading.value = false
}
}
// 获取能源类型标签
const getEnergyTypeTag = (type: string) => {
const config = energyTypeMap[type] || { color: 'default', text: type }
return config
}
onMounted(() => {
fetchProjects()
})
</script>
<template>
<div class="page-container">
<!-- 页面标题 -->
<div class="page-header">
<h2 class="page-title">计量点管理</h2>
</div>
<!-- 筛选区 -->
<div class="filter-bar">
<Space>
<Select
v-model:value="queryParams.projectId"
placeholder="请选择项目"
style="width: 240px"
allow-clear
:options="projectOptions"
/>
<Select
v-model:value="queryParams.energyType"
placeholder="能源类型"
style="width: 140px"
allow-clear
:options="energyTypeOptions"
/>
<Button type="primary" @click="handleSearch">
<SearchOutlined /> 查询
</Button>
<Button @click="handleReset">
<ReloadOutlined /> 重置
</Button>
</Space>
</div>
<!-- 表格区 -->
<div class="table-card">
<div class="table-toolbar">
<Button type="primary" @click="handleAdd">
<PlusOutlined /> 新建计量点
</Button>
</div>
<a-table
:columns="columns"
:data-source="tableData"
:loading="loading"
:row-key="(record: EnergyMeter) => record.id || record.meterCode"
:pagination="{
current: pagination.current,
pageSize: pagination.pageSize,
total: pagination.total,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total: number) => `${total}`
}"
@change="(pag: any) => handlePageChange(pag.current, pag.pageSize)"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'energyType'">
<Tag :color="getEnergyTypeTag(record.energyType).color">
{{ getEnergyTypeTag(record.energyType).text }}
</Tag>
</template>
<template v-else-if="column.key === 'ratedCapacity'">
{{ record.ratedCapacity ? `${record.ratedCapacity} kW` : '-' }}
</template>
<template v-else-if="column.key === 'unitPrice'">
{{ record.unitPrice ? `¥${record.unitPrice}` : '-' }}
</template>
<template v-else-if="column.key === 'status'">
<Tag :color="record.status === 'ACTIVE' ? 'green' : 'red'">
{{ record.status === 'ACTIVE' ? '启用' : '停用' }}
</Tag>
</template>
<template v-else-if="column.key === 'action'">
<Space>
<Button type="link" size="small" @click="handleEdit(record)">编辑</Button>
<Popconfirm title="确定删除该计量点?" @confirm="handleDelete(record.id!)">
<Button type="link" size="small" danger>删除</Button>
</Popconfirm>
</Space>
</template>
</template>
</a-table>
<!-- 未选择项目提示 -->
<a-empty v-if="!queryParams.projectId && tableData.length === 0" description="请先选择项目" />
</div>
<!-- 新建/编辑 Modal -->
<Modal
v-model:open="modalVisible"
:title="modalTitle"
:confirm-loading="modalLoading"
@ok="handleSubmit"
@cancel="modalVisible = false"
width="560px"
>
<Form
:model="formState"
:rules="rules"
layout="vertical"
class="meter-form"
>
<Form.Item label="计量点编码" name="meterCode">
<Input v-model:value="formState.meterCode" placeholder="请输入计量点编码" />
</Form.Item>
<Form.Item label="计量点名称" name="meterName">
<Input v-model:value="formState.meterName" placeholder="请输入计量点名称" />
</Form.Item>
<Form.Item label="能源类型" name="energyType">
<Select v-model:value="formState.energyType" :options="energyTypeOptions" />
</Form.Item>
<Form.Item label="安装位置" name="installationLocation">
<Input v-model:value="formState.installationLocation" placeholder="请输入安装位置" />
</Form.Item>
<Form.Item label="额定容量(kW)" name="ratedCapacity">
<InputNumber v-model:value="formState.ratedCapacity" placeholder="请输入额定容量" style="width: 100%" />
</Form.Item>
<Form.Item label="单价()" name="unitPrice">
<InputNumber v-model:value="formState.unitPrice" placeholder="请输入单价" style="width: 100%" :precision="2" />
</Form.Item>
</Form>
</Modal>
</div>
</template>
<style scoped>
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.page-title {
margin: 0;
font-size: 20px;
font-weight: 500;
color: #262626;
}
.filter-bar {
margin-bottom: 24px;
padding: 16px;
background: #fafafa;
border-radius: 8px;
}
.table-card {
background: #fff;
border-radius: 8px;
padding: 16px;
}
.table-toolbar {
margin-bottom: 16px;
}
.meter-form {
margin-top: 16px;
}
</style>