明树Git Lab

Commit bc1354b0 authored by zhanghan's avatar zhanghan

1

parent 5c1a28a5
Pipeline #108823 passed with stage
in 21 seconds
{
"permissions": {
"allow": [
"mcp__zai-mcp-server__analyze_image"
"mcp__zai-mcp-server__analyze_image",
"mcp__zai-mcp-server__extract_text_from_screenshot"
]
}
}
......@@ -69,22 +69,29 @@
</el-table-column>
<!-- 多级时间列表头渲染逻辑 -->
<template v-if="hasTimeHeaderGroup">
<template v-for="group in timeColumnGroups" :key="`time-group-${group.key}`">
<!-- 有一级分组标题 -->
<el-table-column
v-for="group in timeColumnGroups"
:key="`time-group-${group.key}`"
v-if="!group.isSingle && group.label"
:label="group.label"
align="right"
>
<!-- 遍历一级分组的子项 -->
<template v-for="child in group.children" :key="`child-${child.key || child.prop}`">
<!-- 如果是二级分组 -->
<el-table-column
v-for="timeItem in group.children"
v-if="child.isSubGroup"
:label="child.label"
align="center"
>
<el-table-column
v-for="timeItem in child.children"
:key="`time-col-${timeItem.prop}`"
:label="timeItem.label"
min-width="140"
align="center"
>
<template #default="{ row }">
<!-- 🌟 核心修改:优先使用列级isTextRow配置,其次行级 -->
<el-input
v-if="timeItem.isTextRow || row.isTextRow"
v-model="row[timeItem.prop]"
......@@ -95,7 +102,6 @@
style="width: 100%"
@input="() => handleTextInput(row)"
/>
<!-- 数字行:金额输入框 -->
<el-input
v-else
v-model="row[timeItem.prop]"
......@@ -109,22 +115,52 @@
</template>
</el-table-column>
</el-table-column>
<!-- 如果是直接列(没有二级分组) -->
<el-table-column
v-else
:key="`time-col-${child.prop}`"
:label="child.label"
min-width="140"
align="center"
>
<template #default="{ row }">
<el-input
v-if="child.isTextRow || row.isTextRow"
v-model="row[child.prop]"
type="textarea"
:rows="2"
:disabled="isPreview"
placeholder="请输入说明"
style="width: 100%"
@input="() => handleTextInput(row)"
/>
<el-input
v-else
v-model="row[child.prop]"
:precision="2"
controls-position="right"
:disabled="isPreview"
placeholder="请输入金额"
style="width: 100%"
@change="() => handleFinancialChange(row)"
/>
</template>
<!-- 无时间列分组 → 单级表头逻辑 -->
</el-table-column>
</template>
</el-table-column>
<!-- 单列(没有分组标题,label 为空) -->
<el-table-column
v-else
v-for="time in validDynamicTimeConfig"
:key="`time-col-${time.prop || time}`"
:label="time.label || time"
v-for="timeItem in group.children"
:key="`time-col-${timeItem.prop}`"
:label="timeItem.label"
min-width="140"
align="center"
>
<template #default="{ row }">
<!-- 🌟 核心修改:优先使用列级isTextRow配置,其次行级 -->
<el-input
v-if="time.isTextRow || row.isTextRow"
v-model="row[time.prop || time]"
v-if="timeItem.isTextRow || row.isTextRow"
v-model="row[timeItem.prop]"
type="textarea"
:rows="2"
:disabled="isPreview"
......@@ -132,10 +168,9 @@
style="width: 100%"
@input="() => handleTextInput(row)"
/>
<!-- 数字行:金额输入框 -->
<el-input
v-else
v-model="row[time.prop || time]"
v-model="row[timeItem.prop]"
:precision="2"
controls-position="right"
:disabled="isPreview"
......@@ -145,6 +180,7 @@
/>
</template>
</el-table-column>
</template>
</el-table>
<div v-else style="text-align: center; padding: 20px; color: #909399">
请传入合法的表格配置(包含indicatorList、dynamicTimeList)
......@@ -213,6 +249,7 @@ const validDynamicTimeConfig = computed(() => {
label: item.trim(),
prop: item.trim(),
headerGroup: "",
subGroup: "", // 支持三级分组
isTextRow: false, // 字符串格式默认数字列
};
}
......@@ -220,42 +257,88 @@ const validDynamicTimeConfig = computed(() => {
label: item.label?.trim() || "",
prop: item.prop?.trim() || item.label?.trim() || "",
headerGroup: item.headerGroup?.trim() || "",
subGroup: item.subGroup?.trim() || "", // 支持三级分组
isTextRow: item.isTextRow === true, // 显式转换为布尔值,默认false
};
})
.filter((item) => !!item.prop);
});
// 判断是否有时间列分组
const hasTimeHeaderGroup = computed(() => {
return validDynamicTimeConfig.value.some((item) => !!item.headerGroup);
});
// 时间列分组计算
// 时间列分组计算(支持三级分组:headerGroup -> subGroup -> 列)
const timeColumnGroups = computed(() => {
const timeConfig = validDynamicTimeConfig.value;
if (!timeConfig.length) return [];
const groupMap = {};
const groupMap = {}; // 一级分组:headerGroup
const singleColumns = []; // 没有分组的单列
timeConfig.forEach((item) => {
const groupKey = item.headerGroup || `single_${item.prop}`;
if (!groupMap[groupKey]) {
groupMap[groupKey] = {
label: item.headerGroup || item.label,
key: groupKey,
const headerGroup = item.headerGroup?.trim();
const subGroup = item.subGroup?.trim();
// 如果有有效的 headerGroup,则创建分组
if (headerGroup && headerGroup.length > 0) {
if (!groupMap[headerGroup]) {
groupMap[headerGroup] = {
label: headerGroup,
key: headerGroup,
children: [],
};
}
groupMap[groupKey].children.push(item);
// 如果有 subGroup,在一级分组下创建二级分组
if (subGroup && subGroup.length > 0) {
let subGroupItem = groupMap[headerGroup].children.find(
(child) => child.label === subGroup
);
if (!subGroupItem) {
subGroupItem = {
label: subGroup,
key: `${headerGroup}_${subGroup}`,
isSubGroup: true, // 标记为二级分组
children: [],
};
groupMap[headerGroup].children.push(subGroupItem);
}
subGroupItem.children.push(item);
} else {
// 没有 subGroup,直接挂在一级分组下
groupMap[headerGroup].children.push(item);
}
} else {
// 没有 headerGroup 的作为单列处理(不显示一级标题)
singleColumns.push({
label: "", // 空标题,不显示一级分组
key: `single_${item.prop}`,
isSingle: true, // 标记为单列
children: [item],
});
}
});
// 合并分组和单列,保持原始顺序
const result = [];
const addedKeys = new Set();
timeConfig.forEach((item) => {
const groupKey = item.headerGroup || `single_${item.prop}`;
if (!addedKeys.has(groupKey)) {
result.push(groupMap[groupKey]);
addedKeys.add(groupKey);
const headerGroup = item.headerGroup?.trim();
// 有分组的
if (headerGroup && headerGroup.length > 0) {
if (!addedKeys.has(headerGroup)) {
result.push(groupMap[headerGroup]);
addedKeys.add(headerGroup);
}
} else {
// 单列
const singleKey = `single_${item.prop}`;
if (!addedKeys.has(singleKey)) {
const singleColumn = singleColumns.find((sc) => sc.key === singleKey);
if (singleColumn) {
result.push(singleColumn);
addedKeys.add(singleKey);
}
}
}
});
......@@ -414,6 +497,7 @@ const tableCellStyle = ({ row }) => {
line-height: 48px;
background: #f5f7fa;
text-align: center;
margin-bottom: 0;
}
:deep(.el-input-number) {
......
This diff is collapsed.
......@@ -116,6 +116,7 @@
color: var(--el-color-primary);
}
}
&-header {
border: none;
height: 64px;
......@@ -130,6 +131,7 @@
height: 0;
display: flex;
flex-direction: column;
.tabs-content {
flex: 1;
height: 0;
......
......@@ -64,15 +64,6 @@
</td>
<!-- 1级指标建议值 -->
<td class="cell-item">
<!-- <el-input
type="textarea"
rows="3"
v-model="item.level1Target.value"
:placeholder="item.level1Target.placeholder"
size="small"
class="table-input"
:disabled="isPreview"
/> -->
{{ item.level1Target.placeholder }}
</td>
<td class="cell-item">
......
This diff is collapsed.
......@@ -4,9 +4,7 @@
<search-form @search="handleSearch" />
<div class="manage-header">
<div class="header-left"></div>
<div class="header-right">
<el-button type="primary" @click="annualAdd">新增</el-button>
</div>
<div class="header-right"></div>
</div>
<div class="manage-content" v-loading="loading">
<common-table
......@@ -29,22 +27,11 @@
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
:loading="row.loading"
@click="previewProject(row)"
>{{
canAudit && row.projectLzType == 8 ? "审批" : "查看"
}}</el-button
>
</template>
</common-table>
......@@ -54,9 +41,10 @@
</template>
<script setup>
import { ref, onMounted, getCurrentInstance } from "vue";
import { reactive, ref, onMounted, computed, getCurrentInstance } from "vue";
import { useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { useUserStore } from "@/stores/user.js";
import CommonTable from "@/components/common/commonTable.vue";
import SearchForm from "@/components/common/SearchForm.vue";
......@@ -67,6 +55,19 @@ const handleSearch = (formData) => {
};
const router = useRouter();
const { proxy } = getCurrentInstance();
// 是否是审核角色
const userStore = useUserStore();
const userInfo =
userStore.userInfo ||
(sessionStorage.getItem("userInfo") &&
JSON.parse(sessionStorage.getItem("userInfo"))) ||
{};
let canAudit = ref(false);
userInfo.roles.map((item) => {
if (["xmlx_sp", "xmjc_sp"].includes(item.key)) {
canAudit.value = true;
}
});
let tableData = ref([]);
let tableColumns = ref([
......@@ -76,45 +77,41 @@ let tableColumns = ref([
showOverflowTooltip: true,
},
{
prop: "projectForeignName",
label: "项目外文名称",
prop: "projectCode",
label: "项目编号",
showOverflowTooltip: true,
},
{
prop: "sbdw",
label: "申报单位",
showOverflowTooltip: true,
},
{
prop: "ssejqy",
label: "所属二级企业",
showOverflowTooltip: true,
},
{
prop: "xmgsmc",
label: "项目公司名称",
showOverflowTooltip: true,
},
{
prop: "xmkgsjyj",
label: "项目预计起始时间",
showOverflowTooltip: true,
prop: "projectLzType",
label: "状态",
width: 120,
align: "center",
formatter: (data) => {
return data.projectLzType === "1"
? "待立项"
: data.projectLzType === "3"
? "立项审批中"
: data.projectLzType === "5"
? "已立项"
: data.projectLzType === "7"
? "决策填报中"
: data.projectLzType === "8"
? "决策审批中"
: data.projectLzType === "9"
? "已决策"
: "待立项";
},
{
prop: "xmjgsjyj",
label: "目预计完成时间",
showOverflowTooltip: true,
},
{
prop: "operations",
label: "操作",
width: 170,
width: 160,
slot: "operations",
fixed: "right",
align: "center",
},
]);
let loading = ref(false);
let total = ref(0);
let currentPage = ref(1);
......@@ -123,10 +120,12 @@ let pageSize = ref(10);
const getProjectData = (params = {}) => {
loading.value = true;
proxy.$post({
url: "/api/project/getTzjhList",
url: "/api/project/listProject",
data: {
page: currentPage.value,
pagesize: pageSize.value,
attributes: [],
menuType: "xmjc",
...params,
},
callback: (data) => {
......@@ -136,6 +135,9 @@ const getProjectData = (params = {}) => {
},
});
};
onMounted(() => {
getProjectData();
});
// 分页
const handleSizeChange = (size) => {
pageSize.value = size;
......@@ -146,49 +148,15 @@ const handleCurrentPageChange = (page) => {
currentPage.value = page;
getProjectData();
};
const annualAdd = () => {
router.push("/decisionAdd");
};
const editStatement = (item) => {
router.push({
name: "decisionAdd",
query: {
id: item.id,
},
});
};
const previewStatement = (item) => {
const previewProject = (item) => {
router.push({
name: "decisionAdd",
name: "addProject",
query: {
isPreview: true,
id: item.id,
projectId: item.id,
},
});
};
const deleteStatement = (item) => {
ElMessageBox.confirm("确认删除该项?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
proxy.$post({
url: "/api/project/deleteTzjh",
data: {
id: item.id,
},
callback: (data) => {
ElMessage.success("删除成功");
getProjectData();
},
});
})
.catch(() => {});
};
onMounted(() => {
getProjectData();
});
</script>
<style scoped lang="less"></style>
This diff is collapsed.
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