refactor: make the abstract a paragraph instead of a paper field

A template's abstract paragraph (`0 Abstract`) *is* the paper's abstract: it has
a position in the document, the heading and typography the template gives it,
and the same sentence-by-sentence editing as everything else. `paper.abstract`
was a second home for that text — one the document never reads, so a paper
could show two different abstracts and the column could drift from the body.

The column is gone, from the table, the model, the schemas, the API payloads,
the paper form, the list subtitle and the paper page. Nothing else changed.

The text already written into it is not gone. Revision a83f5c21d7b6 writes each
stored abstract into the paper's body first — one sentence per 。 at the
paragraph carrying the abstract heading, appended after anything already there
rather than replacing it. A template without such a heading keeps the text too,
one position above its first paragraph, where the document renders it under
未设定. Verified against the one paper that had an abstract: 450 characters in,
450 out, identical including `|J| ≤ α · I⁻ᵝ`, split into six sentences in the
`0 Abstract` paragraph, still with its own edit button.

The smoke test no longer assumes an empty database: it records the paper total
before it starts and compares against that, so it can run on a real one.
This commit is contained in:
2026-09-18 18:55:10 +08:00
parent 4e2e3abc30
commit 45926af966
10 changed files with 192 additions and 54 deletions
+7 -5
View File
@@ -56,10 +56,13 @@ export interface PaperListItem {
updated_at: string
}
/** A paper with everything the table does not need. */
export interface PaperDetail extends PaperListItem {
abstract: string | null
}
/**
* A paper as its own page needs it.
*
* There is no `abstract` here on purpose: a paper's abstract is the template's
* `0 Abstract` paragraph, written and edited like any other paragraph.
*/
export interface PaperDetail extends PaperListItem {}
/** A stored citation of one sentence. */
export interface Citation {
@@ -143,7 +146,6 @@ export interface SentenceInput {
export interface PaperPayload {
title: string
template_id: number | null
abstract: string | null
author: string | null
status: PaperStatus
keywords: string | null
@@ -53,7 +53,6 @@ const templates = ref<TemplateListItem[]>([])
const form = reactive({
title: '',
template_id: null as number | null,
abstract: '',
author: '',
status: 'draft' as PaperStatus,
keywords: [] as string[],
@@ -78,7 +77,6 @@ watch(
formRef.value?.clearValidate()
form.title = props.paper?.title ?? ''
form.template_id = props.paper?.template_id ?? null
form.abstract = ''
form.author = props.paper?.author ?? ''
form.status = props.paper?.status ?? 'draft'
form.keywords = splitKeywords(props.paper?.keywords)
@@ -98,7 +96,6 @@ watch(
const detail = await getPaper(props.paper.id)
form.title = detail.title
form.template_id = detail.template_id
form.abstract = detail.abstract ?? ''
form.author = detail.author ?? ''
form.status = detail.status
form.keywords = splitKeywords(detail.keywords)
@@ -121,7 +118,6 @@ async function submit(): Promise<void> {
const payload = {
title: form.title.trim(),
template_id: form.template_id,
abstract: form.abstract.trim() || null,
author: form.author.trim() || null,
status: form.status,
keywords: form.keywords.length ? form.keywords.join(', ') : null,
@@ -226,15 +222,6 @@ async function submit(): Promise<void> {
<el-form-item label="目标期刊">
<el-input v-model="form.target_journal" placeholder="如 情报学报" maxlength="255" clearable />
</el-form-item>
<el-form-item label="摘要">
<el-input
v-model="form.abstract"
type="textarea"
:rows="3"
placeholder="论文摘要,可稍后再写"
/>
</el-form-item>
</el-form>
<template #footer>
-13
View File
@@ -241,9 +241,6 @@ onMounted(async () => {
<el-button link type="primary" class="title-link" @click="openPaper(row)">
{{ row.title }}
</el-button>
<div v-if="row.abstract" class="abstract" :title="row.abstract">
{{ row.abstract }}
</div>
</template>
</el-table-column>
@@ -390,16 +387,6 @@ onMounted(async () => {
text-align: left;
}
.abstract {
margin-top: 2px;
max-width: 320px;
font-size: 12px;
color: var(--el-text-color-secondary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.progress {
font-size: 13px;
font-variant-numeric: tabular-nums;
@@ -222,8 +222,6 @@ onMounted(load)
{{ word }}
</el-tag>
</div>
<p v-if="paper.abstract" class="head-abstract">{{ paper.abstract }}</p>
</div>
<div class="head-actions">
@@ -384,13 +382,6 @@ onMounted(load)
margin-top: 8px;
}
.head-abstract {
margin: 10px 0 0;
font-size: 13px;
line-height: 1.8;
color: var(--el-text-color-regular);
}
.head-actions {
display: flex;
align-items: center;