@ibiz-template/vue3-components 0.7.41-alpha.136 → 0.7.41-alpha.138

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 (40) hide show
  1. package/dist/index-dK7NHPF1.js +339 -0
  2. package/dist/{index.es-Cg7SaUZt.js → index.es-FZv4rjHr.js} +1 -1
  3. package/dist/index.min.css +1 -1
  4. package/dist/index.system.min.js +1 -1
  5. package/dist/{wang-editor-DpxK_csh.js → wang-editor-BaOTSy3S.js} +1 -1
  6. package/dist/{xlsx-util-CNqFg89T.js → xlsx-util-ByzdGnKz.js} +1 -1
  7. package/es/common/back-top/back-top.css +1 -0
  8. package/es/common/back-top/back-top.mjs +201 -0
  9. package/es/common/index.mjs +2 -0
  10. package/es/control/data-view/data-view.mjs +17 -5
  11. package/es/control/list/list.mjs +16 -3
  12. package/es/editor/text-box/input/input.mjs +18 -1
  13. package/es/index.mjs +16 -0
  14. package/es/panel-component/index.mjs +16 -0
  15. package/es/panel-component/panel-button/panel-button.mjs +13 -1
  16. package/es/util/ai-chat-util/ai-chat-util.mjs +21 -21
  17. package/es/view/login-view/login-view.mjs +6 -3
  18. package/lib/common/back-top/back-top.cjs +203 -0
  19. package/lib/common/back-top/back-top.css +1 -0
  20. package/lib/common/index.cjs +2 -0
  21. package/lib/control/data-view/data-view.cjs +15 -3
  22. package/lib/control/list/list.cjs +14 -1
  23. package/lib/editor/text-box/input/input.cjs +18 -1
  24. package/lib/index.cjs +32 -0
  25. package/lib/panel-component/index.cjs +32 -0
  26. package/lib/panel-component/panel-button/panel-button.cjs +13 -1
  27. package/lib/util/ai-chat-util/ai-chat-util.cjs +21 -21
  28. package/lib/view/login-view/login-view.cjs +6 -3
  29. package/package.json +5 -5
  30. package/src/common/back-top/back-top.scss +30 -0
  31. package/src/common/back-top/back-top.tsx +224 -0
  32. package/src/common/index.ts +2 -0
  33. package/src/control/data-view/data-view.tsx +20 -0
  34. package/src/control/list/list.tsx +20 -0
  35. package/src/editor/text-box/input/input.tsx +18 -0
  36. package/src/panel-component/index.ts +17 -0
  37. package/src/panel-component/panel-button/panel-button.tsx +15 -0
  38. package/src/util/ai-chat-util/ai-chat-util.ts +31 -33
  39. package/src/view/login-view/login-view.tsx +3 -0
  40. package/dist/index-scbUG9yD.js +0 -339
