10 changed files with 897 additions and 0 deletions
@ -0,0 +1,71 @@ |
|||||
|
package com.zdxt.enforcementcode.controller.web.supervision.report; |
||||
|
|
||||
|
import com.zdxt.enforcementcode.domain.bo.EnforcementRegistrationBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationAnalysisVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationStatisticsAnalysisDetailVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationStatisticsAnalysisExportVo; |
||||
|
import com.zdxt.enforcementcode.report.IEnforcementRegistrationStatisticsService; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.dromara.common.core.domain.R; |
||||
|
import org.dromara.common.excel.utils.ExcelUtil; |
||||
|
import org.dromara.common.mybatis.core.page.PageQuery; |
||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo; |
||||
|
import org.springframework.validation.annotation.Validated; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析(独立菜单页,按企业维度聚合统计执法次数) |
||||
|
* |
||||
|
* @author zdxt |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Validated |
||||
|
@RequiredArgsConstructor |
||||
|
@RestController |
||||
|
@RequestMapping("/web/supervision/report/registration-statistics") |
||||
|
public class RegistrationStatisticsController { |
||||
|
|
||||
|
private final IEnforcementRegistrationStatisticsService statisticsService; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析列表(分页,V2排序) |
||||
|
*/ |
||||
|
@GetMapping("/list") |
||||
|
public TableDataInfo<RegistrationAnalysisVo> list(EnforcementRegistrationBo bo, PageQuery pageQuery) { |
||||
|
return statisticsService.list(bo, pageQuery); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执法分析详情(指定企业的执法明细聚合) |
||||
|
*/ |
||||
|
@GetMapping("/detail") |
||||
|
public R<List<RegistrationStatisticsAnalysisDetailVo>> detail(EnforcementRegistrationBo bo) { |
||||
|
return R.ok(statisticsService.detail(bo)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执法分析导出 |
||||
|
*/ |
||||
|
@PostMapping("/exportList") |
||||
|
public void exportList(EnforcementRegistrationBo bo, HttpServletResponse response) { |
||||
|
try { |
||||
|
List<RegistrationStatisticsAnalysisExportVo> list = statisticsService.exportList(bo); |
||||
|
ExcelUtil.exportExcel(list, "执法分析", RegistrationStatisticsAnalysisExportVo.class, response); |
||||
|
} catch (Exception e) { |
||||
|
log.error("导出执法分析Excel异常", e); |
||||
|
response.reset(); |
||||
|
response.setContentType("application/json; charset=utf-8"); |
||||
|
try { |
||||
|
response.getWriter().write("{\"code\":500,\"msg\":\"导出失败: " + e.getMessage() + "\"}"); |
||||
|
} catch (Exception ignored) { |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.report; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析-详情弹窗VO(指定企业的执法明细聚合) |
||||
|
* |
||||
|
* @author zdxt |
||||
|
*/ |
||||
|
@Data |
||||
|
public class RegistrationStatisticsAnalysisDetailVo implements Serializable { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* 执法单位 |
||||
|
*/ |
||||
|
private String bureauDeptName; |
||||
|
|
||||
|
/** |
||||
|
* 执法人员 |
||||
|
*/ |
||||
|
private String lawEnforcer; |
||||
|
|
||||
|
/** |
||||
|
* 执法事项 |
||||
|
*/ |
||||
|
private String lawEnforcementItemText; |
||||
|
|
||||
|
/** |
||||
|
* 数量(同一执法单位+人员+事项的次数) |
||||
|
*/ |
||||
|
private Integer total; |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.report; |
||||
|
|
||||
|
import cn.idev.excel.annotation.ExcelIgnoreUnannotated; |
||||
|
import cn.idev.excel.annotation.ExcelProperty; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析-导出Excel VO(12列,对齐旧系统导出格式) |
||||
|
* |
||||
|
* @author zdxt |
||||
|
*/ |
||||
|
@Data |
||||
|
@ExcelIgnoreUnannotated |
||||
|
public class RegistrationStatisticsAnalysisExportVo implements Serializable { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
@ExcelProperty(value = "区域") |
||||
|
private String district; |
||||
|
|
||||
|
@ExcelProperty(value = "街道") |
||||
|
private String street; |
||||
|
|
||||
|
@ExcelProperty(value = "企业名称") |
||||
|
private String enterpriseName; |
||||
|
|
||||
|
@ExcelProperty(value = "执法单位") |
||||
|
private String bureauDeptName; |
||||
|
|
||||
|
@ExcelProperty(value = "执法人员") |
||||
|
private String lawEnforcer; |
||||
|
|
||||
|
@ExcelProperty(value = "执法事项") |
||||
|
private String lawEnforcementItemText; |
||||
|
|
||||
|
@ExcelProperty(value = "执法时间") |
||||
|
private String enforcementTime; |
||||
|
|
||||
|
@ExcelProperty(value = "执法次数") |
||||
|
private Integer totalCount; |
||||
|
|
||||
|
@ExcelProperty(value = "2次及以下") |
||||
|
private String level2; |
||||
|
|
||||
|
@ExcelProperty(value = "3至4次(黄色)") |
||||
|
private String level34; |
||||
|
|
||||
|
@ExcelProperty(value = "5至6次(橙色)") |
||||
|
private String level56; |
||||
|
|
||||
|
@ExcelProperty(value = "7次及以上(红色)") |
||||
|
private String level7plus; |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
package com.zdxt.enforcementcode.report; |
||||
|
|
||||
|
import com.zdxt.enforcementcode.domain.bo.EnforcementRegistrationBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationAnalysisVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationStatisticsAnalysisDetailVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationStatisticsAnalysisExportVo; |
||||
|
import org.dromara.common.mybatis.core.page.PageQuery; |
||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析服务接口(独立菜单页,按企业维度聚合统计执法次数) |
||||
|
* |
||||
|
* @author zdxt |
||||
|
*/ |
||||
|
public interface IEnforcementRegistrationStatisticsService { |
||||
|
|
||||
|
/** |
||||
|
* 执法分析列表(分页,V2排序) |
||||
|
*/ |
||||
|
TableDataInfo<RegistrationAnalysisVo> list(EnforcementRegistrationBo bo, PageQuery pageQuery); |
||||
|
|
||||
|
/** |
||||
|
* 执法分析详情(指定企业的逐条执法记录聚合) |
||||
|
*/ |
||||
|
List<RegistrationStatisticsAnalysisDetailVo> detail(EnforcementRegistrationBo bo); |
||||
|
|
||||
|
/** |
||||
|
* 执法分析导出(全量,V2排序) |
||||
|
*/ |
||||
|
List<RegistrationStatisticsAnalysisExportVo> exportList(EnforcementRegistrationBo bo); |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
package com.zdxt.enforcementcode.report.impl; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
import com.zdxt.enforcementcode.domain.bo.EnforcementRegistrationBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationAnalysisVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationStatisticsAnalysisDetailVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.report.RegistrationStatisticsAnalysisExportVo; |
||||
|
import com.zdxt.enforcementcode.mapper.EnforcementRegistrationMapper; |
||||
|
import com.zdxt.enforcementcode.report.IEnforcementRegistrationStatisticsService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.dromara.common.mybatis.core.page.PageQuery; |
||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析服务实现(独立菜单页,按企业维度聚合统计执法次数,V2排序) |
||||
|
* |
||||
|
* @author zdxt |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@RequiredArgsConstructor |
||||
|
@Service |
||||
|
public class EnforcementRegistrationStatisticsServiceImpl implements IEnforcementRegistrationStatisticsService { |
||||
|
|
||||
|
private final EnforcementRegistrationMapper registrationMapper; |
||||
|
|
||||
|
@Override |
||||
|
public TableDataInfo<RegistrationAnalysisVo> list(EnforcementRegistrationBo bo, PageQuery pageQuery) { |
||||
|
Page<RegistrationAnalysisVo> page = pageQuery.build(); |
||||
|
IPage<RegistrationAnalysisVo> result = registrationMapper.selectAnalysisPageV2(page, bo, null); |
||||
|
return TableDataInfo.build(result); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<RegistrationStatisticsAnalysisDetailVo> detail(EnforcementRegistrationBo bo) { |
||||
|
return registrationMapper.selectAnalysisDetail(bo, null); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<RegistrationStatisticsAnalysisExportVo> exportList(EnforcementRegistrationBo bo) { |
||||
|
// 全量加载(不分页)
|
||||
|
Page<RegistrationAnalysisVo> page = new Page<>(1, Integer.MAX_VALUE, false); |
||||
|
IPage<RegistrationAnalysisVo> result = registrationMapper.selectAnalysisPageV2(page, bo, null); |
||||
|
List<RegistrationAnalysisVo> records = result.getRecords(); |
||||
|
|
||||
|
// 转换为导出VO(含颜色分级列)
|
||||
|
return records.stream().map(vo -> { |
||||
|
RegistrationStatisticsAnalysisExportVo exportVo = new RegistrationStatisticsAnalysisExportVo(); |
||||
|
exportVo.setDistrict(vo.getDistrict()); |
||||
|
exportVo.setStreet(vo.getStreet()); |
||||
|
exportVo.setEnterpriseName(vo.getEnterpriseName()); |
||||
|
exportVo.setBureauDeptName(vo.getBureauDeptName()); |
||||
|
exportVo.setLawEnforcer(vo.getLawEnforcer()); |
||||
|
exportVo.setLawEnforcementItemText(vo.getLawEnforcementItemText()); |
||||
|
exportVo.setEnforcementTime(vo.getEnforcementTime()); |
||||
|
exportVo.setTotalCount(vo.getTotalCount()); |
||||
|
|
||||
|
// 颜色分级列
|
||||
|
int count = vo.getTotalCount() != null ? vo.getTotalCount() : 0; |
||||
|
exportVo.setLevel2(count <= 2 ? String.valueOf(count) : "-"); |
||||
|
exportVo.setLevel34(count >= 3 && count <= 4 ? String.valueOf(count) : "-"); |
||||
|
exportVo.setLevel56(count >= 5 && count <= 6 ? String.valueOf(count) : "-"); |
||||
|
exportVo.setLevel7plus(count >= 7 ? String.valueOf(count) : "-"); |
||||
|
|
||||
|
return exportVo; |
||||
|
}).collect(Collectors.toList()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
|
||||
|
const BASE_URL = '/web/supervision/report/registration-statistics'; |
||||
|
|
||||
|
/** 查询参数 */ |
||||
|
export interface AnalysisQuery { |
||||
|
pageNum?: number; |
||||
|
pageSize?: number; |
||||
|
bureauDeptName?: string; |
||||
|
lawEnforcer?: string; |
||||
|
enterpriseName?: string; |
||||
|
lawEnforcementItemText?: string; |
||||
|
district?: string; |
||||
|
street?: string; |
||||
|
dateType?: number; |
||||
|
dateSearch?: string; |
||||
|
beginTime?: string; |
||||
|
endTime?: string; |
||||
|
numLeft?: string; |
||||
|
numRight?: string; |
||||
|
num?: string; |
||||
|
enterpriseNumber?: string; |
||||
|
} |
||||
|
|
||||
|
/** 执法分析行VO */ |
||||
|
export interface RegistrationAnalysisVo { |
||||
|
district: string; |
||||
|
street: string; |
||||
|
enterpriseName: string; |
||||
|
enterpriseNumber: string; |
||||
|
bureauDeptName: string; |
||||
|
lawEnforcer: string; |
||||
|
lawEnforcementItemText: string; |
||||
|
enforcementTime: string; |
||||
|
totalCount: number; |
||||
|
colorLevel: string; |
||||
|
} |
||||
|
|
||||
|
/** 详情VO */ |
||||
|
export interface AnalysisDetailVo { |
||||
|
bureauDeptName: string; |
||||
|
lawEnforcer: string; |
||||
|
lawEnforcementItemText: string; |
||||
|
total: number; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执法分析列表(分页) |
||||
|
*/ |
||||
|
export const getAnalysisList = (params: AnalysisQuery): AxiosPromise => { |
||||
|
return request({ |
||||
|
url: `${BASE_URL}/list`, |
||||
|
method: 'get', |
||||
|
params |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析详情(指定企业执法明细) |
||||
|
*/ |
||||
|
export const getAnalysisDetail = (params: AnalysisQuery): AxiosPromise => { |
||||
|
return request({ |
||||
|
url: `${BASE_URL}/detail`, |
||||
|
method: 'get', |
||||
|
params |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 执法分析导出 |
||||
|
*/ |
||||
|
export const exportAnalysisList = (params: AnalysisQuery): AxiosPromise<Blob> => { |
||||
|
return request({ |
||||
|
url: `${BASE_URL}/exportList`, |
||||
|
method: 'post', |
||||
|
params, |
||||
|
responseType: 'blob' |
||||
|
}); |
||||
|
}; |
||||
@ -0,0 +1,367 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'; |
||||
|
import { ElMessage } from 'element-plus'; |
||||
|
import { |
||||
|
getAnalysisList, getAnalysisDetail, exportAnalysisList |
||||
|
} from '@/api/efcode/report/registration-statistics'; |
||||
|
import type { AnalysisQuery, RegistrationAnalysisVo, AnalysisDetailVo } from '@/api/efcode/report/registration-statistics'; |
||||
|
import { getDicts } from '@/api/system/dict/data'; |
||||
|
|
||||
|
// 查询参数 |
||||
|
const queryParams = reactive<AnalysisQuery>({ |
||||
|
pageNum: 1, |
||||
|
pageSize: 20, |
||||
|
bureauDeptName: undefined, |
||||
|
lawEnforcer: undefined, |
||||
|
enterpriseName: undefined, |
||||
|
lawEnforcementItemText: undefined, |
||||
|
district: undefined, |
||||
|
street: undefined, |
||||
|
dateType: undefined, |
||||
|
dateSearch: undefined, |
||||
|
beginTime: undefined, |
||||
|
endTime: undefined |
||||
|
}); |
||||
|
|
||||
|
const loading = ref(false); |
||||
|
const tableData = ref<RegistrationAnalysisVo[]>([]); |
||||
|
const total = ref(0); |
||||
|
const tableHeight = ref<number | undefined>(undefined); |
||||
|
const tableRef = ref(); |
||||
|
|
||||
|
// 字典 |
||||
|
const addressTypeOptions = ref<any[]>([]); |
||||
|
const streetOptions = ref<any[]>([]); |
||||
|
|
||||
|
// 时段模式 |
||||
|
const timeMode = ref('year'); |
||||
|
const selectedYear = ref<string>(String(new Date().getFullYear())); |
||||
|
const selectedQuarter = ref<number>(Math.ceil((new Date().getMonth() + 1) / 3)); |
||||
|
const selectedMonth = ref<string>(''); |
||||
|
|
||||
|
// 季度选项 |
||||
|
const quarterOptions = [ |
||||
|
{ label: '第一季度', value: 1 }, |
||||
|
{ label: '第二季度', value: 2 }, |
||||
|
{ label: '第三季度', value: 3 }, |
||||
|
{ label: '第四季度', value: 4 } |
||||
|
]; |
||||
|
|
||||
|
// 年份选项 |
||||
|
const yearOptions = (() => { |
||||
|
const curr = new Date().getFullYear(); |
||||
|
return Array.from({ length: 5 }, (_, i) => String(curr - i)); |
||||
|
})(); |
||||
|
|
||||
|
// 详情弹窗 |
||||
|
const detailDialogVisible = ref(false); |
||||
|
const detailLoading = ref(false); |
||||
|
const detailData = ref<AnalysisDetailVo[]>([]); |
||||
|
const detailEnterpriseName = ref(''); |
||||
|
|
||||
|
onMounted(() => { |
||||
|
loadDicts(); |
||||
|
applyYearFilter(); |
||||
|
handleQuery(); |
||||
|
nextTick(() => calcTableHeight()); |
||||
|
window.addEventListener('resize', calcTableHeight); |
||||
|
}); |
||||
|
|
||||
|
onUnmounted(() => { |
||||
|
window.removeEventListener('resize', calcTableHeight); |
||||
|
}); |
||||
|
|
||||
|
/** 计算表格高度 */ |
||||
|
const calcTableHeight = () => { |
||||
|
const el = tableRef.value?.$el as HTMLElement; |
||||
|
if (!el) return; |
||||
|
const rect = el.getBoundingClientRect(); |
||||
|
tableHeight.value = window.innerHeight - rect.top - 102; |
||||
|
}; |
||||
|
|
||||
|
/** 加载字典 */ |
||||
|
const loadDicts = async () => { |
||||
|
try { |
||||
|
const res = await getDicts('address_type'); |
||||
|
addressTypeOptions.value = res.data || []; |
||||
|
} catch (e) { |
||||
|
console.error('加载字典失败', e); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 区域变更时加载街道 */ |
||||
|
const handleDistrictChange = async (val: string) => { |
||||
|
queryParams.street = undefined; |
||||
|
streetOptions.value = []; |
||||
|
if (val) { |
||||
|
try { |
||||
|
const matched = addressTypeOptions.value.find((item: any) => item.dictLabel === val); |
||||
|
if (matched) { |
||||
|
const res = await getDicts(matched.dictValue); |
||||
|
streetOptions.value = res.data || []; |
||||
|
} |
||||
|
} catch (e) {} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 时段模式变更 */ |
||||
|
const handleTimeModeChange = (mode: string) => { |
||||
|
queryParams.dateType = undefined; |
||||
|
queryParams.dateSearch = undefined; |
||||
|
queryParams.beginTime = undefined; |
||||
|
queryParams.endTime = undefined; |
||||
|
if (mode === 'year') { |
||||
|
applyYearFilter(); |
||||
|
} else if (mode === 'quarter') { |
||||
|
applyQuarterFilter(); |
||||
|
} else if (mode === 'month') { |
||||
|
const now = new Date(); |
||||
|
selectedMonth.value = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`; |
||||
|
applyMonthFilter(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 年度筛选 */ |
||||
|
const applyYearFilter = () => { |
||||
|
const year = selectedYear.value; |
||||
|
queryParams.beginTime = `${year}-01-01`; |
||||
|
queryParams.endTime = `${year}-12-31`; |
||||
|
}; |
||||
|
|
||||
|
/** 季度筛选 */ |
||||
|
const applyQuarterFilter = () => { |
||||
|
const year = selectedYear.value; |
||||
|
const q = selectedQuarter.value; |
||||
|
const startMonth = (q - 1) * 3 + 1; |
||||
|
const endMonth = q * 3; |
||||
|
const endDay = new Date(Number(year), endMonth, 0).getDate(); |
||||
|
queryParams.beginTime = `${year}-${String(startMonth).padStart(2, '0')}-01`; |
||||
|
queryParams.endTime = `${year}-${String(endMonth).padStart(2, '0')}-${endDay}`; |
||||
|
}; |
||||
|
|
||||
|
/** 月度筛选 */ |
||||
|
const applyMonthFilter = () => { |
||||
|
if (selectedMonth.value) { |
||||
|
queryParams.dateSearch = selectedMonth.value; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 年份变更 */ |
||||
|
const handleYearChange = () => { |
||||
|
if (timeMode.value === 'year') { |
||||
|
applyYearFilter(); |
||||
|
} else if (timeMode.value === 'quarter') { |
||||
|
applyQuarterFilter(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 季度变更 */ |
||||
|
const handleQuarterChange = () => { |
||||
|
applyQuarterFilter(); |
||||
|
}; |
||||
|
|
||||
|
/** 月份变更 */ |
||||
|
const handleMonthChange = (val: string) => { |
||||
|
selectedMonth.value = val; |
||||
|
queryParams.dateSearch = val; |
||||
|
}; |
||||
|
|
||||
|
/** 搜索 */ |
||||
|
const handleQuery = () => { |
||||
|
queryParams.pageNum = 1; |
||||
|
getList(); |
||||
|
}; |
||||
|
|
||||
|
/** 重置 */ |
||||
|
const resetQuery = () => { |
||||
|
Object.assign(queryParams, { |
||||
|
pageNum: 1, |
||||
|
pageSize: 20, |
||||
|
bureauDeptName: undefined, |
||||
|
lawEnforcer: undefined, |
||||
|
enterpriseName: undefined, |
||||
|
lawEnforcementItemText: undefined, |
||||
|
district: undefined, |
||||
|
street: undefined, |
||||
|
dateType: undefined, |
||||
|
dateSearch: undefined, |
||||
|
beginTime: undefined, |
||||
|
endTime: undefined |
||||
|
}); |
||||
|
timeMode.value = 'year'; |
||||
|
selectedYear.value = String(new Date().getFullYear()); |
||||
|
selectedQuarter.value = Math.ceil((new Date().getMonth() + 1) / 3); |
||||
|
selectedMonth.value = ''; |
||||
|
streetOptions.value = []; |
||||
|
applyYearFilter(); |
||||
|
handleQuery(); |
||||
|
}; |
||||
|
|
||||
|
/** 查询列表 */ |
||||
|
const getList = async () => { |
||||
|
loading.value = true; |
||||
|
try { |
||||
|
const res = await getAnalysisList(queryParams); |
||||
|
tableData.value = res.rows || []; |
||||
|
total.value = res.total || 0; |
||||
|
} finally { |
||||
|
loading.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 导出 */ |
||||
|
const handleExport = async () => { |
||||
|
try { |
||||
|
const res = await exportAnalysisList(queryParams); |
||||
|
const blob = new Blob([res as any], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); |
||||
|
const url = window.URL.createObjectURL(blob); |
||||
|
const link = document.createElement('a'); |
||||
|
link.href = url; |
||||
|
link.download = '执法分析.xlsx'; |
||||
|
link.click(); |
||||
|
window.URL.revokeObjectURL(url); |
||||
|
} catch (e) { |
||||
|
ElMessage.error('导出失败'); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 点击执法次数查看详情 */ |
||||
|
const handleShowDetail = async (row: RegistrationAnalysisVo) => { |
||||
|
detailEnterpriseName.value = row.enterpriseName; |
||||
|
detailDialogVisible.value = true; |
||||
|
detailLoading.value = true; |
||||
|
try { |
||||
|
const params: AnalysisQuery = { |
||||
|
enterpriseNumber: row.enterpriseNumber, |
||||
|
dateType: queryParams.dateType, |
||||
|
dateSearch: queryParams.dateSearch, |
||||
|
beginTime: queryParams.beginTime, |
||||
|
endTime: queryParams.endTime |
||||
|
}; |
||||
|
const res = await getAnalysisDetail(params); |
||||
|
detailData.value = res.data || []; |
||||
|
} catch (e) { |
||||
|
ElMessage.error('获取详情失败'); |
||||
|
detailData.value = []; |
||||
|
} finally { |
||||
|
detailLoading.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** 颜色分级列样式 */ |
||||
|
const getLevelCellStyle = (level: string) => { |
||||
|
const colorMap: Record<string, string> = { |
||||
|
yellow: '#e6a23c', |
||||
|
orange: '#f56c6c', |
||||
|
red: '#c00' |
||||
|
}; |
||||
|
return colorMap[level] || ''; |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="p-2"> |
||||
|
<!-- 搜索区域 --> |
||||
|
<div class="mb-[10px]"> |
||||
|
<el-card shadow="hover"> |
||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
||||
|
<el-form-item label="执法单位" prop="bureauDeptName"> |
||||
|
<el-input v-model="queryParams.bureauDeptName" placeholder="请输入执法单位" clearable @keyup.enter="handleQuery" style="width: 120px" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="执法人员" prop="lawEnforcer"> |
||||
|
<el-input v-model="queryParams.lawEnforcer" placeholder="请输入执法人员" clearable @keyup.enter="handleQuery" style="width: 90px" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="企业名称" prop="enterpriseName"> |
||||
|
<el-input v-model="queryParams.enterpriseName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" style="width: 120px" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="执法事项" prop="lawEnforcementItemText"> |
||||
|
<el-input v-model="queryParams.lawEnforcementItemText" placeholder="请输入执法事项" clearable @keyup.enter="handleQuery" style="width: 120px" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="时段"> |
||||
|
<el-select v-model="timeMode" style="width: 90px" @change="handleTimeModeChange"> |
||||
|
<el-option label="年度" value="year" /> |
||||
|
<el-option label="季度" value="quarter" /> |
||||
|
<el-option label="月度" value="month" /> |
||||
|
<el-option label="自定义" value="custom" /> |
||||
|
</el-select> |
||||
|
<el-select v-if="timeMode === 'year' || timeMode === 'quarter'" v-model="selectedYear" style="width: 100px; margin-left: 4px" @change="handleYearChange"> |
||||
|
<el-option v-for="y in yearOptions" :key="y" :label="y + '年'" :value="y" /> |
||||
|
</el-select> |
||||
|
<el-select v-if="timeMode === 'quarter'" v-model="selectedQuarter" style="width: 110px; margin-left: 4px" @change="handleQuarterChange"> |
||||
|
<el-option v-for="q in quarterOptions" :key="q.value" :label="q.label" :value="q.value" /> |
||||
|
</el-select> |
||||
|
<el-date-picker v-if="timeMode === 'month'" v-model="selectedMonth" type="month" placeholder="选择月份" value-format="YYYY-MM" style="width: 150px; margin-left: 4px" @change="handleMonthChange" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item v-if="timeMode === 'custom'" label="执法时间"> |
||||
|
<el-date-picker v-model="queryParams.beginTime" type="date" placeholder="开始日期" value-format="YYYY-MM-DD" style="width: 130px" /> |
||||
|
<span style="margin: 0 4px">-</span> |
||||
|
<el-date-picker v-model="queryParams.endTime" type="date" placeholder="结束日期" value-format="YYYY-MM-DD" style="width: 130px" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> |
||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button> |
||||
|
<el-button type="warning" icon="Download" @click="handleExport">导出</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
</el-card> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 表格区域 --> |
||||
|
<el-card shadow="hover"> |
||||
|
<el-table ref="tableRef" v-loading="loading" :data="tableData" :height="tableHeight" border stripe> |
||||
|
<el-table-column label="区域" prop="district" width="100" align="center" /> |
||||
|
<el-table-column label="街道" prop="street" width="120" align="center" /> |
||||
|
<el-table-column label="企业名称" prop="enterpriseName" min-width="200" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="执法单位" prop="bureauDeptName" min-width="150" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="执法人员" prop="lawEnforcer" min-width="120" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="执法事项" prop="lawEnforcementItemText" min-width="150" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="执法时间" prop="enforcementTime" width="110" align="center" /> |
||||
|
<el-table-column label="执法次数" width="100" align="center"> |
||||
|
<template #default="{ row }"> |
||||
|
<el-link type="success" :underline="false" @click="handleShowDetail(row)"> |
||||
|
{{ row.totalCount }} |
||||
|
</el-link> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="2次及以下" width="100" align="center"> |
||||
|
<template #default="{ row }"> |
||||
|
{{ row.totalCount <= 2 ? row.totalCount : '-' }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="3至4次" width="90" align="center"> |
||||
|
<template #default="{ row }"> |
||||
|
<span v-if="row.totalCount >= 3 && row.totalCount <= 4" style="color: #e6a23c; font-weight: bold;">{{ row.totalCount }}</span> |
||||
|
<span v-else>-</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="5至6次" width="90" align="center"> |
||||
|
<template #default="{ row }"> |
||||
|
<span v-if="row.totalCount >= 5 && row.totalCount <= 6" style="color: #f56c6c; font-weight: bold;">{{ row.totalCount }}</span> |
||||
|
<span v-else>-</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="7次及以上" width="100" align="center"> |
||||
|
<template #default="{ row }"> |
||||
|
<span v-if="row.totalCount >= 7" style="color: #c00; font-weight: bold;">{{ row.totalCount }}</span> |
||||
|
<span v-else>-</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
||||
|
</el-card> |
||||
|
|
||||
|
<!-- 详情弹窗 --> |
||||
|
<el-dialog v-model="detailDialogVisible" :title="`执法详情 - ${detailEnterpriseName}`" width="700px" append-to-body destroy-on-close> |
||||
|
<el-table v-loading="detailLoading" :data="detailData" border stripe max-height="400"> |
||||
|
<el-table-column label="执法单位" prop="bureauDeptName" min-width="150" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="执法人员" prop="lawEnforcer" min-width="120" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="执法事项" prop="lawEnforcementItemText" min-width="150" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="数量" prop="total" width="80" align="center" /> |
||||
|
</el-table> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
</style> |
||||
Loading…
Reference in new issue