149 lines
6.6 KiB
Vue
149 lines
6.6 KiB
Vue
<template>
|
||
<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="projectTypeTag(project.project_type)" size="small" effect="plain">
|
||
{{ projectTypeText(project.project_type) }}
|
||
</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">{{ hasCounterparty ? "上游信息" : "客户信息" }}</el-divider>
|
||
<el-descriptions :column="2" border size="small">
|
||
<el-descriptions-item :label="hasCounterparty ? '上游客户' : '客户名称'">
|
||
{{ project.customer_name || "-" }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item :label="hasCounterparty ? '上游金额' : '项目金额'">
|
||
{{ formatMoney(upstreamAmount) }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item :label="hasCounterparty ? '上游对接人' : '对接人'">
|
||
{{ project.upstream_contact || project.contact_person || "-" }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item :label="hasCounterparty ? '上游联系电话' : '联系电话'">
|
||
{{ project.upstream_phone || project.contact_phone || "-" }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<!-- 对方主体(上下游的下游供应商 / 上中游的中游中间方):仅这两类项目展示 -->
|
||
<template v-if="hasCounterparty">
|
||
<el-divider content-position="left">{{ counterpartyLabel }}信息</el-divider>
|
||
<el-descriptions :column="2" border size="small">
|
||
<el-descriptions-item :label="isUpMid ? '中游企业' : '供应商/客户'">
|
||
{{ 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="`${counterpartyLabel}金额`">
|
||
{{ formatMoney(project.downstream_amount) }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item :label="`${counterpartyLabel}对接人`">
|
||
{{ project.downstream_contact || "-" }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item :label="`${counterpartyLabel}联系电话`">
|
||
{{ project.downstream_phone || "-" }}
|
||
</el-descriptions-item>
|
||
<!-- 上中游项目:下游固定为本公司 -->
|
||
<el-descriptions-item v-if="isUpMid" label="下游(本公司)" :span="2">
|
||
{{ ownCompanyName }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</template>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed } from "vue";
|
||
import { useAuthStore } from "@/stores/auth";
|
||
import {
|
||
projectStatusText,
|
||
projectStatusTag,
|
||
projectTypeText,
|
||
projectTypeTag,
|
||
formatDateTime,
|
||
formatMoney,
|
||
formatDateOnly,
|
||
} from "../../dict";
|
||
|
||
const props = defineProps({
|
||
// 项目详情对象
|
||
project: { type: Object, default: null },
|
||
});
|
||
|
||
const authStore = useAuthStore();
|
||
|
||
/** 是否背靠背项目:需要展示下游(供应商)信息 */
|
||
const isBackToBack = computed(() => Number(props.project?.project_type) === 2);
|
||
|
||
/** 是否上中游项目:上游 A 公司 + 中游 B 公司,下游固定为本公司 */
|
||
const isUpMid = computed(() => Number(props.project?.project_type) === 3);
|
||
|
||
/** 是否需要展示「对方主体」(上下游的下游 / 上中游的中游) */
|
||
const hasCounterparty = computed(() => isBackToBack.value || isUpMid.value);
|
||
|
||
/** 对方主体称谓:上下游项目叫「下游」,上中游项目叫「中游」 */
|
||
const counterpartyLabel = computed(() => (isUpMid.value ? "中游" : "下游"));
|
||
|
||
/** 本公司名称:上中游项目的下游固定为本公司 */
|
||
const ownCompanyName = computed(() => authStore.user?.tenant_name || "本公司");
|
||
|
||
/** 上游金额:新字段优先,兼容存量项目仅有旧「项目金额」的情况 */
|
||
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>
|