plain-design 1.0.0-beta.77 → 1.0.0-beta.79

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 (27) hide show
  1. package/dist/plain-design.commonjs.min.js +2 -2
  2. package/dist/plain-design.min.css +2 -1
  3. package/dist/plain-design.min.js +2 -2
  4. package/dist/report.html +2 -2
  5. package/package.json +1 -1
  6. package/src/packages/components/$address/createAddressService.tsx +20 -1
  7. package/src/packages/components/$search/SearchFooter.tsx +32 -0
  8. package/src/packages/components/$search/SearchList.tsx +206 -0
  9. package/src/packages/components/$search/SearchServicePanel.tsx +233 -0
  10. package/src/packages/components/$search/createSearchService.tsx +43 -0
  11. package/src/packages/components/$search/index.tsx +6 -0
  12. package/src/packages/components/$search/search-service.scss +220 -0
  13. package/src/packages/components/$search/search.utils.tsx +112 -0
  14. package/src/packages/components/AddressCascade/createAddressCascade.multiple.tsx +1 -0
  15. package/src/packages/components/AddressCascade/createAddressCascade.single.tsx +1 -0
  16. package/src/packages/components/AddressCascade/index.tsx +2 -0
  17. package/src/packages/components/Cascade/createSingleCascadeRender.tsx +1 -1
  18. package/src/packages/components/CascadePanel/flat/cascade-flat-panel.scss +1 -0
  19. package/src/packages/components/Input/index.tsx +9 -1
  20. package/src/packages/components/Input/input.utils.ts +2 -1
  21. package/src/packages/components/Input/uses/useInputSuffixIcon.tsx +1 -1
  22. package/src/packages/components/Scroll/index.tsx +34 -0
  23. package/src/packages/components/Table/standard/PlcTree/PlcTree.renderNode.tsx +3 -0
  24. package/src/packages/entry.tsx +8 -0
  25. package/src/packages/i18n/lang/en-us.ts +9 -1
  26. package/src/packages/i18n/lang/zh-cn.ts +11 -3
  27. package/src/packages/utils/createListUtils.ts +38 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plain-design",
3
- "version": "1.0.0-beta.77",
3
+ "version": "1.0.0-beta.79",
4
4
  "description": "",
5
5
  "main": "dist/plain-design.min.js",
6
6
  "module": "dist/plain-design.commonjs.min.js",
@@ -1,6 +1,7 @@
1
1
  import {eAddressTypeEnum, iAddressLazyMeta, iAddressSyncMeta} from "./address.utils";
2
2
  import {defer, DFD} from "plain-utils/utils/defer";
3
3
  import {reactive} from "plain-design-composition";
4
+ import i18n from "../i18n";
4
5
 
5
6
  export function createAddressService(
6
7
  config: {
@@ -126,13 +127,14 @@ export function createAddressService(
126
127
  };
127
128
  })();
128
129
 
130
+ let dfd: DFD<iAddressSyncMeta[]> | null = null;
131
+
129
132
  /**
130
133
  * 带缓存地查询所有地址数据
131
134
  * @author 韦胜健
132
135
  * @date 2022.12.16 23:20
133
136
  */
