| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750 |
- <template>
- <div class="p-4">
- <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">
- <el-form-item>
- <span slot="label" class="font-size-4.5">企业名称:</span>
- <el-input
- v-model="searchForm.enterpriseName"
- style="width: 240px"
- size="default"
- placeholder="请输入企业名称"
- @clear="handleSearch"
- />
- </el-form-item>
- <el-form-item>
- <span slot="label" class="font-size-4.5">信用代码:</span>
- <el-input
- v-model="searchForm.unifiedSocialCreditCode"
- style="width: 240px"
- size="default"
- placeholder="输入统一社会信用代码"
- clearable
- />
- </el-form-item>
- <el-form-item>
- <span slot="label" class="font-size-4.5">户号信息:</span>
- <el-input
- v-model="searchForm.accountNumber"
- style="width: 240px"
- size="default"
- placeholder="输入户号信息"
- clearable
- />
- </el-form-item>
- <el-form-item>
- <span slot="label" class="font-size-4.5">年度:</span>
- <el-select
- v-model="searchForm.year"
- style="width: 240px"
- size="default"
- placeholder="请选择年度"
- >
- <el-option
- v-for="item in annualOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" :icon="Search" @click="handleSearch" size="search"
- >查询
- </el-button>
- <el-button :icon="Refresh" @click="handleResetSearch" size="search">重置</el-button>
- </el-form-item>
- </el-form>
- <div class="flex gap-1" style="justify-content: flex-end">
- <el-button type="primary" :icon="Plus" @click="handleAdd" size="search">新增</el-button>
- <el-button
- type="danger"
- :icon="Delete"
- @click="handleBatchDelete"
- :disabled="selectedIds.length === 0"
- size="search"
- >批量删除
- </el-button>
- <el-button type="success" :icon="Download" @click="exportExcel" size="search"
- >导出</el-button
- >
- <el-upload
- class="inline-block ml-2"
- :action="base_url + '/eenterpriseGasAnnualStatistics/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" size="search">导入</el-button>
- </el-upload>
- </div>
- </div>
- <!-- Table -->
- <div class="bg-white rounded-lg shadow-sm p-4 overflow-x-auto">
- <el-table
- :data="tableData"
- style="width: 100%"
- border
- @selection-change="handleSelectionChange"
- :cell-style="{ fontSize: '14px' }"
- :header-cell-style="{ fontSize: '14px' }"
- :row-style="{ fontSize: '14px' }"
- >
- <el-table-column type="selection" width="55" fixed="left" />
- <el-table-column prop="enterpriseName" label="企业名称" align="center" />
- <el-table-column prop="unifiedSocialCreditCode" label="统一社会信用代码" align="center" />
- <el-table-column prop="accountNumber" label="户号信息" align="center" />
- <el-table-column prop="year" label="年度" align="center" />
- <el-table-column prop="openingDate" label="开户日期" align="center" />
- <el-table-column label="第一季度" align="center">
- <el-table-column prop="q1CubicMeter" label="用气量(m³)" align="center" />
- <el-table-column prop="q1Cost" label="费用" align="center" />
- </el-table-column>
- <el-table-column label="第二季度" align="center">
- <el-table-column prop="q2CubicMeter" label="用气量(m³)" align="center" />
- <el-table-column prop="q2CubicMeter" label="费用" align="center" />
- </el-table-column>
- <el-table-column label="第三季度" align="center">
- <el-table-column prop="q3CubicMeter" label="用气量(m³)" align="center" />
- <el-table-column prop="q3CubicMeter" label="费用" align="center" />
- </el-table-column>
- <el-table-column label="第四季度" align="center">
- <el-table-column prop="q4CubicMeter" label="用气量(m³)" align="center" />
- <el-table-column prop="q4CubicMeter" label="费用" align="center" />
- </el-table-column>
- <el-table-column label="年度总量" align="center">
- <el-table-column prop="annualTotalCubicMeter" label="用气量(m³)" align="center" />
- <el-table-column prop="annualTotalCost" label="费用" align="center" />
- </el-table-column>
- <el-table-column label="操作" fixed="right" align="center">
- <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>
- <!-- Pagination -->
- <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>
- <!-- Add/Edit Dialog -->
- <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="enterpriseName"
- :rules="[{ required: true, message: '请输入企业名称', trigger: 'blur' }]"
- >
- <el-input v-model="formData.enterpriseName" placeholder="请输入企业名称" />
- </el-form-item>
- <el-form-item
- label="信用代码"
- prop="unifiedSocialCreditCode"
- :rules="[{ required: true, message: '请输入统一社会信用代码', trigger: 'blur' }]"
- >
- <el-input
- v-model="formData.unifiedSocialCreditCode"
- placeholder="请输入统一社会信用代码"
- />
- </el-form-item>
- <el-form-item
- label="户号信息"
- prop="accountNumber"
- :rules="[{ required: true, message: '请输入户号信息', trigger: 'blur' }]"
- >
- <el-input v-model="formData.accountNumber" placeholder="请输入户号信息" />
- </el-form-item>
- <el-form-item
- label="开户日期"
- prop="openingDate"
- :rules="[{ required: true, message: '请选择开户日期', trigger: 'change' }]"
- >
- <el-date-picker
- v-model="formData.openingDate"
- type="date"
- format="YYYY/MM/DD"
- value-format="YYYY-MM-DD"
- />
- </el-form-item>
- <el-form-item
- label="年度"
- prop="year"
- :rules="[{ required: true, message: '请选择年度', trigger: 'change' }]"
- 部门
- >
- <el-select v-model="formData.year" placeholder="请选择年度" style="width: 100%">
- <el-option
- v-for="item in annualOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item
- label="第一季度费用"
- prop="q1Cost"
- :rules="[
- { required: true, message: '请输入第一季度费用', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q1Cost" placeholder="请输入第一季度费用" />
- </el-form-item>
- <el-form-item
- label="第一季度用气数"
- prop="q1CubicMeter"
- :rules="[
- { required: true, message: '请输入第一季度用气数', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q1CubicMeter" placeholder="请输入第一季度用气数" />
- </el-form-item>
- <el-form-item
- label="第二季度费用"
- prop="q2Cost"
- :rules="[
- { required: true, message: '请输入第二季度费用', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q2Cost" placeholder="请输入第二季度费用" />
- </el-form-item>
- <el-form-item
- label="第二季度用气数"
- prop="q2CubicMeter"
- :rules="[
- { required: true, message: '请输入第二季度用气数', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q2CubicMeter" placeholder="请输入第二季度用气数" />
- </el-form-item>
- <el-form-item
- label="第三季度费用"
- prop="q3Cost"
- :rules="[
- { required: true, message: '请输入第三季度费用', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q3Cost" placeholder="请输入第三季度费用" />
- </el-form-item>
- <el-form-item
- label="第三季度用气数"
- prop="q3CubicMeter"
- :rules="[
- { required: true, message: '请输入第三季度用气数', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q3CubicMeter" placeholder="请输入第三季度用气数" />
- </el-form-item>
- <el-form-item
- label="第四季度费用"
- prop="q4Cost"
- :rules="[
- { required: true, message: '请输入第四季度费用', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q4Cost" placeholder="请输入第四季度费用" />
- </el-form-item>
- <el-form-item
- label="第四季度用气数"
- prop="q4CubicMeter"
- :rules="[
- { required: true, message: '请输入第四季度用气数', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.q4CubicMeter" placeholder="请输入第四季度用气数" />
- </el-form-item>
- <el-form-item
- label="年度总费用"
- prop="annualTotalCost"
- :rules="[
- { required: true, message: '请输入年度总费用', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input v-model.number="formData.annualTotalCost" placeholder="请输入年度总费用" />
- </el-form-item>
- <el-form-item
- label="年度总度数"
- prop="annualTotalCubicMeter"
- :rules="[
- { required: true, message: '请输入年度总度数', trigger: 'blur' },
- { type: 'number', message: '请输入数字', trigger: 'blur' },
- ]"
- >
- <el-input
- v-model.number="formData.annualTotalCubicMeter"
- placeholder="请输入年度总度数"
- />
- </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>
- <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 { ElForm, ElLoading, ElMessage, ElMessageBox } from 'element-plus'
- import { Delete, Download, Edit, Plus, Refresh, Search, Upload } from '@element-plus/icons-vue'
- // 假设 BaseResponse 和 PageType 在全局或 request.ts 中已定义
- interface BaseResponse {
- code: number
- msg: string
- }
- interface PageType<T> {
- records: T[]
- total: number
- size: number
- current: number
- pages: number
- }
- interface Property {
- id: string // 主键ID
- enterpriseName: string // 单位名称
- unifiedSocialCreditCode: string // 统一社会信用代码
- year?: string // 年度(可选)
- accountNumber?: string // 户号信息
- q1Cost?: string // 第一季度费用
- q1CubicMeter?: string // 第一季度用气数
- q2Cost?: string // 第二季度费用
- q2CubicMeter?: string // 第二季度用气数
- q3Cost?: string // 第三季度费用
- q3CubicMeter?: string // 第三季度用气数
- q4Cost?: string // 第四季度费用
- q4CubicMeter?: string // 第四季度用气数
- annualTotalCost?: string // 年度总费用
- annualTotalCubicMeter?: string // 年度总度数
- openingDate?: string // 开户日期
- updateTime?: string // 更新时间
- createTime?: string // 创建时间
- createBy?: string // 创建人
- }
- interface PropertyOneResponse extends BaseResponse {
- data: Property
- }
- interface PropertyListResponse extends BaseResponse {
- data: PageType<Property>
- }
- interface AddProperty {
- enterpriseName: string // 单位名称
- unifiedSocialCreditCode: string // 统一社会信用代码
- year?: string // 年度(可选)
- accountNumber?: string // 户号信息
- q1Cost?: string // 第一季度费用
- q1CubicMeter?: string // 第一季度用气数
- q2Cost?: string // 第二季度费用
- q2CubicMeter?: string // 第二季度用气数
- q3Cost?: string // 第三季度费用
- q3CubicMeter?: string // 第三季度用气数
- q4Cost?: string // 第四季度费用
- q4CubicMeter?: string // 第四季度用气数
- annualTotalCost?: string // 年度总费用
- annualTotalCubicMeter?: string // 年度总度数
- openingDate?: string // 开户日期
- }
- interface UpdateProperty {
- id?: string
- enterpriseName: string // 单位名称
- unifiedSocialCreditCode: string // 统一社会信用代码
- year?: string // 年度(可选)
- accountNumber?: string // 户号信息
- q1Cost?: string // 第一季度费用
- q1CubicMeter?: string // 第一季度用气数
- q2Cost?: string // 第二季度费用
- q2CubicMeter?: string // 第二季度用气数
- q3Cost?: string // 第三季度费用
- q3CubicMeter?: string // 第三季度用气数
- q4Cost?: string // 第四季度费用
- q4CubicMeter?: string // 第四季度用气数
- annualTotalCost?: string // 年度总费用
- annualTotalCubicMeter?: string // 年度总度数
- openingDate?: string // 开户日期
- }
- // 响应式状态变量
- const tableData = ref<Property[]>([])
- const total = ref(0)
- const pageSize = ref(10)
- const pageNum = ref(1)
- const searchForm = reactive({
- accountNumber: '',
- enterpriseName: '',
- unifiedSocialCreditCode: '',
- year: '',
- })
- const dialogVisible = ref(false)
- const dialogTitle = ref('')
- const isEdit = ref(false)
- const formData = reactive<Property>({})
- const formRef = ref<FormInstance>()
- const selectedIds = ref<string[]>([])
- const base_url = import.meta.env.VITE_APP_BASE_API
- // 欠缴状态选项
- const arrearsOptions = [
- { label: '是', value: '是' },
- { label: '否', value: '否' },
- ]
- // 年度选项(动态生成最近5年)
- const currentYear = new Date().getFullYear()
- const annualOptions = Array.from({ length: 10 }, (_, i) => ({
- label: `${currentYear - i}年`,
- value: `${currentYear - i}`,
- }))
- // 新增
- const add = async (data: AddProperty) => {
- const res = await clientPost<AddProperty, BaseResponse>('/eenterpriseGasAnnualStatistics/save', {
- ...data,
- })
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return false
- }
- ElMessage.success(res.msg)
- return true
- }
- // 根据id获取数据
- const getById = async (id: string) => {
- const res = await clientGet<null, PropertyOneResponse>(
- '/eenterpriseGasAnnualStatistics/getById/' + id,
- )
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return null
- }
- return res.data
- }
- // 分页获取数据
- const getList = async () => {
- // 构建参数对象,只包含有值的搜索条件
- const params = {
- pageNum: pageNum.value,
- pageSize: pageSize.value,
- ...(searchForm.accountNumber ? { accountNumber: searchForm.accountNumber } : {}),
- ...(searchForm.unifiedSocialCreditCode
- ? { unifiedSocialCreditCode: searchForm.unifiedSocialCreditCode }
- : {}),
- ...(searchForm.enterpriseName ? { enterpriseName: searchForm.enterpriseName } : {}),
- ...(searchForm.year ? { year: searchForm.year } : {}),
- }
- const res = await clientGet<
- {
- pageNum: number
- pageSize: number
- accountNumber?: string
- unifiedSocialCreditCode?: string
- enterpriseName?: string
- year?: string
- },
- PropertyListResponse
- >('/eenterpriseGasAnnualStatistics/findByPage', {
- params,
- })
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return
- }
- tableData.value = res.data.records
- total.value = res.data.total
- }
- // 批量删除
- const delBatch = async (ids: string[]) => {
- const res = await clientPost<string[], BaseResponse>(
- '/eenterpriseGasAnnualStatistics/deleteBatch',
- 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>(
- '/eenterpriseGasAnnualStatistics/update',
- {
- ...data,
- },
- )
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return false
- }
- ElMessage.success(res.msg)
- return true
- }
- // 导出为excel
- const exportExcel = async () => {
- const loading = ElLoading.service({
- lock: true,
- text: '导出中,请稍候...',
- background: 'rgba(0, 0, 0, 0.1)',
- fullscreen: true,
- })
- try {
- // 构建参数对象,只包含有值的搜索条件
- const params = {
- ...(searchForm.accountNumber ? { accountNumber: searchForm.accountNumber } : {}),
- ...(searchForm.unifiedSocialCreditCode
- ? { unifiedSocialCreditCode: searchForm.unifiedSocialCreditCode }
- : {}),
- ...(searchForm.enterpriseName ? { enterpriseName: searchForm.enterpriseName } : {}),
- ...(searchForm.year ? { year: searchForm.year } : {}),
- }
- await clientDownloadExcel('/eenterpriseGasAnnualStatistics/exportData', {
- params,
- })
- ElMessage.success('导出成功')
- } catch (error) {
- console.error('导出失败:', error)
- ElMessage.error('导出失败')
- } finally {
- loading.close()
- }
- }
- // excel导入
- const importExcel = async (file: File) => {
- const formData = new FormData()
- formData.append('file', file)
- const res = await clientPost<FormData, BaseResponse>(
- '/eenterpriseGasAnnualStatistics/importData',
- formData,
- {
- headers: {
- 'Content-Type': 'multipart/form-data',
- },
- },
- )
- if (res.code !== 200) {
- ElMessage.error(res.msg)
- return false
- }
- ElMessage.success(res.msg)
- getList()
- return true
- }
- // --- CRUD 操作和处理函数 ---
- const handleAdd = () => {
- isEdit.value = false
- dialogTitle.value = '新增用水信息'
- // 重置表单数据
- Object.keys(formData).forEach((key) => delete formData[key as keyof Property])
- // 设置默认值为当前年度
- formData.openingDate = `${currentYear}`
- 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.accountNumber = ''
- searchForm.unifiedSocialCreditCode = ''
- searchForm.enterpriseName = ''
- searchForm.year = ''
- 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, uploadFile) => {
- 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>
- <style scoped>
- /* Add any specific styles here if needed, otherwise UnoCSS handles most */
- </style>
|