@pnt-team/pnt-component-frontend 0.0.111 → 0.0.116

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 (37) hide show
  1. package/README.md +29 -30
  2. package/lib/cjs/api/index.d.ts +9 -1
  3. package/lib/cjs/api/index.js +6 -0
  4. package/lib/cjs/api/types/index.d.ts +43 -6
  5. package/lib/cjs/components/PntBusinessSelect/index.d.ts +0 -5
  6. package/lib/cjs/components/PntBusinessSelect/index.js +1 -11
  7. package/lib/cjs/components/PntRegionSelect/ImportDialog.d.ts +25 -0
  8. package/lib/cjs/components/PntRegionSelect/ImportDialog.js +244 -0
  9. package/lib/cjs/components/PntRegionSelect/index.d.ts +34 -0
  10. package/lib/cjs/components/PntRegionSelect/index.js +387 -0
  11. package/lib/cjs/components/PntRegionSelect/index.scss +166 -0
  12. package/lib/cjs/components/PntRegionSelect/types.d.ts +160 -0
  13. package/lib/cjs/components/PntRegionSelect/types.js +51 -0
  14. package/lib/cjs/components/PntSecureBox/index.scss +3 -0
  15. package/lib/cjs/config.d.ts +17 -0
  16. package/lib/cjs/index.d.ts +5 -1
  17. package/lib/cjs/index.js +10 -0
  18. package/lib/esm/api/index.d.ts +9 -1
  19. package/lib/esm/api/index.js +10 -1
  20. package/lib/esm/api/types/index.d.ts +43 -6
  21. package/lib/esm/components/PntBusinessSelect/index.d.ts +0 -5
  22. package/lib/esm/components/PntBusinessSelect/index.js +1 -3
  23. package/lib/esm/components/PntRegionSelect/ImportDialog.d.ts +25 -0
  24. package/lib/esm/components/PntRegionSelect/ImportDialog.js +241 -0
  25. package/lib/esm/components/PntRegionSelect/index.d.ts +34 -0
  26. package/lib/esm/components/PntRegionSelect/index.js +368 -0
  27. package/lib/esm/components/PntRegionSelect/index.scss +166 -0
  28. package/lib/esm/components/PntRegionSelect/types.d.ts +160 -0
  29. package/lib/esm/components/PntRegionSelect/types.js +49 -0
  30. package/lib/esm/components/PntSecureBox/index.scss +3 -0
  31. package/lib/esm/config.d.ts +17 -0
  32. package/lib/esm/config.js +4 -0
  33. package/lib/esm/index.d.ts +5 -1
  34. package/lib/esm/index.js +3 -0
  35. package/lib/umd/pnt-component-frontend.min.css +1 -1
  36. package/lib/umd/pnt-component-frontend.min.js +1 -1
  37. package/package.json +1 -1
