openxiangda-cli 2.0.0-alpha.67 → 2.0.0-alpha.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,12 +4,10 @@ import {
4
4
  ExportOutlined,
5
5
  EyeOutlined,
6
6
  HistoryOutlined,
7
- ImportOutlined,
8
7
  PlusOutlined,
9
8
  } from '@ant-design/icons';
10
9
  import {
11
10
  Alert,
12
- App,
13
11
  Button,
14
12
  Card,
15
13
  Result,
@@ -47,17 +45,10 @@ export function ResourceListPage({
47
45
  resource,
48
46
  surface,
49
47
  title,
50
- description,
51
48
  readCapability,
52
- createCapability,
53
- createPath,
54
- onExport,
55
- importDisabledReason = '导入能力将在批量事务合同落地后启用',
56
49
  children,
57
50
  }: ResourceListPageProps) {
58
- const navigate = useNavigate();
59
51
  const { hasCapability } = useRuntime();
60
- const { message } = App.useApp();
61
52
  if (!hasCapability(readCapability)) {
62
53
  return (
63
54
  <Shell>
@@ -65,7 +56,6 @@ export function ResourceListPage({
65
56
  </Shell>
66
57
  );
67
58
  }
68
- const canCreate = createCapability ? hasCapability(createCapability) : false;
69
59
  return (
70
60
  <Shell>
71
61
  <Card
@@ -73,42 +63,7 @@ export function ResourceListPage({
73
63
  data-resource={resource}
74
64
  data-surface-layout={surface?.list ? 'standard' : undefined}
75
65
  >
76
- <Space orientation="vertical" size={16} style={{ width: '100%' }}>
77
- <div className="oxa-page-heading">
78
- <div>
79
- <h2 className="oxa-title">{title}</h2>
80
- {description && <div className="oxa-muted">{description}</div>}
81
- </div>
82
- <Space>
83
- <Button
84
- disabled
85
- icon={<ImportOutlined />}
86
- title={importDisabledReason}
87
- >
88
- 导入
89
- </Button>
90
- <Button
91
- icon={<ExportOutlined />}
92
- onClick={() => {
93
- if (onExport) onExport();
94
- else message.info('导出将使用当前 Data API 查询条件');
95
- }}
96
- >
97
- 导出
98
- </Button>
99
- {canCreate && createPath && (
100
- <Button
101
- icon={<PlusOutlined />}
102
- onClick={() => navigate(createPath)}
103
- type="primary"
104
- >
105
- 新增
106
- </Button>
107
- )}
108
- </Space>
109
- </div>
110
- {children}
111
- </Space>
66
+ <div className="oxa-list-surface">{children}</div>
112
67
  </Card>
113
68
  </Shell>
114
69
  );
@@ -289,6 +244,7 @@ interface ResourceDetailPageProps extends StandardResourcePageProps {
289
244
  editCapability?: string;
290
245
  editPath?: string;
291
246
  auditTargetId?: string;
247
+ onAuditOpen?: () => void;
292
248
  hero: ReactNode;
293
249
  meta?: ReactNode;
294
250
  children: ReactNode;
@@ -307,6 +263,7 @@ export function ResourceDetailPage({
307
263
  editCapability,
308
264
  editPath,
309
265
  auditTargetId,
266
+ onAuditOpen,
310
267
  hero,
311
268
  meta,
312
269
  children,
@@ -356,11 +313,14 @@ export function ResourceDetailPage({
356
313
  {auditTargetId && (
357
314
  <Button
358
315
  icon={<HistoryOutlined />}
359
- onClick={() =>
360
- document
361
- .getElementById(auditTargetId)
362
- ?.scrollIntoView({ behavior: 'smooth', block: 'center' })
363
- }
316
+ onClick={() => {
317
+ onAuditOpen?.();
318
+ window.requestAnimationFrame(() =>
319
+ document
320
+ .getElementById(auditTargetId)
321
+ ?.scrollIntoView({ behavior: 'smooth', block: 'center' }),
322
+ );
323
+ }}
364
324
  >
365
325
  操作记录
366
326
  </Button>
@@ -399,6 +359,7 @@ export function MobileResourceDetailPage({
399
359
  editCapability,
400
360
  editPath,
401
361
  auditTargetId,
362
+ onAuditOpen,
402
363
  hero,
403
364
  meta,
404
365
  children,
@@ -417,7 +378,7 @@ export function MobileResourceDetailPage({
417
378
  {backLabel}
418
379
  </Button>
419
380
  <Space>
420
- {auditTargetId && <Button icon={<HistoryOutlined />} onClick={() => document.getElementById(auditTargetId)?.scrollIntoView({ behavior: 'smooth', block: 'center' })}>操作记录</Button>}
381
+ {auditTargetId && <Button icon={<HistoryOutlined />} onClick={() => { onAuditOpen?.(); window.requestAnimationFrame(() => document.getElementById(auditTargetId)?.scrollIntoView({ behavior: 'smooth', block: 'center' })); }}>操作记录</Button>}
421
382
  {editCapability && editPath && hasCapability(editCapability) && <Button icon={<EditOutlined />} onClick={() => navigate(editPath)} type="primary">编辑</Button>}
422
383
  </Space>
423
384
  </header>
@@ -460,7 +460,7 @@ function ManagedFileField({
460
460
  refsRef.current = refs;
461
461
  }, [refs]);
462
462
  if (!onUpload) {
463
- return <Alert type="info" showIcon message="该文件字段尚未配置上传能力" />;
463
+ return <Alert type="info" showIcon title="该文件字段尚未配置上传能力" />;
464
464
  }
465
465
  if (mobile) {
466
466
  const acceptValue = Array.isArray(accept) ? accept.join(',') : accept;
@@ -1,11 +1,10 @@
1
1
  import { Refine } from '@refinedev/core';
2
- import { App as AntdApp, ConfigProvider, Spin } from 'antd';
3
- import zhCN from 'antd/locale/zh_CN';
4
2
  import React from 'react';
5
3
  import ReactDOM from 'react-dom/client';
6
4
  import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
7
5
  import { resourceDefinitions } from '../../../packages/contracts/src/generated.js';
8
6
  import { applicationProvider } from './data-provider';
7
+ import { AppearanceProvider } from './appearance';
9
8
  import { GeneratedResourcePage } from './components/resource/GeneratedResourceCrud';
10
9
  import { FilePreviewPage } from './FilePreviewPage';
11
10
  import { EmptyApplicationPage } from './Shell';
@@ -20,9 +19,13 @@ const firstPath = codes[0] ? `/${codes[0]}` : '/';
20
19
  function GlobalRequestLoading() {
21
20
  const loading = useGlobalRequestLoading();
22
21
  return loading ? (
23
- <div aria-live="polite" className="oxa-global-request-loading">
24
- <Spin size="small" />
25
- <span>正在加载…</span>
22
+ <div
23
+ aria-label="页面请求进行中"
24
+ aria-valuetext="正在加载"
25
+ className="oxa-global-request-loading"
26
+ role="progressbar"
27
+ >
28
+ <span />
26
29
  </div>
27
30
  ) : null;
28
31
  }
@@ -40,21 +43,19 @@ const resourceRoutes = codes.flatMap(resourceCode => [
40
43
 
41
44
  ReactDOM.createRoot(document.getElementById('root')!).render(
42
45
  <React.StrictMode>
43
- <ConfigProvider locale={zhCN} theme={{ token: { borderRadius: 8, colorBgLayout: '#f3f7fd', colorPrimary: '#1677ff', colorText: '#172033', fontSize: 14 }, components: { Card: { headerFontSize: 16 }, Layout: { bodyBg: '#f3f7fd', headerBg: '#ffffff', siderBg: '#ffffff' }, Menu: { itemBorderRadius: 8, itemSelectedBg: '#eaf3ff' } } }}>
44
- <AntdApp>
45
- <GlobalRequestLoading />
46
- <RuntimeBoundary>
47
- <BrowserRouter basename={applicationBasename()}>
48
- <Refine dataProvider={applicationProvider} resources={codes.map(code => ({ name: code, list: `/${code}`, create: `/${code}/new`, edit: `/${code}/:id/edit`, show: `/${code}/:id` }))}>
49
- <Routes>
50
- <Route path="/" element={codes.length ? <Navigate replace to={firstPath} /> : <EmptyApplicationPage />} />
51
- <Route path="/files/:resourceCode/:fileId/preview" element={<FilePreviewPage />} />
52
- {resourceRoutes}
53
- </Routes>
54
- </Refine>
55
- </BrowserRouter>
56
- </RuntimeBoundary>
57
- </AntdApp>
58
- </ConfigProvider>
46
+ <AppearanceProvider>
47
+ <GlobalRequestLoading />
48
+ <RuntimeBoundary>
49
+ <BrowserRouter basename={applicationBasename()}>
50
+ <Refine dataProvider={applicationProvider} resources={codes.map(code => ({ name: code, list: `/${code}`, create: `/${code}/new`, edit: `/${code}/:id/edit`, show: `/${code}/:id` }))}>
51
+ <Routes>
52
+ <Route path="/" element={codes.length ? <Navigate replace to={firstPath} /> : <EmptyApplicationPage />} />
53
+ <Route path="/files/:resourceCode/:fileId/preview" element={<FilePreviewPage />} />
54
+ {resourceRoutes}
55
+ </Routes>
56
+ </Refine>
57
+ </BrowserRouter>
58
+ </RuntimeBoundary>
59
+ </AppearanceProvider>
59
60
  </React.StrictMode>,
60
61
  );
@@ -115,6 +115,13 @@ export async function loadCurrentIdentity(): Promise<RuntimeIdentity> {
115
115
  return activeIdentity;
116
116
  }
117
117
 
118
+ export async function logoutCurrentUser() {
119
+ await request<null>('/api/auth/logout', {
120
+ method: 'POST',
121
+ });
122
+ activeIdentity = undefined;
123
+ }
124
+
118
125
  function currentEnvironmentKey() {
119
126
  const key = activeIdentity?.environment.key || runtimeMount()?.environmentKey;
120
127
  if (!key) throw new Error('OPENXIANGDA_CURRENT_ENVIRONMENT_REQUIRED');