明树Git Lab

Commit 84ae11e0 authored by zhanghan's avatar zhanghan

增加导出功能

parent 81153305
Pipeline #110408 passed with stage
in 22 seconds
......@@ -6,8 +6,19 @@
<span class="backText">返回</span>
</div>
<span class="backName">{{ route.meta.title }}</span>
<div class="back-actions" v-if="showSave">
<div class="back-actions" v-if="showSave || showExport">
<el-button
v-if="showExport"
type="primary"
plain
:disabled="exportDisabled"
@click="handleExport"
>
导出
</el-button>
<el-button
v-if="showSave"
type="primary"
:loading="loading"
:disabled="loading || disabled"
......@@ -23,40 +34,48 @@
import { useRouter, useRoute } from "vue-router";
const props = defineProps({
// 是否显示保存按钮
showSave: {
type: Boolean,
default: false,
},
// 保存按钮文本
saveText: {
type: String,
default: "保存",
},
// 是否禁用保存按钮
disabled: {
type: Boolean,
default: false,
},
// 是否显示loading状态
loading: {
type: Boolean,
default: false,
},
showExport: {
type: Boolean,
default: false,
},
exportDisabled: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['save', 'back']);
const emit = defineEmits(["save", "back", "export"]);
const route = useRoute();
const router = useRouter();
const handleBack = () => {
emit('back');
emit("back");
router.back();
};
const handleSave = () => {
emit('save');
emit("save");
};
const handleExport = () => {
emit("export");
};
</script>
<style scoped lang="scss">
......
import * as XLSX from "xlsx";
/**
* 通用Excel导出 composable
*
* 用法:
* const { exportExcel } = useExportExcel()
*
* exportExcel({
* fileName: "文件名",
* sheets: [
* {
* name: "Sheet名称",
* type: "kv", // kv=键值对表单, table=表格数据
* title: "大标题", // 可选,仅kv模式
* data: ... // kv模式: [[key, value], ...], table模式: [对象数组]
* columns: [...] // 仅table模式: [{ prop, label, formatter? }]
* colWidths: [...] // 可选: [20, 30, ...]
* }
* ]
* })
*/
const buildKvSheet = (config) => {
const rows = config.title ? [[config.title], []] : [];
config.data.forEach((row) => rows.push(row));
const ws = XLSX.utils.aoa_to_sheet(rows);
if (config.colWidths) {
ws["!cols"] = config.colWidths.map((w) => ({ wch: w }));
} else {
ws["!cols"] = [{ wch: 30 }, { wch: 40 }];
}
if (config.title) {
const lastCol = String.fromCharCode(65 + (config.colWidths?.length || 2) - 1);
ws["!merges"] = [XLSX.utils.decode_range(`A1:${lastCol}1`)];
}
return ws;
};
const buildTableSheet = (config) => {
const header = config.columns.map((c) => c.label);
const rows = [header];
(config.data || []).forEach((item) => {
rows.push(
config.columns.map((col) => {
const val = col.prop.split(".").reduce((o, k) => o?.[k], item);
return col.formatter ? col.formatter(val, item) : val ?? "";
})
);
});
const ws = XLSX.utils.aoa_to_sheet(rows);
if (config.colWidths) {
ws["!cols"] = config.colWidths.map((w) => ({ wch: w }));
} else {
ws["!cols"] = config.columns.map((col) => ({
wch: Math.max((col.label || "").length * 2.5, 12),
}));
}
return ws;
};
export function useExportExcel() {
const exportExcel = ({ fileName, sheets = [] }) => {
const wb = XLSX.utils.book_new();
sheets.forEach((sheet) => {
const ws =
sheet.type === "kv"
? buildKvSheet(sheet)
: buildTableSheet(sheet);
XLSX.utils.book_append_sheet(wb, ws, sheet.name || "Sheet1");
});
XLSX.writeFile(wb, `${fileName}.xlsx`);
};
return { exportExcel };
}
......@@ -3,8 +3,11 @@
<div class="add-project-content" v-loading="loading">
<routerBack
:show-save="!loading && !isPreview"
:show-export="!loading"
:export-disabled="!formData.projectName"
:loading="loading"
@save="saveClick"
@export="exportStatement"
/>
<div class="tabs-content">
......@@ -741,12 +744,14 @@ import { useRouter, useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { useUserStore } from "@/stores/user.js";
import { useProjectDetail } from "@/composables/useProjectDetail";
import { useExportExcel } from "@/composables/useExportExcel";
const userStore = useUserStore();
const router = useRouter();
const route = useRoute();
const { proxy } = getCurrentInstance();
const { projectDisabled, cachedInfo } = useProjectDetail();
const { exportExcel } = useExportExcel();
import FileUploader from "@/components/FileUploader/index.vue";
import DynamicTable from "@/components/FormDynamicTable/index.vue";
const transferColumns1 = ref([
......@@ -1627,6 +1632,109 @@ const downloadFile = (data) => {
a.remove();
};
// 导出整个责任书为Excel
const exportStatement = () => {
exportExcel({
fileName: `${formData.projectName || "责任书"}_目标责任书`,
sheets: [
{
name: "基本信息",
type: "kv",
title: "投资目标责任书 - 基本信息",
data: [
["责任书类型", selectedFullPath.value || formData.zrslx || ""],
["项目名称", formData.projectName || ""],
["决策主体", formData.jczt || ""],
["监管单位", formData.jgdw || ""],
["签订单位", formData.qddw || ""],
["投资主体", formData.tzzt || ""],
["项目地点", formData.xmdd || ""],
["建设期(月份)", formData.jsqyf ?? ""],
["项目投产时间", formData.xmtcsj || ""],
["运营期(年)", formData.yyq ?? ""],
["计划竣工时间", formData.jhjgsj || ""],
["决策时间", formData.jcsj || ""],
["项目内容", formData.xmnr || ""],
["项目主要方案内容", formData.xmzyfanr || ""],
["全投资财务内部收益率%(税前)", formData.qtzcwnbsyl ?? ""],
["资本金财务内部收益率%(税后)", formData.zbjcwnbsyl ?? ""],
["签订日期", formData.qdrq || ""],
["填报人", formData.tbr || ""],
[],
["签订状态", formData.qdzt || ""],
["是否按时签订", formData.sfasqd || ""],
["签订时间", formData.qdsj || ""],
],
},
{
name: "造价信息",
type: "kv",
title: "造价信息",
data: [
["项目总投资(万元)", formData.xmztz ?? ""],
["建安费(万元)", formData.jaf ?? ""],
["设备及工具购置费(万元)", formData.sbjgjgzf ?? ""],
["土地相关费用(万元)", formData.tdxgfy ?? ""],
["建设单位管理费(万元)", formData.jsdwglf ?? ""],
["其他建设项目管理费(万元)", formData.qtjsxmglf ?? ""],
["其他费用(万元)", formData.qtfy ?? ""],
["能建方建安费(万元)", formData.njfjaf ?? ""],
["建设期利息(万元)", formData.jsqlx ?? ""],
],
},
{
name: "投融资与运营指标",
type: "table",
data: zrsjtzbData.value,
columns: [
{ prop: "zbmc", label: "指标名称" },
{ prop: "zbmbz", label: "指标目标值" },
{ prop: "khjzf", label: "考核基准分" },
{ prop: "sfsy", label: "是否适用", formatter: (v) => v === "1" ? "是" : "否" },
{ prop: "khsm", label: "考核说明" },
],
colWidths: [35, 15, 12, 10, 30],
},
{
name: "批复意见落实情况",
type: "table",
data: pfyjlsqkData.value,
columns: [
{ prop: "lx", label: "类型", formatter: (v) => pfyjlxList.find((l) => l.key === v)?.name || v || "" },
{ prop: "pfyj", label: "批复意见" },
{ prop: "jzf", label: "基准分" },
{ prop: "lsqk", label: "落实情况", formatter: (v) => lsqkList.find((l) => l.key === v)?.name || v || "" },
{ prop: "lssj", label: "落实时间" },
{ prop: "lsqkjtsm", label: "落实情况具体说明" },
],
colWidths: [12, 30, 10, 12, 20, 30],
},
{
name: "边界条件",
type: "table",
data: formData.qtdxmjcyssydfxyxdbj || [],
columns: [
{ prop: "njfcgbl", label: "指标名称" },
{ prop: "njfcgb2", label: "考核基准分" },
{ prop: "njfcgb3", label: "计分细责" },
],
colWidths: [25, 15, 25],
},
{
name: "投资收益",
type: "table",
data: formData.xmssgczqttgxmtzsylhddgsscktqk || [],
columns: [
{ prop: "njfcgbl", label: "指标名称" },
{ prop: "njfcgb2", label: "考核基准分" },
{ prop: "njfcgb3", label: "计分细责" },
],
colWidths: [25, 15, 25],
},
],
});
};
const backClick = () => {
router.back(-1);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment