feat: 完成前端业务闭环与后端联调

This commit is contained in:
2026-08-24 23:37:56 +08:00
parent c59e36f933
commit 9ad572907b
175 changed files with 10711 additions and 1740 deletions
+41 -3
View File
@@ -8,6 +8,9 @@
@action="createArticle"
/></view>
<view class="article-list-content">
<view v-if="articleCategoryError" class="article-category-error" role="alert">
<text>{{ articleCategoryError }}</text>
</view>
<view v-if="categoryOptions.length > 1" class="article-filter">
<text>文章分类</text>
<picker :range="categoryLabels" :value="categoryIndex" @change="selectCategory">
@@ -21,6 +24,13 @@
class="article-card"
@click="openArticle(item)"
>
<image
v-if="item.coverFile?.accessUrl"
class="article-card__cover"
:src="item.coverFile.accessUrl"
mode="aspectFill"
aria-hidden="true"
/>
<text class="article-card__title">{{ item.title }}</text>
<text class="article-card__summary">{{
item.summary || item.content
@@ -59,6 +69,7 @@ import {
createRequestController,
isRequestCancelled
} from "@/services/api/request-controller.js";
import { getRequestErrorMessage } from "@/services/api/request-error-message.js";
import { familyArticleApi } from "@/services/api/family-article-service.js";
import { goBack, openPage } from "@/utils/navigation/gateway.js";
@@ -67,6 +78,7 @@ const hasValidContext = ref(false);
const listState = ref("loading");
const articles = ref([]);
const categories = ref([]);
const articleCategoryError = ref("");
const selectedCategoryId = ref("");
const articleListRequestController = createRequestController();
const articleCategoryRequestController = createRequestController();
@@ -130,13 +142,18 @@ onUnload(() => {
articleCategoryRequestController.abort();
});
const loadArticleCategories = async () => {
articleCategoryError.value = "";
try {
return await familyArticleApi.getArticleCategories(genealogyId.value, {
requestController: articleCategoryRequestController,
});
} catch (error) {
if (isRequestCancelled(error)) throw error;
return [];
articleCategoryError.value = getRequestErrorMessage(
error,
"谱文分类暂时无法读取,当前仍可查看全部谱文。",
);
return null;
}
};
const loadArticles = async () => {
@@ -152,7 +169,7 @@ const loadArticles = async () => {
]);
if (!pageActive) return;
articles.value = rows;
categories.value = categoryRows;
if (categoryRows) categories.value = categoryRows;
if (!categoryOptions.value.some((item) => item.id === selectedCategoryId.value)) {
selectedCategoryId.value = "";
}
@@ -192,11 +209,20 @@ const handleStateAction = () => {
z-index: 1;
}
.article-list-content {
padding: 18rpx 24rpx 72rpx;
padding: 18rpx 24rpx calc(72rpx + env(safe-area-inset-bottom));
}
.article-list-items {
margin-top: 24rpx;
}
.article-category-error {
margin-top: 20rpx;
padding: 18rpx 22rpx;
border: 1rpx solid rgba(159, 35, 35, 0.22);
background: rgba(255, 247, 233, 0.94);
color: $brand-red;
font-size: clamp(13px, 22rpx, 16px);
line-height: 1.6;
}
.article-filter {
display: flex;
align-items: center;
@@ -207,6 +233,8 @@ const handleStateAction = () => {
background: rgba(255, 252, 242, 0.92);
color: $ink;
font-size: clamp(14px, 24rpx, 17px);
min-height: 80rpx;
box-sizing: border-box;
}
.article-filter__value {
color: $brand-red;
@@ -235,6 +263,14 @@ const handleStateAction = () => {
box-sizing: border-box;
margin-bottom: 16rpx;
padding: 28rpx;
background-color: rgba($paper, 0.82);
}
.article-card__cover {
width: 100%;
height: 280rpx;
margin-bottom: 20rpx;
border-radius: 10rpx;
background: rgba(128, 89, 49, 0.12);
}
.article-card text {
display: block;
@@ -244,6 +280,7 @@ const handleStateAction = () => {
font-family: STKaiti, KaiTi, serif;
font-size: clamp(17px, 31rpx, 22px);
font-weight: 700;
overflow-wrap: anywhere;
}
.article-card__summary {
display: -webkit-box;
@@ -263,6 +300,7 @@ const handleStateAction = () => {
}
.article-list-state-card {
@include adaptive-family-content;
background-color: rgba($paper, 0.82);
width: 100%;
min-height: 340rpx;
margin-top: 30rpx;