| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612 |
- <script setup lang="ts">
- import { onMounted, reactive, ref } from 'vue'
- import { clientDownloadExcel, clientGet, clientPost } from '@/utils/request.ts'
- import type { FormInstance, UploadProps } from 'element-plus'
- import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
- import { Delete, Download, Edit, Plus, Refresh, Search, Upload } from '@element-plus/icons-vue'
- // 基础类型定义
- interface BaseResponse {
- code: number
- msg: string
- }
- interface PageType<T> {
- records: T[]
- total: number
- size: number
- current: number
- pages: number
- }
- // 燃气信息相关接口定义
- interface Property {
- id: string // 主键id
- company?: string // 企业名称
- uniCode?: string // 统一社会信用代码
- tableName?: string // 事项名称
- tableCode?: string // 事项编码
- userInfo?: string // 燃气用户信息(户名户号)
- paymentDetail?: string // 缴纳燃气费明细
- monthlyConsumption3?: number // 近3个月月均燃气用量
- monthlyConsumption6?: number // 近6个月月均燃气用量
- isInArrears?: string // 当前是否欠费
- entityZtlb?: string // 类别
- openDate?: string // 开户日期 (改为string用于显示)
- userAddress?: string // 用户地址
- advanceAmount?: string // 预交金额
- arrearageAmount?: string // 欠费金额
- onehouseOnemeter?: string // 是否一户一表
- paymentPeriod?: string // 缴费所属期
- statisticalDate?: string // 统计日期
- remark?: string // 备注
- createTime?: string // 创建时间 (改为string用于显示)
- createBy?: string // 创建用户
- updateTime?: string // 更新时间 (改为string用于显示)
- updateBy?: string // 更新用户
- }
- interface PropertyOneResponse extends BaseResponse {
- data: Property
- }
- interface PropertyListResponse extends BaseResponse {
- data: PageType<Property>
- }
- interface AddProperty {
- company?: string // 企业名称
- uniCode?: string // 统一社会信用代码
- tableName?: string // 事项名称
- tableCode?: string // 事项编码
- userInfo?: string // 燃气用户信息(户名户号)
- paymentDetail?: string // 缴纳燃气费明细
- monthlyConsumption3?: number // 近3个月月均燃气用量
- monthlyConsumption6?: number // 近6个月月均燃气用量
- isInArrears?: string // 当前是否欠费
- entityZtlb?: string // 类别
- openDate?: string // 开户日期
- userAddress?: string // 用户地址
- advanceAmount?: string // 预交金额
- arrearageAmount?: string // 欠费金额
- onehouseOnemeter?: string // 是否一户一表
- paymentPeriod?: string // 缴费所属期
- statisticalDate?: string // 统计日期
- remark?: string // 备注
- }
- interface UpdateProperty {
- id?: string
- company?: string // 企业名称
- uniCode?: string // 统一社会信用代码
- tableName?: string // 事项名称
- tableCode?: string // 事项编码
- userInfo?: string // 燃气用户信息(户名户号)
- paymentDetail?: string // 缴纳燃气费明细
- monthlyConsumption3?: number // 近3个月月均燃气用量
- monthlyConsumption6?: number // 近6个月月均燃气用量
- isInArrears?: string // 当前是否欠费
- entityZtlb?: string // 类别
- openDate?: string // 开户日期
- userAddress?: string // 用户地址
- advanceAmount?: string // 预交金额
- arrearageAmount?: string // 欠费金额
- onehouseOnemeter?: string // 是否一户一表
- paymentPeriod?: string // 缴费所属期
- statisticalDate?: string // 统计日期
- remark?: string // 备注
- }
- // 响应式状态变量
- const tableData = ref<Property[]>([])
- const total = ref(0)
- const pageSize = ref(10)
- const pageNum = ref(1)
- const searchForm = reactive({
- userInfo: '',
- company: '',
- })
- const dialogVisible = ref(false)
- const dialogTitle = ref('')
- const isEdit = ref(false)
- const formData = reactive<Property>({})
- const formRef = ref<FormInstance>()
- const selectedIds = ref<string[]>([])
- // 欠费状态选项
- const arrearOptions = [
- { label: '是', value: '是' },
- { label: '否', value: '否' },
- ]
- // 一户一表选项
- const onehouseOptions = [
- { label: '是', value: '是' },
- { label: '否', value: '否' },
- ]
- // 获取欠费状态标签
- const getArrearLabel = (value: string | undefined) => {
- return arrearOptions.find((option) => option.value === value)?.label || '-'
- }
- // 获取一户一表标签
- const getOnehouseLabel = (value: string | undefined) => {
- return onehouseOptions.find((option) => option.value === value)?.label || '-'
- }
- // 接口调用函数
- const add = async (data: AddProperty) => {
- const res = await clientPost<AddProperty, BaseResponse>('/egas/save', {
- ...data,
- })
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return false
- }
- ElMessage.success(res.msg)
- return true
- }
- const getById = async (id: string) => {
- const res = await clientGet<null, PropertyOneResponse>('/egas/getById/' + id)
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return null
- }
- return res.data
- }
- const getList = async () => {
- const loading = ElLoading.service({ text: '加载中...' })
- try {
- const res = await clientGet<
- {
- pageNum: number
- pageSize: number
- userInfo?: string
- company?: string
- },
- PropertyListResponse
- >('/egas/findByPage', {
- params: {
- pageNum: pageNum.value,
- pageSize: pageSize.value,
- userInfo: searchForm.userInfo || undefined,
- company: searchForm.company || undefined,
- },
- })
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return
- }
- tableData.value = res.data.records
- total.value = res.data.total
- } catch (error) {
- ElMessage.error('获取数据失败')
- } finally {
- loading.close()
- }
- }
- const delBatch = async (ids: string[]) => {
- const res = await clientPost<string, BaseResponse>('/egas/deleteBatch', JSON.stringify(ids))
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return false
- }
- ElMessage.success(res.msg)
- return true
- }
- const update = async (data: UpdateProperty) => {
- const res = await clientPost<UpdateProperty, BaseResponse>('/egas/update', {
- ...data,
- })
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return false
- }
- ElMessage.success(res.msg)
- return true
- }
- const exportExcel = async () => {
- const loading = ElLoading.service({
- lock: true,
- text: '导出中,请稍候...',
- background: 'rgba(0, 0, 0, 0.1)',
- fullscreen: true,
- })
- try {
- await clientDownloadExcel('/egas/exportData', {
- params: {
- userInfo: searchForm.userInfo || undefined,
- company: searchForm.company || undefined,
- },
- })
- ElMessage.success('导出成功')
- } catch (error) {
- console.error('导出失败:', error)
- ElMessage.error('导出失败')
- } finally {
- loading.close()
- }
- }
- const importExcel = async (file: File) => {
- const formData = new FormData()
- formData.append('file', file)
- const res = await clientPost<FormData, BaseResponse>('/egas/importData', formData, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- })
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return false
- }
- ElMessage.success(res.msg)
- return true
- }
- // 事件处理函数
- const handleAdd = () => {
- isEdit.value = false
- dialogTitle.value = '新增燃气信息'
- // 重置表单数据
- Object.keys(formData).forEach((key) => delete formData[key as keyof Property])
- dialogVisible.value = true
- }
- const handleEdit = async (row: Property) => {
- isEdit.value = true
- dialogTitle.value = '编辑燃气信息'
- const data = await getById(row.id)
- if (data) {
- Object.assign(formData, data)
- dialogVisible.value = true
- }
- }
- const handleDelete = async (id: string) => {
- ElMessageBox.confirm('确定删除此条记录吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning',
- })
- .then(async () => {
- const success = await delBatch([id])
- if (success) {
- getList()
- }
- })
- .catch(() => {
- ElMessage.info('已取消删除')
- })
- }
- const handleBatchDelete = () => {
- if (selectedIds.value.length === 0) {
- ElMessage.warning('请选择要删除的记录')
- return
- }
- ElMessageBox.confirm(`确定删除选中的 ${selectedIds.value.length} 条记录吗?`, '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning',
- })
- .then(async () => {
- const success = await delBatch(selectedIds.value)
- if (success) {
- getList()
- }
- })
- .catch(() => {
- ElMessage.info('已取消批量删除')
- })
- }
- const handleSearch = () => {
- pageNum.value = 1
- getList()
- }
- const handleResetSearch = () => {
- searchForm.userInfo = ''
- searchForm.company = ''
- pageNum.value = 1
- getList()
- }
- const handleConfirm = async () => {
- if (!formRef.value) return
- await formRef.value.validate(async (valid) => {
- if (valid) {
- let success = false
- const dataToSend = { ...formData }
- if (isEdit.value) {
- success = await update(dataToSend)
- } else {
- success = await add(dataToSend)
- }
- if (success) {
- dialogVisible.value = false
- getList()
- }
- } else {
- ElMessage.error('请检查表单填写')
- }
- })
- }
- const handleCurrentChange = (val: number) => {
- pageNum.value = val
- getList()
- }
- const handleSizeChange = (val: number) => {
- pageSize.value = val
- pageNum.value = 1
- getList()
- }
- const handleSelectionChange = (selection: Property[]) => {
- selectedIds.value = selection.map((item) => item.id)
- }
- const handleUploadSuccess: UploadProps['onSuccess'] = async (response) => {
- if (response && response.code === 200) {
- ElMessage.success('文件导入成功')
- getList()
- } else {
- ElMessage.error(`文件导入失败: ${response?.msg || '未知错误'}`)
- }
- }
- const handleUploadError: UploadProps['onError'] = (error) => {
- ElMessage.error(`文件导入失败: ${error.message}`)
- }
- const handleBeforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
- const isExcel =
- rawFile.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
- rawFile.type === 'application/vnd.ms-excel'
- if (!isExcel) {
- ElMessage.error('导入文件只能是 Excel 格式!')
- return false
- }
- return true
- }
- // 初始化
- const init = () => {
- getList()
- }
- onMounted(() => {
- init()
- })
- </script>
- <template>
- <div class="p-4">
- <h1 class="text-2xl font-bold mb-6">燃气信息管理</h1>
- <!-- 搜索和操作栏 -->
- <div class="mb-6 p-4 bg-white rounded-lg shadow-sm flex flex-wrap items-center gap-4">
- <el-form :inline="true" :model="searchForm" class="flex-grow flex flex-wrap gap-x-4">
- <el-form-item label="燃气用户信息">
- <el-input v-model="searchForm.userInfo" placeholder="输入户名或户号" clearable />
- </el-form-item>
- <el-form-item label="企业名称">
- <el-input v-model="searchForm.company" placeholder="输入企业名称" clearable />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
- <el-button :icon="Refresh" @click="handleResetSearch">重置</el-button>
- </el-form-item>
- </el-form>
- <div class="flex gap-2">
- <el-button type="primary" :icon="Plus" @click="handleAdd">新增</el-button>
- <el-button
- type="danger"
- :icon="Delete"
- @click="handleBatchDelete"
- :disabled="selectedIds.length === 0"
- >批量删除</el-button
- >
- <el-button type="success" :icon="Download" @click="exportExcel">导出</el-button>
- <el-upload
- class="inline-block"
- action="/api/egas/importData"
- :show-file-list="false"
- :on-success="handleUploadSuccess"
- :on-error="handleUploadError"
- :before-upload="handleBeforeUpload"
- :http-request="(options) => importExcel(options.file)"
- >
- <el-button type="info" :icon="Upload">导入</el-button>
- </el-upload>
- </div>
- </div>
- <!-- 表格 -->
- <div class="bg-white rounded-lg shadow-sm p-4 overflow-x-auto">
- <el-table
- :data="tableData"
- style="width: 100%"
- border
- @selection-change="handleSelectionChange"
- >
- <el-table-column type="selection" width="55" fixed="left" />
- <el-table-column prop="company" label="企业名称" width="180" />
- <el-table-column prop="uniCode" label="统一社会信用代码" width="200" />
- <el-table-column prop="userInfo" label="燃气用户信息" width="180" />
- <el-table-column prop="isInArrears" label="是否欠费" width="100">
- <template #default="{ row }">
- <el-tag :type="row.isInArrears === '是' ? 'danger' : 'success'" v-if="row.isInArrears">
- {{ row.isInArrears }}
- </el-tag>
- <el-tag type="info" v-else>未知</el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="arrearageAmount" label="欠费金额" width="120" />
- <el-table-column prop="monthlyConsumption3" label="近3个月月均用量" width="150" />
- <el-table-column prop="monthlyConsumption6" label="近6个月月均用量" width="150" />
- <el-table-column prop="onehouseOnemeter" label="是否一户一表" width="120">
- <template #default="{ row }">
- <el-tag
- :type="row.onehouseOnemeter === '是' ? 'success' : 'info'"
- v-if="row.onehouseOnemeter"
- >
- {{ row.onehouseOnemeter }}
- </el-tag>
- <el-tag type="info" v-else>未知</el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="openDate" label="开户日期" width="150" />
- <el-table-column prop="userAddress" label="用户地址" width="200" />
- <el-table-column label="操作" width="180" fixed="right">
- <template #default="{ row }">
- <el-button :icon="Edit" size="small" @click="handleEdit(row)">编辑</el-button>
- <el-button type="danger" :icon="Delete" size="small" @click="handleDelete(row.id)"
- >删除</el-button
- >
- </template>
- </el-table-column>
- </el-table>
- <!-- 分页 -->
- <div class="mt-4 flex justify-end">
- <el-pagination
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- :current-page="pageNum"
- :page-sizes="[10, 20, 50, 100]"
- :page-size="pageSize"
- layout="total, sizes, prev, pager, next, jumper"
- :total="total"
- />
- </div>
- </div>
- <!-- 新增/编辑对话框 -->
- <el-dialog
- v-model="dialogVisible"
- :title="dialogTitle"
- width="800px"
- :close-on-click-modal="false"
- :close-on-press-escape="false"
- >
- <el-form
- :model="formData"
- ref="formRef"
- label-width="120px"
- class="grid grid-cols-1 md:grid-cols-2 gap-4"
- >
- <el-form-item
- label="企业名称"
- prop="company"
- :rules="[{ required: true, message: '请输入企业名称', trigger: 'blur' }]"
- >
- <el-input v-model="formData.company" placeholder="请输入企业名称" />
- </el-form-item>
- <el-form-item label="统一社会信用代码" prop="uniCode">
- <el-input v-model="formData.uniCode" placeholder="请输入统一社会信用代码" />
- </el-form-item>
- <el-form-item label="事项名称" prop="tableName">
- <el-input v-model="formData.tableName" placeholder="请输入事项名称" />
- </el-form-item>
- <el-form-item label="事项编码" prop="tableCode">
- <el-input v-model="formData.tableCode" placeholder="请输入事项编码" />
- </el-form-item>
- <el-form-item
- label="燃气用户信息"
- prop="userInfo"
- :rules="[{ required: true, message: '请输入燃气用户信息', trigger: 'blur' }]"
- >
- <el-input v-model="formData.userInfo" placeholder="请输入户名户号" />
- </el-form-item>
- <el-form-item label="缴纳燃气费明细" prop="paymentDetail">
- <el-input v-model="formData.paymentDetail" placeholder="请输入缴纳燃气费明细" />
- </el-form-item>
- <el-form-item label="近3个月月均用量" prop="monthlyConsumption3">
- <el-input
- v-model.number="formData.monthlyConsumption3"
- placeholder="请输入近3个月月均用量"
- />
- </el-form-item>
- <el-form-item label="近6个月月均用量" prop="monthlyConsumption6">
- <el-input
- v-model.number="formData.monthlyConsumption6"
- placeholder="请输入近6个月月均用量"
- />
- </el-form-item>
- <el-form-item label="当前是否欠费" prop="isInArrears">
- <el-radio-group v-model="formData.isInArrears">
- <el-radio :label="'是'">是</el-radio>
- <el-radio :label="'否'">否</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="欠费金额" prop="arrearageAmount">
- <el-input v-model="formData.arrearageAmount" placeholder="请输入欠费金额" />
- </el-form-item>
- <el-form-item label="类别" prop="entityZtlb">
- <el-input v-model="formData.entityZtlb" placeholder="请输入类别" />
- </el-form-item>
- <el-form-item label="开户日期" prop="openDate">
- <el-date-picker
- v-model="formData.openDate"
- type="date"
- placeholder="选择开户日期"
- value-format="YYYY-MM-DD"
- style="width: 100%"
- />
- </el-form-item>
- <el-form-item label="用户地址" prop="userAddress">
- <el-input v-model="formData.userAddress" placeholder="请输入用户地址" />
- </el-form-item>
- <el-form-item label="是否一户一表" prop="onehouseOnemeter">
- <el-radio-group v-model="formData.onehouseOnemeter">
- <el-radio :label="'是'">是</el-radio>
- <el-radio :label="'否'">否</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="缴费所属期" prop="paymentPeriod">
- <el-input v-model="formData.paymentPeriod" placeholder="请输入缴费所属期" />
- </el-form-item>
- <el-form-item label="统计日期" prop="statisticalDate">
- <el-date-picker
- v-model="formData.statisticalDate"
- type="date"
- placeholder="选择统计日期"
- value-format="YYYY-MM-DD"
- style="width: 100%"
- />
- </el-form-item>
- <el-form-item label="备注" prop="remark">
- <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" :rows="2" />
- </el-form-item>
- </el-form>
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="dialogVisible = false">取消</el-button>
- <el-button type="primary" @click="handleConfirm">确定</el-button>
- </span>
- </template>
- </el-dialog>
- </div>
- </template>
- <style scoped>
- /* 如有特定样式需求,可在此添加,否则UnoCSS会处理大部分样式 */
- </style>
|