CMS React Components (CMS React 元件)
Overview
@rytass/cms-react-components 提供基於 Mezzanine UI 的 CMS 管理介面元件,支援文章生命週期管理、權限控制和審核流程。
Quick Start
安裝
npm install @rytass/cms-react-components @mezzanine-ui/react @mezzanine-ui/core
Provider 設定
import { DialogProvider, ModalProvider } from '@rytass/cms-react-components';
function App() { return ( <DialogProvider> <ModalProvider> <YourCMSApp /> </ModalProvider> </DialogProvider> ); }
Core Components
StandardCMSTable
進階資料表格,支援排序、過濾、分頁、批次操作:
import { StandardCMSTable, ArticleStage, ArticlesPermissions, ArticleTableActions, } from '@rytass/cms-react-components';
const ArticleList = () => { const columns = [ { title: '標題', dataIndex: 'title' }, { title: '建立時間', dataIndex: 'createdAt' }, { title: '狀態', dataIndex: 'stage' }, ];
return (
<StandardCMSTable<Article>
columns={columns}
dataSource={articles}
currentStage={ArticleStage.DRAFT}
userPermissions={[
ArticlesPermissions.CreateArticle,
ArticlesPermissions.UpdateArticleInDraft,
ArticlesPermissions.DeleteArticleInDraft,
ArticlesPermissions.SubmitPutBackArticle,
]}
// 可選:自訂各階段可用操作
actions={{
[ArticleStage.DRAFT]: [
ArticleTableActions.Update,
ArticleTableActions.Submit,
ArticleTableActions.Delete,
],
}}
actionsEvents={{
onView: async (article) => router.push(/articles/${article.id}),
onSubmit: async (article) => await submitArticle(article.id),
onDelete: async (article) => await deleteArticle(article.id),
onPutBack: async (article) => await putBackArticle(article.id),
onRelease: async (article, releasedAt) => await releaseArticle(article.id, releasedAt),
onWithdraw: async (article) => await withdrawArticle(article.id),
onApprove: async (article) => await approveArticle(article.id),
onReject: async (article, reason) => await rejectArticle(article.id, reason),
}}
/>
);
};
StandardCMSFormActions
表單操作按鈕,根據權限和階段顯示:
import { StandardCMSFormActions, ArticleStage, ArticlesPermissions, } from '@rytass/cms-react-components'; import { useForm } from 'react-hook-form';
interface ArticleFormData { title: string; content: string; }
const ArticleForm = () => { const methods = useForm<ArticleFormData>();
return ( <StandardCMSFormActions<ArticleFormData> methods={methods} // react-hook-form 的 UseFormReturn currentStage={ArticleStage.DRAFT} // 當前文章階段 userPermissions={[ // 使用者權限 ArticlesPermissions.CreateArticle, ArticlesPermissions.UpdateArticleInDraft, ArticlesPermissions.SubmitPutBackArticle, ]} createMode={true} // 建立模式 (vs 編輯模式) actionsEvents={{ // 建立模式下的操作 onCreateToDraft: async (data) => await saveToDraft(data), onCreateAndSubmit: async (data) => await createAndSubmit(data), onCreateAndRelease: async (data, releasedAt) => { await createAndRelease(data, releasedAt); }, onCreateAndApprove: async (data) => await createAndApprove(data),
// 編輯模式下的操作
onUpdateToDraft: async (data) => await updateToDraft(data),
onUpdateAndSubmit: async (data) => await updateAndSubmit(data),
onUpdateAndRelease: async (data, releasedAt) => {
await updateAndRelease(data, releasedAt);
},
onUpdateAndApprove: async (data) => await updateAndApprove(data),
// 通用操作
onSubmit: async (data) => await submitForReview(data),
onRelease: async (data, releasedAt) => await release(data, releasedAt),
onApprove: async (data) => await approve(data),
onReject: async (data, reason) => await reject(data, reason),
onLeave: async (data) => router.back(),
onGoToEdit: async (data) => router.push(`/articles/${data.id}/edit`),
}}
leaveButtonText="返回列表" // 可選:自訂離開按鈕文字
actionButtonText="儲存草稿" // 可選:自訂操作按鈕文字
submitButtonText="送審" // 可選:自訂送出按鈕文字
disableLeaveButton={(values) => methods.formState.isSubmitting}
disableActionButton={(values) => !values.title}
disableSubmitButton={(values) => !values.title || !values.content}
>
{/* 表單欄位 */}
<input {...methods.register('title')} placeholder="標題" />
<textarea {...methods.register('content')} placeholder="內容" />
</StandardCMSFormActions>
); };
StandardCMSFormActionsProps:
屬性 型別 必填 說明
methods
UseFormReturn<T>
是 react-hook-form 的表單方法
currentStage
ArticleStage
是 當前文章階段
userPermissions
ArticlesPermissions[]
是 使用者權限
actionsEvents
StandardCMSFormActionsEventsProps<T>
是 各操作回調函式
createMode
boolean
否 是否為建立模式(影響顯示的按鈕)
children
ReactNode
是 表單內容
className
string
否 容器 className
actionsClassName
string
否 按鈕區 className
leaveButtonText
string
否 離開按鈕文字
actionButtonText
string
否 操作按鈕文字
submitButtonText
string
否 送出按鈕文字
disableLeaveButton
(values: T) => boolean
否 離開按鈕禁用條件
disableActionButton
(values: T) => boolean
否 操作按鈕禁用條件
disableSubmitButton
(values: T) => boolean
否 送出按鈕禁用條件
onLeave
(values: T) => Promise<void>
否 離開按鈕事件(優先於 actionsEvents.onLeave)
onAction
(values: T) => Promise<void>
否 操作按鈕事件
onSubmit
(values: T) => Promise<void>
否 送出按鈕事件(優先於 actionsEvents.onSubmit)
StandardCMSList
整合 Tabs + Table 的完整文章列表元件:
import { StandardCMSList, ArticleStage, ArticlesPermissions, } from '@rytass/cms-react-components';
const ArticleManagement = () => {
return (
<StandardCMSList<Article>
columns={columns}
dataSource={articles}
defaultStage={ArticleStage.DRAFT}
userPermissions={[
ArticlesPermissions.CreateArticle,
ArticlesPermissions.UpdateArticleInDraft,
ArticlesPermissions.DeleteArticleInDraft,
]}
onTabChange={(stage) => {
// 切換 Tab 時重新載入資料
fetchArticles(stage);
}}
tabsNaming={{
[ArticleStage.DRAFT]: '草稿區',
[ArticleStage.REVIEWING]: '待審核',
[ArticleStage.VERIFIED]: '可發佈',
[ArticleStage.SCHEDULED]: '已預約',
[ArticleStage.RELEASED]: '已發佈',
}}
actionsEvents={{
onView: (article) => router.push(/articles/${article.id}),
onSubmit: async (article) => await submitArticle(article.id),
onDelete: async (article) => await deleteArticle(article.id),
}}
/>
);
};
StandardCMSListProps:
繼承 StandardCMSTableProps (除了 currentStage ),額外提供:
屬性 型別 必填 說明
defaultStage
ArticleStage
否 預設 Tab(預設 DRAFT )
onTabChange
(stage: ArticleStage) => void
否 Tab 切換回調
tabsNaming
{ [key in ArticleStage]?: string }
否 自訂 Tab 名稱
tableClassName
string
否 Table 自訂 className
StandardCMSTabs
獨立使用的文章狀態 Tabs:
import { StandardCMSTabs, ArticleStage } from '@rytass/cms-react-components';
const [activeStage, setActiveStage] = useState(ArticleStage.DRAFT);
<StandardCMSTabs activeStage={activeStage} onChange={(stage) => setActiveStage(stage)} tabsNaming={{ [ArticleStage.RELEASED]: '已發佈', [ArticleStage.SCHEDULED]: '已預約', [ArticleStage.VERIFIED]: '可發佈', [ArticleStage.REVIEWING]: '待審核', [ArticleStage.DRAFT]: '草稿區', }} />
StandardCMSTabsProps:
屬性 型別 必填 說明
activeStage
ArticleStage
是 當前選中的階段
onChange
(stage: ArticleStage) => void
是 Tab 切換回調
tabsNaming
{ [key in ArticleStage]?: string }
否 自訂 Tab 名稱
預設 Tab 順序: 已發佈 → 已預約 → 可發佈 → 待審核 → 草稿區
Modals
DeleteWithdrawModal
刪除/撤下選擇對話框(讓使用者選擇要刪除還是撤下):
import { useModal, DeleteWithdrawModal, DeleteWithdrawModalRadio, } from '@rytass/cms-react-components';
const { openModal } = useModal();
openModal({ children: ( <DeleteWithdrawModal showSeverityIcon={false} defaultRadioValue={DeleteWithdrawModalRadio.Withdraw} withDelete={true} withWithdraw={true} onDelete={async () => { await deleteArticle(id); // closeModal() 由元件內部自動呼叫 }} onWithdraw={async () => { await withdrawArticle(id); // closeModal() 由元件內部自動呼叫 }} /> ), });
DeleteWithdrawModalProps:
屬性 型別 必填 說明
showSeverityIcon
boolean
否 顯示警告圖示(預設 false )
defaultRadioValue
DeleteWithdrawModalRadio
是 預設選項
withDelete
boolean
否 顯示「永久刪除」選項
withWithdraw
boolean
否 顯示「移至可發佈區」選項
onDelete
() => Promise<void>
是 刪除回調
onWithdraw
() => Promise<void>
是 撤下回調
DeleteWithdrawModalRadio:
enum DeleteWithdrawModalRadio { Delete = 'Delete', // 永久刪除 Withdraw = 'Withdraw', // 撤下至可發佈區 }
RejectModal
審核拒絕對話框(含理由輸入):
import { useModal, RejectModal } from '@rytass/cms-react-components';
const { openModal } = useModal();
openModal({ children: ( <RejectModal onReject={async (reason) => { await rejectArticle(id, reason); // closeModal() 由元件內部自動呼叫 }} /> ), });
RejectModalProps:
屬性 型別 必填 說明
onReject
(reason: string) => Promise<void>
是 拒絕回調,帶入使用者輸入的不通過原因
注意: RejectModal 會自動顯示「審核不通過」標題和說明文字,使用者必須輸入不通過原因才能送出。Modal 會在 onReject 完成後自動關閉。
VerifyReleaseModal
發佈/審核多功能對話框:
import { useModal, VerifyReleaseModal, VerifyReleaseModalRadio, } from '@rytass/cms-react-components';
openModal({ children: ( <VerifyReleaseModal title="發佈文章" showSeverityIcon={false} defaultRadioValue={VerifyReleaseModalRadio.Now} withApprove={true} withReject={true} onRelease={async (releasedAt: string) => { await releaseArticle(id, releasedAt); }} onApprove={async () => { await approveArticle(id); }} onReject={async (reason: string) => { await rejectArticle(id, reason); }} /> ), });
VerifyReleaseModalProps:
屬性 型別 必填 說明
title
string
是 Modal 標題
showSeverityIcon
boolean
否 顯示警告圖示
defaultRadioValue
VerifyReleaseModalRadio
否 預設選項(預設 Now )
withApprove
boolean
否 顯示「即刻通過」選項
withReject
boolean
否 顯示「不通過」選項
onRelease
(releasedAt: string) => Promise<void>
是 發佈回調(ISO 格式時間)
onApprove
() => Promise<void>
否 通過審核回調
onReject
(reason: string) => Promise<void>
否 拒絕審核回調
LogsModal
版本歷史與稽核日誌:
import { useModal, LogsModal, LogsStageData, ArticleStage } from '@rytass/cms-react-components';
const { openModal } = useModal();
// 定義取得日誌資料的函式 const fetchLogsData = async (): Promise<LogsStageData> => { // 從 API 或其他來源取得文章各階段的日誌資料 return { [ArticleStage.DRAFT]: { createdAt: '2024-01-01T00:00:00Z', createdBy: '王小明', updatedAt: '2024-01-02T10:00:00Z', updatedBy: '王小明', submittedAt: '', submittedBy: '', verifiedAt: '', verifiedBy: '', releasedAt: '', releasedBy: '', version: 1, }, [ArticleStage.REVIEWING]: { createdAt: '', createdBy: '', updatedAt: '', updatedBy: '', submittedAt: '2024-01-03T09:00:00Z', submittedBy: '王小明', verifiedAt: '', verifiedBy: '', releasedAt: '', releasedBy: '', version: 2, }, // ... 其他階段 }; };
openModal({ children: ( <LogsModal onGetData={fetchLogsData} stageWording={{ [ArticleStage.DRAFT]: { stageName: '草稿', timeTitle: '最後編輯時間', memberTitle: '編輯人員', }, [ArticleStage.REVIEWING]: { stageName: '待審核', timeTitle: '送審時間', memberTitle: '送審人員', }, // ... 可自訂各階段的文字 }} /> ), });
LogsModalProps
屬性 型別 必填 說明
onGetData
() => Promise<LogsStageData>
是 取得日誌資料的非同步函式
stageWording
{ [keys in ArticleStage]?: { stageName?, timeTitle?, memberTitle? } }
否 自訂各階段的顯示文字
LogsStageData 與 LogsData
// 各階段的日誌資料 type LogsStageData = { [keys in ArticleStage]?: LogsData | null; };
// 單一階段的詳細資料 interface LogsData { createdAt: string; createdBy: string; updatedAt: string; updatedBy: string; submittedAt: string; submittedBy: string; verifiedAt: string; verifiedBy: string; releasedAt: string; releasedBy: string; version?: number; // 版本號 reason?: string; // 退回原因(僅 DRAFT 階段顯示) }
TypeScript Interfaces
Events Props
// Table 操作事件 interface StandardCMSTableEventsProps<T extends TableDataSourceWithID> { onView?: (source: T) => Promise<void>; onSubmit?: (source: T) => Promise<void>; onPutBack?: (source: T) => Promise<void>; onRelease?: (source: T, releasedAt: string) => Promise<void>; onWithdraw?: (source: T) => Promise<void>; onApprove?: (source: T) => Promise<void>; onReject?: (source: T, reason: string) => Promise<void>; onDelete?: (source: T) => Promise<void>; }
// FormActions 操作事件 interface StandardCMSFormActionsEventsProps<T extends FieldValues> { onLeave?: (values: T) => Promise<void>; onGoToEdit?: (values: T) => Promise<void>; onCreateToDraft?: (values: T) => Promise<void>; onCreateAndRelease?: (values: T, releasedAt: string) => Promise<void>; onCreateAndApprove?: (values: T) => Promise<void>; onCreateAndSubmit?: (values: T) => Promise<void>; onUpdateToDraft?: (values: T) => Promise<void>; onUpdateAndRelease?: (values: T, releasedAt: string) => Promise<void>; onUpdateAndApprove?: (values: T) => Promise<void>; onUpdateAndSubmit?: (values: T) => Promise<void>; onRelease?: (values: T, releasedAt: string) => Promise<void>; onApprove?: (values: T) => Promise<void>; onReject?: (values: T, reason: string) => Promise<void>; onSubmit?: (values: T) => Promise<void>; }
ArticleTableActionsType
定義各階段可用的 Table 操作:
interface ArticleTableActionsType { [ArticleStage.DRAFT]?: ( | ArticleTableActions.Update | ArticleTableActions.Submit | ArticleTableActions.Release | ArticleTableActions.Delete )[]; [ArticleStage.REVIEWING]?: ( | ArticleTableActions.Update | ArticleTableActions.Review | ArticleTableActions.Delete | ArticleTableActions.PutBack )[]; [ArticleStage.VERIFIED]?: ( | ArticleTableActions.View | ArticleTableActions.Update | ArticleTableActions.Release | ArticleTableActions.Delete )[]; [ArticleStage.SCHEDULED]?: ( | ArticleTableActions.View | ArticleTableActions.Update | ArticleTableActions.Withdraw )[]; [ArticleStage.RELEASED]?: ( | ArticleTableActions.Update | ArticleTableActions.Delete )[]; [ArticleStage.UNKNOWN]?: []; }
Enums
ArticleStage
enum ArticleStage { DRAFT = 'DRAFT', // 草稿 REVIEWING = 'REVIEWING', // 審核中 VERIFIED = 'VERIFIED', // 已核准 SCHEDULED = 'SCHEDULED', // 預約發布 RELEASED = 'RELEASED', // 已發布 UNKNOWN = 'UNKNOWN', // 未知狀態 }
ArticlesPermissions
細顆粒度權限(按文章狀態細分):
enum ArticlesPermissions { // 通用權限 CreateArticle = 'CreateArticle', // 建立文章 SubmitPutBackArticle = 'SubmitPutBackArticle', // 送審/退回 ApproveRejectArticle = 'ApproveRejectArticle', // 審核通過/拒絕
// Draft 草稿階段 UpdateArticleInDraft = 'UpdateArticleInDraft', DeleteArticleInDraft = 'DeleteArticleInDraft',
// Reviewing 審核中階段 UpdateArticleInReviewing = 'UpdateArticleInReviewing', DeleteArticleInReviewing = 'DeleteArticleInReviewing',
// Verified 已核准階段 UpdateArticleInVerified = 'UpdateArticleInVerified', ReleaseArticleInVerified = 'ReleaseArticleInVerified', DeleteArticleInVerified = 'DeleteArticleInVerified',
// Scheduled 預約發布階段 UpdateArticleInScheduled = 'UpdateArticleInScheduled', ReleaseArticleInScheduled = 'ReleaseArticleInScheduled', WithdrawArticleInScheduled = 'WithdrawArticleInScheduled',
// Released 已發布階段 UpdateArticleInReleased = 'UpdateArticleInReleased', ReleaseArticleInReleased = 'ReleaseArticleInReleased', WithdrawArticleInReleased = 'WithdrawArticleInReleased', DeleteArticleInReleased = 'DeleteArticleInReleased', }
ArticleTableActions
注意:使用 PascalCase(非 SCREAMING_SNAKE_CASE)
enum ArticleTableActions { View = 'View', // 檢視 Update = 'Update', // 編輯 Delete = 'Delete', // 刪除 Submit = 'Submit', // 送審 PutBack = 'PutBack', // 退回 Review = 'Review', // 審核 Release = 'Release', // 發布 Withdraw = 'Withdraw', // 撤下 }
VerifyReleaseModalRadio
enum VerifyReleaseModalRadio { Now = 'Now', // 立即發佈 Schedule = 'Schedule', // 預約發佈 Approve = 'Approve', // 即刻通過 Reject = 'Reject', // 不通過 }
Default Permission Presets
import { defaultAdminRolePermissions, defaultGeneralRolePermissions, defaultTableActions, } from '@rytass/cms-react-components';
// Admin 角色預設權限(完整權限) // 包含所有階段的 Update/Delete/Release/Withdraw 權限
// 一般角色預設權限(有限權限) // 主要包含 Create、Draft 編輯、送審、部分發布權限
// 預設表格操作(按階段) // DRAFT: [Update, Submit, Release, Delete] // REVIEWING: [Update, Review, Delete, PutBack] // VERIFIED: [View, Update, Release, Delete] // SCHEDULED: [View, Update, Withdraw] // RELEASED: [Update, Delete]
Utilities
havePermission
權限檢查工具函式:
import { havePermission, ArticlesPermissions } from '@rytass/cms-react-components';
const canDelete = havePermission({ userPermissions: userPermissions, targetPermission: ArticlesPermissions.DeleteArticleInDraft, });
if (canDelete) { // 顯示刪除按鈕 }
VersionLog Icon
版本日誌圖示元件:
import { VersionLog } from '@rytass/cms-react-components';
<VersionLog width={24} height={24} />
Hooks
useDialog
import { useDialog } from '@rytass/cms-react-components';
const { openDialog, closeDialog } = useDialog();
openDialog({ title: '提示', content: '操作成功!', onConfirm: closeDialog, });
useModal
import { useModal } from '@rytass/cms-react-components';
const { openModal, closeModal } = useModal();
openModal({ children: <YourModalComponent prop1="value" />, // 可選配置(繼承 Mezzanine UI ModalProps) size: 'medium', // 'small' | 'medium' | 'large' | 'extraLarge' width: 600, // 自訂寬度 (px) severity: 'warning', // 'success' | 'warning' | 'error' hideCloseIcon: true, // 是否隱藏關閉按鈕(預設 true) disableCloseOnBackdropClick: false, // 是否禁止點擊背景關閉(預設 false) className: 'my-modal', // 自訂 className onClose: () => {}, // 關閉時回調 });
ModalConfigType:
屬性 型別 預設值 說明
children
React.JSX.Element
Modal 內容(傳入 JSX)
size
ModalSize
'medium'
Modal 尺寸
width
number
自訂寬度 (px)
severity
string
嚴重程度圖示
hideCloseIcon
boolean
true
隱藏關閉按鈕
disableCloseOnBackdropClick
boolean
false
禁止點擊背景關閉
className
string
自訂 className
onClose
() => void
關閉時回調
Complete Example
import { DialogProvider, ModalProvider, StandardCMSList, // 整合版(Tabs + Table) StandardCMSTable, StandardCMSTabs, useModal, DeleteWithdrawModal, DeleteWithdrawModalRadio, // 刪除/撤下選項 RejectModal, VerifyReleaseModal, VerifyReleaseModalRadio, ArticleStage, ArticlesPermissions, ArticleTableActions, defaultAdminRolePermissions, // 預設權限集 defaultGeneralRolePermissions, defaultTableActions, } from '@rytass/cms-react-components';
// App wrapper function App() { return ( <DialogProvider> <ModalProvider> <ArticleManagement /> </ModalProvider> </DialogProvider> ); }
// 方法一:使用 StandardCMSList(推薦) function ArticleManagementSimple() { const { openModal, closeModal } = useModal();
return (
<StandardCMSList<Article>
columns={columns}
dataSource={articles}
defaultStage={ArticleStage.DRAFT}
userPermissions={defaultAdminRolePermissions}
onTabChange={(stage) => fetchArticles(stage)}
actionsEvents={{
onView: async (article) => router.push(/articles/${article.id}),
onSubmit: async (article) => await submitArticle(article.id),
onDelete: async (article) => await deleteArticle(article.id),
onRelease: async (article, releasedAt) => {
await releaseArticle(article.id, releasedAt);
},
onApprove: async (article) => await approveArticle(article.id),
onReject: async (article, reason) => await rejectArticle(article.id, reason),
}}
/>
);
}
// 方法二:分開使用 Tabs + Table(更靈活) function ArticleManagement() { const { openModal, closeModal } = useModal(); const [articles, setArticles] = useState<Article[]>([]); const [currentStage, setCurrentStage] = useState(ArticleStage.DRAFT);
// 使用細顆粒度權限 const userPermissions = [ ArticlesPermissions.CreateArticle, ArticlesPermissions.SubmitPutBackArticle, ArticlesPermissions.ApproveRejectArticle, // Draft ArticlesPermissions.UpdateArticleInDraft, ArticlesPermissions.DeleteArticleInDraft, // Reviewing ArticlesPermissions.UpdateArticleInReviewing, // Released ArticlesPermissions.UpdateArticleInReleased, ArticlesPermissions.ReleaseArticleInReleased, ];
const handleDelete = (article: Article) => { openModal({ children: ( <DeleteWithdrawModal defaultRadioValue={DeleteWithdrawModalRadio.Delete} withDelete={true} withWithdraw={currentStage === ArticleStage.RELEASED} onDelete={async () => { await deleteArticle(article.id); refreshArticles(); }} onWithdraw={async () => { await withdrawArticle(article.id); refreshArticles(); }} /> ), }); };
const handleRelease = (article: Article) => { openModal({ children: ( <VerifyReleaseModal title="發佈文章" withApprove={currentStage === ArticleStage.REVIEWING} withReject={currentStage === ArticleStage.REVIEWING} onRelease={async (releasedAt) => { await releaseArticle(article.id, releasedAt); refreshArticles(); closeModal(); }} onApprove={async () => { await approveArticle(article.id); refreshArticles(); closeModal(); }} onReject={async (reason) => { await rejectArticle(article.id, reason); refreshArticles(); closeModal(); }} /> ), }); };
return ( <div> <StandardCMSTabs activeStage={currentStage} onChange={(stage) => { setCurrentStage(stage); fetchArticles(stage); }} />
<StandardCMSTable<Article>
columns={columns}
dataSource={articles}
currentStage={currentStage}
userPermissions={userPermissions}
actions={defaultTableActions}
actionsEvents={{
onView: async (article) => router.push(`/articles/${article.id}`),
onDelete: handleDelete,
onSubmit: async (article) => {
await submitArticle(article.id);
refreshArticles();
},
onPutBack: async (article) => {
await putBackArticle(article.id);
refreshArticles();
},
onRelease: handleRelease,
onWithdraw: async (article) => {
await withdrawArticle(article.id);
refreshArticles();
},
onApprove: async (article) => {
await approveArticle(article.id);
refreshArticles();
},
onReject: async (article, reason) => {
await rejectArticle(article.id, reason);
refreshArticles();
},
}}
/>
</div>
); }
Dependencies
Peer Dependencies:
-
@mezzanine-ui/core
-
@mezzanine-ui/react
-
@mezzanine-ui/icons
-
react , react-dom
-
react-hook-form
-
dayjs
-
lodash
Troubleshooting
Modal 不顯示
確保在應用根層級包裝 ModalProvider :
<ModalProvider> <App /> </ModalProvider>
權限按鈕不顯示
確認 userPermissions 陣列包含對應的細顆粒度權限:
// 錯誤:使用簡化權限(不存在) userPermissions={[ArticlesPermissions.DELETE]} // ❌ 不存在
// 正確:使用按階段細分的權限 userPermissions={[ ArticlesPermissions.DeleteArticleInDraft, // ✓ Draft 階段刪除 ArticlesPermissions.DeleteArticleInReleased, // ✓ Released 階段刪除 ]}
// 或使用預設權限集 userPermissions={defaultAdminRolePermissions} // ✓ 完整權限