lcw
This commit is contained in:
@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { onMounted, ref, reactive, defineProps, onUnmounted, watch, nextTick } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'barId'
|
||||
},
|
||||
data:{
|
||||
type:Object,
|
||||
default:{
|
||||
title:'', // 图表标题
|
||||
color:[], //['#EB00FF','#F57100']
|
||||
list:[], //[{label:'总数',val:[80,70,60,50]}, {label:'已处置',val:[70,40,30,80]}, ]
|
||||
xData:[] ,//['09-01','09-02','09-03','09-04']
|
||||
labelColor:'#000', //横坐标颜色 - 纵坐标颜色 - 标题颜色
|
||||
rotate:0, //横坐标旋转角度
|
||||
interval:0, //横坐标间隔
|
||||
isVertical:false,//是否竖排垂直展示
|
||||
}
|
||||
},
|
||||
dataZoom:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
rotate:{
|
||||
type:Number,
|
||||
default:0
|
||||
}
|
||||
});
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{
|
||||
init(val)
|
||||
})
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
|
||||
// 初始化
|
||||
function init (val) {
|
||||
let color = val.color;
|
||||
let list = val.list
|
||||
let series = list.map((item ,idx)=>{
|
||||
return {
|
||||
type: "bar",
|
||||
name:item.label,
|
||||
data:item.val,
|
||||
itemStyle:{normal: { color: color[idx] }},
|
||||
showSymbol:false,
|
||||
barWidth: '30%', // 柱状图宽度
|
||||
}
|
||||
})
|
||||
chartFn(series)
|
||||
}
|
||||
|
||||
function chartFn(series) {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
title: {
|
||||
text: props.data.title || '',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: props.data.color[0] || "#000",
|
||||
fontSize: 14
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
top: "25%",
|
||||
right: "0%",
|
||||
left: "0%",
|
||||
bottom: "0%", // 增加底部空间,为两行X轴标签留出空间
|
||||
containLabel: true
|
||||
},
|
||||
legend: {
|
||||
data: props.data.list.map(v => { return v.label }),
|
||||
textStyle: {
|
||||
color: props.data.color[0] || "#409EFF",
|
||||
fontSize: 12
|
||||
},
|
||||
right: "5%",
|
||||
top: "10%"
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
backgroundColor: "rgba(255,255,255,1)",
|
||||
padding: [5, 10],
|
||||
textStyle: { color: "#7588E4" },
|
||||
extraCssText: "box-shadow: 0 0 5px rgba(0,0,0,0.3)"
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: props.data.xData,
|
||||
axisTick: { alignWithLabel: true },
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: props.data.color[0] || "#409EFF"
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
rotate: props.rotate, // 设置标签旋转角度
|
||||
show: true,
|
||||
color: props.data.color[0] || "#409EFF",
|
||||
fontSize: 10,
|
||||
interval: props.data.interval || 0, // 强制显示所有标签
|
||||
formatter: function(value, index) {
|
||||
// 组合显示数量和年龄范围,数量在上,范围在下
|
||||
const bottomValues = props.data.bottomValues || [];
|
||||
const bottomValue = bottomValues[index] || '';
|
||||
return `${bottomValue}\n${value}`;
|
||||
},
|
||||
margin: 10 // 调整边距
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: props.data.color[0] || "#409EFF",
|
||||
fontSize: 10,
|
||||
formatter: '{value}%' // 显示百分比
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: props.data.color[0] || "#409EFF"
|
||||
}
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: props.data.color[0] || "#409EFF"
|
||||
}
|
||||
}
|
||||
},
|
||||
series: series.map((item, index) => ({
|
||||
...item,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
formatter: function(params) {
|
||||
// 显示顶部百分比标签
|
||||
return `占比 ${params.value}%`;
|
||||
},
|
||||
color: props.data.color[0] || "#409EFF",
|
||||
fontSize: 10
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: item.itemStyle.normal.color
|
||||
}
|
||||
}
|
||||
})),
|
||||
// // 底部数值标签
|
||||
// graphic: props.data.bottomValues ? props.data.bottomValues.map((value, idx) => {
|
||||
// const percent = (idx + 0.5) / props.data.xData.length * 100;
|
||||
// return {
|
||||
// type: 'text',
|
||||
// left: `${percent}%`,
|
||||
// bottom: '5%', // 调整到底部,显示在x轴标签下方
|
||||
// style: {
|
||||
// text: value,
|
||||
// fill: '#000',
|
||||
// fontSize: 12
|
||||
// }
|
||||
// };
|
||||
// }) : []
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener('resize', function() {
|
||||
myChart.resize();
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div class="table-data">
|
||||
<table border="1" cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr style="text-align: center;font-size: 12pt;">
|
||||
<th colspan="6">{{ title }}</th>
|
||||
</tr>
|
||||
<tr style="text-align: center;font-size: 12pt;font-weight: normal;">
|
||||
<th v-if="lx == '0' || lx == '1'"></th>
|
||||
<th v-for="item in titleList" :key="item">{{ item }}</th>
|
||||
</tr>
|
||||
<tr style="text-align: center;font-size: 12pt;font-family: 'Times New Roman';" v-for="value in condition"
|
||||
:key="value">
|
||||
<template v-if="lx == '0'">
|
||||
<td>{{ value.tjlx }}</td>
|
||||
<td>{{ value.ajsls }}</td>
|
||||
<td>{{ value.ccs }}</td>
|
||||
<td>{{ value.wfry }}</td>
|
||||
</template>
|
||||
<template v-if="lx == '1'">
|
||||
<td>{{ value.tjlx }}</td>
|
||||
<td>{{ value.rlggcx }}</td>
|
||||
<td>{{ value.qhrsaq }}</td>
|
||||
<td>{{ value.fhshglcx }}</td>
|
||||
<td>{{ value.fhggaq }}</td>
|
||||
</template>
|
||||
<template v-if="lx == '2'">
|
||||
<td>{{ value.ajlx }}</td>
|
||||
<td>{{ value.sl }}</td>
|
||||
<td>{{ value.zb }}</td>
|
||||
</template>
|
||||
<template v-if="lx == '3'">
|
||||
<td>{{ value.afqy }}</td>
|
||||
<td>{{ value.sl }}</td>
|
||||
</template>
|
||||
<template v-if="lx == '4'">
|
||||
<td>{{ value.ssbm }}</td>
|
||||
<td>{{ value.las }}</td>
|
||||
<td>{{ value.pas }}</td>
|
||||
<td>{{ value.ccl }}</td>
|
||||
<td>{{ value.xyrs }}</td>
|
||||
<td>{{ value.bz }}</td>
|
||||
</template>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
listData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
titleList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}, lx: {
|
||||
type: String,
|
||||
default: '0'
|
||||
}
|
||||
})
|
||||
const condition = computed(() => {
|
||||
const data = props.listData.map(item => item)
|
||||
return data
|
||||
})
|
||||
</script>
|
||||
@ -0,0 +1,464 @@
|
||||
<template>
|
||||
<div class="report-container" ref="tableBox">
|
||||
|
||||
<div ref="ajReport">
|
||||
<div class="main-title">{{ wdValue.date }}份全市治安案件形势分析</div>
|
||||
<div class="section-title">一、治安案件总体概述</div>
|
||||
<div class="body-text" v-if="wdValue.zaajZtgsList">
|
||||
{{ wdValue.ym }}月份,全市各级公安机关治安部门受理行政案件{{ wdValue.zaajZtgsList.ajsls }}起、查处案件{{ wdValue.zaajZtgsList.ccs }}起、查处率{{
|
||||
wdValue.zaajZtgsList.ccl }}%、查处违法人员{{ wdValue.zaajZtgsList.wfry }}人。
|
||||
<TableData title="全市治安案件总体情况表" :listData="wdValue.zaajZtgsList.ztqk" :titleList="['受理治安案件数', '查处数', '查处违法人员数']"
|
||||
lx="0" />
|
||||
</div>
|
||||
<div class="section-title">二、治安案件形势分析</div>
|
||||
<div>
|
||||
|
||||
<div class="body-text" v-if="wdValue.zaajList.length > 0">
|
||||
(一)受理案件类别分析。{{ wdValue.ym }}月受理的{{ wdValue.zaajZtgsList.ajsls }}起行政案件中,<span
|
||||
v-for="(item, index) in wdValue.zaajList" :key="index">{{ item.label }}{{ item.sy }}起环比{{ item.sySj }}{{
|
||||
item.hb }}、同比{{ item.bySj }}{{ item.tb }}<span v-if="index == wdValue.zaajList.length - 1">;</span> <span
|
||||
v-else>。</span></span>
|
||||
<TableData title="全市治安案件总体情况表" :listData="wdValue.ajxsfxList"
|
||||
:titleList="['扰乱公共秩序', '侵害人身安全和财产权利', '妨害社会管理秩序', '妨害公共安全']" lx="1" />
|
||||
</div>
|
||||
<div class="body-text">
|
||||
(二)查处案件类别分析。{{ wdValue.ym }}月份的查处63起行政案件中,<span v-for="(item, index) in wdValue.zaajFbqktj" :key="index">
|
||||
{{ item.ajlx }}{{ item.sl }}起、占查处案件总数的{{ item.zb }}<span
|
||||
v-if="index == wdValue.zaajFbqktj.length - 1">,</span>
|
||||
<span v-else>。</span></span>
|
||||
<TableData title="全市查处主要治安案件情况" :listData="wdValue.zaajFbqktj" :titleList="['案件类型', '查处数', '占查处总数的百分比']"
|
||||
lx="2" />
|
||||
</div>
|
||||
<div class="body-text">
|
||||
(三)查处违法犯罪人员年龄分析。{{ wdValue.ym }}月份共查处违法人员{{ wdValue.nldtjOnj.ccxyr }}人,其中<span
|
||||
v-for="value in wdValue.nldtjOnj.nldtj.data" :key="value.agegroup">
|
||||
{{ value.agegroup }} {{ value.count }}人、占查处违法人员总数的{{ value.zb }}<span
|
||||
v-if="index == wdValue.nldtjOnj.nldtj.data.length - 1">。</span><span v-else>、</span>
|
||||
</span>
|
||||
</div>
|
||||
<div style="height:250px; width:280px;margin: 0 auto;">
|
||||
<bar v-if="wdValue.nldtjOnj.nldtj" :echartsId="'myBarChart'" :data="{
|
||||
title: '图一',
|
||||
color: ['#FF6B6B'],
|
||||
...wdValue.nldtjOnj.nldtj
|
||||
}" />
|
||||
</div>
|
||||
<div class="body-text">
|
||||
(四)案件发生区域分析。{{wdValue.sajajfsqy.qyfx }}
|
||||
<TableData title="受理治安案件发生区域" :listData="wdValue.sajajfsqy.xxsj" :titleList="['案件发生区域', '案件数量']" lx="3" />
|
||||
</div>
|
||||
<div class="body-text">
|
||||
(五)治安案件地域分析。{{ wdValue.ym }}月份全市治安案件平均查处率为{{ wdValue.zaajZtgsList.ccl }}%<span v-if="parseFloat(wdValue.zaajZtgsList.ccl) > 0"> ,<span v-for="value in wdValue.jxsajajdyfx.greaterThan" :key="value.ssbm">{{ value.ssbm }}、</span>查处率高,分别为<span v-for="value in wdValue.jxsajajdyfx.lessThan" :key="value.ssbm">{{ value.ccl }}</span>,<span v-for="value in wdValue.jxsajajdyfx.lessThan" :key="value.ssbm">{{ value.ccl }}</span></span><span>。</span>
|
||||
<TableData title="各县(市)公安(分)局治安案件统计表" :listData="wdValue.jxsajajdyfx.res"
|
||||
:titleList="['部门、(市)公安(分)局', '受理数', '查处数','查处率','查处违法人员数','备注']" lx="4" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-title">三、对策建议</div>
|
||||
<div class="body-text">
|
||||
{{ wdValue.xzjyL }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex;justify-content: center;align-items: center;">
|
||||
<el-button type="primary" @click="downloadWithStyles">导出WORD</el-button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { xsasjxsajztgs, xsasjxsajccajlbfx, xsasjxsajajxsfx, xsasjxsajnldtj, xsasjxsajajfsqy, xsasjxsajajdyfx, xsasjxsajaltdtj, xsasjxsajfbqktj, xsasjxsajFatdtj, xsasjxsajxyrQkfx, xsasjxsajypbgZttj, xsasjxsajqxajqk } from '@/api/fileapi'
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { connectSSEWithPost } from '@/utils/sse'
|
||||
import { timeValidate } from '@/utils/tools'
|
||||
import { downloadDocWithStyle, downloadPDF } from "@/utils/export.js"
|
||||
import TableData from './tableData.vue'
|
||||
import Bar from './bar.vue'
|
||||
import Docxtemplater from 'docxtemplater';
|
||||
import PizZip from 'pizzip';
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
const props = defineProps({
|
||||
search: {
|
||||
type: Object,
|
||||
default: () => { }
|
||||
},
|
||||
xzlx: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const params = ref({ ...props.search })
|
||||
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
getxsasjxsajztgs()
|
||||
getxsasjxsajccajlbfx()
|
||||
getxsasjxsajajxsfx()
|
||||
getxsasjxsajnldtj()
|
||||
getxsasjxsajajfsqy()
|
||||
getxsasjxsajajdyfx()
|
||||
getconnectSSEWithPost()
|
||||
})
|
||||
|
||||
|
||||
|
||||
// 值
|
||||
const wdValue = ref({
|
||||
date: timeValidate(new Date(), 'ny'),
|
||||
ym: timeValidate((() => { const d = new Date(); d.setMonth(d.getMonth() - 1); return d; })(), 'ym'),
|
||||
td: timeValidate(new Date(), 'td'),
|
||||
zaajZtgsList: {},
|
||||
ajxsfxList: [],
|
||||
zaajList: [],
|
||||
zaajFbqktj: [],
|
||||
zaajFbqktjList: {},
|
||||
nldtjOnj: {
|
||||
ccxyr: 0,
|
||||
nldtj: { list: [] }
|
||||
},
|
||||
jxsajajdyfx: {},
|
||||
sajajfsqy: {},
|
||||
xzjyL:""
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
const ajReport = ref(null)
|
||||
// 获取报告所有文字内容
|
||||
const getReportTextContent = () => {
|
||||
if (!ajReport.value) {
|
||||
return ''
|
||||
}
|
||||
// 提取元素内的所有文本内容
|
||||
const textContent = ajReport.value.textContent || ''
|
||||
// 处理空白字符,去除多余的换行和空格
|
||||
return textContent
|
||||
.replace(/\s+/g, ' ') // 将多个空白字符替换为单个空格
|
||||
.trim() // 去除首尾空白
|
||||
}
|
||||
|
||||
// 侦防建议
|
||||
const getconnectSSEWithPost = () => {
|
||||
const params = getReportTextContent()
|
||||
connectSSEWithPost({ prompt: params }, {
|
||||
onChunk: (content) => {
|
||||
wdValue.value.xzjyL += content;
|
||||
},
|
||||
onComplete: () => {
|
||||
console.log('SSE连接完成');
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('SSE连接错误:', error);
|
||||
}
|
||||
})
|
||||
}
|
||||
// 区域分析
|
||||
const getxsasjxsajztgs = () => {
|
||||
// ...params.value
|
||||
xsasjxsajztgs({ ...params.value }).then(res => {
|
||||
wdValue.value.zaajZtgsList = res
|
||||
}).catch(error => {
|
||||
console.error('请求失败:', error)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 治安案件类别分析
|
||||
const getxsasjxsajccajlbfx = () => {
|
||||
xsasjxsajccajlbfx({ ...params.value }).then(res => {
|
||||
wdValue.value.zaajFbqktj = res
|
||||
}).catch(error => {
|
||||
console.error('请求失败:', error)
|
||||
})
|
||||
}
|
||||
const xzlx = [
|
||||
{
|
||||
key: 'rlggcx',
|
||||
label: '扰乱公共秩序类',
|
||||
value: ''
|
||||
}, {
|
||||
key: 'qhrsaq',
|
||||
label: '侵害人身安全和财产权利类',
|
||||
value: ''
|
||||
}, {
|
||||
key: 'fhshglcx',
|
||||
label: '妨害社会管理秩序类',
|
||||
value: ''
|
||||
}, {
|
||||
key: 'fhggaq',
|
||||
label: '妨害公共安全类',
|
||||
value: ''
|
||||
}
|
||||
]
|
||||
const strFun = (str) => {
|
||||
const newStr = parseInt(str.slice(0, str.length - 1))
|
||||
return newStr == 0 ? '持平' : newStr > 0 ? `上升${newStr}%` : `下降${Math.abs(newStr)}%`
|
||||
}
|
||||
// 治安案件线索分析
|
||||
const getxsasjxsajajxsfx = () => {
|
||||
xsasjxsajajxsfx({ ...params.value }).then(res => {
|
||||
wdValue.value.ajxsfxList = res
|
||||
const list = res.map(item => item.tjlx)
|
||||
wdValue.value.zaajList = xzlx.map(item => {
|
||||
return {
|
||||
...item,
|
||||
sySj: list[0],
|
||||
bySj: list[2],
|
||||
sy: res[1][item.key],
|
||||
by: res[2][item.key],
|
||||
hb: strFun(res[3][item.key]),
|
||||
tb: strFun(res[4][item.key]),
|
||||
}
|
||||
})
|
||||
|
||||
console.log(wdValue.value.zaajList);
|
||||
|
||||
}).catch(error => {
|
||||
console.error('请求失败:', error)
|
||||
})
|
||||
}
|
||||
const getxsasjxsajnldtj = () => {
|
||||
xsasjxsajnldtj({ ...params.value }).then(res => {
|
||||
wdValue.value.nldtjOnj.ccxyr = res.ccxyr ? res.ccxyr : '0'
|
||||
wdValue.value.nldtjOnj.nldtj.list = [
|
||||
{ label: '占比', val: res.nldtj.map(item => (item.count / res.ccxyr * 100).toFixed(2)) },
|
||||
]
|
||||
wdValue.value.nldtjOnj.nldtj.xData = res.nldtj.map(item => item.agegroup)
|
||||
wdValue.value.nldtjOnj.nldtj.bottomValues = res.nldtj.map(item => item.count)
|
||||
wdValue.value.nldtjOnj.nldtj.data = res.nldtj
|
||||
}).catch(error => {
|
||||
console.error('请求失败:', error)
|
||||
})
|
||||
}
|
||||
|
||||
const getxsasjxsajajfsqy = () => {
|
||||
xsasjxsajajfsqy({ ...params.value }).then(res => {
|
||||
wdValue.value.sajajfsqy = res
|
||||
}).catch(error => {
|
||||
console.error('请求失败:', error)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const getxsasjxsajajdyfx = () => {
|
||||
xsasjxsajajdyfx({ ...params.value }).then(res => {
|
||||
const { greaterThan, lessThan } = compareCclValues(res);
|
||||
wdValue.value.jxsajajdyfx = {
|
||||
greaterThan, lessThan,
|
||||
res
|
||||
}
|
||||
console.log(wdValue.value.jxsajajdyfx);
|
||||
|
||||
}).catch(error => {
|
||||
console.error('请求失败:', error)
|
||||
})
|
||||
}
|
||||
|
||||
// 比较ccl值的方法
|
||||
const compareCclValues = (data) => {
|
||||
// 获取基准ccl值
|
||||
const baseCcl = wdValue.value.zaajZtgsList.ccl || '0%';
|
||||
const baseCclValue = parseFloat(baseCcl);
|
||||
|
||||
// 初始化结果数组
|
||||
const greaterThan = [];
|
||||
const lessThan = [];
|
||||
|
||||
// 遍历数据进行比较
|
||||
data.forEach(item => {
|
||||
const itemCcl = item.ccl || '0%';
|
||||
const itemCclValue = parseFloat(itemCcl);
|
||||
|
||||
if (itemCclValue > baseCclValue) {
|
||||
greaterThan.push(item);
|
||||
} else if (itemCclValue < baseCclValue) {
|
||||
lessThan.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
return { greaterThan, lessThan };
|
||||
}
|
||||
// 导出word
|
||||
const tableBox = ref(null);
|
||||
const downloadWithStyles = async () => {
|
||||
if (!tableBox.value?.innerHTML) return;
|
||||
try {
|
||||
// 将类样式转换为行内样式的函数
|
||||
const convertClassesToInlineStyles = (html) => {
|
||||
// 创建临时DOM元素
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = html;
|
||||
|
||||
// 定义样式映射
|
||||
const styleMap = {
|
||||
'.report-container': {
|
||||
'padding': '20px',
|
||||
'color': '#000'
|
||||
},
|
||||
'.main-title': {
|
||||
'font-size': '22pt',
|
||||
'font-family': '黑体, SimHei, Microsoft YaHei',
|
||||
'text-align': 'center',
|
||||
'font-weight': 'bold',
|
||||
'line-height': '30pt'
|
||||
},
|
||||
'.section-title': {
|
||||
'font-size': '16pt',
|
||||
'font-family': '黑体, SimHei, Microsoft YaHei',
|
||||
'line-height': '30pt',
|
||||
'text-indent': '2em',
|
||||
'font-weight': 'bold'
|
||||
},
|
||||
'.body-text': {
|
||||
'font-size': '16pt',
|
||||
'font-family': '仿宋_GB2312',
|
||||
'line-height': '30pt',
|
||||
'text-indent': '2em'
|
||||
},
|
||||
'.font-bold': {
|
||||
'font-weight': '600'
|
||||
},
|
||||
'.right-align': {
|
||||
'text-align': 'right',
|
||||
'margin-left': 'auto',
|
||||
'width': 'fit-content'
|
||||
}
|
||||
};
|
||||
|
||||
// 遍历所有元素,应用行内样式
|
||||
const elements = tempDiv.querySelectorAll('*');
|
||||
elements.forEach(element => {
|
||||
// 获取元素的所有类名
|
||||
const classes = element.className.split(' ').filter(c => c);
|
||||
|
||||
// 为每个类名应用对应的样式
|
||||
classes.forEach(className => {
|
||||
const styles = styleMap[`.${className}`];
|
||||
if (styles) {
|
||||
Object.entries(styles).forEach(([property, value]) => {
|
||||
element.style[property] = value;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 返回转换后的HTML
|
||||
return tempDiv.innerHTML;
|
||||
};
|
||||
|
||||
// 转换样式并构建导出内容
|
||||
let inlineStyledContent = convertClassesToInlineStyles(tableBox.value.innerHTML);
|
||||
|
||||
// 处理图表转换为图片
|
||||
const tempExportDiv = document.createElement('div');
|
||||
tempExportDiv.innerHTML = inlineStyledContent;
|
||||
|
||||
// 直接在原始DOM中查找所有图表容器
|
||||
const originalChartContainers = tableBox.value.querySelectorAll('div[id]');
|
||||
for (const originalContainer of originalChartContainers) {
|
||||
try {
|
||||
// 获取图表实例
|
||||
const chart = echarts.getInstanceByDom(originalContainer);
|
||||
if (chart) {
|
||||
// 确保图表已渲染并获取完整大小
|
||||
const containerWidth = originalContainer.offsetWidth;
|
||||
const containerHeight = originalContainer.offsetHeight;
|
||||
|
||||
// 调整图表大小以确保完整渲染
|
||||
chart.resize({
|
||||
width: containerWidth,
|
||||
height: containerHeight
|
||||
});
|
||||
|
||||
// 等待一小段时间确保图表渲染完成
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
// 获取图表的base64图片,设置合适的尺寸
|
||||
const imgSrc = chart.getDataURL({
|
||||
pixelRatio: 2, // 提高图片清晰度
|
||||
backgroundColor: '#fff',
|
||||
width: containerWidth,
|
||||
height: containerHeight
|
||||
});
|
||||
|
||||
// 在临时DOM中查找对应的容器并替换
|
||||
const tempContainer = tempExportDiv.querySelector(`div[id="${originalContainer.id}"]`);
|
||||
if (tempContainer) {
|
||||
// 创建图片元素替换图表容器
|
||||
const img = document.createElement('img');
|
||||
img.src = imgSrc;
|
||||
// 使用内联样式确保在Word中占满宽度
|
||||
img.setAttribute('style', 'width: 100%; height: auto; margin: 20px 0;');
|
||||
// 替换容器
|
||||
tempContainer.style.textIndent = '0em';
|
||||
tempContainer.parentNode.replaceChild(img, tempContainer);
|
||||
tempContainer.style.textIndent = '0em';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('转换图表为图片失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取处理后的HTML
|
||||
const processedContent = tempExportDiv.innerHTML;
|
||||
|
||||
const styledContent = `
|
||||
<div style="padding: 20px; color: #000;">
|
||||
${processedContent}
|
||||
</div>
|
||||
`;
|
||||
downloadDocWithStyle(styledContent, `刑事案件分析报告_${timeValidate(new Date(), 'ny')}`);
|
||||
} catch (error) {
|
||||
console.error('导出Word失败:', error);
|
||||
alert('导出Word失败,请检查控制台错误信息');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.report-container {
|
||||
padding: 20px;
|
||||
height: 90%;
|
||||
overflow: auto;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 22pt;
|
||||
font-family: '黑体, SimHei, Microsoft YaHei';
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
line-height: 30pt;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16pt;
|
||||
font-family: '黑体, SimHei, Microsoft YaHei';
|
||||
line-height: 30pt;
|
||||
text-indent: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.body-text {
|
||||
font-size: 16pt;
|
||||
// font-family: ', FangSong, Microsoft YaHei';
|
||||
font-family: '仿宋_GB2312';
|
||||
line-height: 30pt;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.right-align {
|
||||
text-align: right;
|
||||
margin-left: auto;
|
||||
width: fit-content;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss"></style>
|
||||
@ -4,6 +4,7 @@
|
||||
<div class="xsaj">
|
||||
<JudgmentReport :search="search" v-if="xzlx === '02'" />
|
||||
<Xsaj :search="search" v-if="xzlx === '03'" />
|
||||
<Zaaj :search="search" v-if="xzlx === '04'" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -13,6 +14,8 @@
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import JudgmentReport from './AnalysisReport/index.vue'
|
||||
import Xsaj from './caseFile/xsaj.vue'
|
||||
import Zaaj from './caseFile/zaaj.vue'
|
||||
|
||||
const title = ref('详情')
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
|
||||
Reference in New Issue
Block a user