2026-03-24 17:12:13 +08:00

170 lines
5.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<TypeLine
scene="zxfw-pricing-tab"
:title="`${contractName ? `合同段:${contractName} · ` : ''}${fwName}计算`"
:subtitle="`合同ID${contractId}`"
:copy-text="contractId"
:storage-key="`zxfw-pricing-active-cat-${contractId}-${serviceId}`"
:default-category="defaultCategory"
:categories="pricingCategories"
/>
</template>
<script setup lang="ts">
import { computed, defineAsyncComponent, defineComponent, h, markRaw, type Component } from 'vue'
import TypeLine from '@/layout/typeLine.vue'
import MethodUnavailableNotice from '@/features/shared/components/MethodUnavailableNotice.vue'
interface ServiceMethodType {
scale?: boolean | null
onlyCostScale?: boolean | null
amount?: boolean | null
workDay?: boolean | null
}
const props = defineProps<{
contractId: string
contractName?: string
serviceId: string|number
fwName:string
type?: ServiceMethodType
projectInfoKey?: string
}>()
interface PricingCategoryItem {
key: string
label: string
component: Component
}
const resolveMethodEnabled = (value: boolean | null | undefined, fallback = true) =>
typeof value === 'boolean' ? value : fallback
const methodAvailability = computed(() => {
const scale = resolveMethodEnabled(props.type?.scale, true)
const onlyCostScale = resolveMethodEnabled(props.type?.onlyCostScale, false)
const amount = resolveMethodEnabled(props.type?.amount, true)
const workDay = resolveMethodEnabled(props.type?.workDay, true)
return {
investmentScale: scale,
landScale: scale && !onlyCostScale,
workload: amount,
hourly: workDay
}
})
const createPricingPane = (name: string) =>
markRaw(
defineComponent({
name,
setup() {
const AsyncPricingView = defineAsyncComponent({
loader: () => import(`@/features/pricing/components/${name}.vue`),
onError: err => {
console.error('加载 PricingMethodView 组件失败:', err)
}
})
return () => h(AsyncPricingView, {
contractId: props.contractId,
serviceId: props.serviceId,
projectInfoKey: props.projectInfoKey
})
}
})
)
const createMethodUnavailablePane = (title: string, message: string) =>
markRaw(
defineComponent({
name: 'MethodUnavailablePane',
setup() {
return () => h(MethodUnavailableNotice, { title, message })
}
})
)
const investmentScaleView = createPricingPane('InvestmentScalePricingPane')
const landScaleView = createPricingPane('LandScalePricingPane')
const workloadView = createPricingPane('WorkloadPricingPane')
const hourlyView = createPricingPane('HourlyPricingPane')
const workContentPane = markRaw(
defineComponent({
name: 'WorkContentPane',
setup() {
const AsyncWorkContentGrid = defineAsyncComponent({
loader: () => import('@/features/shared/components/WorkContentGrid.vue'),
onError: err => {
console.error('加载 WorkContentGrid 组件失败:', err)
}
})
return () => h(AsyncWorkContentGrid, {
title: '工作内容',
storageKey: `work-content-${props.contractId}-${props.serviceId}`,
contractId: props.contractId,
projectInfoKey: props.projectInfoKey,
serviceId: props.serviceId,
dictMode: 'service'
})
}
})
)
const investmentScaleUnavailableView = createMethodUnavailablePane(
'该服务不适用投资规模法',
'当前服务未启用规模法,投资规模法不可编辑。'
)
const landScaleUnavailableView = createMethodUnavailablePane(
'该服务不适用用地规模法',
'当前服务仅支持投资规模法,用地规模法不可编辑。'
)
const workloadUnavailableView = createMethodUnavailablePane(
'该服务不适用工作量法',
'当前服务未启用工作量法,工作量法不可编辑。'
)
const hourlyUnavailableView = createMethodUnavailablePane(
'该服务不适用工时法',
'当前服务未启用工时法,工时法不可编辑。'
)
const pricingCategories = computed<PricingCategoryItem[]>(() => [
{
key: 'investment-scale-method',
label: '投资规模法',
component: methodAvailability.value.investmentScale ? investmentScaleView : investmentScaleUnavailableView
},
{
key: 'land-scale-method',
label: '用地规模法',
component: methodAvailability.value.landScale ? landScaleView : landScaleUnavailableView
},
{
key: 'workload-method',
label: '工作量法',
component: methodAvailability.value.workload ? workloadView : workloadUnavailableView
},
{
key: 'hourly-method',
label: '工时法',
component: methodAvailability.value.hourly ? hourlyView : hourlyUnavailableView
},
{
key: 'work-content',
label: '工作内容',
component: workContentPane
},
])
const defaultCategory = computed(() => {
const m = methodAvailability.value
if (m.investmentScale) return 'investment-scale-method'
if (m.landScale) return 'land-scale-method'
if (m.workload) return 'workload-method'
if (m.hourly) return 'hourly-method'
return 'work-content'
})
</script>