7 changed files with 1048 additions and 213 deletions
@ -0,0 +1,365 @@ |
|||
<!-- |
|||
* Excel样式统计报表组件 |
|||
* |
|||
* @Author: wzh |
|||
* @Date: 2025-12-24 14:44:06 |
|||
* @Copyright 1.0 |
|||
--> |
|||
<template> |
|||
<div class="excel-statistics-detail"> |
|||
<!-- 查询条件和导出按钮 --> |
|||
<div class="header-section"> |
|||
<div class="query-section"> |
|||
<a-form :model="localQueryForm" layout="inline"> |
|||
<a-form-item label="年度"> |
|||
<a-select v-model:value="localQueryForm.year" placeholder="请选择年度" style="width: 120px"> |
|||
<a-select-option v-for="year in yearOptions" :key="year" :value="year"> |
|||
{{ year }}年 |
|||
</a-select-option> |
|||
</a-select> |
|||
</a-form-item> |
|||
<a-form-item label="季度"> |
|||
<a-select v-model:value="localQueryForm.quarter" placeholder="请选择季度" style="width: 120px"> |
|||
<a-select-option v-for="quarter in quarterOptions" :key="quarter.value" :value="quarter.value"> |
|||
{{ quarter.label }} |
|||
</a-select-option> |
|||
</a-select> |
|||
</a-form-item> |
|||
<a-form-item label="律师姓名"> |
|||
<a-input v-model:value="localQueryForm.lawyerName" placeholder="请输入律师姓名" style="width: 150px" /> |
|||
</a-form-item> |
|||
<a-form-item> |
|||
<a-button type="primary" @click="handleQuery" :loading="queryLoading"> |
|||
<SearchOutlined /> |
|||
查询 |
|||
</a-button> |
|||
<a-button @click="handleReset" style="margin-left: 8px"> |
|||
<ReloadOutlined /> |
|||
重置 |
|||
</a-button> |
|||
</a-form-item> |
|||
</a-form> |
|||
</div> |
|||
<div class="export-section"> |
|||
<a-button type="primary" @click="handleExport" :loading="exportLoading"> |
|||
<ExportOutlined /> |
|||
导出Excel |
|||
</a-button> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Excel样式统计报表 --> |
|||
<div class="statistics-report-container"> |
|||
<!-- 报表标题 --> |
|||
<div class="report-header"> |
|||
<h1>律师服务统计报表</h1> |
|||
<div class="report-subtitle">统计时间:{{ localQueryForm.year }}年<span v-if="localQueryForm.quarter != null">第{{ localQueryForm.quarter }}季度</span></div> |
|||
</div> |
|||
|
|||
<!-- 报表表格 --> |
|||
<div class="report-table"> |
|||
<!-- 表头 --> |
|||
<div class="report-row header-row"> |
|||
<div class="report-cell">序号</div> |
|||
<div class="report-cell">律师姓名</div> |
|||
<div class="report-cell">季度累计服务时长</div> |
|||
<div class="report-cell">季度累计服务成本</div> |
|||
<div class="report-cell">年度累计服务时长</div> |
|||
<div class="report-cell">年度累计服务成本</div> |
|||
</div> |
|||
|
|||
<!-- 数据行 --> |
|||
<div v-for="(item, index) in tableData" :key="index" class="report-row data-row"> |
|||
<div class="report-cell">{{ index + 1 }}</div> |
|||
<div class="report-cell">{{ item.lawyerName || '-' }}</div> |
|||
<div class="report-cell">{{ formatNumber(item.quarterlyServiceDuration) }}</div> |
|||
<div class="report-cell">{{ formatCurrency(item.quarterlyServiceCost) }}</div> |
|||
<div class="report-cell">{{ formatNumber(item.annualServiceDuration) }}</div> |
|||
<div class="report-cell">{{ formatCurrency(item.annualServiceCost) }}</div> |
|||
</div> |
|||
|
|||
<!-- 汇总行 --> |
|||
<div v-if="summaryData" class="report-row summary-row"> |
|||
<div class="report-cell">汇总</div> |
|||
<div class="report-cell">-</div> |
|||
<div class="report-cell">{{ formatNumber(summaryData.totalQuarterlyDuration) }}</div> |
|||
<div class="report-cell">{{ formatCurrency(summaryData.totalQuarterlyCost) }}</div> |
|||
<div class="report-cell">{{ formatNumber(summaryData.totalAnnualDuration) }}</div> |
|||
<div class="report-cell">{{ formatCurrency(summaryData.totalAnnualCost) }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, reactive, computed, onMounted } from 'vue'; |
|||
import { ExportOutlined, SearchOutlined, ReloadOutlined } from '@ant-design/icons-vue'; |
|||
import { message } from 'ant-design-vue'; |
|||
import { serviceApplicationsApi } from '/@/api/business/service-applications/service-applications-api'; |
|||
|
|||
// 接收父组件传递的参数 |
|||
const props = defineProps({ |
|||
queryParams: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
}, |
|||
tableData: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}); |
|||
|
|||
const exportLoading = ref(false); |
|||
const queryLoading = ref(false); |
|||
|
|||
// 本地查询表单 |
|||
const localQueryForm = reactive({ |
|||
quarter: props.queryParams.quarter || null, |
|||
year: props.queryParams.year || new Date().getFullYear(), |
|||
lawyerName: props.queryParams.lawyerName || '', |
|||
firmName: props.queryParams.firmName || '' |
|||
}); |
|||
|
|||
// 季度选项 |
|||
const quarterOptions = [ |
|||
{ label: '第一季度', value: 1 }, |
|||
{ label: '第二季度', value: 2 }, |
|||
{ label: '第三季度', value: 3 }, |
|||
{ label: '第四季度', value: 4 } |
|||
]; |
|||
|
|||
// 年度选项(近5年) |
|||
const yearOptions = ref([]); |
|||
|
|||
// 初始化年度选项 |
|||
function initYearOptions() { |
|||
const currentYear = new Date().getFullYear(); |
|||
for (let i = currentYear; i >= currentYear - 4; i--) { |
|||
yearOptions.value.push(i); |
|||
} |
|||
} |
|||
|
|||
// 表格数据 |
|||
const tableData = ref(props.tableData || []); |
|||
|
|||
// 计算汇总数据 |
|||
const summaryData = computed(() => { |
|||
if (!tableData.value || tableData.value.length === 0) { |
|||
return null; |
|||
} |
|||
|
|||
const summary = { |
|||
totalQuarterlyDuration: 0, |
|||
totalQuarterlyCost: 0, |
|||
totalAnnualDuration: 0, |
|||
totalAnnualCost: 0 |
|||
}; |
|||
|
|||
tableData.value.forEach(item => { |
|||
summary.totalQuarterlyDuration += Number(item.quarterlyServiceDuration) || 0; |
|||
summary.totalQuarterlyCost += Number(item.quarterlyServiceCost) || 0; |
|||
summary.totalAnnualDuration += Number(item.annualServiceDuration) || 0; |
|||
summary.totalAnnualCost += Number(item.annualServiceCost) || 0; |
|||
}); |
|||
|
|||
return summary; |
|||
}); |
|||
|
|||
// 格式化数字 |
|||
function formatNumber(value) { |
|||
if (value === null || value === undefined) return '-'; |
|||
const num = Number(value); |
|||
return isNaN(num) ? '-' : num.toFixed(2); |
|||
} |
|||
|
|||
// 格式化货币 |
|||
function formatCurrency(value) { |
|||
if (value === null || value === undefined) return '-'; |
|||
const num = Number(value); |
|||
return isNaN(num) ? '-' : `¥${num.toFixed(2)}`; |
|||
} |
|||
|
|||
// 查询数据 |
|||
async function handleQuery() { |
|||
queryLoading.value = true; |
|||
try { |
|||
console.log('开始查询律师统计数据...'); |
|||
const params = { |
|||
...localQueryForm, |
|||
pageNum: 1, |
|||
pageSize: 500 // 查询所有数据 |
|||
}; |
|||
|
|||
// 调用律师统计接口 |
|||
const res = await serviceApplicationsApi.statistics(params); |
|||
console.log('律师统计查询结果:', res); |
|||
|
|||
if (res.data && res.data.list && Array.isArray(res.data.list)) { |
|||
tableData.value = res.data.list.map(item => ({ |
|||
...item, |
|||
// 根据实际返回字段映射 |
|||
lawyerName: item.lawyerName || '-', |
|||
certificateNumber: item.certificateNumber || '-', |
|||
quarterlyServiceDuration: item.quarterlyServiceDuration || 0, |
|||
quarterlyServiceCost: item.quarterlyServiceCost || 0, |
|||
annualServiceDuration: item.annualServiceDuration || 0, |
|||
annualServiceCost: item.annualServiceCost || 0 |
|||
})); |
|||
|
|||
// 关闭查询成功提示 |
|||
// message.success(`查询成功,共 ${res.data.total} 条数据`); |
|||
} else { |
|||
tableData.value = []; |
|||
message.warning('暂无数据'); |
|||
} |
|||
} catch (error) { |
|||
message.error('查询失败'); |
|||
console.error('查询律师统计数据失败:', error); |
|||
tableData.value = []; |
|||
} finally { |
|||
queryLoading.value = false; |
|||
} |
|||
} |
|||
|
|||
// 重置查询条件 |
|||
function handleReset() { |
|||
localQueryForm.quarter = null; |
|||
localQueryForm.year = new Date().getFullYear(); |
|||
localQueryForm.lawyerName = ''; |
|||
localQueryForm.firmName = ''; |
|||
tableData.value = []; |
|||
} |
|||
|
|||
// 导出Excel |
|||
async function handleExport() { |
|||
if (tableData.value.length === 0) { |
|||
message.warning('暂无数据可导出'); |
|||
return; |
|||
} |
|||
|
|||
exportLoading.value = true; |
|||
try { |
|||
console.log('开始导出律师统计详情...'); |
|||
const exportParams = { |
|||
quarter: localQueryForm.quarter, |
|||
year: localQueryForm.year, |
|||
lawyerName: localQueryForm.lawyerName, |
|||
firmName: localQueryForm.firmName |
|||
}; |
|||
|
|||
// 调用律师导出接口 |
|||
await serviceApplicationsApi.exportLawyer(exportParams); |
|||
message.success('导出成功'); |
|||
console.log('律师统计详情导出成功'); |
|||
} catch (error) { |
|||
message.error('导出失败'); |
|||
console.error('导出律师统计详情失败:', error); |
|||
} finally { |
|||
exportLoading.value = false; |
|||
} |
|||
} |
|||
|
|||
onMounted(() => { |
|||
initYearOptions(); |
|||
// 如果没有传入数据,则自动查询 |
|||
if (!props.tableData || props.tableData.length === 0) { |
|||
handleQuery(); |
|||
} |
|||
console.log('Excel统计详情组件已加载'); |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.excel-statistics-detail { |
|||
padding: 0 16px; |
|||
} |
|||
|
|||
.header-section { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 20px; |
|||
padding: 16px 0; |
|||
} |
|||
|
|||
.query-section { |
|||
flex: 1; |
|||
} |
|||
|
|||
.export-section { |
|||
margin-left: 16px; |
|||
} |
|||
|
|||
.statistics-report-container { |
|||
border: 1px solid #ddd; |
|||
border-radius: 4px; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.report-header { |
|||
background: #f5f5f5; |
|||
padding: 20px; |
|||
text-align: center; |
|||
border-bottom: 1px solid #ddd; |
|||
} |
|||
|
|||
.report-header h1 { |
|||
margin: 0 0 8px 0; |
|||
font-size: 24px; |
|||
color: #333; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.report-subtitle { |
|||
font-size: 14px; |
|||
color: #666; |
|||
} |
|||
|
|||
.report-table { |
|||
width: 100%; |
|||
border-collapse: collapse; |
|||
} |
|||
|
|||
.report-row { |
|||
display: flex; |
|||
width: 100%; |
|||
} |
|||
|
|||
.report-cell { |
|||
flex: 1; |
|||
padding: 12px; |
|||
border-right: 1px solid #ddd; |
|||
border-bottom: 1px solid #ddd; |
|||
text-align: center; |
|||
min-height: 50px; |
|||
box-sizing: border-box; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.report-cell:last-child { |
|||
border-right: none; |
|||
} |
|||
|
|||
.header-row { |
|||
background-color: #0044cc; |
|||
color: white; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.data-row { |
|||
background-color: white; |
|||
color: #333; |
|||
} |
|||
|
|||
.summary-row { |
|||
background-color: #f0f0f0; |
|||
color: #333; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
/* 最后一行单元格没有下边框 */ |
|||
.report-row:last-child .report-cell { |
|||
border-bottom: none; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue