3 changed files with 1160 additions and 0 deletions
@ -0,0 +1,390 @@ |
|||
<script setup lang="ts"> |
|||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'; |
|||
import { getDicts } from '@/api/system/dict/data'; |
|||
|
|||
/** 表格行数据 */ |
|||
interface DistrictRow { |
|||
id: number; |
|||
areaName: string; |
|||
enterpriseCount: number; |
|||
adminEnforceCount: number; |
|||
adminRank: number; |
|||
adminPercent: string; |
|||
nonAdminEnforceCount: number; |
|||
nonAdminRank: number; |
|||
nonAdminPercent: string; |
|||
} |
|||
|
|||
// ======================== 查询条件 ======================== |
|||
const queryParams = reactive({ |
|||
area: undefined as string | undefined |
|||
}); |
|||
|
|||
const periodType = ref('month'); |
|||
const periodOptions = [ |
|||
{ label: '月度', value: 'month' } |
|||
]; |
|||
const periodDate = ref<string>('2026-09'); |
|||
|
|||
const pickerType = computed<'week' | 'month' | 'year'>(() => 'month'); |
|||
const pickerFormat = computed(() => 'YYYY-MM'); |
|||
|
|||
// ======================== 所属区字典 ======================== |
|||
const areaOptions = ref<any[]>([]); |
|||
|
|||
const loadAreaDict = async () => { |
|||
try { |
|||
const res = await getDicts('address_type'); |
|||
areaOptions.value = res.data || []; |
|||
} catch (e) { |
|||
console.error('加载所属区字典失败', e); |
|||
} |
|||
}; |
|||
|
|||
// ======================== 表格数据 ======================== |
|||
const loading = ref(false); |
|||
const tableData = ref<DistrictRow[]>([]); |
|||
const total = ref(0); |
|||
const currentPage = ref(1); |
|||
const pageSize = ref(20); |
|||
const selectedRows = ref<DistrictRow[]>([]); |
|||
|
|||
const tableHeight = ref<number | undefined>(undefined); |
|||
const tableRef = ref<HTMLElement>(); |
|||
|
|||
const calcTableHeight = () => { |
|||
if (!tableRef.value) return; |
|||
const rect = tableRef.value.getBoundingClientRect(); |
|||
tableHeight.value = window.innerHeight - rect.top - 84; |
|||
}; |
|||
|
|||
/** 构造图片中的 mock 数据 */ |
|||
const buildMockRows = (): DistrictRow[] => { |
|||
return [ |
|||
{ id: 1, areaName: '宝安区', enterpriseCount: 584119, adminEnforceCount: 14421, adminRank: 1, adminPercent: '60%', nonAdminEnforceCount: 9981, nonAdminRank: 1, nonAdminPercent: '60%' }, |
|||
{ id: 2, areaName: '龙岗区', enterpriseCount: 966252, adminEnforceCount: 11415, adminRank: 2, adminPercent: '56.64%', nonAdminEnforceCount: 184, nonAdminRank: 2, nonAdminPercent: '56.64%' }, |
|||
{ id: 3, areaName: '福田区', enterpriseCount: 615441, adminEnforceCount: 6135, adminRank: 4, adminPercent: '70%', nonAdminEnforceCount: 137, nonAdminRank: 4, nonAdminPercent: '70%' }, |
|||
{ id: 4, areaName: '南山区', enterpriseCount: 601902, adminEnforceCount: 5424, adminRank: 5, adminPercent: '80%', nonAdminEnforceCount: 389, nonAdminRank: 5, nonAdminPercent: '80%' }, |
|||
{ id: 5, areaName: '龙华区', enterpriseCount: 572932, adminEnforceCount: 4245, adminRank: 8, adminPercent: '67.5%', nonAdminEnforceCount: 22017, nonAdminRank: 8, nonAdminPercent: '67.5%' }, |
|||
{ id: 6, areaName: '罗湖区', enterpriseCount: 311483, adminEnforceCount: 5064, adminRank: 6, adminPercent: '63.2%', nonAdminEnforceCount: 888, nonAdminRank: 6, nonAdminPercent: '63.2%' }, |
|||
{ id: 7, areaName: '光明区', enterpriseCount: 192114, adminEnforceCount: 7040, adminRank: 3, adminPercent: '78.34%', nonAdminEnforceCount: 50384, nonAdminRank: 3, nonAdminPercent: '78.34%' }, |
|||
{ id: 8, areaName: '坪山区', enterpriseCount: 22103, adminEnforceCount: 3200, adminRank: 7, adminPercent: '55%', nonAdminEnforceCount: 1520, nonAdminRank: 7, nonAdminPercent: '55%' }, |
|||
{ id: 9, areaName: '大鹏新区', enterpriseCount: 11205, adminEnforceCount: 1860, adminRank: 9, adminPercent: '48%', nonAdminEnforceCount: 980, nonAdminRank: 9, nonAdminPercent: '48%' }, |
|||
{ id: 10, areaName: '盐田区', enterpriseCount: 13900, adminEnforceCount: 2150, adminRank: 10, adminPercent: '52%', nonAdminEnforceCount: 1050, nonAdminRank: 10, nonAdminPercent: '52%' } |
|||
]; |
|||
}; |
|||
|
|||
const getList = async () => { |
|||
loading.value = true; |
|||
try { |
|||
// TODO: 接入真实接口 listDistrictScanData |
|||
tableData.value = buildMockRows(); |
|||
total.value = 658; |
|||
} finally { |
|||
loading.value = false; |
|||
} |
|||
}; |
|||
|
|||
const handleSearch = () => { |
|||
currentPage.value = 1; |
|||
getList(); |
|||
}; |
|||
|
|||
const handleReset = () => { |
|||
queryParams.area = undefined; |
|||
periodType.value = 'month'; |
|||
periodDate.value = '2026-09'; |
|||
currentPage.value = 1; |
|||
pageSize.value = 20; |
|||
getList(); |
|||
}; |
|||
|
|||
const handleExport = () => { |
|||
// TODO: 接入导出接口 |
|||
}; |
|||
|
|||
const handleSelectionChange = (selection: DistrictRow[]) => { |
|||
selectedRows.value = selection; |
|||
}; |
|||
|
|||
const handleSizeChange = (size: number) => { |
|||
pageSize.value = size; |
|||
currentPage.value = 1; |
|||
getList(); |
|||
}; |
|||
|
|||
const handlePageChange = (page: number) => { |
|||
currentPage.value = page; |
|||
getList(); |
|||
}; |
|||
|
|||
// ======================== 详情弹窗 ======================== |
|||
interface ScanDetailRow { |
|||
id: number; |
|||
enterpriseName: string; |
|||
scanTime: string; |
|||
scanType: string; |
|||
bureauDeptName: string; |
|||
lawEnforcer: string; |
|||
enforcementItem: string; |
|||
} |
|||
|
|||
const detailDialogVisible = ref(false); |
|||
const detailArea = ref<DistrictRow | null>(null); |
|||
const detailLoading = ref(false); |
|||
const detailTableData = ref<ScanDetailRow[]>([]); |
|||
const detailTotal = ref(0); |
|||
const detailPage = ref(1); |
|||
const detailPageSize = ref(20); |
|||
|
|||
const buildDetailMockRows = (area: DistrictRow, count: number): ScanDetailRow[] => { |
|||
const rows: ScanDetailRow[] = []; |
|||
const enforcerPool = ['张三', '李四', '王五', '赵六', '钱七', '孙八']; |
|||
const bureauPool = [`${area.areaName}市场监督管理局`, `${area.areaName}市场监管局执法大队`]; |
|||
const scanTypePool = ['行政执法', '非行政执法']; |
|||
const enterprisePool = ['深圳市某某科技有限公司', '深圳市某某电子厂', '深圳市某某贸易有限公司']; |
|||
|
|||
for (let i = 1; i <= Math.min(count, 12); i++) { |
|||
const hour = String(8 + (i % 11)).padStart(2, '0'); |
|||
const minute = String((i * 17) % 60).padStart(2, '0'); |
|||
rows.push({ |
|||
id: i, |
|||
enterpriseName: enterprisePool[i % enterprisePool.length], |
|||
scanTime: `${periodDate.value}-${String(i % 28 + 1).padStart(2, '0')} ${hour}:${minute}:00`, |
|||
scanType: scanTypePool[i % scanTypePool.length], |
|||
bureauDeptName: bureauPool[i % bureauPool.length], |
|||
lawEnforcer: enforcerPool[i % enforcerPool.length], |
|||
enforcementItem: `${area.areaName}相关检查` |
|||
}); |
|||
} |
|||
return rows; |
|||
}; |
|||
|
|||
const getDetailList = async () => { |
|||
detailLoading.value = true; |
|||
try { |
|||
if (!detailArea.value) return; |
|||
// TODO: 接入真实接口 listDistrictScanDetail |
|||
detailTableData.value = buildDetailMockRows(detailArea.value, detailArea.value.adminEnforceCount); |
|||
detailTotal.value = detailArea.value.adminEnforceCount + detailArea.value.nonAdminEnforceCount; |
|||
} finally { |
|||
detailLoading.value = false; |
|||
} |
|||
}; |
|||
|
|||
const handleDetail = (row: DistrictRow) => { |
|||
detailArea.value = row; |
|||
detailPage.value = 1; |
|||
detailDialogVisible.value = true; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
const handleDetailSizeChange = (size: number) => { |
|||
detailPageSize.value = size; |
|||
detailPage.value = 1; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
const handleDetailPageChange = (page: number) => { |
|||
detailPage.value = page; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
loadAreaDict(); |
|||
getList(); |
|||
nextTick(() => calcTableHeight()); |
|||
window.addEventListener('resize', calcTableHeight); |
|||
}); |
|||
|
|||
onUnmounted(() => { |
|||
window.removeEventListener('resize', calcTableHeight); |
|||
}); |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="page-card"> |
|||
<!-- ==================== 搜索区域 ==================== --> |
|||
<div class="search-panel"> |
|||
<el-form :inline="true" label-colon> |
|||
<el-form-item label="所属区"> |
|||
<el-select |
|||
v-model="queryParams.area" |
|||
placeholder="请选择" |
|||
class="search-select" |
|||
clearable |
|||
> |
|||
<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="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> |
|||
|
|||
<!-- ==================== 表格区域 ==================== --> |
|||
<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="80" align="center" type="index" /> |
|||
<el-table-column prop="areaName" label="所属区" width="120" align="center" /> |
|||
<el-table-column prop="enterpriseCount" label="商事主体数量(户)" min-width="150" align="center" /> |
|||
<el-table-column prop="adminEnforceCount" label="行政执法数量(条)" min-width="150" align="center" /> |
|||
<el-table-column prop="adminRank" label="行政执法数量排名" min-width="150" align="center" /> |
|||
<el-table-column prop="adminPercent" label="行政执法数量占比(%)" min-width="170" align="center" /> |
|||
<el-table-column prop="nonAdminEnforceCount" label="非行政执法数量" min-width="140" align="center" /> |
|||
<el-table-column prop="nonAdminRank" label="非行政执法数量排名" min-width="160" align="center" /> |
|||
<el-table-column prop="nonAdminPercent" label="非行政执法数量占比(%)" min-width="180" align="center" /> |
|||
<el-table-column label="操作" width="80" align="center" fixed="right"> |
|||
<template #default="{ row }"> |
|||
<el-button 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> |
|||
|
|||
<!-- ==================== 扫码详情弹窗 ==================== --> |
|||
<el-dialog |
|||
v-model="detailDialogVisible" |
|||
width="1100px" |
|||
:title="`${detailArea?.areaName || ''} — ${periodDate} 扫码明细`" |
|||
append-to-body |
|||
top="5vh" |
|||
destroy-on-close |
|||
> |
|||
<el-alert |
|||
v-if="detailArea" |
|||
:closable="false" |
|||
show-icon |
|||
:title="`商事主体:${detailArea.enterpriseCount}户 | 行政执法:${detailArea.adminEnforceCount}条 | 非行政执法:${detailArea.nonAdminEnforceCount}条 | 时段:${periodDate}`" |
|||
type="info" |
|||
class="mb-4" |
|||
/> |
|||
|
|||
<el-table |
|||
v-loading="detailLoading" |
|||
:data="detailTableData" |
|||
border |
|||
stripe |
|||
style="width: 100%" |
|||
max-height="55vh" |
|||
> |
|||
<el-table-column label="序号" type="index" width="80" align="center" /> |
|||
<el-table-column label="企业名称" prop="enterpriseName" min-width="220" align="center" /> |
|||
<el-table-column label="扫码时间" prop="scanTime" min-width="180" align="center" /> |
|||
<el-table-column label="扫码类型" prop="scanType" width="120" align="center" /> |
|||
<el-table-column label="执法单位" prop="bureauDeptName" min-width="220" align="center" /> |
|||
<el-table-column label="执法人员" prop="lawEnforcer" width="120" align="center" /> |
|||
<el-table-column label="执法事项" prop="enforcementItem" min-width="200" align="center" /> |
|||
</el-table> |
|||
|
|||
<el-pagination |
|||
v-model:current-page="detailPage" |
|||
v-model:page-size="detailPageSize" |
|||
:page-sizes="[10, 20, 50, 100]" |
|||
:total="detailTotal" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
class="mt-4" |
|||
@size-change="handleDetailSizeChange" |
|||
@current-change="handleDetailPageChange" |
|||
/> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped lang="scss"> |
|||
.app-container { |
|||
padding: 16px; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.page-card { |
|||
background: #fff; |
|||
border: 1px solid #dcdfe6; |
|||
border-radius: 4px; |
|||
box-sizing: border-box; |
|||
padding: 16px; |
|||
min-height: calc(100vh - 116px); |
|||
} |
|||
|
|||
.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-select { |
|||
width: 220px; |
|||
} |
|||
|
|||
.period-select { |
|||
width: 110px; |
|||
} |
|||
|
|||
.period-date { |
|||
width: 150px; |
|||
} |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
.mb-4 { |
|||
margin-bottom: 16px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,385 @@ |
|||
<script setup lang="ts"> |
|||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'; |
|||
|
|||
/** 表格行数据(执法人员维度) */ |
|||
interface EnforcerRow { |
|||
id: number; |
|||
enforcerName: string; |
|||
bureauName: string; |
|||
adminEnforceCount: number; |
|||
adminRank: number; |
|||
adminPercent: string; |
|||
nonAdminEnforceCount: number; |
|||
nonAdminRank: number; |
|||
nonAdminPercent: string; |
|||
} |
|||
|
|||
// ======================== 查询条件 ======================== |
|||
const queryParams = reactive({ |
|||
enforcerName: '' as string, |
|||
bureauName: '' as string |
|||
}); |
|||
|
|||
const periodType = ref('month'); |
|||
const periodOptions = [ |
|||
{ label: '月度', value: 'month' } |
|||
]; |
|||
const periodDate = ref<string>('2026-09'); |
|||
|
|||
const pickerType = computed<'week' | 'month' | 'year'>(() => 'month'); |
|||
const pickerFormat = computed(() => 'YYYY-MM'); |
|||
|
|||
// ======================== 表格数据 ======================== |
|||
const loading = ref(false); |
|||
const tableData = ref<EnforcerRow[]>([]); |
|||
const total = ref(0); |
|||
const currentPage = ref(1); |
|||
const pageSize = ref(20); |
|||
const selectedRows = ref<EnforcerRow[]>([]); |
|||
|
|||
const tableHeight = ref<number | undefined>(undefined); |
|||
const tableRef = ref<HTMLElement>(); |
|||
|
|||
const calcTableHeight = () => { |
|||
if (!tableRef.value) return; |
|||
const rect = tableRef.value.getBoundingClientRect(); |
|||
tableHeight.value = window.innerHeight - rect.top - 84; |
|||
}; |
|||
|
|||
const buildMockRows = (): EnforcerRow[] => { |
|||
return [ |
|||
{ id: 1, enforcerName: '张三', bureauName: '宝安区市场监督管理局', adminEnforceCount: 128, adminRank: 1, adminPercent: '12.5%', nonAdminEnforceCount: 15, nonAdminRank: 3, nonAdminPercent: '8.2%' }, |
|||
{ id: 2, enforcerName: '李四', bureauName: '龙岗区市场监督管理局', adminEnforceCount: 115, adminRank: 2, adminPercent: '11.2%', nonAdminEnforceCount: 22, nonAdminRank: 1, nonAdminPercent: '12.0%' }, |
|||
{ id: 3, enforcerName: '王五', bureauName: '福田区市场监督管理局', adminEnforceCount: 98, adminRank: 3, adminPercent: '9.6%', nonAdminEnforceCount: 18, nonAdminRank: 2, nonAdminPercent: '9.8%' }, |
|||
{ id: 4, enforcerName: '赵六', bureauName: '南山区市场监督管理局', adminEnforceCount: 87, adminRank: 4, adminPercent: '8.5%', nonAdminEnforceCount: 12, nonAdminRank: 5, nonAdminPercent: '6.5%' }, |
|||
{ id: 5, enforcerName: '钱七', bureauName: '龙华区市场监督管理局', adminEnforceCount: 76, adminRank: 5, adminPercent: '7.4%', nonAdminEnforceCount: 14, nonAdminRank: 4, nonAdminPercent: '7.6%' }, |
|||
{ id: 6, enforcerName: '孙八', bureauName: '宝安区市场监督管理局', adminEnforceCount: 65, adminRank: 6, adminPercent: '6.3%', nonAdminEnforceCount: 8, nonAdminRank: 7, nonAdminPercent: '4.3%' }, |
|||
{ id: 7, enforcerName: '周九', bureauName: '龙岗区市场监督管理局', adminEnforceCount: 58, adminRank: 7, adminPercent: '5.7%', nonAdminEnforceCount: 10, nonAdminRank: 6, nonAdminPercent: '5.4%' }, |
|||
{ id: 8, enforcerName: '吴十', bureauName: '福田区市场监督管理局', adminEnforceCount: 52, adminRank: 8, adminPercent: '5.1%', nonAdminEnforceCount: 6, nonAdminRank: 8, nonAdminPercent: '3.3%' }, |
|||
{ id: 9, enforcerName: '郑十一', bureauName: '南山区市场监督管理局', adminEnforceCount: 45, adminRank: 9, adminPercent: '4.4%', nonAdminEnforceCount: 5, nonAdminRank: 9, nonAdminPercent: '2.7%' }, |
|||
{ id: 10, enforcerName: '冯十二', bureauName: '龙华区市场监督管理局', adminEnforceCount: 38, adminRank: 10, adminPercent: '3.7%', nonAdminEnforceCount: 4, nonAdminRank: 10, nonAdminPercent: '2.2%' }, |
|||
{ id: 11, enforcerName: '陈十三', bureauName: '宝安区市场监督管理局', adminEnforceCount: 32, adminRank: 11, adminPercent: '3.1%', nonAdminEnforceCount: 3, nonAdminRank: 11, nonAdminPercent: '1.6%' }, |
|||
{ id: 12, enforcerName: '褚十四', bureauName: '龙岗区市场监督管理局', adminEnforceCount: 28, adminRank: 12, adminPercent: '2.7%', nonAdminEnforceCount: 2, nonAdminRank: 12, nonAdminPercent: '1.1%' } |
|||
]; |
|||
}; |
|||
|
|||
const getList = async () => { |
|||
loading.value = true; |
|||
try { |
|||
// TODO: 接入真实接口 listEnforcerScanData |
|||
tableData.value = buildMockRows(); |
|||
total.value = 186; |
|||
} finally { |
|||
loading.value = false; |
|||
} |
|||
}; |
|||
|
|||
const handleSearch = () => { |
|||
currentPage.value = 1; |
|||
getList(); |
|||
}; |
|||
|
|||
const handleReset = () => { |
|||
queryParams.enforcerName = ''; |
|||
queryParams.bureauName = ''; |
|||
periodType.value = 'month'; |
|||
periodDate.value = '2026-09'; |
|||
currentPage.value = 1; |
|||
pageSize.value = 20; |
|||
getList(); |
|||
}; |
|||
|
|||
const handleExport = () => { |
|||
// TODO: 接入导出接口 |
|||
}; |
|||
|
|||
const handleSelectionChange = (selection: EnforcerRow[]) => { |
|||
selectedRows.value = selection; |
|||
}; |
|||
|
|||
const handleSizeChange = (size: number) => { |
|||
pageSize.value = size; |
|||
currentPage.value = 1; |
|||
getList(); |
|||
}; |
|||
|
|||
const handlePageChange = (page: number) => { |
|||
currentPage.value = page; |
|||
getList(); |
|||
}; |
|||
|
|||
// ======================== 详情弹窗 ======================== |
|||
interface ScanDetailRow { |
|||
id: number; |
|||
enterpriseName: string; |
|||
scanTime: string; |
|||
scanType: string; |
|||
enforcementItem: string; |
|||
areaName: string; |
|||
} |
|||
|
|||
const detailDialogVisible = ref(false); |
|||
const detailEnforcer = ref<EnforcerRow | null>(null); |
|||
const detailLoading = ref(false); |
|||
const detailTableData = ref<ScanDetailRow[]>([]); |
|||
const detailTotal = ref(0); |
|||
const detailPage = ref(1); |
|||
const detailPageSize = ref(20); |
|||
|
|||
const buildDetailMockRows = (enforcer: EnforcerRow, count: number): ScanDetailRow[] => { |
|||
const rows: ScanDetailRow[] = []; |
|||
const scanTypePool = ['行政执法', '非行政执法']; |
|||
const itemPool = ['特种设备安全检查', '产品质量抽查', '食品安全监督抽检', '计量器具检定', '广告监督检查']; |
|||
const enterprisePool = ['深圳市某某科技有限公司', '深圳市某某电子厂', '深圳市某某贸易有限公司']; |
|||
const areaPool = ['宝安区', '龙岗区', '福田区', '南山区', '龙华区']; |
|||
|
|||
for (let i = 1; i <= Math.min(count, 12); i++) { |
|||
const hour = String(8 + (i % 11)).padStart(2, '0'); |
|||
const minute = String((i * 17) % 60).padStart(2, '0'); |
|||
rows.push({ |
|||
id: i, |
|||
enterpriseName: enterprisePool[i % enterprisePool.length], |
|||
scanTime: `${periodDate.value}-${String(i % 28 + 1).padStart(2, '0')} ${hour}:${minute}:00`, |
|||
scanType: scanTypePool[i % scanTypePool.length], |
|||
enforcementItem: itemPool[i % itemPool.length], |
|||
areaName: areaPool[i % areaPool.length] |
|||
}); |
|||
} |
|||
return rows; |
|||
}; |
|||
|
|||
const getDetailList = async () => { |
|||
detailLoading.value = true; |
|||
try { |
|||
if (!detailEnforcer.value) return; |
|||
// TODO: 接入真实接口 listEnforcerScanDetail |
|||
const combinedCount = detailEnforcer.value.adminEnforceCount + detailEnforcer.value.nonAdminEnforceCount; |
|||
detailTableData.value = buildDetailMockRows(detailEnforcer.value, combinedCount); |
|||
detailTotal.value = combinedCount; |
|||
} finally { |
|||
detailLoading.value = false; |
|||
} |
|||
}; |
|||
|
|||
const handleDetail = (row: EnforcerRow) => { |
|||
detailEnforcer.value = row; |
|||
detailPage.value = 1; |
|||
detailDialogVisible.value = true; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
const handleDetailSizeChange = (size: number) => { |
|||
detailPageSize.value = size; |
|||
detailPage.value = 1; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
const handleDetailPageChange = (page: number) => { |
|||
detailPage.value = page; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
getList(); |
|||
nextTick(() => calcTableHeight()); |
|||
window.addEventListener('resize', calcTableHeight); |
|||
}); |
|||
|
|||
onUnmounted(() => { |
|||
window.removeEventListener('resize', calcTableHeight); |
|||
}); |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="page-card"> |
|||
<!-- ==================== 搜索区域 ==================== --> |
|||
<div class="search-panel"> |
|||
<el-form :inline="true" label-colon> |
|||
<el-form-item label="执法人员"> |
|||
<el-input |
|||
v-model="queryParams.enforcerName" |
|||
placeholder="请输入姓名" |
|||
class="search-input" |
|||
clearable |
|||
@keyup.enter="handleSearch" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="所属单位"> |
|||
<el-input |
|||
v-model="queryParams.bureauName" |
|||
placeholder="请输入单位" |
|||
class="search-input" |
|||
clearable |
|||
@keyup.enter="handleSearch" |
|||
/> |
|||
</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> |
|||
|
|||
<!-- ==================== 表格区域 ==================== --> |
|||
<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="80" align="center" type="index" /> |
|||
<el-table-column prop="enforcerName" label="执法人员" width="120" align="center" /> |
|||
<el-table-column prop="bureauName" label="所属单位" min-width="220" align="center" /> |
|||
<el-table-column prop="adminEnforceCount" label="行政执法次数" width="130" align="center" /> |
|||
<el-table-column prop="adminRank" label="行政执法排名" width="130" align="center" /> |
|||
<el-table-column prop="adminPercent" label="行政执法占比(%)" width="150" align="center" /> |
|||
<el-table-column prop="nonAdminEnforceCount" label="非行政执法次数" width="140" align="center" /> |
|||
<el-table-column prop="nonAdminRank" label="非行政执法排名" width="140" align="center" /> |
|||
<el-table-column prop="nonAdminPercent" label="非行政执法占比(%)" width="160" align="center" /> |
|||
<el-table-column label="操作" width="80" align="center" fixed="right"> |
|||
<template #default="{ row }"> |
|||
<el-button 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> |
|||
|
|||
<!-- ==================== 扫码详情弹窗 ==================== --> |
|||
<el-dialog |
|||
v-model="detailDialogVisible" |
|||
width="1000px" |
|||
:title="`${detailEnforcer?.enforcerName || ''} — ${periodDate} 执法明细`" |
|||
append-to-body |
|||
top="5vh" |
|||
destroy-on-close |
|||
> |
|||
<el-alert |
|||
v-if="detailEnforcer" |
|||
:closable="false" |
|||
show-icon |
|||
:title="`所属单位:${detailEnforcer.bureauName} | 行政执法:${detailEnforcer.adminEnforceCount}次 | 非行政执法:${detailEnforcer.nonAdminEnforceCount}次 | 时段:${periodDate}`" |
|||
type="info" |
|||
class="mb-4" |
|||
/> |
|||
|
|||
<el-table |
|||
v-loading="detailLoading" |
|||
:data="detailTableData" |
|||
border |
|||
stripe |
|||
style="width: 100%" |
|||
max-height="55vh" |
|||
> |
|||
<el-table-column label="序号" type="index" width="80" align="center" /> |
|||
<el-table-column label="企业名称" prop="enterpriseName" min-width="220" align="center" /> |
|||
<el-table-column label="扫码时间" prop="scanTime" min-width="180" align="center" /> |
|||
<el-table-column label="扫码类型" prop="scanType" width="120" align="center" /> |
|||
<el-table-column label="执法事项" prop="enforcementItem" min-width="200" align="center" /> |
|||
<el-table-column label="所属区" prop="areaName" width="100" align="center" /> |
|||
</el-table> |
|||
|
|||
<el-pagination |
|||
v-model:current-page="detailPage" |
|||
v-model:page-size="detailPageSize" |
|||
:page-sizes="[10, 20, 50, 100]" |
|||
:total="detailTotal" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
class="mt-4" |
|||
@size-change="handleDetailSizeChange" |
|||
@current-change="handleDetailPageChange" |
|||
/> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped lang="scss"> |
|||
.app-container { |
|||
padding: 16px; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.page-card { |
|||
background: #fff; |
|||
border: 1px solid #dcdfe6; |
|||
border-radius: 4px; |
|||
box-sizing: border-box; |
|||
padding: 16px; |
|||
min-height: calc(100vh - 116px); |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
|
|||
.period-select { |
|||
width: 110px; |
|||
} |
|||
|
|||
.period-date { |
|||
width: 150px; |
|||
} |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
.mb-4 { |
|||
margin-bottom: 16px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,385 @@ |
|||
<script setup lang="ts"> |
|||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'; |
|||
|
|||
/** 表格行数据 */ |
|||
interface FieldRow { |
|||
id: number; |
|||
fieldName: string; |
|||
enterpriseCount: number; |
|||
adminEnforceCount: number; |
|||
adminRank: number; |
|||
adminPercent: string; |
|||
nonAdminEnforceCount: number; |
|||
nonAdminRank: number; |
|||
nonAdminPercent: string; |
|||
} |
|||
|
|||
// ======================== 查询条件 ======================== |
|||
const queryParams = reactive({ |
|||
field: undefined as string | undefined |
|||
}); |
|||
|
|||
const periodType = ref('month'); |
|||
const periodOptions = [ |
|||
{ label: '月度', value: 'month' } |
|||
]; |
|||
const periodDate = ref<string>('2026-09'); |
|||
|
|||
const pickerType = computed<'week' | 'month' | 'year'>(() => 'month'); |
|||
const pickerFormat = computed(() => 'YYYY-MM'); |
|||
|
|||
/** 所属领域选项(静态) */ |
|||
const fieldOptions = ref([ |
|||
{ label: '特种设备', value: 'special_equipment' }, |
|||
{ label: '产品质量', value: 'product_quality' }, |
|||
{ label: '食品安全', value: 'food_safety' }, |
|||
{ label: '计量器具', value: 'measurement' }, |
|||
{ label: '药品监管', value: 'drug' }, |
|||
{ label: '广告监管', value: 'advertising' }, |
|||
{ label: '知识产权', value: 'ipr' }, |
|||
{ label: '网络交易', value: 'internet' } |
|||
]); |
|||
|
|||
// ======================== 表格数据 ======================== |
|||
const loading = ref(false); |
|||
const tableData = ref<FieldRow[]>([]); |
|||
const total = ref(0); |
|||
const currentPage = ref(1); |
|||
const pageSize = ref(20); |
|||
const selectedRows = ref<FieldRow[]>([]); |
|||
|
|||
const tableHeight = ref<number | undefined>(undefined); |
|||
const tableRef = ref<HTMLElement>(); |
|||
|
|||
const calcTableHeight = () => { |
|||
if (!tableRef.value) return; |
|||
const rect = tableRef.value.getBoundingClientRect(); |
|||
tableHeight.value = window.innerHeight - rect.top - 84; |
|||
}; |
|||
|
|||
const buildMockRows = (): FieldRow[] => { |
|||
return [ |
|||
{ id: 1, fieldName: '特种设备', enterpriseCount: 125600, adminEnforceCount: 28421, adminRank: 1, adminPercent: '68.5%', nonAdminEnforceCount: 3200, nonAdminRank: 1, nonAdminPercent: '58%' }, |
|||
{ id: 2, fieldName: '产品质量', enterpriseCount: 98450, adminEnforceCount: 15230, adminRank: 2, adminPercent: '62.3%', nonAdminEnforceCount: 2150, nonAdminRank: 2, nonAdminPercent: '52%' }, |
|||
{ id: 3, fieldName: '食品安全', enterpriseCount: 132800, adminEnforceCount: 12680, adminRank: 3, adminPercent: '55.8%', nonAdminEnforceCount: 1820, nonAdminRank: 3, nonAdminPercent: '48%' }, |
|||
{ id: 4, fieldName: '计量器具', enterpriseCount: 42300, adminEnforceCount: 8950, adminRank: 4, adminPercent: '50.2%', nonAdminEnforceCount: 1200, nonAdminRank: 4, nonAdminPercent: '45%' }, |
|||
{ id: 5, fieldName: '药品监管', enterpriseCount: 18600, adminEnforceCount: 6420, adminRank: 5, adminPercent: '72.1%', nonAdminEnforceCount: 880, nonAdminRank: 5, nonAdminPercent: '65%' }, |
|||
{ id: 6, fieldName: '广告监管', enterpriseCount: 35200, adminEnforceCount: 4180, adminRank: 6, adminPercent: '48.6%', nonAdminEnforceCount: 620, nonAdminRank: 6, nonAdminPercent: '42%' }, |
|||
{ id: 7, fieldName: '知识产权', enterpriseCount: 28900, adminEnforceCount: 3250, adminRank: 7, adminPercent: '45.3%', nonAdminEnforceCount: 520, nonAdminRank: 7, nonAdminPercent: '40%' }, |
|||
{ id: 8, fieldName: '网络交易', enterpriseCount: 56700, adminEnforceCount: 2150, adminRank: 8, adminPercent: '38.2%', nonAdminEnforceCount: 380, nonAdminRank: 8, nonAdminPercent: '35%' } |
|||
]; |
|||
}; |
|||
|
|||
const getList = async () => { |
|||
loading.value = true; |
|||
try { |
|||
// TODO: 接入真实接口 listFieldScanData |
|||
tableData.value = buildMockRows(); |
|||
total.value = 256; |
|||
} finally { |
|||
loading.value = false; |
|||
} |
|||
}; |
|||
|
|||
const handleSearch = () => { |
|||
currentPage.value = 1; |
|||
getList(); |
|||
}; |
|||
|
|||
const handleReset = () => { |
|||
queryParams.field = undefined; |
|||
periodType.value = 'month'; |
|||
periodDate.value = '2026-09'; |
|||
currentPage.value = 1; |
|||
pageSize.value = 20; |
|||
getList(); |
|||
}; |
|||
|
|||
const handleExport = () => { |
|||
// TODO: 接入导出接口 |
|||
}; |
|||
|
|||
const handleSelectionChange = (selection: FieldRow[]) => { |
|||
selectedRows.value = selection; |
|||
}; |
|||
|
|||
const handleSizeChange = (size: number) => { |
|||
pageSize.value = size; |
|||
currentPage.value = 1; |
|||
getList(); |
|||
}; |
|||
|
|||
const handlePageChange = (page: number) => { |
|||
currentPage.value = page; |
|||
getList(); |
|||
}; |
|||
|
|||
// ======================== 详情弹窗 ======================== |
|||
interface ScanDetailRow { |
|||
id: number; |
|||
enterpriseName: string; |
|||
scanTime: string; |
|||
scanType: string; |
|||
bureauDeptName: string; |
|||
lawEnforcer: string; |
|||
enforcementItem: string; |
|||
} |
|||
|
|||
const detailDialogVisible = ref(false); |
|||
const detailField = ref<FieldRow | null>(null); |
|||
const detailLoading = ref(false); |
|||
const detailTableData = ref<ScanDetailRow[]>([]); |
|||
const detailTotal = ref(0); |
|||
const detailPage = ref(1); |
|||
const detailPageSize = ref(20); |
|||
|
|||
const buildDetailMockRows = (field: FieldRow, count: number): ScanDetailRow[] => { |
|||
const rows: ScanDetailRow[] = []; |
|||
const enforcerPool = ['张三', '李四', '王五', '赵六', '钱七', '孙八']; |
|||
const bureauPool = ['深圳市市场监督管理局', '深圳市市场监管局执法支队', '各区市场监管局']; |
|||
const scanTypePool = ['行政执法', '非行政执法']; |
|||
const enterprisePool = ['深圳市某某科技有限公司', '深圳市某某电子厂', '深圳市某某贸易有限公司']; |
|||
|
|||
for (let i = 1; i <= Math.min(count, 12); i++) { |
|||
const hour = String(8 + (i % 11)).padStart(2, '0'); |
|||
const minute = String((i * 17) % 60).padStart(2, '0'); |
|||
rows.push({ |
|||
id: i, |
|||
enterpriseName: enterprisePool[i % enterprisePool.length], |
|||
scanTime: `${periodDate.value}-${String(i % 28 + 1).padStart(2, '0')} ${hour}:${minute}:00`, |
|||
scanType: scanTypePool[i % scanTypePool.length], |
|||
bureauDeptName: bureauPool[i % bureauPool.length], |
|||
lawEnforcer: enforcerPool[i % enforcerPool.length], |
|||
enforcementItem: `${field.fieldName}相关检查` |
|||
}); |
|||
} |
|||
return rows; |
|||
}; |
|||
|
|||
const getDetailList = async () => { |
|||
detailLoading.value = true; |
|||
try { |
|||
if (!detailField.value) return; |
|||
// TODO: 接入真实接口 listFieldScanDetail |
|||
detailTableData.value = buildDetailMockRows(detailField.value, detailField.value.adminEnforceCount); |
|||
detailTotal.value = detailField.value.adminEnforceCount + detailField.value.nonAdminEnforceCount; |
|||
} finally { |
|||
detailLoading.value = false; |
|||
} |
|||
}; |
|||
|
|||
const handleDetail = (row: FieldRow) => { |
|||
detailField.value = row; |
|||
detailPage.value = 1; |
|||
detailDialogVisible.value = true; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
const handleDetailSizeChange = (size: number) => { |
|||
detailPageSize.value = size; |
|||
detailPage.value = 1; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
const handleDetailPageChange = (page: number) => { |
|||
detailPage.value = page; |
|||
getDetailList(); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
getList(); |
|||
nextTick(() => calcTableHeight()); |
|||
window.addEventListener('resize', calcTableHeight); |
|||
}); |
|||
|
|||
onUnmounted(() => { |
|||
window.removeEventListener('resize', calcTableHeight); |
|||
}); |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="page-card"> |
|||
<!-- ==================== 搜索区域 ==================== --> |
|||
<div class="search-panel"> |
|||
<el-form :inline="true" label-colon> |
|||
<el-form-item label="所属领域"> |
|||
<el-select |
|||
v-model="queryParams.field" |
|||
placeholder="请选择" |
|||
class="search-select" |
|||
clearable |
|||
> |
|||
<el-option v-for="item in fieldOptions" :key="item.value" :label="item.label" :value="item.value" /> |
|||
</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> |
|||
|
|||
<!-- ==================== 表格区域 ==================== --> |
|||
<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="80" align="center" type="index" /> |
|||
<el-table-column prop="fieldName" label="所属领域" width="140" align="center" /> |
|||
<el-table-column prop="enterpriseCount" label="商事主体数量(户)" min-width="150" align="center" /> |
|||
<el-table-column prop="adminEnforceCount" label="行政执法数量(条)" min-width="150" align="center" /> |
|||
<el-table-column prop="adminRank" label="行政执法数量排名" min-width="150" align="center" /> |
|||
<el-table-column prop="adminPercent" label="行政执法数量占比(%)" min-width="170" align="center" /> |
|||
<el-table-column prop="nonAdminEnforceCount" label="非行政执法数量" min-width="140" align="center" /> |
|||
<el-table-column prop="nonAdminRank" label="非行政执法数量排名" min-width="160" align="center" /> |
|||
<el-table-column prop="nonAdminPercent" label="非行政执法数量占比(%)" min-width="180" align="center" /> |
|||
<el-table-column label="操作" width="80" align="center" fixed="right"> |
|||
<template #default="{ row }"> |
|||
<el-button 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> |
|||
|
|||
<!-- ==================== 扫码详情弹窗 ==================== --> |
|||
<el-dialog |
|||
v-model="detailDialogVisible" |
|||
width="1100px" |
|||
:title="`${detailField?.fieldName || ''} — ${periodDate} 扫码明细`" |
|||
append-to-body |
|||
top="5vh" |
|||
destroy-on-close |
|||
> |
|||
<el-alert |
|||
v-if="detailField" |
|||
:closable="false" |
|||
show-icon |
|||
:title="`商事主体:${detailField.enterpriseCount}户 | 行政执法:${detailField.adminEnforceCount}条 | 非行政执法:${detailField.nonAdminEnforceCount}条 | 时段:${periodDate}`" |
|||
type="info" |
|||
class="mb-4" |
|||
/> |
|||
|
|||
<el-table |
|||
v-loading="detailLoading" |
|||
:data="detailTableData" |
|||
border |
|||
stripe |
|||
style="width: 100%" |
|||
max-height="55vh" |
|||
> |
|||
<el-table-column label="序号" type="index" width="80" align="center" /> |
|||
<el-table-column label="企业名称" prop="enterpriseName" min-width="220" align="center" /> |
|||
<el-table-column label="扫码时间" prop="scanTime" min-width="180" align="center" /> |
|||
<el-table-column label="扫码类型" prop="scanType" width="120" align="center" /> |
|||
<el-table-column label="执法单位" prop="bureauDeptName" min-width="220" align="center" /> |
|||
<el-table-column label="执法人员" prop="lawEnforcer" width="120" align="center" /> |
|||
<el-table-column label="执法事项" prop="enforcementItem" min-width="200" align="center" /> |
|||
</el-table> |
|||
|
|||
<el-pagination |
|||
v-model:current-page="detailPage" |
|||
v-model:page-size="detailPageSize" |
|||
:page-sizes="[10, 20, 50, 100]" |
|||
:total="detailTotal" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
class="mt-4" |
|||
@size-change="handleDetailSizeChange" |
|||
@current-change="handleDetailPageChange" |
|||
/> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped lang="scss"> |
|||
.app-container { |
|||
padding: 16px; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.page-card { |
|||
background: #fff; |
|||
border: 1px solid #dcdfe6; |
|||
border-radius: 4px; |
|||
box-sizing: border-box; |
|||
padding: 16px; |
|||
min-height: calc(100vh - 116px); |
|||
} |
|||
|
|||
.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-select { |
|||
width: 220px; |
|||
} |
|||
|
|||
.period-select { |
|||
width: 110px; |
|||
} |
|||
|
|||
.period-date { |
|||
width: 150px; |
|||
} |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
.mb-4 { |
|||
margin-bottom: 16px; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue