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