@cloudbase/framework-plugin-low-code 0.6.30 → 0.6.33

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 (82) hide show
  1. package/lib/builder/config/index.js +2 -5
  2. package/lib/builder/core/copy.d.ts.map +1 -1
  3. package/lib/builder/mp/materials.d.ts.map +1 -1
  4. package/lib/builder/mp/materials.js +21 -5
  5. package/package.json +5 -3
  6. package/template/src/handlers/FieldMiddleware/renderer.jsx +11 -6
  7. package/template/src/handlers/actionHandler/utils.js +41 -17
  8. package/template/webpack/web.prod.js +65 -85
  9. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/cookie.js +0 -286
  10. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/history.js +0 -133
  11. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/local-storage.js +0 -103
  12. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/location.js +0 -588
  13. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/miniprogram.js +0 -101
  14. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/navigator.js +0 -80
  15. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/performance.js +0 -28
  16. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/screen.js +0 -31
  17. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/session-storage.js +0 -96
  18. package/template/dist/mp/miniprogram_npm/miniprogram-render/bom/xml-http-request.js +0 -290
  19. package/template/dist/mp/miniprogram_npm/miniprogram-render/document.js +0 -396
  20. package/template/dist/mp/miniprogram_npm/miniprogram-render/event/custom-event.js +0 -12
  21. package/template/dist/mp/miniprogram_npm/miniprogram-render/event/event-target.js +0 -389
  22. package/template/dist/mp/miniprogram_npm/miniprogram-render/event/event.js +0 -186
  23. package/template/dist/mp/miniprogram_npm/miniprogram-render/index.js +0 -41
  24. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/attribute.js +0 -226
  25. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/class-list.js +0 -153
  26. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/comment.js +0 -80
  27. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/a.js +0 -165
  28. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/canvas.js +0 -138
  29. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/image.js +0 -177
  30. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/input.js +0 -181
  31. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/not-support.js +0 -60
  32. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/option.js +0 -126
  33. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/select.js +0 -155
  34. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/textarea.js +0 -178
  35. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/video.js +0 -165
  36. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/wx-component.js +0 -84
  37. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element/wx-custom-component.js +0 -64
  38. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/element.js +0 -970
  39. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/node.js +0 -140
  40. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/style-list.js +0 -28
  41. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/style.js +0 -158
  42. package/template/dist/mp/miniprogram_npm/miniprogram-render/node/text-node.js +0 -127
  43. package/template/dist/mp/miniprogram_npm/miniprogram-render/tree/parser.js +0 -269
  44. package/template/dist/mp/miniprogram_npm/miniprogram-render/tree/query-selector.js +0 -420
  45. package/template/dist/mp/miniprogram_npm/miniprogram-render/tree/tree.js +0 -130
  46. package/template/dist/mp/miniprogram_npm/miniprogram-render/util/cache.js +0 -95
  47. package/template/dist/mp/miniprogram_npm/miniprogram-render/util/pool.js +0 -24
  48. package/template/dist/mp/miniprogram_npm/miniprogram-render/util/tool.js +0 -131
  49. package/template/dist/mp/miniprogram_npm/miniprogram-render/window.js +0 -651
  50. package/template/generator/app/common.js +0 -17
  51. package/template/generator/app/global-api.js +0 -163
  52. package/template/generator/app/handlers.js +0 -13
  53. package/template/generator/datasources/config.js.tpl +0 -21
  54. package/template/generator/datasources/dataset-profiles.js.tpl +0 -5
  55. package/template/generator/datasources/datasource-profiles.js.tpl +0 -4
  56. package/template/generator/datasources/index.js.tpl +0 -14
  57. package/template/generator/handlers/NodeRenderer.jsx +0 -471
  58. package/template/generator/handlers/RenderWrapper.jsx +0 -145
  59. package/template/generator/index.jsx +0 -116
  60. package/template/generator/index.less +0 -120
  61. package/template/generator/pages/app.tpl +0 -181
  62. package/template/generator/pages/composite.tpl +0 -267
  63. package/template/generator/router/index.tpl +0 -49
  64. package/template/generator/store/computed.js +0 -11
  65. package/template/generator/store/index.js +0 -5
  66. package/template/generator/utils/ScanCodeComponent.js +0 -345
  67. package/template/generator/utils/actionHandler.js +0 -119
  68. package/template/generator/utils/common.js +0 -225
  69. package/template/generator/utils/computed.js +0 -9
  70. package/template/generator/utils/date.js +0 -324
  71. package/template/generator/utils/error.jsx +0 -14
  72. package/template/generator/utils/eventProxy.js +0 -64
  73. package/template/generator/utils/history.js +0 -35
  74. package/template/generator/utils/hooks.js +0 -10
  75. package/template/generator/utils/index.js +0 -41
  76. package/template/generator/utils/initGlobalVar.js +0 -14
  77. package/template/generator/utils/lifecycle.js +0 -158
  78. package/template/generator/utils/monitor-jssdk.min.js +0 -881
  79. package/template/generator/utils/page.js +0 -10
  80. package/template/generator/utils/scan-code-action.js +0 -27
  81. package/template/generator/utils/style.js +0 -81
  82. package/template/generator/utils/widgets.js +0 -343
