neo-cmp-cli 1.12.7 → 1.12.9

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.
Files changed (144) hide show
  1. package/README.md +204 -6
  2. package/dist/index2.js +1 -1
  3. package/dist/neo/env.js +1 -1
  4. package/dist/package.json.js +1 -1
  5. package/package.json +1 -1
  6. package/template/antd-custom-cmp-template/package.json +1 -1
  7. package/template/{neo-bi-cmps → asset-manage-template}/README.md +65 -10
  8. package/template/asset-manage-template/docs/README.md +244 -0
  9. package/template/asset-manage-template/neo.config.js +60 -0
  10. package/template/{neo-bi-cmps → asset-manage-template}/package.json +28 -16
  11. package/template/asset-manage-template/src/assets/img/chart.svg +1 -0
  12. package/template/asset-manage-template/src/components/README.md +3 -0
  13. package/template/asset-manage-template/src/components/assetManage__c/assetApi.ts +70 -0
  14. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetCreateModal.tsx +260 -0
  15. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetGrid.tsx +48 -0
  16. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetSidebar.tsx +74 -0
  17. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetToolbar.tsx +79 -0
  18. package/template/asset-manage-template/src/components/assetManage__c/cmps/assetDisplay.tsx +72 -0
  19. package/template/asset-manage-template/src/components/assetManage__c/constants.ts +28 -0
  20. package/template/asset-manage-template/src/components/assetManage__c/index.tsx +258 -0
  21. package/template/asset-manage-template/src/components/assetManage__c/model.ts +75 -0
  22. package/template/asset-manage-template/src/components/assetManage__c/style.scss +425 -0
  23. package/template/asset-manage-template/src/components/assetManage__c/types.ts +60 -0
  24. package/template/asset-manage-template/src/components/bidList__c/cmps/BidCard.tsx +47 -0
  25. package/template/asset-manage-template/src/components/bidList__c/constants.ts +6 -0
  26. package/template/asset-manage-template/src/components/bidList__c/formatUtils.ts +14 -0
  27. package/template/asset-manage-template/src/components/bidList__c/index.tsx +194 -0
  28. package/template/asset-manage-template/src/components/bidList__c/model.ts +57 -0
  29. package/template/asset-manage-template/src/components/bidList__c/style.scss +179 -0
  30. package/template/asset-manage-template/src/components/bidList__c/types.ts +10 -0
  31. package/template/asset-manage-template/src/components/bidPackage__c/cmps/BidPackageHeader.tsx +140 -0
  32. package/template/asset-manage-template/src/components/bidPackage__c/cmps/PackageItemTable.tsx +148 -0
  33. package/template/asset-manage-template/src/components/bidPackage__c/index.tsx +394 -0
  34. package/template/asset-manage-template/src/components/bidPackage__c/mainTableColumns.tsx +57 -0
  35. package/template/asset-manage-template/src/components/bidPackage__c/model.ts +86 -0
  36. package/template/asset-manage-template/src/components/bidPackage__c/style.scss +256 -0
  37. package/template/asset-manage-template/src/components/bidPackage__c/types.ts +35 -0
  38. package/template/asset-manage-template/src/components/bidPackage__c/utils.ts +19 -0
  39. package/template/{neo-bi-cmps → asset-manage-template}/src/utils/axiosFetcher.ts +0 -0
  40. package/template/{neo-bi-cmps → asset-manage-template}/src/utils/queryObjectData.ts +0 -0
  41. package/template/asset-manage-template/src/utils/url.ts +82 -0
  42. package/template/{neo-bi-cmps → asset-manage-template}/src/utils/xobjects.ts +0 -0
  43. package/template/{neo-bi-cmps → asset-manage-template}/tsconfig.json +1 -1
  44. package/template/echarts-custom-cmp-template/package.json +1 -1
  45. package/template/empty-custom-cmp-template/package.json +2 -2
  46. package/template/neo-custom-cmp-template/package.json +2 -2
  47. package/template/neo-custom-cmp-template/src/components/entityTable__c/index.tsx +62 -6
  48. package/template/neo-h5-cmps/neo.config.js +34 -76
  49. package/template/neo-h5-cmps/package.json +7 -3
  50. package/template/neo-h5-cmps/src/components/entityList__c/index.tsx +0 -4
  51. package/template/neo-h5-cmps/src/components/entityList__c/model.ts +10 -5
  52. package/template/neo-h5-cmps/src/components/entityTabs__c/index.tsx +29 -17
  53. package/template/neo-h5-cmps/src/components/entityTabs__c/model.ts +25 -5
  54. package/template/neo-h5-cmps/src/components/entityTabs__c/style.scss +11 -22
  55. package/template/neo-h5-cmps/src/components/openChatPageBtn__c/index.tsx +3 -1
  56. package/template/neo-h5-cmps/src/utils/xobjects.ts +8 -3
  57. package/template/neo-h5-cmps/tsconfig.json +1 -1
  58. package/template/neo-order-cmps/package.json +2 -2
  59. package/template/react-custom-cmp-template/package.json +1 -1
  60. package/template/react-ts-custom-cmp-template/package.json +1 -1
  61. package/template/vue2-custom-cmp-template/package.json +1 -1
  62. package/template/develop/BI /351/241/271/347/233/256/345/210/206/346/236/220/346/212/245/345/221/212.md" +0 -562
  63. package/template/develop/ChatPage /347/273/204/344/273/266/344/275/277/347/224/250/350/257/264/346/230/216/346/226/207/346/241/243.md" +0 -507
  64. package/template/develop/EntityGrid Web /347/273/204/344/273/266/347/232/204/350/257/246/347/273/206/345/210/206/346/236/220/346/226/207/346/241/243.md" +0 -868
  65. package/template/develop/EntityList H5 /347/273/204/344/273/266/347/232/204/350/257/246/347/273/206/345/210/206/346/236/220/346/226/207/346/241/243.md" +0 -1386
  66. package/template/develop/GlobalSearch/347/273/204/344/273/266/345/257/271/346/257/224/345/210/206/346/236/220.md +0 -866
  67. package/template/develop/Neo /344/270/255/345/217/257/347/224/250 amis /347/273/204/344/273/266.md" +0 -1490
  68. package/template/develop/cmpEventFunctions.ts +0 -257
  69. package/template/develop/cmpEvents.ts +0 -864
  70. package/template/develop/comTree/347/224/237/346/210/220/350/277/207/347/250/213/345/210/206/346/236/220.md +0 -469
  71. package/template/develop/commonModules.js +0 -55
  72. package/template/develop/components-table.md +0 -50
  73. package/template/develop/neo-custom-cmp-template/README.md +0 -48
  74. package/template/develop/neo-custom-cmp-template/docs/README.md +0 -13
  75. package/template/develop/neo-custom-cmp-template/neo.config.js +0 -121
  76. package/template/develop/neo-custom-cmp-template/package.json +0 -63
  77. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/README.md +0 -65
  78. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/index.tsx +0 -180
  79. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/model.ts +0 -50
  80. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/style.scss +0 -260
  81. package/template/develop/neo-custom-cmp-template/src/components/contactForm/README.md +0 -94
  82. package/template/develop/neo-custom-cmp-template/src/components/contactForm/index.tsx +0 -252
  83. package/template/develop/neo-custom-cmp-template/src/components/contactForm/model.ts +0 -56
  84. package/template/develop/neo-custom-cmp-template/src/components/contactForm/style.scss +0 -120
  85. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/README.md +0 -115
  86. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/index.tsx +0 -304
  87. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/model.ts +0 -87
  88. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/style.scss +0 -127
  89. package/template/develop/neo-custom-cmp-template/src/utils/axiosFetcher.ts +0 -29
  90. package/template/develop/neo-custom-cmp-template/src/utils/queryObjectData.ts +0 -39
  91. package/template/develop/neo-custom-cmp-template/src/utils/xobjects.ts +0 -203
  92. package/template/develop/neo-custom-cmp-template/tsconfig.json +0 -68
  93. package/template/develop/neo-ui-component-h5.md +0 -105
  94. package/template/develop/neo-ui-component-web-xregister.md +0 -31
  95. package/template/develop/neo-ui-component-web.md +0 -292
  96. package/template/develop/neoCmps.ts +0 -7508
  97. package/template/develop/neoGlobalSearchInput /347/273/204/344/273/266/347/232/204/350/257/246/347/273/206/345/210/206/346/236/220/346/226/207/346/241/243.md" +0 -497
  98. package/template/develop/pageSchema1.json +0 -744
  99. package/template/develop//344/272/213/344/273/266/345/212/250/344/275/234/344/277/235/345/255/230/346/265/201/347/250/213/345/210/206/346/236/220.md +0 -390
  100. package/template/develop//345/215/225/345/205/203/346/265/213/350/257/225/344/275/277/347/224/250/350/257/264/346/230/216.md +0 -1139
  101. package/template/neo-bi-cmps/.prettierrc.js +0 -12
  102. package/template/neo-bi-cmps/commitlint.config.js +0 -59
  103. package/template/neo-bi-cmps/neo.config.js +0 -124
  104. package/template/neo-bi-cmps/public/css/base.css +0 -283
  105. package/template/neo-bi-cmps/public/scripts/app/bluebird.js +0 -6679
  106. package/template/neo-bi-cmps/public/template.html +0 -13
  107. package/template/neo-bi-cmps/src/assets/css/common.scss +0 -127
  108. package/template/neo-bi-cmps/src/assets/css/mixin.scss +0 -47
  109. package/template/neo-bi-cmps/src/assets/img/NeoCRM.jpg +0 -0
  110. package/template/neo-bi-cmps/src/assets/img/custom-widget.svg +0 -1
  111. package/template/neo-bi-cmps/src/assets/img/favicon.png +0 -0
  112. package/template/neo-bi-cmps/src/assets/img/table.svg +0 -1
  113. package/template/neo-bi-cmps/src/components/targetNumber__c/README.md +0 -100
  114. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/configSchema.ts +0 -253
  115. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/index.scss +0 -76
  116. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/index.tsx +0 -148
  117. package/template/neo-bi-cmps/src/components/targetNumber__c/index.tsx +0 -440
  118. package/template/neo-bi-cmps/src/components/targetNumber__c/model.ts +0 -128
  119. package/template/neo-bi-cmps/src/components/targetNumber__c/style.scss +0 -173
  120. package/template/neo-h5-cmps/src/components/simpleTable__c/README.md +0 -90
  121. package/template/neo-h5-cmps/src/components/simpleTable__c/index.tsx +0 -277
  122. package/template/neo-h5-cmps/src/components/simpleTable__c/model.ts +0 -91
  123. package/template/neo-h5-cmps/src/components/simpleTable__c/style.scss +0 -116
  124. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/.prettierrc.js +0 -0
  125. /package/template/{neo-bi-cmps → asset-manage-template}/@types/neo-ui-common.d.ts +0 -0
  126. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/commitlint.config.js +0 -0
  127. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/public/css/base.css +0 -0
  128. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/public/scripts/app/bluebird.js +0 -0
  129. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/public/template.html +0 -0
  130. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/css/common.scss +0 -0
  131. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/css/mixin.scss +0 -0
  132. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/AIBtn.gif +0 -0
  133. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/NeoCRM.jpg +0 -0
  134. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/aiLogo.png +0 -0
  135. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/card-list.svg +0 -0
  136. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/contact-form.svg +0 -0
  137. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/custom-form.svg +0 -0
  138. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/custom-widget.svg +0 -0
  139. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/data-list.svg +0 -0
  140. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/detail.svg +0 -0
  141. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/favicon.png +0 -0
  142. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/map.svg +0 -0
  143. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/search.svg +0 -0
  144. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/table.svg +0 -0