134
137
  const getAddress = (() => {
135
- let dfd: DFD<iAddressSyncMeta[]> | null = null;
136
138
  return () => {
137
139
  if (!dfd) {
138
140
  dfd = defer<iAddressSyncMeta[]>();
@@ -142,6 +144,15 @@ export function createAddressService(
142
144
  };
143
145
  })();
144
146
 
147
+ /**
148
+ * 清理缓存
149
+ * @author 韦胜健
150
+ * @date 2024.6.18 15:34
151
+ */
152
+ const clear = () => {
153
+ dfd = null;
154
+ };
155
+
145
156
  const getAddressByCodesComputed = (() => {
146
157
 
147
158
  const state = reactive({
@@ -171,6 +182,13 @@ export function createAddressService(
171
182
  return getter;
172
183
  })();
173
184
 
185
+ /**
186
+ * 切换多语言的时候清理缓存
187
+ * @author 韦胜健
188
+ * @date 2024.6.18 15:35
189
+ */
190
+ i18n.hooks.onChangeLang.use(() => clear());
191
+
174
192
  return {
175
193
  config,
176
194
  getAddressByLabel,
@@ -178,6 +196,7 @@ export function createAddressService(
178
196
  getAddressByParentCodes,
179
197
  getAddress,
180
198
  getAddressByCodesComputed,
199
+ clear,
181
200
  };
182
201
  }
183
202
 
@@ -0,0 +1,32 @@
1
+ import {designPage} from "plain-design-composition";
2
+ import {i18n} from "../i18n";
3
+
4
+ export const SearchFooter = designPage(() => {
5
+ return () => (
6
+ <>
7
+ <svg width="15" height="15" aria-label="Enter key" role="img">
8
+ <g fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.2">
9
+ <path d="M12 3.53088v3c0 1-1 2-2 2H4M7 11.53088l-3-3 3-3"></path>
10
+ </g>
11
+ </svg>
12
+ <span>{i18n.$it('search.select').d('选择')}</span>
13
+ <svg width="15" height="15" aria-label="Arrow down" role="img">
14
+ <g fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.2">
15
+ <path d="M7.5 3.5v8M10.5 8.5l-3 3-3-3"></path>
16
+ </g>
17
+ </svg>
18
+ <svg width="15" height="15" aria-label="Arrow up" role="img">
19
+ <g fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.2">
20
+ <path d="M7.5 11.5v-8M10.5 6.5l-3-3-3 3"></path>
21
+ </g>
22
+ </svg>
23
+ <span>{i18n.$it('search.switch').d('切换')}</span>
24
+ <svg width="15" height="15" aria-label="Escape key" role="img">
25
+ <g fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.2">
26
+ <path d="M13.6167 8.936c-.1065.3583-.6883.962-1.4875.962-.7993 0-1.653-.9165-1.653-2.1258v-.5678c0-1.2548.7896-2.1016 1.653-2.1016.8634 0 1.3601.4778 1.4875 1.0724M9 6c-.1352-.4735-.7506-.9219-1.46-.8972-.7092.0246-1.344.57-1.344 1.2166s.4198.8812 1.3445.9805C8.465 7.3992 8.968 7.9337 9 8.5c.032.5663-.454 1.398-1.4595 1.398C6.6593 9.898 6 9 5.963 8.4851m-1.4748.5368c-.2635.5941-.8099.876-1.5443.876s-1.7073-.6248-1.7073-2.204v-.4603c0-1.0416.721-2.131 1.7073-2.131.9864 0 1.6425 1.031 1.5443 2.2492h-2.956"></path>
27
+ </g>
28
+ </svg>
29
+ <span>{i18n.$it('base.close').d('关闭')}</span>
30
+ </>
31
+ );
32
+ });
@@ -0,0 +1,206 @@
1
+ import {computed, designComponent, iMouseEvent, PropType, reactive, useRefs} from "plain-design-composition";
2
+ import {iSearchDataMeta, iSearchServiceConfig, SearchOptionButton, SearchTreeIcon, SearchType2Icon} from "./search.utils";
3
+ import {createListUtils} from "../../utils/createListUtils";
4
+ import {delay} from "plain-utils/utils/delay";
5
+ import VirtualList from "../VirtualList";
6
+
7
+ export const SearchList = designComponent({
8
+ props: {
9
+ data: { type: Array as PropType<iSearchDataMeta[]>, required: true },
10
+ config: { type: Object as PropType<iSearchServiceConfig>, required: true }
11
+ },
12
+ slots: ['default'],
13
+ emits: {
14
+ /*选中选项事件*/
15
+ onSelect: (val: iSearchDataMeta) => true,
16
+ /*删除选项事件,选项可能是历史选项,也可能是收藏选项*/
17
+ onRemoveItem: (val: iSearchDataMeta) => true,
18
+ /*添加选项为收藏选项*/
19
+ onAddFavorite: (val: iSearchDataMeta) => true,
20
+ },
21
+ setup({ props, slots, event: { emit } }) {
22
+
23
+ const { refs, onRef } = useRefs({ virtual: VirtualList });
24
+
25
+ const state = reactive({
26
+ /*当前选中的选项位置索引*/
27
+ selectIndex: null as null | number
28
+ });
29
+
30
+ /*有效可选中的选项数组*/
31
+ const availableList = computed(() => props.data.filter(i => i.type !== 'group'));
32
+ /*选中选项在有效选项数组中的位置索引*/
33
+ const availableIndex = computed(() => state.selectIndex == null ? null : availableList.value.indexOf(props.data[state.selectIndex]));
34
+
35
+ const listUtils = createListUtils({ getList: () => availableList.value, current: () => availableIndex.value, });
36
+
37
+ const methods = {
38
+ /**
39
+ * 选中上一个节点
40
+ * @author 韦胜健
41
+ * @date 2024.6.23 21:27
42
+ */
43
+ selectPrev: async () => {
44
+ const newAvailableIndex = listUtils.prevIndex();
45
+ if (newAvailableIndex == -1) {return;}
46
+ const newSelectIndex = props.data.indexOf(availableList.value[newAvailableIndex]);
47
+ if (!!refs.virtual && availableIndex.value == 0 && newAvailableIndex == availableList.value.length - 1) {
48
+ /*滚动到底部再选中选项*/
49
+ refs.virtual.refs.scroll?.methods.scrollEnd();
50
+ await delay(78);
51
+ } else {
52
+ refs.virtual?.refs.scroll?.methods.showElement(`[data-index="_${newSelectIndex}"]`);
53
+ }
54
+ state.selectIndex = newSelectIndex;
55
+ },
56
+ /**
57
+ * 选中下一个节点
58
+ * @author 韦胜健
59
+ * @date 2024.6.23 21:28
60
+ */
61
+ selectNext: async () => {
62
+ const newAvailableIndex = listUtils.nextIndex();
63
+ if (newAvailableIndex == -1) {return;}
64
+ const newSelectIndex = props.data.indexOf(availableList.value[newAvailableIndex]);
65
+ if (!!refs.virtual && availableIndex.value == availableList.value.length - 1 && newAvailableIndex == 0) {
66
+ /*滚动到顶部再选中选项*/
67
+ refs.virtual.refs.scroll?.methods.scrollTop(0);
68
+ await delay(78);
69
+ } else {
70
+ refs.virtual?.refs.scroll?.methods.showElement(`[data-index="_${newSelectIndex}"]`);
71
+ }
72
+ state.selectIndex = newSelectIndex;
73
+ },
74
+ /**
75
+ * 获取当前选中的节点
76
+ * @author 韦胜健
77
+ * @date 2024.6.23 21:28
78
+ */
79
+ getSelected: (): iSearchDataMeta | null => {
80
+ return state.selectIndex == null ? null : props.data[state.selectIndex];
81
+ },
82
+ /**
83
+ * 选中节点
84
+ * @author 韦胜健
85
+ * @date 2024.6.23 21:28
86
+ */
87
+ selectItem: (dataMeta: iSearchDataMeta) => {
88
+ emit.onSelect(dataMeta);
89
+ },
90
+ /**
91
+ * 删除收藏或者历史
92
+ * @author 韦胜健
93
+ * @date 2024.6.23 21:58
94
+ */
95
+ removeItem: (e: iMouseEvent, dataMeta: iSearchDataMeta) => {
96
+ e.stopPropagation();
97
+ emit.onRemoveItem(dataMeta);
98
+ },
99
+ /**
100
+ * 添加收藏
101
+ * @author 韦胜健
102
+ * @date 2024.6.23 21:58
103
+ */
104
+ addFavorite: (e: iMouseEvent, dataMeta: iSearchDataMeta) => {
105
+ e.stopPropagation();
106
+ emit.onAddFavorite(dataMeta);
107
+ },
108
+ /**
109
+ * 重置选中节点
110
+ * @author 韦胜健
111
+ * @date 2024.6.23 23:42
112
+ */
113
+ resetSelectIndex: async () => {
114
+ await delay();
115
+ state.selectIndex = !availableList.value.length ? null : props.data.indexOf(availableList.value[0]);
116
+ },
117
+ };
118
+
119
+ const renderItem = (
120
+ { item, vid, index }: {
121
+ item: iSearchDataMeta, vid: string, index: number
122
+ }
123
+ ) => {
124
+
125
+ /**
126
+ * 是否为最后一个subHeader,如果返回值为null,表明不是sub_header,否则true为最后一个sub_header,false为普通sub_header
127
+ * @author 韦胜健
128
+ * @date 2024.6.23 23:49
129
+ */
130
+ const isLastSubHeader = (() => {
131
+ if (item.type !== 'sub_header') {return null;}
132
+ const nextItem = index + 1 > props.data.length - 1 ? null : props.data[index + 1];
133
+ return !(!!nextItem && nextItem.type === 'sub_header');
134
+ })();
135
+
136
+ return (
137
+ <div
138
+ className={`search-service-option-item`}
139
+ data-active={String(state.selectIndex === index)}
140
+ key={vid}
141
+ data-vid={vid}
142
+ data-index={`_${index}`}
143
+ onMouseEnter={() => item.type != 'group' && (state.selectIndex = index)}
144
+ >
145
+ {(props.config.render || ((item: iSearchDataMeta) => {
146
+ return (
147
+ <div className="search-service-option-item-default" data-service-item-type={item.type}>
148
+ {item.type == 'group' ? (
149
+ <div className="search-service-option-item-default-title">{item.title}</div>
150
+ ) : (
151
+ <div className="search-service-option-item-default-box" onClick={() => methods.selectItem(item)}>
152
+ {isLastSubHeader != null && SearchTreeIcon[isLastSubHeader ? 'last' : 'normal']()}
153
+ {SearchType2Icon[item.type]()}
154
+ <div className="search-service-option-item-default-label">
155
+ {item.title && <span>{item.title}</span>}
156
+ {item.desc && <span>{item.desc}</span>}
157
+ </div>
158
+ {item.type === 'favorite' ?
159
+ SearchOptionButton.remove((e) => methods.removeItem(e, item)) :
160
+ item.type === 'history' ? <>
161
+ {SearchOptionButton.favorite((e) => methods.addFavorite(e, item))}
162
+ {SearchOptionButton.remove((e) => methods.removeItem(e, item))}
163
+ </> : SearchOptionButton.normal()}
164
+ </div>
165
+ )}
166
+ </div>
167
+ );
168
+ }))(item)}
169
+ </div>
170
+ );
171
+ };
172
+
173
+ return {
174
+ refer: {
175
+ refs,
176
+ methods,
177
+ },
178
+ render: () => (
179
+ !props.data.length ? (
180
+ <div className="search-service-empty" key="empty">
181
+ {slots.default()}
182
+ </div>
183
+ ) : (
184
+ <div className="search-service-list" key="list">
185
+ {availableList.value.length <= 6 ? (
186
+ /*不超过6个元素,就直接渲染选项数组*/
187
+ props.data.map((item, index) => (renderItem({ item, vid: `_${(item.title || String(index)) + (item.desc || String(index))}`, index })))
188
+ ) : (
189
+ /*超过6个就渲染虚拟列表*/
190
+ <div className="search-service-option-virtual-list">
191
+ <VirtualList
192
+ ref={onRef.virtual}
193
+ size={56}
194
+ dynamicSize
195
+ data={props.data}
196
+ alwaysShowScrollbar
197
+ v-slots={{ default: ({ item, vid, index }) => renderItem({ item, vid, index }) }}
198
+ />
199
+ </div>
200
+ )}
201
+ </div>
202
+ )
203
+ )
204
+ };
205
+ },
206
+ });
@@ -0,0 +1,233 @@
1
+ import {computed, createStore, designComponent, getComponentCls, onMounted, PropType, reactive, useClassCache, useRefs} from "plain-design-composition";
2
+ import {iSearchDataMeta, iSearchServiceConfig} from "./search.utils";
3
+ import {debounce} from "plain-utils/utils/debounce";
4
+ import {handleKeyboard} from "../KeyboardService";
5
+ import {Box} from "../Box";
6
+ import Input from "../Input";
7
+ import {SearchList} from "./SearchList";
8
+ import {SearchFooter} from "./SearchFooter";
9
+ import ApplicationConfigurationProvider from "../ApplicationConfigurationProvider";
10
+ import {i18n} from "../../i18n";
11
+
12
+ export const SearchServicePanel = designComponent({
13
+ props: {
14
+ config: { type: Object as PropType<iSearchServiceConfig>, required: true }
15
+ },
16
+ emits: {
17
+ onClose: () => true,
18
+ },
19
+ setup({ props, event: { emit } }) {
20
+
21
+ const configuration = ApplicationConfigurationProvider.inject();
22
+
23
+ /*微调输入框以及footer在黑白主题下的颜色*/
24
+ const inputBackgroundColor = computed(() => ({ backgroundColor: configuration.value.theme.vars[configuration.value.theme.dark ? "bg-1" : 'bg-2'] }));
25
+
26
+ /**
27
+ * 搜索缓存
28
+ * @author 韦胜健
29
+ * @date 2024.6.23 21:21
30
+ */
31
+ const searchCache = createStore({
32
+ initialState: {
33
+ history: [] as iSearchDataMeta[],
34
+ favorite: [] as iSearchDataMeta[],
35
+ },
36
+ getCacheConfig: () => ({ envName: getComponentCls(''), cacheName: props.config.cacheName || `@@search_service}` })
37
+ });
38
+
39
+ const { refs, onRef } = useRefs({ list: SearchList });
40
+
41
+ const state = reactive({
42
+ /*当前输入的搜索关键词*/
43
+ searchText: '',
44
+ /*展示的选项数据*/
45
+ data: [] as iSearchDataMeta[],
46
+ /*当前是否处于加载状态*/
47
+ loading: false,
48
+ /*当前是否处于输入状态*/
49
+ editing: false,
50
+ });
51
+
52
+ const historyData = computed(() => {
53
+ const data: iSearchDataMeta[] = [];
54
+ if (!!searchCache.value.history.length) {
55
+ data.push({ title: i18n.$it('search.searchHistory').d('搜索历史'), type: 'group' });
56
+ data.push(...searchCache.value.history);
57
+ }
58
+ if (!!searchCache.value.favorite.length) {
59
+ data.push({ title: i18n.$it('search.favorite').d('收藏'), type: 'group' });
60
+ data.push(...searchCache.value.favorite);
61
+ }
62
+ return data;
63
+ });
64
+
65
+ const classes = useClassCache(() => [
66
+ getComponentCls('search-service-panel')
67
+ ]);
68
+
69
+ const handler = {
70
+ /**
71
+ * 每次输入搜索关键词的时候都重置数据,防抖执行
72
+ * @author 韦胜健
73
+ * @date 2024.6.23 21:23
74
+ */
75
+ resetData: debounce(async () => {
76
+ if (!state.searchText.trim().length) {
77
+ state.data = [];
78
+ state.editing = false;
79
+ refs.list?.methods.resetSelectIndex();
80
+ return;
81
+ }
82
+ state.loading = true;
83
+ try {
84
+ state.data = await props.config.getData(state.searchText);
85
+ } catch (e) {
86
+ state.data = [];
87
+ throw e;
88
+ } finally {
89
+ state.loading = false;
90
+ state.editing = false;
91
+ refs.list?.methods.resetSelectIndex();
92
+ }
93
+ }, 300),
94
+ /**
95
+ * 搜索关键词变化的话立即标识处于输入状态
96
+ * @author 韦胜健
97
+ * @date 2024.6.23 21:24
98
+ */
99
+ onInputChange: () => {
100
+ state.editing = true;
101
+ handler.resetData();
102
+ },
103
+ /**
104
+ * 处理上下以及enter,esc快捷键
105
+ * @author 韦胜健
106
+ * @date 2024.6.23 21:24
107
+ */
108
+ onKeydown: handleKeyboard({
109
+ up: async (e) => {
110
+ e.preventDefault();
111
+ e.stopPropagation();
112
+ refs.list?.methods.selectPrev();
113
+ },
114
+ down: async (e) => {
115
+ e.preventDefault();
116
+ e.stopPropagation();
117
+ refs.list?.methods.selectNext();
118
+ },
119
+ enter: (e) => {
120
+ e.preventDefault();
121
+ e.stopPropagation();
122
+ const target = refs.list?.methods.getSelected();
123
+ if (!target) {return;}
124
+ handler.onSelectItem(target);
125
+ },
126
+ esc: (e) => {
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+ emit.onClose();
130
+ },
131
+ }),
132
+ /**
133
+ * 处理选中某个选项的动作
134
+ * @author 韦胜健
135
+ * @date 2024.6.23 21:24
136
+ */
137
+ onSelectItem: (dataMeta: iSearchDataMeta) => {
138
+ if (!historyData.value.find(i => i.title === dataMeta.title && i.desc === dataMeta.desc)) {
139
+ dataMeta = { ...dataMeta, type: 'history' };
140
+ searchCache.value.history.unshift(dataMeta);
141
+ if (searchCache.value.history.length > 5) {searchCache.value.history.pop();}
142
+ searchCache.value = { ...searchCache.value };
143
+ }
144
+ props.config.onSelect(dataMeta);
145
+ emit.onClose();
146
+ },
147
+ onRemoveItem: (dataMeta: iSearchDataMeta) => {
148
+ const historyIndex = searchCache.value.history.findIndex(i => i.title === dataMeta.title && i.desc === dataMeta.desc && i.type === 'history');
149
+ if (historyIndex > -1) {
150
+ searchCache.value.history.splice(historyIndex, 1);
151
+ searchCache.value = { ...searchCache.value };
152
+ return;
153
+ }
154
+ const favoriteIndex = searchCache.value.favorite.findIndex(i => i.title === dataMeta.title && i.desc === dataMeta.desc && i.type === 'favorite');
155
+ if (favoriteIndex > -1) {
156
+ searchCache.value.favorite.splice(favoriteIndex, 1);
157
+ searchCache.value = { ...searchCache.value };
158
+ return;
159
+ }
160
+ },
161
+ onAddFavorite: (dataMeta: iSearchDataMeta) => {
162
+ handler.onRemoveItem(dataMeta);
163
+ dataMeta = { ...dataMeta, type: 'favorite' };
164
+ searchCache.value.favorite.unshift(dataMeta);
165
+ searchCache.value = { ...searchCache.value };
166
+ },
167
+ };
168
+
169
+ const renderList = (data: iSearchDataMeta[], empty: () => any) => {
170
+ return (
171
+ <SearchList
172
+ ref={onRef.list}
173
+ data={data}
174
+ config={props.config}
175
+ onSelect={handler.onSelectItem}
176
+ onRemoveItem={handler.onRemoveItem}
177
+ onAddFavorite={handler.onAddFavorite}
178
+ >
179
+ {empty()}
180
+ </SearchList>
181
+ );
182
+ };
183
+
184
+ onMounted(() => {
185
+ refs.list?.methods.resetSelectIndex();
186
+ });
187
+
188
+ return () => (
189
+ <Box className={classes.value}>
190
+ <div className="search-service-input-box">
191
+ <Input
192
+ style={inputBackgroundColor.value}
193
+ autoFocus
194
+ prefixIcon="pi-search"
195
+ v-model={state.searchText}
196
+ placeholder={props.config.placeholder}
197
+ inputMode="stroke"
198
+ onChange={handler.onInputChange}
199
+ loading={state.loading}
200
+ loadingType="kappa"
201
+ onKeyDown={handler.onKeydown}
202
+ />
203
+ </div>
204
+ <div className="search-service-body">
205
+ {!state.searchText.trim().length || (state.editing && !state.data.length) ? (
206
+ /*如果没有搜索关键词,或者处于输入关键词状态并且没有数据的话,显示搜索历史*/
207
+ renderList(historyData.value, () => (
208
+ <div className="search-service-panel-history" key="history">
209
+ {i18n.$it('search.noHistory').d('没有搜索历史')}
210
+ </div>))
211
+ ) : (
212
+ /*否则显示具体的数据*/
213
+ renderList(state.data, () => {
214
+ return (
215
+ <div key="no_match">
216
+ <svg width="40" height="40" viewBox="0 0 20 20" fill="none" fillRule="evenodd" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round">
217
+ <path d="M15.5 4.8c2 3 1.7 7-1 9.7h0l4.3 4.3-4.3-4.3a7.8 7.8 0 01-9.8 1m-2.2-2.2A7.8 7.8 0 0113.2 2.4M2 18L18 2"></path>
218
+ </svg>
219
+ <div>
220
+ {i18n.$it('search.noMatch', { val: state.searchText }).d(`无法找到搜索结果 "${state.searchText}"`)}
221
+ </div>
222
+ </div>
223
+ );
224
+ })
225
+ )}
226
+ </div>
227
+ <div className="search-service-foot" style={inputBackgroundColor.value}>
228
+ {props.config.footer ? props.config.footer() : (<SearchFooter/>)}
229
+ </div>
230
+ </Box>
231
+ );
232
+ },
233
+ });
@@ -0,0 +1,43 @@
1
+ import {iSearchServiceConfig, iSearchServiceCustomConfig, iSearchServiceDefaultConfig} from "./search.utils";
2
+ import $dialog from "../$dialog";
3
+ import {getComponentCls} from "plain-design-composition";
4
+ import './search-service.scss';
5
+ import {i18n} from "../i18n";
6
+
7
+ import {SearchServicePanel} from "./SearchServicePanel";
8
+
9
+ export function createSearchService(defaultConfig?: Partial<iSearchServiceDefaultConfig>) {
10
+
11
+ const _defaultConfig: iSearchServiceDefaultConfig = {
12
+ width: defaultConfig?.width || 560,
13
+ footer: defaultConfig?.footer,
14
+ render: defaultConfig?.render,
15
+ placeholder: defaultConfig?.placeholder || i18n.$it('table.pleaseEnterSearchKey').d('请输入搜索关键词')
16
+ };
17
+
18
+ return (customConfig: iSearchServiceCustomConfig & Partial<iSearchServiceDefaultConfig>) => {
19
+
20
+ const config: iSearchServiceConfig = {
21
+ ..._defaultConfig,
22
+ ...customConfig,
23
+ };
24
+
25
+ const closeDialog = $dialog({
26
+ width: config.width,
27
+ noHead: true,
28
+ noFoot: true,
29
+ externalClass: getComponentCls('search-service'),
30
+ noContentPadding: true,
31
+ render: () => {
32
+ return (
33
+ <SearchServicePanel config={config} onClose={closeDialog}/>
34
+ );
35
+ },
36
+ });
37
+
38
+ return {
39
+ close: closeDialog,
40
+ };
41
+ };
42
+ }
43
+
@@ -0,0 +1,6 @@
1
+ import {createSearchService} from "./createSearchService";
2
+
3
+ export const $search = createSearchService();
4
+
5
+ export default $search;
6
+