@pnt-team/pnt-component-frontend 0.0.111 → 0.0.113
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.
- package/README.md +29 -30
- package/lib/cjs/api/index.d.ts +14 -1
- package/lib/cjs/api/index.js +6 -0
- package/lib/cjs/api/types/index.d.ts +47 -0
- package/lib/cjs/components/PntRegionSelect/ImportDialog.d.ts +25 -0
- package/lib/cjs/components/PntRegionSelect/ImportDialog.js +244 -0
- package/lib/cjs/components/PntRegionSelect/index.d.ts +43 -0
- package/lib/cjs/components/PntRegionSelect/index.js +402 -0
- package/lib/cjs/components/PntRegionSelect/index.scss +166 -0
- package/lib/cjs/components/PntRegionSelect/types.d.ts +158 -0
- package/lib/cjs/components/PntRegionSelect/types.js +51 -0
- package/lib/cjs/components/PntSecureBox/index.scss +3 -0
- package/lib/cjs/index.d.ts +3 -1
- package/lib/cjs/index.js +3 -0
- package/lib/esm/api/index.d.ts +14 -1
- package/lib/esm/api/index.js +16 -1
- package/lib/esm/api/types/index.d.ts +47 -0
- package/lib/esm/components/PntRegionSelect/ImportDialog.d.ts +25 -0
- package/lib/esm/components/PntRegionSelect/ImportDialog.js +241 -0
- package/lib/esm/components/PntRegionSelect/index.d.ts +43 -0
- package/lib/esm/components/PntRegionSelect/index.js +388 -0
- package/lib/esm/components/PntRegionSelect/index.scss +166 -0
- package/lib/esm/components/PntRegionSelect/types.d.ts +158 -0
- package/lib/esm/components/PntRegionSelect/types.js +51 -0
- package/lib/esm/components/PntSecureBox/index.scss +3 -0
- package/lib/esm/index.d.ts +3 -1
- package/lib/esm/index.js +1 -0
- package/lib/umd/pnt-component-frontend.min.css +1 -1
- package/lib/umd/pnt-component-frontend.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,36 +121,35 @@ import {
|
|
|
121
121
|
|
|
122
122
|
**Props:**
|
|
123
123
|
|
|
124
|
-
| 属性
|
|
125
|
-
|
|
|
126
|
-
| `value`
|
|
127
|
-
| `onChange`
|
|
128
|
-
| `multiple`
|
|
129
|
-
| `scene`
|
|
130
|
-
| `statuses`
|
|
131
|
-
| `businessTypes`
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `style` | `React.CSSProperties` | ❌ | - | 自定义样式 |
|
|
124
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
125
|
+
| ------------------ | ----------------------------------------------------------- | :--: | ----------- | ----------------------------------------------------------------------------------- |
|
|
126
|
+
| `value` | `string \| string[]` | ❌ | - | 当前选中值;单选为 string,多选为 string[] |
|
|
127
|
+
| `onChange` | `(value, context) => void` | ❌ | - | 值变化回调;context.selectedOptions 返回纯业务数据对象 |
|
|
128
|
+
| `multiple` | `boolean` | ❌ | `false` | 是否多选 |
|
|
129
|
+
| `scene` | `'default' \| 'sdk' \| 'compliance_age' \| 'custom_region'` | ❌ | `'default'` | 下拉场景;后端按场景返回默认字段集 |
|
|
130
|
+
| `statuses` | `number[]` | ❌ | - | 业务状态筛选(3-线上运营, 4-接入中, 5-中途结项, 6-已下线) |
|
|
131
|
+
| `businessTypes` | `number[]` | ❌ | - | 业务类型筛选(1-正式业务, 2-测试业务) |
|
|
132
|
+
| `labelFormat` | `'name' \| 'name_en' \| 'name_id' \| 'name_en_id'` | ❌ | `'name'` | 标签格式 |
|
|
133
|
+
| `labelField` | `string` | ❌ | - | 自定义 label 字段(消费方接口返回字段非标准 name/name_en 时使用) |
|
|
134
|
+
| `optionLabel` | `(item) => ReactNode` | ❌ | - | 自定义选项 label 渲染;优先级高于 labelFormat/labelField |
|
|
135
|
+
| `placeholder` | `string` | ❌ | - | 占位提示文案 |
|
|
136
|
+
| `disabled` | `boolean` | ❌ | `false` | 是否禁用整个选择器 |
|
|
137
|
+
| `clearable` | `boolean` | ❌ | `true` | 是否可清除 |
|
|
138
|
+
| `filterable` | `boolean` | ❌ | `true` | 是否可远程搜索 |
|
|
139
|
+
| `max` | `number` | ❌ | - | 多选时最大可选数量 |
|
|
140
|
+
| `pageSize` | `number` | ❌ | `20` | 每页条数 |
|
|
141
|
+
| `searchDebounce` | `number` | ❌ | `400` | 搜索防抖延迟(毫秒) |
|
|
142
|
+
| `minCollapsedNum` | `number` | ❌ | - | 多选时最少折叠数量;透传至 TDesign Select |
|
|
143
|
+
| `collapsedItems` | `TdSelectProps['collapsedItems']` | ❌ | - | 折叠项自定义渲染;透传至 TDesign Select |
|
|
144
|
+
| `popupProps` | `Partial<TdSelectProps['popupProps']>` | ❌ | - | 弹层属性透传;与内部 onScrollToBottom 合并;常用 attach、overlayClassName |
|
|
145
|
+
| `fields` | `string[]` | ❌ | - | 字段白名单,传给后端 fields 参数;未传时后端按 scene 返回默认字段 |
|
|
146
|
+
| `pagination` | `boolean` | ❌ | `true` | 是否分页;false 时一次性加载全量数据,不远程搜索 |
|
|
147
|
+
| `onLoaded` | `(options) => void` | ❌ | - | 选项加载完成回调;不分页模式下首屏即全量,可复用此数据避免重复请求 |
|
|
148
|
+
| `optionDisabled` | `(item) => boolean` | ❌ | - | 自定义选项禁用逻辑;与合规场景 creatable 判断叠加(任一为 true 即禁用) |
|
|
149
|
+
| `optionTooltip` | `(item) => string` | ❌ | - | 自定义选项 tooltip 内容;返回非空字符串时该选项悬停显示 tooltip,常用于解释禁用原因 |
|
|
150
|
+
| `tooltipPlacement` | `'top' \| 'bottom' \| 'left' \| 'right'` | ❌ | `'top'` | tooltip 位置 |
|
|
151
|
+
| `className` | `string` | ❌ | - | 自定义类名 |
|
|
152
|
+
| `style` | `React.CSSProperties` | ❌ | - | 自定义样式 |
|
|
154
153
|
|
|
155
154
|
**示例:**
|
|
156
155
|
|
package/lib/cjs/api/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { commonEesType, PntHttpLike } from "../config";
|
|
2
|
-
import { BusinessGameInfoHighSecurityDecryptBody, BusinessGameInfoHighSecurityDecryptResponse, BusinessSelectListBody, BusinessSelectListResponse } from './types/index';
|
|
2
|
+
import { BusinessGameInfoGetCustomRegionBody, BusinessGameInfoGetCustomRegionResponse, BusinessGameInfoHighSecurityDecryptBody, BusinessGameInfoHighSecurityDecryptResponse, BusinessRegionQueryBody, BusinessRegionQueryResponse, BusinessSelectListBody, BusinessSelectListResponse } from './types/index';
|
|
3
3
|
/**
|
|
4
4
|
* 业务下拉选择列表
|
|
5
5
|
* @param http 由 PntProvider 注入的 axios 实例
|
|
@@ -13,3 +13,16 @@ export declare const businessSelectList: (axios: PntHttpLike, data: BusinessSele
|
|
|
13
13
|
* @param url 自定义接口 URL(可选,覆盖默认值)
|
|
14
14
|
*/
|
|
15
15
|
export declare const businessGameInfoHighSecurityDecrypt: (axios: PntHttpLike, data: BusinessGameInfoHighSecurityDecryptBody, url?: string) => Promise<commonEesType<BusinessGameInfoHighSecurityDecryptResponse>>;
|
|
16
|
+
/**
|
|
17
|
+
* 业务区域查询
|
|
18
|
+
* @param axios 由 PntProvider 注入的 axios 实例
|
|
19
|
+
* @param data 请求参数;不传时不带任何参数,返回全部国家区域(251 个);
|
|
20
|
+
* 传 game_id 时返回该业务最终生效的区域
|
|
21
|
+
*/
|
|
22
|
+
export declare const businessRegionQuery: (axios: PntHttpLike, data?: BusinessRegionQueryBody) => Promise<commonEesType<BusinessRegionQueryResponse>>;
|
|
23
|
+
/**
|
|
24
|
+
* 自定义合规区域列表
|
|
25
|
+
* @param axios 由 PntProvider 注入的 axios 实例
|
|
26
|
+
* @param data 请求参数(game_id + env)
|
|
27
|
+
*/
|
|
28
|
+
export declare const businessGameInfoGetCustomRegion: (axios: PntHttpLike, data: BusinessGameInfoGetCustomRegionBody) => Promise<commonEesType<BusinessGameInfoGetCustomRegionResponse>>;
|
package/lib/cjs/api/index.js
CHANGED
|
@@ -19,7 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// src/api/index.ts
|
|
20
20
|
var api_exports = {};
|
|
21
21
|
__export(api_exports, {
|
|
22
|
+
businessGameInfoGetCustomRegion: () => businessGameInfoGetCustomRegion,
|
|
22
23
|
businessGameInfoHighSecurityDecrypt: () => businessGameInfoHighSecurityDecrypt,
|
|
24
|
+
businessRegionQuery: () => businessRegionQuery,
|
|
23
25
|
businessSelectList: () => businessSelectList
|
|
24
26
|
});
|
|
25
27
|
module.exports = __toCommonJS(api_exports);
|
|
@@ -28,8 +30,12 @@ var businessGameInfoHighSecurityDecrypt = (axios, data, url) => axios.post(
|
|
|
28
30
|
url || "/v3/business/game_info/high-security-decrypt?audience=/laas-pnt",
|
|
29
31
|
data
|
|
30
32
|
);
|
|
33
|
+
var businessRegionQuery = (axios, data) => axios.post("/api/v5/business/region/query?audience=/laas-pnt", data);
|
|
34
|
+
var businessGameInfoGetCustomRegion = (axios, data) => axios.post("/v4/business/game_info/get-custom-region?audience=/laas-pnt", data);
|
|
31
35
|
// Annotate the CommonJS export names for ESM import in node:
|
|
32
36
|
0 && (module.exports = {
|
|
37
|
+
businessGameInfoGetCustomRegion,
|
|
33
38
|
businessGameInfoHighSecurityDecrypt,
|
|
39
|
+
businessRegionQuery,
|
|
34
40
|
businessSelectList
|
|
35
41
|
});
|
|
@@ -78,3 +78,50 @@ export interface BusinessGameInfoHighSecurityDecryptBody {
|
|
|
78
78
|
game_id: number;
|
|
79
79
|
}
|
|
80
80
|
export type BusinessGameInfoHighSecurityDecryptResponse = Record<string, unknown>[];
|
|
81
|
+
export interface BusinessRegionQueryBody {
|
|
82
|
+
/** GameID 目标业务 ID;可选,取值必须 > 0。
|
|
83
|
+
* 不传时不带任何参数,返回全部国家区域(251 个);传入时返回该业务最终生效的区域。 */
|
|
84
|
+
game_id?: number;
|
|
85
|
+
/** Search 模糊搜索关键字,按 name_en / name_ch / num_code 匹配;可选,默认空字符串。 */
|
|
86
|
+
search?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface BusinessRegionQueryResponseRegionListItem {
|
|
89
|
+
/** ID 区域主键 ID。 */
|
|
90
|
+
id?: number;
|
|
91
|
+
/** IsEEARegion 是否 EEA 区域。 */
|
|
92
|
+
is_eea_region?: number;
|
|
93
|
+
/** IsSecretRegion 是否特殊合规区域,取值:1=默认区域,2=特殊区域。 */
|
|
94
|
+
is_secret_region?: number;
|
|
95
|
+
/** RegionA2Code 二位字母码。 */
|
|
96
|
+
region_a2_code?: string;
|
|
97
|
+
/** RegionA3Code 三位字母码。 */
|
|
98
|
+
region_a3_code?: string;
|
|
99
|
+
/** RegionCH 中文名称。 */
|
|
100
|
+
region_ch?: string;
|
|
101
|
+
/** RegionCode 数字码,按数据库原始值返回,不做前导零转换。 */
|
|
102
|
+
region_code?: string;
|
|
103
|
+
/** RegionEN 英文名称。 */
|
|
104
|
+
region_en?: string;
|
|
105
|
+
}
|
|
106
|
+
export interface BusinessRegionQueryResponse {
|
|
107
|
+
/** BlackCodes 黑名单数字码列表;base_region_list / business_effective_region_list 返回空数组,business_region_rule_detail 返回真实值。 */
|
|
108
|
+
black_codes?: string[];
|
|
109
|
+
/** RegionList 国家区域列表;base_region_list 返回完整字典(或搜索子集),
|
|
110
|
+
business_effective_region_list 返回业务最终生效结果,business_region_rule_detail 返回完整字典(或搜索子集)。 */
|
|
111
|
+
region_list?: BusinessRegionQueryResponseRegionListItem[];
|
|
112
|
+
/** RuleState 业务规则状态,取值见 RuleState* 常量:0=未配置,1=启用,2=停用;
|
|
113
|
+
仅 business_effective_region_list / business_region_rule_detail 场景返回;base_region_list 场景省略(omitempty)。 */
|
|
114
|
+
rule_state?: number;
|
|
115
|
+
/** WhiteCodes 白名单数字码列表;base_region_list / business_effective_region_list 返回空数组,business_region_rule_detail 返回真实值。 */
|
|
116
|
+
white_codes?: string[];
|
|
117
|
+
}
|
|
118
|
+
export interface BusinessGameInfoGetCustomRegionBody {
|
|
119
|
+
/** GameID 目标业务 ID */
|
|
120
|
+
game_id: number;
|
|
121
|
+
/** Env 环境 */
|
|
122
|
+
env: number;
|
|
123
|
+
}
|
|
124
|
+
export interface BusinessGameInfoGetCustomRegionResponse {
|
|
125
|
+
/** RegionList 自定义合规区域列表 */
|
|
126
|
+
region_list?: BusinessRegionQueryResponseRegionListItem[];
|
|
127
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import type { PntRegionSelectTexts, RegionOption } from './types';
|
|
3
|
+
/** 解析后单行状态 */
|
|
4
|
+
export type ImportRowStatus = 'pending' | 'exists' | 'unmatched';
|
|
5
|
+
export interface ImportRow {
|
|
6
|
+
/** 用户输入的原始文本 */
|
|
7
|
+
region: string;
|
|
8
|
+
status: ImportRowStatus;
|
|
9
|
+
}
|
|
10
|
+
interface ImportDialogProps {
|
|
11
|
+
visible: boolean;
|
|
12
|
+
options: RegionOption[];
|
|
13
|
+
currentValue: string[];
|
|
14
|
+
texts: Required<PntRegionSelectTexts>;
|
|
15
|
+
dialogProps?: Record<string, unknown>;
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
/** 导入确认:回传合并后的值与本次新增项 */
|
|
18
|
+
onConfirm: (nextValue: string[], added: string[]) => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 批量导入弹窗:
|
|
22
|
+
* 粘贴文本 → 按 代码/中文名/英文名(大小写不敏感)解析 → 分类展示 → 确认导入
|
|
23
|
+
*/
|
|
24
|
+
declare const ImportDialog: FC<ImportDialogProps>;
|
|
25
|
+
export default ImportDialog;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/components/PntRegionSelect/ImportDialog.tsx
|
|
20
|
+
var ImportDialog_exports = {};
|
|
21
|
+
__export(ImportDialog_exports, {
|
|
22
|
+
default: () => ImportDialog_default
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(ImportDialog_exports);
|
|
25
|
+
var import_react = require("react");
|
|
26
|
+
var import_tdesign_icons_react = require("tdesign-icons-react");
|
|
27
|
+
var import_tdesign_react = require("tdesign-react");
|
|
28
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
29
|
+
var SEPARATOR = /[\r?\n,,;;]+/;
|
|
30
|
+
var ImportDialog = ({
|
|
31
|
+
visible,
|
|
32
|
+
options,
|
|
33
|
+
currentValue,
|
|
34
|
+
texts,
|
|
35
|
+
dialogProps,
|
|
36
|
+
onClose,
|
|
37
|
+
onConfirm
|
|
38
|
+
}) => {
|
|
39
|
+
const [importText, setImportText] = (0, import_react.useState)("");
|
|
40
|
+
const [rows, setRows] = (0, import_react.useState)([]);
|
|
41
|
+
const [isParsed, setIsParsed] = (0, import_react.useState)(false);
|
|
42
|
+
const aliasMap = (0, import_react.useMemo)(() => {
|
|
43
|
+
const map = /* @__PURE__ */ new Map();
|
|
44
|
+
options.filter((item) => !item.disabled).forEach((item) => {
|
|
45
|
+
[item.region_code, item.region_ch, item.region_en].filter(Boolean).map((alias) => String(alias).trim().toLowerCase()).forEach((alias) => {
|
|
46
|
+
if (alias)
|
|
47
|
+
map.set(alias, item.region_code);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
return map;
|
|
51
|
+
}, [options]);
|
|
52
|
+
const { pendingList, existsList, unmatchedList } = (0, import_react.useMemo)(() => {
|
|
53
|
+
const selectedSet = new Set(currentValue);
|
|
54
|
+
const pending = [];
|
|
55
|
+
const exists = [];
|
|
56
|
+
const unmatched = [];
|
|
57
|
+
const seenPending = /* @__PURE__ */ new Set();
|
|
58
|
+
const seenExists = /* @__PURE__ */ new Set();
|
|
59
|
+
const seenUnmatched = /* @__PURE__ */ new Set();
|
|
60
|
+
rows.forEach((row) => {
|
|
61
|
+
if (row.status === "unmatched") {
|
|
62
|
+
if (!seenUnmatched.has(row.region)) {
|
|
63
|
+
seenUnmatched.add(row.region);
|
|
64
|
+
unmatched.push(row.region);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const code = aliasMap.get(row.region.toLowerCase());
|
|
69
|
+
if (!code)
|
|
70
|
+
return;
|
|
71
|
+
if (row.status === "exists" || selectedSet.has(code)) {
|
|
72
|
+
if (!seenExists.has(code)) {
|
|
73
|
+
seenExists.add(code);
|
|
74
|
+
exists.push(code);
|
|
75
|
+
}
|
|
76
|
+
} else if (!seenPending.has(code)) {
|
|
77
|
+
seenPending.add(code);
|
|
78
|
+
pending.push(code);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
pendingList: pending,
|
|
83
|
+
existsList: exists,
|
|
84
|
+
unmatchedList: unmatched
|
|
85
|
+
};
|
|
86
|
+
}, [rows, aliasMap, currentValue]);
|
|
87
|
+
const reset = () => {
|
|
88
|
+
setImportText("");
|
|
89
|
+
setRows([]);
|
|
90
|
+
setIsParsed(false);
|
|
91
|
+
};
|
|
92
|
+
const handleClose = () => {
|
|
93
|
+
reset();
|
|
94
|
+
onClose();
|
|
95
|
+
};
|
|
96
|
+
const parse = () => {
|
|
97
|
+
const uniqueInputs = Array.from(
|
|
98
|
+
new Set(
|
|
99
|
+
importText.split(SEPARATOR).map((item) => item.trim()).filter(Boolean)
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
const selectedSet = new Set(currentValue);
|
|
103
|
+
const nextRows = uniqueInputs.map((input) => {
|
|
104
|
+
const code = aliasMap.get(input.toLowerCase());
|
|
105
|
+
if (!code)
|
|
106
|
+
return { region: input, status: "unmatched" };
|
|
107
|
+
return {
|
|
108
|
+
region: input,
|
|
109
|
+
status: selectedSet.has(code) ? "exists" : "pending"
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
const priority = {
|
|
113
|
+
unmatched: 0,
|
|
114
|
+
pending: 1,
|
|
115
|
+
exists: 2
|
|
116
|
+
};
|
|
117
|
+
nextRows.sort((a, b) => priority[a.status] - priority[b.status]);
|
|
118
|
+
setRows(nextRows);
|
|
119
|
+
setIsParsed(true);
|
|
120
|
+
};
|
|
121
|
+
const copyUnmatched = async () => {
|
|
122
|
+
if (!unmatchedList.length)
|
|
123
|
+
return;
|
|
124
|
+
const text = unmatchedList.join("\n");
|
|
125
|
+
try {
|
|
126
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
127
|
+
await navigator.clipboard.writeText(text);
|
|
128
|
+
} else {
|
|
129
|
+
const textArea = document.createElement("textarea");
|
|
130
|
+
textArea.value = text;
|
|
131
|
+
document.body.appendChild(textArea);
|
|
132
|
+
textArea.focus();
|
|
133
|
+
textArea.select();
|
|
134
|
+
document.execCommand("copy");
|
|
135
|
+
textArea.remove();
|
|
136
|
+
}
|
|
137
|
+
import_tdesign_react.MessagePlugin.success(texts.copySuccess);
|
|
138
|
+
} catch {
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const handleConfirm = () => {
|
|
142
|
+
if (!isParsed) {
|
|
143
|
+
parse();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const nextSet = new Set(currentValue);
|
|
147
|
+
pendingList.forEach((code) => nextSet.add(code));
|
|
148
|
+
const nextValue = Array.from(nextSet);
|
|
149
|
+
onConfirm(nextValue, pendingList);
|
|
150
|
+
handleClose();
|
|
151
|
+
};
|
|
152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
153
|
+
import_tdesign_react.Dialog,
|
|
154
|
+
{
|
|
155
|
+
visible,
|
|
156
|
+
header: texts.importTitle,
|
|
157
|
+
width: 520,
|
|
158
|
+
closeOnOverlayClick: false,
|
|
159
|
+
confirmBtn: isParsed ? texts.importConfirmBtn : texts.parseBtn,
|
|
160
|
+
cancelBtn: texts.cancelBtn,
|
|
161
|
+
onConfirm: handleConfirm,
|
|
162
|
+
onClose: handleClose,
|
|
163
|
+
...dialogProps,
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pnt-region-import__tip", children: texts.importTip }),
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
167
|
+
import_tdesign_react.Textarea,
|
|
168
|
+
{
|
|
169
|
+
value: importText,
|
|
170
|
+
onChange: (next) => {
|
|
171
|
+
setImportText(String(next != null ? next : ""));
|
|
172
|
+
if (isParsed) {
|
|
173
|
+
setRows([]);
|
|
174
|
+
setIsParsed(false);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
rows: 3,
|
|
178
|
+
placeholder: texts.importPlaceholder
|
|
179
|
+
}
|
|
180
|
+
),
|
|
181
|
+
isParsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-region-import__result", children: [
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-region-import__summary", children: [
|
|
183
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pnt-region-import__summary-item pnt-region-import__summary-item--unmatched", children: [
|
|
184
|
+
texts.importUnmatched,
|
|
185
|
+
":",
|
|
186
|
+
unmatchedList.length
|
|
187
|
+
] }),
|
|
188
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_react.Tooltip, { content: texts.copyUnmatchedTip, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
189
|
+
import_tdesign_react.Button,
|
|
190
|
+
{
|
|
191
|
+
theme: "primary",
|
|
192
|
+
variant: "text",
|
|
193
|
+
size: "small",
|
|
194
|
+
className: "pnt-region-import__copy-btn",
|
|
195
|
+
disabled: !unmatchedList.length,
|
|
196
|
+
onClick: copyUnmatched,
|
|
197
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.FileCopyIcon, { strokeWidth: 2 })
|
|
198
|
+
}
|
|
199
|
+
) }),
|
|
200
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pnt-region-import__summary-dot", children: "·" }),
|
|
201
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pnt-region-import__summary-item pnt-region-import__summary-item--pending", children: [
|
|
202
|
+
texts.importPending,
|
|
203
|
+
":",
|
|
204
|
+
pendingList.length
|
|
205
|
+
] }),
|
|
206
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pnt-region-import__summary-dot", children: "·" }),
|
|
207
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pnt-region-import__summary-item pnt-region-import__summary-item--exists", children: [
|
|
208
|
+
texts.importExists,
|
|
209
|
+
":",
|
|
210
|
+
existsList.length
|
|
211
|
+
] })
|
|
212
|
+
] }),
|
|
213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-region-import__table", children: [
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-region-import__table-head", children: [
|
|
215
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: texts.importRegionColumn }),
|
|
216
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: texts.importStatusColumn })
|
|
217
|
+
] }),
|
|
218
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pnt-region-import__table-body", children: rows.length ? rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
219
|
+
"div",
|
|
220
|
+
{
|
|
221
|
+
className: "pnt-region-import__table-row",
|
|
222
|
+
children: [
|
|
223
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pnt-region-import__region", children: row.region }),
|
|
224
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
225
|
+
"span",
|
|
226
|
+
{
|
|
227
|
+
className: `pnt-region-import__status pnt-region-import__status--${row.status}`,
|
|
228
|
+
children: [
|
|
229
|
+
row.status === "unmatched" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.CloseIcon, { strokeWidth: 2 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.CheckIcon, { strokeWidth: 2 }),
|
|
230
|
+
row.status === "pending" ? texts.importPending : row.status === "exists" ? texts.importExists : texts.importUnmatched
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
)
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
row.region
|
|
237
|
+
)) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pnt-region-import__empty", children: "-" }) })
|
|
238
|
+
] })
|
|
239
|
+
] }) : null
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
};
|
|
244
|
+
var ImportDialog_default = ImportDialog;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import './index.scss';
|
|
3
|
+
import type { PntRegionSelectProps } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* 地区选择器组件
|
|
6
|
+
* @description 统一的国家/地区选择组件,支持单选/多选、批量选择、批量导入、自定义区域、合规区域
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // 基础多选(内部拉取默认区域列表)
|
|
11
|
+
* <PntRegionSelect
|
|
12
|
+
* value={regions}
|
|
13
|
+
* onChange={(v) => setRegions(v)}
|
|
14
|
+
* />
|
|
15
|
+
*
|
|
16
|
+
* // 自定义合规区域
|
|
17
|
+
* <PntRegionSelect
|
|
18
|
+
* dataSource="custom"
|
|
19
|
+
* gameId={gameId}
|
|
20
|
+
* env={0}
|
|
21
|
+
* value={regions}
|
|
22
|
+
* onChange={(v) => setRegions(v)}
|
|
23
|
+
* />
|
|
24
|
+
*
|
|
25
|
+
* // 业务最终生效区域
|
|
26
|
+
* <PntRegionSelect
|
|
27
|
+
* dataSource="business"
|
|
28
|
+
* gameId={gameId}
|
|
29
|
+
* value={regions}
|
|
30
|
+
* onChange={(v) => setRegions(v)}
|
|
31
|
+
* />
|
|
32
|
+
*
|
|
33
|
+
* // 外部受控选项 + 批量导入
|
|
34
|
+
* <PntRegionSelect
|
|
35
|
+
* options={regionList}
|
|
36
|
+
* importable
|
|
37
|
+
* value={regions}
|
|
38
|
+
* onChange={(v) => setRegions(v)}
|
|
39
|
+
* />
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare const PntRegionSelect: FC<PntRegionSelectProps>;
|
|
43
|
+
export default PntRegionSelect;
|