导出报表功能

This commit is contained in:
guanj
2025-09-30 14:54:41 +08:00
parent 167e676838
commit 10511a92a4
3 changed files with 571 additions and 375 deletions

View File

@@ -269,4 +269,31 @@ export function rightEventDevOpen(data: object) {
}); });
} }
// 部门集合
export function getDept(data: object) {
return service({
url: "/report/getDept",
method: "post",
data,
});
}
// 报表导出
export function exportForms(data: object) {
return service({
url: "/report/get",
method: "post",
data,
responseType: "blob",
});
}

View File

@@ -0,0 +1,186 @@
<!--报表导出-->
<template>
<el-dialog
:close-on-click-modal="false"
draggable
v-model="machineVisible"
:title="title"
width="500"
>
<div>
<div style="height: 160px" class="smsConfig">
<el-form :model="form" inline label-width="auto" class="mb10 ml30 mt20">
<el-form-item label="时间">
<el-date-picker
v-model="timeValue"
size="small"
type="daterange"
:disabled-date="isFutureDate"
style="width: 250px; margin-right: 10px"
unlink-panels
:clearable="false"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item label="部门集合">
<el-select
v-model="form.deptList"
placeholder="请选择"
style="width: 250px"
size="small"
multiple
>
<el-option
v-for="item in deptLists"
:key="item.deptsIndex"
:label="item.deptsname"
:value="item.deptsIndex"
/>
</el-select>
</el-form-item>
</el-form>
<el-divider />
<div style="text-align: center">
<el-button
type="primary"
:icon="Check"
@click="save"
class="mt10"
size="small"
>确定</el-button
>
<el-button :icon="Close" @click="setUp" class="mt10" size="small"
>取消</el-button
>
</div>
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, inject, onMounted } from "vue";
import { ElMessage } from "element-plus";
import { Check, Close } from "@element-plus/icons-vue";
import { getDept, exportForms } from "@/api/statistics/index";
import { useStore } from "vuex";
import { log } from "console";
const store = useStore();
const machineVisible = ref(false);
const title = ref("报表导出");
const timeValue = ref([]);
const deptLists = ref();
//form表单校验规则
const emit = defineEmits(["flushed"]);
const form = ref({
searchBeginTime: "",
searchEndTime: "",
deptList: [],
deptId: "",
});
const open = (text: string, data?: any) => {
timeValue.value = [];
form.value = {
searchBeginTime: "",
searchEndTime: "",
deptList: [],
deptId: "",
};
machineVisible.value = true;
init();
};
const init = () => {
getDept({}).then((res) => {
deptLists.value = res.data;
});
};
const save = () => {
(form.value.deptId = store.state.deptId),
(form.value.searchBeginTime = timeValue.value[0]),
(form.value.searchEndTime = timeValue.value[1]
? timeValue.value[1].split(" ")[0] + " 23:59:59"
: "");
exportForms(form.value).then((res: any) => {
let blob = new Blob([res], {
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8",
});
// createObjectURL(blob); //创建下载的链接
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a"); // 创建a标签
link.href = url;
link.download = "导出报表.docx"; // 设置下载的文件名
document.body.appendChild(link);
link.click(); //执行下载
document.body.removeChild(link);
machineVisible.value = false;
});
};
const isFutureDate = (time: any) => {
return time && time > Date.now();
};
// 取消
const setUp = () => {
machineVisible.value = false;
timeValue.value = [];
form.value = {
searchBeginTime: "",
searchEndTime: "",
deptList: [],
deptId: "",
};
};
defineExpose({ open });
</script>
<style lang="scss" scoped>
@use "@/assets/scss/index.scss";
.smsConfig {
color: #fff;
}
.title {
background-color: #0a73ff40;
height: 30px;
line-height: 30px;
font-weight: 600;
padding-left: 10px;
margin-bottom: 10px;
border-left: 10px solid var(--el-color-primary);
}
:deep(.el-card__body) {
padding: 10px !important;
}
:deep(.el-select) {
min-width: 80px !important;
}
.checkbox {
display: flex;
justify-content: space-between;
}
:deep(.el-form-item__label, ) {
color: #fff;
}
:deep(.el-checkbox__label) {
color: #fff;
}
:deep(.el-form-item__label, ) {
color: #fff;
}
</style>

View File

