|
|
@@ -45,13 +45,14 @@ const projectNameSuggestions = computed<ProjectNameSuggestion[]>(() =>
|
|
|
projectNameOptions.value.map((item) => ({ value: item }))
|
|
|
)
|
|
|
|
|
|
-const hasExtProperties = computed(() => Boolean(props.extProperties?.length))
|
|
|
+const hasExtProperties = computed(() =>
|
|
|
+ Boolean(props.extProperties?.length || detailForm.value.extProperty.length)
|
|
|
+)
|
|
|
const currentPeriodExtProperties = computed(() =>
|
|
|
hasExtProperties.value
|
|
|
? detailForm.value.extProperty.filter((item) => item.defaultValue !== 'next')
|
|
|
: []
|
|
|
)
|
|
|
-
|
|
|
const nextPlanExtProperties = computed(() =>
|
|
|
hasExtProperties.value
|
|
|
? detailForm.value.extProperty.filter((item) => item.defaultValue === 'next')
|
|
|
@@ -64,15 +65,19 @@ function createDetailItem(): DetailItem {
|
|
|
projectName: '',
|
|
|
currentRevenue: undefined,
|
|
|
cumulativeRevenue: undefined,
|
|
|
+ beforeRevenue: undefined,
|
|
|
currentOnAccount: undefined,
|
|
|
cumulativeOnAccount: undefined,
|
|
|
+ beforeOnAccount: undefined,
|
|
|
currentPayment: undefined,
|
|
|
cumulativePayment: undefined,
|
|
|
+ beforePayment: undefined,
|
|
|
plannedWorkload: '',
|
|
|
actualCompletion: '',
|
|
|
equipmentUtilizationRate: undefined,
|
|
|
keyWorkCompletion: '',
|
|
|
problemsAnalysis: '',
|
|
|
+ qhse: '',
|
|
|
nextPlannedWorkload: '',
|
|
|
priorityTasks: '',
|
|
|
extProperty: cloneExtProperties(props.extProperties)
|
|
|
@@ -84,15 +89,19 @@ const cloneDetailItem = (data?: Partial<DetailItem>): DetailItem => ({
|
|
|
projectName: data?.projectName || '',
|
|
|
currentRevenue: data?.currentRevenue,
|
|
|
cumulativeRevenue: data?.cumulativeRevenue,
|
|
|
+ beforeRevenue: data?.beforeRevenue,
|
|
|
currentOnAccount: data?.currentOnAccount,
|
|
|
cumulativeOnAccount: data?.cumulativeOnAccount,
|
|
|
+ beforeOnAccount: data?.beforeOnAccount,
|
|
|
currentPayment: data?.currentPayment,
|
|
|
cumulativePayment: data?.cumulativePayment,
|
|
|
+ beforePayment: data?.beforePayment,
|
|
|
plannedWorkload: data?.plannedWorkload || '',
|
|
|
actualCompletion: data?.actualCompletion || '',
|
|
|
equipmentUtilizationRate: data?.equipmentUtilizationRate,
|
|
|
keyWorkCompletion: data?.keyWorkCompletion || '',
|
|
|
problemsAnalysis: data?.problemsAnalysis || '',
|
|
|
+ qhse: data?.qhse || '',
|
|
|
nextPlannedWorkload: data?.nextPlannedWorkload || '',
|
|
|
priorityTasks: data?.priorityTasks || '',
|
|
|
extProperty: mergeExtProperties(props.extProperties || [], data?.extProperty)
|
|
|
@@ -128,21 +137,42 @@ function normalizeExtProperty(data?: Partial<ExtPropertyItem>): ExtPropertyItem
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+function parseExtPropertyList(data?: ExtPropertyItem[] | unknown): unknown[] {
|
|
|
+ if (Array.isArray(data)) return data
|
|
|
+
|
|
|
+ if (typeof data === 'string') {
|
|
|
+ const text = data.trim()
|
|
|
+ if (!text) return []
|
|
|
+
|
|
|
+ try {
|
|
|
+ return parseExtPropertyList(JSON.parse(text))
|
|
|
+ } catch {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data && typeof data === 'object') {
|
|
|
+ const values = Object.values(data as Record<string, unknown>)
|
|
|
+
|
|
|
+ return values.every((item) => item && typeof item === 'object') ? values : []
|
|
|
+ }
|
|
|
+
|
|
|
+ return []
|
|
|
+}
|
|
|
+
|
|
|
function cloneExtProperties(data?: ExtPropertyItem[] | unknown): ExtPropertyItem[] {
|
|
|
- return Array.isArray(data)
|
|
|
- ? data
|
|
|
- .map((item) => normalizeExtProperty(item as Partial<ExtPropertyItem>))
|
|
|
- .filter((item) => item.identifier)
|
|
|
- : []
|
|
|
+ return parseExtPropertyList(data)
|
|
|
+ .map((item) => normalizeExtProperty(item as Partial<ExtPropertyItem>))
|
|
|
+ .filter((item) => item.identifier)
|
|
|
}
|
|
|
|
|
|
function mergeExtProperties(
|
|
|
defaults: ExtPropertyItem[],
|
|
|
current?: ExtPropertyItem[] | unknown
|
|
|
): ExtPropertyItem[] {
|
|
|
- if (!defaults.length) return []
|
|
|
-
|
|
|
const currentItems = cloneExtProperties(current)
|
|
|
+ if (!defaults.length) return currentItems
|
|
|
+
|
|
|
const currentMap = new Map(currentItems.map((item) => [item.identifier, item]))
|
|
|
const defaultIdentifiers = new Set(defaults.map((item) => item.identifier))
|
|
|
const mergedDefaults = defaults.map((item) => {
|
|
|
@@ -228,6 +258,7 @@ const detailRules = reactive<FormRules>({
|
|
|
equipmentUtilizationRate: getEquipmentUtilizationRateRules(),
|
|
|
keyWorkCompletion: requiredTextRule('请输入重点工作及完成情况'),
|
|
|
problemsAnalysis: requiredTextRule('请输入存在问题及分析'),
|
|
|
+ qhse: requiredTextRule('请输入设备安全管理工作'),
|
|
|
nextPlannedWorkload: requiredTextRule('请输入下期计划工作量'),
|
|
|
priorityTasks: requiredTextRule('请输入重点工作事项')
|
|
|
})
|
|
|
@@ -398,8 +429,7 @@ onMounted(() => {
|
|
|
:show-close="false"
|
|
|
header-class="mb-0! p-4!"
|
|
|
body-class="bg-gray-100"
|
|
|
- footer-class="p-4!"
|
|
|
- >
|
|
|
+ footer-class="p-4!">
|
|
|
<template #header>
|
|
|
<div class="flex items-center">
|
|
|
<span class="font-bold text-xl">{{ detailDrawerTitle }}</span>
|
|
|
@@ -414,8 +444,7 @@ onMounted(() => {
|
|
|
:rules="detailRules"
|
|
|
:disabled="type === 'view'"
|
|
|
scroll-to-error
|
|
|
- require-asterisk-position="right"
|
|
|
- >
|
|
|
+ require-asterisk-position="right">
|
|
|
<section class="detail-section">
|
|
|
<div class="detail-section__grid detail-section__grid--single">
|
|
|
<el-form-item label="项目名称" prop="projectName">
|
|
|
@@ -427,8 +456,7 @@ onMounted(() => {
|
|
|
:fetch-suggestions="queryProjectNameSearch"
|
|
|
:trigger-on-focus="true"
|
|
|
@change="handleProjectNameComplete"
|
|
|
- @select="handleProjectNameSelect"
|
|
|
- />
|
|
|
+ @select="handleProjectNameSelect" />
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
</section>
|
|
|
@@ -441,48 +469,42 @@ onMounted(() => {
|
|
|
v-model="detailForm.currentRevenue"
|
|
|
class="w-full!"
|
|
|
:controls="false"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ :precision="2" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="收入-累计" prop="cumulativeRevenue">
|
|
|
<el-input-number
|
|
|
v-model="detailForm.cumulativeRevenue"
|
|
|
class="w-full!"
|
|
|
:controls="false"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ :precision="2" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="挂帐-本期" prop="currentOnAccount">
|
|
|
<el-input-number
|
|
|
v-model="detailForm.currentOnAccount"
|
|
|
class="w-full!"
|
|
|
:controls="false"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ :precision="2" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="挂帐-累计" prop="cumulativeOnAccount">
|
|
|
<el-input-number
|
|
|
v-model="detailForm.cumulativeOnAccount"
|
|
|
class="w-full!"
|
|
|
:controls="false"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ :precision="2" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="回款-本期" prop="currentPayment">
|
|
|
<el-input-number
|
|
|
v-model="detailForm.currentPayment"
|
|
|
class="w-full!"
|
|
|
:controls="false"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ :precision="2" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="回款-累计" prop="cumulativePayment">
|
|
|
<el-input-number
|
|
|
v-model="detailForm.cumulativePayment"
|
|
|
class="w-full!"
|
|
|
:controls="false"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ :precision="2" />
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
</section>
|
|
|
@@ -496,8 +518,7 @@ onMounted(() => {
|
|
|
:key="item.identifier"
|
|
|
:label="getExtPropertyLabel(item)"
|
|
|
:prop="getExtPropertyProp(item)"
|
|
|
- :rules="getExtPropertyRules(item)"
|
|
|
- >
|
|
|
+ :rules="getExtPropertyRules(item)">
|
|
|
<el-input-number
|
|
|
v-if="isDoubleExtProperty(item)"
|
|
|
v-model="item.actualValue"
|
|
|
@@ -505,15 +526,13 @@ onMounted(() => {
|
|
|
:controls="false"
|
|
|
:precision="2"
|
|
|
:min="getExtPropertyNumberBoundary(item.minValue)"
|
|
|
- :max="getExtPropertyNumberBoundary(item.maxValue)"
|
|
|
- />
|
|
|
+ :max="getExtPropertyNumberBoundary(item.maxValue)" />
|
|
|
<el-input
|
|
|
v-else
|
|
|
v-model="item.actualValue"
|
|
|
type="textarea"
|
|
|
:rows="3"
|
|
|
- :placeholder="`请输入${item.name}`"
|
|
|
- />
|
|
|
+ :placeholder="`请输入${item.name}`" />
|
|
|
</el-form-item>
|
|
|
</template>
|
|
|
<template v-else>
|
|
|
@@ -522,24 +541,21 @@ onMounted(() => {
|
|
|
v-model="detailForm.plannedWorkload"
|
|
|
type="textarea"
|
|
|
:rows="3"
|
|
|
- placeholder="请输入计划工作量"
|
|
|
- />
|
|
|
+ placeholder="请输入计划工作量" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="实际完成" prop="actualCompletion">
|
|
|
<el-input
|
|
|
v-model="detailForm.actualCompletion"
|
|
|
type="textarea"
|
|
|
:rows="3"
|
|
|
- placeholder="请输入实际完成"
|
|
|
- />
|
|
|
+ placeholder="请输入实际完成" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="设备利用率(%)" prop="equipmentUtilizationRate">
|
|
|
<el-input-number
|
|
|
v-model="detailForm.equipmentUtilizationRate"
|
|
|
class="w-full!"
|
|
|
:controls="false"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ :precision="2" />
|
|
|
</el-form-item>
|
|
|
</template>
|
|
|
</div>
|
|
|
@@ -553,16 +569,21 @@ onMounted(() => {
|
|
|
v-model="detailForm.keyWorkCompletion"
|
|
|
type="textarea"
|
|
|
:rows="4"
|
|
|
- placeholder="请输入重点工作及完成情况"
|
|
|
- />
|
|
|
+ placeholder="请输入重点工作及完成情况" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="存在问题及分析" prop="problemsAnalysis">
|
|
|
<el-input
|
|
|
v-model="detailForm.problemsAnalysis"
|
|
|
type="textarea"
|
|
|
:rows="4"
|
|
|
- placeholder="请输入存在问题及分析"
|
|
|
- />
|
|
|
+ placeholder="请输入存在问题及分析" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="设备安全管理工作" prop="qhse">
|
|
|
+ <el-input
|
|
|
+ v-model="detailForm.qhse"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入设备安全管理工作" />
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
</section>
|
|
|
@@ -575,24 +596,21 @@ onMounted(() => {
|
|
|
v-model="detailForm.nextPlannedWorkload"
|
|
|
type="textarea"
|
|
|
:rows="4"
|
|
|
- placeholder="请输入下期计划工作量"
|
|
|
- />
|
|
|
+ placeholder="请输入下期计划工作量" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="重点工作事项" prop="priorityTasks">
|
|
|
<el-input
|
|
|
v-model="detailForm.priorityTasks"
|
|
|
type="textarea"
|
|
|
:rows="4"
|
|
|
- placeholder="请输入重点工作事项"
|
|
|
- />
|
|
|
+ placeholder="请输入重点工作事项" />
|
|
|
</el-form-item>
|
|
|
<el-form-item
|
|
|
v-for="item in nextPlanExtProperties"
|
|
|
:key="item.identifier"
|
|
|
:label="getExtPropertyLabel(item)"
|
|
|
:prop="getExtPropertyProp(item)"
|
|
|
- :rules="getExtPropertyRules(item)"
|
|
|
- >
|
|
|
+ :rules="getExtPropertyRules(item)">
|
|
|
<el-input-number
|
|
|
v-if="isDoubleExtProperty(item)"
|
|
|
v-model="item.actualValue"
|
|
|
@@ -600,15 +618,13 @@ onMounted(() => {
|
|
|
:controls="false"
|
|
|
:precision="2"
|
|
|
:min="getExtPropertyNumberBoundary(item.minValue)"
|
|
|
- :max="getExtPropertyNumberBoundary(item.maxValue)"
|
|
|
- />
|
|
|
+ :max="getExtPropertyNumberBoundary(item.maxValue)" />
|
|
|
<el-input
|
|
|
v-else
|
|
|
v-model="item.actualValue"
|
|
|
type="textarea"
|
|
|
:rows="4"
|
|
|
- :placeholder="`请输入${item.name}`"
|
|
|
- />
|
|
|
+ :placeholder="`请输入${item.name}`" />
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
</section>
|