@cloudbase/framework-plugin-low-code 0.6.67 → 0.7.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.
@@ -1,117 +1,17 @@
1
1
  import * as React from 'react';
2
+ import { useRef } from 'react';
2
3
  import * as _ from 'lodash';
3
- import { ForContext, getComponentRenderList } from './FieldMiddleware/renderer';
4
+ import { CompRenderer, ForContext } from './FieldMiddleware/renderer';
4
5
  import { isScopeSlot } from '../utils/index';
5
- import { observer } from 'mobx-react-lite';
6
6
 
7
- export function getComponentChildren(component, context = {}) {
7
+ function getComponentChildren(component) {
8
8
  const { properties } = component;
9
9
  if (!properties) {
10
10
  return [];
11
11
  }
12
- const list = Object.values(properties).sort(
12
+ return Object.values(properties).sort(
13
13
  (a, b) => (a['x-index'] || 0) - (b['x-index'] || 0)
14
14
  );
15
- const {
16
- virtualFields,
17
- codeContext,
18
- scopeContext,
19
- forContext,
20
- injectContext = {},
21
- dataContext,
22
- updateContext,
23
- } = context;
24
-
25
- return list.map((schema) => {
26
- return getRenderList({
27
- key: schema.key,
28
- componentSchema: schema,
29
- rootNode: false,
30
- renderSlot: false,
31
- virtualFields,
32
- codeContext,
33
- scopeContext,
34
- forContext,
35
- injectContext,
36
- context: dataContext,
37
- updateContext,
38
- });
39
- });
40
- }
41
-
42
- function getRenderList(props) {
43
- const {
44
- key = '',
45
- className,
46
- virtualFields,
47
- componentSchema,
48
- renderSlot,
49
- rootNode = true,
50
- codeContext,
51
- scopeContext = {},
52
- context = {},
53
- updateContext,
54
- forContext = {},
55
- } = props;
56
-
57
- const { 'x-props': xProps, properties = {} } = componentSchema;
58
-
59
- // 判断是否为 slot
60
- const isSlot = !xProps;
61
- if (isSlot && !(renderSlot || rootNode)) {
62
- return null;
63
- }
64
-
65
- // const preClassName = useRef();
66
-
67
- // wrapperClass
68
- const containerEl = Object.values(properties)[0];
69
- if (containerEl && containerEl['x-props'] && className) {
70
- let { classNameList = [] } = containerEl['x-props'];
71
-
72
- // 先替换掉先前计算出来的className部分
73
- // if (preClassName.current) {
74
- // if (preClassName.current !== className) {
75
- // classNameList = classNameList.filter(
76
- // (clsName) => clsName !== preClassName.current
77
- // );
78
- // preClassName.current = className;
79
- // }
80
- // } else {
81
- // preClassName.current = className;
82
- // }
83
-
84
- containerEl['x-props'].classNameList = Array.from(
85
- new Set([className, ...classNameList])
86
- );
87
- }
88
-
89
- if (xProps && xProps.sourceKey) {
90
- const { sourceKey } = xProps;
91
- const Field = virtualFields[sourceKey];
92
- if (!Field) {
93
- return (
94
- <div style={{ color: 'red' }}>
95
- 组件<em>{sourceKey}</em>未找到
96
- </div>
97
- );
98
- }
99
- }
100
-
101
- return getComponentRenderList({
102
- key,
103
- componentSchema,
104
- id: componentSchema.key,
105
- xProps,
106
- emitEvents: componentSchema.emitEvents || [],
107
- virtualFields,
108
- renderSlot,
109
- codeContext,
110
- scopeContext,
111
- forContext,
112
- context,
113
- updateContext,
114
- });
115
15
  }
116
16
 
117
17
  export function generateSlotMetaMap(componentSchema, context, options = {}) {
@@ -136,10 +36,14 @@ export function generateSlotMetaMap(componentSchema, context, options = {}) {
136
36
  node: isHOC
137
37
  ? (props) => {
138
38
  let clonedScopeContext = _.cloneDeep(scopeContext);
139
- _.set(clonedScopeContext, `${componentSchema.key}.${key}`, props);
39
+ _.set(
40
+ clonedScopeContext,
41
+ `${componentSchema.key}.${child.key}`,
42
+ props
43
+ );
140
44
  return (
141
45
  <AppRender
142
- key={key}
46
+ key={child.key}
143
47
  componentSchema={child}
144
48
  renderSlot={options?.renderSlot}
145
49
  virtualFields={virtualFields}
@@ -154,7 +58,7 @@ export function generateSlotMetaMap(componentSchema, context, options = {}) {
154
58
  return (
155
59
  <ForContext.Provider value={forContext}>
156
60
  <AppRender
157
- key={key}
61
+ key={child.key}
158
62
  componentSchema={child}
159
63
  renderSlot={options?.renderSlot}
160
64
  virtualFields={virtualFields}
@@ -172,10 +76,89 @@ export function generateSlotMetaMap(componentSchema, context, options = {}) {
172
76
  return slots;
173
77
  }
174
78
 
175
- export const AppRender = observer(function (props) {
176
- return getRenderList({
177
- ...props,
178
- forContext: React.useContext(ForContext),
179
- injectContext: {},
180
- });
181
- });
79
+ export function AppRender(props) {
80
+ const {
81
+ className,
82
+ virtualFields,
83
+ componentSchema,
84
+ renderSlot,
85
+ rootNode = true,
86
+ codeContext,
87
+ scopeContext = {},
88
+ context = {},
89
+ updateContext,
90
+ } = props;
91
+
92
+ const { 'x-props': xProps, properties = {} } = componentSchema;
93
+
94
+ // 判断是否为 slot
95
+ const isSlot = !xProps;
96
+ if (isSlot && !(renderSlot || rootNode)) {
97
+ return null;
98
+ }
99
+
100
+ const preClassName = useRef();
101
+
102
+ // wrapperClass
103
+ const containerEl = Object.values(properties)[0];
104
+ if (containerEl && containerEl['x-props'] && className) {
105
+ let { classNameList = [] } = containerEl['x-props'];
106
+
107
+ // 先替换掉先前计算出来的className部分
108
+ if (preClassName.current) {
109
+ if (preClassName.current !== className) {
110
+ classNameList = classNameList.filter(
111
+ (clsName) => clsName !== preClassName.current
112
+ );
113
+ preClassName.current = className;
114
+ }
115
+ } else {
116
+ preClassName.current = className;
117
+ }
118
+
119
+ containerEl['x-props'].classNameList = [className, ...classNameList];
120
+ }
121
+
122
+ if (xProps && xProps.sourceKey) {
123
+ const { sourceKey } = xProps;
124
+ const Field = virtualFields[sourceKey];
125
+ if (!Field) {
126
+ return (
127
+ <div style={{ color: 'red' }}>
128
+ 组件<em>{sourceKey}</em>未找到
129
+ </div>
130
+ );
131
+ }
132
+ }
133
+
134
+ const children = getComponentChildren(componentSchema);
135
+
136
+ return (
137
+ <CompRenderer
138
+ id={componentSchema.key}
139
+ xProps={xProps}
140
+ emitEvents={componentSchema.emitEvents || []}
141
+ componentSchema={componentSchema}
142
+ virtualFields={virtualFields}
143
+ renderSlot={renderSlot}
144
+ codeContext={codeContext}
145
+ scopeContext={scopeContext}
146
+ context={context}
147
+ updateContext={updateContext}
148
+ >
149
+ {children.map((comp) => (
150
+ <AppRender
151
+ key={comp.key}
152
+ componentSchema={comp}
153
+ rootNode={false}
154
+ renderSlot={false}
155
+ virtualFields={virtualFields}
156
+ codeContext={codeContext}
157
+ scopeContext={scopeContext}
158
+ context={context}
159
+ updateContext={updateContext}
160
+ />
161
+ ))}
162
+ </CompRenderer>
163
+ );
164
+ }
@@ -1,4 +1,11 @@
1
1
  import config from '../../datasources/config'
2
+ import { getTcbInstance, getAccessToken } from '@cloudbase/weda-cloud-sdk/dist/h5';
3
+
4
+ async function loginScope() {
5
+ const { auth } = await getTcbInstance();
6
+ return auth.loginScope();
7
+ }
8
+
2
9
  export function getComponentId(key) {
3
10
  return `__weapps-component-wrapper-${key}`;
4
11
  }
@@ -77,7 +84,7 @@ export function resolveComponentProps(props, isPlainProps) {
77
84
  ...props,
78
85
  };
79
86
  }
80
- const { data = {}, events = [], $node, ...restProps } = props;
87
+ const { data = {}, events = [], ...restProps } = props;
81
88
  const customProps = { ...data };
82
89
  const builtinProps = [
83
90
  // react 保留字
@@ -141,63 +148,159 @@ export function getStaticResourceAttribute(staticUrl) {
141
148
  }
142
149
  return staticUrl;
143
150
  }
151
+
152
+ export function findLoginPage(app = window.app) {
153
+ const { pages = [] } = app.utils._getConfig();
154
+ return pages.find(item => item.type === 'login');
155
+ }
156
+
157
+ let _AUTH_CONFIG_CACHE = null;
158
+ async function getAuthConfig(app = window.app) {
159
+ if (_AUTH_CONFIG_CACHE) {
160
+ return _AUTH_CONFIG_CACHE;
161
+ }
162
+ try {
163
+ const res = await app.cloud.callWedaApi({
164
+ action: "DescribeRuntimeResourceStrategy",
165
+ data: {
166
+ ResourceType: `<%= isAdminPortal? 'modelApp' : 'app'%>`,
167
+ ResourceId: app.id,
168
+ },
169
+ });
170
+ const settingData = {};
171
+ // 云api不支持map只能传字符串,需要转换
172
+ res.forEach((item) => {
173
+ settingData[item.Key] = ['AllowRegister', 'NeedLogin'].includes(item.Key) ? item.Value === '1' : item.Value;
174
+ });
175
+ _AUTH_CONFIG_CACHE = settingData;
176
+ return _AUTH_CONFIG_CACHE;
177
+ } catch (e) {
178
+ return {
179
+ NeedLogin: false,
180
+ RejectStrategy: "show_warning",
181
+ };
182
+ }
183
+ }
184
+
185
+ let _AUTH_CACHE_MAP = {}
186
+ async function getAccessPermission(app, appId, pageId) {
187
+ const cacheKey = `${appId}-${pageId}`
188
+ if (_AUTH_CACHE_MAP[cacheKey] !== undefined) {
189
+ return _AUTH_CACHE_MAP[cacheKey];
190
+ }
191
+
192
+ let isAccess = false;
193
+ try {
194
+ const res = await app.cloud.callWedaApi({
195
+ action: 'DescribeResourcesPermission',
196
+ data: {
197
+ ResourceType: `<%= isAdminPortal? 'modelApp' : 'app'%>`,
198
+ ResourceIdList: [cacheKey],
199
+ AppResourceId: appId,
200
+ },
201
+ });
202
+ if (Array.isArray(res) && res.length > 0) {
203
+ isAccess = !!res[0].IsAccess;
204
+ }
205
+ _AUTH_CACHE_MAP[cacheKey] = isAccess;
206
+ } catch (e) {
207
+ console.warn('getAccessPermission', e);
208
+ }
209
+ return isAccess
210
+ }
211
+
144
212
  /**
145
213
  * 检查页面权限
146
214
  **/
147
- const _AUTH_CACHE_MAP = {}
148
- export async function checkAuth(app, appId, pageId) {
149
- <% if(isAdminPortal||isXPage){ %>return true;<% } %>
150
- const cacheKey = `${appId}-${pageId}`
151
- if(_AUTH_CACHE_MAP[cacheKey] !== undefined) {
152
- return _AUTH_CACHE_MAP[cacheKey]
215
+ export async function checkAuth(app, appId, $page) {
216
+ <% if (isAdminPortal || isXPage) { %>return true;<% } %>
217
+ const loginPage = findLoginPage(app);
218
+ if (loginPage?.id === $page.id) {
219
+ return true
153
220
  }
154
221
  app.showNavigationBarLoading();
155
- const checkAuthResult = await app.cloud.callWedaApi({
156
- action: 'DescribeResourcesPermission',
157
- data: {
158
- ResourceType: `<%= isAdminPortal? 'modelApp' : 'app'%>`,
159
- ResourceIdList: [cacheKey],
160
- },
161
- });
162
- let isLogin = false;
163
- if (Array.isArray(checkAuthResult) && checkAuthResult.length > 0) {
164
- isLogin = checkAuthResult[0]?.IsAccess ?? false;
222
+ const requestList = [getAccessPermission(app, appId, $page.id)];
223
+ // 暂时先认为有登录页则自定义登录功能开启且生效
224
+ if (loginPage) {
225
+ requestList.push(getAuthConfig(app));
165
226
  }
227
+ const [isAccess, authConfig] = await Promise.all(requestList);
166
228
  app.hideNavigationBarLoading();
167
229
 
168
- if (!isLogin) {
230
+ if (!isAccess) {
231
+ if (loginPage && (authConfig.NeedLogin || authConfig.RejectStrategy == 'to_login')) {
232
+ redirectToLogin($page);
233
+ } else {
234
+ app.showToast({
235
+ title: '页面无访问权限',
236
+ icon: 'error',
237
+ });
238
+ }
239
+ } else if (loginPage && authConfig.NeedLogin) {
240
+ // 此分支逻辑本不应该前端判断是否登录,历史原因后端短期内搞不定,后续后端优化后删除
241
+ try {
242
+ const [scope, { accessToken }] = await Promise.all([loginScope(), getAccessToken()]);
243
+ if (!accessToken || scope === 'anonymous') {
244
+ redirectToLogin($page);
245
+ }
246
+ } catch (e) {
247
+ console.error('获取身份失败', e);
248
+ redirectToLogin($page);
249
+ }
250
+ }
251
+ return isAccess;
252
+ }
253
+
254
+ export function redirectToLogin(currentPage) {
255
+ // 去登录则清空权限缓存。
256
+ _AUTH_CACHE_MAP = {};
257
+ const app = window.app;
258
+ const loginPage = findLoginPage(app);
259
+ if (!currentPage) {
260
+ currentPage = app.utils.getCurrentPage() || {};
261
+ }
262
+ if (loginPage?.id === currentPage.id) {
263
+ return true
264
+ }
265
+ if (loginPage) {
266
+ app.redirectTo({
267
+ pageId: loginPage.id,
268
+ params: {
269
+ sourcePageId: currentPage.id,
270
+ sourcePageParams: currentPage.dataset.params
271
+ }
272
+ })
273
+ } else {
169
274
  app.showToast({
170
- title: '页面无访问权限',
275
+ title: '用户未登录',
171
276
  icon: 'error',
172
277
  });
173
278
  }
174
- _AUTH_CACHE_MAP[cacheKey] = isLogin
175
- return isLogin;
176
279
  }
177
280
 
178
281
  const _REPORTED = {}
179
- export function reportTime(tag, time, only=false){
180
- if(!window._aegis || !tag){
282
+ export function reportTime(tag, time, only = false) {
283
+ if (!window._aegis || !tag) {
181
284
  return;
182
285
  }
183
- if(window['_WedaHostConfig'] && !window['_WedaHostConfig']['_REPORTED']) {
286
+ if (window['_WedaHostConfig'] && !window['_WedaHostConfig']['_REPORTED']) {
184
287
  window['_WedaHostConfig']['_REPORTED'] = _REPORTED
185
288
  }
186
289
 
187
290
  const CACHE_MAP = window['_WedaHostConfig']?.['_REPORTED'] || _REPORTED
188
291
 
189
- if(only && CACHE_MAP[tag]){
190
- return ;
292
+ if (only && CACHE_MAP[tag]) {
293
+ return;
191
294
  }
192
295
  CACHE_MAP[tag] = true
193
296
  try {
194
- let t = time === undefined? (performance?.now?.() || Date.now() - window['_aegis_inited']) :time;
297
+ let t = time === undefined ? (performance?.now?.() || Date.now() - window['_aegis_inited']) : time;
195
298
  window._aegis.reportTime({
196
299
  name: tag,
197
300
  duration: t,
198
- ext2: config.isProd? 'production' : 'preview',
301
+ ext2: config.isProd ? 'production' : 'preview',
199
302
  })
200
- }catch(e){
303
+ } catch (e) {
201
304
  console.log(e)
202
305
  }
203
306
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react'
2
2
  import * as ReactDOM from 'react-dom'
3
- import { setConfig } from '@cloudbase/weda-cloud-sdk/dist/h5'
3
+ import { setConfig, getAccessToken, initTcb } from '@cloudbase/weda-cloud-sdk/dist/h5'
4
4
  import App from './router'
5
5
  import './utils/monitor-jssdk.min'
6
6
  import './index.less'
@@ -12,6 +12,7 @@ import attachFastClick from 'fastclick'
12
12
  import { initWebConfig } from 'handlers/lifecycle'
13
13
  const AppConfig = require('../webpack/miniprogram.config')
14
14
  import { app } from './app/global-api'
15
+ import { redirectToLogin, findLoginPage, getAuthConfig } from './handlers/utils'
15
16
  // app 中注册配置页面以及app的全局配置miniprogram.config,h5里分app以及web页分别处理,使用process.env.isApp 区分判断
16
17
  if (process.env.isApp) {
17
18
  initWebConfig(app, AppConfig);
@@ -23,12 +24,55 @@ setConfig({
23
24
  if (!cfg.options || !cfg.options.showLoading) return
24
25
  app.showLoading()
25
26
  },
27
+ beforeCallFunction: async (params) => {
28
+ try{
29
+ const loginPage = findLoginPage();
30
+
31
+ let skip = false;
32
+ switch (params?.data?.methodName) {
33
+ case 'callWedaApi': {
34
+ if(['GetMiniProgramUserTicket', 'DescribeRuntimeResourceStrategy'].includes(params?.data?.params.action)){
35
+ skip = true;
36
+ }
37
+ break;
38
+ }
39
+ }
40
+
41
+ // 后续做过滤处理
42
+ if (!loginPage || (params?.data?.mode === 'c' && skip)) {
43
+ return params;
44
+ }
45
+ const { accessToken } = await getAccessToken();
46
+ if (accessToken) {
47
+ params.data.accessToken = accessToken;
48
+ }
49
+ } catch (e) {
50
+ console.error('beforeCallFunction error', e);
51
+ }
52
+ return params;
53
+ },
26
54
  afterDSRequest: (cfg, error, result) => {
27
55
  if (!cfg.options) return
28
56
  if (cfg.options.showLoading) app.hideLoading()
29
57
  if (!cfg.options.showToast) return
30
58
  const isSuccess = !error && result && !result.code
31
59
  app.showToast({icon: isSuccess ? 'success' : 'error'})
60
+ },
61
+ async afterCallFunction(params, error, res) {
62
+ if(params?.data?.params?.action != 'DescribeRuntimeResourceStrategy' && ['InnerError.AuthFailure','InvalidAccessToken'].includes(res?.result?.code)) {
63
+ const loginPage = findLoginPage();
64
+ if (loginPage) {
65
+ const authConfig = await getAuthConfig();
66
+ if (authConfig.NeedLogin || authConfig.RejectStrategy == 'to_login') {
67
+ redirectToLogin();
68
+ } else if (authConfig.RejectStrategy == 'show_warning') {
69
+ app.showToast({
70
+ title: '接口无访问权限',
71
+ icon: 'error',
72
+ });
73
+ }
74
+ }
75
+ }
32
76
  }
33
77
  })
34
78
  // window.app.yyptReport = window.yyptReport
@@ -78,24 +78,37 @@ initLifeCycle({
78
78
  export default function App() {
79
79
  // 检查权限
80
80
  const [weDaHasLogin, setWeDaHasLogin] = React.useState(false);
81
- const dataContextRef = React.useRef(observable({}))
82
- const context = dataContextRef.current;
81
+ const context = React.useRef(observable({})).current;
83
82
  const containerRef = React.useRef(null);
84
83
  const microApp = React.useRef(null);
85
84
  const pureSrc = '<%= pageSource %>';
86
85
  const isPure = !!pureSrc;
87
86
 
88
- React.useEffect(() => {
89
- checkAuth(app, app.id, '<%= pageName %>').then((checkAuthResult) => {
90
- setWeDaHasLogin(checkAuthResult)
91
- reportTime('FIRST_PAGE_CONTENT_RENDERED', undefined, true)
92
- });
87
+ /**
88
+ * 更新数据容器的上下文的方法
89
+ * 会传递到事件emit的地方,将从组件获取到的数据data赋值给上下文
90
+ * 当组件卸载时,传过来的data为undefined即可
91
+ * {
92
+ * id1: [{...}],
93
+ * id2: {...},
94
+ * id3: undefined,
95
+ * id4: null,
96
+ * ...
97
+ * }
98
+ * @param id
99
+ * @param data
100
+ */
101
+ const updateContext = (id, data) => {
102
+ if (id) {
103
+ context[id] = { data };
104
+ }
105
+ }
93
106
 
107
+ React.useEffect(() => {
94
108
  Object.assign($page, {
95
109
  id: '<%= pageName %>',
96
110
  state: observable(initPageState),
97
111
  computed: createComputed(computed),
98
- // _context: context,
99
112
  handler,
100
113
  });
101
114
 
@@ -107,6 +120,12 @@ export default function App() {
107
120
  app.utils.set($page.dataset.state, keyPath, userSetState[keyPath]);
108
121
  });
109
122
  };
123
+
124
+ checkAuth(app, app.id, $page).then((checkAuthResult) => {
125
+ setWeDaHasLogin(checkAuthResult)
126
+ reportTime('FIRST_PAGE_CONTENT_RENDERED', undefined, true)
127
+ });
128
+
110
129
  return () => {
111
130
  if (microApp.current) {
112
131
  microApp.current.unmount();
@@ -115,10 +134,10 @@ export default function App() {
115
134
  }, []);
116
135
 
117
136
  React.useEffect(() => {
118
- $page.widgets = createWidgets(widgetsContext, dataBinds, {}, dataContextRef.current);
137
+ $page.widgets = createWidgets(widgetsContext, dataBinds, {}, context);
119
138
  // widgets 内的 dataBinds 可能需要关联 widgets,需要重新执行 dataBinds
120
139
  retryDataBinds();
121
- }, [dataContextRef.current]);
140
+ }, [context]);
122
141
 
123
142
  // Web 环境页面级别生命周期
124
143
  if (!process.env.isMiniprogram) {
@@ -160,27 +179,8 @@ export default function App() {
160
179
  <AppRender pageListenerInstances={pageListenerInstances}
161
180
  virtualFields={virtualFields}
162
181
  componentSchema={componentSchema}
163
- context={dataContextRef.current}
164
- /**
165
- * 更新数据容器的上下文的方法
166
- * 会传递到事件emit的地方,将从组件获取到的数据data赋值给上下文
167
- * 当组件卸载时,传过来的data为undefined即可
168
- * {
169
- * id1: [{...}],
170
- * id2: {...},
171
- * id3: undefined,
172
- * id4: null,
173
- * ...
174
- * }
175
- * @param id
176
- * @param data
177
- */
178
- updateContext={(id, data) => {
179
- if (id) {
180
- dataContextRef.current[id] = { data };
181
- // console.log('111', context[id])
182
- }
183
- }}
182
+ context={context}
183
+ updateContext={updateContext}
184
184
  />
185
185
  )}
186
186
  </div>
@@ -1,42 +0,0 @@
1
- import { observable } from 'mobx';
2
- let loading = {};
3
- export let enumOptions = observable({});
4
- export function formatEnum(path, optionname) {
5
- // 判断是单选还是多选
6
- let isSingle = Array.isArray(path);
7
- // 获取到options
8
- let parseOptions = getEnumOptions(optionname);
9
- if (parseOptions === '') {
10
- return !isSingle ? path : path.join(',');
11
- }
12
- let multiTmp = [];
13
- let value = !isSingle
14
- ? JSON.parse(parseOptions)?.find((item) => item?.key === path)?.value
15
- : JSON.parse(parseOptions)
16
- ?.filter((item) => path.some((pathValue) => item?.key === pathValue))
17
- .map((item) => multiTmp.push(item?.value));
18
- // 对多选或者单选有不同处理
19
- return !isSingle ? value : multiTmp?.join(',');
20
- }
21
- function getEnumOptions(optionName) {
22
- if (enumOptions[optionName]) {
23
- return enumOptions[optionName];
24
- }
25
- if (!loading[optionName]) {
26
- loading[optionName] = true;
27
- getGeneralOptions(optionName).then((data) => {
28
- enumOptions[optionName] = data?.Items[0]?.Config;
29
- });
30
- }
31
- return '';
32
- }
33
- export async function getGeneralOptions(optionName) {
34
- return app.cloud.callWedaApi({
35
- action: 'DescribeGeneralOptionsDetailList',
36
- data: {
37
- PageSize: 1,
38
- PageIndex: 1,
39
- LikeNameOrTitle: optionName,
40
- },
41
- });
42
- }