|
|
@@ -1,5 +1,6 @@
|
|
|
<script lang="ts" setup>
|
|
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
|
+import type { CSSProperties } from 'vue'
|
|
|
import type { DeptOption, DetailItem, OperationMeeting } from './types'
|
|
|
import { OperationMeetingApi } from '@/api/pms/meeting'
|
|
|
import { useTableComponents } from '@/components/ZmTable/useTableComponents'
|
|
|
@@ -12,15 +13,6 @@ interface Props {
|
|
|
deptOptions?: DeptOption[]
|
|
|
}
|
|
|
|
|
|
-interface SummaryColumn {
|
|
|
- property?: string
|
|
|
-}
|
|
|
-
|
|
|
-interface DetailSummaryMethodProps {
|
|
|
- columns: SummaryColumn[]
|
|
|
- data: DetailItem[]
|
|
|
-}
|
|
|
-
|
|
|
interface OperationMeetingForm
|
|
|
extends Omit<Partial<OperationMeeting>, 'meetingDate' | 'meetingSeries'> {
|
|
|
meetingDate?: number | string | Date
|
|
|
@@ -52,7 +44,7 @@ const drawerTitle = computed(() =>
|
|
|
)
|
|
|
|
|
|
const isMobile = computed(() => width.value <= 768)
|
|
|
-const drawerSize = computed(() => (isMobile.value ? '100%' : '92.2%'))
|
|
|
+const drawerSize = computed(() => (isMobile.value ? '100%' : '100%'))
|
|
|
const detailDrawerSize = computed(() => (isMobile.value ? '100%' : '50%'))
|
|
|
|
|
|
const companyDisplayName = computed(() => {
|
|
|
@@ -211,6 +203,13 @@ const detailCardGroups: { title: string; fields: DetailCardField[] }[] = [
|
|
|
}
|
|
|
]
|
|
|
|
|
|
+const meetingTableBlueColumns = new Set<keyof DetailItem>([
|
|
|
+ 'projectName',
|
|
|
+ 'actualCompletion',
|
|
|
+ 'keyWorkCompletion',
|
|
|
+ 'problemsAnalysis'
|
|
|
+])
|
|
|
+
|
|
|
const requiredTextRule = (message: string) => [
|
|
|
{
|
|
|
required: true,
|
|
|
@@ -355,28 +354,14 @@ const formatDetailCardValue = (item: DetailItem, field: DetailCardField) => {
|
|
|
return `${formatSummaryNumber(numericValue)}${field.unit || ''}`
|
|
|
}
|
|
|
|
|
|
-const getDetailSummaries = ({ columns, data }: DetailSummaryMethodProps) => {
|
|
|
- const sums: string[] = []
|
|
|
-
|
|
|
- columns.forEach((column, index) => {
|
|
|
- if (index === 0) {
|
|
|
- sums[index] = '公司整体'
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (!column.property || !detailSummaryFields.includes(column.property as DetailSummaryField)) {
|
|
|
- sums[index] = ''
|
|
|
- return
|
|
|
- }
|
|
|
+const getMeetingTableCellStyle: any = ({ column }): CSSProperties | undefined => {
|
|
|
+ const property = column.property as keyof DetailItem | undefined
|
|
|
|
|
|
- const total = data.reduce(
|
|
|
- (sum, item) => sum + Number(item[column.property as keyof DetailItem] || 0),
|
|
|
- 0
|
|
|
- )
|
|
|
- sums[index] = formatSummaryNumber(total)
|
|
|
- })
|
|
|
+ if (property && meetingTableBlueColumns.has(property)) {
|
|
|
+ return { color: '#1b71f6' }
|
|
|
+ }
|
|
|
|
|
|
- return sums
|
|
|
+ return undefined
|
|
|
}
|
|
|
|
|
|
const handleAddDetailItem = () => {
|
|
|
@@ -660,8 +645,10 @@ onMounted(() => {
|
|
|
require-asterisk-position="right"
|
|
|
:disabled="type === 'view'"
|
|
|
>
|
|
|
- <section class="p-6 bg-white border-solid border-1 border-gray-200/90 rounded-xl mb-6">
|
|
|
- <h3 class="text-lg font-bold mb-4">会议信息</h3>
|
|
|
+ <section
|
|
|
+ class="meeting-info-section bg-white border-solid border-1 border-gray-200/90 rounded-xl mb-4"
|
|
|
+ >
|
|
|
+ <h3 class="meeting-info-section__title">会议信息</h3>
|
|
|
|
|
|
<div class="meeting-section__grid">
|
|
|
<el-form-item label="所属公司" class="meeting-form-item mb-0! min-w-0">
|
|
|
@@ -699,18 +686,22 @@ onMounted(() => {
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
|
|
|
- <el-form-item
|
|
|
- label="需集团协调支持的事项"
|
|
|
- prop="support"
|
|
|
- class="meeting-form-item meeting-section__grid-full mb-0! min-w-0"
|
|
|
- >
|
|
|
- <el-input
|
|
|
- v-model="operationMeeting.support"
|
|
|
- type="textarea"
|
|
|
- :rows="4"
|
|
|
- placeholder="请输入需集团协调支持的事项"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
+ <section class="meeting-summary-strip meeting-section__grid-full">
|
|
|
+ <div class="meeting-summary-strip__title">
|
|
|
+ <span>公司整体</span>
|
|
|
+ <small>经营数据汇总</small>
|
|
|
+ </div>
|
|
|
+ <div class="meeting-summary-strip__grid">
|
|
|
+ <div
|
|
|
+ v-for="item in detailSummaryCards"
|
|
|
+ :key="item.label"
|
|
|
+ class="meeting-summary-strip__item"
|
|
|
+ >
|
|
|
+ <span>{{ item.label }}</span>
|
|
|
+ <strong>{{ item.value }}<em>万元</em></strong>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
</div>
|
|
|
</section>
|
|
|
<section class="p-6 bg-white border-solid border-1 border-gray-200/90 rounded-xl">
|
|
|
@@ -723,29 +714,20 @@ onMounted(() => {
|
|
|
</div>
|
|
|
<div class="meeting-detail-table-view">
|
|
|
<ZmTable
|
|
|
+ class="meeting-table"
|
|
|
:data="detailItems"
|
|
|
:loading="loading"
|
|
|
- show-summary
|
|
|
- :summary-method="getDetailSummaries"
|
|
|
+ :max-height="660"
|
|
|
+ align="left"
|
|
|
+ :show-overflow-tooltip="false"
|
|
|
+ :cell-style="getMeetingTableCellStyle"
|
|
|
>
|
|
|
- <zm-table-column width="120" label="项目名称" prop="projectName" />
|
|
|
- <zm-table-column label="收入(万元)">
|
|
|
- <zm-table-column label="本期" prop="currentRevenue" />
|
|
|
- <zm-table-column label="累计" prop="cumulativeRevenue" />
|
|
|
- </zm-table-column>
|
|
|
- <zm-table-column label="挂帐(万元)">
|
|
|
- <zm-table-column label="本期" prop="currentOnAccount" />
|
|
|
- <zm-table-column label="累计" prop="cumulativeOnAccount" />
|
|
|
- </zm-table-column>
|
|
|
- <zm-table-column label="回款(万元)">
|
|
|
- <zm-table-column label="本期" prop="currentPayment" />
|
|
|
- <zm-table-column label="累计" prop="cumulativePayment" />
|
|
|
- </zm-table-column>
|
|
|
+ <zm-table-column width="156" align="center" label="项目名称" prop="projectName" />
|
|
|
<zm-table-column label="本期生产运行情况">
|
|
|
- <zm-table-column width="100" label="计划工作量" prop="plannedWorkload" />
|
|
|
- <zm-table-column width="100" label="实际完成" prop="actualCompletion" />
|
|
|
+ <zm-table-column width="120" label="计划工作量" prop="plannedWorkload" />
|
|
|
+ <zm-table-column width="120" label="实际完成" prop="actualCompletion" />
|
|
|
<zm-table-column
|
|
|
- width="88"
|
|
|
+ width="120"
|
|
|
label="设备利用率"
|
|
|
prop="equipmentUtilizationRate"
|
|
|
:formatter="(row) => `${row.equipmentUtilizationRate}%`"
|
|
|
@@ -753,17 +735,17 @@ onMounted(() => {
|
|
|
</zm-table-column>
|
|
|
<zm-table-column label="生产管理情况及重点工作 ">
|
|
|
<zm-table-column label="重点工作及完成情况" prop="keyWorkCompletion" />
|
|
|
- <zm-table-column label="存在问题及分析" prop="problemsAnalysis" />
|
|
|
+ <zm-table-column width="300" label="存在问题及分析" prop="problemsAnalysis" />
|
|
|
</zm-table-column>
|
|
|
<zm-table-column label="下期工作计划 ">
|
|
|
- <zm-table-column width="100" label="计划工作量" prop="nextPlannedWorkload" />
|
|
|
+ <zm-table-column width="120" label="计划工作量" prop="nextPlannedWorkload" />
|
|
|
<zm-table-column label="重点工作事项" prop="priorityTasks" />
|
|
|
</zm-table-column>
|
|
|
- <zm-table-column label="操作" width="120" fixed="right">
|
|
|
+ <zm-table-column label="操作" width="140" fixed="right">
|
|
|
<template #default="{ row, $index }">
|
|
|
<el-button
|
|
|
link
|
|
|
- size="small"
|
|
|
+ size="default"
|
|
|
type="primary"
|
|
|
@click="handleEditDetailItem(row, $index)"
|
|
|
>
|
|
|
@@ -772,7 +754,7 @@ onMounted(() => {
|
|
|
<el-button
|
|
|
v-if="type !== 'view'"
|
|
|
link
|
|
|
- size="small"
|
|
|
+ size="default"
|
|
|
type="danger"
|
|
|
@click="handleDeleteDetailItem($index)"
|
|
|
>
|
|
|
@@ -832,23 +814,24 @@ onMounted(() => {
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</article>
|
|
|
-
|
|
|
- <section class="meeting-detail-summary-card">
|
|
|
- <div class="meeting-detail-summary-card__title">公司整体</div>
|
|
|
- <div class="meeting-detail-summary-card__grid">
|
|
|
- <div
|
|
|
- v-for="item in detailSummaryCards"
|
|
|
- :key="item.label"
|
|
|
- class="meeting-detail-summary-card__item"
|
|
|
- >
|
|
|
- <span>{{ item.label }}</span>
|
|
|
- <strong>{{ item.value }}万元</strong>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </section>
|
|
|
</template>
|
|
|
<el-empty v-else description="暂无会议明细" :image-size="80" />
|
|
|
</div>
|
|
|
+
|
|
|
+ <section class="meeting-support-panel">
|
|
|
+ <el-form-item
|
|
|
+ label="需集团协调支持的事项"
|
|
|
+ prop="support"
|
|
|
+ class="meeting-form-item mb-0! min-w-0"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="operationMeeting.support"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入需集团协调支持的事项"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </section>
|
|
|
</section>
|
|
|
</el-form>
|
|
|
|
|
|
@@ -1053,13 +1036,136 @@ onMounted(() => {
|
|
|
.meeting-section__grid {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
- gap: 32px;
|
|
|
+ gap: 10px 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-info-section {
|
|
|
+ padding: 10px 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-info-section__title {
|
|
|
+ margin: 0 0 8px;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 800;
|
|
|
+ line-height: 20px;
|
|
|
+ color: #1f2937;
|
|
|
}
|
|
|
|
|
|
.meeting-section__grid-full {
|
|
|
grid-column: 1 / -1;
|
|
|
}
|
|
|
|
|
|
+.meeting-summary-strip {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 112px minmax(0, 1fr);
|
|
|
+ gap: 8px;
|
|
|
+ align-items: stretch;
|
|
|
+ padding: 6px 8px;
|
|
|
+ background: linear-gradient(180deg, #f8fbff 0%, #fff 100%);
|
|
|
+ border: 1px solid #dbeafe;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-summary-strip__title {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ padding-right: 8px;
|
|
|
+ border-right: 1px solid #dbeafe;
|
|
|
+
|
|
|
+ span {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 800;
|
|
|
+ line-height: 20px;
|
|
|
+ color: #1f2937;
|
|
|
+ }
|
|
|
+
|
|
|
+ small {
|
|
|
+ margin-top: 0;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 16px;
|
|
|
+ color: #64748b;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-summary-strip__grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
|
+ gap: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-summary-strip__item {
|
|
|
+ display: flex;
|
|
|
+ min-width: 0;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 4px 6px;
|
|
|
+ background: rgb(255 255 255 / 72%);
|
|
|
+ border: 1px solid rgb(219 234 254 / 70%);
|
|
|
+ border-radius: 7px;
|
|
|
+
|
|
|
+ span {
|
|
|
+ display: block;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 16px;
|
|
|
+ color: #64748b;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ strong {
|
|
|
+ display: flex;
|
|
|
+ min-width: 0;
|
|
|
+ flex-shrink: 0;
|
|
|
+ align-items: baseline;
|
|
|
+ gap: 3px;
|
|
|
+ margin-top: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 800;
|
|
|
+ line-height: 18px;
|
|
|
+ color: #1b71f6;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ em {
|
|
|
+ font-size: 12px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #64748b;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-table {
|
|
|
+ --zm-table-font-size: 18px;
|
|
|
+ --zm-table-header-font-size: 18px;
|
|
|
+ --zm-table-header-font-weight: 800;
|
|
|
+ --zm-table-row-font-weight: 800;
|
|
|
+ --zm-table-header-text-color: #333;
|
|
|
+ --zm-table-border-color: #cbd5e1;
|
|
|
+ --zm-table-header-border-color: #c2ccda;
|
|
|
+ --zm-table-row-border-color: #d4dce8;
|
|
|
+
|
|
|
+ :deep(.header-wrapper) {
|
|
|
+ height: 20px;
|
|
|
+
|
|
|
+ .truncate {
|
|
|
+ height: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-support-panel {
|
|
|
+ padding-top: 18px;
|
|
|
+ margin-top: 18px;
|
|
|
+ border-top: 1px solid var(--el-border-color-lighter);
|
|
|
+}
|
|
|
+
|
|
|
.meeting-form-tip {
|
|
|
margin-top: 6px;
|
|
|
font-size: 12px;
|
|
|
@@ -1132,8 +1238,7 @@ onMounted(() => {
|
|
|
}
|
|
|
|
|
|
.meeting-detail-card__title span,
|
|
|
-.meeting-detail-card__field span,
|
|
|
-.meeting-detail-summary-card__item span {
|
|
|
+.meeting-detail-card__field span {
|
|
|
font-size: 12px;
|
|
|
line-height: 1.4;
|
|
|
color: var(--el-text-color-secondary);
|
|
|
@@ -1160,23 +1265,20 @@ onMounted(() => {
|
|
|
color: var(--el-text-color-primary);
|
|
|
}
|
|
|
|
|
|
-.meeting-detail-card__fields,
|
|
|
-.meeting-detail-summary-card__grid {
|
|
|
+.meeting-detail-card__fields {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
gap: 10px 12px;
|
|
|
}
|
|
|
|
|
|
-.meeting-detail-card__field,
|
|
|
-.meeting-detail-summary-card__item {
|
|
|
+.meeting-detail-card__field {
|
|
|
display: flex;
|
|
|
min-width: 0;
|
|
|
flex-direction: column;
|
|
|
gap: 4px;
|
|
|
}
|
|
|
|
|
|
-.meeting-detail-card__field strong,
|
|
|
-.meeting-detail-summary-card__item strong {
|
|
|
+.meeting-detail-card__field strong {
|
|
|
min-width: 0;
|
|
|
font-size: 13px;
|
|
|
font-weight: 600;
|
|
|
@@ -1192,25 +1294,26 @@ onMounted(() => {
|
|
|
border-top: 1px solid var(--el-border-color-lighter);
|
|
|
}
|
|
|
|
|
|
-.meeting-detail-summary-card {
|
|
|
- padding: 14px;
|
|
|
- background: var(--el-fill-color-lighter);
|
|
|
- border: 1px solid var(--el-border-color-lighter);
|
|
|
- border-radius: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.meeting-detail-summary-card__title {
|
|
|
- margin-bottom: 10px;
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 700;
|
|
|
- color: var(--el-text-color-primary);
|
|
|
-}
|
|
|
-
|
|
|
@media (width <= 960px) {
|
|
|
.meeting-section__grid {
|
|
|
grid-template-columns: 1fr;
|
|
|
}
|
|
|
|
|
|
+ .meeting-summary-strip {
|
|
|
+ grid-template-columns: 1fr;
|
|
|
+ }
|
|
|
+
|
|
|
+ .meeting-summary-strip__title {
|
|
|
+ padding-right: 0;
|
|
|
+ padding-bottom: 12px;
|
|
|
+ border-right: 0;
|
|
|
+ border-bottom: 1px solid #dbeafe;
|
|
|
+ }
|
|
|
+
|
|
|
+ .meeting-summary-strip__grid {
|
|
|
+ grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
+ }
|
|
|
+
|
|
|
.detail-section__grid {
|
|
|
grid-template-columns: 1fr;
|
|
|
}
|
|
|
@@ -1232,8 +1335,8 @@ onMounted(() => {
|
|
|
gap: 12px;
|
|
|
}
|
|
|
|
|
|
- .meeting-detail-card__fields,
|
|
|
- .meeting-detail-summary-card__grid {
|
|
|
+ .meeting-summary-strip__grid,
|
|
|
+ .meeting-detail-card__fields {
|
|
|
grid-template-columns: 1fr;
|
|
|
}
|
|
|
}
|