380 lines
11 KiB
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> |