@@ -0,0 +1,224 @@
1
+ /* eslint-disable no-lonely-if */
2
+ import {
3
+ ref,
4
+ watch,
5
+ PropType,
6
+ Teleport,
7
+ computed,
8
+ onMounted,
9
+ Transition,
10
+ onUnmounted,
11
+ CSSProperties,
12
+ defineComponent,
13
+ } from 'vue';
14
+ import { useNamespace, useUIStore } from '@ibiz-template/vue3-util';
15
+ import './back-top.scss';
16
+
17
+ export const IBizBackTop = defineComponent({
18
+ name: 'IBizBackTop',
19
+ props: {
20
+ mode: {
21
+ type: String as PropType<'top' | 'bottom' | 'auto'>,
22
+ default: 'bottom',
23
+ },
24
+ target: {
25
+ type: [String, Object] as PropType<string | HTMLElement>,
26
+ default: '',
27
+ },
28
+ right: {
29
+ type: [Number, String] as PropType<number | string>,
30
+ default: 30,
31
+ },
32
+ bottom: {
33
+ type: [Number, String] as PropType<number | string>,
34
+ default: 40,
35
+ },
36
+ offset: {
37
+ type: Number,
38
+ default: 200,
39
+ },
40
+ teleport: {
41
+ type: [String, Object] as PropType<string | HTMLElement>,
42
+ default: '',
43
+ },
44
+ immediate: {
45
+ type: Boolean,
46
+ default: false,
47
+ },
48
+ zIndex: {
49
+ type: [Number, String] as PropType<number | string>,
50
+ default: 5,
51
+ },
52
+ },
53
+ setup(props, { slots }) {
54
+ const { zIndex } = useUIStore();
55
+ const ns = useNamespace('back-top');
56
+ const zIndexVal = zIndex.increment();
57
+ // 状态
58
+ const isVisible = ref(false);
59
+ const isAtBottom = ref(false);
60
+ const scrollContainer = ref<HTMLElement | null>(null);
61
+
62
+ // 计算位置样式
63
+ const positionStyle = computed<CSSProperties>(() => {
64
+ const rightVal =
65
+ typeof props.right === 'number' ? `${props.right}px` : props.right;
66
+ const bottomVal =
67
+ typeof props.bottom === 'number' ? `${props.bottom}px` : props.bottom;
68
+ return {
69
+ right: rightVal,
70
+ bottom: bottomVal,
71
+ zIndex: props.zIndex || zIndexVal,
72
+ };
73
+ });
74
+
75
+ // 获取滚动容器
76
+ const getScrollContainer = () => {
77
+ if (!props.target) return document.documentElement;
78
+ if (typeof props.target === 'string') {
79
+ return document.querySelector(props.target) as HTMLElement;
80
+ }
81
+ return props.target;
82
+ };
83
+
84
+ // 获取滚动数据
85
+ const getScrollData = () => {
86
+ const el = scrollContainer.value;
87
+ if (!el) return { scrollTop: 0, scrollHeight: 0, clientHeight: 0 };
88
+
89
+ return {
90
+ scrollTop: el.scrollTop,
91
+ scrollHeight: el.scrollHeight,
92
+ clientHeight: el.clientHeight,
93
+ };
94
+ };
95
+
96
+ // 滚动监听处理
97
+ const handleScroll = () => {
98
+ const { scrollTop, scrollHeight, clientHeight } = getScrollData();
99
+
100
+ // 判断是否在底部
101
+ const atBottom = scrollTop + clientHeight >= scrollHeight - props.offset;
102
+ isAtBottom.value = atBottom;
103
+
104
+ if (props.mode === 'top') {
105
+ isVisible.value = scrollTop > props.offset;
106
+ } else if (props.mode === 'bottom') {
107
+ const distanceToBottom = scrollHeight - scrollTop - clientHeight;
108
+ isVisible.value = distanceToBottom > props.offset;
109
+ } else {
110
+ if (atBottom) {
111
+ // 如果当前在底部,显示“回到顶部”按钮
112
+ isVisible.value = scrollTop > props.offset;
113
+ } else {
114
+ // 如果当前不在底部,显示“回到底部”按钮
115
+ if (scrollHeight - scrollTop - clientHeight > props.offset)
116
+ isVisible.value = true;
117
+ }
118
+ }
119
+ };
120
+
121
+ // 滚动操作
122
+ const scrollTo = () => {
123
+ const el = scrollContainer.value;
124
+ if (!el) return;
125
+
126
+ let targetPosition = 0;
127
+
128
+ if (props.mode === 'bottom') {
129
+ targetPosition = getScrollData().scrollHeight;
130
+ } else if (props.mode === 'auto') {
131
+ targetPosition = isAtBottom.value ? 0 : getScrollData().scrollHeight;
132
+ } else {
133
+ targetPosition = 0;
134
+ }
135
+
136
+ el.scrollTo({
137
+ top: targetPosition,
138
+ behavior: props.immediate ? 'auto' : 'smooth',
139
+ });
140
+ };
141
+
142
+ // 绑定与解绑事件
143
+ const bindEvents = () => {
144
+ scrollContainer.value = getScrollContainer();
145
+ if (scrollContainer.value) {
146
+ scrollContainer.value.addEventListener('scroll', handleScroll, {
147
+ passive: true,
148
+ });
149
+ // 初始化时执行一次,防止刷新后位置不对
150
+ setTimeout(() => handleScroll(), 300);
151
+ }
152
+ };
153
+
154
+ const unbindEvents = () => {
155
+ if (scrollContainer.value) {
156
+ scrollContainer.value.removeEventListener('scroll', handleScroll);
157
+ }
158
+ };
159
+
160
+ // 监听 target 变化重新绑定
161
+ watch(
162
+ () => props.target,
163
+ () => {
164
+ unbindEvents();
165
+ bindEvents();
166
+ },
167
+ );
168
+
169
+ onMounted(() => {
170
+ bindEvents();
171
+ });
172
+
173
+ onUnmounted(() => {
174
+ zIndex.decrement();
175
+ unbindEvents();
176
+ });
177
+
178
+ /**
179
+ * @description 绘制图标
180
+ * @returns {*}
181
+ */
182
+ const renderIcon = () => {
183
+ if (props.mode === 'bottom')
184
+ return <ion-icon name='chevron-down-outline'></ion-icon>;
185
+ if (props.mode === 'top')
186
+ return <ion-icon name='chevron-up-outline'></ion-icon>;
187
+ if (isAtBottom.value)
188
+ return <ion-icon name='chevron-up-outline'></ion-icon>;
189
+ return <ion-icon name='chevron-down-outline'></ion-icon>;
190
+ };
191
+
192
+ /**
193
+ * @description 绘制内容
194
+ * @returns {*}
195
+ */
196
+ const renderContent = () => {
197
+ return (
198
+ <Transition name='fade'>
199
+ {isVisible.value && (
200
+ <div class={ns.b()} onClick={scrollTo} style={positionStyle.value}>
201
+ {slots.default ? slots.default() : renderIcon()}
202
+ </div>
203
+ )}
204
+ </Transition>
205
+ );
206
+ };
207
+ return {
208
+ ns,
209
+ isVisible,
210
+ positionStyle,
211
+ scrollTo,
212
+ renderIcon,
213
+ renderContent,
214
+ };
215
+ },
216
+ render() {
217
+ if (!this.teleport) return this.renderContent();
218
+ return (
219
+ <Teleport to={this.teleport} disabled={!this.teleport}>
220
+ {this.renderContent()}
221
+ </Teleport>
222
+ );
223
+ },
224
+ });
@@ -44,6 +44,7 @@ import { IBizCropping } from './cropping/cropping';
44
44
  import { IBizEditorEmptyText } from './editor-empty-text/editor-empty-text';
