明树Git Lab

Commit f1fcb653 authored by zhanghan's avatar zhanghan

回收开发

parent 91b35f0b
Pipeline #106972 passed with stage
in 19 seconds
<template>
<div>11111111111111</div>
</template>
<script setup></script>
<style scoped lang="scss"></style>
......@@ -51,6 +51,9 @@
<slot name="header-actions" />
</div>
<!-- 表格上方默认插槽 -->
<slot></slot>
<!-- 表格主体 -->
<el-table
:data="modelValue"
......@@ -63,9 +66,16 @@
<!-- 序号列 -->
<el-table-column type="index" fixed="left" width="60" label="序号" />
<!-- 动态列 -->
<!-- 🌟 有配置headerGroup → 渲染多级表头(按组合并) -->
<template
v-if="hasHeaderGroup"
v-for="group in headerColumnGroups"
:key="group.key"
>
<el-table-column :label="group.label" :align="group.align || 'center'">
<!-- 二级表头:列渲染逻辑(原生模板,适配Vite编译) -->
<el-table-column
v-for="column in columns"
v-for="column in group.children"
:key="column.prop"
:prop="column.prop"
:label="column.label"
......@@ -73,18 +83,16 @@
:align="column.align || 'left'"
>
<template #default="scope">
<!-- 普通输入框 -->
<template v-if="column.type === 'input'">
<el-input
v-if="column.type === 'input'"
v-model="scope.row[column.prop]"
:placeholder="column.placeholder"
:disabled="disabled"
:maxlength="column.maxlength"
/>
<!-- 数字输入框 -->
</template>
<template v-else-if="column.type === 'number'">
<el-input
v-else-if="column.type === 'number'"
v-model.number="scope.row[column.prop]"
type="number"
:placeholder="column.placeholder"
......@@ -93,10 +101,9 @@
:min="column.min"
:max="column.max"
/>
<!-- 文本域 -->
</template>
<template v-else-if="column.type === 'textarea'">
<el-input
v-else-if="column.type === 'textarea'"
v-model="scope.row[column.prop]"
type="textarea"
:placeholder="column.placeholder"
......@@ -105,10 +112,9 @@
:maxlength="column.maxlength"
:show-word-limit="column.showWordLimit || false"
/>
<!-- 下拉选择框 -->
</template>
<template v-else-if="column.type === 'select'">
<el-select
v-else-if="column.type === 'select'"
v-model="scope.row[column.prop]"
:placeholder="column.placeholder"
:disabled="disabled"
......@@ -121,10 +127,9 @@
:value="item.key || item.value"
/>
</el-select>
<!-- 单选框组 -->
</template>
<template v-else-if="column.type === 'radio'">
<el-radio-group
v-else-if="column.type === 'radio'"
v-model="scope.row[column.prop]"
:disabled="disabled"
>
......@@ -137,10 +142,11 @@
{{ item.name || item.label }}
</el-radio>
</el-radio-group>
<!-- 时间选择器 -->
<el-date-picker
</template>
<template
v-else-if="column.type === 'date' || column.type === 'datetime'"
>
<el-date-picker
v-model="scope.row[column.prop]"
:type="column.type === 'datetime' ? 'datetime' : 'date'"
:format="column.format || 'YYYY-MM-DD'"
......@@ -149,15 +155,111 @@
:disabled="disabled"
style="width: 100%"
/>
</template>
<template v-else-if="column.type === 'upload'">
<FileUploader
v-model="scope.row[column.prop]"
:isInline="true"
:disabled="disabled"
/>
</template>
</template>
</el-table-column>
</el-table-column>
</template>
<!-- 文件上传组件 -->
<!-- 🌟 无配置headerGroup → 渲染原生单级表头(和原组件完全一致) -->
<el-table-column
v-else
v-for="column in columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:min-width="column.minWidth || 140"
:align="column.align || 'left'"
>
<template #default="scope">
<template v-if="column.type === 'input'">
<el-input
v-model="scope.row[column.prop]"
:placeholder="column.placeholder"
:disabled="disabled"
:maxlength="column.maxlength"
/>
</template>
<template v-else-if="column.type === 'number'">
<el-input
v-model.number="scope.row[column.prop]"
type="number"
:placeholder="column.placeholder"
:disabled="disabled"
:precision="column.precision"
:min="column.min"
:max="column.max"
/>
</template>
<template v-else-if="column.type === 'textarea'">
<el-input
v-model="scope.row[column.prop]"
type="textarea"
:placeholder="column.placeholder"
:disabled="disabled"
:rows="column.rows || 3"
:maxlength="column.maxlength"
:show-word-limit="column.showWordLimit || false"
/>
</template>
<template v-else-if="column.type === 'select'">
<el-select
v-model="scope.row[column.prop]"
:placeholder="column.placeholder"
:disabled="disabled"
:multiple="column.multiple || false"
>
<el-option
v-for="item in selectOptions?.[column.optionKey] || []"
:key="item.key || item.value"
:label="item.name || item.label"
:value="item.key || item.value"
/>
</el-select>
</template>
<template v-else-if="column.type === 'radio'">
<el-radio-group
v-model="scope.row[column.prop]"
:disabled="disabled"
>
<el-radio
v-for="item in selectOptions?.[column.optionKey] || []"
:key="item.key || item.value"
:label="item.key || item.value"
style="margin-right: 12px"
>
{{ item.name || item.label }}
</el-radio>
</el-radio-group>
</template>
<template
v-else-if="column.type === 'date' || column.type === 'datetime'"
>
<el-date-picker
v-model="scope.row[column.prop]"
:type="column.type === 'datetime' ? 'datetime' : 'date'"
:format="column.format || 'YYYY-MM-DD'"
:value-format="column.valueFormat || 'YYYY-MM-DD'"
:placeholder="column.placeholder"
:disabled="disabled"
style="width: 100%"
/>
</template>
<template v-else-if="column.type === 'upload'">
<FileUploader
v-else-if="column.type === 'upload'"
v-model="scope.row[column.prop]"
:isInline="true"
:disabled="disabled"
/>
</template>
</template>
</el-table-column>
<!-- 操作列 -->
......@@ -184,7 +286,6 @@
>
删除
</el-button>
<!-- 自定义操作按钮 -->
<el-button
v-for="(btn, btnIndex) in operationButtons"
......@@ -198,7 +299,6 @@
>
{{ btn.text }}
</el-button>
<!-- 操作列自定义插槽 -->
<slot
name="operations"
......@@ -213,85 +313,40 @@
</template>
<script setup>
import { defineProps, defineEmits, ref } from "vue";
import { defineProps, defineEmits, ref, computed } from "vue";
import { ElMessageBox, ElMessage } from "element-plus";
import { Download, Upload } from "@element-plus/icons-vue";
// 请确认项目实际路径,不一致直接修改
import FileUploader from "@/components/FileUploader/index.vue";
// 请确认项目实际路径,不一致直接修改
import { getTableFileData, exportTableFile } from "@/common/tableFileHandle";
// 定义Props
const props = defineProps({
// 核心配置
modelValue: {
type: Array,
required: true,
default: () => [],
},
columns: {
type: Array,
required: true,
default: () => [],
},
defaultRow: {
type: Object,
required: true,
default: () => ({}),
},
// 核心双向绑定数据
modelValue: { type: Array, required: true, default: () => [] },
// 列配置(headerGroup用于多级表头合并)
columns: { type: Array, required: true, default: () => [] },
// 新增行默认值
defaultRow: { type: Object, default: () => ({}) },
// 基础配置
addButtonText: {
type: String,
default: "新增",
},
disabled: {
type: Boolean,
default: false,
},
selectOptions: {
type: Object,
default: () => ({}),
},
scrollbarAlwaysOn: {
type: Boolean,
default: false,
},
// 新增/删除按钮配置
showAddButton: {
type: Boolean,
default: true,
},
showDeleteButton: {
type: Boolean,
default: true,
},
// 导入导出功能配置
showImportExport: {
type: Boolean,
default: false,
},
exportName: {
type: String,
default: "表格数据",
},
// 自定义操作按钮配置
operationButtons: {
type: Array,
default: () => [],
},
operationColumnWidth: {
type: [String, Number],
default: "auto",
},
operationColumnMinWidth: {
type: [String, Number],
default: 60,
},
addButtonText: { type: String, default: "新增" },
disabled: { type: Boolean, default: false },
selectOptions: { type: Object, default: () => ({}) },
scrollbarAlwaysOn: { type: Boolean, default: false },
// 按钮显隐配置
showAddButton: { type: Boolean, default: true },
showDeleteButton: { type: Boolean, default: true },
// 导入导出配置
showImportExport: { type: Boolean, default: false },
exportName: { type: String, default: "表格数据" },
// 自定义操作按钮
operationButtons: { type: Array, default: () => [] },
operationColumnWidth: { type: [String, Number], default: "auto" },
operationColumnMinWidth: { type: [String, Number], default: 60 },
});
// 定义Emits
// 定义事件
const emit = defineEmits([
"update:modelValue",
"add",
......@@ -303,44 +358,77 @@ const emit = defineEmits([
// 导入上传组件Ref
const uploadRef = ref(null);
// 🌟 多级表头开关:是否有列配置了headerGroup(核心判断)
const hasHeaderGroup = computed(() => {
return props.columns.some((col) => !!col.headerGroup);
});
// 🌟 多级表头分组计算属性:按headerGroup自动分组,保持列原始顺序
const headerColumnGroups = computed(() => {
const { columns } = props;
if (!columns.length) return [];
const groupMap = {};
columns.forEach((col) => {
// 无headerGroup用唯一标识,避免分组混乱
const groupKey = col.headerGroup || `single_${col.prop}`;
if (!groupMap[groupKey]) {
groupMap[groupKey] = {
label: col.headerGroup || col.label,
key: groupKey,
children: [],
};
}
groupMap[groupKey].children.push(col);
});
// 保持列的原始配置顺序,解决分组后列乱序问题
const result = [];
const addedKeys = new Set();
columns.forEach((col) => {
const groupKey = col.headerGroup || `single_${col.prop}`;
if (!addedKeys.has(groupKey)) {
result.push(groupMap[groupKey]);
addedKeys.add(groupKey);
}
});
return result;
});
/**
* 导出数据转换:将select/radio的key值转为文字描述
* @param {Array} data 原始表格数据
* @returns {Array} 转换后的导出数据
* 导出数据转换:select/radio的key值转为文字描述
*/
const convertDataForExport = (data) => {
if (!data || !data.length) return [];
return data.map((row) => {
const newRow = { ...row };
// 遍历列配置,处理select/radio类型字段
props.columns.forEach((column) => {
if (column.type === "select" || column.type === "radio") {
const prop = column.prop;
const optionKey = column.optionKey;
const options = props.selectOptions?.[optionKey] || [];
if (
newRow[prop] !== undefined &&
newRow[prop] !== null &&
newRow[prop] !== ""
) {
// 处理多选(select multiple)
// 处理多选
if (column.multiple && Array.isArray(newRow[prop])) {
newRow[prop] = newRow[prop]
.map((key) => {
const option = options.find(
(item) => (item.key || item.value) === key
(item) => (item.key || item.value) === key,
);
return option ? item.name || item.label : key;
})
.join(","); // 多选用中文逗号分隔
.join(",");
} else {
// 单选处理
// 处理单选
const option = options.find(
(item) => (item.key || item.value) === newRow[prop]
(item) => (item.key || item.value) === newRow[prop],
);
newRow[prop] = option ? option.name || option.label : newRow[prop];
newRow[prop] = option ? item.name || item.label : newRow[prop];
}
}
}
......@@ -350,47 +438,41 @@ const convertDataForExport = (data) => {
};
/**
* 导入数据转换:将文字描述转回对应的key值
* @param {Array} data 导入的原始数据
* @returns {Array} 转换后的表格数据
* 导入数据转换:文字描述转回对应的key值
*/
const convertDataForImport = (data) => {
if (!data || !data.length) return [];
return data.map((row) => {
const newRow = { ...row };
// 遍历列配置,处理select/radio类型字段
props.columns.forEach((column) => {
if (column.type === "select" || column.type === "radio") {
const prop = column.prop;
const optionKey = column.optionKey;
const options = props.selectOptions?.[optionKey] || [];
if (
newRow[prop] !== undefined &&
newRow[prop] !== null &&
newRow[prop] !== ""
) {
// 处理多选(select multiple)
// 处理多选
if (column.multiple) {
const textList = newRow[prop]
.split(",")
.map((item) => item.trim());
newRow[prop] = textList.map((text) => {
const option = options.find(
(item) => (item.name || item.label) === text
(item) => (item.name || item.label) === text,
);
return option ? option.key || item.value : text;
return option ? item.key || item.value : text;
});
} else {
// 单选处理
// 处理单选
const option = options.find(
(item) => (item.name || item.label) === newRow[prop]
(item) => (item.name || item.label) === newRow[prop],
);
newRow[prop] = option ? option.key || option.value : newRow[prop];
newRow[prop] = option ? item.key || item.value : newRow[prop];
}
} else {
// 空值处理为默认空
newRow[prop] = "";
}
}
......@@ -399,7 +481,7 @@ const convertDataForImport = (data) => {
});
};
// 1. 新增行
// 新增行
const handleAdd = () => {
try {
const newRow = { ...props.defaultRow };
......@@ -412,7 +494,7 @@ const handleAdd = () => {
}
};
// 2. 删除行
// 删除行
const handleDelete = (index) => {
ElMessageBox.confirm("确认删除该项?", "提示", {
confirmButtonText: "确认",
......@@ -434,23 +516,22 @@ const handleDelete = (index) => {
.catch(() => {});
};
// 3. 自定义操作按钮点击
// 自定义操作按钮点击
const handleCustomOperation = (btn, scope) => {
if (btn.click) {
try {
btn.click(scope.row, scope.$index);
} catch (e) {
console.error("自定义按钮点击事件执行失败:", e);
console.error("自定义按钮点击失败:", e);
ElMessage.error("操作执行失败,请稍后重试");
}
}
emit("custom-operation", btn, scope.row, scope.$index);
};
// 4. 导出表格数据(修改:添加数据转换)
// 导出表格数据
const handleExport = () => {
try {
// 先转换数据,再导出
const exportData = convertDataForExport(props.modelValue);
exportTableFile(exportData, props.columns, "", props.exportName);
ElMessage.success("导出成功");
......@@ -460,10 +541,9 @@ const handleExport = () => {
}
};
// 5. 导入表格数据(修改:添加数据转换)
// 导入表格数据
const handleImport = (file) => {
uploadRef.value?.clearFiles();
getTableFileData(file, props.columns)
.then((rawImportData) => {
const convertedData = convertDataForImport(rawImportData);
......@@ -476,7 +556,7 @@ const handleImport = (file) => {
});
};
// 6. 导入成功后的数据处理
// 导入成功后数据处理
const handleImportSuccess = (importData) => {
try {
const newData = [...props.modelValue, ...importData];
......@@ -523,14 +603,8 @@ const handleImportSuccess = (importData) => {
--el-table-row-hover-bg-color: #f8f9fa;
}
:deep(.el-upload) {
width: 100%;
}
:deep(.el-textarea) {
width: 100%;
}
:deep(.el-upload),
:deep(.el-textarea),
:deep(.el-date-picker) {
width: 100%;
}
......
......@@ -156,12 +156,6 @@ const routes = [
title: "投后管理",
redirect: "/runningPeriod",
children: [
{
path: "/runningPeriod",
name: "runningPeriod",
title: "运营期投资检查",
component: () => import("@/views/castbehind/runningPeriod.vue"),
},
{
path: "/investmentCecovery",
name: "investmentCecovery",
......@@ -169,6 +163,20 @@ const routes = [
component: () =>
import("@/views/castbehind/investmentCecovery.vue"),
},
{
path: "/investmentCecoveryAdd",
name: "investmentCecoveryAdd",
title: "运营期投资回收",
component: () =>
import("@/views/castbehind/investmentCecoveryAdd.vue"),
},
{
path: "/runningPeriod",
name: "runningPeriod",
title: "运营期投资检查",
component: () => import("@/views/castbehind/runningPeriod.vue"),
},
{
path: "/runningPeriodAdd",
name: "runningPeriodAdd",
......
<template>
<div class="building-container">
<img src="@/assets/images/building.png" alt="" />
<div class="title">努力开发中……</div>
<div class="manage-container">
<div class="manage-wrap">
<div class="manage-header">
<div class="header-left"></div>
<div class="header-right">
<el-button type="primary" @click="investmentCecoveryAdd"
>新增</el-button
>
</div>
</div>
<div class="manage-content" v-loading="loading">
<common-table
:autoHeight="true"
:maxRows="10"
:data="tableData"
:columns="tableColumns"
:total="total"
:current-page="currentPage"
:page-size="pageSize"
:index="true"
:indexLabel="'序号'"
title=""
:border="true"
@size-change="handleSizeChange"
@current-page-change="handleCurrentPageChange"
>
<template #operations="{ row, index }">
<el-button
link
type="primary"
size="small"
@click="previewStatement(row)"
>查看</el-button
>
<el-button
link
type="primary"
size="small"
@click="editStatement(row)"
>编辑</el-button
>
<el-button
link
type="danger"
size="small"
@click="deleteStatement(row)"
>删除</el-button
>
</template>
</common-table>
</div>
</div>
</div>
</template>
<script setup></script>
<script setup>
import { ref, onMounted, getCurrentInstance } from "vue";
import { useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import CommonTable from "@/components/common/commonTable.vue";
const router = useRouter();
const { proxy } = getCurrentInstance();
let tableData = ref([]);
let tableColumns = ref([
{
prop: "qc",
label: "项目全称",
showOverflowTooltip: true,
},
{
prop: "jc",
label: "项目简称",
showOverflowTooltip: true,
},
{
prop: "nbtzglzt",
label: "内部投资管理主体",
showOverflowTooltip: true,
width: 170,
},
{
prop: "xmscjd",
label: "项目所处阶段",
showOverflowTooltip: true,
width: 120,
},
{
prop: "gqjg",
label: "股权结构",
showOverflowTooltip: true,
width: 120,
},
{
prop: "xmzbjze",
label: "项目资本金总额(亿元)",
showOverflowTooltip: true,
width: 180,
},
{
prop: "operations",
label: "操作",
width: 170,
slot: "operations",
fixed: "right",
align: "center",
},
]);
let loading = ref(false);
let total = ref(0);
let currentPage = ref(1);
let pageSize = ref(10);
// 获取列表数据
const getStatementData = () => {
loading.value = true;
proxy.$post({
url: "/api/project/getYyqtzhsList",
data: {
page: currentPage.value,
pagesize: pageSize.value,
},
callback: (data) => {
tableData.value = data.rows;
total.value = data.count;
loading.value = false;
},
});
};
// 分页
const handleSizeChange = (size) => {
pageSize.value = size;
currentPage.value = 1;
getStatementData();
};
const handleCurrentPageChange = (page) => {
currentPage.value = page;
getStatementData();
};
const investmentCecoveryAdd = () => {
router.push("/investmentCecoveryAdd");
};
const editStatement = (item) => {
router.push({
name: "investmentCecoveryAdd",
query: {
id: item.id,
},
});
};
const previewStatement = (item) => {
router.push({
name: "investmentCecoveryAdd",
query: {
isPreview: true,
id: item.id,
},
});
};
const deleteStatement = (item) => {
ElMessageBox.confirm("确认删除该项?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
proxy.$post({
url: "/api/project/deleteYyqtzhs",
data: {
id: item.id,
},
callback: (data) => {
ElMessage.success("删除成功");
getStatementData();
},
});
})
.catch(() => {});
};
onMounted(() => {
getStatementData();
});
</script>
<style lang="less">
.building-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
img {
max-width: 300px;
}
.title {
font-size: 18px;
color: #999;
}
}
<style scoped lang="less">
@import "@/styles/manage.less";
</style>
<template>
<div class="add-project-container">
<div class="add-project-content" v-loading="loading">
<div class="add-project-header">
<div class="header-left"></div>
<div class="header-right">
<el-button type="default" @click="backClick">返回</el-button>
<template v-if="!loading && !isPreview">
<el-button type="primary" @click="saveClick">保存</el-button>
</template>
</div>
</div>
<div class="tabs-content">
<div class="project-tab-content">
<div class="tab-content">
<el-form :model="formData" :label-width="200" :disabled="isPreview">
<el-collapse v-model="activeCollapse">
<el-collapse-item title="测试列表" name="测试列表">
</el-collapse-item>
<el-collapse-item title="项目基本信息" name="项目基本信息">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目名称" required>
<el-select
v-model="formData.projectId"
placeholder="请选择项目名称"
no-data-text="暂无数据"
@change="changeProject"
>
<el-option
v-for="item in projectList"
:key="item.id"
:label="item.projectName"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属行业">
<CommonSelector
v-model="formData.sshy"
dictName="participation_industry"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目公司名称">
<el-input
v-model="formData.xmgsmc"
placeholder="请输入项目公司名称"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="填报单位名称">
<el-input
v-model="formData.sbdw"
placeholder="请输入填报单位名称"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属二级企业">
<el-input
v-model="formData.ssejqy"
placeholder="请输入所属二级企业"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目阶段">
<CommonSelector
v-model="formData.xmjd"
dictName="project_phase"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目类别">
<CommonSelector
v-model="formData.xmlx"
dictName="xmlx"
></CommonSelector>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="投资模式分类">
<CommonSelector
v-model="formData.tzms"
dictName="tzms"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="投资回收方式">
<CommonSelector
v-model="formData.tzhsfs"
dictName="tzhsfs"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下年项目阶段">
<CommonSelector
v-model="formData.xnxmjd"
dictName="xmjd"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="财务报表类型">
<CommonSelector
v-model="formData.cwbblx"
dictName="cwbblx"
/>
</el-form-item>
</el-col>
</el-row>
<DynamicTable
:columns="transferColumns"
:disabled="isPreview"
v-model="formData.cgdwczqkxz"
>
</DynamicTable>
</el-collapse-item>
<el-collapse-item
title="投资额完成情况(万元)"
name="投资额完成情况(万元)"
><el-row gutter="20">
<el-col :span="12">
<el-form-item label="项目投资总额(决策值)(万元)">
<el-input
v-model="formData.tzzejc"
placeholder="请输入项目投资总额(决策值)(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="我方资本金出资额-决策值(万元)">
<el-input
v-model="formData.wfzbjczejc"
placeholder="请输入我方资本金出资额-决策值(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="投资总额-实际值(万元)">
<el-input
v-model="formData.tzzesj"
placeholder="请输入投资总额-实际值(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="我方资本家出资额--实际值(万元)">
<el-input
v-model="formData.wfzbjczesj"
placeholder="请输入我方资本家出资额--实际值(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="投资总额-计划值(万元)">
<el-input
v-model="formData.tzzejhz"
placeholder="请输入投资总额-计划值(万元)"
/>
</el-form-item>
</el-col>
</el-row>
</el-collapse-item>
<el-collapse-item
title="2025年投资回收累计完成情况-年度更新"
name="2025年投资回收累计完成情况-年度更新"
>
<el-row gutter="20">
<!-- 第一行:决策目标值相关数字项 -->
<el-col :span="12">
<el-form-item label="本年完成 投资回收决策目标值(万元)">
<el-input
v-model="formData.bnwc"
type="number"
precision="8"
placeholder="请输入本年完成 投资回收决策目标值(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="截止本年累计(决策目标值)">
<el-input
v-model="formData.jzbnlj"
type="number"
precision="8"
placeholder="请输入截止本年累计(决策目标值)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下一年完成数(万元)">
<el-input
v-model="formData.xynwcs"
type="number"
precision="8"
placeholder="请输入下一年完成数(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="本年计划(万元)">
<el-input
v-model="formData.bnjh"
type="number"
precision="8"
placeholder="请输入本年计划(万元)"
/>
</el-form-item>
</el-col>
<!-- 第二行:实际值相关数字项 -->
<el-col :span="12">
<el-form-item label="本年完成--投资回收实际值(万元)">
<el-input
v-model="formData.bnwcsjz"
type="number"
precision="8"
placeholder="请输入本年完成--投资回收实际值(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="截止本年累计--投资回收实际值">
<el-input
v-model="formData.jzbnljsjz"
type="number"
precision="8"
placeholder="请输入截止本年累计--投资回收实际值"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="累计欠收(万元)">
<el-input
v-model="formData.ljqs"
type="number"
precision="8"
placeholder="请输入累计欠收(万元)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="完成率(%)">
<el-input
v-model="formData.wcl"
type="number"
precision="2"
placeholder="请输入完成率(%)"
/>
</el-form-item>
</el-col>
<!-- 第三行及以后:长文本说明项(占满整行) -->
<el-col :span="24">
<el-form-item label="计划与决策目标值差异说明">
<el-input
v-model="formData.jhyjcmbcysm"
type="textarea"
rows="3"
placeholder="请输入计划与决策目标值差异说明"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="实际与计划差异说明">
<el-input
v-model="formData.sjyjhcysm"
type="textarea"
rows="3"
placeholder="请输入实际与计划差异说明"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="存在主要问题">
<el-input
v-model="formData.czdzywt"
type="textarea"
rows="3"
placeholder="请输入存在主要问题"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="采取措施及开展情况">
<el-input
v-model="formData.cqcsjgzkzqk"
type="textarea"
rows="3"
placeholder="请输入采取措施及开展情况"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input
v-model="formData.bz"
type="textarea"
rows="3"
placeholder="请输入备注"
/>
</el-form-item>
</el-col>
</el-row>
</el-collapse-item>
</el-collapse>
</el-form>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, ref, onMounted, getCurrentInstance, h, computed } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { useUserStore } from "@/stores/user.js";
import { number } from "echarts";
import DynamicTable from "@/components/FormDynamicTable/index.vue";
const transferColumns = ref([
{
prop: "mc",
label: "能建方持股比例",
type: "textarea",
headerGroup: "能建内容",
placeholder: "请填写能建方持股比例",
},
{
prop: "mc",
label: "能建方持股比例情况",
type: "textarea",
headerGroup: "能建内容",
placeholder: "请填写能建方持股比例情况",
},
{
prop: "mc",
label: "能建方持股比例情况",
type: "textarea",
headerGroup: "能建以外",
placeholder: "请填写能建方持股比例情况",
},
{
prop: "mc",
label: "政府方持股比例",
type: "textarea",
headerGroup: "能建以外",
placeholder: "请填写政府方持股比例",
},
{
prop: "fj",
label: "基金持股比例",
type: "textarea",
headerGroup: "能建以外",
placeholder: "请输入基金持股比例",
min: 0,
},
{
prop: "bz",
label: "能建方关联名称",
headerGroup: "能建以外",
type: "textarea",
placeholder: "请输入能建方关联名称",
},
]);
// 初始化全局变量
const userStore = useUserStore();
const router = useRouter();
const route = useRoute();
const { proxy } = getCurrentInstance();
const token = ref(
userStore.authToken || sessionStorage.getItem("authToken") || "",
);
// 小记金额
const subtotalNum = computed(() => {
let totalHtje = tzfhs.value.reduce((sum, item) => {
const num = Number(item.fhje) || 0; // 兼容空值/非数字
return sum + num;
}, 0);
let totalYwlr = wtyys.value.reduce((sum, item) => {
const num = Number(item.ywlr) || 0; // 兼容空值/非数字
return sum + num;
}, 0);
return (totalHtje + totalYwlr).toFixed(2);
});
// 折叠面板默认展开项
const activeCollapse = ref([
"项目基本信息",
"出资情况",
"合同约定权益获取",
"分红情况",
"投资额完成情况(万元)",
"净现金流",
"资金流出",
"分红情况",
]);
// 表单数据
const formData = reactive({
projectName: "",
qc: "",
jc: "",
nbtzglzt: "",
xmscjd: "",
gqjg: "",
xmzbjze: "",
gszbjyczze: "",
gsdqycze: "",
gsdqyjcze: "",
gsdqycwcje: "",
gsdqsycze: "",
cgbczqk: "",
wfqyhttkyd: "",
qyhqjz: "",
qyhqyyd: "",
dbqk: "",
lrfp: "",
sfddlrfptj: "",
ljhqfh: "",
ytrzj: "",
ljtrzj: "",
sxtrzj: "",
jt: "",
zx: "",
lxr: "",
lxfs: "",
bz: "",
projectId: "",
del: 0, // del字段保留0默认值(删除标记,0为正常)
createdAt: "",
updatedAt: "",
});
let options = ref();
function sumWtyysColumns(param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = h("div", "合计");
return;
}
const prop = column.property;
if (prop === "lx" || prop === "fwsj" || !prop) {
sums[index] = "";
return;
}
if (prop === "htje") {
const values = data.map((item) => Number(item.htje) || 0);
const total = values.reduce((prev, curr) => prev + curr, 0);
sums[index] = total.toFixed(2) + "(万元)";
return;
}
if (prop === "ywlr") {
const values = data.map((item) => Number(item.ywlr) || 0);
const total = values.reduce((prev, curr) => prev + curr, 0);
sums[index] = total.toFixed(2) + "(万元)";
return;
}
sums[index] = "";
});
return sums;
}
function sumTzfhsColumns(param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = h("div", "合计");
return;
}
const prop = column.property;
if (prop === "fhsj" || !prop) {
sums[index] = "";
return;
}
// 分红金额合计
if (prop === "fhje") {
const values = data.map((item) => Number(item.fhje) || 0);
const total = values.reduce((prev, curr) => prev + curr, 0);
sums[index] = total.toFixed(2) + "(万元)";
return;
}
sums[index] = "";
});
return sums;
}
// ========== 选择项目同步名称(通用) ==========
const changeProject = (val) => {
proxy.$post({
url: "/api/project/getProjectFinalInfo",
data: { id: val },
callback: (data) => {
loading.value = false;
Object.assign(formData, data);
},
error: () => {
loading.value = false;
ElMessage.error("获取项目详情失败");
},
});
const selectItem = projectList.value.find((item) => item.id === val);
if (selectItem) formData.projectName = selectItem.projectName;
};
// 加载状态
const loading = ref(false);
// 是否预览模式
const isPreview = ref(!!route.query.isPreview);
// 项目列表数据
const projectList = ref([]);
// 当前编辑的记录ID
const rcCgqyglId = ref(route.query.id || "");
let wtyys = ref([]);
const addPfyjlsqk = () => {
wtyys.value.push({});
};
const deletePfyjlsqk = (index) => {
ElMessageBox.confirm("确认删除该项?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
wtyys.value.splice(index, 1);
});
};
let tzfhs = ref([]);
// 新增
const addTzfhs = () => {
tzfhs.value.push({});
};
// 删除
const deleteTzfhs = (index) => {
ElMessageBox.confirm("确认删除该项?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
tzfhs.value.splice(index, 1);
});
};
// 获取项目列表
const getProjectData = () => {
proxy.$post({
url: "/api/project/listProject",
data: {
page: 1,
pagesize: 1000,
attributes: [],
menuType: "xmjc",
},
callback: (data) => {
projectList.value = data.rows || [];
},
});
};
// 获取单条记录详情(编辑/预览)
const getRcCgqyglDetail = () => {
if (!rcCgqyglId.value) return;
loading.value = true;
proxy.$post({
url: "/api/project/getCgqygl",
data: { id: rcCgqyglId.value },
callback: (data) => {
loading.value = false;
Object.assign(formData, {
...data,
});
if (data.wtyys) {
Object.assign(wtyys.value, data.wtyys);
}
// 新增:加载
if (data.tzfhs) {
Object.assign(tzfhs.value, data.tzfhs);
}
},
});
};
const backClick = () => {
router.back(-1);
};
// 保存/提交表单
const saveClick = () => {
// 基础校验
if (!formData.projectId) {
ElMessage.warning("请选择项目信息");
return;
}
loading.value = true;
// 区分新增/编辑
const url = rcCgqyglId.value
? "/api/project/updateCgqygl"
: "/api/project/createCgqygl";
// 处理空数字字段:空值转为null,避免提交空字符串
const submitData = {
...formData,
projectId: formData.projectId + "",
wtyys: wtyys.value,
tzfhs: tzfhs.value,
};
proxy.$post({
url: url,
data: submitData,
callback: (res) => {
loading.value = false;
ElMessage.success(rcCgqyglId.value ? "编辑成功" : "新增成功");
router.back(-1);
},
});
};
// 页面初始化
onMounted(() => {
// 获取项目列表
getProjectData();
options.value = JSON.parse(sessionStorage.getItem("resourceData"));
// 如果有ID则加载详情
if (rcCgqyglId.value) {
getRcCgqyglDetail();
}
});
</script>
<style scoped lang="less">
@import "@/styles/verticalManages.less";
// @import "@/styles/manage.less";
.DynamicTable-slot {
display: flex;
div {
text-align: center;
line-height: 38px;
}
div:nth-child(1) {
border: 1px solid #bbc0ca;
flex: 2;
}
div:nth-child(2) {
border: 1px solid #bbc0ca;
flex: 4;
}
height: 40px;
background-color: #f5f7fa;
}
.subtotal {
background-color: #f5f7fa;
height: 40px;
display: flex;
.label {
width: 100px;
height: 40px;
text-align: center;
line-height: 40px;
border-right: 1px solid #ebeef5;
}
.value {
padding-left: 16px;
width: 100%;
line-height: 40px;
}
}
</style>
......@@ -19,10 +19,10 @@
<el-collapse-item title="基本信息" name="基本信息">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目信息" required>
<el-form-item label="项目名称" required>
<el-select
v-model="formData.projectId"
placeholder="请选择项目信息"
placeholder="请选择项目名称"
no-data-text="暂无数据"
@change="changeProject"
>
......@@ -35,6 +35,7 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目外文名称">
<el-input
......@@ -71,10 +72,142 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目公司名称/被投资企业名称">
<el-form-item label="项目公司名称">
<el-input
v-model="formData.xmgsmc"
placeholder="请输入项目公司名称"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目预计完成时间">
<el-date-picker
v-model="formData.xmjgsjyj"
type="date"
placeholder="请选择项目预计完成时间"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="填报人">
<el-input
v-model="formData.tbr"
placeholder="请输入填报人"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="填报人联系电话">
<el-input
v-model="formData.tbrlxdh"
placeholder="请输入填报人联系电话"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目建设期 (月)">
<el-input
v-model="formData.xmjsqy"
:min="0"
placeholder="请输入项目建设期 (月)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目流转状态(审批状态)">
<CommonSelector
v-model="formData.projectLzType"
dictName="xmlzzt"
></CommonSelector>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目阶段">
<CommonSelector
v-model="formData.xmjd"
dictName="project_phase"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="运营年限(年)">
<el-input
v-model="formData.yynxn"
:min="0"
placeholder="请输入运营年限(年)"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="建成后成效">
<el-input
v-model="formData.jchcx"
type="textarea"
:rows="3"
placeholder="请输入建成后成效"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目信息" required>
<el-select
v-model="formData.projectId"
placeholder="请选择项目信息"
no-data-text="暂无数据"
@change="changeProject"
>
<el-option
v-for="item in projectList"
:key="item.id"
:label="item.projectName"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目外文名称">
<el-input
v-model="formData.projectForeignName"
placeholder="请输入项目外文名称"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="填报单位名称">
<el-input
v-model="formData.tbdwmc"
placeholder="请输入填报单位名称"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属二级企业">
<el-input
v-model="formData.ssejqy"
placeholder="请输入所属二级企业"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目预计起始时间">
<el-date-picker
v-model="formData.xmkgsjyj"
type="date"
placeholder="请选择项目预计起始时间"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目公司名称">
<el-input
v-model="formData.xmgsmc"
placeholder="请输入项目公司名称/被投资企业名称"
placeholder="请输入项目公司名称"
/>
</el-form-item>
</el-col>
......@@ -1125,7 +1258,7 @@ const formData = reactive({
projectForeignName: "",
sbdw: "", // 申报单位
ssejqy: "", // 所属二级企业
xmgsmc: "", // 项目公司名称/被投资企业名称
xmgsmc: "", // 项目公司名称
xmkgsjyj: "", // 项目预计起始时间
xmjgsjyj: "", // 项目预计完成时间
tbr: "", // 填报人
......
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