diff --git a/components/AppButton.vue b/components/AppButton.vue
index 3fd0052..a526382 100644
--- a/components/AppButton.vue
+++ b/components/AppButton.vue
@@ -35,8 +35,8 @@ const emit = defineEmits(["click"]);
const skin = computed(() =>
props.type === "secondary"
- ? "/static/assets/foundation/transparent/a01-scroll-secondary-v3.png"
- : "/static/assets/foundation/transparent/a01-scroll-primary-v3.png",
+ ? "/static/assets/foundation/transparent/scroll-secondary.png"
+ : "/static/assets/foundation/transparent/scroll-primary.png",
);
const handleClick = (event) => {
@@ -45,7 +45,7 @@ const handleClick = (event) => {
diff --git a/components/AppTabbar.vue b/components/AppTabbar.vue
index 50f6564..655dee2 100644
--- a/components/AppTabbar.vue
+++ b/components/AppTabbar.vue
@@ -1,4 +1,3 @@
-
-
+ {{ item.publisher }}{{ item.content }}{{ feedTypeLabel(item.type) }} · {{ item.time }}
+ >
+ {{ item.publisher }}
+ {{ feedPreview(item.content) }}
+
+ {{ feedTypeLabel(item.type) }} · {{ formatMinuteTimestamp(item.time) }}
+ {{ item.recommendationReason }}
+
+ {{ loadMoreLabel }}
+
{{ stateCopy.title }}
import { computed, ref } from "vue";
-import { onLoad, onShow } from "@dcloudio/uni-app";
+import { onLoad, onShow, onUnload } from "@dcloudio/uni-app";
import AppLoading from "@/components/AppLoading.vue";
import AppTabbar from "@/components/AppTabbar.vue";
+import FamilyFeedMedia from "@/components/family/FeedMedia.vue";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
-import { appApi, isRequestCancelled } from "@/utils/api.js";
-import { genealogyContext } from "@/utils/genealogy-context.js";
-import { goRoot, openPage } from "@/utils/navigation.js";
+import {
+ createRequestController,
+ isRequestCancelled
+} from "@/services/api/request-controller.js";
+import { familyFeedApi } from "@/services/api/family-feed-service.js";
+import { formatMinuteTimestamp } from "@/utils/display-time.js";
+import { genealogyContext } from "@/utils/genealogy/context.js";
+import { goRoot, openPage } from "@/utils/navigation/gateway.js";
const genealogyId = ref("");
const hasValidContext = ref(false);
const feedState = ref("loading");
const feeds = ref([]);
+const FEED_PAGE_SIZE = 20;
+const totalFeedCount = ref(0);
+const currentFeedPage = ref(1);
+const loadMoreState = ref("idle");
+const hasMoreFeeds = computed(
+ () => feedState.value === "list" && feeds.value.length < totalFeedCount.value,
+);
+const loadMoreLabel = computed(() => {
+ if (loadMoreState.value === "loading") return "正在加载";
+ if (loadMoreState.value === "error") return "加载失败,重新加载";
+ return "继续加载";
+});
let active = true;
+let skipInitialShowRefresh = true;
+const feedListRequestController = createRequestController();
+const recommendationRequestController = createRequestController();
const feedTypeLabel = (type) =>
String(type || "")
.trim()
.toLowerCase() === "text"
? "文字动态"
: "家族动态";
+const feedPreview = (content) => {
+ const text = String(content || "").trim();
+ return text.length > 96 ? `${text.slice(0, 96).trimEnd()}…` : text;
+};
const shortcuts = [
{ key: "articles", label: "谱文" },
{ key: "albums", label: "相册" },
@@ -109,16 +142,67 @@ const stateCopy = computed(() =>
const loadFeeds = async () => {
if (!hasValidContext.value) return;
feedState.value = "loading";
+ loadMoreState.value = "idle";
+ currentFeedPage.value = 1;
+ feedListRequestController.abort();
+ recommendationRequestController.abort();
try {
- const rows = await appApi.getFeeds(genealogyId.value);
+ const [pageResult, recommendationResult] = await Promise.allSettled([
+ familyFeedApi.getFeedPage(
+ genealogyId.value,
+ { pageNum: 1, pageSize: FEED_PAGE_SIZE },
+ { requestController: feedListRequestController },
+ ),
+ familyFeedApi.getFeedRecommendations(genealogyId.value, {
+ requestController: recommendationRequestController,
+ }),
+ ]);
+ if (pageResult.status === "rejected") throw pageResult.reason;
if (!active) return;
- feeds.value = rows;
+ const recommendations =
+ recommendationResult.status === "fulfilled"
+ ? recommendationResult.value
+ : [];
+ const reasons = new Map(
+ recommendations.map((item) => [String(item.id), item.recommendationReason]),
+ );
+ feeds.value = pageResult.value.rows.map((item) => ({
+ ...item,
+ recommendationReason: reasons.get(String(item.id)) || "",
+ }));
+ totalFeedCount.value = pageResult.value.total;
+ loadMoreState.value =
+ feeds.value.length < totalFeedCount.value ? "idle" : "done";
feedState.value = feeds.value.length ? "list" : "empty";
} catch (error) {
if (!active || isRequestCancelled(error)) return;
feedState.value = "error";
}
};
+const loadMoreFeeds = async () => {
+ if (!hasMoreFeeds.value || loadMoreState.value === "loading") return;
+ loadMoreState.value = "loading";
+ try {
+ const nextPage = currentFeedPage.value + 1;
+ const page = await familyFeedApi.getFeedPage(
+ genealogyId.value,
+ { pageNum: nextPage, pageSize: FEED_PAGE_SIZE },
+ { requestController: feedListRequestController },
+ );
+ if (!active) return;
+ const knownIds = new Set(feeds.value.map((item) => String(item.id)));
+ feeds.value = feeds.value.concat(
+ page.rows.filter((item) => !knownIds.has(String(item.id))),
+ );
+ currentFeedPage.value = nextPage;
+ totalFeedCount.value = page.total;
+ loadMoreState.value =
+ feeds.value.length < totalFeedCount.value ? "idle" : "done";
+ } catch (error) {
+ if (!active || isRequestCancelled(error)) return;
+ loadMoreState.value = "error";
+ }
+};
onLoad((query) => {
const supplied = Object.prototype.hasOwnProperty.call(
query || {},
@@ -132,11 +216,20 @@ onLoad((query) => {
else feedState.value = "error";
});
onShow(() => {
+ if (skipInitialShowRefresh) {
+ skipInitialShowRefresh = false;
+ return;
+ }
if (hasValidContext.value) void loadFeeds();
});
+onUnload(() => {
+ active = false;
+ feedListRequestController.abort();
+ recommendationRequestController.abort();
+});
const toPublish = () =>
hasValidContext.value
- ? openPage("F02", { genealogyId: genealogyId.value }, "F01")
+ ? openPage("F02", { genealogyId: genealogyId.value, mode: "create" }, "F01")
: goRoot("G01");
const openFeed = (item) =>
openPage("F03", { genealogyId: genealogyId.value, feedId: item.id }, "F01");
@@ -190,10 +283,17 @@ const handlePrimaryAction = () =>
.feed-shortcuts {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 8rpx;
margin-top: 15rpx;
}
.feed-shortcut {
+ box-sizing: border-box;
min-height: 48px;
+ margin: 0;
+ padding: 0;
+ border: 1rpx solid rgba(181, 137, 63, 0.45);
+ border-radius: 8rpx;
+ background: rgba(255, 252, 244, 0.58);
display: flex;
align-items: center;
justify-content: center;
@@ -237,6 +337,37 @@ const handlePrimaryAction = () =>
color: $ink-muted;
font-size: clamp(13px, 21rpx, 16px);
}
+.feed-shortcut::after {
+ border: 0;
+}
+.feed-shortcut:active {
+ background: rgba(181, 137, 63, 0.1);
+}
+.feed-card__reason {
+ margin-top: 8rpx;
+ color: #9a6555;
+ font-size: clamp(12px, 20rpx, 15px);
+}
+.feed-more {
+ @include adaptive-scroll-button(secondary);
+ display: block;
+ width: 420rpx;
+ max-width: 100%;
+ min-height: 76rpx;
+ margin: 22rpx auto 0;
+ padding: 0 24rpx;
+ border: 0;
+ color: $ink;
+ font-size: clamp(14px, 22rpx, 17px);
+ font-weight: 700;
+ line-height: 76rpx;
+}
+.feed-more::after {
+ border: 0;
+}
+.feed-more[disabled] {
+ opacity: 0.62;
+}
.feed-state-card {
min-height: 230rpx;
display: flex;
diff --git a/pages/family/videos.vue b/pages/family/videos.vue
new file mode 100644
index 0000000..8ad2922
--- /dev/null
+++ b/pages/family/videos.vue
@@ -0,0 +1,660 @@
+
+
+
+
+
+
+ {{
+ isEdit ? "编辑家族视频" : "发布家族视频"
+ }}
+ {{
+ isEdit
+ ? "原视频、封面和相关设置会保留。"
+ : "视频上传成功后会自动关联,无需额外填写。"
+ }}
+
+
+ *视频文件
+
+ {{
+ isEdit
+ ? "当前视频已关联"
+ : uploading
+ ? "上传中…"
+ : receipt
+ ? "重新选择视频"
+ : "选择视频"
+ }}
+
+ 已上传:{{ receipt.fileName || "视频" }}
+
+ {{ uploadError }}
+
+
+ 视频封面
+
+ {{
+ coverUploading
+ ? "上传中…"
+ : coverReceipt
+ ? "重新选择封面"
+ : "选择图片"
+ }}
+
+ 已上传:{{ coverReceipt.fileName || "视频封面" }}
+
+ {{
+ coverUploadError
+ }}
+
+
+ *视频标题
+
+
+
+ 视频说明
+
+
+ {{ submitError }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 暂时无法读取视频
+ 请检查网络后重新加载。
+
+
+
+ 还没有家族视频
+ 可以先发布一段值得留存的影像。
+
+
+
+
+
+ {{ video.title }}
+ {{
+ video.description
+ }}
+ {{
+ video.publishTime || "刚刚发布"
+ }}
+
+
+
+
+
+
+ {{
+ videoActionError
+ }}
+
+
+ {{ stateCopy.title }}
+ {{ stateCopy.copy }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/genealogy/application-review.vue b/pages/genealogy/application-review.vue
new file mode 100644
index 0000000..7021dd9
--- /dev/null
+++ b/pages/genealogy/application-review.vue
@@ -0,0 +1,258 @@
+
+
+
+
+
+
+ 暂时无法打开审核页面
+ 未找到家谱信息,请返回后重新进入。
+
+
+
+
+
+
+ 暂时无法读取待审核申请
+ {{ applicationReviewError || "请检查网络后重试。" }}
+
+
+
+ 暂无待审核申请
+ 新的加入申请会显示在这里。
+
+
+
+ 共 {{ applications.length }} 条待审核申请
+ {{ feedbackMessage }}
+
+
+ {{ applicantName(item) }}
+ {{ applicationTime(item) }}
+
+ {{ applicantPhone(item) }}
+ {{ applicationRelation(item) }}
+ {{ applicationReason(item) }}
+
+
+
+
+
+
+
+
+
+ 拒绝原因
+
+ {{ rejectionError }}
+
+ {{ operationError }}
+
+
+
+
+
+
+
diff --git a/pages/genealogy/g03-create-genealogy.vue b/pages/genealogy/create.vue
similarity index 58%
rename from pages/genealogy/g03-create-genealogy.vue
rename to pages/genealogy/create.vue
index 968ee92..700741c 100644
--- a/pages/genealogy/g03-create-genealogy.vue
+++ b/pages/genealogy/create.vue
@@ -1,4 +1,3 @@
-
@@ -9,7 +8,7 @@
立谱信息
为家族创建一部家谱
创建成功后会回到我的家谱;首代人物可在后续合同开放后再录入。创建成功后会回到“我的家谱”;可在世系树中录入首位成员。
@@ -44,7 +43,12 @@
fieldErrors.genealogyName
}}
-
+
*所在地区
@@ -59,6 +63,12 @@
: regionPickerError || "请选择所在地区"
}}
+
{{
fieldErrors.regionCode
@@ -109,7 +119,7 @@
封面图片
选择图片后会取得真实上传回执,并在创建家谱时关联。图片上传成功后,会作为家谱封面保存。
访问规则
-
+
{{ option.label }}
@@ -146,60 +163,20 @@
-
-
-
-
- 选择地区
-
-
-
- {{ label }}
-
-
-
- {{ option.label }}
-
-
-
-
-
-
+
@@ -312,118 +292,36 @@ const validate = () => {
);
};
-const fetchRegionChildren = async (parentCode) => {
- regionLoading.value = true;
- regionPickerError.value = "";
- try {
- return await appApi.getRegionChildren(parentCode, {
- requestController: regionController,
- });
- } catch (error) {
- if (!isRequestCancelled(error))
- regionPickerError.value = error?.message || "地区列表加载失败,请重试";
- return [];
- } finally {
- regionLoading.value = false;
- }
-};
-
-const loadRegionRoot = async () => {
- if (isSubmitting.value || isUploading.value || regionLoading.value) return;
- const roots = await fetchRegionChildren("0");
- if (!roots.length || regionPickerError.value) return;
- regionPickerColumns.value = [roots];
- regionPickerIndexes.value = [0];
- regionPickerTrail.value = [];
- await loadPickerColumns();
-};
-
-const loadPickerColumns = async (provinceIndex = 0, cityIndex = 0) => {
- const provinces =
- regionPickerColumns.value[0] || (await fetchRegionChildren("0"));
- const province = provinces[provinceIndex];
- if (!province) return;
-
- const cities = await fetchRegionChildren(province.regionCode);
- const city = cities[cityIndex];
- if (!city) {
- regionPickerColumns.value = [provinces];
- regionPickerIndexes.value = [provinceIndex];
- return;
- }
-
- const districts = await fetchRegionChildren(city.regionCode);
- if (!districts.length || regionPickerError.value) return;
- regionPickerColumns.value = [provinces, cities, districts];
- regionPickerIndexes.value = [provinceIndex, cityIndex, 0];
-};
-
-const handleRegionPickerChange = async (event) => {
- if (regionLoading.value) return;
- const nextIndexes = (event?.detail?.value || []).map(
- (index) => Number(index) || 0,
- );
- const indexes = regionPickerIndexes.value;
- const provinceIndex = nextIndexes[0] || 0;
- const cityIndex = nextIndexes[1] || 0;
- const districtIndex = nextIndexes[2] || 0;
-
- if (provinceIndex !== (indexes[0] || 0)) {
- await loadPickerColumns(provinceIndex, 0);
- return;
- }
- if (cityIndex !== (indexes[1] || 0)) {
- await loadPickerColumns(indexes[0] || 0, cityIndex);
- return;
- }
- regionPickerIndexes.value = [indexes[0] || 0, indexes[1] || 0, districtIndex];
-};
-
const openRegionPicker = async () => {
if (isSubmitting.value || isUploading.value || regionLoading.value) return;
- if (!regionPickerColumns.value.length) await loadRegionRoot();
- if (regionPickerColumns.value.length) {
- regionPickerOpen.value = true;
- }
+ await regionPickerDialog.value?.open(selectedRegion.value?.regionCode || "");
};
-
-const closeRegionPicker = () => {
- regionPickerOpen.value = false;
-};
-
-const confirmRegionSelection = () => {
- const indexes = regionPickerIndexes.value;
- const trail = [];
- regionPickerColumns.value.forEach((column, index) => {
- const option = column[Number(indexes[index])];
- if (option) trail.push(option);
- });
- const region = trail[trail.length - 1];
- if (!region) return;
- regionPickerIndexes.value = trail.map(
- (_, index) => Number(indexes[index]) || 0,
- );
+const selectRegion = ({ region, trail }) => {
selectedRegion.value = region;
regionPickerTrail.value = trail;
fieldErrors.regionCode = "";
regionPickerError.value = "";
- regionPickerOpen.value = false;
};
onMounted(() => {
- loadRegionRoot();
+ void regionPickerDialog.value?.prepare();
});
const requestBack = () =>
- runBackGuard({
- transientOpen: regionPickerOpen.value || discardDialogVisible.value,
- dirty: hasDraft.value,
- submitting: isSubmitting.value || isUploading.value,
- "close-transient": () =>
- regionPickerOpen.value ? closeRegionPicker() : cancelDiscard(),
- "block-submitting": () => true,
- "confirm-discard": requestDiscardConfirmation,
- });
+ createdGenealogyId.value
+ ? returnTo("G01")
+ : runBackGuard({
+ transientOpen:
+ regionPickerTransientOpen.value || discardDialogVisible.value,
+ dirty: hasDraft.value,
+ submitting: isSubmitting.value || isUploading.value,
+ "close-transient": () =>
+ regionPickerTransientOpen.value
+ ? regionPickerDialog.value?.close()
+ : cancelDiscard(),
+ "block-submitting": () => true,
+ "confirm-discard": requestDiscardConfirmation,
+ });
onBackPress((event) => handleBackPress(event, requestBack));
@@ -433,7 +331,7 @@ const uploadCover = async () => {
uploadError.value = "";
try {
const receipt = await pickAndUploadImage({
- requestController: createController,
+ requestController: coverUploadRequestController,
});
if (!pageActive) return;
coverOssId.value = receipt.ossId;
@@ -444,7 +342,7 @@ const uploadCover = async () => {
!isImagePickCancelled(error) &&
!isRequestCancelled(error)
) {
- uploadError.value = error?.message || "封面图片上传失败,请稍后重试";
+ uploadError.value = getRequestErrorMessage(error, "封面图片上传失败,请稍后重试");
}
} finally {
if (pageActive) isUploading.value = false;
@@ -452,43 +350,71 @@ const uploadCover = async () => {
};
const submitCreate = async () => {
- if (isSubmitting.value || isUploading.value || !validate()) return;
- const access = toApiGenealogyAccess(form.accessPreset);
- if (!access) {
- submitError.value = "访问规则无效,请重新选择";
- return;
+ if (isSubmitting.value || isUploading.value) return;
+ if (!createdGenealogyId.value && !validate()) return;
+
+ let createPayload = null;
+ let createAttempt = null;
+ if (!createdGenealogyId.value) {
+ const access = toApiGenealogyAccess(form.accessPreset);
+ if (!access) {
+ submitError.value = "请选择家谱开放方式";
+ return;
+ }
+ createPayload = {
+ surname: form.surname,
+ genealogyName: form.genealogyName,
+ regionCode: selectedRegion.value.regionCode,
+ ancestralHall: form.ancestralHall,
+ originPlace: form.originPlace,
+ addressDetail: form.addressDetail,
+ intro: form.intro,
+ coverOssId: coverOssId.value,
+ ...access,
+ };
+ createAttempt = genealogyCreateGuard.begin(createPayload);
+ if (createAttempt === null) {
+ submitError.value =
+ "上次创建结果暂时无法确认,请先返回“我的家谱”检查,避免重复创建。";
+ return;
+ }
}
isSubmitting.value = true;
submitError.value = "";
try {
- const created = await appApi.createGenealogy(
- {
- surname: form.surname,
- genealogyName: form.genealogyName,
- regionCode: selectedRegion.value.regionCode,
- ancestralHall: form.ancestralHall,
- originPlace: form.originPlace,
- addressDetail: form.addressDetail,
- intro: form.intro,
- coverOssId: coverOssId.value,
- ...access,
- },
- { requestController: createController },
- );
- if (!pageActive) return;
+ if (!createdGenealogyId.value) {
+ const created = await genealogyApi.createGenealogy(
+ createPayload,
+ { requestController: genealogyCreateRequestController },
+ );
+ if (!pageActive) return;
+ createdGenealogyId.value = created.id;
+ }
await finishPage(
"G01",
{},
{
operation: "genealogy-created",
- entityId: created.id,
+ entityId: createdGenealogyId.value,
refresh: true,
},
);
} catch (error) {
- if (!pageActive || isRequestCancelled(error)) return;
- submitError.value = error?.message || "创建失败,请稍后重试";
+ if (!pageActive) return;
+ if (
+ !createdGenealogyId.value &&
+ createAttempt &&
+ genealogyCreateGuard.recordFailure(createAttempt, error)
+ ) {
+ submitError.value =
+ "创建结果暂时无法确认,请先返回“我的家谱”检查,避免重复创建。";
+ return;
+ }
+ if (isRequestCancelled(error)) return;
+ submitError.value = createdGenealogyId.value
+ ? "家谱已经创建,但页面返回失败。请再次点击“返回我的家谱”,不要重复创建。"
+ : getRequestErrorMessage(error, "创建失败,请稍后重试");
} finally {
if (pageActive) isSubmitting.value = false;
}
@@ -496,8 +422,8 @@ const submitCreate = async () => {
onUnload(() => {
pageActive = false;
- createController.abort();
- regionController.abort();
+ coverUploadRequestController.abort();
+ genealogyCreateRequestController.abort();
discardConfirmation.dispose();
});
@@ -590,6 +516,13 @@ onUnload(() => {
text-align: right;
overflow-wrap: anywhere;
}
+.region-selector-chevron {
+ width: 28rpx;
+ height: 28rpx;
+ margin-left: 12rpx;
+ flex: 0 0 auto;
+ opacity: 0.7;
+}
.region-selector-value--placeholder {
color: #ab9a86;
}
@@ -644,7 +577,7 @@ onUnload(() => {
}
.upload-button {
justify-self: start;
- min-height: 60rpx;
+ min-height: 88rpx;
margin: 0;
padding: 0 20rpx;
border: 1rpx solid rgba(159, 23, 15, 0.42);
@@ -681,6 +614,11 @@ onUnload(() => {
}
.access-rule__option {
flex: 1;
+ display: flex;
+ min-height: 88rpx;
+ box-sizing: border-box;
+ align-items: center;
+ justify-content: center;
padding: 20rpx 12rpx;
border: 1rpx solid rgba(128, 89, 49, 0.34);
border-radius: 12rpx;
@@ -697,108 +635,4 @@ onUnload(() => {
.create-card .app-button {
margin-top: 32rpx;
}
-.region-sheet {
- position: fixed;
- z-index: 10;
- inset: 0;
- display: flex;
- align-items: flex-end;
-}
-.region-sheet__mask {
- position: absolute;
- inset: 0;
- background: rgba(43, 30, 20, 0.42);
-}
-.region-sheet__panel {
- position: relative;
- width: 100%;
- padding: 22rpx 28rpx calc(24rpx + env(safe-area-inset-bottom));
- border-radius: 30rpx 30rpx 0 0;
- background: #fdf9ef;
- box-shadow: 0 -12rpx 36rpx rgba(43, 30, 20, 0.2);
-}
-.region-sheet__intro {
- padding: 0 10rpx 16rpx;
- text-align: center;
-}
-.region-sheet__title {
- display: block;
-}
-.region-sheet__title {
- color: $ink;
- font-family: STKaiti, KaiTi, serif;
- font-size: clamp(19px, 36rpx, 24px);
- font-weight: 700;
-}
-.region-sheet__picker {
- overflow: hidden;
- border: 1rpx solid rgba(128, 89, 49, 0.28);
- border-radius: 16rpx;
- background: rgba(255, 252, 245, 0.8);
-}
-.region-sheet__column-headings {
- display: flex;
- height: 84rpx;
- border-bottom: 1rpx solid rgba(128, 89, 49, 0.18);
-}
-.region-sheet__column-heading {
- box-sizing: border-box;
- width: 33.333%;
- padding: 24rpx 12rpx;
- color: $ink-muted;
- font-size: clamp(16px, 26rpx, 20px);
- text-align: center;
-}
-.region-sheet__column-heading + .region-sheet__column-heading {
- border-left: 1rpx solid rgba(128, 89, 49, 0.16);
-}
-.region-sheet__picker-view {
- width: 100%;
- height: 520rpx;
-}
-.region-sheet__picker-item {
- box-sizing: border-box;
- height: 104rpx;
- overflow: hidden;
- padding: 0 6rpx;
- color: $ink-muted;
- font-size: clamp(16px, 26rpx, 20px);
- line-height: 104rpx;
- text-align: center;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.region-sheet__picker-item--selected {
- color: $brand-red;
- font-weight: 700;
-}
-.region-sheet__footer {
- display: flex;
- align-items: center;
- margin-top: 22rpx;
- gap: 12rpx;
-}
-.region-sheet__cancel {
- min-width: 116rpx;
- padding: 20rpx 10rpx;
- color: $ink-muted;
- font-size: clamp(16px, 28rpx, 20px);
- text-align: center;
-}
-.region-sheet__confirm {
- flex: 1;
- height: 82rpx;
- margin: 0;
- padding: 0;
- border: 0;
- border-radius: 10rpx;
- background: $brand-red;
- color: #fff;
- font-size: clamp(16px, 29rpx, 20px);
- font-weight: 700;
- line-height: 82rpx;
-}
-.region-sheet__confirm::after {
- display: none;
-}
diff --git a/pages/genealogy/g06-search-genealogies.vue b/pages/genealogy/g06-search-genealogies.vue
deleted file mode 100644
index d581c44..0000000
--- a/pages/genealogy/g06-search-genealogies.vue
+++ /dev/null
@@ -1,232 +0,0 @@
-
-
-
-
-
- 公开家谱以下结果来自服务端公开家谱列表。
-
- 暂时无法读取公开家谱
- 暂未找到公开家谱
-
-
- {{ item.name }}{{ item.surname }}氏
- {{
- item.location
- }}
- {{ item.intro }}
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/genealogy/g09-my-applications.vue b/pages/genealogy/g09-my-applications.vue
deleted file mode 100644
index 0c14e3f..0000000
--- a/pages/genealogy/g09-my-applications.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
-
-
- 暂时无法读取我的申请
- 暂无加入申请申请记录会直接从服务端读取。
- 已读取 {{ applications.length }} 条申请申请详情接口尚未开放,当前不会用本地数据补造申请内容。
-
-
-
-
-
-
-
diff --git a/pages/genealogy/g10-application-review.vue b/pages/genealogy/g10-application-review.vue
deleted file mode 100644
index c2148f6..0000000
--- a/pages/genealogy/g10-application-review.vue
+++ /dev/null
@@ -1,128 +0,0 @@
-
-
-
-
-
-
- 申请审核入口无效
-
- 暂时无法读取待审核申请
- 暂无待审核申请待审核记录会直接从服务端读取。
- 已读取 {{ applications.length }} 条待审核申请审核详情接口尚未开放,当前不会用本地数据补造申请内容或审核结果。
-
-
-
-
-
-
-
diff --git a/pages/genealogy/g12-generation-poems.vue b/pages/genealogy/generation-poems.vue
similarity index 73%
rename from pages/genealogy/g12-generation-poems.vue
rename to pages/genealogy/generation-poems.vue
index e78a2e9..13f2a76 100644
--- a/pages/genealogy/g12-generation-poems.vue
+++ b/pages/genealogy/generation-poems.vue
@@ -1,4 +1,3 @@
-
@@ -45,29 +44,37 @@
继续加载后续字辈(剩余 {{ remainingPoemCount }} 代)
-
+
{{ canManage ? "继续维护字辈诗" : "读取维护列表" }}
+ />{{ canManage ? "继续维护字辈诗" : "查看字辈列表" }}
- 服务端批量维护
- 录入完整字辈序列
+ 统一维护
+ 填写完整字辈
提交前会先请求服务端批量预览。无分隔符时每个字符对应一代;也可用空格、逗号、分号、顿号、斜杠或竖线分隔多字字辈。保存前可先查看调整结果。没有分隔符时,每个字对应一代;多个字可用空格、逗号、分号、顿号、斜杠或竖线分开。
字辈内容