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 if (this.inputArray.length > Constants.RICH_EDITOR_FIRST) { 100 this.deleteBuildSpan(startOffset, endOffset); 101 } 102 103 await this.dealAccount(startOffset, endOffset); 104 105 this.isAccountCheckSuccess = true; 106 if (this.staffArray.length < Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX) { 107 this.controller.addTextSpan(this.errInput.join(';')); 108 if (this.showCode !== EncryptProtectionShowCodeEnum.INIT_SUCCESS) { 109 this.showFlag = true; 110 } 111 } 112 } 113 114 private async dealAccount(startOffset: number[], endOffset: number[]) { 115 HiLog.info(TAG, 'dealAccount start'); 116 this.inputArray.filter(item =>{ 117 return !CommonUtil.isEmptyStr(item); 118 }); 119 this.shardingCount = this.inputArray.length / Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX; 120 let startLine: number = 0; 121 for (let i = 0; i < this.shardingCount; i++) { 122 if (this.staffArray.length >= Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX) { 123 this.errInput = []; 124 break; 125 } 126 let searchArray: string[] = this.inputArray.slice(startLine, (i + 1) * Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX); 127 let accountResponse: DomainAccountResponse | undefined = 128 await AccountManager.getDomainAccountByAccountNames(searchArray); 129 this.dealAccountResponse(searchArray, accountResponse, startOffset, endOffset); 130 131 startLine = (i + 1) * Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX; 132 } 133 HiLog.info(TAG, 'dealAccount end'); 134 } 135 136 private dealAccountResponse(searchArray: string[], accountResponse: DomainAccountResponse | undefined, 137 startOffset: number[], endOffset: number[]) { 138 let businessCode = this.getBusinessCode(accountResponse); 139 if (businessCode !== Constants.INTERFACE_SUCCESS) { 140 this.batchDealError(searchArray, startOffset, endOffset); 141 this.showCode = EncryptProtectionHelper.convertErrorCodeToShowCode(businessCode); 142 return; 143 } 144 let dataArray: Array<DomainAccountInfo> | undefined = accountResponse?.getData(); 145 searchArray.forEach(accountName =>{ 146 let matchAccount = dataArray?.find( 147 data => data.accountName.toLocaleUpperCase() === accountName.toLocaleUpperCase()); 148 if (matchAccount) { 149 this.addStaff(matchAccount); 150 if (this.inputArray.length === Constants.RICH_EDITOR_FIRST) { 151 this.deleteBuildSpan(startOffset, endOffset); 152 } 153 this.succ = CommonUtil.increaseByAppStorageKey(AppStorageConstant.ACCOUNT_VERIFY_SUCCESS_COUNT, 1); 154 this.addBuildSpan(accountName, matchAccount[this.textContent]); 155 } else { 156 // case: not found 157 this.showErrInput(accountName, startOffset, endOffset); 158 this.showCode = EncryptProtectionShowCodeEnum.INPUT_ERROR; 159 } 160 }) 161 } 162 163 private getBusinessCode(accountResponse: DomainAccountResponse | undefined): number { 164 if (accountResponse === undefined || accountResponse.getErrorCode() === Constants.ERR_CODE_NETWORK_ERROR) { 165 // case: ipc error 166 return Constants.ERR_JS_NETWORK_INVALID; 167 } 168 if (accountResponse.getErrorCode() !== Constants.INTERFACE_SUCCESS) { 169 // case: ipc success, but return error code 170 return accountResponse.getErrorCode(); 171 } 172 if (CommonUtil.isEmptyArray(accountResponse.getData())) { 173 // case: ipc success, but no data 174 return Constants.ERR_JS_ACCOUNT_NOT_FOUND; 175 } 176 return Constants.INTERFACE_SUCCESS; 177 } 178 179 private addStaff(matchAccount: DomainAccountInfo): void { 180 let staff: Staff = { 181 authAccount: matchAccount.accountName.toLocaleLowerCase(), 182 textContent: matchAccount[this.textContent] as string 183 }; 184 if (this.staffArray.length >= Constants.TIPS_STAFF_MAX_WIDTH) { 185 return; 186 } 187 this.staffArray.push(staff); 188 } 189 190 private batchDealError(accountNameArray: string[], startOffset: number[], endOffset: number[]) { 191 accountNameArray.forEach(accountName =>{ 192 this.showErrInput(accountName, startOffset, endOffset); 193 }) 194 } 195 196 private deleteBuildSpan(startOffset: number[], endOffset: number[]) { 197 for (let i: number = startOffset.length - 1; i >= 0; i--) { 198 this.controller.deleteSpans({ start: startOffset[i], end: endOffset[i] }); 199 } 200 } 201 202 private addBuildSpan(staffName: string, textContent: string) { 203 let index: number = this.controller.getCaretOffset(); 204 let staffBuilder: CustomBuilder = () => { 205 this.StaffItemBuilder(staffName, textContent, index); 206 }; 207 this.controller.addBuilderSpan(staffBuilder); 208 } 209 210 private showErrInput(staffName: string, startOffset: number[], endOffset: number[]) { 211 if (this.inputArray.length === Constants.RICH_EDITOR_FIRST) { 212 this.deleteBuildSpan(startOffset, endOffset); 213 } 214 this.errInput.push(staffName); 215 this.fail = CommonUtil.increaseByAppStorageKey(AppStorageConstant.ACCOUNT_VERIFY_FAIL_COUNT, 1); 216 } 217 218 private onDataChange() { 219 !this.isInitDataStatus && this.staffArray && this.staffArray.forEach((item: Staff, index: number) => { 220 let staffItemBuilder: CustomBuilder = () => { 221 this.StaffItemBuilder(item.authAccount, item.textContent, index); 222 }; 223 this.controller.addBuilderSpan(staffItemBuilder); 224 }); 225 } 226 227 private onErrorStyleChange() { 228 this.controller.updateSpanStyle({ 229 textStyle: { 230 fontSize: $r('sys.float.ohos_id_text_size_body1'), 231 fontColor: this.showFlag ? 232 $r('sys.color.ohos_id_color_handup') : $r('sys.color.ohos_id_color_text_primary') 233 } 234 }); 235 } 236 237 private initShowCode() { 238 this.isInitDataStatus = true; 239 this.showCode = EncryptProtectionShowCodeEnum.INIT_SUCCESS; 240 this.showFlag = false; 241 } 242 243 private dealError(inputId: string, startOffset: number[], endOffset: number[]) { 244 this.errInput = []; 245 this.deleteBuildSpan(startOffset, endOffset); 246 this.showErrInput(inputId, startOffset, endOffset); 247 this.controller.addTextSpan(this.errInput.join(';')); 248 this.showCode = EncryptProtectionShowCodeEnum.DEFAULT_ERROR; 249 this.showFlag = true; 250 } 251 252 async aboutToAppear() { 253 AccountManager.connectAbility(getContext(this) as common.UIAbilityContext); 254 await AccountTipsConfig.getConfigTips(); 255 this.textContent = AccountTipsConfig.showContentKey; 256 if (this.staffArray.length) { 257 setTimeout(() => { 258 this.onDataChange(); 259 }, Constants.ENCRYPTION_SET_TIMEOUT_TIME); 260 } 261 } 262 263 build() { 264 Column() { 265 Flex({ 266 direction: FlexDirection.Row, 267 wrap: FlexWrap.Wrap, 268 }) { 269 RichEditor(this.options) 270 .onReady(() => { 271 this.controller.setTypingStyle({ 272 fontSize: $r('sys.float.ohos_id_text_size_body1') 273 }) 274 }) 275 .placeholder(!this.staffArray.length ? ($r('app.string.enter_a_complete_work_ID')) : '', 276 { 277 font: { size: $r('sys.float.ohos_id_text_size_body1') }, 278 fontColor: $r('sys.color.ohos_id_color_text_hint') 279 }) 280 .flexGrow(Constants.ENCRYPTION_ADD_STAFF_FLEX_GROW) 281 .backgroundColor($r('sys.color.ohos_id_color_dialog_bg')) 282 .borderRadius(Constants.PP_ROW_RADIUS) 283 .align(Alignment.Center) 284 .padding({ 285 top: Constants.PP_BUTTON_PAD, 286 bottom: Constants.PP_BUTTON_PAD, 287 left: Constants.PP_BUTTON_PAD, 288 right: Constants.PP_BUTTON_PAD 289 }) 290 .width(Constants.FOOTER_ROW_WIDTH) 291 .constraintSize({ 292 minHeight: Constants.RICH_EDITOR_MIN_HEIGHT 293 }) 294 .aboutToIMEInput((value: RichEditorInsertValue) => { 295 this.isInitDataStatus = true; 296 this.initShowCode(); 297 if (value.insertValue === Constants.ENTER_KEY_VALUE) { 298 let richEditorSpans: (RichEditorTextSpanResult | RichEditorImageSpanResult)[] = 299 this.controller.getSpans(); 300 let inputId: string = ''; 301 let startOffset: number[] = []; 302 let endOffset: number[] = []; 303 for (let index: number = 0; index < richEditorSpans.length; index++) { 304 let buildSpan: RichEditorTextSpanResult = richEditorSpans[index] as RichEditorTextSpanResult; 305 if (buildSpan.textStyle) { 306 inputId += buildSpan.value; 307 startOffset.push(buildSpan.spanPosition.spanRange[0]); 308 endOffset.push(buildSpan.spanPosition.spanRange[1]); 309 if (inputId.length > EncryptProtectionHelper.INPUT_MAX_LENGTH) { 310 this.dealError(inputId, startOffset, endOffset); 311 return true; 312 } 313 } 314 } 315 if (this.isAccountCheckSuccess) { 316 this.onSubmitMock(inputId, startOffset, endOffset); 317 } 318 return false; 319 } 320 return true; 321 }) 322 .aboutToDelete((value: RichEditorDeleteValue) => { 323 if (!value.richEditorDeleteSpans.length) { 324 return false; 325 }; 326 this.initShowCode(); 327 let richEditorSpansAll: (RichEditorTextSpanResult | RichEditorImageSpanResult)[] = 328 this.controller.getSpans(); 329 let richEditorDeleteSpans: (RichEditorTextSpanResult | RichEditorImageSpanResult)[] = 330 value.richEditorDeleteSpans; 331 let len = richEditorDeleteSpans[richEditorDeleteSpans.length - 1].spanPosition.spanIndex; 332 let textNum: number = 0; 333 for (let i = 0; i <= len; i++) { 334 let buildSpan: RichEditorTextSpanResult = richEditorSpansAll[i] as RichEditorTextSpanResult; 335 if (buildSpan?.textStyle) { 336 textNum++; 337 } 338 } 339 for (let index: number = richEditorDeleteSpans.length - 1; index >= 0; index--) { 340 let buildSpan: RichEditorImageSpanResult = richEditorDeleteSpans[index] as RichEditorImageSpanResult; 341 if (buildSpan.imageStyle) { 342 let spanIndex: number = buildSpan.spanPosition.spanIndex; 343 spanIndex -= textNum; 344 this.removeItem(spanIndex); 345 } else { 346 textNum--; 347 } 348 } 349 return true; 350 }) 351 } 352 .onFocus(() => { 353 this.focusFlag = !this.focusFlag; 354 }) 355 .onBlur(() => { 356 this.focusFlag = !this.focusFlag; 357 }) 358 359 Divider() 360 .strokeWidth(this.focusFlag ? 361 px2vp(Constants.ENCRYPTION_ADD_STAFF_BORDER2) : px2vp(Constants.ENCRYPTION_ADD_STAFF_BORDER)) 362 .color((EncryptProtectionHelper.isShowErr(this.showCode, this.staffArrayLength)) 363 ? $r('sys.color.ohos_id_color_handup') : 364 this.focusFlag ? $r('sys.color.ohos_id_color_primary') : $r('sys.color.ohos_id_color_list_separator')) 365 .opacity(this.focusFlag ? Constants.FOOTER_OPACITY_SEPC : Constants.FOOTER_OPACITY_ONE); 366 367 Flex({ direction: FlexDirection.Row }) { 368 if (EncryptProtectionHelper.getShowErr(this.showCode)) { 369 Text(EncryptProtectionHelper.getShowErr(this.showCode)) 370 .inputMessageText() 371 } 372 Blank() 373 if (this.staffArray.length >= 374 Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX * Constants.ENCRYPTION_ADD_STAFF_LENGTH) { 375 Text(`${this.staffArray.length}/${Constants.ENCRYPTION_ADD_STAFF_LENGTH_MAX}`) 376 .fontSize($r('sys.float.ohos_id_text_size_body3')) 377 .lineHeight(Constants.PP_TEXT_LINE_HEIGHT2) 378 .fontColor(this.staffArrayLength 379 ? $r('sys.color.ohos_id_color_handup') : $r('sys.color.ohos_id_color_text_secondary')) 380 .fontWeight(FontWeight.Medium) 381 .margin({ top: Constants.ENCRYPTION_ADD_STAFF_BORDER_MARGIN_TOP }) 382 .textAlign(TextAlign.End) 383 } 384 } 385 } 386 .opacity(this.isDisable ? Constants.DU_LINE_WIDTH : Constants.FOOTER_OPACITY_ONE) 387 .enabled(this.isDisable ? false : true) 388 } 389} 390 391export { AddStaff }; 392