neo-cmp-cli 1.12.8 → 1.12.10

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 (161) hide show
  1. package/README.md +204 -6
  2. package/dist/index2.js +1 -1
  3. package/dist/module/neoInitByCopy.js +1 -1
  4. package/dist/neo/env.js +1 -1
  5. package/dist/package.json.js +1 -1
  6. package/package.json +4 -1
  7. package/template/antd-custom-cmp-template/package.json +1 -1
  8. package/template/asset-manage-template/README.md +154 -0
  9. package/template/asset-manage-template/docs/README.md +244 -0
  10. package/template/asset-manage-template/neo.config.js +60 -0
  11. package/template/asset-manage-template/package.json +74 -0
  12. package/template/asset-manage-template/src/assets/img/chart.svg +1 -0
  13. package/template/asset-manage-template/src/components/README.md +3 -0
  14. package/template/asset-manage-template/src/components/assetManage__c/assetApi.ts +70 -0
  15. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetCreateModal.tsx +260 -0
  16. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetGrid.tsx +48 -0
  17. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetSidebar.tsx +74 -0
  18. package/template/asset-manage-template/src/components/assetManage__c/cmps/AssetToolbar.tsx +79 -0
  19. package/template/asset-manage-template/src/components/assetManage__c/cmps/assetDisplay.tsx +72 -0
  20. package/template/asset-manage-template/src/components/assetManage__c/constants.ts +28 -0
  21. package/template/asset-manage-template/src/components/assetManage__c/index.tsx +258 -0
  22. package/template/asset-manage-template/src/components/assetManage__c/model.ts +75 -0
  23. package/template/asset-manage-template/src/components/assetManage__c/style.scss +425 -0
  24. package/template/asset-manage-template/src/components/assetManage__c/types.ts +60 -0
  25. package/template/asset-manage-template/src/components/bidList__c/cmps/BidCard.tsx +47 -0
  26. package/template/asset-manage-template/src/components/bidList__c/constants.ts +6 -0
  27. package/template/asset-manage-template/src/components/bidList__c/formatUtils.ts +14 -0
  28. package/template/asset-manage-template/src/components/bidList__c/index.tsx +194 -0
  29. package/template/asset-manage-template/src/components/bidList__c/model.ts +57 -0
  30. package/template/asset-manage-template/src/components/bidList__c/style.scss +179 -0
  31. package/template/asset-manage-template/src/components/bidList__c/types.ts +10 -0
  32. package/template/asset-manage-template/src/components/bidPackage__c/cmps/BidPackageHeader.tsx +140 -0
  33. package/template/asset-manage-template/src/components/bidPackage__c/cmps/PackageItemTable.tsx +148 -0
  34. package/template/asset-manage-template/src/components/bidPackage__c/index.tsx +394 -0
  35. package/template/asset-manage-template/src/components/bidPackage__c/mainTableColumns.tsx +57 -0
  36. package/template/asset-manage-template/src/components/bidPackage__c/model.ts +86 -0
  37. package/template/asset-manage-template/src/components/bidPackage__c/style.scss +256 -0
  38. package/template/asset-manage-template/src/components/bidPackage__c/types.ts +35 -0
  39. package/template/asset-manage-template/src/components/bidPackage__c/utils.ts +19 -0
  40. package/template/{neo-bi-cmps → asset-manage-template}/src/utils/axiosFetcher.ts +0 -0
  41. package/template/{neo-bi-cmps → asset-manage-template}/src/utils/queryObjectData.ts +36 -0
  42. package/template/asset-manage-template/src/utils/url.ts +82 -0
  43. package/template/{neo-bi-cmps → asset-manage-template}/src/utils/xobjects.ts +0 -0
  44. package/template/asset-manage-template/tsconfig.json +40 -0
  45. package/template/echarts-custom-cmp-template/package.json +1 -1
  46. package/template/empty-custom-cmp-template/package.json +2 -2
  47. package/template/neo-custom-cmp-template/package.json +5 -2
  48. package/template/neo-custom-cmp-template/src/components/entityTable__c/index.tsx +62 -6
  49. package/template/neo-custom-cmp-template/src/utils/queryObjectData.ts +36 -0
  50. package/template/neo-custom-cmp-template/tsconfig.json +1 -2
  51. package/template/neo-h5-cmps/neo.config.js +1 -6
  52. package/template/neo-h5-cmps/package.json +7 -4
  53. package/template/neo-h5-cmps/src/utils/queryObjectData.ts +36 -0
  54. package/template/neo-h5-cmps/tsconfig.json +3 -4
  55. package/template/neo-order-cmps/package.json +2 -2
  56. package/template/neo-order-cmps/src/utils/queryObjectData.ts +36 -0
  57. package/template/neo-web-cmps/@types/neo-ui-common.d.ts +36 -0
  58. package/template/neo-web-cmps/neo.config.js +53 -0
  59. package/template/{neo-bi-cmps → neo-web-cmps}/package.json +10 -7
  60. package/template/neo-web-cmps/src/assets/img/AIBtn.gif +0 -0
  61. package/template/neo-web-cmps/src/assets/img/aiLogo.png +0 -0
  62. package/template/neo-web-cmps/src/assets/img/card-list.svg +1 -0
  63. package/template/neo-web-cmps/src/assets/img/contact-form.svg +1 -0
  64. package/template/neo-web-cmps/src/assets/img/custom-form.svg +1 -0
  65. package/template/neo-web-cmps/src/assets/img/data-list.svg +1 -0
  66. package/template/neo-web-cmps/src/assets/img/detail.svg +1 -0
  67. package/template/neo-web-cmps/src/assets/img/map.svg +1 -0
  68. package/template/neo-web-cmps/src/assets/img/search.svg +1 -0
  69. package/template/neo-web-cmps/src/components/entityGrid2__c/index.tsx +72 -0
  70. package/template/neo-web-cmps/src/components/entityGrid2__c/model.ts +195 -0
  71. package/template/neo-web-cmps/src/components/entityGrid2__c/style.scss +13 -0
  72. package/template/neo-web-cmps/src/components/entityGrid__c/index.tsx +52 -0
  73. package/template/neo-web-cmps/src/components/entityGrid__c/model.ts +195 -0
  74. package/template/neo-web-cmps/src/components/entityGrid__c/style.scss +13 -0
  75. package/template/neo-web-cmps/src/utils/axiosFetcher.ts +37 -0
  76. package/template/neo-web-cmps/src/utils/queryObjectData.ts +112 -0
  77. package/template/{develop/neo-custom-cmp-template → neo-web-cmps}/src/utils/xobjects.ts +28 -64
  78. package/template/{neo-bi-cmps → neo-web-cmps}/tsconfig.json +2 -3
  79. package/template/react-custom-cmp-template/package.json +1 -1
  80. package/template/react-ts-custom-cmp-template/package.json +1 -1
  81. package/template/vue2-custom-cmp-template/package.json +1 -1
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. package/template/develop/Neo /344/270/255/345/217/257/347/224/250 amis /347/273/204/344/273/266.md" +0 -1490
  88. package/template/develop/cmpEventFunctions.ts +0 -257
  89. package/template/develop/cmpEvents.ts +0 -864
  90. 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
  91. package/template/develop/commonModules.js +0 -55
  92. package/template/develop/components-table.md +0 -50
  93. package/template/develop/neo-custom-cmp-template/README.md +0 -48
  94. package/template/develop/neo-custom-cmp-template/docs/README.md +0 -13
  95. package/template/develop/neo-custom-cmp-template/neo.config.js +0 -121
  96. package/template/develop/neo-custom-cmp-template/package.json +0 -63
  97. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/README.md +0 -65
  98. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/index.tsx +0 -180
  99. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/model.ts +0 -50
  100. package/template/develop/neo-custom-cmp-template/src/components/contactCardList/style.scss +0 -260
  101. package/template/develop/neo-custom-cmp-template/src/components/contactForm/README.md +0 -94
  102. package/template/develop/neo-custom-cmp-template/src/components/contactForm/index.tsx +0 -252
  103. package/template/develop/neo-custom-cmp-template/src/components/contactForm/model.ts +0 -56
  104. package/template/develop/neo-custom-cmp-template/src/components/contactForm/style.scss +0 -120
  105. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/README.md +0 -115
  106. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/index.tsx +0 -304
  107. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/model.ts +0 -87
  108. package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/style.scss +0 -127
  109. package/template/develop/neo-custom-cmp-template/src/utils/axiosFetcher.ts +0 -29
  110. package/template/develop/neo-custom-cmp-template/src/utils/queryObjectData.ts +0 -39
  111. package/template/develop/neo-custom-cmp-template/tsconfig.json +0 -68
  112. package/template/develop/neo-ui-component-h5.md +0 -105
  113. package/template/develop/neo-ui-component-web-xregister.md +0 -31
  114. package/template/develop/neo-ui-component-web.md +0 -292
  115. package/template/develop/neoCmps.ts +0 -7508
  116. 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
  117. package/template/develop/pageSchema1.json +0 -744
  118. 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
  119. 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
  120. package/template/develop//345/261/236/346/200/247/351/205/215/347/275/256/351/241/271/347/261/273/345/236/213/346/261/207/346/200/273.md +0 -558
  121. package/template/neo-bi-cmps/neo.config.js +0 -124
  122. package/template/neo-bi-cmps/src/components/targetNumber__c/README.md +0 -100
  123. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/configSchema.ts +0 -253
  124. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/index.scss +0 -76
  125. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/index.tsx +0 -148
  126. package/template/neo-bi-cmps/src/components/targetNumber__c/index.tsx +0 -440
  127. package/template/neo-bi-cmps/src/components/targetNumber__c/model.ts +0 -128
  128. package/template/neo-bi-cmps/src/components/targetNumber__c/style.scss +0 -173
  129. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/.prettierrc.js +0 -0
  130. /package/template/{neo-bi-cmps → asset-manage-template}/@types/neo-ui-common.d.ts +0 -0
  131. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/commitlint.config.js +0 -0
  132. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/public/css/base.css +0 -0
  133. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/public/scripts/app/bluebird.js +0 -0
  134. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/public/template.html +0 -0
  135. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/css/common.scss +0 -0
  136. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/css/mixin.scss +0 -0
  137. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/AIBtn.gif +0 -0
  138. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/NeoCRM.jpg +0 -0
  139. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/aiLogo.png +0 -0
  140. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/card-list.svg +0 -0
  141. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/contact-form.svg +0 -0
  142. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/custom-form.svg +0 -0
  143. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/custom-widget.svg +0 -0
  144. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/data-list.svg +0 -0
  145. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/detail.svg +0 -0
  146. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/favicon.png +0 -0
  147. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/map.svg +0 -0
  148. /package/template/{neo-bi-cmps → asset-manage-template}/src/assets/img/search.svg +0 -0
  149. /package/template/{develop/neo-custom-cmp-template → asset-manage-template}/src/assets/img/table.svg +0 -0
  150. /package/template/{neo-bi-cmps → neo-web-cmps}/.prettierrc.js +0 -0
  151. /package/template/{neo-bi-cmps → neo-web-cmps}/README.md +0 -0
  152. /package/template/{neo-bi-cmps → neo-web-cmps}/commitlint.config.js +0 -0
  153. /package/template/{neo-bi-cmps → neo-web-cmps}/public/css/base.css +0 -0
  154. /package/template/{neo-bi-cmps → neo-web-cmps}/public/scripts/app/bluebird.js +0 -0
  155. /package/template/{neo-bi-cmps → neo-web-cmps}/public/template.html +0 -0
  156. /package/template/{neo-bi-cmps → neo-web-cmps}/src/assets/css/common.scss +0 -0
  157. /package/template/{neo-bi-cmps → neo-web-cmps}/src/assets/css/mixin.scss +0 -0
  158. /package/template/{neo-bi-cmps → neo-web-cmps}/src/assets/img/NeoCRM.jpg +0 -0
  159. /package/template/{neo-bi-cmps → neo-web-cmps}/src/assets/img/custom-widget.svg +0 -0
  160. /package/template/{neo-bi-cmps → neo-web-cmps}/src/assets/img/favicon.png +0 -0
  161. /package/template/{neo-bi-cmps → neo-web-cmps}/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
+ };