|
|
|
@ -6,7 +6,6 @@ import { |
|
|
|
listScanDomain, |
|
|
|
listScanDomainDetails, |
|
|
|
exportScanDomain, |
|
|
|
type ScanDetailRow, |
|
|
|
type ScanTimeParams |
|
|
|
} from '@/api/efcode/report/scan-data-situation'; |
|
|
|
import { getDomainInfo, type DashboardDomainVo } from '@/api/efcode/dashboard/area-info'; |
|
|
|
@ -28,7 +27,10 @@ const queryParams = reactive({ |
|
|
|
area: undefined as string | undefined, |
|
|
|
field: undefined as string | undefined, |
|
|
|
periodType: 'month' as string, |
|
|
|
year: String(new Date().getFullYear()) |
|
|
|
year: String(new Date().getFullYear()), |
|
|
|
quarter: Math.ceil((new Date().getMonth() + 1) / 3) as number, |
|
|
|
month: String(new Date().getMonth() + 1).padStart(2, '0') as string, |
|
|
|
week: '' as string |
|
|
|
}); |
|
|
|
|
|
|
|
const periodOptions = [ |
|
|
|
@ -38,6 +40,14 @@ const periodOptions = [ |
|
|
|
{ label: '年度', value: 'year' } |
|
|
|
]; |
|
|
|
|
|
|
|
// 季度选项 |
|
|
|
const quarterOptions = [ |
|
|
|
{ label: '第一季度', value: 1 }, |
|
|
|
{ label: '第二季度', value: 2 }, |
|
|
|
{ label: '第三季度', value: 3 }, |
|
|
|
{ label: '第四季度', value: 4 } |
|
|
|
]; |
|
|
|
|
|
|
|
/** 年份选项(近 5 年) */ |
|
|
|
const yearOptions = (() => { |
|
|
|
const curr = new Date().getFullYear(); |
|
|
|
@ -86,18 +96,18 @@ const calcTableHeight = () => { |
|
|
|
/** 按当前时段类型拼装接口时间参数 */ |
|
|
|
const buildTimeParams = (): ScanTimeParams => { |
|
|
|
const year = queryParams.year; |
|
|
|
const n = new Date(); |
|
|
|
if (queryParams.periodType === 'quarter') { |
|
|
|
return { year, quarter: String(Math.ceil((n.getMonth() + 1) / 3)) }; |
|
|
|
return { year, quarter: String(queryParams.quarter) }; |
|
|
|
} |
|
|
|
if (queryParams.periodType === 'month') { |
|
|
|
return { year, month: String(n.getMonth() + 1) }; |
|
|
|
return queryParams.month ? { year, month: queryParams.month } : { year }; |
|
|
|
} |
|
|
|
if (queryParams.periodType === 'week') { |
|
|
|
// 周度:取本周一 ~ 本周日 |
|
|
|
const day = n.getDay() || 7; |
|
|
|
const monday = new Date(n); |
|
|
|
monday.setDate(n.getDate() - (day - 1)); |
|
|
|
// 周度:以选择周(取周一)为起点,拼本周一 ~ 本周日 |
|
|
|
const base = queryParams.week ? new Date(queryParams.week) : new Date(); |
|
|
|
const day = base.getDay() || 7; |
|
|
|
const monday = new Date(base); |
|
|
|
monday.setDate(base.getDate() - (day - 1)); |
|
|
|
const sunday = new Date(monday); |
|
|
|
sunday.setDate(monday.getDate() + 6); |
|
|
|
const fmt = (d: Date) => |
|
|
|
@ -113,6 +123,12 @@ const currentField = () => { |
|
|
|
return { domainId: queryParams.field, domainName: item?.domainName }; |
|
|
|
}; |
|
|
|
|
|
|
|
/** 当前选中的所属区(dictValue→districtCode,dictLabel→districtName) */ |
|
|
|
const currentArea = () => { |
|
|
|
const item = areaOptions.value.find((i: any) => i.dictValue === queryParams.area); |
|
|
|
return { districtCode: queryParams.area, districtName: item?.dictLabel }; |
|
|
|
}; |
|
|
|
|
|
|
|
const getList = async () => { |
|
|
|
loading.value = true; |
|
|
|
try { |
|
|
|
@ -120,7 +136,8 @@ const getList = async () => { |
|
|
|
...buildTimeParams(), |
|
|
|
pageNum: currentPage.value, |
|
|
|
pageSize: pageSize.value, |
|
|
|
...currentField() |
|
|
|
...currentField(), |
|
|
|
...currentArea() |
|
|
|
}); |
|
|
|
tableData.value = (res as any)?.rows || []; |
|
|
|
total.value = (res as any)?.total || 0; |
|
|
|
@ -137,10 +154,14 @@ const handleSearch = () => { |
|
|
|
}; |
|
|
|
|
|
|
|
const handleReset = () => { |
|
|
|
const n = new Date(); |
|
|
|
queryParams.area = undefined; |
|
|
|
queryParams.field = undefined; |
|
|
|
queryParams.periodType = 'month'; |
|
|
|
queryParams.year = String(new Date().getFullYear()); |
|
|
|
queryParams.year = String(n.getFullYear()); |
|
|
|
queryParams.quarter = Math.ceil((n.getMonth() + 1) / 3); |
|
|
|
queryParams.month = String(n.getMonth() + 1).padStart(2, '0'); |
|
|
|
queryParams.week = ''; |
|
|
|
currentPage.value = 1; |
|
|
|
pageSize.value = 20; |
|
|
|
getList(); |
|
|
|
@ -181,14 +202,23 @@ const handlePageChange = (page: number) => { |
|
|
|
getList(); |
|
|
|
}; |
|
|
|
|
|
|
|
// ======================== 详情弹窗 ======================== |
|
|
|
// ======================== 详情弹窗(领域 → 街道) ======================== |
|
|
|
interface StreetRow { |
|
|
|
id?: number | string; |
|
|
|
streetName?: string; |
|
|
|
districtName?: string; |
|
|
|
xzzfCount?: number | null; |
|
|
|
xzzfslpm?: number | string | null; |
|
|
|
xzzfslzb?: number | string | null; |
|
|
|
fxzzfsl?: number | null; |
|
|
|
fxzzfslpm?: number | string | null; |
|
|
|
fxzzfslzb?: number | string | null; |
|
|
|
} |
|
|
|
|
|
|
|
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 detailTableData = ref<StreetRow[]>([]); |
|
|
|
|
|
|
|
const getDetailList = async () => { |
|
|
|
detailLoading.value = true; |
|
|
|
@ -196,13 +226,11 @@ const getDetailList = async () => { |
|
|
|
if (!detailField.value) return; |
|
|
|
const res = await listScanDomainDetails({ |
|
|
|
...buildTimeParams(), |
|
|
|
pageNum: detailPage.value, |
|
|
|
pageSize: detailPageSize.value, |
|
|
|
domainId: detailField.value.domainId || queryParams.field, |
|
|
|
domainName: detailField.value.domainName || detailField.value.fieldName || currentField().domainName |
|
|
|
domainName: detailField.value.domainName || detailField.value.fieldName || currentField().domainName, |
|
|
|
...currentArea() |
|
|
|
}); |
|
|
|
detailTableData.value = (res as any)?.rows || []; |
|
|
|
detailTotal.value = (res as any)?.total || 0; |
|
|
|
detailTableData.value = (res as any)?.rows || (Array.isArray(res) ? res : []); |
|
|
|
} catch (e) { |
|
|
|
console.warn('[scan-field] 详情接口调用失败', e); |
|
|
|
} finally { |
|
|
|
@ -212,22 +240,10 @@ const getDetailList = async () => { |
|
|
|
|
|
|
|
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(() => { |
|
|
|
loadAreaDict(); |
|
|
|
loadFieldDict(); |
|
|
|
@ -272,10 +288,37 @@ onUnmounted(() => { |
|
|
|
<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-select v-model="queryParams.year" class="year-select"> |
|
|
|
<el-form-item v-if="queryParams.periodType !== 'week'"> |
|
|
|
<el-select v-model="queryParams.year" v-if="queryParams.periodType === 'year'" class="year-select"> |
|
|
|
<el-option v-for="y in yearOptions" :key="y" :label="`${y}年`" :value="y" /> |
|
|
|
</el-select> |
|
|
|
<!-- 季度:年份 + 季度 --> |
|
|
|
<el-select |
|
|
|
v-if="queryParams.periodType === 'quarter'" |
|
|
|
v-model="queryParams.quarter" |
|
|
|
class="quarter-select" |
|
|
|
> |
|
|
|
<el-option v-for="q in quarterOptions" :key="q.value" :label="q.label" :value="q.value" /> |
|
|
|
</el-select> |
|
|
|
<!-- 月度:年份 + 月份 --> |
|
|
|
<el-date-picker |
|
|
|
v-if="queryParams.periodType === 'month'" |
|
|
|
v-model="queryParams.month" |
|
|
|
type="month" |
|
|
|
value-format="MM" |
|
|
|
placeholder="选择月份" |
|
|
|
class="month-picker" |
|
|
|
/> |
|
|
|
</el-form-item> |
|
|
|
<!-- 周度:选择具体周 --> |
|
|
|
<el-form-item v-if="queryParams.periodType === 'week'"> |
|
|
|
<el-date-picker |
|
|
|
v-model="queryParams.week" |
|
|
|
type="week" |
|
|
|
value-format="YYYY-MM-DD" |
|
|
|
placeholder="选择周" |
|
|
|
class="week-picker" |
|
|
|
/> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item> |
|
|
|
<el-button type="primary" @click="handleSearch">搜索</el-button> |
|
|
|
@ -327,11 +370,11 @@ onUnmounted(() => { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- ==================== 扫码明细弹窗 ==================== --> |
|
|
|
<!-- ==================== 领域 → 街道详情弹窗 ==================== --> |
|
|
|
<el-dialog |
|
|
|
v-model="detailDialogVisible" |
|
|
|
width="1100px" |
|
|
|
:title="`${detailField?.fieldName || ''} — 扫码明细`" |
|
|
|
width="1400px" |
|
|
|
:title="detailField?.domainName || detailField?.fieldName || ''" |
|
|
|
append-to-body |
|
|
|
top="5vh" |
|
|
|
destroy-on-close |
|
|
|
@ -344,25 +387,29 @@ onUnmounted(() => { |
|
|
|
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-column label="序号" type="index" width="70" align="center" /> |
|
|
|
<el-table-column label="所属街道" min-width="160" align="center"> |
|
|
|
<template #default="{ row }">{{ row.streetName || row.districtName || '-' }}</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="行政执法数量(条)" min-width="170" align="center"> |
|
|
|
<template #default="{ row }">{{ row.xzzfCount ?? '-' }}</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="行政执法数量排名" min-width="170" align="center"> |
|
|
|
<template #default="{ row }">{{ row.xzzfslpm ?? '-' }}</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="行政执法数量占比(%)" min-width="160" align="center"> |
|
|
|
<template #default="{ row }">{{ row.xzzfslzb ?? '-' }}</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="非行政执法数量(条)" min-width="180" align="center"> |
|
|
|
<template #default="{ row }">{{ row.fxzzfsl ?? '-' }}</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="非行政执法数量排名" min-width="180" align="center"> |
|
|
|
<template #default="{ row }">{{ row.fxzzfslpm ?? '-' }}</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="非行政执法数量占比(%)" min-width="180" align="center"> |
|
|
|
<template #default="{ row }">{{ row.fxzzfslzb ?? '-' }}</template> |
|
|
|
</el-table-column> |
|
|
|
</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> |
|
|
|
@ -403,6 +450,20 @@ onUnmounted(() => { |
|
|
|
.year-select { |
|
|
|
width: 110px; |
|
|
|
} |
|
|
|
|
|
|
|
.quarter-select { |
|
|
|
width: 110px; |
|
|
|
margin-left: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.month-picker { |
|
|
|
width: 120px; |
|
|
|
margin-left: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.week-picker { |
|
|
|
width: 220px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.table-panel { |
|
|
|
|