日程详情:只读日历不再给「编辑日程」入口 laoyang/FamilyBook#31
真机(DEL-AL20 / HarmonyOS 7.0.0.109)实测发现:只读共享本(如「工作学习」) 里的日程,首页详情卡仍显示「编辑日程」,用户改完点保存才被服务端拒: 「保存失败:这本日历你没有写权限。」 根因是 canEdit 写死 true,只判了 isEditableEvent(kind/id/calId), 没判这本日历能不能写。 - Types.ets 新增 isEventWritable(e, books):复用 FbCalBook.canWrite 口径 (由 FbCalRepo.fetchBooks 依 /calendar/books 的 kind+perm 算出), 不与写权限推导逻辑重复;books 缺失时判为不可编辑(宁可少给入口) - FbHomePage:canEdit 由写死 true 改为按写权限判定; openEvent 里顺手预加载 calBooks(原本懒加载,进详情时还是空数组, 会把本来能编辑的日程也误判成只读) - FbCalendarPage:同步改用 isEventWritable,两处口径一致 真机复验:只读日程详情只剩「导航」;有权限的日程「编辑日程」正常, 改标题保存后杀进程重启仍在(确认真落库)。
This commit is contained in:
@@ -641,6 +641,36 @@ export function isEditableEvent(e: FbCalEvent): boolean {
|
|||||||
return e.kind === 'custom' && e.id > 0 && e.calId > 0;
|
return e.kind === 'custom' && e.id > 0 && e.calId > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个日程**现在能不能真的改**(决定详情卡要不要给「编辑日程」入口)。
|
||||||
|
*
|
||||||
|
* 🔴 2026-10-29 真机实测发现的问题(工单 laoyang/FamilyBook#31):
|
||||||
|
* 首页只判了 `isEditableEvent()`(kind/id/calId),**没判写权限**,
|
||||||
|
* 于是「工作学习」这种只读共享本里的日程照样显示「编辑日程」,
|
||||||
|
* 用户改完点保存才被服务端拒:「保存失败:这本日历你没有写权限。」
|
||||||
|
* ⇒ 能做什么要在**入口处**就说清,不能让用户白改一遍。
|
||||||
|
*
|
||||||
|
* 写权限口径与 `FbCalRepo.fetchBooks()` 一致(它按 `/calendar/books` 的
|
||||||
|
* `kind` + `perm` 算出 `FbCalBook.canWrite`),这里直接复用那个布尔值,
|
||||||
|
* 不再自行推导,避免两处漂移。
|
||||||
|
*
|
||||||
|
* @param e 要判定的日程
|
||||||
|
* @param books 当前账号的日历本列表(拿不到时**判为不可编辑**,
|
||||||
|
* 宁可少给入口,也不让用户改完才报错)
|
||||||
|
*/
|
||||||
|
export function isEventWritable(e: FbCalEvent, books: FbCalBook[]): boolean {
|
||||||
|
if (!isEditableEvent(e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const b of books) {
|
||||||
|
if (b.id === e.calId) {
|
||||||
|
return b.canWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 找不到这本 ⇒ 不认(可能是权限被撤、本被删,或 books 还没加载完) */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** 日历本(calendar/calendars) */
|
/** 日历本(calendar/calendars) */
|
||||||
export interface FbCalBook {
|
export interface FbCalBook {
|
||||||
id: number;
|
id: number;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { common } from '@kit.AbilityKit';
|
|||||||
import { BusinessError } from '@kit.BasicServicesKit';
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||||
import { FbAppState, fbAppState } from '../../common/Store';
|
import { FbAppState, fbAppState } from '../../common/Store';
|
||||||
import { FbCalBook, FbCalEvent, isEditableEvent } from '../../model/Types';
|
import { FbCalBook, FbCalEvent, isEditableEvent, isEventWritable } from '../../model/Types';
|
||||||
import { parseCalendar } from '../../data/FbParse';
|
import { parseCalendar } from '../../data/FbParse';
|
||||||
import { loadModule } from '../../data/FbModuleLoad';
|
import { loadModule } from '../../data/FbModuleLoad';
|
||||||
import { FbCalRepo, FbCalEventFull } from '../../data/FbCalRepo';
|
import { FbCalRepo, FbCalEventFull } from '../../data/FbCalRepo';
|
||||||
@@ -899,7 +899,11 @@ export struct FbCalendarPage {
|
|||||||
accent: this.accent,
|
accent: this.accent,
|
||||||
bookName: this.detailBase !== null ? this.detailBase.calName : '',
|
bookName: this.detailBase !== null ? this.detailBase.calName : '',
|
||||||
bookColor: this.detailBase !== null ? this.detailBase.color : '#9AA0A6',
|
bookColor: this.detailBase !== null ? this.detailBase.color : '#9AA0A6',
|
||||||
canEdit: this.detailBase !== null && isEditableEvent(this.detailBase),
|
/* 🔴 2026-10-29(工单 laoyang/FamilyBook#31):原来只判 `isEditableEvent`
|
||||||
|
(kind/id/calId),**没判写权限** ⇒ 只读共享本里的日程也给「编辑日程」,
|
||||||
|
用户改完点保存才报「这本日历你没有写权限」。改为按本的可写性判定。
|
||||||
|
本页 `books` 在页面加载时就拉了(见 `loadBooks`),不会出现空数组误判。 */
|
||||||
|
canEdit: this.detailBase !== null && isEventWritable(this.detailBase, this.books),
|
||||||
onNavigate: (): void => {
|
onNavigate: (): void => {
|
||||||
this.navigateDetail();
|
this.navigateDetail();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import { FbColors, FbMetric, FB_MASK } from '../../common/Theme';
|
|||||||
import { FbAppState, fbAppState } from '../../common/Store';
|
import { FbAppState, fbAppState } from '../../common/Store';
|
||||||
import { FbCalEvent, FbCalBook, FbCatOpt, FbHomeData, FbMark, FbMemoryItem, FbRecentDay,
|
import { FbCalEvent, FbCalBook, FbCatOpt, FbHomeData, FbMark, FbMemoryItem, FbRecentDay,
|
||||||
FbTaskItem, FbBoardOpt, FbTaskDetail, FbTaskMeta, taskKey,
|
FbTaskItem, FbBoardOpt, FbTaskDetail, FbTaskMeta, taskKey,
|
||||||
FbWeather, isEditableEvent } from '../../model/Types';
|
FbWeather, isEditableEvent, isEventWritable } from '../../model/Types';
|
||||||
import { common } from '@kit.AbilityKit';
|
import { common } from '@kit.AbilityKit';
|
||||||
import { BusinessError } from '@kit.BasicServicesKit';
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||||
@@ -413,6 +413,16 @@ export struct FbHomePage {
|
|||||||
this.evtBase = e;
|
this.evtBase = e;
|
||||||
this.evtFull = null;
|
this.evtFull = null;
|
||||||
this.evtError = '';
|
this.evtError = '';
|
||||||
|
/* 🔴 2026-10-29(工单 #31):详情卡的「编辑日程」按 `calBooks[calId].canWrite` 判定,
|
||||||
|
而 `calBooks` 原本是懒加载(只在新建/编辑时才拉)⇒ 刚进详情时它还是空数组,
|
||||||
|
会把**本来能编辑**的日程也误判成只读。
|
||||||
|
这里顺手拉一次(拉过就复用,`ensureCalBooks` 内部有缓存判断),
|
||||||
|
不 await —— 详情内容先出来,按钮随 books 到位再显示,不拖慢打开速度。 */
|
||||||
|
if (this.calBooks.length === 0) {
|
||||||
|
this.ensureCalBooks().catch((): void => {
|
||||||
|
/* 拉不到就维持"不给编辑入口",比让用户白改一遍好 */
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!isEditableEvent(e)) {
|
if (!isEditableEvent(e)) {
|
||||||
this.evtLoading = false;
|
this.evtLoading = false;
|
||||||
this.evtFull = this.shellOf(e);
|
this.evtFull = this.shellOf(e);
|
||||||
@@ -1498,7 +1508,13 @@ export struct FbHomePage {
|
|||||||
那个理由成立,但**结论错了** —— 正确解法不是"不给编辑",
|
那个理由成立,但**结论错了** —— 正确解法不是"不给编辑",
|
||||||
而是"编辑也不许跳"(与 v79 任务面板的处理完全一致)。
|
而是"编辑也不许跳"(与 v79 任务面板的处理完全一致)。
|
||||||
现在点「编辑」只在本页叠一张表单,卡片不动、模块不动。 */
|
现在点「编辑」只在本页叠一张表单,卡片不动、模块不动。 */
|
||||||
canEdit: true,
|
/* 🔴 2026-10-29 真机实测修(工单 laoyang/FamilyBook#31):
|
||||||
|
原来这里写死 `true`,于是**只读共享本**(如「工作学习」)里的日程
|
||||||
|
也显示「编辑日程」,用户改完点保存才被服务端拒
|
||||||
|
「保存失败:这本日历你没有写权限。」
|
||||||
|
v86 开编辑入口的决定本身没错(编辑就地改、不跳页),
|
||||||
|
错在没把"没有写权限的本"排除掉 ⇒ 改为按 calWrite 判定。 */
|
||||||
|
canEdit: this.evtBase !== null && isEventWritable(this.evtBase, this.calBooks),
|
||||||
onNavigate: (): void => {
|
onNavigate: (): void => {
|
||||||
this.navigateEvent();
|
this.navigateEvent();
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user