bee-front-components 1.0.0

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 (92) hide show
  1. package/config/config.ts +28 -0
  2. package/lib/assets/images/empty.png +0 -0
  3. package/lib/components/BaseModal/index.d.ts +41 -0
  4. package/lib/components/BaseModal/index.js +133 -0
  5. package/lib/components/BaseModal/index.module.less +66 -0
  6. package/lib/components/Buttons/Button.d.ts +17 -0
  7. package/lib/components/Buttons/Button.js +34 -0
  8. package/lib/components/Buttons/ButtonPermission.d.ts +18 -0
  9. package/lib/components/Buttons/ButtonPermission.js +34 -0
  10. package/lib/components/Buttons/index.d.ts +3 -0
  11. package/lib/components/Buttons/index.js +3 -0
  12. package/lib/components/Buttons/index.module.less +21 -0
  13. package/lib/components/ContentHeader/index.d.ts +17 -0
  14. package/lib/components/ContentHeader/index.js +22 -0
  15. package/lib/components/ContentHeader/index.module.less +14 -0
  16. package/lib/components/Empty/index.d.ts +17 -0
  17. package/lib/components/Empty/index.js +23 -0
  18. package/lib/components/Empty/index.module.less +15 -0
  19. package/lib/components/ExcelExport/index.d.ts +28 -0
  20. package/lib/components/ExcelExport/index.js +60 -0
  21. package/lib/components/ExcelExport/index.module.less +61 -0
  22. package/lib/components/Modal/index.d.ts +26 -0
  23. package/lib/components/Modal/index.js +191 -0
  24. package/lib/components/Modal/index.module.less +79 -0
  25. package/lib/components/PageHeader/index.d.ts +43 -0
  26. package/lib/components/PageHeader/index.js +72 -0
  27. package/lib/components/PageHeader/index.module.less +38 -0
  28. package/lib/components/PdfViewer/index.d.ts +49 -0
  29. package/lib/components/PdfViewer/index.js +699 -0
  30. package/lib/components/QueryBar/TableQueryBar.d.ts +32 -0
  31. package/lib/components/QueryBar/TableQueryBar.js +115 -0
  32. package/lib/components/QueryBar/index.d.ts +25 -0
  33. package/lib/components/QueryBar/index.js +102 -0
  34. package/lib/components/QueryBar/index.module.less +58 -0
  35. package/lib/components/RemainDay/index.d.ts +22 -0
  36. package/lib/components/RemainDay/index.js +47 -0
  37. package/lib/components/RemainDay/index.module.less +42 -0
  38. package/lib/components/Scanner/hooks/useKeyboardScanner.d.ts +14 -0
  39. package/lib/components/Scanner/hooks/useKeyboardScanner.js +95 -0
  40. package/lib/components/Scanner/index.d.ts +60 -0
  41. package/lib/components/Scanner/index.js +318 -0
  42. package/lib/components/Scanner/index.module.less +264 -0
  43. package/lib/components/Scanner/utils/device.d.ts +2 -0
  44. package/lib/components/Scanner/utils/device.js +18 -0
  45. package/lib/components/StatusTab/index.d.ts +36 -0
  46. package/lib/components/StatusTab/index.js +118 -0
  47. package/lib/components/StatusTab/index.module.less +20 -0
  48. package/lib/components/StatusTag/index.d.ts +32 -0
  49. package/lib/components/StatusTag/index.js +142 -0
  50. package/lib/components/StatusTag/index.module.less +37 -0
  51. package/lib/components/StepProgress/index.d.ts +36 -0
  52. package/lib/components/StepProgress/index.js +84 -0
  53. package/lib/components/StepProgress/index.module.less +180 -0
  54. package/lib/components/Table/index.d.ts +44 -0
  55. package/lib/components/Table/index.js +135 -0
  56. package/lib/components/Table/index.module.less +24 -0
  57. package/lib/components/TableOperationColumn/index.d.ts +45 -0
  58. package/lib/components/TableOperationColumn/index.js +205 -0
  59. package/lib/components/TableOperationColumn/index.module.less +22 -0
  60. package/lib/components/Tabs/TabGroup.d.ts +9 -0
  61. package/lib/components/Tabs/TabGroup.js +12 -0
  62. package/lib/components/Tabs/TabPane.d.ts +9 -0
  63. package/lib/components/Tabs/TabPane.js +12 -0
  64. package/lib/components/Tabs/Tabs.d.ts +23 -0
  65. package/lib/components/Tabs/Tabs.js +42 -0
  66. package/lib/components/Tabs/index.d.ts +4 -0
  67. package/lib/components/Tabs/index.js +4 -0
  68. package/lib/components/Tabs/index.module.less +20 -0
  69. package/lib/components/Upload/BatchUpload/index.d.ts +42 -0
  70. package/lib/components/Upload/BatchUpload/index.js +140 -0
  71. package/lib/components/Upload/BatchUpload/index.module.less +10 -0
  72. package/lib/components/Upload/DraggerUpload/index.d.ts +42 -0
  73. package/lib/components/Upload/DraggerUpload/index.js +142 -0
  74. package/lib/components/Upload/DraggerUpload/index.module.less +30 -0
  75. package/lib/components/Upload/FileUpload.d.ts +36 -0
  76. package/lib/components/Upload/FileUpload.js +122 -0
  77. package/lib/components/Upload/index.d.ts +4 -0
  78. package/lib/components/Upload/index.js +4 -0
  79. package/lib/components/VipFlag/index.d.ts +10 -0
  80. package/lib/components/VipFlag/index.js +23 -0
  81. package/lib/components/VipFlag/index.module.less +20 -0
  82. package/lib/typings/blank.d.ts +0 -0
  83. package/lib/typings.d.ts +3 -0
  84. package/lib/utils/const.d.ts +21 -0
  85. package/lib/utils/const.js +22 -0
  86. package/lib/utils/index.d.ts +95 -0
  87. package/lib/utils/index.js +319 -0
  88. package/lib/utils/menuTab.d.ts +60 -0
  89. package/lib/utils/menuTab.js +122 -0
  90. package/lib/utils/utils.d.ts +61 -0
  91. package/lib/utils/utils.js +270 -0
  92. package/package.json +41 -0