@@ -0,0 +1,387 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/components/PntRegionSelect/index.tsx
30
+ var PntRegionSelect_exports = {};
31
+ __export(PntRegionSelect_exports, {
32
+ default: () => PntRegionSelect_default
33
+ });
34
+ module.exports = __toCommonJS(PntRegionSelect_exports);
35
+ var import_api = require("../../api");
36
+ var import_config = require("../../config");
37
+ var import_react = require("react");
38
+ var import_tdesign_react = require("tdesign-react");
39
+ var import_ImportDialog = __toESM(require("./ImportDialog"));
40
+ var import_index = require("./index.scss");
41
+ var import_types = require("./types");
42
+ var import_jsx_runtime = require("react/jsx-runtime");
43
+ var toRegionOptions = (list) => (list || []).map((item) => {
44
+ var _a, _b, _c;
45
+ return {
46
+ ...item,
47
+ region_code: (_a = item.region_code) != null ? _a : "",
48
+ region_ch: (_b = item.region_ch) != null ? _b : "",
49
+ region_en: (_c = item.region_en) != null ? _c : ""
50
+ };
51
+ });
52
+ var getLabelText = (item, format) => {
53
+ const { region_ch, region_en, region_code } = item;
54
+ switch (format) {
55
+ case "name_en":
56
+ return region_en || region_ch || region_code;
57
+ case "name_en_name":
58
+ return region_en && region_ch ? `${region_en}(${region_ch})` : region_en || region_ch || region_code;
59
+ case "code":
60
+ return region_code;
61
+ default:
62
+ return region_ch || region_en || region_code;
63
+ }
64
+ };
65
+ var PntRegionSelect = (props) => {
66
+ const {
67
+ value = [],
68
+ onChange,
69
+ multiple = true,
70
+ dataSource = "default",
71
+ scope = "business",
72
+ gameId,
73
+ options: externalOptions,
74
+ disabled = false,
75
+ placeholder,
76
+ max,
77
+ filterable = true,
78
+ labelFormat = "name",
79
+ texts: customTexts,
80
+ onLoaded,
81
+ optionDisabled,
82
+ optionTooltip,
83
+ importable = false,
84
+ invertible = false,
85
+ minCollapsedNum,
86
+ collapsedItems,
87
+ onBlur,
88
+ importDialogProps,
89
+ className,
90
+ style,
91
+ popupProps
92
+ } = props;
93
+ const { http, regionQuery } = (0, import_config.usePntConfig)();
94
+ const texts = (0, import_react.useMemo)(
95
+ () => ({ ...import_types.DEFAULT_TEXTS, ...customTexts }),
96
+ [customTexts]
97
+ );
98
+ const [innerOptions, setInnerOptions] = (0, import_react.useState)([]);
99
+ const [loading, setLoading] = (0, import_react.useState)(false);
100
+ const [searchKeyword, setSearchKeyword] = (0, import_react.useState)("");
101
+ const [importVisible, setImportVisible] = (0, import_react.useState)(false);
102
+ const fetchSeqRef = (0, import_react.useRef)(0);
103
+ const onLoadedRef = (0, import_react.useRef)(onLoaded);
104
+ onLoadedRef.current = onLoaded;
105
+ const isExternal = externalOptions !== void 0;
106
+ const fetchData = (0, import_react.useCallback)(async () => {
107
+ var _a, _b, _c;
108
+ if (isExternal)
109
+ return;
110
+ const seq = ++fetchSeqRef.current;
111
+ setLoading(true);
112
+ try {
113
+ let list = [];
114
+ const url = scope === "platform" ? (regionQuery == null ? void 0 : regionQuery.queryPlatUrl) || "/api/v5/business/region/plat-query?audience=/laas-pnt" : (regionQuery == null ? void 0 : regionQuery.queryUrl) || "/api/v5/business/region/query?audience=/laas-pnt";
115
+ if (dataSource === "business") {
116
+ if (!gameId) {
117
+ console.warn(
118
+ '[PntRegionSelect] dataSource="business" 时必须传入 gameId'
119
+ );
120
+ return;
121
+ }
122
+ const res = await (0, import_api.businessRegionQuery)(http, {
123
+ game_id: Number(gameId)
124
+ }, url);
125
+ if (seq !== fetchSeqRef.current)
126
+ return;
127
+ if (res.code === 0 && ((_a = res.data) == null ? void 0 : _a.region_list)) {
128
+ list = toRegionOptions(res.data.region_list);
129
+ }
130
+ } else {
131
+ const res = await (0, import_api.businessRegionQuery)(http, {}, url);
132
+ if (seq !== fetchSeqRef.current)
133
+ return;
134
+ if (res.code === 0 && ((_b = res.data) == null ? void 0 : _b.region_list)) {
135
+ list = toRegionOptions(res.data.region_list);
136
+ }
137
+ }
138
+ setInnerOptions(list);
139
+ (_c = onLoadedRef.current) == null ? void 0 : _c.call(onLoadedRef, list);
140
+ } catch {
141
+ } finally {
142
+ if (seq === fetchSeqRef.current) {
143
+ setLoading(false);
144
+ }
145
+ }
146
+ }, [http, dataSource, gameId, isExternal, scope, regionQuery]);
147
+ (0, import_react.useEffect)(() => {
148
+ fetchData();
149
+ }, [fetchData]);
150
+ const options = (0, import_react.useMemo)(
151
+ () => isExternal ? externalOptions : innerOptions,
152
+ [isExternal, externalOptions, innerOptions]
153
+ );
154
+ const valueArr = (0, import_react.useMemo)(() => {
155
+ if (value === void 0 || value === null || value === "")
156
+ return [];
157
+ return Array.isArray(value) ? value.map(String) : [String(value)];
158
+ }, [value]);
159
+ const filteredOptions = (0, import_react.useMemo)(() => {
160
+ if (!searchKeyword)
161
+ return options;
162
+ const kw = searchKeyword.toLowerCase();
163
+ return options.filter(
164
+ (item) => {
165
+ var _a, _b, _c;
166
+ return ((_a = item.region_ch) == null ? void 0 : _a.toLowerCase().includes(kw)) || ((_b = item.region_en) == null ? void 0 : _b.toLowerCase().includes(kw)) || ((_c = item.region_code) == null ? void 0 : _c.toLowerCase().includes(kw));
167
+ }
168
+ );
169
+ }, [options, searchKeyword]);
170
+ const isOptionDisabled = (0, import_react.useCallback)(
171
+ (item) => {
172
+ if (item.disabled)
173
+ return true;
174
+ return optionDisabled ? optionDisabled(item) : false;
175
+ },
176
+ [optionDisabled]
177
+ );
178
+ const emitMultiple = (0, import_react.useCallback)(
179
+ (nextValue) => {
180
+ onChange == null ? void 0 : onChange(
181
+ nextValue,
182
+ options.filter((o) => nextValue.includes(o.region_code))
183
+ );
184
+ },
185
+ [onChange, options]
186
+ );
187
+ const handleSelectAll = (0, import_react.useCallback)(() => {
188
+ const allValues = filteredOptions.filter((item) => !isOptionDisabled(item)).map((item) => item.region_code);
189
+ emitMultiple(Array.from(/* @__PURE__ */ new Set([...valueArr, ...allValues])));
190
+ }, [filteredOptions, valueArr, emitMultiple, isOptionDisabled]);
191
+ const handleClearAll = (0, import_react.useCallback)(() => {
192
+ emitMultiple([]);
193
+ }, [emitMultiple]);
194
+ const handleInvert = (0, import_react.useCallback)(() => {
195
+ const selectedSet = new Set(valueArr);
196
+ const nextValue = filteredOptions.filter((item) => !isOptionDisabled(item)).map((item) => item.region_code).filter((code) => !selectedSet.has(code));
197
+ emitMultiple(nextValue);
198
+ }, [filteredOptions, valueArr, emitMultiple, isOptionDisabled]);
199
+ const isAllSelected = (0, import_react.useMemo)(() => {
200
+ const selectable = filteredOptions.filter(
201
+ (item) => !isOptionDisabled(item)
202
+ );
203
+ return selectable.length > 0 && selectable.every((item) => valueArr.includes(item.region_code));
204
+ }, [filteredOptions, valueArr, isOptionDisabled]);
205
+ const isIndeterminate = (0, import_react.useMemo)(() => {
206
+ const selectable = filteredOptions.filter(
207
+ (item) => !isOptionDisabled(item)
208
+ );
209
+ const selected = selectable.filter(
210
+ (item) => valueArr.includes(item.region_code)
211
+ );
212
+ return selected.length > 0 && selected.length < selectable.length;
213
+ }, [filteredOptions, valueArr, isOptionDisabled]);
214
+ const selectOptions = (0, import_react.useMemo)(() => {
215
+ return filteredOptions.map((item) => {
216
+ const label = getLabelText(item, labelFormat);
217
+ const isDisabled = isOptionDisabled(item);
218
+ const tooltip = optionTooltip ? optionTooltip(item) : void 0;
219
+ return {
220
+ label,
221
+ value: item.region_code,
222
+ disabled: isDisabled,
223
+ tooltip,
224
+ rawItem: item
225
+ };
226
+ });
227
+ }, [filteredOptions, labelFormat, isOptionDisabled, optionTooltip]);
228
+ const handleChange = (0, import_react.useCallback)(
229
+ (val) => {
230
+ var _a, _b;
231
+ const values = Array.isArray(val) ? val : val ? [val] : [];
232
+ const strValues = values.map(String);
233
+ const selectedOptions = options.filter(
234
+ (o) => strValues.includes(o.region_code)
235
+ );
236
+ if (multiple) {
237
+ onChange == null ? void 0 : onChange(strValues, selectedOptions);
238
+ } else {
239
+ onChange == null ? void 0 : onChange(
240
+ (_a = strValues[0]) != null ? _a : "",
241
+ (_b = selectedOptions[0]) != null ? _b : void 0
242
+ );
243
+ }
244
+ },
245
+ [onChange, options, multiple]
246
+ );
247
+ const handleImportConfirm = (0, import_react.useCallback)(
248
+ (nextValue) => {
249
+ emitMultiple(nextValue);
250
+ onBlur == null ? void 0 : onBlur({ value: nextValue });
251
+ },
252
+ [emitMultiple, onBlur]
253
+ );
254
+ const panelTopContent = (0, import_react.useMemo)(() => {
255
+ if (!multiple)
256
+ return null;
257
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-region-select__toolbar", children: [
258
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
259
+ import_tdesign_react.Checkbox,
260
+ {
261
+ checked: isAllSelected,
262
+ indeterminate: isIndeterminate,
263
+ onChange: (checked) => {
264
+ if (checked) {
265
+ handleSelectAll();
266
+ } else {
267
+ handleClearAll();
268
+ }
269
+ },
270
+ children: texts.selectAll
271
+ }
272
+ ),
273
+ invertible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
274
+ "span",
275
+ {
276
+ role: "button",
277
+ tabIndex: 0,
278
+ className: "pnt-region-select__invert",
279
+ onClick: (event) => {
280
+ event.preventDefault();
281
+ event.stopPropagation();
282
+ handleInvert();
283
+ },
284
+ onKeyDown: (event) => {
285
+ if (event.key === "Enter" || event.key === " ") {
286
+ event.preventDefault();
287
+ event.stopPropagation();
288
+ handleInvert();
289
+ }
290
+ },
291
+ children: texts.invertSelection
292
+ }
293
+ ),
294
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pnt-region-select__count", children: texts.selectedCount.replace("{count}", String(valueArr.length)) })
295
+ ] });
296
+ }, [
297
+ multiple,
298
+ isAllSelected,
299
+ isIndeterminate,
300
+ handleSelectAll,
301
+ handleClearAll,
302
+ invertible,
303
+ handleInvert,
304
+ texts,
305
+ valueArr.length
306
+ ]);
307
+ const emptyContent = (0, import_react.useMemo)(() => {
308
+ if (loading)
309
+ return null;
310
+ if (filteredOptions.length === 0) {
311
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pnt-region-select__empty", children: texts.noResult });
312
+ }
313
+ return null;
314
+ }, [loading, filteredOptions.length, texts.noResult]);
315
+ const selectNode = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
316
+ import_tdesign_react.Select,
317
+ {
318
+ value: multiple ? valueArr : valueArr[0],
319
+ onChange: handleChange,
320
+ filterable,
321
+ onSearch: setSearchKeyword,
322
+ loading: loading && options.length === 0,
323
+ multiple,
324
+ max,
325
+ clearable: true,
326
+ disabled,
327
+ placeholder: placeholder || texts.placeholder,
328
+ panelTopContent,
329
+ empty: emptyContent,
330
+ minCollapsedNum,
331
+ collapsedItems,
332
+ onBlur,
333
+ popupProps: {
334
+ ...popupProps,
335
+ overlayClassName: [
336
+ "pnt-region-select-popup",
337
+ popupProps == null ? void 0 : popupProps.overlayClassName
338
+ ].filter(Boolean).join(" ")
339
+ },
340
+ className: className ? `pnt-region-select ${className}` : "pnt-region-select",
341
+ style,
342
+ children: selectOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
343
+ import_tdesign_react.Select.Option,
344
+ {
345
+ value: opt.value,
346
+ label: opt.label,
347
+ disabled: opt.disabled,
348
+ title: opt.tooltip
349
+ },
350
+ opt.value
351
+ ))
352
+ }
353
+ );
354
+ if (importable && multiple) {
355
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
356
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-region-select__import-wrapper", children: [
357
+ selectNode,
358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
359
+ import_tdesign_react.Button,
360
+ {
361
+ theme: "primary",
362
+ size: "small",
363
+ variant: "outline",
364
+ disabled,
365
+ className: "pnt-region-select__import-btn",
366
+ onClick: () => setImportVisible(true),
367
+ children: texts.importBtn
368
+ }
369
+ )
370
+ ] }),
371
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
372
+ import_ImportDialog.default,
373
+ {
374
+ visible: importVisible,
375
+ options,
376
+ currentValue: valueArr,
377
+ texts,
378
+ dialogProps: importDialogProps,
379
+ onClose: () => setImportVisible(false),
380
+ onConfirm: handleImportConfirm
381
+ }
382
+ )
383
+ ] });
384
+ }
385
+ return selectNode;
386
+ };
387
+ var PntRegionSelect_default = PntRegionSelect;
@@ -0,0 +1,166 @@
1
+ .pnt-region-select {
2
+ width: 100%;
3
+
4
+ &__toolbar {
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: space-between;
8
+ padding: 8px 12px;
9
+ border-bottom: 1px solid var(--td-component-border, #e7e7e7);
10
+ background: var(--td-bg-color-container, #fff);
11
+ }
12
+
13
+ &__invert {
14
+ margin-left: 12px;
15
+ margin-right: auto;
16
+ font-size: 12px;
17
+ color: var(--td-brand-color, #0052d9);
18
+ cursor: pointer;
19
+ user-select: none;
20
+
21
+ &:hover {
22
+ color: var(--td-brand-color-hover, #2667d4);
23
+ }
24
+ }
25
+
26
+ &__count {
27
+ margin-left: auto;
28
+ font-size: 12px;
29
+ color: var(--td-text-color-secondary, #999);
30
+ }
31
+
32
+ &__invert + &__count {
33
+ margin-left: 0;
34
+ }
35
+
36
+ &__empty {
37
+ padding: 16px;
38
+ text-align: center;
39
+ color: var(--td-text-color-secondary, #999);
40
+ font-size: 14px;
41
+ }
42
+
43
+ // ---- 批量导入 ----
44
+ &__import-wrapper {
45
+ position: relative;
46
+ display: flex;
47
+ align-items: center;
48
+
49
+ .pnt-region-select {
50
+ flex: 1;
51
+ }
52
+ }
53
+
54
+ &__import-btn {
55
+ position: absolute;
56
+ right: 32px;
57
+ z-index: 1;
58
+ flex-shrink: 0;
59
+ }
60
+ }
61
+
62
+ .pnt-region-select-popup {
63
+ .t-select__list {
64
+ padding-top: 0;
65
+ }
66
+ }
67
+
68
+ // ---- 批量导入弹窗 ----
69
+ .pnt-region-import {
70
+ &__tip {
71
+ margin-bottom: 8px;
72
+ font-size: 12px;
73
+ color: var(--td-text-color-secondary, #999);
74
+ }
75
+
76
+ &__result {
77
+ margin-top: 12px;
78
+ }
79
+
80
+ &__summary {
81
+ display: flex;
82
+ align-items: center;
83
+ gap: 4px;
84
+ margin-bottom: 8px;
85
+ font-size: 12px;
86
+ }
87
+
88
+ &__summary-item {
89
+ &--unmatched {
90
+ color: var(--td-error-color, #d54941);
91
+ }
92
+
93
+ &--pending {
94
+ color: var(--td-success-color, #2ba471);
95
+ }
96
+
97
+ &--exists {
98
+ color: var(--td-text-color-secondary, #999);
99
+ }
100
+ }
101
+
102
+ &__summary-dot {
103
+ color: var(--td-text-color-placeholder, #bbb);
104
+ }
105
+
106
+ &__copy-btn {
107
+ padding: 0 4px;
108
+ height: 20px;
109
+ }
110
+
111
+ &__table {
112
+ border: 1px solid var(--td-component-border, #e7e7e7);
113
+ border-radius: 4px;
114
+ overflow: hidden;
115
+ }
116
+
117
+ &__table-head {
118
+ display: flex;
119
+ justify-content: space-between;
120
+ padding: 6px 12px;
121
+ background: var(--td-bg-color-secondarycontainer, #f3f3f3);
122
+ font-size: 12px;
123
+ color: var(--td-text-color-secondary, #999);
124
+ }
125
+
126
+ &__table-body {
127
+ max-height: 200px;
128
+ overflow-y: auto;
129
+ }
130
+
131
+ &__table-row {
132
+ display: flex;
133
+ justify-content: space-between;
134
+ align-items: center;
135
+ padding: 6px 12px;
136
+ font-size: 12px;
137
+
138
+ & + & {
139
+ border-top: 1px solid var(--td-component-border, #e7e7e7);
140
+ }
141
+ }
142
+
143
+ &__status {
144
+ display: inline-flex;
145
+ align-items: center;
146
+ gap: 4px;
147
+
148
+ &--unmatched {
149
+ color: var(--td-error-color, #d54941);
150
+ }
151
+
152
+ &--pending {
153
+ color: var(--td-success-color, #2ba471);
154
+ }
155
+
156
+ &--exists {
157
+ color: var(--td-text-color-secondary, #999);
158
+ }
159
+ }
160
+
161
+ &__empty {
162
+ padding: 16px;
163
+ text-align: center;
164
+ color: var(--td-text-color-secondary, #999);
165
+ }
166
+ }
@@ -0,0 +1,160 @@
1
+ /// <reference types="react" />
2
+ /**
3
+ * 地区选项数据结构(统一格式)
4
+ */
5
+ export interface RegionOption {
6
+ /** 地区代码(唯一标识,如 'CN'、'HK') */
7
+ region_code: string;
8
+ /** 中文名称 */
9
+ region_ch: string;
10
+ /** 英文名称 */
11
+ region_en: string;
12
+ /** ISO 3166-1 alpha-2 代码 */
13
+ region_a2_code?: string;
14
+ /** ISO 3166-1 alpha-3 代码 */
15
+ region_a3_code?: string;
16
+ /** 是否禁用(合规区域 creatable=false 时使用) */
17
+ disabled?: boolean;
18
+ /** 禁用原因提示 */
19
+ disabledReason?: string;
20
+ }
21
+ /**
22
+ * 数据源类型
23
+ * - default: 全部国家区域(不带任何参数,返回全部 251 个)/api/v5/business/region/query
24
+ * - business: 业务最终生效的区域(必须传 gameId)/api/v5/business/region/query
25
+ */
26
+ export type RegionDataSource = 'default' | 'business';
27
+ /**
28
+ * 标签格式
29
+ * - name: 中文名
30
+ * - name_en: 英文名
31
+ * - name_en_name: 英文名(中文名)
32
+ * - code: 仅代码
33
+ */
34
+ export type RegionLabelFormat = 'name' | 'name_en' | 'name_en_name' | 'code';
35
+ /**
36
+ * 组件文案集合
37
+ */
38
+ export interface PntRegionSelectTexts {
39
+ /** 占位提示 */
40
+ placeholder?: string;
41
+ /** 全选按钮 */
42
+ selectAll?: string;
43
+ /** 反选按钮 */
44
+ invertSelection?: string;
45
+ /** 清空按钮 */
46
+ clearAll?: string;
47
+ /** 已选数量提示({count} 为占位符) */
48
+ selectedCount?: string;
49
+ /** 搜索无结果提示 */
50
+ noResult?: string;
51
+ /** 加载中提示 */
52
+ loading?: string;
53
+ /** 批量导入按钮 */
54
+ importBtn?: string;
55
+ /** 批量导入弹窗标题 */
56
+ importTitle?: string;
57
+ /** 批量导入弹窗说明 */
58
+ importTip?: string;
59
+ /** 批量导入输入框占位 */
60
+ importPlaceholder?: string;
61
+ /** 解析按钮 */
62
+ parseBtn?: string;
63
+ /** 导入确认按钮 */
64
+ importConfirmBtn?: string;
65
+ /** 取消按钮 */
66
+ cancelBtn?: string;
67
+ /** 解析结果:未匹配 */
68
+ importUnmatched?: string;
69
+ /** 解析结果:待导入 */
70
+ importPending?: string;
71
+ /** 解析结果:已存在 */
72
+ importExists?: string;
73
+ /** 复制未匹配项提示 */
74
+ copyUnmatchedTip?: string;
75
+ /** 复制成功提示 */
76
+ copySuccess?: string;
77
+ /** 解析结果表格:地区列 */
78
+ importRegionColumn?: string;
79
+ /** 解析结果表格:状态列 */
80
+ importStatusColumn?: string;
81
+ }
82
+ export declare const DEFAULT_TEXTS: Required<PntRegionSelectTexts>;
83
+ /**
84
+ * 地区选择器组件 Props
85
+ */
86
+ export interface PntRegionSelectProps {
87
+ /**
88
+ * 当前选中值:多选为地区代码数组,单选为单个地区代码
89
+ * (兼容 TDesign FormItem 注入的单值/多值)
90
+ */
91
+ value?: string | string[];
92
+ /**
93
+ * 值变化回调:多选时回传 (string[], RegionOption[]),
94
+ * 单选时回传 (string, RegionOption)
95
+ */
96
+ onChange?: (value: string[] | string, options: RegionOption[] | RegionOption) => void;
97
+ /** 是否多选 @default true */
98
+ multiple?: boolean;
99
+ /** 数据源类型 @default 'default' */
100
+ dataSource?: RegionDataSource;
101
+ /**
102
+ * 接口作用域 @default 'business'
103
+ * - business: 业务级区域查询 /api/v5/business/region/query
104
+ * - platform: 平台级区域查询 /api/v5/business/region/plat-query
105
+ */
106
+ scope?: 'business' | 'platform';
107
+ /** 业务ID(dataSource='business' 时必传) */
108
+ gameId?: string | number;
109
+ /**
110
+ * 外部受控选项列表(传入后跳过内部请求,直接使用该数据;
111
+ * 适用于选项由父组件获取/过滤的场景)
112
+ */
113
+ options?: RegionOption[];
114
+ /** 是否禁用 @default false */
115
+ disabled?: boolean;
116
+ /** 占位文案 */
117
+ placeholder?: string;
118
+ /** 最大可选数量(多选时生效) */
119
+ max?: number;
120
+ /** 是否可搜索 @default true */
121
+ filterable?: boolean;
122
+ /** 标签格式 @default 'name' */
123
+ labelFormat?: RegionLabelFormat;
124
+ /** 自定义文案 */
125
+ texts?: PntRegionSelectTexts;
126
+ /** 数据加载完成回调 */
127
+ onLoaded?: (options: RegionOption[]) => void;
128
+ /** 自定义选项禁用逻辑 */
129
+ optionDisabled?: (item: RegionOption) => boolean;
130
+ /** 自定义选项 tooltip */
131
+ optionTooltip?: (item: RegionOption) => string;
132
+ /**
133
+ * 是否启用批量导入(仅多选时生效):
134
+ * 输入框右侧显示导入按钮,支持粘贴文本按 代码/中文名/英文名 解析匹配
135
+ * @default false
136
+ */
137
+ importable?: boolean;
138
+ /** 是否在工具栏显示反选按钮(仅多选时生效) @default false */
139
+ invertible?: boolean;
140
+ /** 最小折叠数量(多选时透传 TDesign Select) */
141
+ minCollapsedNum?: number;
142
+ /** 折叠项自定义渲染(透传 TDesign Select) */
143
+ collapsedItems?: (props: {
144
+ value: unknown[];
145
+ collapsedSelectedItems: unknown[];
146
+ count: number;
147
+ }) => React.ReactNode;
148
+ /** 失焦回调(透传 TDesign Select,常用于表单校验触发) */
149
+ onBlur?: (context: {
150
+ value: unknown;
151
+ }) => void;
152
+ /** 批量导入弹窗属性透传(如 attach 挂载容器) */
153
+ importDialogProps?: Record<string, unknown>;
154
+ /** 自定义类名 */
155
+ className?: string;
156
+ /** 自定义样式 */
157
+ style?: React.CSSProperties;
158
+ /** 弹层属性透传 */
159
+ popupProps?: Record<string, unknown>;
160
+ }