• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BusinessError } from '@ohos.base';
17import { staffItem } from './staff';
18import Constants from '../../common/constant';
19import { AccountTipsConfig } from '../AccountTipsConfig';
20import { HiLog } from '../../common/HiLog';
21import CommonUtil from '../../common/CommonUtil';
22import AccountManager from '../../manager/AccountManager';
23import DomainAccountResponse from '../../bean/response/DomainAccountResponse';
24import AppStorageConstant from '../../common/AppStorageConstant';
25import { common } from '@kit.AbilityKit';
26import DomainAccountInfo from '../../bean/data/DomainAccountInfo';
27import EncryptProtectionShowCodeEnum from '../../common/enum/EncryptProtectionShowCodeEnum';
28import EncryptProtectionHelper from '../helper/EncryptProtectionHelper';
29
30interface Staff {
31  authAccount: string;
32  textContent: string;
33}
34
35const TAG = 'AddStaff';
36
37@Extend(Text)
38function inputMessageText() {
39  .fontSize($r('sys.float.ohos_id_text_size_body3'))
40  .lineHeight(Constants.PP_TEXT_LINE_HEIGHT2)
41  .fontColor($r('sys.color.ohos_id_color_handup'))
42  .fontWeight(FontWeight.Medium)
43  .margin({ top: Constants.ENCRYPTION_ADD_STAFF_BORDER_MARGIN_TOP })
44  .textAlign(TextAlign.Start)
45}
46
47@Component
48struct AddStaff {
49  @State succ: number = 0;
50  @State fail: number = 0;
51  @Link isAccountCheckSuccess: boolean;
52  @State staffArrayLength: boolean = false;
53  @State textContent: string = '';
54  @Link @Watch('onDataChange') staffArray: Staff[];
55  @State focusFlag: boolean = false;
56  @Prop isDisable: boolean = false;
57  @State isInitDataStatus: boolean = false;
58  @State errInput: string[] = [];
59  @State inputArray: string[] = [];
60  private controller: RichEditorController = new RichEditorController();
61  private options: RichEditorOptions = { controller: this.controller };
62
63  private shardingCount: number = 0;
64  @State @Watch('onErrorStyleChange') showFlag: boolean = false;
65  @State showCode: number = EncryptProtectionShowCodeEnum.INIT_SUCCESS;
66
67  @Builder
68  StaffItemBuilder(authAccount: string, textContent: string, index: number) {
69    Column() {
70      staffItem({
71        authAccount: authAccount,
72        textContent: textContent,
73        isActive: true,
74        changeIndex: Number(index)
75      });
76    }
77    .alignItems(HorizontalAlign.Start);
78  }
79
80  removeItem(i: number) {
81    this.staffArray.splice(i, 1)
82    this.staffArrayLength = false;
83  }
84
85  private async onSubmitMock(inputId: string, startOffset: number[], endOffset: number[]) {
86    if (!inputId) {
87      return;
88    }
89    if (this.staffArray.length >= Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX) {
90      this.staffArrayLength = true;
91      this.deleteBuildSpan(startOffset, endOffset);
92      return;
93    }
94    this.isAccountCheckSuccess = false;
95    let regex: RegExp = new RegExp('(\r|\n)*', 'g');
96    let inputString = inputId.replace(regex, '');
97    this.inputArray = inputString.split(';');
98    this.errInput = [];
99
100    await this.dealAccount(startOffset, endOffset);
101
102    this.isAccountCheckSuccess = true;
103    if (this.staffArray.length < Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX) {
104      this.controller.addTextSpan(this.errInput.join(';'));
105      if (this.showCode !== EncryptProtectionShowCodeEnum.INIT_SUCCESS) {
106        this.showFlag = true;
107      }
108    }
109  }
110
111  private async dealAccount(startOffset: number[], endOffset: number[]) {
112    HiLog.info(TAG, 'dealAccount start');
113    this.inputArray = this.inputArray.filter(item =>{
114      return !CommonUtil.isEmptyStr(item);
115    });
116    this.shardingCount = this.inputArray.length / Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX;
117    let startLine: number = 0;
118    for (let i = 0; i < this.shardingCount; i++) {
119      if (this.staffArray.length >= Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX) {
120        this.staffArrayLength = true;
121        this.errInput = [];
122        break;
123      }
124      let searchArray: string[] = this.inputArray.slice(startLine, (i + 1) * Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX);
125      let accountResponse: DomainAccountResponse | undefined =
126        await AccountManager.getDomainAccountByAccountNames(searchArray);
127      if (i === Constants.ENCRYPTION_FIRST_QUERY_BATCH) {
128        this.deleteBuildSpan(startOffset, endOffset);
129      }
130      this.dealAccountResponse(searchArray, accountResponse, startOffset, endOffset);
131
132      startLine = (i + 1) * Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX;
133    }
134    HiLog.info(TAG, 'dealAccount end');
135  }
136
137  private dealAccountResponse(searchArray: string[], accountResponse: DomainAccountResponse | undefined,
138    startOffset: number[], endOffset: number[]) {
139    let businessCode = this.getBusinessCode(accountResponse);
140    if (businessCode !== Constants.INTERFACE_SUCCESS) {
141      this.batchDealError(searchArray, startOffset, endOffset);
142      this.showCode = EncryptProtectionHelper.convertErrorCodeToShowCode(businessCode);
143      return;
144    }
145    let dataArray: Array<DomainAccountInfo> | undefined = accountResponse?.getData();
146    searchArray.forEach(accountName =>{
147      let matchAccount = dataArray?.find(
148        data => data.accountName.toLocaleUpperCase() === accountName.toLocaleUpperCase());
149      if (matchAccount) {
150        if (this.staffArray.length >= Constants.TIPS_STAFF_MAX_LENGTH) {
151          this.staffArrayLength = true;
152          return;
153        }
154        this.addStaff(matchAccount);
155        if (this.inputArray.length === Constants.RICH_EDITOR_FIRST) {
156          this.deleteBuildSpan(startOffset, endOffset);
157        }
158        this.succ = CommonUtil.increaseByAppStorageKey(AppStorageConstant.ACCOUNT_VERIFY_SUCCESS_COUNT, 1);
159        this.addBuildSpan(accountName, matchAccount[this.textContent]);
160      } else {
161        // case: not found
162        this.showErrInput(accountName, startOffset, endOffset);
163        this.showCode = EncryptProtectionShowCodeEnum.INPUT_ERROR;
164      }
165    })
166  }
167
168  private getBusinessCode(accountResponse: DomainAccountResponse | undefined): number {
169    if (accountResponse === undefined || accountResponse.getErrorCode() === Constants.ERR_CODE_NETWORK_ERROR) {
170      // case: ipc error
171      return Constants.ERR_JS_NETWORK_INVALID;
172    }
173    if (accountResponse.getErrorCode() !== Constants.INTERFACE_SUCCESS) {
174      // case: ipc success, but return error code
175      return accountResponse.getErrorCode();
176    }
177    if (CommonUtil.isEmptyArray(accountResponse.getData())) {
178      // case: ipc success, but no data
179      return Constants.ERR_JS_ACCOUNT_NOT_FOUND;
180    }
181    return Constants.INTERFACE_SUCCESS;
182  }
183
184  private addStaff(matchAccount: DomainAccountInfo): void {
185    let staff: Staff = {
186      authAccount: matchAccount.accountName.toLocaleLowerCase(),
187      textContent: matchAccount[this.textContent] as string
188    };
189    this.staffArray.push(staff);
190  }
191
192  private batchDealError(accountNameArray: string[], startOffset: number[], endOffset: number[]) {
193    accountNameArray.forEach(accountName =>{
194      this.showErrInput(accountName, startOffset, endOffset);
195    })
196  }
197
198  private deleteBuildSpan(startOffset: number[], endOffset: number[]) {
199    for (let i: number = startOffset.length - 1; i >= 0; i--) {
200      this.controller.deleteSpans({ start: startOffset[i], end: endOffset[i] });
201    }
202  }
203
204  private addBuildSpan(staffName: string, textContent: string) {
205    let index: number = this.controller.getCaretOffset();
206    let staffBuilder: CustomBuilder = () => {
207      this.StaffItemBuilder(staffName, textContent, index);
208    };
209    this.controller.addBuilderSpan(staffBuilder);
210  }
211
212  private showErrInput(staffName: string, startOffset: number[], endOffset: number[]) {
213    if (this.inputArray.length === Constants.RICH_EDITOR_FIRST) {
214      this.deleteBuildSpan(startOffset, endOffset);
215    }
216    this.errInput.push(staffName);
217    this.fail = CommonUtil.increaseByAppStorageKey(AppStorageConstant.ACCOUNT_VERIFY_FAIL_COUNT, 1);
218  }
219
220  private onDataChange() {
221    !this.isInitDataStatus && this.staffArray && this.staffArray.forEach((item: Staff, index: number) => {
222      let staffItemBuilder: CustomBuilder = () => {
223        this.StaffItemBuilder(item.authAccount, item.textContent, index);
224      };
225      this.controller.addBuilderSpan(staffItemBuilder);
226    });
227  }
228
229  private onErrorStyleChange() {
230    this.controller.updateSpanStyle({
231      textStyle: {
232        fontSize: $r('sys.float.ohos_id_text_size_body1'),
233        fontColor: this.showFlag ?
234        $r('sys.color.ohos_id_color_handup') : $r('sys.color.ohos_id_color_text_primary')
235      }
236    });
237  }
238
239  private initShowCode() {
240    this.isInitDataStatus = true;
241    this.showCode = EncryptProtectionShowCodeEnum.INIT_SUCCESS;
242    this.showFlag = false;
243  }
244
245  private dealError(inputId: string, startOffset: number[], endOffset: number[]) {
246    this.errInput = [];
247    this.deleteBuildSpan(startOffset, endOffset);
248    this.showErrInput(inputId, startOffset, endOffset);
249    this.controller.addTextSpan(this.errInput.join(';'));
250    this.showCode = EncryptProtectionShowCodeEnum.DEFAULT_ERROR;
251    this.showFlag = true;
252  }
253
254  async aboutToAppear() {
255    AccountManager.connectAbility(getContext(this) as common.UIAbilityContext);
256    await AccountTipsConfig.getConfigTips();
257    this.textContent = AccountTipsConfig.showContentKey;
258    if (this.staffArray.length) {
259      setTimeout(() => {
260        this.onDataChange();
261      }, Constants.ENCRYPTION_SET_TIMEOUT_TIME);
262    }
263  }
264
265  build() {
266    Column() {
267      Flex({
268        direction: FlexDirection.Row,
269        wrap: FlexWrap.Wrap,
270      }) {
271        RichEditor(this.options)
272          .onReady(() => {
273            this.controller.setTypingStyle({
274              fontSize: $r('sys.float.ohos_id_text_size_body1')
275            })
276          })
277          .placeholder(!this.staffArray.length ? ($r('app.string.enter_a_complete_work_ID')) : '',
278            {
279              font: { size: $r('sys.float.ohos_id_text_size_body1') },
280              fontColor: $r('sys.color.ohos_id_color_text_hint')
281            })
282          .flexGrow(Constants.ENCRYPTION_ADD_STAFF_FLEX_GROW)
283          .backgroundColor($r('sys.color.ohos_id_color_dialog_bg'))
284          .borderRadius(Constants.PP_ROW_RADIUS)
285          .align(Alignment.Center)
286          .padding({
287            top: Constants.PP_BUTTON_PAD,
288            bottom: Constants.PP_BUTTON_PAD,
289            left: Constants.PP_BUTTON_PAD,
290            right: Constants.PP_BUTTON_PAD
291          })
292          .width(Constants.FOOTER_ROW_WIDTH)
293          .constraintSize({
294            minHeight: Constants.RICH_EDITOR_MIN_HEIGHT
295          })
296          .aboutToIMEInput((value: RichEditorInsertValue) => {
297            this.isInitDataStatus = true;
298            this.initShowCode();
299            if (value.insertValue === Constants.ENTER_KEY_VALUE) {
300              let richEditorSpans: (RichEditorTextSpanResult | RichEditorImageSpanResult)[] =
301              this.controller.getSpans();
302              let inputId: string = '';
303              let startOffset: number[] = [];
304              let endOffset: number[] = [];
305              for (let index: number = 0; index < richEditorSpans.length; index++) {
306                let buildSpan: RichEditorTextSpanResult = richEditorSpans[index] as RichEditorTextSpanResult;
307                if (buildSpan.textStyle) {
308                  inputId += buildSpan.value;
309                  startOffset.push(buildSpan.spanPosition.spanRange[0]);
310                  endOffset.push(buildSpan.spanPosition.spanRange[1]);
311                  if (inputId.length > EncryptProtectionHelper.INPUT_MAX_LENGTH) {
312                    this.dealError(inputId, startOffset, endOffset);
313                    return true;
314                  }
315                }
316              }
317              if (this.isAccountCheckSuccess) {
318                this.onSubmitMock(inputId, startOffset, endOffset);
319              }
320              return false;
321            }
322            return true;
323          })
324          .aboutToDelete((value: RichEditorDeleteValue) => {
325            if (!value.richEditorDeleteSpans.length) {
326              return false;
327            };
328            this.initShowCode();
329            let richEditorSpansAll: (RichEditorTextSpanResult | RichEditorImageSpanResult)[] =
330              this.controller.getSpans();
331            let richEditorDeleteSpans: (RichEditorTextSpanResult | RichEditorImageSpanResult)[] =
332            value.richEditorDeleteSpans;
333            let len = richEditorDeleteSpans[richEditorDeleteSpans.length - 1].spanPosition.spanIndex;
334            let textNum: number = 0;
335            for (let i = 0; i <= len; i++) {
336              let buildSpan: RichEditorTextSpanResult = richEditorSpansAll[i] as RichEditorTextSpanResult;
337              if (buildSpan?.textStyle) {
338                textNum++;
339              }
340            }
341            for (let index: number = richEditorDeleteSpans.length - 1; index >= 0; index--) {
342              let buildSpan: RichEditorImageSpanResult = richEditorDeleteSpans[index] as RichEditorImageSpanResult;
343              if (buildSpan.imageStyle) {
344                let spanIndex: number = buildSpan.spanPosition.spanIndex;
345                spanIndex -= textNum;
346                this.removeItem(spanIndex);
347              } else {
348                textNum--;
349              }
350            }
351            return true;
352          })
353      }
354      .onFocus(() => {
355        this.focusFlag = !this.focusFlag;
356      })
357      .onBlur(() => {
358        this.focusFlag = !this.focusFlag;
359      })
360
361      Divider()
362        .strokeWidth(this.focusFlag ?
363        px2vp(Constants.ENCRYPTION_ADD_STAFF_BORDER2) : px2vp(Constants.ENCRYPTION_ADD_STAFF_BORDER))
364        .color((EncryptProtectionHelper.isShowErr(this.showCode, this.staffArrayLength))
365          ? $r('sys.color.ohos_id_color_handup') :
366          this.focusFlag ? $r('sys.color.ohos_id_color_primary') : $r('sys.color.ohos_id_color_list_separator'))
367        .opacity(this.focusFlag ? Constants.FOOTER_OPACITY_SEPC : Constants.FOOTER_OPACITY_ONE);
368
369      Flex({ direction: FlexDirection.Row }) {
370        if (EncryptProtectionHelper.getShowErr(this.showCode)) {
371          Text(EncryptProtectionHelper.getShowErr(this.showCode))
372            .inputMessageText()
373        }
374        Blank()
375        if (this.staffArray.length >=
376          Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX * Constants.ENCRYPTION_ADD_STAFF_LENGTH) {
377          Text(`${this.staffArray.length}/${Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX}`)
378            .fontSize($r('sys.float.ohos_id_text_size_body3'))
379            .lineHeight(Constants.PP_TEXT_LINE_HEIGHT2)
380            .fontColor(this.staffArrayLength
381              ? $r('sys.color.ohos_id_color_handup') : $r('sys.color.ohos_id_color_text_secondary'))
382            .fontWeight(FontWeight.Medium)
383            .margin({ top: Constants.ENCRYPTION_ADD_STAFF_BORDER_MARGIN_TOP })
384            .textAlign(TextAlign.End)
385        }
386      }
387    }
388    .opacity(this.isDisable ? Constants.DU_LINE_WIDTH : Constants.FOOTER_OPACITY_ONE)
389    .enabled(this.isDisable ? false : true)
390  }
391}
392
393export { AddStaff };
394