@@ -121,10 +121,333 @@ export const bootstrap = createBootstrap(conf())(() => (
121121
122122@querycap/route-tree 对@reactor/router 进行封装,提供了路由权限以及 index 路由的功能,在实际使用中主要还是使用@querycap-canary/routes。
123123
124+ ### 基本使用
125+
126+ ```ts
127+ import {
128+ EachRoutes,
129+ isVirtualRoute,
130+ Route,
131+ RouteProvider,
132+ SwitchRoutes,
133+ useNavigate,
134+ useRouteContext,
135+ load,
136+ } from '@querycap-canary/routes';
137+ import { IconOverview } from 'src-modules/power-plant/common/Icons';
138+ import { getRouterByStrategy } from 'src-modules/power-plant/common/Access';
139+
140+ export const overviewRoutes = (
141+ <Route
142+ path="overview"
143+ title="总览"
144+ icon={<IconOverview />}
145+ render={getRouterByStrategy('bff-smart-power-plant.MOD_OVERVIEW')}
146+ >
147+ <Route index content={load(() => import('./Overview'))} />
148+ </Route>
149+ );
150+
151+ export const rootRoutes = (
152+ <Route>
153+ {loginRoutes}
154+ <Route path={'/'} content={<FocusUserAndProject />}>
155+ <Route path={':appName / :projectID ' } content={<Main />}>
156+ < Route index content = {<AutoRedirectAccessibleByStrategy />} / >
157+ {overviewRoutes }
158+ {healthRoutes }
159+ {optimizeRoutes }
160+ {supportRoutes }
161+ {dataRoutes }
162+ {platformRoutes }
163+ < / Route >
164+ < / Route >
165+ < / Route >
166+ );
167+
168+ export const bootstrap = createBootstrap (conf ())(() => (
169+ <Setup >{rootRoutes }< / Setup >
170+ ));
171+ ` ` `
172+
173+ ### Route
174+
175+ 路由组件,根据 path 匹配对应的路径,渲染 content,render 可实现路由权限,在 render 内部可以决定是否渲染组件。index 标识根路由,title 和 icon 会显示在菜单栏。
176+
177+ ### Link
178+
179+ ` ` ` ts
180+ import { Link } from ' @reactorx/router' ;
181+
182+ const PlatformManage = () => {
183+ return (
184+ < div
185+ css = {{
186+ display : ' flex' ,
187+ height : ' calc(100vh - 4em)' ,
188+ alignItems : ' center' ,
189+ justifyContent : ' center' ,
190+ }}
191+ >
192+ < Link to = {' /optimize/feedback' }>
193+ < div css = {select().marginTop(' 1em' )}> 意见反馈< / div >
194+ < / Link >
195+ < Link to = {' /platform/user' }>
196+ < div
197+ css = {select()
198+ .marginTop(' 1em' )
199+ .color(colors.gray8)}
200+ >
201+ 用户管理
202+ < / div >
203+ < / Link >
204+ < / div >
205+ );
206+ };
207+ ` ` `
208+
209+ ### NavLink
210+
211+ ` ` ` ts
212+ import { NavLink } from ' @reactorx/router' ;
213+
214+ const Example = () => {
215+ return <NavLink to ={` groups/${projectID }?name=${name } ` }>查看< / NavLink > ;
216+ };
217+ ` ` `
218+
219+ ### SwitchRoutes
220+
221+ 类似 react-router-dom 的 Switch,如上面的 Main 内部就使用了 SwitchRoutes,当 content 内部使用了 SwitchRoutes 时,使用 Route 的 children 来实现多个子路由的渲染。content 结合 load 可以实现动态加载。
222+
223+ ` ` ` ts
224+ const Main = () => {
225+ return (
226+ < ThemeState fontSize = {theme.fontSizes.s }>
227+ < ProLayout
228+ logo = {logo }
229+ layout = {' top' }
230+ renderHeader = {<CurrentUser />}
231+ theme = {' light' }
232+ >
233+ < SwitchRoutes / >
234+ < / ProLayout >
235+ < / ThemeState >
236+ );
237+ };
238+ ` ` `
239+
240+ ### 嵌套路由
241+
242+ ` ` ` ts
243+ export const platformRoutes = (
244+ < Route path = " platform" title = " 平台管理" icon = {<IconPlatform />}>
245+ < Route index content = {load(() => import (' ./PlatformManage' ))} / >
246+ < Route path = {' user' } content = {load(() => import (' ./UserManage' ))}>
247+ < Route index content = {<AutoRedirectAccessible />} / >
248+ {profileRoutes }
249+ {roleRoutes }
250+ < / Route >
251+ < / Route >
252+ );
253+ ` ` `
254+
255+ ### 路径参数
256+
257+ ` ` ` ts
258+ < Route path = {' history/:modelID' }>
259+ < Route index content = {load(() => import (' ./HistoryRecord' ))} / >
260+ < Route
261+ path = {' :resultID' }
262+ content = {load(() => import (' ./HistorySuggestDetail' ))}
263+ / >
264+ < / Route >
265+ ` ` `
266+
267+ 获取路径参数
268+
269+ ` ` ` ts
270+ import { useRouter } from ' @reactorx/router' ;
271+
272+ const HistorySuggestDetail = () => {
273+ const { match, history } = useRouter ();
274+ const { modelID, resultID } = match .params ;
275+
276+ return <>child < / > ;
277+ };
278+ ` ` `
279+
280+ query 参数解析
281+
282+ ` ` ` ts
283+ import { parseSearchString , toSearchString , useRouter } from ' @reactorx/router' ;
284+
285+ export const UserMenu = ({ children }: { children? : ReactNode }) => {
286+ const triggerRef = useRef <HTMLDivElement >(null );
287+ const logout = useLogout ();
288+ const { history } = useRouter ();
289+
290+ const [isOpened, openPopover, closePopover] = useToggle ();
291+
292+ useToggleControlOnClick (triggerRef , () =>
293+ isOpened ? closePopover () : openPopover (),
294+ );
295+
296+ const [{ selectValue$ }, Select] = useNewSelect ();
297+
298+ useObservableEffect (() => {
299+ if (! triggerRef .current ) {
300+ return ;
301+ }
302+
303+ return selectValue$ .pipe (
304+ tap (opt => {
305+ if (opt === ' to-logout' ) {
306+ history .replace ({
307+ search: toSearchString ({
308+ ... parseSearchString (location .search ),
309+ _from: ' close' ,
310+ }),
311+ }); // 兼容OAuth退出
312+ logout ();
313+ }
314+ closePopover ();
315+ }),
316+ );
317+ }, []);
318+
319+ const user = useLogonUser ();
320+
321+ return (
322+ < ThemeState fontSize = {roundedEm(0.9)}>
323+ < div
324+ css = {select()
325+ .fontSize(theme.state.fontSize)
326+ .paddingTop(roundedEm (1.4))
327+ .paddingBottom(roundedEm (1))
328+ .paddingX(roundedEm (1.4))
329+ .with(
330+ select (' & > a' )
331+ .outline(' none' )
332+ .paddingY(roundedEm (0.6))
333+ .colorFill(pipe (theme.state.color, tint (0.1))),
334+ )}
335+ >
336+ < span ref = {triggerRef } onClick = {preventDefault }>
337+ < span css = {select().display(' block' )}>
338+ <span >
339+ {user .identities [AccountIdentityType .NICKNAME ] || '用户'}
340+ < / span >
341+ & nbsp ;
342+ < IconChevronDown / >
343+ < / span >
344+ < span
345+ css = {select()
346+ .display(' block' )
347+ .opacity(0.4)}
348+ >
349+ <small >{user.accountID }< / small >
350+ < / span >
351+ < / span >
352+ {isOpened && (
353+ <Select >
354+ <SelectMenuPopover
355+ triggerRef = {triggerRef }
356+ onRequestClose = {() => closePopover()}
357+ fullWidth
358+ placement = {' bottom-left' }
359+ >
360+ {children }
361+ <MenuOptGroup >
362+ <div data -opt = {' to-logout' }> 退出登录< / div >
363+ </MenuOptGroup >
364+ </SelectMenuPopover >
365+ </Select >
366+ )}
367+ < / div >
368+ < / ThemeState >
369+ );
370+ };
371+ ` ` `
372+
373+ 其他
374+
375+ ` ` ` ts
376+ import {
377+ Navigate ,
378+ Route ,
379+ useLocation ,
380+ useNavigate ,
381+ } from ' @querycap-canary/routes' ;
382+
383+ const { pathname , query , hash , params } = useLocation ();
384+ const navigate = useNavigate ();
385+ ` ` `
386+
124387## 请求
125388
126389@querycap/request 提供了请求相关的 react hook、axios 全局 Provider、错误处理等 api。
127390
391+ ### useRequest
392+
393+ useRequest 用于手动发起请求的场景,如表单。
394+
395+ ` ` ` ts
396+ import { useRequest } from ' @reactorx/request' ;
397+
398+ const AcFormApp = ({
399+ action ,
400+ app ,
401+ onSuccess ,
402+ }: {
403+ action: string ;
404+ app? : IApp ;
405+ onSuccess? : () => void ;
406+ }) => {
407+ const [formCtx, Form] = useNewForm <typeof putApp .arg .body >(' AcFormApp' , app );
408+ const notify = useNotify ();
409+
410+ const [put] = useRequest (putApp , {
411+ onSuccess : () => {
412+ onSuccess && onSuccess ();
413+ notify (' success' , ` ${action }成功 ` );
414+ },
415+ onFail : actor => {
416+ formCtx .setErrors (pickErrors (actor .arg .data .errorFields ));
417+ },
418+ });
419+
420+ return (
421+ < Form
422+ css = {select().maxWidth(400)}
423+ onSubmit = {values => {
424+ put ({
425+ body: values ,
426+ });
427+ }}
428+ >
429+ < FormControlWithField
430+ name = " name"
431+ desc = " url safe 字符"
432+ label = {displayApp(' name' )}
433+ validate = {pipe(required (), validateSafeURL())}
434+ readOnly = {!!app }
435+ >
436+ {props = > <SimpleInputText {... props } />}
437+ < / FormControlWithField >
438+ < FormControlWithField name = " fullName" label = {displayApp(' fullName' )}>
439+ {props = > <SimpleInputText {... props } />}
440+ < / FormControlWithField >
441+ <FormControls >
442+ < Button type = {' submit' } primary >
443+ {app ? ' 更新' : ' 创建' }
444+ < / Button >
445+ < / FormControls >
446+ < / Form >
447+ );
448+ };
449+ ` ` `
450+
128451### useTempDataOfRequest
129452
130453` ` ` ts
@@ -161,7 +484,7 @@ declare const useTempDataOfRequest: <TRequestActor extends RequestActor<
161484];
162485` ` `
163486
164- 用于组件挂载完成时发起请求。
487+ 用于组件挂载完成时发起请求,内部是对 useRequest 的封装 。
165488
166489请求发出的时机:
167490
0 commit comments