|
|
@@ -15,6 +15,7 @@ interface Props {
|
|
|
type: 'create' | 'edit' | 'view'
|
|
|
deptOptions?: DeptOption[]
|
|
|
loading?: boolean
|
|
|
+ showMeetingMeta?: boolean
|
|
|
}
|
|
|
|
|
|
interface DetailCardField {
|
|
|
@@ -32,7 +33,8 @@ interface MeetingTableCellStyleProps {
|
|
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
deptOptions: () => [],
|
|
|
- loading: false
|
|
|
+ loading: false,
|
|
|
+ showMeetingMeta: true
|
|
|
})
|
|
|
|
|
|
const emits = defineEmits<{
|
|
|
@@ -73,6 +75,15 @@ const detailSummaryToneMap: Record<DetailSummaryField, 'revenue' | 'account' | '
|
|
|
cumulativePayment: 'payment'
|
|
|
}
|
|
|
|
|
|
+const detailSummaryIconMap: Record<DetailSummaryField, string> = {
|
|
|
+ currentRevenue: 'i-lucide:badge-japanese-yen',
|
|
|
+ cumulativeRevenue: 'i-lucide:badge-japanese-yen',
|
|
|
+ currentOnAccount: 'i-lucide:badge-alert',
|
|
|
+ cumulativeOnAccount: 'i-lucide:badge-alert',
|
|
|
+ currentPayment: 'i-lucide:badge-check',
|
|
|
+ cumulativePayment: 'i-lucide:badge-check'
|
|
|
+}
|
|
|
+
|
|
|
const detailCardGroups: { title: string; fields: DetailCardField[] }[] = [
|
|
|
{
|
|
|
title: '经营情况',
|
|
|
@@ -156,10 +167,13 @@ const detailSummaryCards = computed(() =>
|
|
|
detailSummaryFields.map((field) => ({
|
|
|
label: detailSummaryLabelMap[field],
|
|
|
value: formatSummaryNumber(getDetailSummaryTotal(field)),
|
|
|
- tone: detailSummaryToneMap[field]
|
|
|
+ tone: detailSummaryToneMap[field],
|
|
|
+ icon: detailSummaryIconMap[field]
|
|
|
}))
|
|
|
)
|
|
|
|
|
|
+const showMeetingMetaFields = computed(() => props.type !== 'view' || props.showMeetingMeta)
|
|
|
+
|
|
|
const formatDetailCardValue = (item: DetailItem, field: DetailCardField) => {
|
|
|
const value = item[field.prop]
|
|
|
|
|
|
@@ -196,12 +210,18 @@ const visible = ref(false)
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <section class="py-2.5 px-4 bg-white border-solid border-1 border-gray-200/90 rounded-xl mb-4">
|
|
|
+ <section class="p-2 bg-white border-solid border-1 border-gray-200/90 rounded-xl">
|
|
|
<div class="meeting-section__top">
|
|
|
<h2 class="meeting-section__title">生产运营双周例会汇报</h2>
|
|
|
|
|
|
- <div class="meeting-section__grid">
|
|
|
+ <div
|
|
|
+ :class="[
|
|
|
+ 'meeting-section__grid',
|
|
|
+ { 'meeting-section__grid--company-only': !showMeetingMetaFields }
|
|
|
+ ]"
|
|
|
+ >
|
|
|
<el-form-item
|
|
|
+ v-if="showMeetingMetaFields"
|
|
|
label="会议期次"
|
|
|
label-position="left"
|
|
|
prop="meetingSeries"
|
|
|
@@ -232,6 +252,7 @@ const visible = ref(false)
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item
|
|
|
+ v-if="showMeetingMetaFields"
|
|
|
label="会议日期"
|
|
|
label-position="left"
|
|
|
prop="meetingDate"
|
|
|
@@ -259,130 +280,140 @@ const visible = ref(false)
|
|
|
:key="item.label"
|
|
|
:class="['meeting-summary-strip__item', `meeting-summary-strip__item--${item.tone}`]"
|
|
|
>
|
|
|
- <div class="i-mingcute:currency-cny-2-fill size-4 icon"></div>
|
|
|
+ <div :class="item.icon + ' size-5 icon'"></div>
|
|
|
<span>{{ item.label }}</span>
|
|
|
<strong>{{ item.value }}<em>万元</em></strong>
|
|
|
</div>
|
|
|
</div>
|
|
|
</section>
|
|
|
- </section>
|
|
|
|
|
|
- <section class="p-2 bg-white border-solid border-1 border-gray-200/90 rounded-xl">
|
|
|
- <el-button class="mb-2" size="default" link @click="() => (visible = !visible)">
|
|
|
- <div class="flex items-center gap-1">
|
|
|
- <div class="i-lucide:chevron-right size-4"></div>
|
|
|
- <!-- {{ visible ? '收起' : '展开' }} -->
|
|
|
- </div>
|
|
|
- </el-button>
|
|
|
- <div v-show="visible" class="flex items-center justify-between gap-4 mb-4">
|
|
|
- <h3 class="text-lg font-bold m-0">会议明细</h3>
|
|
|
- <el-button v-if="type !== 'view'" type="primary" @click="emits('add-detail')">
|
|
|
- <Icon icon="ep:plus" class="mr-5px" />
|
|
|
- 新增一行
|
|
|
+ <section class="meeting-detail-panel">
|
|
|
+ <el-button class="mb-2" size="default" link @click="() => (visible = !visible)">
|
|
|
+ <div class="flex items-center gap-1">
|
|
|
+ <div
|
|
|
+ :class="[
|
|
|
+ 'i-lucide:chevron-right size-4 meeting-detail-toggle__icon',
|
|
|
+ { 'meeting-detail-toggle__icon--expanded': visible }
|
|
|
+ ]"
|
|
|
+ ></div>
|
|
|
+ <!-- {{ visible ? '收起' : '展开' }} -->
|
|
|
+ </div>
|
|
|
</el-button>
|
|
|
- </div>
|
|
|
- <div class="meeting-detail-table-view">
|
|
|
- <ZmTable
|
|
|
- class="meeting-table"
|
|
|
- :data="details"
|
|
|
- :loading="loading"
|
|
|
- :max-height="660"
|
|
|
- align="left"
|
|
|
- :show-overflow-tooltip="false"
|
|
|
- :cell-style="getMeetingTableCellStyle"
|
|
|
- >
|
|
|
- <zm-table-column min-width="8%" align="center" label="项目名称" prop="projectName" />
|
|
|
- <zm-table-column min-width="27%" label="本期生产运行情况">
|
|
|
- <zm-table-column min-width="10%" label="计划工作量" prop="plannedWorkload" />
|
|
|
- <zm-table-column min-width="10%" label="实际完成" prop="actualCompletion" />
|
|
|
- <zm-table-column
|
|
|
- min-width="7%"
|
|
|
- label="设备利用率"
|
|
|
- prop="equipmentUtilizationRate"
|
|
|
- :formatter="(row) => `${row.equipmentUtilizationRate}%`"
|
|
|
- />
|
|
|
- </zm-table-column>
|
|
|
- <zm-table-column min-width="31%" label="生产管理情况及重点工作 ">
|
|
|
- <zm-table-column min-width="19%" label="重点工作及完成情况" prop="keyWorkCompletion" />
|
|
|
- <zm-table-column min-width="12%" label="存在问题及分析" prop="problemsAnalysis" />
|
|
|
- </zm-table-column>
|
|
|
- <zm-table-column min-width="29%" label="下期工作计划 ">
|
|
|
- <zm-table-column min-width="10%" label="计划工作量" prop="nextPlannedWorkload" />
|
|
|
- <zm-table-column min-width="19%" label="重点工作事项" prop="priorityTasks" />
|
|
|
- </zm-table-column>
|
|
|
- <zm-table-column label="操作" min-width="5%" align="center" fixed="right">
|
|
|
- <template #default="{ row, $index }">
|
|
|
- <div class="meeting-table__actions">
|
|
|
+ <div v-show="visible" class="flex items-center justify-between gap-4 mb-4">
|
|
|
+ <h3 class="text-lg font-bold m-0">会议明细</h3>
|
|
|
+ <el-button v-if="type !== 'view'" type="primary" @click="emits('add-detail')">
|
|
|
+ <Icon icon="ep:plus" class="mr-5px" />
|
|
|
+ 新增一行
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ <div class="meeting-detail-table-view">
|
|
|
+ <ZmTable
|
|
|
+ class="meeting-table"
|
|
|
+ :data="details"
|
|
|
+ :loading="loading"
|
|
|
+ :max-height="660"
|
|
|
+ align="left"
|
|
|
+ :show-overflow-tooltip="false"
|
|
|
+ :cell-style="getMeetingTableCellStyle"
|
|
|
+ >
|
|
|
+ <zm-table-column min-width="8%" align="center" label="项目名称" prop="projectName" />
|
|
|
+ <zm-table-column min-width="27%" label="本期生产运行情况">
|
|
|
+ <zm-table-column min-width="10%" label="计划工作量" prop="plannedWorkload" />
|
|
|
+ <zm-table-column min-width="10%" label="实际完成" prop="actualCompletion" />
|
|
|
+ <zm-table-column
|
|
|
+ min-width="7%"
|
|
|
+ label="设备利用率"
|
|
|
+ prop="equipmentUtilizationRate"
|
|
|
+ :formatter="(row) => `${row.equipmentUtilizationRate}%`"
|
|
|
+ />
|
|
|
+ </zm-table-column>
|
|
|
+ <zm-table-column min-width="31%" label="生产管理情况及重点工作 ">
|
|
|
+ <zm-table-column min-width="19%" label="重点工作及完成情况" prop="keyWorkCompletion" />
|
|
|
+ <zm-table-column min-width="12%" label="存在问题及分析" prop="problemsAnalysis" />
|
|
|
+ </zm-table-column>
|
|
|
+ <zm-table-column min-width="29%" label="下期工作计划 ">
|
|
|
+ <zm-table-column min-width="10%" label="计划工作量" prop="nextPlannedWorkload" />
|
|
|
+ <zm-table-column min-width="19%" label="重点工作事项" prop="priorityTasks" />
|
|
|
+ </zm-table-column>
|
|
|
+ <zm-table-column label="操作" min-width="5%" align="center" fixed="right">
|
|
|
+ <template #default="{ row, $index }">
|
|
|
+ <div class="meeting-table__actions">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ size="default"
|
|
|
+ type="primary"
|
|
|
+ @click="emits('edit-detail', row, $index)"
|
|
|
+ >
|
|
|
+ {{ type === 'view' ? '查看' : '编辑' }}
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="type !== 'view'"
|
|
|
+ link
|
|
|
+ size="default"
|
|
|
+ type="danger"
|
|
|
+ @click="emits('delete-detail', $index)"
|
|
|
+ >
|
|
|
+ 删除
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </zm-table-column>
|
|
|
+ </ZmTable>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-loading="loading" class="meeting-detail-card-view">
|
|
|
+ <template v-if="details.length">
|
|
|
+ <article v-for="(item, index) in details" :key="index" class="meeting-detail-card">
|
|
|
+ <div class="meeting-detail-card__header">
|
|
|
+ <div class="meeting-detail-card__title">
|
|
|
+ <span>项目名称</span>
|
|
|
+ <strong>{{ item.projectName || '-' }}</strong>
|
|
|
+ </div>
|
|
|
+ <el-tag size="small" effect="plain">第 {{ index + 1 }} 项</el-tag>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <section
|
|
|
+ v-for="group in detailCardGroups"
|
|
|
+ :key="group.title"
|
|
|
+ class="meeting-detail-card__group"
|
|
|
+ >
|
|
|
+ <h4>{{ group.title }}</h4>
|
|
|
+ <div class="meeting-detail-card__fields">
|
|
|
+ <div
|
|
|
+ v-for="field in group.fields"
|
|
|
+ :key="field.prop"
|
|
|
+ class="meeting-detail-card__field"
|
|
|
+ >
|
|
|
+ <span>{{ field.label }}</span>
|
|
|
+ <strong>{{ formatDetailCardValue(item, field) }}</strong>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <div class="meeting-detail-card__actions">
|
|
|
<el-button
|
|
|
link
|
|
|
- size="default"
|
|
|
+ size="small"
|
|
|
type="primary"
|
|
|
- @click="emits('edit-detail', row, $index)"
|
|
|
+ @click="emits('edit-detail', item, index)"
|
|
|
>
|
|
|
{{ type === 'view' ? '查看' : '编辑' }}
|
|
|
</el-button>
|
|
|
<el-button
|
|
|
v-if="type !== 'view'"
|
|
|
link
|
|
|
- size="default"
|
|
|
+ size="small"
|
|
|
type="danger"
|
|
|
- @click="emits('delete-detail', $index)"
|
|
|
+ @click="emits('delete-detail', index)"
|
|
|
>
|
|
|
删除
|
|
|
</el-button>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </zm-table-column>
|
|
|
- </ZmTable>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div v-loading="loading" class="meeting-detail-card-view">
|
|
|
- <template v-if="details.length">
|
|
|
- <article v-for="(item, index) in details" :key="index" class="meeting-detail-card">
|
|
|
- <div class="meeting-detail-card__header">
|
|
|
- <div class="meeting-detail-card__title">
|
|
|
- <span>项目名称</span>
|
|
|
- <strong>{{ item.projectName || '-' }}</strong>
|
|
|
- </div>
|
|
|
- <el-tag size="small" effect="plain">第 {{ index + 1 }} 项</el-tag>
|
|
|
- </div>
|
|
|
-
|
|
|
- <section
|
|
|
- v-for="group in detailCardGroups"
|
|
|
- :key="group.title"
|
|
|
- class="meeting-detail-card__group"
|
|
|
- >
|
|
|
- <h4>{{ group.title }}</h4>
|
|
|
- <div class="meeting-detail-card__fields">
|
|
|
- <div
|
|
|
- v-for="field in group.fields"
|
|
|
- :key="field.prop"
|
|
|
- class="meeting-detail-card__field"
|
|
|
- >
|
|
|
- <span>{{ field.label }}</span>
|
|
|
- <strong>{{ formatDetailCardValue(item, field) }}</strong>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </section>
|
|
|
-
|
|
|
- <div class="meeting-detail-card__actions">
|
|
|
- <el-button link size="small" type="primary" @click="emits('edit-detail', item, index)">
|
|
|
- {{ type === 'view' ? '查看' : '编辑' }}
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- v-if="type !== 'view'"
|
|
|
- link
|
|
|
- size="small"
|
|
|
- type="danger"
|
|
|
- @click="emits('delete-detail', index)"
|
|
|
- >
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </article>
|
|
|
- </template>
|
|
|
- <el-empty v-else description="暂无会议明细" :image-size="80" />
|
|
|
- </div>
|
|
|
+ </article>
|
|
|
+ </template>
|
|
|
+ <el-empty v-else description="暂无会议明细" :image-size="80" />
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
|
|
|
<section class="meeting-support-panel">
|
|
|
<el-form-item
|
|
|
@@ -409,6 +440,11 @@ const visible = ref(false)
|
|
|
gap: 18px 20px;
|
|
|
}
|
|
|
|
|
|
+.meeting-section__grid--company-only {
|
|
|
+ grid-template-columns: minmax(280px, 420px);
|
|
|
+ justify-content: start;
|
|
|
+}
|
|
|
+
|
|
|
.meeting-section__top {
|
|
|
display: grid;
|
|
|
grid-template-columns: max-content minmax(0, 1fr);
|
|
|
@@ -526,16 +562,45 @@ const visible = ref(false)
|
|
|
color: #1b71f6;
|
|
|
}
|
|
|
|
|
|
+.meeting-summary-strip__item--revenue {
|
|
|
+ background: linear-gradient(180deg, #eff6ff 0%, #fff 100%);
|
|
|
+ border-color: #bfdbfe;
|
|
|
+}
|
|
|
+
|
|
|
.meeting-summary-strip__item--account strong,
|
|
|
.meeting-summary-strip__item--account .icon {
|
|
|
color: #f59e0b;
|
|
|
}
|
|
|
|
|
|
+.meeting-summary-strip__item--account {
|
|
|
+ background: linear-gradient(180deg, #fffbeb 0%, #fff 100%);
|
|
|
+ border-color: #fde68a;
|
|
|
+}
|
|
|
+
|
|
|
.meeting-summary-strip__item--payment strong,
|
|
|
.meeting-summary-strip__item--payment .icon {
|
|
|
color: #10b981;
|
|
|
}
|
|
|
|
|
|
+.meeting-summary-strip__item--payment {
|
|
|
+ background: linear-gradient(180deg, #ecfdf5 0%, #fff 100%);
|
|
|
+ border-color: #bbf7d0;
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-detail-panel {
|
|
|
+ padding-top: 12px;
|
|
|
+ margin-top: 12px;
|
|
|
+ border-top: 1px solid var(--el-border-color-lighter);
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-detail-toggle__icon {
|
|
|
+ transition: transform var(--el-transition-duration) ease;
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-detail-toggle__icon--expanded {
|
|
|
+ transform: rotate(90deg);
|
|
|
+}
|
|
|
+
|
|
|
.meeting-table {
|
|
|
--zm-table-font-size: 18px;
|
|
|
--zm-table-header-font-size: 18px;
|
|
|
@@ -572,8 +637,8 @@ const visible = ref(false)
|
|
|
}
|
|
|
|
|
|
.meeting-support-panel {
|
|
|
- padding-top: 18px;
|
|
|
- margin-top: 18px;
|
|
|
+ padding-top: 12px;
|
|
|
+ margin-top: 12px;
|
|
|
border-top: 1px solid var(--el-border-color-lighter);
|
|
|
}
|
|
|
|