Files
jiapuapp/pages/genealogy/g11-genealogy-settings.vue
T
2026-07-20 06:52:26 +08:00

437 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面编号G-11用途家谱设置公开范围与访问说明页面设计阶段使用本地模拟交互)。 -->
<template>
<view class="settings-page">
<GenealogyPageBackground />
<view class="settings-page__header"><PageHeader title="家谱设置" /></view>
<view
class="settings-panel"
:class="{
'settings-state--form': settingsState === 'form',
'settings-state--success': settingsState === 'success',
'settings-state--error': settingsState === 'error',
'settings-state--no-permission': settingsState === 'no-permission',
}"
>
<image
class="settings-panel__skin"
src="/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png"
mode="scaleToFill"
/>
<AppLoading
v-if="settingsState === 'loading'"
text="正在读取家谱设置"
description="请稍候,正在准备名称与访问规则。"
/>
<view v-else-if="settingsState === 'form'" class="settings-form">
<text class="settings-form__eyebrow">谱主可见 · 基础设置</text>
<text class="settings-form__title">完善家谱访问规则</text>
<text class="settings-form__copy"
>这里仅安排接口支持的名称公开范围与访问说明管理权转让将在成员选择场景中单独处理</text
>
<view class="settings-field">
<image
src="/static/assets/modules/genealogy/transparent/g-form-field-frame.png"
mode="scaleToFill"
/>
<text>家谱名称</text>
<input
v-model="genealogyDraft.name"
maxlength="20"
placeholder="请输入家谱名称"
placeholder-class="settings-placeholder"
@input="nameError = ''"
/>
</view>
<text v-if="nameError" class="settings-field-error">{{
nameError
}}</text>
<view class="visibility-block">
<text class="visibility-block__label">公开范围</text>
<view class="visibility-options">
<view
v-for="option in visibilityOptions"
:key="option.value"
class="visibility-option"
@click="genealogyDraft.visibility = option.value"
>
<image
:src="
genealogyDraft.visibility === option.value
? '/static/assets/foundation/transparent/a01-scroll-primary-v3.png'
: '/static/assets/foundation/transparent/a01-scroll-secondary-v3.png'
"
mode="aspectFit"
/>
<text
:class="{
'visibility-option__text--active':
genealogyDraft.visibility === option.value,
}"
>{{ option.label }}</text
>
</view>
</view>
<text class="visibility-block__hint">{{ visibilityHint }}</text>
</view>
<view class="settings-field settings-field--note">
<image
src="/static/assets/modules/genealogy/transparent/g-form-field-frame.png"
mode="scaleToFill"
/>
<text>访问说明</text>
<textarea
v-model="genealogyDraft.accessNote"
maxlength="80"
placeholder="向访问者说明家谱用途"
placeholder-class="settings-placeholder"
/>
</view>
<view class="settings-action" @click="saveSettings">
<image
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
mode="aspectFit"
/>
<text>保存设置</text>
</view>
</view>
<view v-else class="settings-result">
<text class="settings-result__eyebrow">{{
settingsState === "success"
? "设置已保存"
: settingsState === "no-permission"
? "权限不足"
: "设置未保存"
}}</text>
<text class="settings-result__title">{{
settingsState === "success"
? "新的访问规则已经生效"
: settingsState === "no-permission"
? "当前账号不能修改家谱"
: "暂时无法打开家谱设置"
}}</text>
<text class="settings-result__copy">{{
settingsState === "success"
? `${genealogyDraft.name} · ${visibilityLabel}`
: settingsState === "no-permission"
? "只有家谱所有者可以修改名称、公开范围和访问说明。"
: "请从家谱总览重新进入,当前修改不会被保留。"
}}</text>
<view class="settings-action" @click="settingsState = 'form'">
<image
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
mode="aspectFit"
/>
<text>{{
settingsState === "success" ? "继续调整" : "重新查看"
}}</text>
</view>
</view>
</view>
<view v-if="feedbackVisible" class="settings-feedback">
<image
src="/static/assets/foundation/transparent/a01-scroll-secondary-v3.png"
mode="aspectFit"
/>
<text>设置已保存</text>
</view>
</view>
</template>
<script setup>
import { computed, reactive, ref } from "vue";
import { onLoad, onUnload } from "@dcloudio/uni-app";
import AppLoading from "@/components/AppLoading.vue";
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
const genealogyId = ref("");
const settingsState = ref("loading");
const nameError = ref("");
const feedbackVisible = ref(false);
let feedbackTimer = null;
const genealogyDraft = reactive({
name: "汤氏家谱",
visibility: "MEMBER_ONLY",
accessNote: "家族资料,请妥善保存",
});
const visibilityOptions = [
{ value: "MEMBER_ONLY", label: "仅成员可见" },
{ value: "PUBLIC_APPLY", label: "公开可申请" },
];
const visibilityLabel = computed(
() =>
visibilityOptions.find((item) => item.value === genealogyDraft.visibility)
?.label || "",
);
const visibilityHint = computed(() =>
genealogyDraft.visibility === "MEMBER_ONLY"
? "只有已加入本家谱的成员可以查看谱系和家族资料。"
: "访客可检索到家谱并提交入谱申请,资料仍需审核后查看。",
);
onLoad((query) => {
genealogyId.value = query.genealogyId || "";
settingsState.value =
query.state === "loading"
? "loading"
: query.state === "success"
? "success"
: query.state === "no-permission"
? "no-permission"
: query.state === "error" || !genealogyId.value
? "error"
: "form";
});
onUnload(() => {
if (feedbackTimer) clearTimeout(feedbackTimer);
});
const saveSettings = () => {
if (!genealogyDraft.name.trim()) {
nameError.value = "请填写家谱名称";
return;
}
settingsState.value = "success";
feedbackVisible.value = true;
feedbackTimer = setTimeout(() => {
feedbackVisible.value = false;
feedbackTimer = null;
}, 1800);
};
</script>
<style scoped lang="scss">
.settings-page {
position: relative;
min-height: 100vh;
overflow-x: hidden;
background: $paper;
}
.settings-page__header {
position: relative;
z-index: 3;
}
.settings-panel {
position: relative;
z-index: 2;
width: calc(100% - 32rpx);
height: min(620px, calc((100vw - 16px) * 1.43));
margin: 18rpx auto 0;
}
.settings-panel__skin {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.settings-form {
position: absolute;
inset: 7.5% 8%;
}
.settings-form__eyebrow,
.settings-result__eyebrow {
display: block;
color: $brand-red;
font-size: 23rpx;
letter-spacing: 3rpx;
}
.settings-form__title,
.settings-result__title {
display: block;
margin-top: 10rpx;
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 35rpx;
font-weight: 700;
}
.settings-form__copy,
.settings-result__copy {
display: block;
margin-top: 10rpx;
color: $ink-muted;
font-size: 24rpx;
line-height: 1.55;
}
.settings-field {
position: relative;
height: 92rpx;
margin-top: 17rpx;
}
.settings-field > image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.settings-field > text {
position: absolute;
top: 31rpx;
left: 24rpx;
z-index: 1;
color: $ink;
font-size: 24rpx;
font-weight: 700;
}
.settings-field input,
.settings-field textarea {
position: absolute;
top: 0;
right: 20rpx;
bottom: 0;
left: 164rpx;
z-index: 1;
height: 92rpx;
color: $ink;
font-size: 24rpx;
line-height: 92rpx;
}
.settings-field textarea {
box-sizing: border-box;
padding-top: 26rpx;
line-height: 1.5;
}
.settings-placeholder {
color: #a79884;
}
.settings-field-error {
display: block;
margin-top: 3rpx;
color: $brand-red;
font-size: 24rpx;
line-height: 34rpx;
text-align: right;
}
.visibility-block {
margin-top: 17rpx;
}
.visibility-block__label {
display: block;
color: $ink;
font-size: 24rpx;
font-weight: 700;
}
.visibility-options {
display: flex;
gap: 14rpx;
margin-top: 10rpx;
}
.visibility-option {
position: relative;
width: calc(50% - 7rpx);
height: 64rpx;
}
.visibility-option image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.visibility-option text {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: $ink;
font-size: 24rpx;
font-weight: 700;
}
.visibility-option .visibility-option__text--active {
color: #fff9ed;
}
.visibility-block__hint {
display: block;
margin-top: 9rpx;
color: $ink-muted;
font-size: 22rpx;
line-height: 1.45;
}
.settings-field--note {
margin-top: 14rpx;
}
.settings-action {
position: relative;
width: 100%;
height: 78rpx;
margin-top: 19rpx;
}
.settings-action image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.settings-action text {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: #fff9ed;
font-size: 26rpx;
font-weight: 700;
letter-spacing: 3rpx;
}
.settings-result {
position: absolute;
top: 29%;
right: 12%;
left: 12%;
text-align: center;
}
.settings-result__eyebrow {
text-align: center;
}
.settings-result__copy {
margin-top: 22rpx;
}
.settings-result .settings-action {
width: 420rpx;
max-width: 100%;
margin: 34rpx auto 0;
}
.settings-feedback {
position: fixed;
z-index: 30;
top: 138rpx;
left: 50%;
display: flex;
min-width: 240rpx;
min-height: 74rpx;
align-items: center;
justify-content: center;
padding: 0 34rpx;
transform: translateX(-50%);
}
.settings-feedback image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.settings-feedback text {
position: relative;
z-index: 1;
color: $ink;
font-size: 22rpx;
}
@media (min-width: 400px) {
.settings-panel {
width: calc(100% - 48rpx);
}
.settings-form {
right: 9%;
left: 9%;
}
}
</style>