@@ -0,0 +1,260 @@
1
+ /**
2
+ * 新增资产弹窗(参照 entityTable__c:getDesc 动态表单 + xObject.create)
3
+ */
4
+ import * as React from 'react';
5
+ import {
6
+ Modal,
7
+ Form,
8
+ Input,
9
+ Select,
10
+ message,
11
+ Spin,
12
+ Empty,
13
+ DatePicker,
14
+ InputNumber,
15
+ } from 'antd';
16
+ // @ts-ignore
17
+ import { xObject } from 'neo-open-api';
18
+ import moment from 'moment';
19
+ import type { FieldDesc } from '../types';
20
+
21
+ const { Option } = Select;
22
+
23
+ export interface AssetCreateModalProps {
24
+ visible: boolean;
25
+ assetApiKey?: string;
26
+ assetFields?: string[];
27
+ /** 实体显示名,用于标题 */
28
+ entityLabel?: string;
29
+ onClose: () => void;
30
+ onSuccess: () => void;
31
+ }
32
+
33
+ export const AssetCreateModal: React.FC<AssetCreateModalProps> = ({
34
+ visible,
35
+ assetApiKey,
36
+ assetFields,
37
+ entityLabel,
38
+ onClose,
39
+ onSuccess,
40
+ }) => {
41
+ const [form] = Form.useForm();
42
+ const [loadingMeta, setLoadingMeta] = React.useState(false);
43
+ const [submitting, setSubmitting] = React.useState(false);
44
+ const [fieldList, setFieldList] = React.useState<FieldDesc[]>([]);
45
+ const [entityTypeList, setEntityTypeList] = React.useState<any[]>([]);
46
+ const [objectLabel, setObjectLabel] = React.useState<string>('');
47
+
48
+ const loadMeta = React.useCallback(async () => {
49
+ if (!assetApiKey) return;
50
+ setLoadingMeta(true);
51
+ try {
52
+ const [descRes, typeRes] = await Promise.all([
53
+ xObject.getDesc(assetApiKey),
54
+ xObject.getEntityTypeList(assetApiKey),
55
+ ]);
56
+ if (typeRes?.status) {
57
+ setEntityTypeList(typeRes.data || []);
58
+ }
59
+ if (descRes?.status) {
60
+ const data = descRes.data || {};
61
+ const fields: FieldDesc[] = data.fields || [];
62
+ setObjectLabel(data.label || '');
63
+ setFieldList(fields);
64
+ } else {
65
+ setFieldList([]);
66
+ message.error(descRes?.msg || '获取实体字段失败');
67
+ }
68
+ } catch (e) {
69
+ console.error(e);
70
+ message.error('获取实体字段失败');
71
+ setFieldList([]);
72
+ } finally {
73
+ setLoadingMeta(false);
74
+ }
75
+ }, [assetApiKey]);
76
+
77
+ React.useEffect(() => {
78
+ if (visible && assetApiKey) {
79
+ form.resetFields();
80
+ loadMeta();
81
+ }
82
+ }, [visible, assetApiKey, form, loadMeta]);
83
+
84
+ const filteredFields = React.useMemo(() => {
85
+ let list = fieldList;
86
+ if (assetFields && assetFields.length > 0) {
87
+ list = list.filter((f) => assetFields.includes(f.apiKey));
88
+ }
89
+ return list.filter((f) => f.apiKey !== 'id');
90
+ }, [fieldList, assetFields]);
91
+
92
+ const handleOk = () => {
93
+ if (!assetApiKey) return;
94
+ form.validateFields().then(async (values: any) => {
95
+ setSubmitting(true);
96
+ const payload = { ...values };
97
+ Object.keys(payload).forEach((fieldKey) => {
98
+ const field = fieldList.find((f) => f.apiKey === fieldKey);
99
+ if (
100
+ field &&
101
+ (field.type === 'date' ||
102
+ field.type === 'datetime' ||
103
+ field.type === 'time')
104
+ ) {
105
+ const v = payload[fieldKey];
106
+ if (v && moment.isMoment(v)) {
107
+ payload[fieldKey] = v.valueOf();
108
+ } else if (v instanceof Date) {
109
+ payload[fieldKey] = v.getTime();
110
+ }
111
+ }
112
+ });
113
+ try {
114
+ const response = await xObject.create(assetApiKey, {
115
+ data: payload,
116
+ method: 'POST',
117
+ });
118
+ if (response && (response.code === 200 || response.code === '200')) {
119
+ message.success('创建成功');
120
+ onClose();
121
+ onSuccess();
122
+ } else {
123
+ message.error(response?.message || '创建失败');
124
+ }
125
+ } catch (err) {
126
+ console.error(err);
127
+ message.error('创建失败');
128
+ } finally {
129
+ setSubmitting(false);
130
+ }
131
+ });
132
+ };
133
+
134
+ const titleName = entityLabel || objectLabel || assetApiKey || '资产';
135
+
136
+ const renderFieldInput = (field: FieldDesc) => {
137
+ const selectitem = field.selectitem || [];
138
+ const checkitem = field.checkitem || [];
139
+
140
+ switch (field.type) {
141
+ case 'entityType':
142
+ case 'entitytype':
143
+ return (
144
+ <Select placeholder="请选择业务类型">
145
+ {entityTypeList.map((item) => (
146
+ <Option key={item.apiKey} value={item.id} disabled={!item.active}>
147
+ {item.label}
148
+ </Option>
149
+ ))}
150
+ </Select>
151
+ );
152
+ case 'picklist':
153
+ return (
154
+ <Select placeholder={`请选择${field.label}`}>
155
+ {selectitem.map((item) => (
156
+ <Option key={item.apiKey} value={item.id}>
157
+ {item.label}
158
+ </Option>
159
+ ))}
160
+ </Select>
161
+ );
162
+ case 'textarea':
163
+ return <Input.TextArea placeholder={`请输入${field.label}`} rows={3} />;
164
+ case 'multipicklist':
165
+ return (
166
+ <Select placeholder={`请选择${field.label}`} mode="multiple">
167
+ {checkitem.map((item) => (
168
+ <Option key={item.apiKey} value={item.id}>
169
+ {item.label}
170
+ </Option>
171
+ ))}
172
+ </Select>
173
+ );
174
+ case 'datetime':
175
+ return (
176
+ <DatePicker
177
+ placeholder={`请选择${field.label}`}
178
+ format="YYYY/MM/DD HH:mm:ss"
179
+ showTime
180
+ style={{ width: '100%' }}
181
+ />
182
+ );
183
+ case 'date':
184
+ return (
185
+ <DatePicker
186
+ placeholder={`请选择${field.label}`}
187
+ format="YYYY/MM/DD"
188
+ style={{ width: '100%' }}
189
+ />
190
+ );
191
+ case 'time':
192
+ return (
193
+ <DatePicker
194
+ placeholder={`请选择${field.label}`}
195
+ format="HH:mm:ss"
196
+ showTime
197
+ style={{ width: '100%' }}
198
+ />
199
+ );
200
+ case 'int':
201
+ case 'float':
202
+ return (
203
+ <InputNumber
204
+ placeholder={`请输入${field.label}`}
205
+ style={{ width: '100%' }}
206
+ />
207
+ );
208
+ default:
209
+ return <Input placeholder={`请输入${field.label}`} />;
210
+ }
211
+ };
212
+
213
+ return (
214
+ <Modal
215
+ title={`新增${titleName}`}
216
+ visible={visible}
217
+ onOk={handleOk}
218
+ onCancel={onClose}
219
+ cancelText="取消"
220
+ okText="确定"
221
+ width={600}
222
+ destroyOnClose
223
+ confirmLoading={submitting}
224
+ >
225
+ {!assetApiKey ? (
226
+ <Empty
227
+ description="未配置资产实体 API Key"
228
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
229
+ />
230
+ ) : (
231
+ <Spin spinning={loadingMeta} tip="加载表单字段...">
232
+ {filteredFields.length === 0 && !loadingMeta ? (
233
+ <Empty
234
+ description="未获取到可填写的字段,请检查实体权限或 assetFields 配置"
235
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
236
+ />
237
+ ) : (
238
+ <Form form={form} layout="vertical">
239
+ {filteredFields.map((field) => (
240
+ <Form.Item
241
+ key={field.apiKey}
242
+ name={field.apiKey}
243
+ label={field.label}
244
+ rules={[
245
+ {
246
+ required: !!field.required,
247
+ message: `请填写${field.label}`,
248
+ },
249
+ ]}
250
+ >
251
+ {renderFieldInput(field)}
252
+ </Form.Item>
253
+ ))}
254
+ </Form>
255
+ )}
256
+ </Spin>
257
+ )}
258
+ </Modal>
259
+ );
260
+ };
@@ -0,0 +1,48 @@
1
+ import * as React from 'react';
2
+ import { Spin, Empty, Row } from 'antd';
3
+ import type { AssetItem } from '../types';
4
+ import { AssetCard } from './assetDisplay';
5
+
6
+ export interface AssetGridProps {
7
+ assetApiKey?: string;
8
+ assets: AssetItem[];
9
+ loadingAssets: boolean;
10
+ }
11
+
12
+ export function AssetGrid({
13
+ assetApiKey,
14
+ assets,
15
+ loadingAssets,
16
+ }: AssetGridProps) {
17
+ if (!assetApiKey) {
18
+ return (
19
+ <section className="asset-grid-wrapper content-placeholder">
20
+ <Empty
21
+ description="请在设计器中配置资产实体 API Key(assetApiKey)"
22
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
23
+ className="grid-empty"
24
+ />
25
+ </section>
26
+ );
27
+ }
28
+
29
+ return (
30
+ <section className="asset-grid-wrapper">
31
+ <Spin spinning={loadingAssets} tip="加载资产数据...">
32
+ {assets.length === 0 && !loadingAssets ? (
33
+ <Empty
34
+ description="暂无匹配的资产数据"
35
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
36
+ className="grid-empty"
37
+ />
38
+ ) : (
39
+ <Row gutter={[20, 20]} className="asset-grid">
40
+ {assets.map((asset) => (
41
+ <AssetCard key={asset.id} asset={asset} />
42
+ ))}
43
+ </Row>
44
+ )}
45
+ </Spin>
46
+ </section>
47
+ );
48
+ }
@@ -0,0 +1,74 @@
1
+ import * as React from 'react';
2
+ import { Spin, Empty } from 'antd';
3
+ import { AppstoreOutlined, InboxOutlined } from '@ant-design/icons';
4
+ import type { CategoryItem } from '../types';
5
+ import { CATEGORY_ICONS } from '../constants';
6
+
7
+ export interface AssetSidebarProps {
8
+ categoryApiKey?: string;
9
+ categories: CategoryItem[];
10
+ activeCategoryId: string | null;
11
+ loadingCategories: boolean;
12
+ totalAssets: number;
13
+ onCategoryClick: (categoryId: string | null) => void;
14
+ }
15
+
16
+ export function AssetSidebar({
17
+ categoryApiKey,
18
+ categories,
19
+ activeCategoryId,
20
+ loadingCategories,
21
+ totalAssets,
22
+ onCategoryClick,
23
+ }: AssetSidebarProps) {
24
+ if (!categoryApiKey) {
25
+ return (
26
+ <aside className="asset-sidebar">
27
+ <div className="sidebar-placeholder">
28
+ <Empty
29
+ description="请在设计器中配置分类实体 API Key(categoryApiKey)"
30
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
31
+ />
32
+ </div>
33
+ </aside>
34
+ );
35
+ }
36
+
37
+ return (
38
+ <aside className="asset-sidebar">
39
+ <div className="sidebar-header">
40
+ <span className="sidebar-label">资产分类</span>
41
+ </div>
42
+ <Spin spinning={loadingCategories} size="small">
43
+ <nav className="sidebar-nav">
44
+ <div
45
+ className={`sidebar-item ${
46
+ activeCategoryId === null ? 'active' : ''
47
+ }`}
48
+ onClick={() => onCategoryClick(null)}
49
+ >
50
+ <AppstoreOutlined className="sidebar-icon" />
51
+ <span className="sidebar-text">全部资产</span>
52
+ <span className="sidebar-count">{totalAssets}</span>
53
+ </div>
54
+ {categories.map((cat) => {
55
+ const icon = CATEGORY_ICONS[cat.name] || <InboxOutlined />;
56
+ return (
57
+ <div
58
+ key={cat.id}
59
+ className={`sidebar-item ${
60
+ activeCategoryId === cat.id ? 'active' : ''
61
+ }`}
62
+ onClick={() => onCategoryClick(cat.id)}
63
+ >
64
+ <span className="sidebar-icon">{icon}</span>
65
+ <span className="sidebar-text">{cat.name}</span>
66
+ </div>
67
+ );
68
+ })}
69
+ </nav>
70
+ </Spin>
71
+ <div className="sidebar-footer">数据源: {categoryApiKey}</div>
72
+ </aside>
73
+ );
74
+ }
@@ -0,0 +1,79 @@
1
+ import * as React from 'react';
2
+ import { Input, Select, Button } from 'antd';
3
+ import {
4
+ SearchOutlined,
5
+ ReloadOutlined,
6
+ PlusOutlined,
7
+ } from '@ant-design/icons';
8
+
9
+ const { Option } = Select;
10
+
11
+ export interface AssetToolbarProps {
12
+ assetApiKey?: string;
13
+ searchKeyword: string;
14
+ statusFilter: number | undefined;
15
+ loadingAssets: boolean;
16
+ onSearchChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
17
+ onStatusChange: React.ComponentProps<typeof Select>['onChange'];
18
+ onRefresh: () => void;
19
+ onAdd: () => void;
20
+ }
21
+
22
+ export function AssetToolbar({
23
+ assetApiKey,
24
+ searchKeyword,
25
+ statusFilter,
26
+ loadingAssets,
27
+ onSearchChange,
28
+ onStatusChange,
29
+ onRefresh,
30
+ onAdd,
31
+ }: AssetToolbarProps) {
32
+ const hasAsset = Boolean(assetApiKey);
33
+
34
+ return (
35
+ <section className="asset-toolbar">
36
+ <div className="toolbar-left">
37
+ <Input
38
+ className="search-input"
39
+ placeholder="搜索资产名称、序列号..."
40
+ prefix={<SearchOutlined style={{ color: '#bfbfbf' }} />}
41
+ value={searchKeyword}
42
+ onChange={onSearchChange}
43
+ allowClear
44
+ disabled={!hasAsset}
45
+ />
46
+ <Select
47
+ className="status-select"
48
+ placeholder="所有状态"
49
+ value={statusFilter}
50
+ onChange={onStatusChange}
51
+ allowClear
52
+ disabled={!hasAsset}
53
+ >
54
+ <Option value={1}>在库</Option>
55
+ <Option value={2}>使用中</Option>
56
+ <Option value={3}>维修中</Option>
57
+ </Select>
58
+ </div>
59
+ <div className="toolbar-right">
60
+ <Button
61
+ type="primary"
62
+ icon={<PlusOutlined />}
63
+ onClick={onAdd}
64
+ disabled={!hasAsset}
65
+ >
66
+ 新增资产
67
+ </Button>
68
+ <Button
69
+ icon={<ReloadOutlined />}
70
+ onClick={onRefresh}
71
+ loading={loadingAssets}
72
+ disabled={!hasAsset}
73
+ >
74
+ 刷新
75
+ </Button>
76
+ </div>
77
+ </section>
78
+ );
79
+ }
@@ -0,0 +1,72 @@
1
+ import * as React from 'react';
2
+ import { LaptopOutlined } from '@ant-design/icons';
3
+ import { Col } from 'antd';
4
+ import { STATUS_MAP } from '../constants';
5
+ import type { AssetItem } from '../types';
6
+
7
+ export function formatDate(value: string | number | undefined): string {
8
+ if (!value) return '-';
9
+ const d = new Date(typeof value === 'string' ? value : Number(value));
10
+ if (isNaN(d.getTime())) return '-';
11
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(
12
+ 2,
13
+ '0',
14
+ )}-${String(d.getDate()).padStart(2, '0')}`;
15
+ }
16
+
17
+ export function renderStatusBadge(status: string | number | undefined) {
18
+ const key = status != null && status !== '' ? String(status) : '';
19
+ const info = STATUS_MAP[key] || {
20
+ label: status != null && status !== '' ? String(status) : '未知',
21
+ color: '#8c8c8c',
22
+ bg: '#f5f5f5',
23
+ };
24
+ return (
25
+ <span
26
+ className="status-badge"
27
+ style={{ color: info.color, backgroundColor: info.bg }}
28
+ >
29
+ {info.label}
30
+ </span>
31
+ );
32
+ }
33
+
34
+ export interface AssetCardProps {
35
+ asset: AssetItem;
36
+ }
37
+
38
+ export function AssetCard({ asset }: AssetCardProps) {
39
+ const imgUrl =
40
+ asset.productIMG__c?.url || asset.productIMG__c?.fileUrl || null;
41
+
42
+ return (
43
+ <Col xs={24} sm={12} md={8} lg={6}>
44
+ <div className="asset-card">
45
+ <div className="card-image">
46
+ {imgUrl ? (
47
+ <img src={imgUrl} alt={asset.name} />
48
+ ) : (
49
+ <div className="card-image-placeholder">
50
+ <LaptopOutlined />
51
+ </div>
52
+ )}
53
+ </div>
54
+ <div className="card-body">
55
+ <div className="card-title-row">
56
+ <h3 className="card-name" title={asset.name}>
57
+ {asset.name}
58
+ </h3>
59
+ {renderStatusBadge(asset.status__c)}
60
+ </div>
61
+ <p className="card-serial">SN: {asset.serialNumber__c || '-'}</p>
62
+ <div className="card-footer">
63
+ <span className="card-date">
64
+ 入库日期: {formatDate(asset.purchaseDate__c)}
65
+ </span>
66
+ <span className="card-detail-link">详情</span>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </Col>
71
+ );
72
+ }
@@ -0,0 +1,28 @@
1
+ import * as React from 'react';
2
+ import { LaptopOutlined, CodeOutlined, InboxOutlined } from '@ant-design/icons';
3
+
4
+ /** 资产状态:与常见 picklist 取值 1/2/3 对应 */
5
+ export const STATUS_MAP: Record<
6
+ string,
7
+ { label: string; color: string; bg: string }
8
+ > = {
9
+ '1': { label: '在库', color: '#52c41a', bg: '#f6ffed' },
10
+ '2': { label: '使用中', color: '#1890ff', bg: '#e6f7ff' },
11
+ '3': { label: '维修中', color: '#ff4d4f', bg: '#fff2f0' },
12
+ };
13
+
14
+ export const DEFAULT_ASSET_FIELDS = [
15
+ 'name',
16
+ 'categoryId__c',
17
+ 'status__c',
18
+ 'serialNumber__c',
19
+ 'purchaseDate__c',
20
+ 'productIMG__c',
21
+ ];
22
+
23
+ /** 分类名称到图标(无匹配则用通用图标) */
24
+ export const CATEGORY_ICONS: Record<string, React.ReactNode> = {
25
+ 办公硬件: React.createElement(LaptopOutlined),
26
+ 正版软件: React.createElement(CodeOutlined),
27
+ 通用耗材: React.createElement(InboxOutlined),
28
+ };