@pnt-team/pnt-component-frontend 0.0.138 → 0.0.139
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/lib/cjs/api/cos.d.ts +103 -0
- package/lib/cjs/api/cos.js +146 -0
- package/lib/cjs/api/index.d.ts +23 -0
- package/lib/cjs/api/index.js +38 -0
- package/lib/cjs/api/types/index.d.ts +117 -0
- package/lib/cjs/api/types/index.js +17 -0
- package/lib/cjs/assets/css/tdesign-theme.css +584 -0
- package/lib/cjs/assets/images/uploadImg.png +0 -0
- package/lib/cjs/assets/svg/inputSearch.svg +4 -0
- package/lib/cjs/assets/svg/inputTip.svg +5 -0
- package/lib/cjs/components/PntRegionSelect/index.scss +1 -1
- package/lib/esm/api/cos.d.ts +103 -0
- package/lib/esm/api/cos.js +189 -0
- package/lib/esm/api/index.d.ts +23 -0
- package/lib/esm/api/index.js +23 -0
- package/lib/esm/api/types/index.d.ts +117 -0
- package/lib/esm/api/types/index.js +1 -0
- package/lib/esm/assets/css/tdesign-theme.css +584 -0
- package/lib/esm/assets/images/uploadImg.png +0 -0
- package/lib/esm/assets/svg/inputSearch.svg +4 -0
- package/lib/esm/assets/svg/inputTip.svg +5 -0
- package/lib/esm/assets/svg/inputWarnTip.svg +5 -0
- package/lib/esm/components/PntBusinessSelect/index.d.ts +192 -0
- package/lib/esm/components/PntBusinessSelect/index.js +513 -0
- package/lib/esm/components/PntBusinessSelect/index.scss +27 -0
- package/lib/esm/components/PntCosUploader/index.d.ts +134 -0
- package/lib/esm/components/PntCosUploader/index.js +300 -0
- package/lib/esm/components/PntGeneralLayout/index.d.ts +114 -0
- package/lib/esm/components/PntGeneralLayout/index.js +103 -0
- package/lib/esm/components/PntGeneralLayout/index.scss +121 -0
- package/lib/esm/components/PntImage/index.d.ts +93 -0
- package/lib/esm/components/PntImage/index.js +200 -0
- package/lib/esm/components/PntImage/index.scss +61 -0
- package/lib/esm/components/PntRegionSelect/ImportDialog.d.ts +29 -0
- package/lib/esm/components/PntRegionSelect/ImportDialog.js +244 -0
- package/lib/esm/components/PntRegionSelect/index.d.ts +39 -0
- package/lib/esm/components/PntRegionSelect/index.js +471 -0
- package/lib/esm/components/PntRegionSelect/index.scss +174 -0
- package/lib/esm/components/PntRegionSelect/types.d.ts +181 -0
- package/lib/esm/components/PntRegionSelect/types.js +77 -0
- package/lib/esm/components/PntSecureBox/index.d.ts +122 -0
- package/lib/esm/components/PntSecureBox/index.js +166 -0
- package/lib/esm/components/PntSecureBox/index.scss +23 -0
- package/lib/esm/components/PntTable/index.d.ts +14 -0
- package/lib/esm/components/PntTable/index.js +404 -0
- package/lib/esm/components/PntTable/index.scss +290 -0
- package/lib/esm/components/PntTable/types.d.ts +250 -0
- package/lib/esm/components/PntTable/types.js +81 -0
- package/lib/esm/components/PntTable/useTableCore.d.ts +38 -0
- package/lib/esm/components/PntTable/useTableCore.js +499 -0
- package/lib/esm/components/PntUpload/index.d.ts +149 -0
- package/lib/esm/components/PntUpload/index.js +276 -0
- package/lib/esm/components/PntUpload/index.scss +101 -0
- package/lib/esm/config.d.ts +97 -0
- package/lib/esm/config.js +60 -0
- package/lib/esm/global.css +2 -0
- package/lib/esm/global.d.ts +39 -0
- package/lib/esm/hooks/useHighSecurity.d.ts +88 -0
- package/lib/esm/hooks/useHighSecurity.js +250 -0
- package/lib/esm/index.d.ts +16 -0
- package/lib/esm/index.js +33 -0
- package/lib/esm/utils/const.d.ts +13 -0
- package/lib/esm/utils/const.js +23 -0
- package/lib/esm/utils/index.d.ts +6 -0
- package/lib/esm/utils/index.js +22 -0
- package/lib/umd/pnt-component-frontend.min.css +1 -0
- package/lib/umd/pnt-component-frontend.min.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,181 @@
|
|
|
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
|
+
/** 英文文案(locale='en' 时使用) */
|
|
84
|
+
export declare const EN_TEXTS: Required<PntRegionSelectTexts>;
|
|
85
|
+
/** 根据 locale 获取默认文案 */
|
|
86
|
+
export declare const getTextsByLocale: (locale: 'zh' | 'en') => Required<PntRegionSelectTexts>;
|
|
87
|
+
/**
|
|
88
|
+
* 地区选择器组件 Props
|
|
89
|
+
*/
|
|
90
|
+
export interface PntRegionSelectProps {
|
|
91
|
+
/**
|
|
92
|
+
* 当前选中值:多选为地区代码数组,单选为单个地区代码
|
|
93
|
+
* (兼容 TDesign FormItem 注入的单值/多值)
|
|
94
|
+
*/
|
|
95
|
+
value?: string | string[];
|
|
96
|
+
/**
|
|
97
|
+
* 值变化回调:多选时回传 (string[], RegionOption[]),
|
|
98
|
+
* 单选时回传 (string, RegionOption)
|
|
99
|
+
*/
|
|
100
|
+
onChange?: (value: string[] | string, options: RegionOption[] | RegionOption) => void;
|
|
101
|
+
/** 是否多选 @default true */
|
|
102
|
+
multiple?: boolean;
|
|
103
|
+
/** 数据源类型 @default 'default' */
|
|
104
|
+
dataSource?: RegionDataSource;
|
|
105
|
+
/**
|
|
106
|
+
* 接口作用域 @default 'business'
|
|
107
|
+
* - business: 业务级区域查询 /api/v5/business/region/query
|
|
108
|
+
* - platform: 平台级区域查询 /api/v5/business/region/plat-query
|
|
109
|
+
*/
|
|
110
|
+
scope?: 'business' | 'platform';
|
|
111
|
+
/** 业务ID(dataSource='business' 时必传) */
|
|
112
|
+
gameId?: string | number;
|
|
113
|
+
/**
|
|
114
|
+
* 语言设置 @default 'zh'
|
|
115
|
+
* - zh: 中文(默认文案)
|
|
116
|
+
* - en: 英文(内置英文文案)
|
|
117
|
+
* @description 优先级低于 texts prop,高于 PntProvider 全局 locale
|
|
118
|
+
*/
|
|
119
|
+
locale?: 'zh' | 'en';
|
|
120
|
+
/**
|
|
121
|
+
* 外部受控选项列表(传入后跳过内部请求,直接使用该数据;
|
|
122
|
+
* 适用于选项由父组件获取/过滤的场景)
|
|
123
|
+
*/
|
|
124
|
+
options?: RegionOption[];
|
|
125
|
+
/** 是否禁用 @default false */
|
|
126
|
+
disabled?: boolean;
|
|
127
|
+
/** 占位文案 */
|
|
128
|
+
placeholder?: string;
|
|
129
|
+
/** 最大可选数量(多选时生效) */
|
|
130
|
+
max?: number;
|
|
131
|
+
/** 是否可搜索 @default true */
|
|
132
|
+
filterable?: boolean;
|
|
133
|
+
/** 标签格式 @default 'name' */
|
|
134
|
+
labelFormat?: RegionLabelFormat;
|
|
135
|
+
/** 自定义文案 */
|
|
136
|
+
texts?: PntRegionSelectTexts;
|
|
137
|
+
/** 数据加载完成回调 */
|
|
138
|
+
onLoaded?: (options: RegionOption[]) => void;
|
|
139
|
+
/** 自定义选项禁用逻辑 */
|
|
140
|
+
optionDisabled?: (item: RegionOption) => boolean;
|
|
141
|
+
/** 自定义选项过滤逻辑(内部拉取数据时生效,用于只展示部分区域) */
|
|
142
|
+
optionFilter?: (item: RegionOption) => boolean;
|
|
143
|
+
/** 自定义选项 tooltip */
|
|
144
|
+
optionTooltip?: (item: RegionOption) => string;
|
|
145
|
+
/**
|
|
146
|
+
* 是否启用批量导入(仅多选时生效):
|
|
147
|
+
* 输入框右侧显示导入按钮,支持粘贴文本按 代码/中文名/英文名 解析匹配
|
|
148
|
+
* @default false
|
|
149
|
+
*/
|
|
150
|
+
importable?: boolean;
|
|
151
|
+
/** 是否在工具栏显示反选按钮(仅多选时生效) @default false */
|
|
152
|
+
invertible?: boolean;
|
|
153
|
+
/** 最小折叠数量(多选时透传 TDesign Select) */
|
|
154
|
+
minCollapsedNum?: number;
|
|
155
|
+
/** 折叠项自定义渲染(透传 TDesign Select) */
|
|
156
|
+
collapsedItems?: (props: {
|
|
157
|
+
value: unknown[];
|
|
158
|
+
collapsedSelectedItems: unknown[];
|
|
159
|
+
count: number;
|
|
160
|
+
}) => React.ReactNode;
|
|
161
|
+
/** 失焦回调(透传 TDesign Select,常用于表单校验触发) */
|
|
162
|
+
onBlur?: (context: {
|
|
163
|
+
value: unknown;
|
|
164
|
+
}) => void;
|
|
165
|
+
/** 批量导入弹窗属性透传(如 attach 挂载容器) */
|
|
166
|
+
importDialogProps?: Record<string, unknown>;
|
|
167
|
+
/** 自定义类名 */
|
|
168
|
+
className?: string;
|
|
169
|
+
/** 自定义样式 */
|
|
170
|
+
style?: React.CSSProperties;
|
|
171
|
+
/** 弹层属性透传 */
|
|
172
|
+
popupProps?: Record<string, unknown>;
|
|
173
|
+
/**
|
|
174
|
+
* 对外输出是否保留数据源原始码(含前导零,如 '004')
|
|
175
|
+
* - true(默认): 输出数据源原始码,如 '004'、'012'
|
|
176
|
+
* - false: 输出归一化码(去前导零),如 '4'、'12'
|
|
177
|
+
* @description 旧接口存储/提交不带前导零的项目需设为 false
|
|
178
|
+
* @default true
|
|
179
|
+
*/
|
|
180
|
+
preserveLeadingZero?: boolean;
|
|
181
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 地区选项数据结构(统一格式)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 数据源类型
|
|
7
|
+
* - default: 全部国家区域(不带任何参数,返回全部 251 个)/api/v5/business/region/query
|
|
8
|
+
* - business: 业务最终生效的区域(必须传 gameId)/api/v5/business/region/query
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 标签格式
|
|
13
|
+
* - name: 中文名
|
|
14
|
+
* - name_en: 英文名
|
|
15
|
+
* - name_en_name: 英文名(中文名)
|
|
16
|
+
* - code: 仅代码
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 组件文案集合
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export const DEFAULT_TEXTS = {
|
|
24
|
+
placeholder: '请选择国家/地区',
|
|
25
|
+
selectAll: '全选',
|
|
26
|
+
invertSelection: '反选',
|
|
27
|
+
clearAll: '清空',
|
|
28
|
+
selectedCount: '已选 {count} 项',
|
|
29
|
+
noResult: '未找到匹配的地区',
|
|
30
|
+
loading: '加载中...',
|
|
31
|
+
importBtn: '批量导入',
|
|
32
|
+
importTitle: '批量导入国家/地区',
|
|
33
|
+
importTip: '支持输入地区代码、中文名或英文名,多个地区以换行、逗号或分号分隔',
|
|
34
|
+
importPlaceholder: '请输入地区代码、中文名或英文名',
|
|
35
|
+
parseBtn: '解析',
|
|
36
|
+
importConfirmBtn: '导入',
|
|
37
|
+
cancelBtn: '取消',
|
|
38
|
+
importUnmatched: '未匹配',
|
|
39
|
+
importPending: '待导入',
|
|
40
|
+
importExists: '已存在',
|
|
41
|
+
copyUnmatchedTip: '复制未匹配项',
|
|
42
|
+
copySuccess: '复制成功',
|
|
43
|
+
importRegionColumn: '地区',
|
|
44
|
+
importStatusColumn: '状态'
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** 英文文案(locale='en' 时使用) */
|
|
48
|
+
export const EN_TEXTS = {
|
|
49
|
+
placeholder: 'Please select country/region',
|
|
50
|
+
selectAll: 'Select All',
|
|
51
|
+
invertSelection: 'Invert',
|
|
52
|
+
clearAll: 'Clear',
|
|
53
|
+
selectedCount: 'Selected {count} item(s)',
|
|
54
|
+
noResult: 'No matching region found',
|
|
55
|
+
loading: 'Loading...',
|
|
56
|
+
importBtn: 'Batch Import',
|
|
57
|
+
importTitle: 'Batch Import Country/Region',
|
|
58
|
+
importTip: 'Supports region codes, Chinese names or English names, separated by line breaks, commas or semicolons',
|
|
59
|
+
importPlaceholder: 'Enter region codes, Chinese names or English names',
|
|
60
|
+
parseBtn: 'Parse',
|
|
61
|
+
importConfirmBtn: 'Import',
|
|
62
|
+
cancelBtn: 'Cancel',
|
|
63
|
+
importUnmatched: 'Unmatched',
|
|
64
|
+
importPending: 'Pending',
|
|
65
|
+
importExists: 'Existed',
|
|
66
|
+
copyUnmatchedTip: 'Copy unmatched items',
|
|
67
|
+
copySuccess: 'Copied successfully',
|
|
68
|
+
importRegionColumn: 'Region',
|
|
69
|
+
importStatusColumn: 'Status'
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** 根据 locale 获取默认文案 */
|
|
73
|
+
export const getTextsByLocale = locale => locale === 'en' ? EN_TEXTS : DEFAULT_TEXTS;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 地区选择器组件 Props
|
|
77
|
+
*/
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import './index.scss';
|
|
3
|
+
interface PntSecureBoxProps {
|
|
4
|
+
/**
|
|
5
|
+
* 高敏信息的唯一标识 key
|
|
6
|
+
* @description 用于标识和存储特定的高敏数据项
|
|
7
|
+
*/
|
|
8
|
+
dataKey: string;
|
|
9
|
+
/**
|
|
10
|
+
* 高敏信息的实际值
|
|
11
|
+
* @description 初始显示的值,通常为脱敏后的数据
|
|
12
|
+
*/
|
|
13
|
+
dataValue: string;
|
|
14
|
+
/**
|
|
15
|
+
* 环境标识
|
|
16
|
+
* @description 用于区分不同环境(如:dev, test, production);可缺省,默认 0
|
|
17
|
+
*/
|
|
18
|
+
env?: string | number;
|
|
19
|
+
/**
|
|
20
|
+
* 游戏 ID
|
|
21
|
+
* @description 标识具体的游戏项目
|
|
22
|
+
*/
|
|
23
|
+
gameId: string | number;
|
|
24
|
+
/**
|
|
25
|
+
* 自定义渲染函数
|
|
26
|
+
* @description 接收处理后的数据作为参数,返回需要渲染的 React 元素
|
|
27
|
+
* @param content - 处理后的数据内容(真实数据或脱敏数据)
|
|
28
|
+
* @returns React 元素
|
|
29
|
+
*/
|
|
30
|
+
renderDom: (content: string) => React.ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* 自定义查看按钮文案
|
|
33
|
+
* @description 用于适配多语言场景,默认为 'View'
|
|
34
|
+
*/
|
|
35
|
+
viewText?: string;
|
|
36
|
+
/**
|
|
37
|
+
* 页面 ID
|
|
38
|
+
* @description 用于记录操作日志和权限验证
|
|
39
|
+
*/
|
|
40
|
+
pageId?: string;
|
|
41
|
+
/**
|
|
42
|
+
* 明文是否也掩码显示
|
|
43
|
+
* @description
|
|
44
|
+
* - false(默认):非加密值直接展示原值
|
|
45
|
+
* - true:非加密值也展示 ******,点击后本地揭示(不调接口,防窥屏)
|
|
46
|
+
*/
|
|
47
|
+
maskPlain?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* 接口变体
|
|
50
|
+
* @description
|
|
51
|
+
* - 'business'(默认):业务级,走 /v3/business/game_info/high-security-decrypt
|
|
52
|
+
* - 'platform':平台级(发布记录页等场景),走 /v3/business/game_info/plat-high-security-decrypt
|
|
53
|
+
*/
|
|
54
|
+
scope?: 'business' | 'platform';
|
|
55
|
+
/**
|
|
56
|
+
* 解锁后是否显示复制按钮
|
|
57
|
+
* @description 默认 true,解锁后按钮文案切换为「复制」;传 false 则解锁后按钮消失(旧行为)
|
|
58
|
+
*/
|
|
59
|
+
copyable?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* 复制按钮文案
|
|
62
|
+
* @description 用于适配多语言场景,默认为 'Copy'
|
|
63
|
+
*/
|
|
64
|
+
copyText?: string;
|
|
65
|
+
/**
|
|
66
|
+
* 复制成功后的内联提示文案
|
|
67
|
+
* @description 仅在使用默认复制(未传 onCopy)时生效;
|
|
68
|
+
* 传入非空字符串后,复制成功按钮文案临时切换为该文案 2 秒;默认 'Copied',传 '' 关闭内联提示
|
|
69
|
+
*/
|
|
70
|
+
copySuccessText?: string;
|
|
71
|
+
/**
|
|
72
|
+
* 自定义复制行为
|
|
73
|
+
* @description 传入后替换默认的 navigator.clipboard.writeText;
|
|
74
|
+
* 消费方自行处理复制与反馈(此时 copySuccessText 不再生效)
|
|
75
|
+
*/
|
|
76
|
+
onCopy?: (value: string) => void | Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* securityData 变化回调
|
|
79
|
+
* @description 当 securityData 变化时触发(包括解密成功后);
|
|
80
|
+
* 回调参数为当前 gameId+env 下的整个 securityData 对象(key 为字段名,value 为明文);
|
|
81
|
+
* 消费方可用于同步表单字段、调试等
|
|
82
|
+
*/
|
|
83
|
+
onSecurityDataChange?: (securityData: Record<string, string>) => void;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 高敏信息展示统一组件
|
|
87
|
+
* @description 用于统一处理和展示高敏信息,支持脱敏显示、按需获取真实数据、解锁后复制。
|
|
88
|
+
* 通过 PntProvider 注入 http 实例,对接 `/api/v3/business/game_info/high-security-decrypt`。
|
|
89
|
+
*
|
|
90
|
+
* @param {PntSecureBoxProps} props - 组件属性
|
|
91
|
+
* @param {string} props.dataKey - 高敏信息的唯一标识 key
|
|
92
|
+
* @param {string} props.dataValue - 高敏信息的实际值
|
|
93
|
+
* @param {string | number} props.env - 环境标识
|
|
94
|
+
* @param {string | number} props.gameId - 游戏 ID
|
|
95
|
+
* @param {(content: string) => React.ReactNode} props.renderDom - 自定义渲染函数
|
|
96
|
+
* @param {string} [props.viewText] - 自定义查看按钮文案
|
|
97
|
+
* @param {string} [props.pageId] - 页面 ID
|
|
98
|
+
* @param {boolean} [props.copyable=true] - 解锁后是否显示复制按钮
|
|
99
|
+
* @param {string} [props.copyText] - 复制按钮文案
|
|
100
|
+
* @param {string} [props.copySuccessText] - 复制成功内联提示文案
|
|
101
|
+
* @param {(value: string) => void | Promise<void>} [props.onCopy] - 自定义复制行为
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```tsx
|
|
105
|
+
* import { PntSecureBox } from '@pnt-team/pnt-component-frontend';
|
|
106
|
+
*
|
|
107
|
+
* <PntSecureBox
|
|
108
|
+
* dataKey="userPhone"
|
|
109
|
+
* dataValue="_high_security_:AAAA...:6542"
|
|
110
|
+
* env={2}
|
|
111
|
+
* gameId={12345}
|
|
112
|
+
* renderDom={(content) => <span>{content}</span>}
|
|
113
|
+
* viewText="查看"
|
|
114
|
+
* copyText="复制"
|
|
115
|
+
* copySuccessText="已复制"
|
|
116
|
+
* />
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @returns {ReactElement} 高敏信息展示组件
|
|
120
|
+
*/
|
|
121
|
+
declare const PntSecureBox: FC<PntSecureBoxProps>;
|
|
122
|
+
export default PntSecureBox;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { useHighSecurity } from "../../hooks/useHighSecurity";
|
|
2
|
+
import { isSecurityData } from "../../utils";
|
|
3
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import "./index.scss";
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
7
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
+
/**
|
|
9
|
+
* 高敏信息展示统一组件
|
|
10
|
+
* @description 用于统一处理和展示高敏信息,支持脱敏显示、按需获取真实数据、解锁后复制。
|
|
11
|
+
* 通过 PntProvider 注入 http 实例,对接 `/api/v3/business/game_info/high-security-decrypt`。
|
|
12
|
+
*
|
|
13
|
+
* @param {PntSecureBoxProps} props - 组件属性
|
|
14
|
+
* @param {string} props.dataKey - 高敏信息的唯一标识 key
|
|
15
|
+
* @param {string} props.dataValue - 高敏信息的实际值
|
|
16
|
+
* @param {string | number} props.env - 环境标识
|
|
17
|
+
* @param {string | number} props.gameId - 游戏 ID
|
|
18
|
+
* @param {(content: string) => React.ReactNode} props.renderDom - 自定义渲染函数
|
|
19
|
+
* @param {string} [props.viewText] - 自定义查看按钮文案
|
|
20
|
+
* @param {string} [props.pageId] - 页面 ID
|
|
21
|
+
* @param {boolean} [props.copyable=true] - 解锁后是否显示复制按钮
|
|
22
|
+
* @param {string} [props.copyText] - 复制按钮文案
|
|
23
|
+
* @param {string} [props.copySuccessText] - 复制成功内联提示文案
|
|
24
|
+
* @param {(value: string) => void | Promise<void>} [props.onCopy] - 自定义复制行为
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* import { PntSecureBox } from '@pnt-team/pnt-component-frontend';
|
|
29
|
+
*
|
|
30
|
+
* <PntSecureBox
|
|
31
|
+
* dataKey="userPhone"
|
|
32
|
+
* dataValue="_high_security_:AAAA...:6542"
|
|
33
|
+
* env={2}
|
|
34
|
+
* gameId={12345}
|
|
35
|
+
* renderDom={(content) => <span>{content}</span>}
|
|
36
|
+
* viewText="查看"
|
|
37
|
+
* copyText="复制"
|
|
38
|
+
* copySuccessText="已复制"
|
|
39
|
+
* />
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @returns {ReactElement} 高敏信息展示组件
|
|
43
|
+
*/
|
|
44
|
+
const PntSecureBox = prop => {
|
|
45
|
+
const {
|
|
46
|
+
dataKey,
|
|
47
|
+
dataValue,
|
|
48
|
+
env,
|
|
49
|
+
gameId,
|
|
50
|
+
renderDom,
|
|
51
|
+
viewText,
|
|
52
|
+
pageId,
|
|
53
|
+
maskPlain,
|
|
54
|
+
scope,
|
|
55
|
+
copyable = true,
|
|
56
|
+
copyText,
|
|
57
|
+
copySuccessText = 'Copied',
|
|
58
|
+
onCopy,
|
|
59
|
+
onSecurityDataChange
|
|
60
|
+
} = prop;
|
|
61
|
+
|
|
62
|
+
// 缓存读写用的 key:dataKey + 密文后 16 位指纹
|
|
63
|
+
// 避免不同子渠道使用相同 dataKey(如 "app_key")但密文不同时缓存冲突
|
|
64
|
+
const storeKey = isSecurityData(dataValue) ? `${dataKey}#${dataValue.slice(-16)}` : dataKey;
|
|
65
|
+
|
|
66
|
+
// 通过 PntProvider 注入的 http 实例请求高敏数据,缓存按 gameId+env 隔离
|
|
67
|
+
const {
|
|
68
|
+
securityData,
|
|
69
|
+
isUnlocked,
|
|
70
|
+
requestSecurityData
|
|
71
|
+
} = useHighSecurity({
|
|
72
|
+
gameId,
|
|
73
|
+
env,
|
|
74
|
+
scope
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 明文揭示状态(maskPlain 模式下使用,本地 state,不调接口)
|
|
78
|
+
const [plainViewed, setPlainViewed] = useState(false);
|
|
79
|
+
// 复制成功内联反馈状态
|
|
80
|
+
const [copied, setCopied] = useState(false);
|
|
81
|
+
const copyTimer = useRef(null);
|
|
82
|
+
|
|
83
|
+
// 卸载时清理定时器
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
return () => {
|
|
86
|
+
if (copyTimer.current) clearTimeout(copyTimer.current);
|
|
87
|
+
};
|
|
88
|
+
}, []);
|
|
89
|
+
const isSecurity = isSecurityData(dataValue);
|
|
90
|
+
const unlocked = isSecurity ? isUnlocked(storeKey) : maskPlain ? plainViewed : true;
|
|
91
|
+
const displayValue = unlocked ? isSecurity ? securityData[storeKey] || '******' : dataValue : '******';
|
|
92
|
+
|
|
93
|
+
// securityData 变化时回调,把整个对象抛给消费方
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (!onSecurityDataChange) return;
|
|
96
|
+
// 0.0.130 起 storeKey 含密文指纹(dataKey#tail16),内部缓存键不再是纯 dataKey;
|
|
97
|
+
// 按本 prop 文档契约(key 为字段名),这里把自身条目以原始 dataKey 补一份别名,
|
|
98
|
+
// 保证消费方 securityData[dataKey] 能取到明文(同 dataKey 多密文时以后解锁的为准)
|
|
99
|
+
const ownValue = securityData[storeKey];
|
|
100
|
+
const payload = ownValue !== undefined && securityData[dataKey] !== ownValue ? {
|
|
101
|
+
...securityData,
|
|
102
|
+
[dataKey]: ownValue
|
|
103
|
+
} : securityData;
|
|
104
|
+
onSecurityDataChange(payload);
|
|
105
|
+
}, [securityData, onSecurityDataChange, storeKey, dataKey]);
|
|
106
|
+
const handleView = () => {
|
|
107
|
+
if (isSecurity) {
|
|
108
|
+
requestSecurityData({
|
|
109
|
+
env,
|
|
110
|
+
gameId,
|
|
111
|
+
pageId,
|
|
112
|
+
forceRefresh: true,
|
|
113
|
+
param: [{
|
|
114
|
+
key: dataKey,
|
|
115
|
+
value: dataValue,
|
|
116
|
+
cacheKey: storeKey
|
|
117
|
+
}]
|
|
118
|
+
});
|
|
119
|
+
} else if (maskPlain) {
|
|
120
|
+
setPlainViewed(true);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const handleCopy = useCallback(async () => {
|
|
124
|
+
// 待复制的明文值
|
|
125
|
+
const value = unlocked ? isSecurity ? securityData[storeKey] || '' : dataValue : '';
|
|
126
|
+
if (onCopy) {
|
|
127
|
+
await onCopy(value);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
await navigator.clipboard.writeText(value);
|
|
132
|
+
if (copySuccessText) {
|
|
133
|
+
if (copyTimer.current) clearTimeout(copyTimer.current);
|
|
134
|
+
setCopied(true);
|
|
135
|
+
copyTimer.current = setTimeout(() => setCopied(false), 2000);
|
|
136
|
+
}
|
|
137
|
+
} catch (err) {
|
|
138
|
+
// eslint-disable-next-line no-console
|
|
139
|
+
console.warn('[pnt-component-frontend] 复制失败', err);
|
|
140
|
+
}
|
|
141
|
+
}, [unlocked, isSecurity, securityData, storeKey, dataValue, onCopy, copySuccessText]);
|
|
142
|
+
|
|
143
|
+
// 渲染逻辑:
|
|
144
|
+
// 1. 敏感数据未解锁:显示查看按钮(viewText)
|
|
145
|
+
// 2. 敏感数据已解锁 + copyable:显示复制按钮(copyText),复制成功临时显示 copySuccessText
|
|
146
|
+
// 3. 敏感数据已解锁 + !copyable:不显示按钮(旧行为)
|
|
147
|
+
// 4. 普通明文(非敏感):无任何按钮
|
|
148
|
+
const isSensitive = isSecurity || !!maskPlain;
|
|
149
|
+
const showViewBtn = !unlocked;
|
|
150
|
+
const showCopyBtn = unlocked && isSensitive && copyable;
|
|
151
|
+
return /*#__PURE__*/_jsx("div", {
|
|
152
|
+
className: "pnt-secure-box",
|
|
153
|
+
children: /*#__PURE__*/_jsxs(_Fragment, {
|
|
154
|
+
children: [renderDom(displayValue), showViewBtn && /*#__PURE__*/_jsx("span", {
|
|
155
|
+
className: "view-icon",
|
|
156
|
+
onClick: handleView,
|
|
157
|
+
children: viewText || 'View'
|
|
158
|
+
}), showCopyBtn && /*#__PURE__*/_jsx("span", {
|
|
159
|
+
className: "copy-icon",
|
|
160
|
+
onClick: handleCopy,
|
|
161
|
+
children: copied && copySuccessText ? copySuccessText : copyText || 'Copy'
|
|
162
|
+
})]
|
|
163
|
+
})
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
export default PntSecureBox;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.pnt-secure-box {
|
|
2
|
+
position: relative;
|
|
3
|
+
color: #333;
|
|
4
|
+
max-width: fit-content;
|
|
5
|
+
|
|
6
|
+
.view-icon,
|
|
7
|
+
.copy-icon {
|
|
8
|
+
position: absolute;
|
|
9
|
+
top: 1px;
|
|
10
|
+
right: -30px;
|
|
11
|
+
color: #3f8cff !important;
|
|
12
|
+
cursor: pointer;
|
|
13
|
+
font-size: small;
|
|
14
|
+
}
|
|
15
|
+
.copy-icon {
|
|
16
|
+
right: -50px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.security-value {
|
|
20
|
+
position: relative;
|
|
21
|
+
top: 3px;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PntTable — 统一表格组件
|
|
3
|
+
*
|
|
4
|
+
* 封装 tdesign-react Table,落地产品规范 12 章 47 条规则:
|
|
5
|
+
* 排序三态循环、筛选草稿/生效分离、多选三态+翻页清空、分页越界校验、
|
|
6
|
+
* 请求顺序控制、7 种状态管理、蓝紫双主题、同字段 sort+headerFilter 互斥。
|
|
7
|
+
*
|
|
8
|
+
* 零业务侵入:业务项目通过 fetcher 注入数据源,不依赖组件库内部 API。
|
|
9
|
+
*/
|
|
10
|
+
/// <reference types="react" />
|
|
11
|
+
import './index.scss';
|
|
12
|
+
import type { PntTableProps, PntTableRef } from './types';
|
|
13
|
+
export declare const PntTable: import("react").ForwardRefExoticComponent<PntTableProps & import("react").RefAttributes<PntTableRef>>;
|
|
14
|
+
export default PntTable;
|