@@ -0,0 +1,318 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ /**
3
+ * @name 扫码工具
4
+ * @description 用于通过扫码枪或摄像头识别二维码中的相关信息
5
+ * @param {ScannerMode} mode 扫码识别类型
6
+ * @param {boolean} enabled 是否启用扫码组件功能
7
+ * @param {boolean} closeAfterScan 是否在扫码成功后自动关闭摄像头 默认true
8
+ * @param {number} keyboardInterval 扫码枪单次输入最大间隔,单位ms 默认 50ms
9
+ * @param {number} minLength 扫码枪最小字符长度 默认为1
10
+ * @param {string} cameraTitle 摄像头标题
11
+ * @param {boolean} showScanArea 是否显示扫码框
12
+ * @param {boolean} continuous 扫码成功后是否允许继续扫描
13
+ * @param {boolean} showButton 是否显示扫码按钮 仅camera或auto模式有效
14
+ * @param {string} buttonText 扫码按钮文字
15
+ * @param {string} scanerTip 扫码提示文字
16
+ * @param {function} onScan 扫码成功回调
17
+ * @param {function} onError 扫码异常回调
18
+ * @param {function} onClose 摄像头关闭回调
19
+ * @author lichen
20
+ */
21
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
22
+ import classNames from "classnames";
23
+ import { BrowserQRCodeReader } from "@zxing/browser";
24
+ import { ButtonColor, FuncType } from "choerodon-ui/pro/lib/button/enum";
25
+ import { ButtonPermission } from "../Buttons";
26
+ import { getDefaultScannerMode } from "./utils/device";
27
+ import { useKeyboardScanner } from "./hooks/useKeyboardScanner";
28
+ import styles from "./index.module.less?modules";
29
+
30
+ // 扫码识别类型 分别对应不同扫码设备
31
+ export let ScannerMode = /*#__PURE__*/function (ScannerMode) {
32
+ ScannerMode["auto"] = "auto";
33
+ ScannerMode["keyboard"] = "keyboard";
34
+ ScannerMode["camera"] = "camera";
35
+ return ScannerMode;
36
+ }({});
37
+
38
+ // 组件入参
39
+
40
+ // 同一个二维码实例标识
41
+
42
+ const Scanner = props => {
43
+ const _props$mode = props.mode,
44
+ mode = _props$mode === void 0 ? "auto" : _props$mode,
45
+ _props$enabled = props.enabled,
46
+ enabled = _props$enabled === void 0 ? true : _props$enabled,
47
+ _props$closeAfterScan = props.closeAfterScan,
48
+ closeAfterScan = _props$closeAfterScan === void 0 ? true : _props$closeAfterScan,
49
+ _props$keyboardInterv = props.keyboardInterval,
50
+ keyboardInterval = _props$keyboardInterv === void 0 ? 50 : _props$keyboardInterv,
51
+ _props$minLength = props.minLength,
52
+ minLength = _props$minLength === void 0 ? 1 : _props$minLength,
53
+ _props$showButton = props.showButton,
54
+ showButton = _props$showButton === void 0 ? true : _props$showButton,
55
+ _props$buttonText = props.buttonText,
56
+ buttonText = _props$buttonText === void 0 ? "扫一扫" : _props$buttonText,
57
+ _props$cameraTitle = props.cameraTitle,
58
+ cameraTitle = _props$cameraTitle === void 0 ? "扫描二维码" : _props$cameraTitle,
59
+ _props$scanerTip = props.scanerTip,
60
+ scanerTip = _props$scanerTip === void 0 ? "可通过扫码枪进行扫码录入" : _props$scanerTip,
61
+ _props$showScanArea = props.showScanArea,
62
+ showScanArea = _props$showScanArea === void 0 ? true : _props$showScanArea,
63
+ _props$continuous = props.continuous,
64
+ continuous = _props$continuous === void 0 ? false : _props$continuous,
65
+ onScan = props.onScan,
66
+ onError = props.onError,
67
+ onClose = props.onClose;
68
+ const actualMode = useMemo(() => mode === "auto" ? getDefaultScannerMode() : mode, [mode]); // 当前实际应用的扫码方式
69
+
70
+ const lastScanRef = useRef(null); // 防抖标识 避免摄像头连续识别同一个二维码,重复触发onScan
71
+ const videoRef = useRef(null); // 摄像头video DOM实例
72
+ const readerRef = useRef(null); // ZXing BrowserQRCodeReader扫描器实例
73
+ const controlsRef = useRef(null); // ZXing解码控制器,用于停止摄像头解码
74
+
75
+ const _useState = useState(false),
76
+ _useState2 = _slicedToArray(_useState, 2),
77
+ cameraOpen = _useState2[0],
78
+ setCameraOpen = _useState2[1]; // 摄像头是否开启
79
+ const _useState3 = useState(false),
80
+ _useState4 = _slicedToArray(_useState3, 2),
81
+ cameraLoading = _useState4[0],
82
+ setCameraLoading = _useState4[1]; // 摄像头进程是否加载中
83
+ const _useState5 = useState(""),
84
+ _useState6 = _slicedToArray(_useState5, 2),
85
+ cameraError = _useState6[0],
86
+ setCameraError = _useState6[1]; // 当前进程遇到的错误信息提示
87
+
88
+ // 释放摄像头资源
89
+ const releaseCameraResource = useCallback(() => {
90
+ try {
91
+ var _controlsRef$current;
92
+ // 停止ZXing解码器,停止帧循环解析
93
+ (_controlsRef$current = controlsRef.current) === null || _controlsRef$current === void 0 ? void 0 : _controlsRef$current.stop();
94
+ } catch {
95
+ // 停止解码器发生异常,卸载场景无需抛出,静默忽略
96
+ } finally {
97
+ // 无论stop是否抛错,强制关闭摄像头媒体流
98
+ const video = videoRef.current;
99
+ if (video !== null && video !== void 0 && video.srcObject) {
100
+ const stream = video.srcObject;
101
+ stream.getTracks().forEach(track => track.stop());
102
+ video.srcObject = null;
103
+ }
104
+ // 清空实例引用,释放内存
105
+ controlsRef.current = null;
106
+ readerRef.current = null;
107
+ }
108
+ }, []);
109
+
110
+ // 关闭扫码进程
111
+ const handleCloseCamera = useCallback(() => {
112
+ releaseCameraResource(); // 释放媒体资源
113
+ setCameraLoading(false);
114
+ setCameraOpen(false);
115
+ if (typeof onClose === "function") {
116
+ onClose();
117
+ }
118
+ }, [releaseCameraResource, onClose]);
119
+
120
+ // 统一处理扫码结果
121
+ const handleScan = useCallback(rawValue => {
122
+ const value = rawValue === null || rawValue === void 0 ? void 0 : rawValue.trim();
123
+ if (!value) {
124
+ return;
125
+ }
126
+
127
+ // 若1秒内重复识别同一个二维码则直接忽略
128
+ const now = Date.now();
129
+ if (lastScanRef !== null && lastScanRef !== void 0 && lastScanRef.current) {
130
+ const currentScanRef = lastScanRef.current;
131
+ if ((currentScanRef === null || currentScanRef === void 0 ? void 0 : currentScanRef.value) === value && now - (currentScanRef === null || currentScanRef === void 0 ? void 0 : currentScanRef.time) < 1000) {
132
+ return;
133
+ }
134
+ }
135
+ lastScanRef.current = {
136
+ value,
137
+ time: now
138
+ };
139
+ if (typeof onScan === "function") {
140
+ onScan(value);
141
+ }
142
+
143
+ // 摄像头模式下默认扫码成功就关闭
144
+ if (actualMode === "camera" && closeAfterScan && !continuous) {
145
+ handleCloseCamera();
146
+ }
147
+ }, [actualMode, closeAfterScan, continuous, onScan]);
148
+
149
+ // 启动摄像头扫码进程
150
+ const startCamera = useCallback(async () => {
151
+ var _navigator, _navigator$mediaDevic, _window;
152
+ // 总开关关闭则直接退出 不启动摄像头 如果正在 loading,直接返回,防止多次点击重复拉起摄像头
153
+ if (!enabled || cameraLoading) return;
154
+
155
+ // 校验浏览器是否具备媒体设备API,部分老旧浏览器无navigator.mediaDevices
156
+ if (!((_navigator = navigator) !== null && _navigator !== void 0 && (_navigator$mediaDevic = _navigator.mediaDevices) !== null && _navigator$mediaDevic !== void 0 && _navigator$mediaDevic.getUserMedia)) {
157
+ const error = new Error("当前浏览器不支持摄像头访问,请使用支持摄像头功能的浏览器。");
158
+ setCameraError(error.message);
159
+ onError === null || onError === void 0 ? void 0 : onError(error);
160
+ return;
161
+ }
162
+
163
+ // 浏览器安全上下文校验 getUserMedia仅允许https和localhost http环境会直接拒绝摄像头权限
164
+ if (!((_window = window) !== null && _window !== void 0 && _window.isSecureContext)) {
165
+ const error = new Error("摄像头功能需要HTTPS环境");
166
+ setCameraError(error.message);
167
+ onError === null || onError === void 0 ? void 0 : onError(error);
168
+ return;
169
+ }
170
+ // 重置上一次的错误信息,开启loading,打开摄像头弹窗
171
+ setCameraError("");
172
+ setCameraLoading(true);
173
+ setCameraOpen(true);
174
+ }, [enabled, handleScan, onError]);
175
+
176
+ // 监听弹窗打开,DOM渲染完成之后,初始化摄像头
177
+ useEffect(() => {
178
+ // 弹窗打开,loading=true,并且video已经挂载
179
+ const initCamera = async () => {
180
+ if (!cameraOpen || !cameraLoading || !videoRef.current) return;
181
+ try {
182
+ const reader = new BrowserQRCodeReader();
183
+ readerRef.current = reader;
184
+ const constraints = {
185
+ video: {
186
+ facingMode: {
187
+ ideal: "environment"
188
+ },
189
+ width: {
190
+ ideal: 1280
191
+ },
192
+ height: {
193
+ ideal: 720
194
+ }
195
+ },
196
+ audio: false
197
+ };
198
+ const controls = await (reader === null || reader === void 0 ? void 0 : reader.decodeFromConstraints(constraints, videoRef.current, result => {
199
+ // result为空 代表当前帧未识别到二维码,直接跳过
200
+ if (!result) return;
201
+ // 获取二维码原始文本,交给统一扫码结果处理器
202
+ const value = result === null || result === void 0 ? void 0 : result.getText();
203
+ handleScan(value);
204
+ }));
205
+ controlsRef.current = controls;
206
+ } catch (error) {
207
+ let message = "摄像头启动失败,请检查浏览器摄像头权限。";
208
+ if (error instanceof DOMException) {
209
+ switch (error.name) {
210
+ case "NotAllowedError":
211
+ message = "摄像头权限被拒绝,请在浏览器设置中允许访问摄像头。";
212
+ break;
213
+ case "NotFoundError":
214
+ message = "未找到可用的摄像头设备。";
215
+ break;
216
+ case "NotReadableError":
217
+ message = "摄像头正在被其他应用占用,请关闭其他使用摄像头的程序后重试。";
218
+ break;
219
+ case "SecurityError":
220
+ message = "浏览器安全策略禁止访问摄像头,请检查 HTTPS 配置。";
221
+ break;
222
+ default:
223
+ message = (error === null || error === void 0 ? void 0 : error.message) || message;
224
+ }
225
+ }
226
+ setCameraError(message);
227
+ onError === null || onError === void 0 ? void 0 : onError(error instanceof Error ? error : new Error(message));
228
+ } finally {
229
+ setCameraLoading(false);
230
+ }
231
+ };
232
+ initCamera();
233
+ }, [cameraOpen, cameraLoading, handleScan, onError]);
234
+
235
+ // 组件卸载时释放摄像头资源
236
+ useEffect(() => {
237
+ return () => {
238
+ releaseCameraResource();
239
+ };
240
+ }, [releaseCameraResource]);
241
+
242
+ // 根据传入参数的可用状态执行关闭进程操作
243
+ useEffect(() => {
244
+ if (!enabled && cameraOpen) {
245
+ handleCloseCamera();
246
+ }
247
+ }, [enabled, cameraOpen, handleCloseCamera]);
248
+
249
+ // 调用自定义hook 触发扫码枪扫描逻辑
250
+ useKeyboardScanner({
251
+ enabled: enabled && actualMode === "keyboard" && !cameraOpen,
252
+ minLength,
253
+ maxInterval: keyboardInterval,
254
+ onScan: handleScan
255
+ });
256
+ return /*#__PURE__*/React.createElement(React.Fragment, null, showButton && /*#__PURE__*/React.createElement(React.Fragment, null, actualMode === "camera" ? /*#__PURE__*/React.createElement(ButtonPermission, {
257
+ icon: "icon-saoyisao",
258
+ disabled: !enabled,
259
+ funcType: "raised",
260
+ onClick: startCamera
261
+ }, buttonText) : /*#__PURE__*/React.createElement(ButtonPermission, {
262
+ className: styles.scanTip,
263
+ funcType: "link",
264
+ color: "red"
265
+ }, scanerTip)), actualMode === "camera" && cameraOpen && /*#__PURE__*/React.createElement("div", {
266
+ className: styles.mask,
267
+ role: "dialog"
268
+ }, /*#__PURE__*/React.createElement("div", {
269
+ className: styles.modal
270
+ }, /*#__PURE__*/React.createElement("div", {
271
+ className: styles.header
272
+ }, /*#__PURE__*/React.createElement("span", {
273
+ className: styles.title
274
+ }, cameraTitle), /*#__PURE__*/React.createElement("button", {
275
+ type: "button",
276
+ className: styles.close,
277
+ onClick: handleCloseCamera
278
+ }, "\xD7")), /*#__PURE__*/React.createElement("div", {
279
+ className: styles.camera
280
+ }, /*#__PURE__*/React.createElement("video", {
281
+ ref: videoRef,
282
+ className: styles.video,
283
+ autoPlay: true,
284
+ muted: true,
285
+ playsInline: true
286
+ }), showScanArea && /*#__PURE__*/React.createElement("div", {
287
+ className: styles.area
288
+ }, /*#__PURE__*/React.createElement("div", {
289
+ className: classNames(styles.corner, styles.topLeft)
290
+ }), /*#__PURE__*/React.createElement("div", {
291
+ className: classNames(styles.corner, styles.topRight)
292
+ }), /*#__PURE__*/React.createElement("div", {
293
+ className: classNames(styles.corner, styles.bottomLeft)
294
+ }), /*#__PURE__*/React.createElement("div", {
295
+ className: classNames(styles.corner, styles.bottomRight)
296
+ }), /*#__PURE__*/React.createElement("div", {
297
+ className: styles.line
298
+ })), cameraLoading && /*#__PURE__*/React.createElement("div", {
299
+ className: styles.loading
300
+ }, "\u6B63\u5728\u542F\u52A8\u6444\u50CF\u5934..."), cameraError && /*#__PURE__*/React.createElement("div", {
301
+ className: styles.error
302
+ }, /*#__PURE__*/React.createElement("div", {
303
+ className: styles.errorText
304
+ }, cameraError), /*#__PURE__*/React.createElement("button", {
305
+ type: "button",
306
+ className: styles.retry,
307
+ onClick: startCamera
308
+ }, "\u91CD\u8BD5"))), /*#__PURE__*/React.createElement("div", {
309
+ className: styles.footer
310
+ }, /*#__PURE__*/React.createElement("span", {
311
+ className: styles.tip
312
+ }, "\u8BF7\u5C06\u4E8C\u7EF4\u7801\u653E\u5165\u626B\u63CF\u6846\u5185"), /*#__PURE__*/React.createElement("button", {
313
+ type: "button",
314
+ className: styles.cancel,
315
+ onClick: handleCloseCamera
316
+ }, "\u53D6\u6D88")))));
317
+ };
318
+ export default Scanner;
@@ -0,0 +1,264 @@
1
+ // 扫码组件样式
2
+ .scanTip {
3
+ font-size: @smallFont;
4
+ color: @errorColor;
5
+ pointer-events: none;
6
+ }
7
+ /** 遮罩层 */
8
+ .mask {
9
+ z-index: 9999;
10
+ .position(fixed, 0, 0, 0, 0);
11
+ .flex;
12
+ padding: 0.2rem;
13
+ background-color: rgba(0, 0, 0, 0.75);
14
+ }
15
+
16
+ /** 扫码框弹窗 */
17
+ .modal {
18
+ position: relative;
19
+ overflow: hidden;
20
+ .flex(column, stretch, stretch);
21
+ width: 7.2rem;
22
+ max-height: 90vh;
23
+ border-radius: 0.08rem;
24
+ background-color: black;
25
+ }
26
+
27
+ /* =========================
28
+ * 顶部
29
+ * ========================= */
30
+
31
+ .header {
32
+ .flex(@justify: space-between);
33
+ height: 0.52rem;
34
+ flex-shrink: 0;
35
+ padding: 0 0.16rem;
36
+ color: @white;
37
+ background-color: @primaryWord;
38
+ }
39
+
40
+ .title {
41
+ font-size: 0.16rem;
42
+ font-weight: 500;
43
+ }
44
+
45
+ .close {
46
+ .flex;
47
+ width: 0.32rem;
48
+ height: 0.32rem;
49
+ line-height: 1;
50
+ padding: 0;
51
+ font-size: @hugeFont;
52
+ border: none;
53
+ color: @white;
54
+ background-color: transparent;
55
+ cursor: pointer;
56
+ transition: opacity 0.2s ease;
57
+ &:hover {
58
+ opacity: 0.7;
59
+ }
60
+ }
61
+
62
+ /* =========================
63
+ * 摄像头
64
+ * ========================= */
65
+
66
+ .camera {
67
+ overflow: hidden;
68
+ position: relative;
69
+ width: 100%;
70
+ aspect-ratio: 16 / 9;
71
+ background: black;
72
+ }
73
+
74
+ .video {
75
+ display: block;
76
+ width: 100%;
77
+ height: 100%;
78
+ object-fit: cover;
79
+ }
80
+
81
+ /* =========================
82
+ * 扫描框
83
+ * ========================= */
84
+
85
+ .area {
86
+ .position(absolute, 50%, @left: 50%);
87
+ width: 60%;
88
+ max-width: 3.6rem;
89
+ aspect-ratio: 1;
90
+ transform: translate(-50%, -50%);
91
+ }
92
+
93
+ .corner {
94
+ position: absolute;
95
+ width: 0.3rem;
96
+ height: 0.3rem;
97
+ border-color: @white;
98
+ border-style: solid;
99
+ }
100
+
101
+ .topLeft {
102
+ top: 0;
103
+ left: 0;
104
+ border-width: 0.03rem 0 0 0.03rem;
105
+ }
106
+
107
+ .topRight {
108
+ top: 0;
109
+ right: 0;
110
+ border-width: 0.03rem 0.03rem 0 0;
111
+ }
112
+
113
+ .bottomLeft {
114
+ bottom: 0;
115
+ left: 0;
116
+ border-width: 0 0 0.03rem 0.03rem;
117
+ }
118
+
119
+ .bottomRight {
120
+ right: 0;
121
+ bottom: 0;
122
+ border-width: 0 0.03rem 0.03rem 0;
123
+ }
124
+
125
+ .line {
126
+ .position(absolute, 0, @left: 0);
127
+ width: 100%;
128
+ height: 0.02rem;
129
+ background: @primaryColor;
130
+ box-shadow: 0 0 0.08rem rgba(@primaryColor, 0.8);
131
+ animation: scan 2s linear infinite;
132
+ }
133
+
134
+ @keyframes scan {
135
+ 0% {
136
+ top: 0;
137
+ }
138
+
139
+ 50% {
140
+ top: calc(100% - 0.02rem);
141
+ }
142
+
143
+ 100% {
144
+ top: 0;
145
+ }
146
+ }
147
+
148
+ /* =========================
149
+ * Loading
150
+ * ========================= */
151
+
152
+ .loading {
153
+ .position(absolute, 50%, @left: 50%);
154
+ padding: 0.12rem 0.2rem;
155
+ color: @white;
156
+ font-size: @fontSize;
157
+ border-radius: 0.04rem;
158
+ background-color: rgba(0, 0, 0, 0.65);
159
+ transform: translate(-50%, -50%);
160
+ }
161
+
162
+ /* =========================
163
+ * 错误
164
+ * ========================= */
165
+
166
+ .error {
167
+ .position(absolute, 50%, @left: 50%);
168
+ width: 80%;
169
+ box-sizing: border-box;
170
+ padding: 0.2rem;
171
+ border-radius: 0.06rem;
172
+ transform: translate(-50%, -50%);
173
+ text-align: center;
174
+ color: @white;
175
+ background-color: rgba(0, 0, 0, 0.82);
176
+ }
177
+
178
+ .errorText {
179
+ font-size: @fontSize;
180
+ line-height: 1.6;
181
+ }
182
+
183
+ .retry {
184
+ height: 0.36rem;
185
+ margin-top: 0.16rem;
186
+ padding: 0 0.2rem;
187
+ font-size: @fontSize;
188
+ color: @white;
189
+ background-color: @primaryColor;
190
+ border: none;
191
+ border-radius: 0.04rem;
192
+ cursor: pointer;
193
+ &:hover {
194
+ background: @hoverPrimaryColor;
195
+ }
196
+ }
197
+
198
+ /* =========================
199
+ * 底部
200
+ * ========================= */
201
+
202
+ .footer {
203
+ .flex(@justify: space-between);
204
+ gap: 0.16rem;
205
+ box-sizing: border-box;
206
+ min-height: 0.64rem;
207
+ padding: 0.12rem 0.16rem;
208
+ font-size: @fontSize;
209
+ color: @white;
210
+ background-color: @primaryWord;
211
+ }
212
+
213
+ .tip {
214
+ color: @lightWord;
215
+ }
216
+
217
+ .cancel {
218
+ height: 0.36rem;
219
+ flex-shrink: 0;
220
+ padding: 0 0.2rem;
221
+ border: 0.01rem solid @minorWord;
222
+ font-size: @fontSize;
223
+ color: @white;
224
+ background-color: @labelWord;
225
+ border-radius: 0.04rem;
226
+ cursor: pointer;
227
+ &:hover {
228
+ background-color: @minorWord;
229
+ }
230
+ }
231
+
232
+ /* =========================
233
+ * Pad
234
+ * ========================= */
235
+
236
+ @media (max-width: 7.68rem) {
237
+ .mask {
238
+ align-items: stretch;
239
+ padding: 0;
240
+ }
241
+
242
+ .modal {
243
+ width: 100%;
244
+ height: 100%;
245
+ max-height: none;
246
+ border-radius: 0;
247
+ }
248
+
249
+ .camera {
250
+ flex: 1;
251
+ aspect-ratio: auto;
252
+ }
253
+
254
+ .area {
255
+ width: 70%;
256
+ }
257
+
258
+ .footer {
259
+ padding-bottom: max(
260
+ 0.12rem,
261
+ env(safe-area-inset-bottom)
262
+ );
263
+ }
264
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isMobileDevice(): boolean;
2
+ export declare function getDefaultScannerMode(): "keyboard" | "camera";
@@ -0,0 +1,18 @@
1
+ // 判断当前是否为移动端设备
2
+ export function isMobileDevice() {
3
+ var _navigator, _navigator2, _navigator3;
4
+ if (typeof navigator === "undefined") {
5
+ return false;
6
+ }
7
+ const userAgent = ((_navigator = navigator) === null || _navigator === void 0 ? void 0 : _navigator.userAgent) || "";
8
+
9
+ // iPadOS 13+ 有可能伪装成 Mac 通过MacIntel来识别
10
+ const isIPad = /iPad/i.test(userAgent) || ((_navigator2 = navigator) === null || _navigator2 === void 0 ? void 0 : _navigator2.platform) === "MacIntel" && ((_navigator3 = navigator) === null || _navigator3 === void 0 ? void 0 : _navigator3.maxTouchPoints) > 1;
11
+ const isMobile = /Android|iPhone|iPod|Windows Phone|Mobile/i.test(userAgent);
12
+ return isIPad || isMobile;
13
+ }
14
+
15
+ // 获取当前默认使用的扫码类别 keyboard为扫码枪 camera为调用摄像头
16
+ export function getDefaultScannerMode() {
17
+ return isMobileDevice() ? "camera" : "keyboard";
18
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @name 状态标签页组件
3
+ * @param {IStatusTabProps} props 组件属性
4
+ * @param {string} lookupCode 状态枚举值
5
+ * @param {string} currentStatus 当前状态
6
+ * @param {function} onChange 状态切换回调
7
+ * @author chuzhengyang
8
+ */
9
+ import React from "react";
10
+ export declare const organizationId: any;
11
+ interface IStatusItem {
12
+ /** 排序标识 */
13
+ orderSeq: number;
14
+ /** 枚举中文表述 */
15
+ meaning: string;
16
+ /** 枚举值 */
17
+ value: string;
18
+ /** 可用标识 */
19
+ enabledFlag: number;
20
+ /** 数量 */
21
+ count?: number;
22
+ }
23
+ interface IStatusTabProps {
24
+ /** 状态枚举值,与 statusList 互斥 */
25
+ lookupCode?: string;
26
+ /** 直接传入状态列表,与 lookupCode 互斥 */
27
+ statusList?: IStatusItem[];
28
+ /** 当前状态 */
29
+ currentStatus: string;
30
+ /** 查询数量url */
31
+ queryCountUrl?: string;
32
+ /** 状态切换回调 */
33
+ onChange: (key: string) => void;
34
+ }
35
+ declare const StatusTab: React.FC<IStatusTabProps>;
36
+ export default StatusTab;