@pnt-team/pnt-component-frontend 0.0.89 → 0.0.91
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/components/PntBusinessSelect/index.js +13 -32
- package/lib/cjs/components/PntGeneralLayout/index.js +1 -9
- package/lib/cjs/components/PntImage/index.d.ts +87 -0
- package/lib/cjs/components/PntImage/index.js +137 -0
- package/lib/{esm/components/PntImagePreview → cjs/components/PntImage}/index.scss +14 -7
- package/lib/cjs/index.d.ts +1 -1
- package/lib/cjs/index.js +3 -3
- package/lib/esm/components/PntBusinessSelect/index.js +8 -34
- package/lib/esm/components/PntImage/index.d.ts +87 -0
- package/lib/esm/components/PntImage/index.js +181 -0
- package/lib/{cjs/components/PntImagePreview → esm/components/PntImage}/index.scss +14 -7
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -1
- 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/lib/cjs/components/PntImagePreview/index.d.ts +0 -75
- package/lib/cjs/components/PntImagePreview/index.js +0 -98
- package/lib/esm/components/PntImagePreview/index.d.ts +0 -75
- package/lib/esm/components/PntImagePreview/index.js +0 -120
|
@@ -110,60 +110,46 @@ var PntBusinessSelect = (props) => {
|
|
|
110
110
|
);
|
|
111
111
|
const fetchData = (0, import_react.useCallback)(
|
|
112
112
|
async (kw, page, append) => {
|
|
113
|
-
var _a, _b
|
|
113
|
+
var _a, _b;
|
|
114
114
|
if (append) {
|
|
115
|
-
if (appendLoadingRef.current || loadingRef.current)
|
|
116
|
-
console.log("[PntBS] fetchData APPEND blocked: loading=" + loadingRef.current + " appendLoading=" + appendLoadingRef.current);
|
|
115
|
+
if (appendLoadingRef.current || loadingRef.current)
|
|
117
116
|
return;
|
|
118
|
-
}
|
|
119
117
|
const meta = listMetaRef.current;
|
|
120
|
-
if (meta.keyword !== kw)
|
|
121
|
-
console.log("[PntBS] fetchData APPEND blocked: kw mismatch " + kw + " vs " + meta.keyword);
|
|
118
|
+
if (meta.keyword !== kw)
|
|
122
119
|
return;
|
|
123
|
-
|
|
124
|
-
if (page <= meta.page) {
|
|
125
|
-
console.log("[PntBS] fetchData APPEND blocked: page " + page + " <= " + meta.page);
|
|
120
|
+
if (page <= meta.page)
|
|
126
121
|
return;
|
|
127
|
-
|
|
128
|
-
if (optionsRef.current.length >= meta.total) {
|
|
129
|
-
console.log("[PntBS] fetchData APPEND blocked: no more");
|
|
122
|
+
if (optionsRef.current.length >= meta.total)
|
|
130
123
|
return;
|
|
131
|
-
}
|
|
132
124
|
appendLoadingRef.current = true;
|
|
133
125
|
}
|
|
134
126
|
const seq = ++fetchSeqRef.current;
|
|
135
|
-
console.log('[PntBS] fetchData START kw="' + kw + '" page=' + page + " append=" + append + " seq=" + seq);
|
|
136
127
|
loadingRef.current = true;
|
|
137
128
|
setLoading(true);
|
|
138
129
|
try {
|
|
139
130
|
const res = await requestFn(buildParams(kw, page));
|
|
140
|
-
|
|
141
|
-
if (seq !== fetchSeqRef.current) {
|
|
142
|
-
console.log("[PntBS] fetchData seq MISMATCH - DROPPED (seq=" + seq + " latest=" + fetchSeqRef.current + ")");
|
|
131
|
+
if (seq !== fetchSeqRef.current)
|
|
143
132
|
return;
|
|
144
|
-
}
|
|
145
133
|
if (res.code === 0 && res.data) {
|
|
146
134
|
const newList = res.data.list || [];
|
|
147
135
|
const resTotal = ((_a = res.data.pagination) == null ? void 0 : _a.total) || 0;
|
|
148
136
|
let nextList;
|
|
149
137
|
if (append) {
|
|
150
138
|
const existed = new Set(optionsRef.current.map((o) => o.game_id));
|
|
151
|
-
nextList = [
|
|
139
|
+
nextList = [
|
|
140
|
+
...optionsRef.current,
|
|
141
|
+
...newList.filter((o) => !existed.has(o.game_id))
|
|
142
|
+
];
|
|
152
143
|
} else {
|
|
153
144
|
nextList = newList;
|
|
154
145
|
lastReplaceAtRef.current = Date.now();
|
|
155
146
|
}
|
|
156
147
|
optionsRef.current = nextList;
|
|
157
148
|
listMetaRef.current = { keyword: kw, page, total: resTotal };
|
|
158
|
-
console.log("[PntBS] fetchData SET options count=" + nextList.length + " first=" + (((_b = nextList[0]) == null ? void 0 : _b.name) || "null"));
|
|
159
149
|
setOptions(nextList);
|
|
160
|
-
(
|
|
161
|
-
} else {
|
|
162
|
-
console.log("[PntBS] fetchData BAD RESPONSE code=" + res.code + " hasData=" + !!res.data);
|
|
150
|
+
(_b = onLoadedRef.current) == null ? void 0 : _b.call(onLoadedRef, nextList);
|
|
163
151
|
}
|
|
164
|
-
} catch
|
|
165
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
166
|
-
console.log("[PntBS] fetchData ERROR seq=" + seq + ' kw="' + kw + '": ' + msg);
|
|
152
|
+
} catch {
|
|
167
153
|
} finally {
|
|
168
154
|
if (append)
|
|
169
155
|
appendLoadingRef.current = false;
|
|
@@ -178,13 +164,10 @@ var PntBusinessSelect = (props) => {
|
|
|
178
164
|
const handleSearch = (0, import_react.useCallback)(
|
|
179
165
|
(val) => {
|
|
180
166
|
keywordRef.current = val;
|
|
181
|
-
console.log('[PntBS] handleSearch val="' + val + '" debounceMs=' + searchDebounce);
|
|
182
167
|
if (debounceRef.current)
|
|
183
168
|
clearTimeout(debounceRef.current);
|
|
184
169
|
debounceRef.current = setTimeout(() => {
|
|
185
|
-
|
|
186
|
-
console.log('[PntBS] handleSearch timer fired, fetchData kw="' + kw + '" append=false seq++');
|
|
187
|
-
fetchData(kw, 1, false);
|
|
170
|
+
fetchData(keywordRef.current, 1, false);
|
|
188
171
|
}, searchDebounce);
|
|
189
172
|
},
|
|
190
173
|
[fetchData, searchDebounce]
|
|
@@ -203,7 +186,6 @@ var PntBusinessSelect = (props) => {
|
|
|
203
186
|
clearTimeout(debounceRef.current);
|
|
204
187
|
keywordRef.current = "";
|
|
205
188
|
if (listMetaRef.current.keyword) {
|
|
206
|
-
console.log('[PntBS] popupClose resetting from kw="' + listMetaRef.current.keyword + '"');
|
|
207
189
|
fetchData("", 1, false);
|
|
208
190
|
}
|
|
209
191
|
},
|
|
@@ -400,7 +382,6 @@ var PntBusinessSelect = (props) => {
|
|
|
400
382
|
[onChange, multiple, getLabelText]
|
|
401
383
|
);
|
|
402
384
|
const handleClear = (0, import_react.useCallback)(() => {
|
|
403
|
-
console.log("[PntBS] handleClear X-button clicked, resetting");
|
|
404
385
|
keywordRef.current = "";
|
|
405
386
|
if (debounceRef.current)
|
|
406
387
|
clearTimeout(debounceRef.current);
|
|
@@ -70,15 +70,7 @@ var PntGeneralLayout = (prop) => {
|
|
|
70
70
|
operation && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "header-operation", children: operation })
|
|
71
71
|
] }),
|
|
72
72
|
subHeaderContent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "general-layout-sub-header", children: subHeaderContent }),
|
|
73
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
74
|
-
"div",
|
|
75
|
-
{
|
|
76
|
-
className: "general-layout-body",
|
|
77
|
-
ref: bodyRef,
|
|
78
|
-
style: bodyStyle,
|
|
79
|
-
children
|
|
80
|
-
}
|
|
81
|
-
),
|
|
73
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "general-layout-body", ref: bodyRef, style: bodyStyle, children }),
|
|
82
74
|
footer && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Footer, { children: footer })
|
|
83
75
|
] });
|
|
84
76
|
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import './index.scss';
|
|
3
|
+
/**
|
|
4
|
+
* PntImage 文案集合
|
|
5
|
+
* @description 所有内部展示文案均可通过 texts prop 自定义,用于多语言场景
|
|
6
|
+
*/
|
|
7
|
+
export interface PntImageTexts {
|
|
8
|
+
/** 上传中占位文案(仅上传预览模式生效) */
|
|
9
|
+
uploading?: string;
|
|
10
|
+
/** 图片加载中占位文案(纯预览模式生效,透传给 tdesign Image loading) */
|
|
11
|
+
loading?: string;
|
|
12
|
+
/** 图片加载失败占位文案(纯预览模式生效,透传给 tdesign Image error) */
|
|
13
|
+
loadFailed?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface PntImageProps {
|
|
16
|
+
/**
|
|
17
|
+
* 图片地址
|
|
18
|
+
* @description 图片的完整 URL 地址;为空则展示 defaultImg 或内置 uploadImg
|
|
19
|
+
*/
|
|
20
|
+
src: string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* alt 文本
|
|
23
|
+
* @description 图片加载失败时的替代文本,纯预览模式必传以提升可访问性
|
|
24
|
+
*/
|
|
25
|
+
alt?: string;
|
|
26
|
+
/**
|
|
27
|
+
* 默认图片
|
|
28
|
+
* @description src 为空时展示的占位图;不传则使用内置的 uploadImg
|
|
29
|
+
*/
|
|
30
|
+
defaultImg?: string;
|
|
31
|
+
/**
|
|
32
|
+
* 自定义样式
|
|
33
|
+
* @description 一般用于控制图片宽高
|
|
34
|
+
*/
|
|
35
|
+
style?: React.CSSProperties;
|
|
36
|
+
/**
|
|
37
|
+
* 上传中状态
|
|
38
|
+
* @description 当为 true 时显示上传中 loading 占位,阻止其他操作;仅在上传预览模式(传入 onRemove)生效
|
|
39
|
+
*/
|
|
40
|
+
loading?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* 删除回调
|
|
43
|
+
* @description 传入即启用「上传预览模式」,mask 含预览 + 删除按钮;不传则为「纯预览模式」
|
|
44
|
+
* @param e - 事件对象
|
|
45
|
+
*/
|
|
46
|
+
onRemove?: (e: any) => void;
|
|
47
|
+
/**
|
|
48
|
+
* attach 容器
|
|
49
|
+
* @description 弹窗场景下需要透传给 tdesign ImageViewer 的 attach,避免预览浮层被父容器裁剪
|
|
50
|
+
*/
|
|
51
|
+
container?: HTMLElement | (() => HTMLElement);
|
|
52
|
+
/**
|
|
53
|
+
* 多语言文案
|
|
54
|
+
* @description 传入即覆盖默认中文文案;仅对应字段会覆盖,未传字段仍用默认值
|
|
55
|
+
*/
|
|
56
|
+
texts?: PntImageTexts;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* PntImage 业务图片组件
|
|
60
|
+
* @description 统一覆盖「上传图片预览」和「纯图片预览」两种业务场景,避免业务侧维护两套组件
|
|
61
|
+
*
|
|
62
|
+
* 模式判定:传入 `onRemove` 即为上传预览模式,否则为纯预览模式
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```tsx
|
|
66
|
+
* // 上传预览模式
|
|
67
|
+
* <PntImage
|
|
68
|
+
* src={iconUrl}
|
|
69
|
+
* loading={loading}
|
|
70
|
+
* defaultImg={defaultImg}
|
|
71
|
+
* onRemove={handleRemove}
|
|
72
|
+
* style={{ width: 136, height: 136 }}
|
|
73
|
+
* />
|
|
74
|
+
*
|
|
75
|
+
* // 纯预览模式
|
|
76
|
+
* <PntImage
|
|
77
|
+
* src={url}
|
|
78
|
+
* alt="avatar"
|
|
79
|
+
* style={{ width: 60, height: 60 }}
|
|
80
|
+
* container={container}
|
|
81
|
+
* />
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @returns {ReactElement} 业务图片组件
|
|
85
|
+
*/
|
|
86
|
+
declare const PntImage: FC<PntImageProps>;
|
|
87
|
+
export default PntImage;
|
|
@@ -0,0 +1,137 @@
|
|
|
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/PntImage/index.tsx
|
|
30
|
+
var PntImage_exports = {};
|
|
31
|
+
__export(PntImage_exports, {
|
|
32
|
+
default: () => PntImage_default
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(PntImage_exports);
|
|
35
|
+
var import_uploadImg = __toESM(require("../../assets/images/uploadImg.png"));
|
|
36
|
+
var import_tdesign_icons_react = require("tdesign-icons-react");
|
|
37
|
+
var import_tdesign_react = require("tdesign-react");
|
|
38
|
+
var import_index = require("./index.scss");
|
|
39
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
40
|
+
var DEFAULT_TEXTS = {
|
|
41
|
+
uploading: "上传中",
|
|
42
|
+
loading: "加载中",
|
|
43
|
+
loadFailed: "加载失败"
|
|
44
|
+
};
|
|
45
|
+
var PntImage = ({
|
|
46
|
+
src,
|
|
47
|
+
alt = "",
|
|
48
|
+
defaultImg,
|
|
49
|
+
style,
|
|
50
|
+
loading = false,
|
|
51
|
+
onRemove,
|
|
52
|
+
container,
|
|
53
|
+
texts
|
|
54
|
+
}) => {
|
|
55
|
+
const isUploadMode = typeof onRemove === "function";
|
|
56
|
+
const finalSrc = (src == null ? void 0 : src.length) ? src : defaultImg || import_uploadImg.default;
|
|
57
|
+
const attach = container ? typeof container === "function" ? container : () => container : void 0;
|
|
58
|
+
const finalTexts = { ...DEFAULT_TEXTS, ...texts };
|
|
59
|
+
const UploadLoadingContent = (isImageLoading) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
60
|
+
"div",
|
|
61
|
+
{
|
|
62
|
+
className: isImageLoading ? "pnt-image-progress" : "pnt-image-upload-progress",
|
|
63
|
+
style,
|
|
64
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-image-loading", children: [
|
|
65
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.LoadingIcon, { size: "18px", name: "loading" }),
|
|
66
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: finalTexts.uploading })
|
|
67
|
+
] })
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
const basicImageLoading = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
71
|
+
import_tdesign_react.Space,
|
|
72
|
+
{
|
|
73
|
+
direction: "vertical",
|
|
74
|
+
align: "center",
|
|
75
|
+
size: "small",
|
|
76
|
+
style: { color: "var(--td-text-color-disabled)" },
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.ImageIcon, { size: 24 }),
|
|
79
|
+
finalTexts.loading
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
const basicImageError = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_tdesign_react.Space, { direction: "vertical", align: "center", size: "small", children: [
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.ImageErrorIcon, { size: 24 }),
|
|
85
|
+
finalTexts.loadFailed
|
|
86
|
+
] });
|
|
87
|
+
const basicMask = (open) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
88
|
+
"div",
|
|
89
|
+
{
|
|
90
|
+
className: "pnt-image-mask pnt-image-mask--basic",
|
|
91
|
+
style: { background: "rgba(0,0,0,.1)", height: "100%" },
|
|
92
|
+
onClick: open
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
const uploadMask = (open) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pnt-image-mask pnt-image-mask--upload", children: [
|
|
96
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.BrowseIcon, { onClick: open, size: "16px", name: "browse" }) }),
|
|
97
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pnt-image-divider" }),
|
|
98
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tdesign_icons_react.DeleteIcon, { onClick: onRemove, size: "16px", name: "delete" }) })
|
|
99
|
+
] });
|
|
100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
101
|
+
"div",
|
|
102
|
+
{
|
|
103
|
+
className: "pnt-image-wrapper",
|
|
104
|
+
onClick: (e) => {
|
|
105
|
+
if (isUploadMode && ((src == null ? void 0 : src.length) || loading)) {
|
|
106
|
+
e.stopPropagation();
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
children: isUploadMode && loading ? UploadLoadingContent(false) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
110
|
+
import_tdesign_react.ImageViewer,
|
|
111
|
+
{
|
|
112
|
+
images: [finalSrc],
|
|
113
|
+
closeOnOverlay: true,
|
|
114
|
+
attach,
|
|
115
|
+
trigger: ({ open }) => {
|
|
116
|
+
const mask = isUploadMode ? uploadMask(open) : basicMask(open);
|
|
117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
118
|
+
import_tdesign_react.Image,
|
|
119
|
+
{
|
|
120
|
+
alt,
|
|
121
|
+
src: finalSrc,
|
|
122
|
+
loading: isUploadMode ? UploadLoadingContent(true) : basicImageLoading,
|
|
123
|
+
error: isUploadMode ? void 0 : basicImageError,
|
|
124
|
+
overlayContent: isUploadMode ? src ? mask : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {}) : mask,
|
|
125
|
+
overlayTrigger: "hover",
|
|
126
|
+
fit: "contain",
|
|
127
|
+
className: "pnt-image",
|
|
128
|
+
style
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
var PntImage_default = PntImage;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
.pnt-image-
|
|
1
|
+
.pnt-image-wrapper {
|
|
2
2
|
position: relative;
|
|
3
3
|
|
|
4
|
-
.pnt-image-
|
|
5
|
-
.pnt-image-
|
|
4
|
+
.pnt-image-progress,
|
|
5
|
+
.pnt-image-upload-progress {
|
|
6
6
|
width: 136px;
|
|
7
7
|
height: 136px;
|
|
8
8
|
display: flex;
|
|
9
9
|
align-items: center;
|
|
10
10
|
justify-content: center;
|
|
11
11
|
|
|
12
|
-
.pnt-image-
|
|
12
|
+
.pnt-image-loading {
|
|
13
13
|
width: 100%;
|
|
14
14
|
height: 100%;
|
|
15
15
|
text-align: center;
|
|
@@ -33,18 +33,25 @@
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
.pnt-image
|
|
36
|
+
.pnt-image {
|
|
37
37
|
width: 136px;
|
|
38
38
|
height: 136px;
|
|
39
39
|
|
|
40
|
-
.pnt-image-
|
|
40
|
+
.pnt-image-mask {
|
|
41
41
|
background: rgba(0, 0, 0, 60%);
|
|
42
42
|
color: #fff;
|
|
43
43
|
height: 100%;
|
|
44
44
|
display: flex;
|
|
45
45
|
align-items: center;
|
|
46
46
|
justify-content: center;
|
|
47
|
-
|
|
47
|
+
|
|
48
|
+
// 纯预览模式:半透明遮罩,鼠标手型
|
|
49
|
+
&--basic {
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 上传预览模式:分隔线
|
|
54
|
+
.pnt-image-divider {
|
|
48
55
|
margin: 0 var(--td-comp-margin-l);
|
|
49
56
|
border-left: 1px var(--td-text-color-anti) solid;
|
|
50
57
|
height: var(--td-comp-size-xxxs);
|
package/lib/cjs/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { PntProvider, usePntConfig, type PntConfig, type commonEesType, } from './config';
|
|
2
|
-
export { default as
|
|
2
|
+
export { default as PntImage } from './components/PntImage';
|
|
3
3
|
export { default as PntBusinessSelect } from './components/PntBusinessSelect';
|
|
4
4
|
export { default as PntSecureBox } from './components/PntSecureBox';
|
|
5
5
|
export { default as PntGeneralLayout } from './components/PntGeneralLayout';
|
package/lib/cjs/index.js
CHANGED
|
@@ -31,14 +31,14 @@ var src_exports = {};
|
|
|
31
31
|
__export(src_exports, {
|
|
32
32
|
PntBusinessSelect: () => import_PntBusinessSelect.default,
|
|
33
33
|
PntGeneralLayout: () => import_PntGeneralLayout.default,
|
|
34
|
-
|
|
34
|
+
PntImage: () => import_PntImage.default,
|
|
35
35
|
PntProvider: () => import_config.PntProvider,
|
|
36
36
|
PntSecureBox: () => import_PntSecureBox.default,
|
|
37
37
|
usePntConfig: () => import_config.usePntConfig
|
|
38
38
|
});
|
|
39
39
|
module.exports = __toCommonJS(src_exports);
|
|
40
40
|
var import_config = require("./config");
|
|
41
|
-
var
|
|
41
|
+
var import_PntImage = __toESM(require("./components/PntImage"));
|
|
42
42
|
var import_PntBusinessSelect = __toESM(require("./components/PntBusinessSelect"));
|
|
43
43
|
var import_PntSecureBox = __toESM(require("./components/PntSecureBox"));
|
|
44
44
|
var import_PntGeneralLayout = __toESM(require("./components/PntGeneralLayout"));
|
|
@@ -46,7 +46,7 @@ var import_PntGeneralLayout = __toESM(require("./components/PntGeneralLayout"));
|
|
|
46
46
|
0 && (module.exports = {
|
|
47
47
|
PntBusinessSelect,
|
|
48
48
|
PntGeneralLayout,
|
|
49
|
-
|
|
49
|
+
PntImage,
|
|
50
50
|
PntProvider,
|
|
51
51
|
PntSecureBox,
|
|
52
52
|
usePntConfig
|
|
@@ -153,36 +153,19 @@ const PntBusinessSelect = props => {
|
|
|
153
153
|
// append=true 为滚动翻页(追加),append=false 为初始化/搜索/重置(替换)
|
|
154
154
|
const fetchData = useCallback(async (kw, page, append) => {
|
|
155
155
|
if (append) {
|
|
156
|
-
if (appendLoadingRef.current || loadingRef.current)
|
|
157
|
-
console.log('[PntBS] fetchData APPEND blocked: loading=' + loadingRef.current + ' appendLoading=' + appendLoadingRef.current);
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
156
|
+
if (appendLoadingRef.current || loadingRef.current) return;
|
|
160
157
|
const meta = listMetaRef.current;
|
|
161
|
-
if (meta.keyword !== kw)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
if (page <= meta.page) {
|
|
166
|
-
console.log('[PntBS] fetchData APPEND blocked: page ' + page + ' <= ' + meta.page);
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
if (optionsRef.current.length >= meta.total) {
|
|
170
|
-
console.log('[PntBS] fetchData APPEND blocked: no more');
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
158
|
+
if (meta.keyword !== kw) return;
|
|
159
|
+
if (page <= meta.page) return;
|
|
160
|
+
if (optionsRef.current.length >= meta.total) return;
|
|
173
161
|
appendLoadingRef.current = true;
|
|
174
162
|
}
|
|
175
163
|
const seq = ++fetchSeqRef.current;
|
|
176
|
-
console.log('[PntBS] fetchData START kw="' + kw + '" page=' + page + ' append=' + append + ' seq=' + seq);
|
|
177
164
|
loadingRef.current = true;
|
|
178
165
|
setLoading(true);
|
|
179
166
|
try {
|
|
180
167
|
const res = await requestFn(buildParams(kw, page));
|
|
181
|
-
|
|
182
|
-
if (seq !== fetchSeqRef.current) {
|
|
183
|
-
console.log('[PntBS] fetchData seq MISMATCH - DROPPED (seq=' + seq + ' latest=' + fetchSeqRef.current + ')');
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
168
|
+
if (seq !== fetchSeqRef.current) return;
|
|
186
169
|
if (res.code === 0 && res.data) {
|
|
187
170
|
const newList = res.data.list || [];
|
|
188
171
|
const resTotal = res.data.pagination?.total || 0;
|
|
@@ -200,15 +183,11 @@ const PntBusinessSelect = props => {
|
|
|
200
183
|
page,
|
|
201
184
|
total: resTotal
|
|
202
185
|
};
|
|
203
|
-
console.log('[PntBS] fetchData SET options count=' + nextList.length + ' first=' + (nextList[0]?.name || 'null'));
|
|
204
186
|
setOptions(nextList);
|
|
205
187
|
onLoadedRef.current?.(nextList);
|
|
206
|
-
} else {
|
|
207
|
-
console.log('[PntBS] fetchData BAD RESPONSE code=' + res.code + ' hasData=' + !!res.data);
|
|
208
188
|
}
|
|
209
|
-
} catch
|
|
210
|
-
|
|
211
|
-
console.log('[PntBS] fetchData ERROR seq=' + seq + ' kw="' + kw + '": ' + msg);
|
|
189
|
+
} catch {
|
|
190
|
+
// 请求失败静默处理,不阻塞主流程
|
|
212
191
|
} finally {
|
|
213
192
|
if (append) appendLoadingRef.current = false;
|
|
214
193
|
if (seq === fetchSeqRef.current) {
|
|
@@ -221,12 +200,9 @@ const PntBusinessSelect = props => {
|
|
|
221
200
|
// ---- 远程搜索(防抖) ----
|
|
222
201
|
const handleSearch = useCallback(val => {
|
|
223
202
|
keywordRef.current = val;
|
|
224
|
-
console.log('[PntBS] handleSearch val="' + val + '" debounceMs=' + searchDebounce);
|
|
225
203
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
226
204
|
debounceRef.current = setTimeout(() => {
|
|
227
|
-
|
|
228
|
-
console.log('[PntBS] handleSearch timer fired, fetchData kw="' + kw + '" append=false seq++');
|
|
229
|
-
fetchData(kw, 1, false);
|
|
205
|
+
fetchData(keywordRef.current, 1, false);
|
|
230
206
|
}, searchDebounce);
|
|
231
207
|
}, [fetchData, searchDebounce]);
|
|
232
208
|
|
|
@@ -250,7 +226,6 @@ const PntBusinessSelect = props => {
|
|
|
250
226
|
// 上次搜索结果,关闭时必须重置回默认列表。
|
|
251
227
|
keywordRef.current = '';
|
|
252
228
|
if (listMetaRef.current.keyword) {
|
|
253
|
-
console.log('[PntBS] popupClose resetting from kw="' + listMetaRef.current.keyword + '"');
|
|
254
229
|
fetchData('', 1, false);
|
|
255
230
|
}
|
|
256
231
|
}, [fetchData]);
|
|
@@ -475,7 +450,6 @@ const PntBusinessSelect = props => {
|
|
|
475
450
|
// 点击 clear 按钮(X)时重置列表——TDesign 的 onClearValue 只 setInputValue,
|
|
476
451
|
// 不触发 handleInputChange / onSearch,所以需要主动重置。
|
|
477
452
|
const handleClear = useCallback(() => {
|
|
478
|
-
console.log('[PntBS] handleClear X-button clicked, resetting');
|
|
479
453
|
keywordRef.current = '';
|
|
480
454
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
481
455
|
if (listMetaRef.current.keyword) {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import './index.scss';
|
|
3
|
+
/**
|
|
4
|
+
* PntImage 文案集合
|
|
5
|
+
* @description 所有内部展示文案均可通过 texts prop 自定义,用于多语言场景
|
|
6
|
+
*/
|
|
7
|
+
export interface PntImageTexts {
|
|
8
|
+
/** 上传中占位文案(仅上传预览模式生效) */
|
|
9
|
+
uploading?: string;
|
|
10
|
+
/** 图片加载中占位文案(纯预览模式生效,透传给 tdesign Image loading) */
|
|
11
|
+
loading?: string;
|
|
12
|
+
/** 图片加载失败占位文案(纯预览模式生效,透传给 tdesign Image error) */
|
|
13
|
+
loadFailed?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface PntImageProps {
|
|
16
|
+
/**
|
|
17
|
+
* 图片地址
|
|
18
|
+
* @description 图片的完整 URL 地址;为空则展示 defaultImg 或内置 uploadImg
|
|
19
|
+
*/
|
|
20
|
+
src: string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* alt 文本
|
|
23
|
+
* @description 图片加载失败时的替代文本,纯预览模式必传以提升可访问性
|
|
24
|
+
*/
|
|
25
|
+
alt?: string;
|
|
26
|
+
/**
|
|
27
|
+
* 默认图片
|
|
28
|
+
* @description src 为空时展示的占位图;不传则使用内置的 uploadImg
|
|
29
|
+
*/
|
|
30
|
+
defaultImg?: string;
|
|
31
|
+
/**
|
|
32
|
+
* 自定义样式
|
|
33
|
+
* @description 一般用于控制图片宽高
|
|
34
|
+
*/
|
|
35
|
+
style?: React.CSSProperties;
|
|
36
|
+
/**
|
|
37
|
+
* 上传中状态
|
|
38
|
+
* @description 当为 true 时显示上传中 loading 占位,阻止其他操作;仅在上传预览模式(传入 onRemove)生效
|
|
39
|
+
*/
|
|
40
|
+
loading?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* 删除回调
|
|
43
|
+
* @description 传入即启用「上传预览模式」,mask 含预览 + 删除按钮;不传则为「纯预览模式」
|
|
44
|
+
* @param e - 事件对象
|
|
45
|
+
*/
|
|
46
|
+
onRemove?: (e: any) => void;
|
|
47
|
+
/**
|
|
48
|
+
* attach 容器
|
|
49
|
+
* @description 弹窗场景下需要透传给 tdesign ImageViewer 的 attach,避免预览浮层被父容器裁剪
|
|
50
|
+
*/
|
|
51
|
+
container?: HTMLElement | (() => HTMLElement);
|
|
52
|
+
/**
|
|
53
|
+
* 多语言文案
|
|
54
|
+
* @description 传入即覆盖默认中文文案;仅对应字段会覆盖,未传字段仍用默认值
|
|
55
|
+
*/
|
|
56
|
+
texts?: PntImageTexts;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* PntImage 业务图片组件
|
|
60
|
+
* @description 统一覆盖「上传图片预览」和「纯图片预览」两种业务场景,避免业务侧维护两套组件
|
|
61
|
+
*
|
|
62
|
+
* 模式判定:传入 `onRemove` 即为上传预览模式,否则为纯预览模式
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```tsx
|
|
66
|
+
* // 上传预览模式
|
|
67
|
+
* <PntImage
|
|
68
|
+
* src={iconUrl}
|
|
69
|
+
* loading={loading}
|
|
70
|
+
* defaultImg={defaultImg}
|
|
71
|
+
* onRemove={handleRemove}
|
|
72
|
+
* style={{ width: 136, height: 136 }}
|
|
73
|
+
* />
|
|
74
|
+
*
|
|
75
|
+
* // 纯预览模式
|
|
76
|
+
* <PntImage
|
|
77
|
+
* src={url}
|
|
78
|
+
* alt="avatar"
|
|
79
|
+
* style={{ width: 60, height: 60 }}
|
|
80
|
+
* container={container}
|
|
81
|
+
* />
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @returns {ReactElement} 业务图片组件
|
|
85
|
+
*/
|
|
86
|
+
declare const PntImage: FC<PntImageProps>;
|
|
87
|
+
export default PntImage;
|