@@ -1,17 +1,13 @@
<template> <template>
<div id="index" ref="appRef"> <div id="index" ref="appRef">
<div <div class="bg" :class="store.state.screenNotic == 1
class="bg" ? pushFlag
:class=" ? bottomTextRef?.urgentList.length > 0
store.state.screenNotic == 1 ? 'bg-red'
? pushFlag
? bottomTextRef?.urgentList.length > 0
? 'bg-red'
: ''
: ''
: '' : ''
" : ''
> : ''
">
<dv-loading v-if="loading">Loading...</dv-loading> <dv-loading v-if="loading">Loading...</dv-loading>
<div v-else class="host-body"> <div v-else class="host-body">
@@ -19,8 +15,7 @@
<div class="react-left"> <div class="react-left">
<span class="text fw-b"> <span class="text fw-b">
{{ timeInfo.dateYear }} {{ timeInfo.dateWeek }} {{ timeInfo.dateYear }} {{ timeInfo.dateWeek }}
{{ timeInfo.dateDay }}</span {{ timeInfo.dateDay }}</span>
>
</div> </div>
<dv-decoration-10 class="dv-dec-10" :color="color[1]" /> <dv-decoration-10 class="dv-dec-10" :color="color[1]" />
@@ -29,11 +24,7 @@
<div class="title"> <div class="title">
<span class="title-text">{{ title }}</span> <span class="title-text">{{ title }}</span>
</div> </div>
<dv-decoration-8 <dv-decoration-8 class="dv-dec-8" :reverse="true" :color="color[2]" />
class="dv-dec-8"
:reverse="true"
:color="color[2]"
/>
</div> </div>
<dv-decoration-10 class="dv-dec-10-s" :color="color[1]" /> <dv-decoration-10 class="dv-dec-10-s" :color="color[1]" />
</div> </div>
@@ -41,10 +32,7 @@
<div class="d-flex secondLine"> <div class="d-flex secondLine">
<div class="react-right mr-1"> <div class="react-right mr-1">
<span class="text fw-b" style="display: flex"> <span class="text fw-b" style="display: flex">
<datePicker <datePicker ref="datePickerRef" @timeChangeInfo="timeChangeInfo" />
ref="datePickerRef"
@timeChangeInfo="timeChangeInfo"
/>
</span> </span>
</div> </div>
@@ -61,9 +49,8 @@
<el-dropdown-item @click="handleClick('2')" <el-dropdown-item @click="handleClick('2')"
>模拟短信发送</el-dropdown-item >模拟短信发送</el-dropdown-item
> --> > -->
<el-dropdown-item @click="handleClick('3')" <el-dropdown-item @click="handleClick('3')">系统配置</el-dropdown-item>
>系统配置</el-dropdown-item <el-dropdown-item @click="handleClick('4')">报表导出</el-dropdown-item>
>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@@ -85,36 +72,22 @@
<alarm ref="alarmRef" /> <alarm ref="alarmRef" />
<!-- 紧急告警 --> <!-- 紧急告警 -->
<div <div class="icon" v-if="!(bottomTextRef?.urgentList.length == 0)" :color="color[0][1]" :class="bottomTextRef?.urgentList.length > 0
class="icon" ? 'animate-flash-red'
v-if="!(bottomTextRef?.urgentList.length == 0)" : ''
:color="color[0][1]" " @click="drawerClick">
:class="
bottomTextRef?.urgentList.length > 0
? 'animate-flash-red'
: ''
"
@click="drawerClick"
>
<!-- <WarnTriangleFilled /> --> <!-- <WarnTriangleFilled /> -->
<span <span class="iconfont icon-gaojing" :style="{
class="iconfont icon-gaojing" color:
:style="{ bottomTextRef?.urgentList.length > 0
color: ? '#ff0000'
bottomTextRef?.urgentList.length > 0 : color[0][1],
? '#ff0000' }"></span>
: color[0][1], <span class="count" v-if="bottomTextRef?.urgentList.length > 0">{{
}" bottomTextRef?.urgentList.length > 99
></span> ? "99+"
<span : bottomTextRef?.urgentList.length
class="count" }}</span>
v-if="bottomTextRef?.urgentList.length > 0"
>{{
bottomTextRef?.urgentList.length > 99
? "99+"
: bottomTextRef?.urgentList.length
}}</span
>
</div> </div>
</dv-border-box-13> </dv-border-box-13>
</div> </div>
@@ -127,10 +100,7 @@
<!-- <bottom-left /> --> <!-- <bottom-left /> -->
</dv-border-box-13> </dv-border-box-13>
<dv-border-box-13 :color="color[0]"> <dv-border-box-13 :color="color[0]">
<informationTable <informationTable ref="informationTableRef" @handleCurrentChange="handleCurrentChange" />
ref="informationTableRef"
@handleCurrentChange="handleCurrentChange"
/>
</dv-border-box-13> </dv-border-box-13>
<dv-border-box-13 :color="color[0]"> <dv-border-box-13 :color="color[0]">
<sendTrends ref="sendTrendsRef" /> <sendTrends ref="sendTrendsRef" />
@@ -140,20 +110,16 @@
</div> </div>
</div> </div>
</div> </div>
<bottomText <bottomText ref="bottomTextRef" @handleCurrentChange="handleCurrentChange" />
ref="bottomTextRef"
@handleCurrentChange="handleCurrentChange"
/>
<!-- 已发短信查询 --> <!-- 已发短信查询 -->
<smsQueries <smsQueries ref="smsQueriesRef" v-if="smsQueriesFlag" @close="smsQueriesFlag = false" />
ref="smsQueriesRef"
v-if="smsQueriesFlag"
@close="smsQueriesFlag = false"
/>
<!-- 系统配置 --> <!-- 系统配置 -->
<Config ref="ConfigRef" @flushed="inquire" /> <Config ref="ConfigRef" @flushed="inquire" />
<!-- 报表导出 -->
<ReportForms ref="reportForms" />
</div> </div>
</template> </template>
@@ -186,6 +152,7 @@ import bottomText from "./components/bottomText.vue"; //边框组件
import socketClient from "@/utils/webSocketClient"; import socketClient from "@/utils/webSocketClient";
import { useStore } from "vuex"; import { useStore } from "vuex";
import Config from "./components/config.vue"; import Config from "./components/config.vue";
import ReportForms from "./components/reportForms.vue";
const store = useStore(); const store = useStore();
const smsQueriesRef = ref(); // 短信查询组件引用 const smsQueriesRef = ref(); // 短信查询组件引用
@@ -213,6 +180,7 @@ const timeInfo: any = reactive({
dateWeek: "", dateWeek: "",
}); });
const timeType = ref(3); const timeType = ref(3);
const reportForms = ref();
// 适配处理 // 适配处理
const { appRef, calcRate, windowDraw, unWindowDraw } = useDraw(); const { appRef, calcRate, windowDraw, unWindowDraw } = useDraw();
// 连接webSocket客户端 // 连接webSocket客户端
@@ -233,7 +201,6 @@ const drawerClick = () => {
bottomTextRef.value?.openDrawer(); bottomTextRef.value?.openDrawer();
}; };
// 生命周期 // 生命周期
onMounted(() => { onMounted(() => {
stopSpeak(); stopSpeak();
@@ -285,6 +252,9 @@ const handleClick = (type: string) => {
if (type === "3") { if (type === "3") {
ConfigRef.value.open("系统配置"); ConfigRef.value.open("系统配置");
} }
if (type === "4") {
reportForms.value.open("报表导出");
}
}, 100); }, 100);
}; };
@@ -314,18 +284,24 @@ const inquire = async () => {
}, 500); }, 500);
}; };
watch(store.state, (val) => { watch(
timeChangeInfo() store.state,
}, { (val) => {
deep: true, timeChangeInfo();
}) },
{
deep: true,
}
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@use "@/assets/scss/index.scss"; @use "@/assets/scss/index.scss";
.react-right { .react-right {
width: 460px !important; width: 460px !important;
} }
.count { .count {
position: absolute; position: absolute;
top: -8px; top: -8px;
@@ -339,21 +315,25 @@ watch(store.state, (val) => {
font-size: 10px; font-size: 10px;
text-align: center; text-align: center;
} }
.icon { .icon {
position: absolute; position: absolute;
top: 8px; top: 8px;
right: 25px; right: 25px;
} }
.significant { .significant {
position: absolute; position: absolute;
top: 12px; top: 12px;
left: 15px; left: 15px;
.count { .count {
top: -3px; top: -3px;
left: 13px; left: 13px;
height: 13px; height: 13px;
} }
} }
.react-left { .react-left {
position: absolute; position: absolute;
left: 140px; left: 140px;
@@ -361,14 +341,17 @@ watch(store.state, (val) => {
font-size: 18px; font-size: 18px;
line-height: 35px; line-height: 35px;
} }
.titles { .titles {
margin-right: 10px; margin-right: 10px;
.react-right { .react-right {
width: 50px !important; width: 50px !important;
line-height: 20px !important; line-height: 20px !important;
font-size: 14px !important; font-size: 14px !important;
} }
} }
.iconfont { .iconfont {
font-size: 35px !important; font-size: 35px !important;
} }