优化项目管理

This commit is contained in:
2026-09-13 22:31:42 +08:00
parent 2f6cdbb3cd
commit a8c09c1db5
30 changed files with 1654 additions and 346 deletions
@@ -1,32 +1,71 @@
<template>
<el-descriptions v-if="project" :column="2" border size="small">
<el-descriptions-item label="项目名称" :span="2">{{ project.project_name }}</el-descriptions-item>
<el-descriptions-item label="项目编号">{{ project.project_no || "-" }}</el-descriptions-item>
<el-descriptions-item label="客户名称">{{ project.customer_name || "-" }}</el-descriptions-item>
<el-descriptions-item label="项目金额">{{ formatMoney(project.amount) }}</el-descriptions-item>
<el-descriptions-item label="项目状态">
<el-tag :type="projectStatusTag(project.status)" size="small">
{{ projectStatusText(project.status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="负责人">{{ project.owner_user_name || "-" }}</el-descriptions-item>
<el-descriptions-item label="客户行业">{{ project.industry || "-" }}</el-descriptions-item>
<el-descriptions-item label="开始日期">{{ formatDateOnly(project.start_date) }}</el-descriptions-item>
<el-descriptions-item label="结束日期">{{ formatDateOnly(project.end_date) }}</el-descriptions-item>
<el-descriptions-item label="来源商机">
{{ project.business_name || (project.business_id ? `#${project.business_id}` : "-") }}
</el-descriptions-item>
<el-descriptions-item label="对接人">{{ project.contact_person || "-" }}</el-descriptions-item>
<el-descriptions-item label="对接人职位">{{ project.contact_position || "-" }}</el-descriptions-item>
<el-descriptions-item label="对接人手机">{{ project.contact_phone || "-" }}</el-descriptions-item>
<el-descriptions-item label="项目地址" :span="2">{{ project.address || "-" }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ formatDateTime(project.create_time) }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ formatDateTime(project.update_time) }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ project.remark || "-" }}</el-descriptions-item>
</el-descriptions>
<div v-if="project" class="project-basic">
<el-divider content-position="left">基本信息</el-divider>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="项目名称" :span="2">{{ project.project_name }}</el-descriptions-item>
<el-descriptions-item label="项目编号">{{ project.project_no || "-" }}</el-descriptions-item>
<el-descriptions-item label="项目类型">
<el-tag :type="isBackToBack ? 'warning' : 'info'" size="small" effect="plain">
{{ isBackToBack ? "上下游项目" : "单一项目" }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="项目状态">
<el-tag :type="projectStatusTag(project.status)" size="small">
{{ projectStatusText(project.status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="负责人">{{ project.owner_user_name || "-" }}</el-descriptions-item>
<el-descriptions-item v-if="isBackToBack" label="项目毛利">
<span class="profit">¥{{ formatMoney(profitAmount) }}</span>
</el-descriptions-item>
<el-descriptions-item label="项目起止时间" :span="2">
{{ formatDateOnly(contractStart) }} ~ {{ formatDateOnly(contractEnd) }}
</el-descriptions-item>
<el-descriptions-item label="来源商机">
{{ project.business_name || (project.business_id ? `#${project.business_id}` : "-") }}
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ formatDateTime(project.create_time) }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ formatDateTime(project.update_time) }}</el-descriptions-item>
<el-descriptions-item label="项目地址" :span="2">{{ project.address || "-" }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ project.remark || "-" }}</el-descriptions-item>
</el-descriptions>
<!-- 单一项目不存在上下游概念,只展示客户信息;上下游项目则区分上游(客户侧) -->
<el-divider content-position="left">{{ isBackToBack ? "上游信息" : "客户信息" }}</el-divider>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="客户名称">{{ project.customer_name || "-" }}</el-descriptions-item>
<el-descriptions-item :label="isBackToBack ? '上游金额' : '项目金额'">
{{ formatMoney(upstreamAmount) }}
</el-descriptions-item>
<el-descriptions-item :label="isBackToBack ? '上游对接人' : '对接人'">
{{ project.upstream_contact || project.contact_person || "-" }}
</el-descriptions-item>
<el-descriptions-item :label="isBackToBack ? '上游联系电话' : '联系电话'">
{{ project.upstream_phone || project.contact_phone || "-" }}
</el-descriptions-item>
</el-descriptions>
<!-- 下游(供应商侧):仅上下游项目展示 -->
<template v-if="isBackToBack">
<el-divider content-position="left">下游信息</el-divider>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="供应商/客户">
{{ project.supplier_name || "-" }}
<el-tag v-if="Number(project.supplier_ref_type) === 1" size="small" effect="plain" type="success">客户</el-tag>
<el-tag v-else-if="Number(project.supplier_ref_type) === 2" size="small" effect="plain" type="warning">
供应商
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="下游金额">{{ formatMoney(project.downstream_amount) }}</el-descriptions-item>
<el-descriptions-item label="下游对接人">{{ project.downstream_contact || "-" }}</el-descriptions-item>
<el-descriptions-item label="下游联系电话">{{ project.downstream_phone || "-" }}</el-descriptions-item>
</el-descriptions>
</template>
</div>
</template>
<script setup>
import { computed } from "vue";
import {
projectStatusText,
projectStatusTag,
@@ -35,8 +74,46 @@ import {
formatDateOnly,
} from "../../dict";
defineProps({
const props = defineProps({
// 项目详情对象
project: { type: Object, default: null },
});
/** 是否背靠背项目:需要展示下游(供应商)信息 */
const isBackToBack = computed(() => Number(props.project?.project_type) === 2);
/** 上游金额:新字段优先,兼容存量项目仅有旧「项目金额」的情况 */
const upstreamAmount = computed(
() => Number(props.project?.upstream_amount) || Number(props.project?.amount) || 0
);
/** 项目毛利:上游金额 − 下游金额 */
const profitAmount = computed(
() => upstreamAmount.value - (Number(props.project?.downstream_amount) || 0)
);
/** 项目起止时间:由关联合同汇总(最早开始 / 最晚结束),兼容历史手工日期 */
const contractStart = computed(() => props.project?.contract_start_date || props.project?.start_date || "");
const contractEnd = computed(() => props.project?.contract_end_date || props.project?.end_date || "");
</script>
<style lang="less" scoped>
.project-basic {
padding-top:20px;
/* 首段标题紧贴容器顶部,避免多余留白 */
:deep(.el-divider:first-child) {
margin-top: 0;
}
}
.profit {
font-weight: 600;
color: var(--el-color-danger);
}
.tip {
margin-left: 6px;
font-size: 12px;
color: var(--el-text-color-secondary);
}
</style>