@@ -1,267 +0,0 @@
1
- import * as React from "react";
2
- import { observer } from "mobx-react-lite";
3
- import { observable, autorun, reaction, runInAction } from "mobx";
4
- import { AppRender } from "/src/handlers/RenderWrapper";
5
- import { createWidgets, retryDataBinds, WidgetsContext, bindFuncObj, createComputed, resolveComponentProps} from '/src/utils/index'
6
- import getStateFn from "./lowcode/state.js";
7
- import computed from "./lowcode/computed.js";
8
- import lifecycle from "./lowcode/lifecycle.js";
9
- // import i18n from '@tcwd/weapps-sdk/lib/i18n'
10
- <% if(isSandbox) { %>
11
- import { ErrorBoundary } from 'react-error-boundary'
12
- import { createErrorFallback } from '/src/utils/error'
13
- <% } %>
14
- import componentAPI from './lowcode/index';
15
- import get from 'lodash.get'
16
-
17
- <% handlersImports.forEach(handler => { %>
18
- import handler$<%= handler.name %> from "./lowcode/handler/<%= handler.name %>.js";
19
- <% }) %>
20
-
21
- // Import Components outof sandbox
22
- <% useComponents.forEach(compItem => {%>
23
- <% if(!isSandbox && compItem.isComposite){ %>
24
- import <%= compItem.var %> from "/src/libraries/<%= compItem.moduleName %>@<%= compItem.version %>/components/<%= compItem.name %>";
25
- <% } else if(!isSandbox) { %>
26
- const <%= compItem.var %> = window["@weapps-materials-main-<%= compItem.moduleName %>"].components["<%= compItem.name %>"];
27
- <% } %>
28
- <%}) %>
29
-
30
- import * as constObj from '../../libCommonRes/const'
31
- import * as toolsObj from '../../libCommonRes/tools'
32
-
33
- import "./lowcode/style.css";
34
-
35
- const libCode = '<%= materialName %>'
36
-
37
- class CompositeCompWrapper extends React.Component {
38
-
39
- $WEAPPS_COMP = {}
40
-
41
- componentDidUpdate() {
42
- runInAction(() => {
43
- const { data } = this.props
44
- for(let prop in data) {
45
- // 更新 propsData
46
- if (typeof data[prop] !== 'function') {
47
- this.propsData[prop] = data[prop]
48
- }
49
- }
50
- })
51
- }
52
-
53
-
54
- constructor(props) {
55
- super(props);
56
-
57
- this.compConfig = <%= JSON.stringify(compConfig, null, 2) %>
58
-
59
- // Import Components in sandbox
60
- <% useComponents.forEach(compItem => {%>
61
- <% if(isSandbox){ %>
62
- const <%= compItem.var %> = window["@weapps-materials-main-<%= compItem.moduleName %>"].components["<%= compItem.name %>"];
63
- <% } %>
64
- <%}) %>
65
-
66
- this.virtualFields = Object.assign({}, props.pageVirtualFields || {}, {
67
- <% useComponents.forEach(compItem => {%>
68
- "<%= compItem.key %>": <% if(compItem.isPlainProps) {%> (props) => <<%= compItem.var %> {...resolveComponentProps(props, 1)} /> <% } else {%> (props) => <<%= compItem.var %>{...resolveComponentProps(props, 0)} /> <% }%>,
69
- <%}) %>
70
- });
71
-
72
- // 挂载给到 $comp.props.events 使用
73
- this.events = (<%= emitEvents %>).reduce((obj, trigger) => {
74
- obj[trigger] = (eventData, domEvent) => {
75
- this.props.emit(trigger, eventData, domEvent);
76
- this.node._listeners && this.node._listeners.emit(trigger, eventData, domEvent)
77
- };
78
- return obj;
79
- }, {});
80
- this.handler = this.$WEAPPS_COMP.handler = {
81
- <% handlersImports.forEach(handler => { %>
82
- <%= handler.name %>: handler$<%= handler.name %>.bind(this),
83
- <% }) %>
84
- };
85
- const widgetContext = <%= widgets %>
86
- const dataBinds = this._dataBinds = <%= dataBinds %>
87
- this.componentSchema = <%= componentSchema %>;
88
-
89
- const defaultProps = <%= JSON.stringify(defaultProps, null, 2) %>
90
- this.propsData = observable(Object.assign({}, defaultProps, this.props.data || {}))
91
- this.$WEAPPS_COMP.lib = { const: constObj, tools: toolsObj }
92
- /*
93
- this.i18n = this.$WEAPPS_COMP.i18n = {
94
- ...i18n,
95
- t (key, data) {
96
- return i18n.t(libCode + ':' + key, data)
97
- },
98
- }
99
- */
100
- this.$WEAPPS_COMP.props = { ...this.props, events: this.events, data: this.propsData }
101
-
102
- this.state = this.$WEAPPS_COMP.state = observable(getStateFn.bind(this)())
103
- this.computed = this.$WEAPPS_COMP.computed = createComputed(computed, this)
104
- this.node = this.$WEAPPS_COMP.node = this.createWidgetNode(this) || {}
105
- this.initPublicMethods()
106
-
107
- this.widgets = this.$WEAPPS_COMP.widgets = createWidgets(widgetContext, dataBinds)
108
- // widgets 内的 dataBinds 可能需要关联 widgets,需要重新执行 dataBinds
109
- retryDataBinds()
110
- Object.keys(this.widgets || {}).forEach(widgetId => {
111
- // 将实例 ownerWidget 挂到内部组件上。内部组件就可以通过 $comp.node.ownerWidget 获取到所在的组件实例
112
- const node = this.widgets[widgetId]
113
- if (Array.isArray(node)) {
114
- node.forEach(item => {
115
- item.ownerWidget = this.node;
116
- item.getOwnerWidget = () => this.node;
117
- })
118
- }
119
- else {
120
- node.ownerWidget = this.node
121
- node.getOwnerWidget = () => this.node
122
- }
123
- // this.widgets[widgetId].ownerWidget = this.node
124
- // this.widgets[widgetId].getOwnerWidget = () => this.node
125
- })
126
-
127
- this.pageListenerInstances = [];
128
- this.createCompAPI(this)
129
- }
130
-
131
- // publicMthods 挂载内部,使用 $comp.api。挂载到外部使用 $comp.node.api
132
- initPublicMethods() {
133
- const publicMethods = componentAPI.publicMethods || {}
134
- Object.keys(publicMethods).map(fnName => {
135
- const bindFunc = publicMethods[fnName].bind(this)
136
- this[fnName] = bindFunc
137
- this.$WEAPPS_COMP[fnName] = bindFunc
138
- if(this.node) this.node[fnName] = bindFunc
139
- })
140
- }
141
-
142
- // 创建自身节点
143
- createWidgetNode(compThis) {
144
- // 当为数组时,需要判断自己属于 widgets 的哪一项
145
- const {
146
- compositeParent,
147
- forIndexes,
148
- id
149
- } = compThis.props
150
- let widgetData = compositeParent.$WEAPPS_COMP
151
- ? compositeParent.$WEAPPS_COMP.widgets[id]
152
- : compositeParent.$page.widgets[id]
153
- if(Array.isArray(widgetData)) {
154
- widgetData = widgetData.length > 0 ? get(widgetData, forIndexes) : {}
155
- }
156
- widgetData = widgetData || {}
157
- Object.assign(widgetData, {
158
- getConfig: () => compThis.compConfig,
159
- }, bindFuncObj(componentAPI.publicMethods || {}, compThis)
160
- )
161
-
162
- return widgetData
163
- }
164
-
165
- createCompAPI(compThis) {
166
- compThis.$WEAPPS_COMP = {
167
- _dataBinds: compThis._dataBinds,
168
- compConfig: compThis.compConfig,
169
- widgets: compThis.widgets,
170
- node: compThis.node,
171
- handler: compThis.handler,
172
- lib: { const: constObj, tools: toolsObj },
173
- // i18n: compThis.i18n,
174
- get props() {
175
- return {...compThis.props, events: compThis.events, data: compThis.propsData }
176
- },
177
- get state() {
178
- return compThis.state
179
- },
180
- get computed() {
181
- return compThis.computed
182
- },
183
- };
184
- }
185
-
186
- initWatchMethods() {
187
- const { watch = {}, watchState = {}, watchWidget = {}, watchEffects = {}} = componentAPI
188
- const _this = this
189
- const weappInst = _this.$WEAPPS_COMP
190
-
191
- // # watch effect
192
- this.watchEffectDisposers = Object.keys(watchEffects).map(fnName => {
193
- return autorun(watchEffects[fnName].bind(this))
194
- })
195
- const disposers = this.watchEffectDisposers
196
-
197
- // # watch props
198
- Object.keys(watch).map(key => runWatcher(parseWatcher(watch[key]), weappInst.props.data, key, 'watch'))
199
-
200
- // # watch state
201
- Object.keys(watchState).map(key => runWatcher(parseWatcher(watchState[key]), weappInst.state, key, 'watchState'))
202
-
203
- // # watch widgets
204
- Object.keys(watchWidget).map(key => runWatcher(parseWatcher(watchWidget[key]), weappInst.widgets, key, 'watchWidgets'))
205
-
206
- function runWatcher({ handler, immediate } = {}, target, key, label) {
207
- if (!handler) {
208
- console.error(`Invalid ${label}(${key}) of ${weappInst.node.widgetType}, watch must a function or {handler: function}`)
209
- return
210
- }
211
- const disposer = reaction(() => get(target, key), handler.bind(_this), { fireImmediately: immediate })
212
- disposers.push(disposer)
213
- }
214
- }
215
-
216
- componentDidMount() {
217
- this.initPublicMethods()
218
- this.initWatchMethods()
219
-
220
- lifecycle.onAttached && lifecycle.onAttached.bind(this)()
221
- lifecycle.onReady && lifecycle.onReady.bind(this)()
222
- }
223
-
224
- componentWillUnmount() {
225
- if(this.watchEffectDisposers) {
226
- this.watchEffectDisposers.forEach(disposer => disposer())
227
- this.watchEffectDisposers = null
228
- }
229
- this.node._listeners && this.node._listeners.clear()
230
- lifecycle.onDetached && lifecycle.onDetached.bind(this)()
231
- }
232
-
233
- render() {
234
- return (
235
- <WidgetsContext.Provider value={{ parent: this }}>
236
- <AppRender
237
- className={this.props.className}
238
- virtualFields={this.virtualFields}
239
- componentSchema={this.componentSchema}
240
- codeContext={this}
241
- />
242
- </WidgetsContext.Provider>
243
- );
244
- }
245
- }
246
-
247
- CompositeCompWrapper.contextType = WidgetsContext
248
-
249
- export default observer((props) => (
250
- <% if(isSandbox) { %>
251
- <ErrorBoundary FallbackComponent={createErrorFallback('<%= name %>', '<%= id %>')}>
252
- <% } %>
253
- <CompositeCompWrapper {...props}></CompositeCompWrapper>
254
- <% if(isSandbox) { %>
255
- </ErrorBoundary>
256
- <% } %>
257
- ));
258
-
259
- function parseWatcher(watcher) {
260
- if (!watcher) return
261
- if (watcher instanceof Function) {
262
- return { handler: watcher, immediate: false }
263
- }
264
- const { handler, immediate = false } = watcher
265
- if (!(handler instanceof Function)) return
266
- return { handler, immediate }
267
- }
@@ -1,49 +0,0 @@
1
- import * as React from 'react';
2
- import { BrowserRouter, Router, Route, Redirect, Switch, HashRouter } from 'react-router-dom';
3
- import { history, generateBrowserHistory, createHistory } from '../utils/index';
4
- import { wx } from '@tcwd/weapps-sdk'
5
-
6
- <%= mountApis %>
7
- <%= routerImports %>
8
-
9
- import lifecycle from '../lowcode/lifecycle'
10
- function NotFound() {
11
- lifecycle.onAppPageNotFound && lifecycle.onAppPageNotFound()
12
- console.error('页面 404,可以在生命周期配置 onAppPageNotFound 并跳转到对应页面')
13
- return <>页面404</>
14
- }
15
- function Loading() {
16
- React.useEffect(() => {
17
- wx.showLoading()
18
- return () => wx.hideLoading()
19
- }, [])
20
- return <></>
21
- }
22
- export default () => {
23
- window.$$global.homePageId = '<%= homePageId %>'
24
- // 显式声明HASH 或 app 的 路由使用 hash router,而其他web应用使用 BrowserRouter
25
- if (process.env.isApp || process.env.isAdminPortal || <%= isHash %>) {
26
- return (
27
- <Router history={history}>
28
- <React.Suspense fallback={<Loading/>}>
29
- <Switch>
30
- <%= routerRenders %>
31
- <Route component={NotFound} />
32
- </Switch>
33
- </React.Suspense>
34
- </Router>
35
- )
36
- } else {
37
- return (
38
- <Router history={generateBrowserHistory({basename: "<%= basename %>"})}>
39
- <React.Suspense fallback={<Loading/>}>
40
- <Switch>
41
- <%= routerRenders %>
42
- <Route component={NotFound} />
43
- </Switch>
44
- </React.Suspense>
45
- </Router>
46
- )
47
- }
48
-
49
- }
@@ -1,11 +0,0 @@
1
- // import all state of all pages & global
2
- import globalComputed from '../lowcode/computed'
3
- <% pageIds.forEach(function(pageId) { %>import <%= pageId %>Computed from '../lowcode/<%= pageId%>/computed';
4
- <% }); %>
5
-
6
- const computed = {
7
- global: globalComputed,<% pageIds.forEach(function(pageId) { %>
8
- <%= pageId %>: <%= pageId %>Computed,<% }); %>
9
- };
10
-
11
- export default computed;
@@ -1,5 +0,0 @@
1
- import { observable } from 'mobx';
2
- import initState from '../lowcode/state';
3
-
4
- const globalState = observable(initState);
5
- export default globalState;
@@ -1,345 +0,0 @@
1
- import React, { useMemo, useRef, useEffect, useImperativeHandle, useState, useCallback } from 'react';
2
- import ReactDOM from 'react-dom';
3
-
4
- import { BrowserMultiFormatReader, NotFoundException, BarcodeFormat, DecodeHintType } from '@zxing/library';
5
- import { app } from '../app/global-api';
6
-
7
-
8
- export const FORMAT = {
9
- 0: { scanType: 'AZTEC', wxtype: null },
10
- 1: { scanType: 'CODABAR', wxtype: 'barCode' },
11
- 2: { scanType: 'CODE_39', wxtype: 'barCode' },
12
- 3: { scanType: 'CODE_93', wxtype: 'barCode' },
13
- 4: { scanType: 'CODE_128', wxtype: 'barCode' },
14
- 5: { scanType: 'DATA_MATRIX', wxtype: 'qrCode' },
15
- 6: { scanType: 'EAN_8', wxtype: 'barCode' },
16
- 7: { scanType: 'EAN_13', wxtype: 'barCode' },
17
- 8: { scanType: 'ITF', wxtype: 'barCode' },
18
- 9: { scanType: 'MAXICODE', wxtype: null },
19
- 10: { scanType: 'PDF_417', wxtype: 'qrCode' },
20
- 11: { scanType: 'QR_CODE', wxtype: 'qrCode' },
21
- 12: { scanType: 'RSS_14', wxtype: 'barCode' },
22
- 13: { scanType: 'RSS_EXPANDED', wxtype: 'barCode' },
23
- 14: { scanType: 'UPC_A', wxtype: 'barCode' },
24
- 15: { scanType: 'UPC_E', wxtype: 'barCode' },
25
- 16: { scanType: 'UPC_EAN_EXTENSION', wxtype: 'barCode' },
26
- };
27
-
28
- const hints = new Map();
29
- const formats = [
30
- BarcodeFormat.QR_CODE,
31
- BarcodeFormat.UPC_A,
32
- BarcodeFormat.UPC_E,
33
- BarcodeFormat.EAN_8,
34
- BarcodeFormat.EAN_13,
35
- BarcodeFormat.CODE_39,
36
- BarcodeFormat.CODE_93,
37
- BarcodeFormat.CODE_128,
38
- BarcodeFormat.DATA_MATRIX,
39
- BarcodeFormat.PDF_417,
40
- ];
41
- hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
42
-
43
- const Codescanner = React.forwardRef(({ events = {}, closeScanCode, scanType, onInit }, fref) => {
44
- const ref = useRef();
45
- const {
46
- fail = () => {},
47
- success = () => {},
48
- complete = () => {},
49
- } = events;
50
-
51
- const inited = useRef(false);
52
- const codeReader = new BrowserMultiFormatReader(hints);
53
- const start = async () => {
54
- setTimeout(() => {
55
- // try harder after 5 sceonds
56
- hints.set(DecodeHintType.TRY_HARDER, true);
57
- codeReader.timeBetweenDecodingAttempts = 1500;
58
- codeReader.hints = hints;
59
- }, 5000);
60
- const devices = await codeReader.listVideoInputDevices();
61
-
62
- if (devices.length) {
63
- try {
64
- await codeReader.decodeFromConstraints(
65
- { video: { facingMode: 'environment' } },
66
- ref.current,
67
- (result, err) => {
68
- if (!inited.current) {
69
- inited.current = true;
70
- onInit();
71
- }
72
- if (result) {
73
- if (scanType.includes(FORMAT[result.format].wxtype)) {
74
- success(wechatLikeResult(result));
75
- complete();
76
- closeScanCode();
77
- }
78
- }
79
-
80
- if (err && !err instanceof NotFoundException) {
81
- fail(err);
82
- complete();
83
- }
84
- },
85
- );
86
- } catch (err) {
87
- fail(err);
88
- complete();
89
- }
90
- } else {
91
- fail(new Error('No camera detect'));
92
- complete();
93
- }
94
- };
95
-
96
- const stop = () => {
97
- codeReader.reset();
98
- };
99
-
100
- useImperativeHandle(fref, () => ({
101
- start,
102
- stop,
103
- }));
104
-
105
- useEffect(() => {
106
- start().catch(fail);
107
- return () => {
108
- stop();
109
- };
110
- }, []);
111
- return (
112
- <>
113
- <video
114
- autoPlay
115
- ref={ref}
116
- id="weapp-scancode-video"
117
- ></video>
118
- </>
119
- );
120
- });
121
-
122
-
123
- function fileToImage(file) {
124
- return new Promise((resolve, reject) => {
125
- const reader = new FileReader();
126
- reader.readAsDataURL(file);
127
- reader.onload = async (ev) => {
128
- const img = new Image();
129
- img.src = ev.target.result;
130
- resolve(img);
131
- };
132
- reader.onerror = reject;
133
- });
134
- }
135
-
136
- const SCAN_CODE_STATE = 'scan-code-modal';
137
- export default function ScanCode({ root, options }) {
138
- const {
139
- onlyFromCamera,
140
- scanType,
141
- success: successCallback,
142
- fail,
143
- complete,
144
- enableDefaultBehavior,
145
- } = options;
146
- useEffect(() => {
147
- // 覆盖一次返回按键为关闭
148
- if (history.state?.SCANCODE !== SCAN_CODE_STATE) {
149
- history.pushState({ SCANCODE: SCAN_CODE_STATE }, null);
150
- }
151
- const onPopState = () => {
152
- closeScanCode();
153
- };
154
- window.addEventListener('popstate', onPopState);
155
- return () => {
156
- if (history.state?.SCANCODE === SCAN_CODE_STATE) {
157
- history.back();
158
- }
159
- window.removeEventListener('popstate', onPopState);
160
- };
161
- }, [closeScanCode]);
162
- const ref = useRef();
163
- const closeScanCode = () => {
164
- ref.current?.stop?.();
165
- ReactDOM.render(null, root);
166
- };
167
- const success = useCallback((res) => {
168
- const {result} = res;
169
- if (enableDefaultBehavior) {
170
- if (/^https?:\/\//.test(result)) {
171
- window.open(result);
172
- } else {
173
- app.showModal({
174
- title: '扫描到以下内容',
175
- content: result,
176
- showCancel: false,
177
- confirmColor: '#006eff',
178
- });
179
- }
180
- }
181
- successCallback(res);
182
- });
183
- const [isCameraInit, setIscameraInit] = useState(false);
184
- const onInitCamera = () => {
185
- setIscameraInit(true);
186
- };
187
- const [modalErrMessage, setModalErrMessage] = useState('');
188
- const handleModalClick = () => {
189
- setModalErrMessage('');
190
- };
191
- const fileChanged = async (ev) => {
192
- const { files } = ev.target;
193
- if (files.length <= 0) return;
194
- const file = files[0];
195
- const img = await fileToImage(file);
196
- hints.set(DecodeHintType.TRY_HARDER, true);
197
- const codeReader = new BrowserMultiFormatReader(hints);
198
- try {
199
- const result = await codeReader.decodeFromImage(img);
200
- success(wechatLikeResult(result));
201
- closeScanCode();
202
- } catch (err) {
203
- onScanFail(err);
204
- }
205
- };
206
- const scanTypeText = useMemo(() => scanType.map((type) => {
207
- switch (type) {
208
- case 'qrCode':
209
- return '二维码';
210
- case 'barCode':
211
- return '条码';
212
- default:
213
- return type;
214
- }
215
- }).join(' / '), [scanType]);
216
- const onScanFail = (err) => {
217
- if (err instanceof NotFoundException) {
218
- setModalErrMessage(`未发现${scanTypeText}`);
219
- setIscameraInit(false);
220
- } else if (err.message === 'Permission denied') {
221
- setModalErrMessage('请打开相机权限以获取扫码功能');
222
- } else if (err.message === 'No camera detect') {
223
- setModalErrMessage('未能检测到相机设备');
224
- } else {
225
- setModalErrMessage(err.message);
226
- }
227
- setIscameraInit(false);
228
- fail(err);
229
- };
230
- if (modalErrMessage) {
231
- return <div className="weapp-scancode-modal" onClick={handleModalClick}>
232
- <div className="weapp-scancode-modal-main">
233
- <div className="weapp-scancode-scan-wrapper">
234
- <p className="weapp-scancode-scan-not-found">{modalErrMessage}</p>
235
- <p>点击重新扫码</p>
236
- </div>
237
- <CloseButton onClick={closeScanCode} />
238
- </div>
239
- </div>;
240
- }
241
- return (
242
- <div className="weapp-scancode-modal">
243
- <div className="weapp-scancode-modal-main">
244
- <Codescanner
245
- events={{ fail: onScanFail, success, complete }}
246
- ref={ref}
247
- closeScanCode={closeScanCode}
248
- scanType={scanType}
249
- onInit={(onInitCamera)}
250
- />
251
-
252
- {isCameraInit && <><CloseButton onClick={closeScanCode} />
253
- <div className="weapp-scancode-scan-wrapper">
254
- <div className="weapp-scancode-scan-square">
255
- <div className="weapp-scancode-scan-bar"></div>
256
- </div>
257
- <p className="weapp-scancode-scan-tip">扫${scanTypeText}</p>
258
- </div>
259
- </>
260
- }
261
- {!onlyFromCamera && isCameraInit && <div
262
- className="weapp-scancode-img-selector"
263
- >
264
- <input onChange={fileChanged} type="file" id="weapp-scancode-img-picker-input" accept="image/*" style={{ display: 'none' }} />
265
- <label
266
- htmlFor="weapp-scancode-img-picker-input"
267
- className="weapp-scancode-img-picker"
268
- >
269
- <span>
270
- <svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg">
271
- <title>icon/album</title>
272
- <g id="icon/album" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
273
- <rect id="矩形" x="0" y="0" width="24" height="24"></rect>
274
- <path d="M21,4 C21.5522847,4 22,4.44771525 22,5 L22,19 C22,19.5522847 21.5522847,20 21,20 L3,20 C2.44771525,20 2,19.5522847 2,19 L2,5 C2,4.44771525 2.44771525,4 3,4 L21,4 Z M20.5,5.5 L3.5,5.5 L3.5,13.932 L8.34720227,9.89314397 C8.69729746,9.60139798 9.19512095,9.58601647 9.56028418,9.84165631 L9.65637439,9.91809179 L14.036,13.86 L16.8907001,11.8207928 C17.2650251,11.5533999 17.7734822,11.5758744 18.1227552,11.8752513 L18.1227552,11.8752513 L20.5,13.913 L20.5,5.5 Z" id="形状结合" fill="#FFFFFF" fillRule="nonzero"></path>
275
- </g>
276
- </svg>
277
- </span>
278
- </label>
279
- </div>}
280
- </div>
281
- </div>
282
- );
283
- }
284
-
285
- function CloseButton({ onClick }) {
286
- return (
287
- <a
288
- className="weapp-scancode-close-button"
289
- aria-label="close modal"
290
- onClick={onClick}
291
- >
292
- <svg width="12px" height="12px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
293
- <path fillRule="evenodd" clipRule="evenodd" d="M12.5348 2.04999L7.9998 6.58499L3.4638 2.04999L2.0498 3.46499L6.5858 8.00099L2.0498 12.536L3.4638 13.95L7.9998 9.41499L12.5348 13.95L13.9498 12.536L9.4138 8.00099L13.9498 3.46499L12.5348 2.04999Z" fill="currentColor"/>
294
- </svg>
295
- </a>
296
- );
297
- }
298
-
299
- function wechatLikeResult(zxingResult) {
300
- const wechatResult = {
301
- result: zxingResult.text || zxingResult.result,
302
- scanType: FORMAT[zxingResult.format].wxtype,
303
- };
304
- return wechatResult;
305
- }
306
-
307
- // https://github.com/AlloyTeam/AlloyImage/blob/master/src/module/filter/toGray.js
308
- function toGray(imgData) {
309
- const { data } = imgData;
310
-
311
- for (let i = 0, n = data.length;i < n;i += 4) {
312
- const gray = parseInt((0.299 * data[i] + 0.578 * data[i + 1] + 0.114 * data[i + 2]), 10);
313
- // eslint-disable-next-line no-multi-assign
314
- data[i + 2] = data[i + 1] = data[i] = gray;
315
- }
316
-
317
- imgData.data.set(data);
318
-
319
- return imgData;
320
- }
321
-
322
- // https://github.com/AlloyTeam/AlloyImage/blob/master/src/module/filter/sharp.js
323
- function sharp(imgData, arg = []) {
324
- const lamta = arg[0] || 0.6;
325
- const { data } = imgData;
326
- const { width } = imgData;
327
-
328
- for (let i = 0, n = data.length;i < n;i += 4) {
329
- const ii = i / 4;
330
- const row = parseInt(ii / width, 10);
331
- const col = ii % width;
332
- if (row === 0 || col === 0) continue;
333
-
334
- const A = ((row - 1) * width + (col - 1)) * 4;
335
- const B = ((row - 1) * width + col) * 4;
336
- const E = (ii - 1) * 4;
337
-
338
- for (let j = 0;j < 3;j ++) {
339
- const delta = data[i + j] - (data[B + j] + data[E + j] + data[A + j]) / 3;
340
- data[i + j] += delta * lamta;
341
- }
342
- }
343
-
344
- return imgData;
345
- }