明树Git Lab

Commit bc1354b0 authored by zhanghan's avatar zhanghan

1

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