明树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 @@ ...@@ -51,6 +51,9 @@
<slot name="header-actions" /> <slot name="header-actions" />
</div> </div>
<!-- 表格上方默认插槽 -->
<slot></slot>
<!-- 表格主体 --> <!-- 表格主体 -->
<el-table <el-table
:data="modelValue" :data="modelValue"
...@@ -63,8 +66,111 @@ ...@@ -63,8 +66,111 @@
<!-- 序号列 --> <!-- 序号列 -->
<el-table-column type="index" fixed="left" width="60" label="序号" /> <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 group.children"
: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-model="scope.row[column.prop]"
:isInline="true"
:disabled="disabled"
/>
</template>
</template>
</el-table-column>
</el-table-column>
</template>
<!-- 🌟 无配置headerGroup → 渲染原生单级表头(和原组件完全一致) -->
<el-table-column <el-table-column
v-else
v-for="column in columns" v-for="column in columns"
:key="column.prop" :key="column.prop"
:prop="column.prop" :prop="column.prop"
...@@ -73,90 +179,86 @@ ...@@ -73,90 +179,86 @@
:align="column.align || 'left'" :align="column.align || 'left'"
> >
<template #default="scope"> <template #default="scope">
<!-- 普通输入框 --> <template v-if="column.type === 'input'">
<el-input <el-input
v-if="column.type === 'input'" v-model="scope.row[column.prop]"
v-model="scope.row[column.prop]" :placeholder="column.placeholder"
:placeholder="column.placeholder" :disabled="disabled"
:disabled="disabled" :maxlength="column.maxlength"
:maxlength="column.maxlength"
/>
<!-- 数字输入框 -->
<el-input
v-else-if="column.type === 'number'"
v-model.number="scope.row[column.prop]"
type="number"
:placeholder="column.placeholder"
:disabled="disabled"
:precision="column.precision"
:min="column.min"
:max="column.max"
/>
<!-- 文本域 -->
<el-input
v-else-if="column.type === 'textarea'"
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"
/>
<!-- 下拉选择框 -->
<el-select
v-else-if="column.type === '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 === 'number'">
<!-- 单选框组 --> <el-input
<el-radio-group v-model.number="scope.row[column.prop]"
v-else-if="column.type === 'radio'" type="number"
v-model="scope.row[column.prop]" :placeholder="column.placeholder"
:disabled="disabled" :disabled="disabled"
> :precision="column.precision"
<el-radio :min="column.min"
v-for="item in selectOptions?.[column.optionKey] || []" :max="column.max"
:key="item.key || item.value" />
:label="item.key || item.value" </template>
style="margin-right: 12px" <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"
> >
{{ item.name || item.label }} <el-option
</el-radio> v-for="item in selectOptions?.[column.optionKey] || []"
</el-radio-group> :key="item.key || item.value"
:label="item.name || item.label"
<!-- 时间选择器 --> :value="item.key || item.value"
<el-date-picker />
</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'" v-else-if="column.type === 'date' || column.type === 'datetime'"
v-model="scope.row[column.prop]" >
:type="column.type === 'datetime' ? 'datetime' : 'date'" <el-date-picker
:format="column.format || 'YYYY-MM-DD'" v-model="scope.row[column.prop]"
:value-format="column.valueFormat || 'YYYY-MM-DD'" :type="column.type === 'datetime' ? 'datetime' : 'date'"
:placeholder="column.placeholder" :format="column.format || 'YYYY-MM-DD'"
:disabled="disabled" :value-format="column.valueFormat || 'YYYY-MM-DD'"
style="width: 100%" :placeholder="column.placeholder"
/> :disabled="disabled"
style="width: 100%"
<!-- 文件上传组件 --> />
<FileUploader </template>
v-else-if="column.type === 'upload'" <template v-else-if="column.type === 'upload'">
v-model="scope.row[column.prop]" <FileUploader
:isInline="true" v-model="scope.row[column.prop]"
:disabled="disabled" :isInline="true"
/> :disabled="disabled"
/>
</template>
</template> </template>
</el-table-column> </el-table-column>
...@@ -184,7 +286,6 @@ ...@@ -184,7 +286,6 @@
> >
删除 删除
</el-button> </el-button>
<!-- 自定义操作按钮 --> <!-- 自定义操作按钮 -->
<el-button <el-button
v-for="(btn, btnIndex) in operationButtons" v-for="(btn, btnIndex) in operationButtons"
...@@ -198,7 +299,6 @@ ...@@ -198,7 +299,6 @@
> >
{{ btn.text }} {{ btn.text }}
</el-button> </el-button>
<!-- 操作列自定义插槽 --> <!-- 操作列自定义插槽 -->
<slot <slot
name="operations" name="operations"
...@@ -213,85 +313,40 @@ ...@@ -213,85 +313,40 @@
</template> </template>
<script setup> <script setup>
import { defineProps, defineEmits, ref } from "vue"; import { defineProps, defineEmits, ref, computed } from "vue";
import { ElMessageBox, ElMessage } from "element-plus"; import { ElMessageBox, ElMessage } from "element-plus";
import { Download, Upload } from "@element-plus/icons-vue"; import { Download, Upload } from "@element-plus/icons-vue";
// 请确认项目实际路径,不一致直接修改
import FileUploader from "@/components/FileUploader/index.vue"; import FileUploader from "@/components/FileUploader/index.vue";
// 请确认项目实际路径,不一致直接修改
import { getTableFileData, exportTableFile } from "@/common/tableFileHandle"; import { getTableFileData, exportTableFile } from "@/common/tableFileHandle";
// 定义Props // 定义Props
const props = defineProps({ const props = defineProps({
// 核心配置 // 核心双向绑定数据
modelValue: { modelValue: { type: Array, required: true, default: () => [] },
type: Array, // 列配置(headerGroup用于多级表头合并)
required: true, columns: { type: Array, required: true, default: () => [] },
default: () => [], // 新增行默认值
}, defaultRow: { type: Object, default: () => ({}) },
columns: {
type: Array,
required: true,
default: () => [],
},
defaultRow: {
type: Object,
required: true,
default: () => ({}),
},
// 基础配置 // 基础配置
addButtonText: { addButtonText: { type: String, default: "新增" },
type: String, disabled: { type: Boolean, default: false },
default: "新增", selectOptions: { type: Object, default: () => ({}) },
}, scrollbarAlwaysOn: { type: Boolean, default: false },
disabled: { // 按钮显隐配置
type: Boolean, showAddButton: { type: Boolean, default: true },
default: false, showDeleteButton: { type: Boolean, default: true },
}, // 导入导出配置
selectOptions: { showImportExport: { type: Boolean, default: false },
type: Object, exportName: { type: String, default: "表格数据" },
default: () => ({}), // 自定义操作按钮
}, operationButtons: { type: Array, default: () => [] },
scrollbarAlwaysOn: { operationColumnWidth: { type: [String, Number], default: "auto" },
type: Boolean, operationColumnMinWidth: { type: [String, Number], default: 60 },
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([ const emit = defineEmits([
"update:modelValue", "update:modelValue",
"add", "add",
...@@ -303,44 +358,77 @@ const emit = defineEmits([ ...@@ -303,44 +358,77 @@ const emit = defineEmits([
// 导入上传组件Ref // 导入上传组件Ref
const uploadRef = ref(null); 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值转为文字描述 * 导出数据转换:select/radio的key值转为文字描述
* @param {Array} data 原始表格数据
* @returns {Array} 转换后的导出数据
*/ */
const convertDataForExport = (data) => { const convertDataForExport = (data) => {
if (!data || !data.length) return []; if (!data || !data.length) return [];
return data.map((row) => { return data.map((row) => {
const newRow = { ...row }; const newRow = { ...row };
// 遍历列配置,处理select/radio类型字段
props.columns.forEach((column) => { props.columns.forEach((column) => {
if (column.type === "select" || column.type === "radio") { if (column.type === "select" || column.type === "radio") {
const prop = column.prop; const prop = column.prop;
const optionKey = column.optionKey; const optionKey = column.optionKey;
const options = props.selectOptions?.[optionKey] || []; const options = props.selectOptions?.[optionKey] || [];
if ( if (
newRow[prop] !== undefined && newRow[prop] !== undefined &&
newRow[prop] !== null && newRow[prop] !== null &&
newRow[prop] !== "" newRow[prop] !== ""
) { ) {
// 处理多选(select multiple) // 处理多选
if (column.multiple && Array.isArray(newRow[prop])) { if (column.multiple && Array.isArray(newRow[prop])) {
newRow[prop] = newRow[prop] newRow[prop] = newRow[prop]
.map((key) => { .map((key) => {
const option = options.find( const option = options.find(
(item) => (item.key || item.value) === key (item) => (item.key || item.value) === key,
); );
return option ? item.name || item.label : key; return option ? item.name || item.label : key;
}) })
.join(","); // 多选用中文逗号分隔 .join(",");
} else { } else {
// 单选处理 // 处理单选
const option = options.find( 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) => { ...@@ -350,47 +438,41 @@ const convertDataForExport = (data) => {
}; };
/** /**
* 导入数据转换:将文字描述转回对应的key值 * 导入数据转换:文字描述转回对应的key值
* @param {Array} data 导入的原始数据
* @returns {Array} 转换后的表格数据
*/ */
const convertDataForImport = (data) => { const convertDataForImport = (data) => {
if (!data || !data.length) return []; if (!data || !data.length) return [];
return data.map((row) => { return data.map((row) => {
const newRow = { ...row }; const newRow = { ...row };
// 遍历列配置,处理select/radio类型字段
props.columns.forEach((column) => { props.columns.forEach((column) => {
if (column.type === "select" || column.type === "radio") { if (column.type === "select" || column.type === "radio") {
const prop = column.prop; const prop = column.prop;
const optionKey = column.optionKey; const optionKey = column.optionKey;
const options = props.selectOptions?.[optionKey] || []; const options = props.selectOptions?.[optionKey] || [];
if ( if (
newRow[prop] !== undefined && newRow[prop] !== undefined &&
newRow[prop] !== null && newRow[prop] !== null &&
newRow[prop] !== "" newRow[prop] !== ""
) { ) {
// 处理多选(select multiple) // 处理多选
if (column.multiple) { if (column.multiple) {
const textList = newRow[prop] const textList = newRow[prop]
.split(",") .split(",")
.map((item) => item.trim()); .map((item) => item.trim());
newRow[prop] = textList.map((text) => { newRow[prop] = textList.map((text) => {
const option = options.find( 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 { } else {
// 单选处理 // 处理单选
const option = options.find( 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 { } else {
// 空值处理为默认空
newRow[prop] = ""; newRow[prop] = "";
} }
} }
...@@ -399,7 +481,7 @@ const convertDataForImport = (data) => { ...@@ -399,7 +481,7 @@ const convertDataForImport = (data) => {
}); });
}; };
// 1. 新增行 // 新增行
const handleAdd = () => { const handleAdd = () => {
try { try {
const newRow = { ...props.defaultRow }; const newRow = { ...props.defaultRow };
...@@ -412,7 +494,7 @@ const handleAdd = () => { ...@@ -412,7 +494,7 @@ const handleAdd = () => {
} }
}; };
// 2. 删除行 // 删除行
const handleDelete = (index) => { const handleDelete = (index) => {
ElMessageBox.confirm("确认删除该项?", "提示", { ElMessageBox.confirm("确认删除该项?", "提示", {
confirmButtonText: "确认", confirmButtonText: "确认",
...@@ -434,23 +516,22 @@ const handleDelete = (index) => { ...@@ -434,23 +516,22 @@ const handleDelete = (index) => {
.catch(() => {}); .catch(() => {});
}; };
// 3. 自定义操作按钮点击 // 自定义操作按钮点击
const handleCustomOperation = (btn, scope) => { const handleCustomOperation = (btn, scope) => {
if (btn.click) { if (btn.click) {
try { try {
btn.click(scope.row, scope.$index); btn.click(scope.row, scope.$index);
} catch (e) { } catch (e) {
console.error("自定义按钮点击事件执行失败:", e); console.error("自定义按钮点击失败:", e);
ElMessage.error("操作执行失败,请稍后重试"); ElMessage.error("操作执行失败,请稍后重试");
} }
} }
emit("custom-operation", btn, scope.row, scope.$index); emit("custom-operation", btn, scope.row, scope.$index);
}; };
// 4. 导出表格数据(修改:添加数据转换) // 导出表格数据
const handleExport = () => { const handleExport = () => {
try { try {
// 先转换数据,再导出
const exportData = convertDataForExport(props.modelValue); const exportData = convertDataForExport(props.modelValue);
exportTableFile(exportData, props.columns, "", props.exportName); exportTableFile(exportData, props.columns, "", props.exportName);
ElMessage.success("导出成功"); ElMessage.success("导出成功");
...@@ -460,10 +541,9 @@ const handleExport = () => { ...@@ -460,10 +541,9 @@ const handleExport = () => {
} }
}; };
// 5. 导入表格数据(修改:添加数据转换) // 导入表格数据
const handleImport = (file) => { const handleImport = (file) => {
uploadRef.value?.clearFiles(); uploadRef.value?.clearFiles();
getTableFileData(file, props.columns) getTableFileData(file, props.columns)
.then((rawImportData) => { .then((rawImportData) => {
const convertedData = convertDataForImport(rawImportData); const convertedData = convertDataForImport(rawImportData);
...@@ -476,7 +556,7 @@ const handleImport = (file) => { ...@@ -476,7 +556,7 @@ const handleImport = (file) => {
}); });
}; };
// 6. 导入成功后的数据处理 // 导入成功后数据处理
const handleImportSuccess = (importData) => { const handleImportSuccess = (importData) => {
try { try {
const newData = [...props.modelValue, ...importData]; const newData = [...props.modelValue, ...importData];
...@@ -523,14 +603,8 @@ const handleImportSuccess = (importData) => { ...@@ -523,14 +603,8 @@ const handleImportSuccess = (importData) => {
--el-table-row-hover-bg-color: #f8f9fa; --el-table-row-hover-bg-color: #f8f9fa;
} }
:deep(.el-upload) { :deep(.el-upload),
width: 100%; :deep(.el-textarea),
}
:deep(.el-textarea) {
width: 100%;
}
:deep(.el-date-picker) { :deep(.el-date-picker) {
width: 100%; width: 100%;
} }
......
...@@ -156,12 +156,6 @@ const routes = [ ...@@ -156,12 +156,6 @@ const routes = [
title: "投后管理", title: "投后管理",
redirect: "/runningPeriod", redirect: "/runningPeriod",
children: [ children: [
{
path: "/runningPeriod",
name: "runningPeriod",
title: "运营期投资检查",
component: () => import("@/views/castbehind/runningPeriod.vue"),
},
{ {
path: "/investmentCecovery", path: "/investmentCecovery",
name: "investmentCecovery", name: "investmentCecovery",
...@@ -169,6 +163,20 @@ const routes = [ ...@@ -169,6 +163,20 @@ const routes = [
component: () => component: () =>
import("@/views/castbehind/investmentCecovery.vue"), 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", path: "/runningPeriodAdd",
name: "runningPeriodAdd", name: "runningPeriodAdd",
......
<template> <template>
<div class="building-container"> <div class="manage-container">
<img src="@/assets/images/building.png" alt="" /> <div class="manage-wrap">
<div class="title">努力开发中……</div> <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> </div>
</template> </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";
<style lang="less"> const router = useRouter();
.building-container { const { proxy } = getCurrentInstance();
width: 100%;
height: 100%; let tableData = ref([]);
display: flex; let tableColumns = ref([
flex-direction: column; {
align-items: center; prop: "qc",
justify-content: center; label: "项目全称",
img { showOverflowTooltip: true,
max-width: 300px; },
} {
.title { prop: "jc",
font-size: 18px; label: "项目简称",
color: #999; 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 scoped lang="less">
@import "@/styles/manage.less";
</style> </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 @@ ...@@ -19,10 +19,10 @@
<el-collapse-item title="基本信息" name="基本信息"> <el-collapse-item title="基本信息" name="基本信息">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="项目信息" required> <el-form-item label="项目名称" required>
<el-select <el-select
v-model="formData.projectId" v-model="formData.projectId"
placeholder="请选择项目信息" placeholder="请选择项目名称"
no-data-text="暂无数据" no-data-text="暂无数据"
@change="changeProject" @change="changeProject"
> >
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="项目外文名称"> <el-form-item label="项目外文名称">
<el-input <el-input
...@@ -71,10 +72,142 @@ ...@@ -71,10 +72,142 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <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 <el-input
v-model="formData.xmgsmc" v-model="formData.xmgsmc"
placeholder="请输入项目公司名称/被投资企业名称" placeholder="请输入项目公司名称"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
...@@ -1125,7 +1258,7 @@ const formData = reactive({ ...@@ -1125,7 +1258,7 @@ const formData = reactive({
projectForeignName: "", projectForeignName: "",
sbdw: "", // 申报单位 sbdw: "", // 申报单位
ssejqy: "", // 所属二级企业 ssejqy: "", // 所属二级企业
xmgsmc: "", // 项目公司名称/被投资企业名称 xmgsmc: "", // 项目公司名称
xmkgsjyj: "", // 项目预计起始时间 xmkgsjyj: "", // 项目预计起始时间
xmjgsjyj: "", // 项目预计完成时间 xmjgsjyj: "", // 项目预计完成时间
tbr: "", // 填报人 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