You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
340 lines
10 KiB
340 lines
10 KiB
<script setup lang="ts">
|
|
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
|
|
import { getDicts } from '@/api/system/dict/data';
|
|
|
|
/** 企业行数据 */
|
|
interface EnterpriseRow {
|
|
id: number;
|
|
enterpriseName: string;
|
|
areaName: string;
|
|
streetName: string;
|
|
enforcementCount: number | null;
|
|
}
|
|
|
|
// ======================== 查询条件 ========================
|
|
const queryParams = reactive({
|
|
enterpriseName: '' as string,
|
|
area: undefined as string | undefined,
|
|
street: undefined as string | undefined
|
|
});
|
|
|
|
// 时段类型:week=周度 month=月度 quarter=季度 year=年度
|
|
const periodType = ref('month');
|
|
const periodOptions = [
|
|
{ label: '周度', value: 'week' },
|
|
{ label: '月度', value: 'month' },
|
|
{ label: '季度', value: 'quarter' },
|
|
{ label: '年度', value: 'year' }
|
|
];
|
|
const periodDate = ref<string>('2026-09');
|
|
|
|
/** 根据时段切换日期选择器类型 */
|
|
const pickerType = computed<'week' | 'month' | 'year'>(() => {
|
|
if (periodType.value === 'week') return 'week';
|
|
if (periodType.value === 'year') return 'year';
|
|
return 'month';
|
|
});
|
|
const pickerFormat = computed(() => {
|
|
if (pickerType.value === 'year') return 'YYYY';
|
|
if (pickerType.value === 'week') return 'YYYY-MM-DD';
|
|
return 'YYYY-MM';
|
|
});
|
|
|
|
// ======================== 区域/街道字典 ========================
|
|
const areaOptions = ref<any[]>([]);
|
|
const streetOptions = ref<any[]>([]);
|
|
|
|
const loadAreaDict = async () => {
|
|
try {
|
|
const res = await getDicts('address_type');
|
|
areaOptions.value = res.data || [];
|
|
} catch (e) {
|
|
console.error('加载所属区字典失败', e);
|
|
}
|
|
};
|
|
|
|
/** 切换所属区时联动加载所属街道 */
|
|
const handleAreaChange = async (val: string) => {
|
|
queryParams.street = undefined;
|
|
streetOptions.value = [];
|
|
if (!val) return;
|
|
try {
|
|
const res = await getDicts(val);
|
|
streetOptions.value = res.data || [];
|
|
} catch (e) {
|
|
console.error('加载所属街道字典失败', e);
|
|
}
|
|
};
|
|
|
|
// ======================== 表格数据 ========================
|
|
const loading = ref(false);
|
|
const tableData = ref<EnterpriseRow[]>([]);
|
|
const total = ref(0);
|
|
const currentPage = ref(1);
|
|
const pageSize = ref(20);
|
|
const selectedRows = ref<EnterpriseRow[]>([]);
|
|
|
|
// 表格高度(与 efcode/report/registration/indexList.vue 实现一致)
|
|
const tableHeight = ref<number | undefined>(undefined);
|
|
const tableRef = ref<HTMLElement>();
|
|
|
|
/** 计算表格高度:视口高度 - 表格顶部偏移 - 分页区高度(~52px) - 底部边距(16px) */
|
|
const calcTableHeight = () => {
|
|
if (!tableRef.value) return;
|
|
const rect = tableRef.value.getBoundingClientRect();
|
|
tableHeight.value = window.innerHeight - rect.top - 84;
|
|
};
|
|
|
|
/** 构造设计稿中的占位数据(前2条有数据,其余为空行) */
|
|
const buildMockRows = (): EnterpriseRow[] => {
|
|
const rows: EnterpriseRow[] = [
|
|
{ id: 1, enterpriseName: '深圳市宝安区西乡佳创电子厂', areaName: '宝安区', streetName: '光明街道', enforcementCount: 996 },
|
|
{ id: 2, enterpriseName: '深圳市黄金屋真空科技有限公司', areaName: '龙华区', streetName: '福海街道', enforcementCount: 990 }
|
|
];
|
|
for (let i = 3; i <= 7; i++) {
|
|
rows.push({ id: i, enterpriseName: '', areaName: '', streetName: '', enforcementCount: null });
|
|
}
|
|
return rows;
|
|
};
|
|
|
|
const getList = async () => {
|
|
loading.value = true;
|
|
try {
|
|
// TODO: 接入真实接口后替换为接口返回数据
|
|
// const res = await listKeyEnterprise({ ...queryParams, periodType: periodType.value, periodDate: periodDate.value, pageNum: currentPage.value, pageSize: pageSize.value });
|
|
tableData.value = buildMockRows();
|
|
total.value = 26064;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
/** 搜索 */
|
|
const handleSearch = () => {
|
|
currentPage.value = 1;
|
|
getList();
|
|
};
|
|
|
|
/** 重置 */
|
|
const handleReset = () => {
|
|
queryParams.enterpriseName = '';
|
|
queryParams.area = undefined;
|
|
queryParams.street = undefined;
|
|
streetOptions.value = [];
|
|
periodType.value = 'month';
|
|
periodDate.value = '2026-09';
|
|
currentPage.value = 1;
|
|
pageSize.value = 20;
|
|
getList();
|
|
};
|
|
|
|
/** 导出 */
|
|
const handleExport = () => {
|
|
// TODO: 接入导出接口后实现文件下载
|
|
};
|
|
|
|
/** 查看详情 */
|
|
const handleDetail = (_row: EnterpriseRow) => {
|
|
// TODO: 待详情页面创建后放开路由跳转
|
|
};
|
|
|
|
/** 多选 */
|
|
const handleSelectionChange = (selection: EnterpriseRow[]) => {
|
|
selectedRows.value = selection;
|
|
};
|
|
|
|
/** 切换每页条数 */
|
|
const handleSizeChange = (size: number) => {
|
|
pageSize.value = size;
|
|
currentPage.value = 1;
|
|
getList();
|
|
};
|
|
|
|
/** 翻页 */
|
|
const handlePageChange = (page: number) => {
|
|
currentPage.value = page;
|
|
getList();
|
|
};
|
|
|
|
onMounted(() => {
|
|
loadAreaDict();
|
|
getList();
|
|
nextTick(() => calcTableHeight());
|
|
window.addEventListener('resize', calcTableHeight);
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
window.removeEventListener('resize', calcTableHeight);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="key-enterprise-container">
|
|
<!-- ==================== 搜索区域 ==================== -->
|
|
<div class="search-panel">
|
|
<el-form :inline="true" label-colon>
|
|
<el-form-item label="企业名称">
|
|
<el-input
|
|
v-model="queryParams.enterpriseName"
|
|
placeholder="请输入关键字"
|
|
class="search-input"
|
|
clearable
|
|
@keyup.enter="handleSearch"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="所属区">
|
|
<el-select
|
|
v-model="queryParams.area"
|
|
placeholder="请选择"
|
|
class="search-select"
|
|
clearable
|
|
@change="handleAreaChange"
|
|
>
|
|
<el-option v-for="item in areaOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="所属街道">
|
|
<el-select
|
|
v-model="queryParams.street"
|
|
placeholder="请选择"
|
|
class="search-select"
|
|
clearable
|
|
>
|
|
<el-option v-for="item in streetOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="时段">
|
|
<el-select v-model="periodType" class="period-select">
|
|
<el-option v-for="item in periodOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-date-picker
|
|
v-model="periodDate"
|
|
:type="pickerType"
|
|
:format="pickerFormat"
|
|
:value-format="pickerFormat"
|
|
class="period-date"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
|
<el-button type="primary" @click="handleReset">重置</el-button>
|
|
<el-button @click="handleExport">导出</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</div>
|
|
|
|
<!-- ==================== 表格区域(表格样式对齐 /statistics/administrative/enterprise-enforcement) ==================== -->
|
|
<div class="table-panel">
|
|
<div ref="tableRef">
|
|
<el-table
|
|
v-loading="loading"
|
|
:data="tableData"
|
|
border
|
|
stripe
|
|
style="width: 100%"
|
|
:height="tableHeight"
|
|
@selection-change="handleSelectionChange"
|
|
>
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
<el-table-column label="序号" width="90" align="center">
|
|
<template #default="{ $index }">
|
|
{{ tableData[$index].enterpriseName ? $index + 1 : '' }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="enterpriseName" label="企业名称" min-width="300" align="center" />
|
|
<el-table-column prop="areaName" label="所属区" width="160" align="center" />
|
|
<el-table-column prop="streetName" label="所属街道" width="160" align="center" />
|
|
<el-table-column label="行政执法次数" width="180" align="center">
|
|
<template #default="{ row }">
|
|
<span v-if="row.enforcementCount !== null">{{ row.enforcementCount }}次</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="80" align="center">
|
|
<template #default="{ row }">
|
|
<el-button
|
|
v-if="row.enterpriseName"
|
|
type="primary"
|
|
link
|
|
size="small"
|
|
@click="handleDetail(row)"
|
|
>
|
|
详情
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</div>
|
|
|
|
<!-- ==================== 分页 ==================== -->
|
|
<el-pagination
|
|
v-model:current-page="currentPage"
|
|
v-model:page-size="pageSize"
|
|
:page-sizes="[10, 20, 50, 100]"
|
|
:total="total"
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
class="mt-4"
|
|
@size-change="handleSizeChange"
|
|
@current-change="handlePageChange"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.key-enterprise-container {
|
|
padding: 16px;
|
|
background: #f5f7fa;
|
|
min-height: calc(100vh - 84px);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* ==================== 搜索面板 ==================== */
|
|
.search-panel {
|
|
background: #fff;
|
|
border: 1px solid #e4e7ed;
|
|
border-radius: 4px;
|
|
padding: 18px 20px 0;
|
|
margin-bottom: 16px;
|
|
|
|
:deep(.el-form-item__label) {
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.search-input {
|
|
width: 210px;
|
|
}
|
|
|
|
.search-select {
|
|
width: 220px;
|
|
}
|
|
|
|
.period-select {
|
|
width: 110px;
|
|
}
|
|
|
|
.period-date {
|
|
width: 150px;
|
|
}
|
|
}
|
|
|
|
/* ==================== 表格面板 ==================== */
|
|
/* el-table 不做任何自定义皮肤覆盖,与
|
|
efcode/report/registration/indexList.vue(/statistics/administrative/enterprise-enforcement)
|
|
保持 100% 一致:原生 border + stripe + 动态高度 */
|
|
.table-panel {
|
|
background: #fff;
|
|
border: 1px solid #e4e7ed;
|
|
border-radius: 4px;
|
|
padding: 16px 20px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* ==================== 分页(元素合在一起,不做左右分布) ==================== */
|
|
.mt-4 {
|
|
margin-top: 16px;
|
|
justify-content: flex-end;
|
|
}
|
|
</style>
|
|
|