| | |
| | | (source.name.includes(candidateQuery.value) || String(source.selection.testId).includes(candidateQuery.value) || source.batteryNo.includes(candidateQuery.value)))) |
| | | const candidateGroups = computed(() => [...new Map(sources.value.map(source => [source.groupId, source.group])).entries()]) |
| | | const selections = computed(() => selectedTests.value.map(item => item.selection)) |
| | | const matrix = computed(() => savedReport.value || draftMatrix.value) |
| | | const matrix = computed(() => draftMatrix.value || savedReport.value) |
| | | const projectMode = computed(() => !savedReport.value || savedReport.value.spliceMode === 'project-cycles') |
| | | const projectSeries = computed(() => matrix.value ? spliceProjectSeries(matrix.value) : []) |
| | | const detailColumns = computed(() => matrix.value?.segments || []) |
| | |
| | | name: reportName.value, description: experimentName.value, settings: statisticSettings.value, |
| | | } : null) |
| | | |
| | | function formContent() { return JSON.stringify([reportName.value, experimentName.value, statisticSettings.value]) } |
| | | function formContent() { return JSON.stringify([reportName.value, experimentName.value, selections.value, statisticSettings.value]) } |
| | | function applySaved(saved: SavedSpliceReport) { |
| | | savedReport.value = saved |
| | | reportName.value = saved.name; experimentName.value = saved.description || '' |
| | |
| | | samples.value = [...new Set(saved.segments.map(segment => segment.source.batteryNo))] |
| | | const keys = saved.settings.metrics |
| | | statisticMetrics.forEach(metric => { statisticVisible[metric.key] = !keys || (keys.length > 0 && !keys.some(key => statisticMetrics.some(item => item.key === key))) || keys.includes(metric.key) }) |
| | | draftMatrix.value = null |
| | | savedContent.value = formContent() |
| | | } |
| | | async function loadPage() { |
| | |
| | | const version = route.query.version === undefined ? undefined : Number(route.query.version) |
| | | if (version !== undefined && (!Number.isInteger(version) || version < 1)) throw new Error('报表版本号无效') |
| | | applySaved(version === undefined ? await getSpliceReport(editingId.value, !readonly.value) : await getSpliceVersion(editingId.value, version)) |
| | | if (!readonly.value) sources.value = await getSpliceSources() |
| | | } else { |
| | | if (!canCreate.value) throw new Error('无新增拼接报表权限') |
| | | selectedTests.value = []; samples.value = []; reportName.value = ''; experimentName.value = '' |
| | |
| | | onMounted(loadPage) |
| | | watch(() => route.fullPath, loadPage) |
| | | watch(selections, async selected => { |
| | | if (editingId.value) return |
| | | const request = ++previewRequest |
| | | draftMatrix.value = null; previewError.value = '' |
| | | // 来源移除后同步移除其人工值,仍在范围内的修改继续保留。 |
| | |
| | | saving.value = true |
| | | try { |
| | | const payload = { name: reportName.value.trim(), description: experimentName.value, settings: statisticSettings.value } |
| | | if (editingId.value && savedReport.value) await editSpliceReport(editingId.value, { ...payload, baseVersionNo: savedReport.value.versionNo, changeSummary: '更新拼接报表设置' }) |
| | | if (editingId.value && savedReport.value) await editSpliceReport(editingId.value, { ...payload, selections: selections.value, baseVersionNo: savedReport.value.versionNo, changeSummary: '更新拼接报表设置' }) |
| | | else await createSpliceReport({ ...payload, selections: selections.value }) |
| | | ElMessage.success(editingId.value ? '拼接报表已更新' : '拼接报表已保存') |
| | | await router.push('/report-splice') |
| | |
| | | |
| | | <section class="test-panel"> |
| | | <header class="panel-heading"><div><strong>拼接测试</strong></div><small>{{ selectedTests.length }} 个来源段</small></header> |
| | | <div class="test-table-wrap"><table class="test-table"><thead><tr><th>顺序</th><th>测试名称</th><th>测试类型</th><th>电池组</th><th>电池号</th><th v-if="!editingId">操作</th></tr></thead><tbody> |
| | | <div class="test-table-wrap"><table class="test-table"><thead><tr><th>顺序</th><th>测试名称</th><th>测试类型</th><th>电池组</th><th>电池号</th><th v-if="!readonly">操作</th></tr></thead><tbody> |
| | | <tr v-for="(item, index) in selectedTests" :key="spliceSourceKey(item)"><td><span class="order-index">{{ index + 1 }}</span></td><td>{{ item.name }}</td><td>{{ item.type }}</td><td>{{ item.group }}</td><td>{{ item.batteryNo }}</td> |
| | | <td v-if="!editingId && !readonly"><el-tooltip content="上移"><el-button circle aria-label="上移测试" :disabled="index === 0" @click="moveTest(index, -1)"><el-icon><ArrowUp /></el-icon></el-button></el-tooltip><el-tooltip content="下移"><el-button circle aria-label="下移测试" :disabled="index === selectedTests.length - 1" @click="moveTest(index, 1)"><el-icon><ArrowDown /></el-icon></el-button></el-tooltip><button class="delete-link" @click="removeSpliceTest(index)">删除</button></td></tr> |
| | | <td v-if="!readonly"><el-tooltip content="上移"><el-button circle aria-label="上移测试" :disabled="index === 0" @click="moveTest(index, -1)"><el-icon><ArrowUp /></el-icon></el-button></el-tooltip><el-tooltip content="下移"><el-button circle aria-label="下移测试" :disabled="index === selectedTests.length - 1" @click="moveTest(index, 1)"><el-icon><ArrowDown /></el-icon></el-button></el-tooltip><button class="delete-link" @click="removeSpliceTest(index)">删除</button></td></tr> |
| | | <tr v-if="!selectedTests.length"><td colspan="6">暂无已选测试</td></tr> |
| | | </tbody></table></div> |
| | | <div v-if="!editingId && !readonly" class="panel-actions"><button class="primary-button compact-button" type="button" @click="openAddTest"><el-icon><Plus /></el-icon>添加拼接</button> |
| | | <div v-if="!readonly" class="panel-actions"><button class="primary-button compact-button" type="button" @click="openAddTest"><el-icon><Plus /></el-icon>添加拼接</button> |
| | | </div> |
| | | </section> |
| | | |