cms-react
npx skills add https://github.com/rytass/utils --skill cms-react
Agent 安装分布
Skill 文档
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/iconsreact,react-domreact-hook-formdayjslodash
Troubleshooting
Modal ä¸é¡¯ç¤º
確ä¿å¨æç¨æ ¹å±¤ç´å
è£ ModalProviderï¼
<ModalProvider>
<App />
</ModalProvider>
æ¬éæéä¸é¡¯ç¤º
ç¢ºèª userPermissions é£åå
å«å°æçç´°é¡ç²åº¦æ¬éï¼
// é¯èª¤ï¼ä½¿ç¨ç°¡åæ¬éï¼ä¸åå¨ï¼
userPermissions={[ArticlesPermissions.DELETE]} // â ä¸åå¨
// æ£ç¢ºï¼ä½¿ç¨æé段細åçæ¬é
userPermissions={[
ArticlesPermissions.DeleteArticleInDraft, // â Draft éæ®µåªé¤
ArticlesPermissions.DeleteArticleInReleased, // â Released éæ®µåªé¤
]}
// æä½¿ç¨é è¨æ¬éé
userPermissions={defaultAdminRolePermissions} // â 宿´æ¬é