45
45
  import { IBizKanbanSetting } from './kanben-setting/kanben-setting';
46
46
  import { IBizHighLightCode } from './high-light-code/high-light-code';
47
+ import { IBizBackTop } from './back-top/back-top';
47
48
 
48
49
  export * from './col/col';
49
50
  export * from './row/row';
@@ -57,6 +58,7 @@ export { DoingNotice } from './doing-notice/doing-notice';
57
58
 
58
59
  export const IBizCommonComponents = {
59
60
  install: (v: App): void => {
61
+ v.component(IBizBackTop.name, IBizBackTop);
60
62
  v.component(IBizKanbanSetting.name, IBizKanbanSetting);
61
63
  v.component(IBizEditorEmptyText.name, IBizEditorEmptyText);
62
64
  v.component(IBizCropping.name, IBizCropping);
@@ -31,6 +31,8 @@ import {
31
31
  IMDControlGroupState,
32
32
  DataViewControlController,
33
33
  getMDCtrlItemProvider,
34
+ filterPresetAttrs,
35
+ ScriptFactory,
34
36
  } from '@ibiz-template/runtime';
35
37
  import { createUUID } from 'qx-util';
36
38
  import draggable from 'vuedraggable';
@@ -1053,12 +1055,23 @@ export const DataViewControl = defineComponent({
1053
1055
  return renderDefaultStyle();
1054
1056
  };
1055
1057
 
1058
+ function renderAttrs(): IParams {
1059
+ const attrs: IParams = {};
1060
+ filterPresetAttrs(c.model.controlAttributes).forEach(item => {
1061
+ attrs[item.attrName!] = ScriptFactory.execSingleLine(item.attrValue!, {
1062
+ ...c.getEventArgs(),
1063
+ });
1064
+ });
1065
+ return attrs;
1066
+ }
1067
+
1056
1068
  return {
1057
1069
  c,
1058
1070
  ns,
1059
1071
  semanticClass,
1060
1072
  semanticStyle,
1061
1073
  infiniteScroll,
1074
+ renderAttrs,
1062
1075
  renderLayoutByStyle,
1063
1076
  };
1064
1077
  },
@@ -1074,6 +1087,13 @@ export const DataViewControl = defineComponent({
1074
1087
  controller={this.c}
1075
1088
  >
1076
1089
  {this.renderLayoutByStyle()}
1090
+ {this.c.state.isLoaded && this.c.showScrollTo !== 'none' && (
1091
+ <iBizBackTop
1092
+ target={this.infiniteScroll}
1093
+ mode={this.c.showScrollTo}
1094
+ {...this.renderAttrs()}
1095
+ />
1096
+ )}
1077
1097
  </iBizControlBase>
1078
1098
  </iBizControlNavigation>
1079
1099
  );
@@ -27,6 +27,8 @@ import {
27
27
  IControlProvider,
28
28
  IMDControlGroupState,
29
29
  getMDCtrlItemProvider,
30
+ ScriptFactory,
31
+ filterPresetAttrs,
30
32
  } from '@ibiz-template/runtime';
31
33
  import draggable from 'vuedraggable';
32
34
  import { showTitle } from '@ibiz-template/core';
@@ -912,6 +914,16 @@ export const ListControl = defineComponent({
912
914
  );
913
915
  };
914
916
 
917
+ function renderAttrs(): IParams {
918
+ const attrs: IParams = {};
919
+ filterPresetAttrs(c.model.controlAttributes).forEach(item => {
920
+ attrs[item.attrName!] = ScriptFactory.execSingleLine(item.attrValue!, {
921
+ ...c.getEventArgs(),
922
+ });
923
+ });
924
+ return attrs;
925
+ }
926
+
915
927
  return {
916
928
  c,
917
929
  ns,
@@ -920,6 +932,7 @@ export const ListControl = defineComponent({
920
932
  semanticStyle,
921
933
  reverseScroll,
922
934
  infiniteScroll,
935
+ renderAttrs,
923
936
  renderNoData,
924
937
  onPageChange,
925
938
  onPageRefresh,
@@ -988,6 +1001,13 @@ export const ListControl = defineComponent({
988
1001
  )
989
1002
  ) : null}
990
1003
  {!this.reverseScroll && this.renderCollapseExpandIcon()}
1004
+ {this.c.state.isLoaded && this.c.showScrollTo !== 'none' && (
1005
+ <iBizBackTop
1006
+ target={this.infiniteScroll}
1007
+ mode={this.c.showScrollTo}
1008
+ {...this.renderAttrs()}
1009
+ />
1010
+ )}
991
1011
  </iBizControlBase>
992
1012
  </iBizControlNavigation>
993
1013
  );
@@ -3,6 +3,7 @@
3
3
  /* eslint-disable no-nested-ternary */
4
4
  import { computed, defineComponent, onUnmounted, ref, watch } from 'vue';
5
5
  import { debounce } from 'lodash-es';
6
+ import { createUUID } from 'qx-util';
6
7
  import {
7
8
  useUIStore,
8
9
  useNamespace,
@@ -411,6 +412,21 @@ export const IBizInput = defineComponent({
411
412
 
412
413
  useCodeListListen(c.model.appCodeListId, c.context.srfappid, fn);
413
414
 
415
+ // 当前实例唯一标识
416
+ const curInstanceUUID = ref('');
417
+ const initCurInstanceUUID = () => {
418
+ const { predefinedType } = c.model;
419
+ if (predefinedType === 'AUTH_USERID') {
420
+ curInstanceUUID.value = 'login-username';
421
+ } else if (predefinedType === 'AUTH_PASSWORD') {
422
+ curInstanceUUID.value = 'login-password';
423
+ } else {
424
+ curInstanceUUID.value = createUUID();
425
+ }
426
+ };
427
+ // 初始化当前实例唯一标识
428
+ initCurInstanceUUID();
429
+
414
430
  return {
415
431
  c,
416
432
  ns,
@@ -430,6 +446,7 @@ export const IBizInput = defineComponent({
430
446
  currentFormatVal,
431
447
  shouldAutoComplete,
432
448
  showFormDefaultContent,
449
+ curInstanceUUID,
433
450
  onBlur,
434
451
  onFocus,
435
452
  onClick,
@@ -507,6 +524,7 @@ export const IBizInput = defineComponent({
507
524
  autocomplete={this.shouldAutoComplete}
508
525
  v-child-class={this.childClass}
509
526
  v-child-style={this.childStyle}
527
+ id={this.curInstanceUUID}
510
528
  {...this.$attrs}
511
529
  >
512
530
  {slots}
@@ -74,6 +74,23 @@ export { PanelRememberMeController } from './panel-remember-me/panel-remember-me
74
74
  export { PanelTabPanelController } from './panel-tab-panel/panel-tab-panel.controller';
75
75
  export { SearchFormButtonsController } from './searchform-buttons/searchform-buttons.controller';
76
76
  export { ViewMsgPosController } from './view-msg-pos/view-msg-pos.controller';
77
+ // 添加面板组件状态对象导出
78
+ export { ExtendMenuBase } from './app-extend-menu/extend-menu-base/extend-menu-base.state';
79
+ export { AppSwitchState } from './app-switch/app-switch.state';
80
+ export { AuthCaptchaState } from './auth-captcha/auth-captcha.state';
81
+ export { CoopPosState } from './coop-pos/coop-pos.state';
82
+ export { GlobalSearchState } from './global-search/global-search.state';
83
+ export { IndexBlankPlaceholderState } from './index-blank-placeholder/index-blank-placeholder.state';
84
+ export { NavBreadcrumbState } from './nav-breadcrumb/nav-breadcrumb.state';
85
+ export { NavTabsState } from './nav-tabs/nav-tabs.state';
86
+ export { PanelAppLoginViewState } from './panel-app-login-view/panel-app-login-view.state';
87
+ export { PanelAppTitleState } from './panel-app-title/panel-app-title.state';
88
+ export { PanelButtonListState } from './panel-button-list/panel-button-list.state';
89
+ export { PanelButtonState } from './panel-button/panel-button.state';
90
+ export { PanelContainerGroupState } from './panel-container-group/panel-container-group.state';
91
+ export { PanelRememberMeState } from './panel-remember-me/panel-remember-me.state';
92
+ export { PanelTabPanelState } from './panel-tab-panel/panel-tab-panel.state';
93
+ export { SplitContainerState } from './split-container/split-container.state';
77
94
 
78
95
  export * from './auth-userinfo';
79
96
  export * from './nav-pos-index';
@@ -1,3 +1,4 @@
1
+ import { createUUID } from 'qx-util';
1
2
  import { useNamespace, useSemanticNode } from '@ibiz-template/vue3-util';
2
3
  import { IPanelButton } from '@ibiz/model-core';
3
4
  import { defineComponent, PropType, computed, ref } from 'vue';
@@ -78,6 +79,18 @@ export const PanelButton = defineComponent({
78
79
  }
79
80
  };
80
81
 
82
+ // 当前实例唯一标识
83
+ const curInstanceUUID = ref('');
84
+ const initCurInstanceUUID = () => {
85
+ if (props.modelData && props.modelData.uiactionId === 'app_login') {
86
+ curInstanceUUID.value = 'login-submit';
87
+ } else {
88
+ curInstanceUUID.value = createUUID();
89
+ }
90
+ };
91
+ // 初始化当前实例唯一标识
92
+ initCurInstanceUUID();
93
+
81
94
  return {
82
95
  ns,
83
96
  isText,
@@ -94,6 +107,7 @@ export const PanelButton = defineComponent({
94
107
  itemStyle,
95
108
  semanticClass,
96
109
  semanticStyle,
110
+ curInstanceUUID,
97
111
  };
98
112
  },
99
113
  render() {
@@ -115,6 +129,7 @@ export const PanelButton = defineComponent({
115
129
  text={this.isText}
116
130
  data-id={this.modelData.id}
117
131
  title={showTitle(this.tooltip)}
132
+ id={this.curInstanceUUID}
118
133
  disabled={this.state.disabled}
119
134
  loading={this.state.loading}
120
135
  onClick={this.handleButtonClick}
@@ -83,28 +83,25 @@ export class AIChatUtil implements IApiAIChatUtil {
83
83
  chatOptions: IData;
84
84
  }> {
85
85
  // 容器参数
86
- const containerOptions: IData = {};
87
- // 窗口是否启用最小化
88
- if (editorParams.enableaiminimize) {
89
- containerOptions.enableAIMinimize =
90
- editorParams.enableaiminimize === 'true';
91
- }
92
- // 窗口的打开模式(禁用窗口最小化不识别)
93
- if (editorParams.openmode) {
94
- containerOptions.openMode = containerOptions.enableAIMinimize
95
- ? editorParams.openmode
96
- : 'default';
97
- } else {
98
- containerOptions.enableAIMinimize = ibiz.config.common.enableAIMinimize;
99
- }
86
+ const containerOptions: IData = {
87
+ minimizeOptions: {
88
+ enable:
89
+ editorParams.enableaiminimize === 'true' ||
90
+ ibiz.config.common.enableAIMinimize,
91
+ openMode: editorParams.openmode || 'default',
92
+ containerId:
93
+ editorParams.minimizecontainerid ||
94
+ ibiz.config.common.aiMinimizeContainerId,
95
+ },
96
+ };
100
97
  // 窗口的自动关闭模式(禁用窗口最小化不识别窗口最小化关闭模式)
101
98
  if (editorParams.autoclose) {
102
99
  try {
103
100
  const autoClose = JSON.parse(editorParams.autoclose);
104
101
  if (
105
- !containerOptions.enableAIMinimize &&
106
102
  autoClose &&
107
- autoClose.mode === 'minimize'
103
+ autoClose.mode === 'minimize' &&
104
+ !containerOptions.minimizeOptions.enable
108
105
  ) {
109
106
  autoClose.mode = 'close';
110
107
  }
@@ -852,29 +849,30 @@ export class AIChatUtil implements IApiAIChatUtil {
852
849
  chatOptions: IData;
853
850
  }> {
854
851
  // 容器参数
855
- const containerOptions: IData = {};
856
- // 窗口是否启用最小化
857
- if (params.hasOwnProperty('enableaiminimize')) {
858
- containerOptions.enableAIMinimize = params.enableaiminimize === 'true';
859
- delete params.disableminimize;
860
- } else {
861
- containerOptions.enableAIMinimize = ibiz.config.common.enableAIMinimize;
862
- }
863
- // 窗口的打开模式(禁用窗口最小化不识别)
864
- if (params.hasOwnProperty('openmode')) {
865
- containerOptions.openMode = containerOptions.enableAIMinimize
866
- ? params.openmode
867
- : 'default';
868
- delete params.openmode;
869
- }
852
+ const containerOptions: IData = {
853
+ minimizeOptions: {
854
+ enable:
855
+ params.enableaiminimize === 'true' ||
856
+ ibiz.config.common.enableAIMinimize,
857
+ openMode: params.openmode || 'default',
858
+ containerId:
859
+ params.minimizecontainerid ||
860
+ ibiz.config.common.aiMinimizeContainerId,
861
+ },
862
+ };
863
+ if (params.hasOwnProperty('enableaiminimize'))
864
+ delete params.enableaiminimize;
865
+ if (params.hasOwnProperty('openmode')) delete params.openmode;
866
+ if (params.hasOwnProperty('minimizecontainerid'))
867
+ delete params.minimizecontainerid;
870
868
  // 窗口的自动关闭模式(禁用窗口最小化不识别窗口最小化关闭模式)
871
869
  if (params.hasOwnProperty('autoclose')) {
872
870
  try {
873
871
  const autoClose = JSON.parse(params.autoclose);
874
872
  if (
875
- !containerOptions.enableAIMinimize &&
876
873
  autoClose &&
877
- autoClose.mode === 'minimize'
874
+ autoClose.mode === 'minimize' &&
875
+ !containerOptions.minimizeOptions.enable
878
876
  ) {
879
877
  autoClose.mode = 'close';
880
878
  }
@@ -212,6 +212,7 @@ export const LoginView = defineComponent({
212
212
  v-model={loginData.username}
213
213
  clearable
214
214
  placeholder={ibiz.i18n.t('app.pleaseEnterAccount')}
215
+ id='login-username'
215
216
  >
216
217
  {{
217
218
  prefix: () => <ion-icon name='person'></ion-icon>,
@@ -224,6 +225,7 @@ export const LoginView = defineComponent({
224
225
  v-model={loginData.password}
225
226
  show-password
226
227
  placeholder={ibiz.i18n.t('app.pleaseEnterPassword')}
228
+ id='login-password'
227
229
  >
228
230
  {{
229
231
  prefix: () => <ion-icon name='unlock-alt'></ion-icon>,
@@ -242,6 +244,7 @@ export const LoginView = defineComponent({
242
244
  round
243
245
  loading={loading.value}
244
246
  onKeyup={(e: KeyboardEvent) => onKeyUp(e)}
247
+ id='login-submit'
245
248
  >
246
249
  {ibiz.i18n.t('view.loginView.login')}
247
250
  </el-button>