feat: 完成前端业务闭环与后端联调
This commit is contained in:
+120
-4
@@ -89,6 +89,13 @@
|
||||
label="移出家谱"
|
||||
@click="openConfirmation('remove', member)"
|
||||
/>
|
||||
<AppButton
|
||||
v-if="isOwnerViewer && member.roleType === GENEALOGY_MEMBER_ROLE.ADMIN"
|
||||
compact
|
||||
type="secondary"
|
||||
label="权限设置"
|
||||
@click="openPermissionEditor(member)"
|
||||
/>
|
||||
<AppButton
|
||||
v-if="member.capabilities.canLeave"
|
||||
compact
|
||||
@@ -159,6 +166,18 @@
|
||||
>
|
||||
<text v-if="operationError" class="edit-error" role="alert">{{ operationError }}</text>
|
||||
</AppDialog>
|
||||
<AppDialog :visible="Boolean(permissionTarget)" eyebrow="管理员权限" :title="`设置${permissionTarget?.memberName || '成员'}的权限`" :confirm-text="permissionSaving ? '正在保存' : '保存权限'" cancel-text="取消" show-cancel :close-on-mask="!permissionSaving" @confirm="savePermissions" @cancel="closePermissionEditor">
|
||||
<AppLoading v-if="permissionLoading" text="正在读取权限目录" />
|
||||
<view v-else-if="permissionOptions.length" class="permission-list">
|
||||
<label v-for="option in permissionOptions" :key="option.code" class="permission-item" :class="{ 'permission-item--disabled': !option.enabled }">
|
||||
<checkbox :checked="selectedPermissionCodes.includes(option.code)" :disabled="!option.enabled || permissionSaving" @click="togglePermission(option)" />
|
||||
<view><text>{{ option.label }}</text><text v-if="option.description">{{ option.description }}</text></view>
|
||||
</label>
|
||||
</view>
|
||||
<text v-else-if="!permissionError" class="edit-hint">当前没有可授权的权限项。</text>
|
||||
<textarea v-model.trim="permissionReason" maxlength="200" placeholder="授权原因(可选)" class="permission-reason" />
|
||||
<text v-if="permissionError" class="edit-error">{{ permissionError }}</text>
|
||||
</AppDialog>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -179,6 +198,7 @@ import {
|
||||
isRequestCancelled
|
||||
} from "@/services/api/request-controller.js";
|
||||
import { genealogyMemberApi } from "@/services/api/genealogy-member-service.js";
|
||||
import { genealogyCapabilityApi } from "@/services/api/genealogy-capability-service.js";
|
||||
import { lineageApi } from "@/services/api/lineage-service.js";
|
||||
import { getRequestErrorMessage } from "@/services/api/request-error-message.js";
|
||||
import { formatMinuteTimestamp } from "@/utils/display-time.js";
|
||||
@@ -198,6 +218,17 @@ const hasLeftGenealogy = ref(false);
|
||||
const personOptions = ref([]);
|
||||
const personOptionsState = ref("idle");
|
||||
const memberListController = createRequestController();
|
||||
const permissionTarget = ref(null);
|
||||
const selectedPermissionCodes = ref([]);
|
||||
const permissionReason = ref("");
|
||||
const permissionSaving = ref(false);
|
||||
const permissionLoading = ref(false);
|
||||
const permissionError = ref("");
|
||||
const permissionOptions = ref([]);
|
||||
const permissionCatalogController = createRequestController();
|
||||
const memberPermissionController = createRequestController();
|
||||
const memberPermissionSaveController = createRequestController();
|
||||
let permissionLoadSequence = 0;
|
||||
const personOptionsController = createRequestController();
|
||||
const memberUpdateController = createRequestController();
|
||||
const membershipOperationController = createRequestController();
|
||||
@@ -470,12 +501,86 @@ const returnToOverview = () =>
|
||||
hasLeftGenealogy.value
|
||||
? returnTo("G01")
|
||||
: returnTo("G05", { genealogyId: genealogyId.value });
|
||||
const openPermissionEditor = async (member) => {
|
||||
const activeLoad = ++permissionLoadSequence;
|
||||
permissionCatalogController.abort();
|
||||
memberPermissionController.abort();
|
||||
permissionTarget.value = member;
|
||||
permissionOptions.value = [];
|
||||
selectedPermissionCodes.value = [];
|
||||
permissionReason.value = "";
|
||||
permissionError.value = "";
|
||||
permissionLoading.value = true;
|
||||
try {
|
||||
const catalog = await genealogyCapabilityApi.getPermissionCatalog(
|
||||
genealogyId.value,
|
||||
{ requestController: permissionCatalogController },
|
||||
);
|
||||
const enabledCodes = catalog.filter((option) => option.enabled).map((option) => option.code);
|
||||
const permissions = await genealogyCapabilityApi.getMemberPermissions(
|
||||
genealogyId.value,
|
||||
member.memberId,
|
||||
enabledCodes,
|
||||
{ requestController: memberPermissionController },
|
||||
);
|
||||
if (!isPageActive || activeLoad !== permissionLoadSequence) return;
|
||||
permissionOptions.value = catalog;
|
||||
selectedPermissionCodes.value = permissions.permissionCodes;
|
||||
} catch (error) {
|
||||
if (!isPageActive || activeLoad !== permissionLoadSequence || isRequestCancelled(error)) return;
|
||||
permissionError.value = getRequestErrorMessage(error, "权限目录暂时无法读取,当前不会保存任何变更。");
|
||||
} finally {
|
||||
if (isPageActive && activeLoad === permissionLoadSequence) permissionLoading.value = false;
|
||||
}
|
||||
};
|
||||
const closePermissionEditor = () => {
|
||||
if (permissionSaving.value) return;
|
||||
permissionLoadSequence += 1;
|
||||
permissionCatalogController.abort();
|
||||
memberPermissionController.abort();
|
||||
permissionTarget.value = null;
|
||||
permissionLoading.value = false;
|
||||
};
|
||||
const togglePermission = (option) => {
|
||||
if (!option?.enabled || permissionSaving.value || permissionLoading.value) return;
|
||||
selectedPermissionCodes.value = selectedPermissionCodes.value.includes(option.code)
|
||||
? selectedPermissionCodes.value.filter((code) => code !== option.code)
|
||||
: [...selectedPermissionCodes.value, option.code];
|
||||
};
|
||||
const savePermissions = async () => {
|
||||
if (!permissionTarget.value || permissionSaving.value || permissionLoading.value || permissionError.value) return;
|
||||
const enabledCodes = permissionOptions.value.filter((option) => option.enabled).map((option) => option.code);
|
||||
permissionSaving.value = true;
|
||||
permissionError.value = "";
|
||||
try {
|
||||
await genealogyCapabilityApi.saveMemberPermissions(
|
||||
genealogyId.value,
|
||||
permissionTarget.value.memberId,
|
||||
selectedPermissionCodes.value,
|
||||
permissionReason.value,
|
||||
enabledCodes,
|
||||
{ requestController: memberPermissionSaveController },
|
||||
);
|
||||
if (!isPageActive) return;
|
||||
feedbackMessage.value = "管理员权限已保存";
|
||||
permissionTarget.value = null;
|
||||
} catch (error) {
|
||||
if (!isPageActive || isRequestCancelled(error)) return;
|
||||
permissionError.value = getRequestErrorMessage(error, "权限保存失败,请稍后重试。");
|
||||
} finally {
|
||||
if (isPageActive) permissionSaving.value = false;
|
||||
}
|
||||
};
|
||||
const requestBack = () =>
|
||||
runBackGuard({
|
||||
transientOpen: Boolean(editTarget.value || confirmTarget.value),
|
||||
submitting: operationPending.value,
|
||||
transientOpen: Boolean(editTarget.value || confirmTarget.value || permissionTarget.value),
|
||||
submitting: operationPending.value || permissionSaving.value,
|
||||
"close-transient": () =>
|
||||
editTarget.value ? closeEdit() : closeConfirmation(),
|
||||
editTarget.value
|
||||
? closeEdit()
|
||||
: confirmTarget.value
|
||||
? closeConfirmation()
|
||||
: closePermissionEditor(),
|
||||
"block-submitting": () => true,
|
||||
});
|
||||
|
||||
@@ -500,6 +605,9 @@ onUnload(() => {
|
||||
personOptionsController.abort();
|
||||
memberUpdateController.abort();
|
||||
membershipOperationController.abort();
|
||||
permissionCatalogController.abort();
|
||||
memberPermissionController.abort();
|
||||
memberPermissionSaveController.abort();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -518,7 +626,7 @@ onUnload(() => {
|
||||
}
|
||||
|
||||
.page-content {
|
||||
padding: 18rpx 24rpx 72rpx;
|
||||
padding: 18rpx 24rpx calc(72rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.state-card,
|
||||
@@ -725,4 +833,12 @@ onUnload(() => {
|
||||
.edit-error {
|
||||
color: $brand-red;
|
||||
}
|
||||
|
||||
.permission-list { margin-top: 18rpx; }
|
||||
.permission-item { display: flex; min-height: 76rpx; align-items: flex-start; padding: 18rpx 0; border-bottom: 1rpx solid rgba($gold, 0.38); color: $ink; font-size: 26rpx; }
|
||||
.permission-item checkbox { margin-right: 16rpx; }
|
||||
.permission-item view { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 6rpx; }
|
||||
.permission-item view text:last-child:not(:first-child) { color: $ink-muted; font-size: 22rpx; line-height: 1.45; }
|
||||
.permission-item--disabled { opacity: 0.54; }
|
||||
.permission-reason { width: 100%; min-height: 100rpx; margin-top: 18rpx; padding: 16rpx; box-sizing: border-box; border: 1rpx solid rgba($gold, 0.38); border-radius: 10rpx; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user