import { Observable } from 'rxjs/Observable' ; import { combineLatest } from 'rxjs/observable/combineLatest' ; import { switchMap } from 'rxjs/operators/switchMap' ; import { map } from 'rxjs/operators/map' ; import { catchError } from 'rxjs/operators/catchError' ; import { ScenarioFieldConfigSchema , ScenarioFieldSchema , CustomScenarioFieldSchema , CustomFieldSchema , CustomFieldLinkSchema } from '../../schemas' ; import { SDK } from '../../SDK' ; export interface WithCustomFieldsOptions { appendCommonGroupChoices ? : boolean ; } export const withCustomFields = ( sdk , options = { } ) => ( configs$ ) : Observable < ScenarioFieldConfigSchema [ ] > => { return configs$ . pipe ( switchMap ( ( configs ) => { if ( configs . length === 0 ) { return Observable . of ( configs ) ; } return combineLatest ( configs . map ( normalizeScenarioFieldConfig ( sdk , options ) ) ) ; } ) ) ; } ; const normalizeScenarioFieldConfig = ( sdk , options ) => ( config ) : Observable < ScenarioFieldConfigSchema > => { if ( config . scenariofields . length === 0 ) { return Observable . of ( config ) ; } const scenarioFields$ = combineLatest ( config . scenariofields . map ( normalizeScenarioField ( sdk , options ) ) ) ; return scenarioFields$ . pipe ( map ( ( scenarioFields ) : ScenarioFieldConfigSchema => { return { ... config , scenariofields : scenarioFields } ; } ) ) ; } ; const normalizeScenarioField = ( sdk , options ) => ( scenarioField ) : Observable < ScenarioFieldSchema > => { if ( ! isCustomScenarioFieldSchema ( scenarioField ) ) { return Observable . of ( scenarioField ) ; } return getCustomField ( sdk , scenarioField , options ) . pipe ( map ( ( customField ) : CustomScenarioFieldSchema => { return customField ? { ... scenarioField , customfield : customField } : scenarioField ; } ) ) ; } ; /**
 * 给 ScenarioField 填充 CustomField 数据
 *
 * 后端的 getScenarioFieldConfigs/getOrgScenarioFieldConfigs 接口支持 withCustomfields 参数，
 * 当 withCustomfields=true 时，会把 CustomField 数据一并返回，挂在 scenarioField.customfield 字段上；
 * 但后端没有处理 ScenarioFieldConfig 消息推送，推送数据里还是缺少 CustomField 数据，
 * 不过后端会保证推送 CustomFieldLink 变化，因此可以依赖 scenarioField.customfield + CustomFieldLink 来解决问题，
 * 这块逻辑相当于将 ScenarioFieldConfig 跟 CustomField 和 CustomFieldLink 进行关联。
 *
 * 另：
 * 当时添加 getScenarioFieldConfigs/getOrgScenarioFieldConfigs 时，
 * 想着放在 SDK 方便使用，避免同样代码在 web、org-admin-web 各自实现一遍；
 * 后来出现一个“任务类型自定义字段预览”问题，这个问题在 web、org-admin-web 都会发生，
 * 因此决定在 SDK 这里进行修复，于是写下了这块代码；
 * 不曾想今日（2020-04-14）再来耕耘，甚是悔恨。
 */ const getCustomField = ( sdk , scenarioField , options ) : Observable < CustomFieldSchema | void > => { const empty$ = Observable . of ( [ ] ) ; const customFieldId = scenarioField . _customfieldId ; let customField$ ; let withChoices = false ; let choicesDeleted = false ; if ( scenarioField . customfield ) { let customField = scenarioField . customfield ; if ( customField . type === 'commongroup' ) { if ( options . appendCommonGroupChoices ) { withChoices = true ; } else { const { choices , ... choicesDropped } = customField ; customField = choicesDropped as CustomFieldSchema ; choicesDeleted = true ; } } customField$ = Observable . of ( customField ) ; } const customFieldPadding$ = scenarioField . customfield !== null && sdk . fetch . getCustomField ( customFieldId ) . pipe ( map ( ( resp ) => [ resp ] ) , catchError ( ( ) => { return Observable . of ( [ ] as CustomFieldSchema [ ] ) ; } ) ) ; const customFieldLink$ = sdk . getLinkByCustomFieldId ( customFieldId , { request : empty$ } ) . changes ( ) . pipe ( map ( ( [ link ] ) => { return link ? [ linkToCustomField ( link ) as CustomFieldSchema ] : [ ] ; } ) ) ; return sdk . getCustomField ( customFieldId , { request : customField$ || customFieldPadding$ || empty$ , withChoices : withChoices , padding : withChoices && customField$ ? customField$ : void 0 , } ) . changes ( ) . pipe ( switchMap ( ( [ customField ] ) => { if ( customField && ! customField . choices && choicesDeleted ) { customField = { ... customField , choices : [ ] } ; } return customField ? Observable . of ( [ customField ] ) : customFieldLink$ ; } ) , map ( ( [ customField ] ) => { return customField ? customField : void 0 ; } ) ) ; } ; const linkToCustomField = ( link ) => { return { ... link , _id : link . _customfieldId , _advancedCustomfieldId : link . advancedCustomfield ? link . advancedCustomfield . _id : null } as Partial < CustomFieldSchema > ; } ; export const isCustomScenarioFieldSchema = ( it ) : it is CustomScenarioFieldSchema => { return it . fieldType === 'customfield' ; } ;