修复提醒弹窗内容为空:后端补充content字段,前端增加title兜底,清除基础资料页空toast

- 后端 _map_reminder 返回 reminder_content 作为 content 字段
- 前端 mockApi 透传 content 字段
- NotificationBell 弹窗展示 content,title 为空时显示"(无标题)"
- 提醒中心和工作台页面 title 列增加空值兜底
- 删除 MasterDataPage 中 13 处 toast.success("") 空弹窗调用

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
taiyi 2026-05-29 23:13:11 +08:00
parent f7dfc5d282
commit 4d1fd71364
9 changed files with 23 additions and 20 deletions

View File

@ -261,6 +261,7 @@ class ReminderService:
return {
"reminder_id": reminder.id,
"title": reminder.reminder_title,
"content": reminder.reminder_content,
"type": reminder.reminder_type,
"biz_type": reminder.biz_type,
"biz_id": reminder.biz_id,

View File

@ -25,8 +25,8 @@
>
<div class="item-dot" :class="item.status === 'pending' ? 'dot-blue' : 'dot-gray'"></div>
<div class="item-body">
<p class="item-title">{{ item.title }}</p>
<p class="item-meta">{{ item.biz_type }} / {{ item.biz_id }}</p>
<p class="item-title">{{ item.title || '(无标题)' }}</p>
<p class="item-meta">{{ item.content || item.type }}</p>
</div>
</li>
</ul>

View File

@ -776,6 +776,7 @@ function buildReminderRow(item) {
return {
reminder_id: item.reminder_id,
title: item.title,
content: item.content,
type: item.type,
biz_type: item.biz_type,
biz_id: item.biz_id,

View File

@ -1336,7 +1336,7 @@ async function handleSetDefaultSpec(spec) {
return;
}
loadingProductDetail.value = true;
toast.success("");
try {
await setDefaultProductSpec(spec.product_id);
if (productDetail.value?.product_name) {
@ -1409,7 +1409,7 @@ async function loadSuppliers() {
async function handleSearchCustomers() {
loadingCustomers.value = true;
toast.success("");
try {
const data = await loadCustomers();
} catch (error) {
@ -1450,7 +1450,7 @@ async function handleCreateCustomer() {
return;
}
creatingCustomer.value = true;
toast.success("");
try {
const result = await createCustomer({
...customerCreateForm,
@ -1472,7 +1472,7 @@ async function handleImportCustomers() {
return;
}
importingCustomer.value = true;
toast.success("");
try {
const result = await importCustomers({ ...customerImportForm });
showImportCustomerForm.value = false;
@ -1489,7 +1489,7 @@ async function handleImportCustomers() {
async function handleSearchCategories() {
loadingCategories.value = true;
toast.success("");
try {
const data = await loadCategories();
} catch (error) {
@ -1515,7 +1515,7 @@ async function handleCreateCategory() {
return;
}
creatingCategory.value = true;
toast.success("");
try {
const result = await createProductCategory({ ...categoryCreateForm });
showCreateCategoryForm.value = false;
@ -1558,7 +1558,7 @@ async function handleUpdateCategory() {
return;
}
updatingCategory.value = true;
toast.success("");
try {
await updateProductCategory(editingCategoryId.value, { ...categoryEditForm });
resetCategoryEditForm();
@ -1574,7 +1574,7 @@ async function handleUpdateCategory() {
async function handleSearchProducts() {
loadingProducts.value = true;
toast.success("");
try {
const data = await loadProducts();
} catch (error) {
@ -1603,7 +1603,7 @@ async function handleCreateProduct() {
return;
}
creatingProduct.value = true;
toast.success("");
try {
const result = await createProduct({
product_name: productCreateForm.product_name.trim(),
@ -1666,7 +1666,7 @@ async function handleUpdateSpec() {
return;
}
updatingSpec.value = true;
toast.success("");
try {
await updateProductSpecification(editingSpecId.value, {
...editingSpecForm,
@ -1689,7 +1689,7 @@ async function handleUpdateSpec() {
async function handleSearchSuppliers() {
loadingSuppliers.value = true;
toast.success("");
try {
const data = await loadSuppliers();
} catch (error) {
@ -1712,7 +1712,7 @@ async function handleCreateSupplier() {
return;
}
creatingSupplier.value = true;
toast.success("");
try {
const result = await createSupplier({ ...supplierCreateForm });
showCreateSupplierForm.value = false;
@ -1745,7 +1745,7 @@ async function handleViewSupplierDetail(row) {
async function switchTab(tabKey) {
activeTab.value = tabKey;
toast.success("");
if (tabKey === "categories" && !categoryRows.value.length) {
await handleSearchCategories();
}

View File

@ -54,7 +54,7 @@
<thead><tr><th>标题</th><th>类型</th><th>业务对象</th><th>状态</th><th>操作</th></tr></thead>
<tbody>
<tr v-for="row in filteredReminders" :key="row.reminder_id">
<td>{{ row.title }}</td>
<td>{{ row.title || '(无标题)' }}</td>
<td>{{ row.type }}</td>
<td>{{ row.biz_type }} / {{ row.biz_id }}</td>
<td><span class="status">{{ row.status }}</span></td>

View File

@ -25,8 +25,8 @@
>
<div class="item-dot" :class="(item.status === 'pending' || item.status === '未读') ? 'dot-blue' : 'dot-gray'"></div>
<div class="item-body">
<p class="item-title">{{ item.title }}</p>
<p class="item-meta">{{ item.type }}</p>
<p class="item-title">{{ item.title || '(无标题)' }}</p>
<p class="item-meta">{{ item.content || item.type }}</p>
</div>
</li>
</ul>

View File

@ -225,6 +225,7 @@ export async function fetchRemindersPage(filters = {}) {
reminderRows: (data.list || []).map((item) => ({
reminderId: item.reminder_id,
title: item.title,
content: item.content,
type: item.type,
bizType: item.biz_type,
bizId: item.biz_id,

View File

@ -59,7 +59,7 @@
<div v-if="pendingReminders.length === 0" class="empty-box">暂无待处理提醒</div>
<div v-else class="reminder-list">
<article v-for="item in pendingReminders" :key="item.reminder_id" class="reminder-row">
<span class="reminder-title">{{ item.title }}</span>
<span class="reminder-title">{{ item.title || '(无标题)' }}</span>
<span class="reminder-type">{{ item.type || "-" }}</span>
<span class="reminder-time">{{ item.created_at || "-" }}</span>
</article>

View File

@ -55,7 +55,7 @@
</thead>
<tbody>
<tr v-for="row in reminderRows" :key="row.reminderId">
<td :data-label="'标题'">{{ row.title }}</td>
<td :data-label="'标题'">{{ row.title || '(无标题)' }}</td>
<td :data-label="'类型'">{{ row.type }}</td>
<td :data-label="'状态'"><span class="status" :class="statusClass(row.status)">{{ row.status }}</span></td>
<td :data-label="'创建时间'">{{ row.createdAt }}</td>