|
|
@@ -0,0 +1,274 @@
|
|
|
+<template>
|
|
|
+ <div class="report_module">
|
|
|
+ <div class="module_title">
|
|
|
+ <div class="title_left">
|
|
|
+ <template v-if="showTitle && titleList.length">
|
|
|
+ <template v-for="(item, index) in titleList">
|
|
|
+ <span :class="{ span_item: index != titleList.length - 1 }">{{ item }}</span><span
|
|
|
+ v-if="index != titleList.length - 1" class="split_line">/</span>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ <slot name="title_left" />
|
|
|
+ </div>
|
|
|
+ <div class="title_right">
|
|
|
+ <slot name="title_right" />
|
|
|
+ <template v-if="showPrintBtn">
|
|
|
+ <el-button class="default_button" :loading="state.printLoading">
|
|
|
+ <img v-if="!state.printLoading" src="@/assets/icon/print_icon.webp" alt="打印PDF" />打印PDF
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ <template v-if="showExportBtn">
|
|
|
+ <el-button class="default_button" :loading="state.exportLoading">
|
|
|
+ <img v-if="!state.exportLoading" src="@/assets/icon/export_icon.webp" alt="导出Excel" />导出Excel
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div :class="[`module_${tableOrChart}`, { table_42: tableOrChart == 'table' }]">
|
|
|
+ <!-- 表格或图表显示 -->
|
|
|
+ <slot name="module_table_chart" />
|
|
|
+ <!-- 表格分页 -->
|
|
|
+ <div class="page_pagination" v-if="tableOrChart == 'table' && showTablePage">
|
|
|
+ <el-pagination background :page-size="20" :pager-count="11" layout="prev, pager, next" :total="1000" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 描述 -->
|
|
|
+ <div v-if="showDescribe" class="module_describe">
|
|
|
+ <div ref="textContainer" class="text_container" :class="{ 'expanded': state.isExpanded }">
|
|
|
+ <slot name="module_describe"></slot>
|
|
|
+ </div>
|
|
|
+ <button v-if="state.showExpandButton" @click="ToggleExpand" class="toggle_button"
|
|
|
+ :class="state.isExpanded ? 'show_expanded' : 'hide_expanded'">
|
|
|
+ {{ state.isExpanded ? '收起' : '展开' }}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script lang="ts" setup>
|
|
|
+import { onMounted, reactive, nextTick, ref } from "vue";
|
|
|
+const props = defineProps({
|
|
|
+ titleList: {
|
|
|
+ type: Array,
|
|
|
+ default: []
|
|
|
+ },//标题
|
|
|
+ showTitle: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },//是否显示标题
|
|
|
+ showPrintBtn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },//是否显示打印按钮
|
|
|
+ showExportBtn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },//是否显示导出按钮
|
|
|
+ tableOrChart: {
|
|
|
+ type: String,
|
|
|
+ default: 'table'
|
|
|
+ },
|
|
|
+ showTablePage: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },//表格是否显示分页
|
|
|
+ showDescribe: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },//是否显示描述
|
|
|
+})
|
|
|
+const state = reactive({
|
|
|
+ printLoading: false,
|
|
|
+ exportLoading: false,
|
|
|
+ isExpanded: false,//是否展开或者收缩
|
|
|
+ showExpandButton: true,
|
|
|
+});
|
|
|
+const textContainer = ref(null);
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ nextTick(() => {
|
|
|
+ checkLines();
|
|
|
+ })
|
|
|
+});
|
|
|
+// 检查行数并设置是否显示按钮
|
|
|
+const checkLines = () => {
|
|
|
+ const container = textContainer.value;
|
|
|
+ if (container) {
|
|
|
+ const range = document.createRange();// 创建一个 Range 对象
|
|
|
+ range.selectNodeContents(container);// 选择要测量的文本内容
|
|
|
+ const rect = range.getBoundingClientRect();// 获取文本内容的边界矩形
|
|
|
+ const lineHeight = parseInt(window.getComputedStyle(container).lineHeight, 10);// 获取行高
|
|
|
+ const lines = Math.ceil(rect.height / lineHeight);// 计算行数
|
|
|
+ console.log("打印行数lines", lines);
|
|
|
+ state.showExpandButton = lines > 3;
|
|
|
+ }
|
|
|
+}
|
|
|
+const ToggleExpand = () => {
|
|
|
+ state.isExpanded = !state.isExpanded;
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.report_module {
|
|
|
+ width: 100%;
|
|
|
+ background-color: #fff;
|
|
|
+ margin-top: 10px;
|
|
|
+ border-radius: 10px;
|
|
|
+
|
|
|
+ .module_title {
|
|
|
+ width: 100%;
|
|
|
+ padding: 0 20px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin: auto;
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #333333;
|
|
|
+ text-align: left;
|
|
|
+ line-height: 50px;
|
|
|
+ padding-top: 10px;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+
|
|
|
+ .title_left {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-wrap: wrap;
|
|
|
+
|
|
|
+ .span_item {
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+
|
|
|
+ .split_line {
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #999999;
|
|
|
+ margin: 0 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .title_right {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .default_button {
|
|
|
+ margin-left: 0px;
|
|
|
+ height: 36px;
|
|
|
+ line-height: 36px;
|
|
|
+ padding: 0 10px;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666666;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ &:active,
|
|
|
+ &:focus {
|
|
|
+ outline: none; // 去掉点击后的轮廓
|
|
|
+ box-shadow: none; // 去掉点击后的阴影
|
|
|
+ background-color: inherit; // 保持背景颜色不变
|
|
|
+ color: #666666; // 保持文字颜色不变
|
|
|
+ border: 1px solid #DCDFE6;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: #f9f9f9;
|
|
|
+ border: 1px solid #DCDFE6;
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+
|
|
|
+ span {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ margin-right: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-icon-loading {
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .module_table {
|
|
|
+ width: 100%;
|
|
|
+ padding: 0 20px 14px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border-collapse: collapse;
|
|
|
+ }
|
|
|
+
|
|
|
+ .module_chart {
|
|
|
+ width: 100%;
|
|
|
+ padding: 0 20px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ min-height: 360px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .module_describe {
|
|
|
+ width: 100%;
|
|
|
+ padding: 14px 20px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #999999;
|
|
|
+ line-height: 24px;
|
|
|
+ text-align: left;
|
|
|
+
|
|
|
+ .text_container {
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ display: -webkit-box;
|
|
|
+ -webkit-line-clamp: 3;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+ transition: max-height 0.3s ease-out;
|
|
|
+ max-height: 72px;
|
|
|
+
|
|
|
+ p {
|
|
|
+ line-height: 22px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .text_container.expanded {
|
|
|
+ -webkit-line-clamp: unset;
|
|
|
+ max-height: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .toggle_button {
|
|
|
+ margin-top: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ background: none;
|
|
|
+ border: none;
|
|
|
+ color: #2E64FA;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1;
|
|
|
+ width: 100%;
|
|
|
+ height: 24px;
|
|
|
+ text-align: right;
|
|
|
+ padding: 0 20px 0 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .show_expanded {
|
|
|
+ background-image: url('@/assets/icon/up_expanded.webp');
|
|
|
+ background-size: 16px 16px;
|
|
|
+ background-position: 100% 50%;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ }
|
|
|
+
|
|
|
+ .hide_expanded {
|
|
|
+ background-image: url('@/assets/icon/down_expanded.webp');
|
|
|
+ background-size: 16px 16px;
|
|
|
+ background-position: 100% 50%;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|