/**
 * 新規場合、hpId ある && ir == null && name あるの場合、自動採番する
 *      hpId        取引先ID(必須)、主従関係
 *      asset_ids   AssetIDの配列
 *      name        点検報告書单号
 *
 * 編集場合
 *      asset_ids   AssetIDの配列(nullの場合、reportの明細をそのまま読み込む。空の場合は明細全部削除する)
 *      id          点検報告書ID（必須）
 *      name        点検報告書单号(必須)
 */
global class OFSInsReportLayoutController {
    private static integer SECTIONMAX = 10;
    private static integer REPORTMAX = 6;
    private static integer FIELDMAX = 100;
    private static Integer ASSETMAX = 100;
    private static Integer GROUPMAX = 900;
    // 显示数据条数限制
    private static Integer SELECT_LIMIT = 200;

    private static final String HOSPITAL_STRING = '病院';

    private String pName;
    private String pReportId;
    private String pAssetIds;
    private Id pHpId;
    private String pEventCId;

    private String oldHospital;
    private String oldStatus;
    public Boolean isPDF{get;private set;}
    private Boolean isUpDown;
    private Boolean isSubmit;
    public String alertMessage {
        private set;
        get;
    }
    public Decimal nowAssetcount {
        get;
        set;
    }
    public Decimal countorder {
        get;
        set;
    }
    public Decimal runCount;
    public List < String > assetSerialNumberList = new List < String > ();

    /*****************select option******************/
    public static List < SelectOption > textOpts {
        get;
        private set;
    }
    static {
        textOpts = new List < SelectOption > ();
        textOpts.add(new SelectOption('', '-无-'));
        textOpts.add(new SelectOption('S:Asset_situation__c', Schema.SObjectType.Asset.fields.Asset_situation__c.label));
        textOpts.add(new SelectOption('S:Name', Schema.SObjectType.Asset.fields.Name.label));
        textOpts.add(new SelectOption('S:SerialNumber', Schema.SObjectType.Asset.fields.SerialNumber.label));
        textOpts.add(new SelectOption('S:CurrentContract__r.Management_Code__c', Schema.SObjectType.Asset.fields.CurrentContract__c.label));
        textOpts.add(new SelectOption('S:Status', Schema.SObjectType.Asset.fields.Status.label));
        textOpts.add(new SelectOption('S:Installation_Site__c', Schema.SObjectType.Asset.fields.Installation_Site__c.label));
        textOpts.add(new SelectOption('S:Department_Name__c', Schema.SObjectType.Asset.fields.Department_Name__c.label));
    }
    public static List < SelectOption > equalOpts {
        get;
        private set;
    }
    static {
        equalOpts = new List < SelectOption > ();
        equalOpts.add(new SelectOption('equals', '等于'));
        equalOpts.add(new SelectOption('contains', '包含'));
    }
    public String text1 {
        get;
        set;
    } // 对象
    public String cond1 {
        get;
        set;
    } // 条件
    public String val1 {
        get;
        set;
    } // 值
    /*****************ソートキー******************/
    public String sortKey {
        get;
        set;
    }
    public String preSortKey {
        get;
        private set;
    }
    public Boolean sortOrderAsc {
        get;
        private set;
    }
    public String[] sortOrder {
        get;
        private set;
    }
    private String[] columus = new String[] {
        'Asset_situation__c',
        'Name',
        'SerialNumber',
        'CurrentContract__r.Management_Code__c',
        'Department_Name__c',
        'Status',
        'Installation_Site__c',
        'Room_Number__c',
        'InstallDate',
        'Asset_Owner__c',
        'Accumulation_Repair_Amount__c'
    };

    private Boolean isSoft;

    /*****************ソート時再検索条件（画面からの入力条件を無視するため）******************/
    private String text1ForSort = null;
    private String cond1ForSort = null;
    private String val1ForSort = null;

    public Boolean initFlag {
        get;
        private set;
    }
    //編集か新規か、判断するためにフラグ
    private Boolean editFlag {
        get;
        private set;
    }
    public List < Asset > assetList {
        get;
        private set;
    }
    public List < Inspection_Item__c > ahList {
        get;
        private set;
    }
    public Map < Asset,
    Inspection_Item__c > ahMap {
        get;
        private set;
    }
    public Map < Id,
    Inspection_Item__c > ahIdMap {
        get;
        private set;
    }
    public Map < Id,
    Integer > assetMap {
        get;
        private set;
    }
    public List < Inspection_Item__c > newAhList {
        get;
        private set;
    }
    private OFSInsReportLayout__c layout;
    private RecordType layoutRecordType; // 新規 点検報告書 の時、urlparam の rtより取得
    private String settingSoql;
    private List < Asset > assetRecords;
    public List < AssetInfo > checkedInfoList {
        get;
        set;
    }
    public List < AssetInfo > unCheckedInfoList {
        get;
        set;
    }
    public List < AssetInfo > checkedInfoListBuff {
        get;
        set;
    }
    public List < AssetInfo > unCheckedInfoListBuff {
        get;
        set;
    }
    public List < List < AssetInfo >> checkedInfoListForThousend {
        get;
        set;
    }
    public List < List < AssetInfo >> unCheckedInfoListForThousend {
        get;
        set;
    }
    public Integer ThousandFLG {
        get;
        set;
    }
    public List < List < AssetInfo >> ResultOfRefresh {
        get;
        set;
    }
    public List < SectionBean > sectionList {
        get;
        private set;
    }
    public Inspection_Report__c ir {
        get;
        private set;
    }
    // SWAG-AREBA8 start
    public Map < String,
    AssetInfo > tmpDelInfoMap {
        get;
        set;
    }
    // SWAG-AREBA8 end
    public Boolean saveOK {
        get;
        set;
    }
    public Boolean activeOn {
        get;
        set;
    }

    public Integer productCount {
        get {
            return checkedInfoList == null ? 0 : checkedInfoList.size();
        }
    }
    public Integer productCount2 {
        get {
            return unCheckedInfoList == null ? 0 : unCheckedInfoList.size();
        }
    }

    public List < Map < String,
    String >> selectedRptMapList {
        get;
        private set;
    }
    // カスタム設定
    public static Map < String,
    OFSInsReportLayout__c > oirSettingMap {
        get;
        private set;
    }
    static {
        oirSettingMap = new Map < String,
        OFSInsReportLayout__c > ();
        List < OFSInsReportLayout__c > oirList = OFSInsReportLayout__c.getall().values();
        for (OFSInsReportLayout__c oir: oirList) {
            oirSettingMap.put(oir.recordType_devName__c, oir);
        }
    }


    public string staticResource { get; private set; }
    //public boolean IsAddmessage { get; private set; }
    
    /**
    * Visaulforceから呼ばれるコンストラクタ
    */
    public OFSInsReportLayoutController(ApexPages.StandardController controller) {
        staticResource = JSON.serialize(PIHelper.getPIIntegrationInfo('Inspection_Report__c'));
}
    public OFSInsReportLayoutController() {
        countorder = 1;
        nowAssetcount = 1;
        runCount = 0;
        isUpDown = true;
        staticResource = JSON.serialize(PIHelper.getPIIntegrationInfo('Inspection_Report__c'));
    }

    // TODO 全部画面リフレッシュにする
    public void init() {
        initFlag = true;
        editFlag = false;
        text1 = '';
        cond1 = 'equals';
        val1 = null;
        isUpDown = true;
        isSoft = false;
        isPDF = false;
        isSubmit = false;
        activeOn = true;
        ThousandFLG = 0;
        // 默认排序
        this.sortKey = '0';
        this.preSortKey = '0';
        this.sortOrderAsc = true;
        this.sortOrder = new String[] {
            '↑',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            ''
        };
        // 排序用检索条件退避
        text1ForSort = '';
        cond1ForSort = 'equals';
        val1ForSort = null;

        sectionList = new List < SectionBean > ();
        assetList = new List < Asset > ();
        ahList = new List < Inspection_Item__c > ();
        checkedInfoList = new List < AssetInfo > ();
        unCheckedInfoList = new List < AssetInfo > ();
        newAhList = new List < Inspection_Item__c > ();
        assetRecords = new List < Asset > ();
        ahMap = new Map < Asset,
        Inspection_Item__c > ();
        ahIdMap = new Map < Id,
        Inspection_Item__c > ();
        assetMap = new Map < Id,
        Integer > ();
        selectedRptMapList = new List < Map < String,
        String >> ();
        // SWAG-AREBA8 start
        tmpDelInfoMap = new Map < String,
        AssetInfo > ();
        // SWAG-AREBA8 end
        pAssetIds = ApexPages.currentPage().getParameters().get('asset_ids');
        pReportId = ApexPages.currentPage().getParameters().get('id');
        pHpId = ApexPages.currentPage().getParameters().get('hpid');
        pName = ApexPages.currentPage().getParameters().get('name');
        pEventCId = ApexPages.currentPage().getParameters().get('ecid');
        String pRt = ApexPages.currentPage().getParameters().get('rt');

        List < String > assetIdList = new List < String > ();
        if (String.isBlank(pAssetIds) == false) assetIdList = pAssetIds.split('_');
        for (String aId: assetIdList) {
            assetMap.put(aId, assetMap.size());
        }

        if (String.isBlank(pReportId) == false) {
            // 点検報告書明細の編集ボタンの置き換えを対応する
            List < Inspection_Item__c > iis = [select Id, Inspection_ReportId__c from Inspection_Item__c where Id = :pReportId];
            if (iis.size() > 0) {
                pReportId = iis[0].Inspection_ReportId__c;
            }

            List < Inspection_Report__c > queryIrs = [select Id, RecordType.DeveloperName, RecordType.Name, Name, Status__c, Inspection_StartTime__c, Inspection_EndTime__c,Responsible_Person_Encrypted__c,phone_Encrypted__c,AWS_Data_Id__c from Inspection_Report__c where Id = :pReportId];
            if (queryIrs.size() <= 0) {
                initFlag = false;
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '无法找到点检报告书'));
                return;
            }
            ir = queryIrs[0];
            editFlag = true; //既存点検報告書編集
            layout = oirSettingMap.get(ir.RecordType.DeveloperName);
        }

        if (String.isBlank(pRt) != true && layout == null) {
            layout = oirSettingMap.get(pRt);
            layoutRecordType = [select Id, Name, DeveloperName from RecordType where IsActive = true and SobjectType = 'Inspection_Report__c'and DeveloperName = :pRt];
        }

        if (layout == null) {
            //error
            initFlag = false;
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '无法获取自定义设置'));
            return;
        }

        //TODO : oirSettingMapのRecordTypeは'EndoscopeSystem'しかないです
        //layout = oirSettingMap.get(ir.RecordType.DeveloperName);
        //layout = oirSettingMap.get('EndoscopeSystem');
        Map < String,
        SectionBean > sectionMap = new Map < String,
        SectionBean > ();
        for (Integer i = 1; i <= SECTIONMAX; i++) {
            String strSection = 'section' + i + '__c';
            String sectionStr = String.valueOf(layout.get(strSection));
            if (String.isBlank(sectionStr) == false) {
                SectionBean section = new SectionBean(sectionStr);
                if (i == 1) section.isTop = true;
                sectionList.add(section);
                sectionMap.put(section.id, section);
            }
        }
        List < List < String >> sectionApiList = new List < List < String >> (); // FIXME yu why not Set<String>、apiTempSet と重複しています。
        String jsonField = '';
        for (Integer i = 1; i <= FIELDMAX; i++) {
            String strI = 'field' + i + '__c';
            String jsonFieldtmp = String.valueOf(layout.get(strI));
            if (String.isBlank(jsonFieldtmp) == false) {
                jsonFieldtmp = jsonFieldtmp.trim();
                if (jsonFieldtmp.endsWith(' _')) {
                    jsonField += jsonFieldtmp.substring(0, jsonFieldtmp.length() - 2);
                    continue;
                } else {
                    jsonField += jsonFieldtmp;
                }
                SectionItem field = new SectionItem(jsonField, i);
                jsonField = ''; // 次を備えるため、'' にする
                SectionBean section = sectionMap.get(field.getSectionId());
                if (section != null) {
                    sectionApiList.add(field.getApiList()); // FIXME yu why not addAll
                    if (field.isRight()) {
                        section.rightSectionList.add(field);
                    } else {
                        section.leftSectionList.add(field);
                    }
                }
            }
        }

        this.settingSoql = 'select Id, Name, Name_Manual__c, Next_StartHour_Page__c, Next_StartMinute_Page__c, Next_EndHour_Page__c, Next_EndMinute_Page__c,Responsible_Person_Encrypted__c,phone_Encrypted__c,AWS_Data_Id__c '
        // fxk 2021/8/4 新加 Start
        + ' , Remarks__c, CleaningFluid__c,SterilizationMethod__c,Disinfectant__c,UsedMachine__c,Used_ET__c ,Mode__c';
        // fxk 2021/8/4 新加 End
        // 重複な項目を追加しないためのセット
        Set < String > apiTempSet = new Set < String > ();
        apiTempSet.add('Id');
        apiTempSet.add('Name');
        apiTempSet.add('Name_Manual__c');
        apiTempSet.add('Next_StartHour_Page__c');
        apiTempSet.add('Next_StartMinute_Page__c');
        apiTempSet.add('Next_EndHour_Page__c');
        apiTempSet.add('Next_EndMinute_Page__c');
        for (List < String > apiList: sectionApiList) {
            for (String apiStr: apiList) {
                if (String.isBlank(apiStr) == false && apiTempSet.contains(apiStr) == false) {
                    this.settingSoql += ', ';
                    this.settingSoql += apiStr;
                    apiTempSet.add(apiStr);
                }
            }
        }
        //TODO: timecheckflag
        if (apiTempSet.contains('NextInspection_Day__c') == true) {

}
        if (apiTempSet.contains('Inspection_Date__c') == true) {

}

        // 图表reportの読み込むロジック、InsReportにはないです
        String idSoql = this.settingSoql + ' from Inspection_Report__c where Id = :pReportId';
        String nameSoql = this.settingSoql + ' from Inspection_Report__c where Name = :pName';

        if (String.isBlank(pReportId) == false) {
            //pReportIdで検索
            List < Inspection_Report__c > idQueryResults = Database.query(idSoql);
            //if (id検索結果ある)
            if (idQueryResults.size() == 1) {
                Inspection_Report__c irTmp = idQueryResults[0];
                if (String.isBlank(pName) == true || (String.isBlank(pName) == false && irTmp.Name == pName)) {
                    ir = irTmp;
                    editFlag = true; //既存点検報告書編集
                } //else: pNameが値ある、及びid検索結果とpNameが違う、irを作らない
                if (ir == null) {
                    //errorMsg
                    ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '无法找到点检报告书'));
                    return;
                } //else: irできった
            } //else: ir検索結果がない、下記のnameのif文に入る
        } //else: pReportIdがないと、ir検索できない、下記のnameのif文に入る
        if (String.isBlank(pName) == false && ir == null) {
            //nameで検索
            List < Inspection_Report__c > nameQueryResults = Database.query(nameSoql);
            //if (name検索結果ある)
            if (nameQueryResults.size() == 1) {
                ir = nameQueryResults[0];
                editFlag = true; //既存点検報告書編集
            } //else: ir検索結果がない、下記のpHpIdのif文に入る
        } //else: pNameがない、下記のpHpIdのif文に入る、あるいはirが既にできった
        if (ir != null) {
            //点検報告書にすでにある明細をahMapに入れる
            //urlにはpAssetIdsというパラメーターがある、pAssetIdsと点検報告書と両方とも条件として、明細を検索する
            if (pAssetIds != null) {
                ahList = [Select Id, Name, AssetId__r.Id, AssetId__r.Asset_situation__c, AssetId__r.Name, AssetId__r.Final_Examination_Date__c, AssetId__r.After_repair_last_internal_check_day__c, AssetId__r.Hospital__r.Id, AssetId__r.Hospital__r.Name, AssetId__r.Department_Class__r.Id, AssetId__r.Department_Class__r.Name, AssetId__r.Account.Id, AssetId__r.Account.Name, AssetId__r.SerialNumber, AssetId__r.CurrentContract__c, AssetId__r.CurrentContract__r.Management_Code__c, AssetId__r.Department_Name__c, AssetId__r.Status, AssetId__r.Installation_Site__c, AssetId__r.Room_Number__c, AssetId__r.InstallDate, AssetId__r.Asset_Owner__c, AssetId__r.Accumulation_Repair_Amount__c, AssetId__c, Inspection_ReportId__c, SerialNumber__c, Diagnosis__c, FaultNumber__c, Behavior__c, IsContinueUse__c, SerialNo_Manual__c, Fault_Classification1__c, Fault_Classification2__c, ItemStatus__c, Fault_Classification3__c, Product_Manual__c, Inspection_Result__c, Inspection_Comment__c,Abandonment_Reasons__c from Inspection_Item__c Where AssetId__c in :assetIdList and Inspection_ReportId__c = :ir.Id order by Name];
                //urlにはpAssetIds=null、点検報告書の明細を変更しない、全部読み込んで
            } else {
                ahList = [Select Id, Name, AssetId__r.Id, AssetId__r.Asset_situation__c, AssetId__r.Name, AssetId__r.Final_Examination_Date__c, AssetId__r.After_repair_last_internal_check_day__c, AssetId__r.Hospital__r.Id, AssetId__r.Hospital__r.Name, AssetId__r.Department_Class__r.Id, AssetId__r.Department_Class__r.Name, AssetId__r.Account.Id, AssetId__r.Account.Name, AssetId__r.SerialNumber, AssetId__r.CurrentContract__c, AssetId__r.CurrentContract__r.Management_Code__c, AssetId__r.Department_Name__c, AssetId__r.Status, AssetId__r.Installation_Site__c, AssetId__r.Room_Number__c, AssetId__r.InstallDate, AssetId__r.Asset_Owner__c, AssetId__r.Accumulation_Repair_Amount__c, AssetId__c, Inspection_ReportId__c, SerialNumber__c, Diagnosis__c, FaultNumber__c, Behavior__c, IsContinueUse__c, SerialNo_Manual__c, Fault_Classification1__c, Fault_Classification2__c, ItemStatus__c, Fault_Classification3__c, Product_Manual__c, Inspection_Result__c, Inspection_Comment__c,Abandonment_Reasons__c from Inspection_Item__c Where Inspection_ReportId__c = :ir.Id order by Name];
            }
            for (Inspection_Item__c ah: ahList) {
                if (ah.AssetId__c != null) {
                    ahMap.put(ah.AssetId__r, ah);
                    ahIdMap.put(ah.AssetId__c, ah);
                } else {
                    newAhList.add(ah);
                }
            }
        } else if (String.isBlank(pHpId) == false && ir == null) {
            List < Account > queryAccs = [select Id, Name, ParentId, Parent.ParentId, Parent.Parent.RecordType.DeveloperName, Parent.RecordType.DeveloperName, RecordType.DeveloperName, RecordType.Name from Account where Id = :pHpId];
            if (queryAccs.size() <= 0) {
                initFlag = false;
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '无法找到医院'));
                return;
            } else {
                Account tempacc = queryAccs[0];
                //点検報告書を新規する
                ir = new Inspection_Report__c();
                editFlag = false; //点検報告書新規
                if (tempacc.RecordType.DeveloperName == 'HP') {
                    //医院
                    ir.Hospital__c = tempacc.Id;
                } else if (tempacc.Parent.RecordType.DeveloperName == 'HP') {
                    //战略科室
                    ir.Hospital__c = tempacc.ParentId;
                } else if (tempacc.Parent.Parent.RecordType.DeveloperName == 'HP') {
                    //科室
                    ir.Hospital__c = tempacc.Parent.ParentId;
                    ir.Department__c = tempacc.Id;
                    ir.Manual_Department__c = tempacc.Name;
                }
            }

            //新規する時、nameがないと、irのNo.を自動採番する
            if (String.isBlank(pName) == true) {
                makeIrNo();
                //nameがあれば、irに入れる
            } else {
                ir.Name = pName;
            }
        } else {
            ir = new Inspection_Report__c();
            editFlag = false;
        }

        if (ir == null) {
            //error message
            initFlag = false;
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '参数错误'));
            return;
        }

        // 新規時デフォルト値設定
        if (ir.Id == null) {
            ir.Inspection_Date__c = Date.today();
            ir.Reporter__c = UserInfo.getUserId();
            ir.RecordTypeId = layoutRecordType.Id;
        }

        //signFlg = String.isBlank(ir.ResponsiblePerson_Sign__c) ? false : true;
        //irName = ir.Name;
        if (editFlag == false) ir.Status__c = '草案中';
        assetSerialNumberList.clear();
        getAssetSerialNumber();
        String soqlconfim = this.makeSoqlconfim();
        List < Asset > assetRecordsconfim = Database.query(soqlconfim);
        if (assetRecordsconfim.size() > Integer.valueOf(System.Label.Asset_Maxcount)) {
            //alertMessage = '未选保有设备行数' + assetRecordsconfim.size();
            makePageNo(assetRecordsconfim.size());
        }
        // 病院から保有设备を取得
        this.getAssetFromHp();
    }

    public PageReference addNewRows() {
        for (Integer i = 0; i < 10; i++) {
            checkedInfoList.add(new AssetInfo(checkedInfoList.size()));
        }
        return null;
    }

    public void makeIrNo() {
        Savepoint sp = Database.setSavepoint();
        ir.Name = '*';

        try {
            insert(this.ir);
        } catch(Exception e) {
            ApexPages.addMessages(e);
        }
        String idstr = ir.Id;
        String soql = this.settingSoql + ' from Inspection_Report__c where Id = :idstr';
        List < Inspection_Report__c > irQueryResults = Database.query(soql);
        if (irQueryResults.size() > 0) {
            ir = irQueryResults[0];
        } else {
            //error
        }
        // 強制ロールバック
        Database.rollback(sp);
        // upsertのために。idを削除
        ir.Id = null;
    }

    /**
    * 選択済み／未選択製品の置き換え
    */
    public PageReference exchangeAsset() {
        isUpDown = false;
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, 'unCheckedInfoList+++++++++++++ size： ' + unCheckedInfoList.size()));
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, 'unCheckedInfoListForThousend+++++++++++++ size： ' + unCheckedInfoListForThousend.size()));
        
        System.debug('exchangeAsset start');
        // 病院変更チェック
        if (!this.checkHpChange()) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '保有设备的医院与点检报告书的医院不符，请点击刷新按钮重新取得保有设备。'));
            return null;
        }
        Date systemToday = System.today();
        List < AssetInfo > tmpChecked = new List < AssetInfo > ();
        List < AssetInfo > tmpNewRows = new List < AssetInfo > ();
        List < AssetInfo > tmpUnChecked = new List < AssetInfo > ();
        for (AssetInfo ass: this.checkedInfoList) {
            if (ass.isManual) {
                tmpNewRows.add(ass);
            } else {
                if (ass.rec_checkBox_c) {
                    tmpChecked.add(ass);
                    system.debug('=====uncheck SerialNumber1:' + ass.rec.SerialNumber);
                } else {
                    tmpUnChecked.add(ass);
                }
            }
        }
        // for (AssetInfo Ai: unCheckedInfoList) {
        //     if (Ai.rec_checkBox_c) {
        //         ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '+++++++++++++++： ' + Ai.rec.SerialNumber));
        //         system.debug('=====uncheck SerialNumber1:' + Ai.rec.SerialNumber);
        //     }
        // }
        // for (List < AssetInfo > Li: unCheckedInfoListForThousend) {
        //     for (AssetInfo Ai: Li) {
        //         if (Ai.rec_checkBox_c) {
        //             ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '---------------： ' + Ai.rec.SerialNumber));
        //             system.debug('=====uncheck SerialNumber2:' + Ai.rec.SerialNumber);
        //         }
        //     }
        // }
        
        if (ThousandFLG > 0) {
            this.unCheckedInfoList.clear();
            for (List < AssetInfo > Li: unCheckedInfoListForThousend) {
                for (AssetInfo Ai: Li) {
                    ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '---------------： ' + Ai.rec.SerialNumber));
                    unCheckedInfoList.add(Ai);
                }
            }
        }
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, 'unCheckedInfoList size： ' + unCheckedInfoList.size()));
        for (AssetInfo ass: this.unCheckedInfoList) {
            if (ass.rec_checkBox_c) {
                system.debug('=====uncheck SerialNumber3:' + ass.rec.SerialNumber);
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '3333333333333： ' + ass.rec.SerialNumber));
                tmpChecked.add(ass);
            } else {
                tmpUnChecked.add(ass);
            }
        }
        for (List < AssetInfo > Li: unCheckedInfoListForThousend) {
            for (AssetInfo Ai: Li) {
                if (Ai.rec_checkBox_c) {
                    ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '4444444444444444 ' + Ai.rec.SerialNumber));
                    system.debug('=====uncheck SerialNumber4:' + Ai.rec.SerialNumber);
                }
            }
        }
        // return null;
        this.checkedInfoList = new List < AssetInfo > ();
        for (AssetInfo ass: tmpChecked) {
            ass.lineNo = this.checkedInfoList.size();
            this.checkedInfoList.add(ass);
            // SWAG-AREBA8 start
            if (tmpDelInfoMap.containsKey(ass.rec.Id) == true) {
                tmpDelInfoMap.remove(ass.rec.Id);
            }
            // SWAG-AREBA8 end
        }
        for (AssetInfo ass: tmpNewRows) {
            ass.lineNo = this.checkedInfoList.size();
            this.checkedInfoList.add(ass);
        }

        this.unCheckedInfoList = new List < AssetInfo > ();
        this.unCheckedInfoList.addAll(tmpUnChecked);
        // SWAG-AREBA8 start
        for (AssetInfo uncheck: unCheckedInfoList) {
            if (tmpDelInfoMap.containsKey(uncheck.rec.Id) == false) {
                tmpDelInfoMap.put(uncheck.rec.Id, uncheck);
            }
        }
        // SWAG-AREBA8 end
        if (ThousandFLG > 0) {
            unCheckedInfoListForThousend.clear();
            List < AssetInfo > bufflist = new List < AssetInfo > ();
            for (AssetInfo ainfo: unCheckedInfoList) {
                bufflist.add(ainfo);
                if (bufflist.size() == GROUPMAX) {
                    unCheckedInfoListForThousend.add(bufflist);
                    bufflist.clear();
                }
            }
            unCheckedInfoListForThousend.add(bufflist);
        }
        getAssetFromHp();
        return null;
    }

    public PageReference showPDF() {
        alertMessage = '';
        isPDF = true;
        save();
        if (saveOK) {
            PageReference pageRef = new PageReference('/apex/InsReportPDFOuter?id=' + ir.Id);
            pageRef.setRedirect(true);
            return pageRef;
        } else {
            ir.Status__c = oldStatus;
        }
        return null;
    }
    //   20201209 liying  JPH-BVW4MJ start
    public PageReference showPDF1() {
        alertMessage = '';
        isPDF = true;
        //   20201216 liying  JPH-BVW4MJ start
        if (ir.Status__c != '申请中' && ir.Status__c != '批准') {
            save();
            if (saveOK) {
                PageReference pageRef = new PageReference('/apex/InsReportPDF?id=' + ir.Id);
                pageRef.setRedirect(true);
                return pageRef;
            } else {
                ir.Status__c = oldStatus;
            }
        } else {
            PageReference pageRef = new PageReference('/apex/InsReportPDF?id=' + ir.Id);
            //pageRef.setRedirect(true);
            return pageRef;
        }
        //   20201216 liying  JPH-BVW4MJ end
        return null;
    }
    //   20201209 liying  JPH-BVW4MJ end
    public PageReference submit() {
        alertMessage = '';
        isSubmit = true;
        Savepoint sp = Database.setSavepoint();
        save();
        if (saveOK) {
            try {
                // 承認プロセス
                Approval.ProcessSubmitRequest psr = new Approval.ProcessSubmitRequest();
                Id ir_id = ir.id;
                psr.setObjectId(ir.id);
                Approval.ProcessResult submitResult = Approval.process(psr);
                ir = Database.query(this.settingSoql + ' from Inspection_Report__c where Id = :ir_id');
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '报告书已提交'));
            } catch(Exception ex) {
                Database.rollback(sp);
                ir.Status__c = oldStatus;
                ApexPages.addMessages(ex);
                return null;
            }
        } else {
            ir.Status__c = oldStatus;
        }
        return null;
    }

    public PageReference saveBtn() {
        isPDF = false;
        isSubmit = false;
        save();
        if (saveOK) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '保存好了'));
        } else {
            ir.Status__c = oldStatus;
        }
        return null;
    }

    /**
    * 保存
    */
    public PageReference save() {
        alertMessage = '';
        System.debug('OFSInsReportLayoutController save start');
        saveOK = false;
        oldStatus = ir.Status__c;
        Boolean isIrNew = (ir.Id == null) ? true: false;
        // 保有設備のチェックは入力規則（Is_Same_Hospital）がやる
        /*
        if (!this.checkHpChange()) {
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '已选保有设备字段历史中已有数据的时候，不能更改医院。'));
        return null;
        }
        */
        //add by rentx 20210630
        //错误信息展示
        Boolean isError = false;
        for (AssetInfo ai: checkedInfoList) {
            //之前的逻辑不变 只是做一个判断 
            // if (ai.isNew == true) {
                //设备状态 NG时 故障描述必填
                if (ai.ah.ItemStatus__c == 'NG' && String.isBlank(ai.ah.Diagnosis__c)) {
                    isError = true;
                    ai.ah.Diagnosis__c.addError('设备状态NG时,请填写故障描述!');
                }
                //设备状态 医院放弃时 放弃理由必填
                if (ai.ah.ItemStatus__c == '医院放弃' && (ai.ah.Abandonment_Reasons__c == null || ai.ah.Abandonment_Reasons__c == '')) {
                    isError = true;
                    ai.ah.Abandonment_Reasons__c.addError('设备状态为医院放弃时,请填写放弃理由!');
                }
            // }

        }
        
        if (isError) {
            system.debug('795'+ir.AWS_Data_Id__c);
            return null;
        }
        system.debug('798'+ir.AWS_Data_Id__c);
        //add by rentx 20210630
        if (timeCheck() != true) {
            system.debug('800');
            return null;
        }

        system.debug('804');
        if (isPDF) {
            ir.Status__c = 'PDF';
        }

        if (isSubmit) {
            ir.Status__c = '填写完毕';
        }

        system.debug('813');
        Savepoint sp = Database.setSavepoint();
        try {
            // 部长经理总监
            if (ir.Reporter__c != null) {
                User target = [SELECT Id, Name, SalesManager__c, BuchangApprovalManagerSales__c, JingliApprovalManager__c, BuchangApprovalManager__c, ZongjianApprovalManager__c FROM User WHERE Id = :ir.Reporter__c];
                ir.SalesManager__c = target.SalesManager__c == null ? target.Id: target.SalesManager__c;
                ir.BuchangApprovalManagerSales__c = target.BuchangApprovalManagerSales__c == null ? target.Id: target.BuchangApprovalManagerSales__c;
                ir.JingliApprovalManager__c = target.JingliApprovalManager__c == null ? target.Id: target.JingliApprovalManager__c;
                ir.BuchangApprovalManager__c = target.BuchangApprovalManager__c == null ? target.Id: target.BuchangApprovalManager__c;
                ir.ZongjianApprovalManager__c = target.ZongjianApprovalManager__c == null ? target.Id: target.ZongjianApprovalManager__c;
            }
            OFSInsReportAssetHistoryController.upsertInspection_Report(ir);
        } catch(Exception e) {
            clearIrId(sp, e, isIrNew);
            system.debug('829');
            return null;
        }

        system.debug('832');
        // 日報からくる場合、保存時、EventCに書き戻す
        if (String.isBlank(pEventCId) == false) {
            try {
                Event__c ec = new Event__c(Id = pEventCId, InsReport_ID__c = ir.Id);
                update ec;
            } catch(Exception e) {
                clearIrId(sp, e, isIrNew);
                system.debug('840');
                return null;
            }
        }
        system.debug('844');
        //List<Inspection_Item__c> toUpsertAhs = new List<Inspection_Item__c>();
        List < Inspection_Item__c > toDeleteAhs = new List < Inspection_Item__c > ();
        List < Inspection_Item__c > manualDeleteAhs = new List < Inspection_Item__c > ();
        Map < Inspection_Item__c,
        AssetInfo > toUpsertAhsMap = new Map < Inspection_Item__c,
        AssetInfo > ();
        for (AssetInfo ai: checkedInfoList) {
            // 空行、製品を選択しない場合
            if (ai.isManual == true && ai.ah.Product_Manual__c == null) {
                // Idあれば削除
                if (ai.ah.Id != null) {
                    manualDeleteAhs.add(ai.ah);
                }
            }
            // データあり
            else {
                // 主従関係なので、新規の時のみInspection_ReportId__cを設定
                if (ai.isNew == true) {
                    ai.ah.Inspection_ReportId__c = ir.Id;
                }
                // TODO 明細を新規する時、名前を設定
                //toUpsertAhs.add(ai.ah);
                toUpsertAhsMap.put(ai.ah, ai);
                system.debug('OFSInsReportLayoutController save toUpsertAhs:' + ai.ah.Id);
            }

        }
        // next event操作
        //---------------- HWAG-AVT9ZU 取消自动创建报告操作
        //if(handleEvent() == false) return null;
        List < Id > unCheckedAssetIds = new List < Id > ();
        // SWAG-AREBA8 start
        //for (AssetInfo ai :unCheckedInfoList) {
        for (AssetInfo ai: tmpDelInfoMap.values()) {
            unCheckedAssetIds.add(ai.rec.Id);
        }
        // SWAG-AREBA8 end
        toDeleteAhs = [select Id, AssetId__c from Inspection_Item__c where AssetId__c in :unCheckedAssetIds and Inspection_ReportId__c = :ir.Id];

        system.debug('884');
        try {
            if (manualDeleteAhs.size() > 0) toDeleteAhs.addAll(manualDeleteAhs);
            OFSInsReportAssetHistoryController.deleteInspection_Item(ir, toDeleteAhs);
        } catch(Exception e) {
            clearIrId(sp, e, isIrNew);
            system.debug('890');
            return null;
        }

        system.debug('894');
        try {
            //OFSInsReportAssetHistoryController.upsertInspection_Item(ir, toUpsertAhs);
            OFSInsReportAssetHistoryController.upsertInspection_Item(ir, new List < Inspection_Item__c > (toUpsertAhsMap.keySet()));
        } catch(Exception e) {
            clearIrId(sp, e, isIrNew);
            for (Inspection_Item__c ah: toUpsertAhsMap.keySet()) {
                if (toUpsertAhsMap.get(ah).isNew == true) ah.Id = null;
            }
            system.debug('903');
            return null;
        }

        system.debug('905');
        saveOK = true;
        this.init();
        return null;
    }
    // save時、Excptionが発生した時の共通処理
    private void clearIrId(Savepoint sp, Exception e, Boolean isIrNew) {
        if (isIrNew) ir.Id = null;
        Database.rollback(sp);
        ApexPages.addMessages(e);
        //IsAddmessage = true;
    }

    private Boolean checkHpChange() {
        Boolean hasCheckdInfo = false;
        for (AssetInfo ai: this.checkedInfoList) {
            if (ai.rec != null) {
                hasCheckdInfo = true;
                break;
            }
        }

        if (this.oldHospital != ir.Hospital__c && hasCheckdInfo == true) {
            return false;
        }

        return true;
    }

    public void makePageNo(Integer assetReCount) {
        nowAssetcount = 1;
        Integer aaa = 1;
        integer mods = math.mod(assetReCount, Integer.valueOf(System.Label.Asset_Maxcount));
        if (mods == 0) {
            aaa = assetReCount / Integer.valueOf(System.Label.Asset_Maxcount);
        } else {
            aaa = assetReCount / Integer.valueOf(System.Label.Asset_Maxcount) + 1;
        }

        nowAssetcount = aaa;
        //alertMessage = 'assetReCount +++' + assetReCount   + 'countorder' + countorder;
        if (countorder > nowAssetcount) {
            countorder = 1;
        }
    }

    // 取已选择资产的机身编码
    public void getAssetSerialNumber() {
        assetSerialNumberList = new List < String > ();
        assetSerialNumberList.clear();
        for (AssetInfo ai: this.checkedInfoList) {
            if (String.isNotEmpty(ai.ah.SerialNumber__c)) {
                assetSerialNumberList.add(ai.ah.SerialNumber__c);
            }
        }
    }
    // 下翻页
    public void DownPage() {
        isUpDown = false;
        if (countorder < nowAssetcount) {
            countorder++;
        }
        getAssetFromHp();
    }
    // 上翻页
    public void UpPage() {
        isUpDown = false;
        if (countorder == 1) {} else if (countorder <= nowAssetcount) {
            countorder--;
        }
        getAssetFromHp();
    }

    public void getAssetFromHp() {
        runCount++;
        assetSerialNumberList.clear();
        getAssetSerialNumber();
        // hpId ある && ir == null && name あるの場合、自動採番する
        if (ir.Id == null && ir.Name == null && ir.Hospital__c != null) {
            makeIrNo();
        }
        unCheckedInfoListBuff = new List < AssetInfo > ();
        checkedInfoListBuff = new List < AssetInfo > ();
        unCheckedInfoListForThousend = new List < List < AssetInfo >> ();
        checkedInfoListForThousend = new List < List < AssetInfo >> ();
        this.oldHospital = ir.Hospital__c;
        if (isUpDown) {
            checkedInfoList = new List < AssetInfo > ();
            // 上のリストには、明細を全部入れよう
            for (Asset ar: ahMap.keySet()) {
                checkedInfoList.add(new AssetInfo(checkedInfoList.size(), ar, ahMap.get(ar)));
            }
        }

        unCheckedInfoList = new List < AssetInfo > ();
        String soqlconfim = this.makeSoqlconfim();
        List < Asset > assetRecordsconfim = Database.query(soqlconfim);
        //alertMessage = '未选保有设备行数' + assetRecordsconfim.size();
        makePageNo(assetRecordsconfim.size());
        // 取引先に繋がっている全部保有设备
        String soql = this.makeSoql();
        System.debug('soql +++++++' + soql);
        assetRecords = Database.query(soql);
        // 分页：因为集合变量在页面不能显示包含1000的元素，故分页实现；
        if (assetRecords.size() > 0) {
            for (Asset ar: assetRecords) {
                //urlの中のassetIdsがない、明細を変更しない
                if (pAssetIds == null) {
                    //点検報告書にすでにある明細
                    if (ahIdMap.containsKey(ar.Id) == true) {
                        //checkedInfoList.add(new AssetInfo(checkedInfoList.size(), ar, ahMap.get(ar.Id)));
                        //他のAssetを全部未チェックリストにする
                    } else {
                        unCheckedInfoList.add(new AssetInfo(unCheckedInfoList.size(), ar));
                        unCheckedInfoListBuff.add(new AssetInfo(unCheckedInfoList.size(), ar));
                        if (unCheckedInfoListBuff.size() == GROUPMAX) {
                            unCheckedInfoListForThousend.add(unCheckedInfoListBuff);
                            unCheckedInfoListBuff = new List < AssetInfo > ();
                            system.debug('unCheckedInfoList###########' + unCheckedInfoList.size());
                        }

                    }
                } else {
                    //urlの中のassetIdsをチェックする
                    if (assetMap.containsKey(ar.Id) == true) {
                        //点検報告書にすでにある明細
                        if (ahIdMap.containsKey(ar.Id) == true) {
                            //checkedInfoList.add(new AssetInfo(checkedInfoList.size(), ar, ahMap.get(ar.Id)));
                            //明細を新規する
                        } else {
                            checkedInfoList.add(new AssetInfo(checkedInfoList.size(), ar, ir));
                            checkedInfoListBuff.add(new AssetInfo(checkedInfoList.size(), ar, ir));
                            if (checkedInfoListBuff.size() == GROUPMAX) {
                                checkedInfoListForThousend.add(checkedInfoListBuff);
                                checkedInfoListBuff = new List < AssetInfo > ();
                            }
                        }
                        //他のAssetを全部未チェックリストにする
                    } else {
                        unCheckedInfoList.add(new AssetInfo(unCheckedInfoList.size(), ar));
                        unCheckedInfoListBuff.add(new AssetInfo(unCheckedInfoList.size(), ar));
                        if (unCheckedInfoListBuff.size() == GROUPMAX) {
                            unCheckedInfoListForThousend.add(unCheckedInfoListBuff);
                            unCheckedInfoListBuff = new List < AssetInfo > ();
                            system.debug('unCheckedInfoList###########' + unCheckedInfoList.size());
                        }
                    }
                }
            }
        }

        system.debug('unCheckedInfoListForThousend::::' + unCheckedInfoListForThousend);
        system.debug('unCheckedInfoList::::' + unCheckedInfoList.size());
        if (unCheckedInfoListForThousend != null) {
            ThousandFLG = unCheckedInfoListForThousend.size();
            checkedInfoListForThousend.add(checkedInfoListBuff);
            unCheckedInfoListForThousend.add(unCheckedInfoListBuff);
            //ThousandFLG = unCheckedInfoListForThousend.size();
        }
        system.debug('ThousandFLG::::' + ThousandFLG);
        if (isUpDown) {
            for (Inspection_Item__c ah: newAhList) {
                checkedInfoList.add(new AssetInfo(checkedInfoList.size(), ah));
            }
        }
        // 最後10行追加
        if (Schema.getGlobalDescribe().get('Inspection_Item__c').getDescribe().isCreateable() && isUpDown) {
            this.addNewRows();
        }
    }

    /*private Boolean handleEvent() {
    List<Inspection_Report__c> irQueryResults = [select NextInspection_Day__c, Inspection_Date__c, Next_StartTime__c, Next_EndTime__c
                              , Department__r.id, Department__r.Name, Hospital__r.Name
                              , Manual_Department__c, Name, Id, Event_ID__c
                             from Inspection_Report__c
                            where Id = :ir.Id];
    if (irQueryResults.size() < 0) {
      return false;
    }
    Inspection_Report__c insReport = irQueryResults[0];

    if (insReport.Next_StartTime__c == null
      || insReport.Next_EndTime__c == null
      || insReport.NextInspection_Day__c == null) {
      return true;
    }

    Event e = null;//event初期化
    //画面上は点検報告書新規の場合
    if (this.editFlag == false) {
      e = new Event();
    //画面上は既存点検報告書編集の場合
    } else {
      List< Event> eList = [ select id from Event where Id =:insReport.Event_ID__c];
      if (eList.size()>0) {
        e = eList[0];
      } else {
        //error
        //ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '没有找到相关联的活动'));
        return true;
      }
      if (insReport.Next_StartTime__c == null
        || insReport.Next_EndTime__c == null
        || insReport.NextInspection_Day__c == null) {
        try {
          delete e;
        } catch (Exception ex) {
          ApexPages.addmessages(ex);
          return false;
        }
      }
    }

    e.OwnerId = UserInfo.getUserId();
    e.ActivityDate = insReport.NextInspection_Day__c;
    e.StartDateTime = insReport.Next_StartTime__c;
    e.EndDateTime = insReport.Next_EndTime__c;
    e.Activity_Type2__c = HOSPITAL_STRING;
    e.Subject = '设备点检(上次点检单号:' + insReport.Name + ')';

    if (insReport.Department__c != null) {
      e.whatid__c = insReport.Department__r.id;
      e.Location = insReport.Department__r.Name;
    }
    if (String.isBlank(e.Location) == true) {
      e.Location = insReport.Hospital__r.Name + insReport.Manual_Department__c;
    }

    try {
      upsert e;
      insReport.Event_ID__c = e.Id;
      update insReport;
    } catch (Exception ex) {
      ApexPages.addmessages(ex);
      return false;
    }
    return true;
    }*/

    private Boolean timeCheck() {
        //TODO timeのフォーマットをチェック,入力規則にするかな
        try {
            if (ir.Inspection_Date__c != null && ir.StartHour_Page__c != null && ir.StartMinute_Page__c != null && ir.EndHour_Page__c != null && ir.EndMinute_Page__c != null) {
                ir.Inspection_StartTime__c = Datetime.newInstance(ir.Inspection_Date__c.year(), ir.Inspection_Date__c.month(), ir.Inspection_Date__c.day(), Integer.valueOf(ir.StartHour_Page__c), Integer.valueOf(ir.StartMinute_Page__c), 0);
                ir.Inspection_EndTime__c = Datetime.newInstance(ir.Inspection_Date__c.year(), ir.Inspection_Date__c.month(), ir.Inspection_Date__c.day(), Integer.valueOf(ir.EndHour_Page__c), Integer.valueOf(ir.EndMinute_Page__c), 0);
            } else {
                ir.Inspection_StartTime__c = null;
                ir.Inspection_EndTime__c = null;
            }
            if (ir.NextInspection_Day__c != null && ir.Next_StartHour_Page__c != null && ir.Next_StartMinute_Page__c != null && ir.Next_EndHour_Page__c != null && ir.Next_EndMinute_Page__c != null) {
                ir.Next_StartTime__c = Datetime.newInstance(ir.NextInspection_Day__c.year(), ir.NextInspection_Day__c.month(), ir.NextInspection_Day__c.day(), Integer.valueOf(ir.Next_StartHour_Page__c), Integer.valueOf(ir.Next_StartMinute_Page__c), 0);
                ir.Next_EndTime__c = Datetime.newInstance(ir.NextInspection_Day__c.year(), ir.NextInspection_Day__c.month(), ir.NextInspection_Day__c.day(), Integer.valueOf(ir.Next_EndHour_Page__c), Integer.valueOf(ir.Next_EndMinute_Page__c), 0);
            } else {
                ir.Next_StartTime__c = null;
                ir.Next_EndTime__c = null;
            }
        } catch(Exception e) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '请输入正确的时间'));
            return false;
        }

        return true;
    }

    // 检索按钮
    public PageReference searchBtn() {
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '66666666666:' + unCheckedInfoList.size()));
        countorder = 1;
        //验证
        assetSerialNumberList.clear();
        getAssetSerialNumber();
        List < Asset > assetconfimList = getAssetconfim(text1, cond1, val1);
        // 获取assets
        List < Asset > assetList = getAsset(text1, cond1, val1);
        // 作成明细行
        getSortedUnCheckedInfoList(assetList);
        makePageNo(assetconfimList.size());
        // 排序用检索条件退避
        text1ForSort = text1;
        cond1ForSort = cond1;
        val1ForSort = val1;
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '=====unCheckedInfoList:' + unCheckedInfoList.size()));
        system.debug('=====unCheckedInfoList:' + unCheckedInfoList.size());
        for (AssetInfo Ai: unCheckedInfoList) {
            if (Ai.rec_checkBox_c) {
                system.debug('=====uncheck SerialNumber1:' + Ai.rec.SerialNumber);
            }
        }
        for (List < AssetInfo > Li: unCheckedInfoListForThousend) {
            for (AssetInfo Ai: Li) {
                if (Ai.rec_checkBox_c) {
                    system.debug('=====uncheck SerialNumber2:' + Ai.rec.SerialNumber);
                }
            }
        }
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '77777777777777777:' + unCheckedInfoList.size()));
        return null;
    }
    // 明细排序
    public void sortTable() {
        // 排序
        if (this.sortKey == this.preSortKey) {
            // 方向が変わるのみ
            this.sortOrderAsc = !this.sortOrderAsc;
            this.sortOrder[Integer.valueOf(this.sortKey)] = (this.sortOrderAsc == true ? '↑': '↓');
        } else {
            if (preSortKey == '') {
                preSortKey = '0';
            }
            this.sortOrderAsc = true;
            this.sortOrder[Integer.valueOf(this.preSortKey)] = '';
            this.sortOrder[Integer.valueOf(this.sortKey)] = (this.sortOrderAsc == true ? '↑': '↓');
        }
        this.preSortKey = this.sortKey;
        // 获取排序后unCheckAsset
        isSoft = true;
        List < String > assetIdsrechList = new List < String > ();
        assetIdsrechList.clear();
        for (AssetInfo ai: this.UnCheckedInfoList) {
            if (String.isNotEmpty(ai.rec.SerialNumber)) {
                assetIdsrechList.add(ai.rec.SerialNumber);
            }
        }
        List < Asset > assetList = getAssetxiuz(assetIdsrechList);
        // 作成明细行
        getSortedUnCheckedInfoList(assetList);
    }

    private List < Asset > getAsset(String txt, String con, String val) {
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '+++++++++++++++++——————————————————————————'));
        String soql = this.makeSoqlconfim();
        soql += makeTextSql(txt, con, val);
        //if(assetSerialNumberList.size() > 0){
        //  soql += ' AND SerialNumber not in '  + assetSerialNumberList  ;
        //}
        if (isSoft) {
            soql += ' order by ' + this.columus[Integer.valueOf(this.sortKey)] + ' ' + (this.sortOrderAsc == true ? 'asc nulls first': 'desc nulls last ');
        } else {
            soql += ' order by SerialNumber, Name, Department_Name__c, InstallDate';
        }
        soql += ' limit ' + System.Label.Asset_Maxcount;
        soql += ' OFFSET ' + (countorder - 1) * Integer.valueOf(System.Label.Asset_Maxcount);
        //soql += ' limit ' + System.Label.Asset_Maxcount;
        //soql += ' limit ' + (SELECT_LIMIT + 1);
        //system.debug('====soql:' + soql);
        return Database.query(soql);
    }
    //排序修正
    private List < Asset > getAssetxiuz(List < String > txt) {
        String soql = this.makeSoqlconfim();
        //if(txt.size() > 0){
        soql += ' AND SerialNumber in :txt';
        //}
        if (isSoft) {
            soql += ' order by ' + this.columus[Integer.valueOf(this.sortKey)] + ' ' + (this.sortOrderAsc == true ? 'asc nulls first': 'desc nulls last ');
        } else {
            soql += ' order by SerialNumber, Name, Department_Name__c, InstallDate';
        }
        //soql += ' limit ' + System.Label.Asset_Maxcount;
        //soql += ' OFFSET ' + (countorder - 1) * Integer.valueOf(System.Label.Asset_Maxcount);
        //soql += ' limit ' + System.Label.Asset_Maxcount;
        //soql += ' limit ' + (SELECT_LIMIT + 1);
        //system.debug('====soql:' + soql);
        return Database.query(soql);
    }
    //检索验证
    private List < Asset > getAssetconfim(String txt, String con, String val) {
        String soql = this.makeSoqlconfim();
        soql += makeTextSql(txt, con, val);

        if (isSoft) {
            soql += ' order by ' + this.columus[Integer.valueOf(this.sortKey)] + ' ' + (this.sortOrderAsc == true ? 'asc nulls first': 'desc nulls last ');
        } else {
            soql += ' order by SerialNumber, Name, Department_Name__c, InstallDate';
        }
        system.debug('====getAssetconfim:' + soql);
        return Database.query(soql);
    }

    private String makeSoqlconfim() {
        String sqlTail = '(\'';
        for (Integer i = 0; i < assetSerialNumberList.size(); i++) {
            if (i < assetSerialNumberList.size() - 1) {
                sqlTail += assetSerialNumberList[i] + '\',\'';
            } else {
                sqlTail += assetSerialNumberList[i] + '\')';
            }
        }
        String soql = 'SELECT Id, Name, Asset_situation__c, SerialNumber, Department_Name__c, Installation_Site__c, InstallDate, Asset_Owner__c, Accumulation_Repair_Amount__c ' + ' , Maintenance_Price_Month__c, Room_Number__c, CurrentContract__c, CurrentContract__r.Management_Code__c, Status, After_repair_last_internal_check_day__c, Final_Examination_Date__c ' + ' , Hospital__r.Name, Hospital__r.Id, Hospital__c, Department_Class__r.Id, Department_Class__r.Name, Department_Class__c, Account.Id, Account.Name ' + '  FROM Asset WHERE Status != \'廃棄\' AND Status != \'未使用\' AND Category5__c != \'竞争对手\' ';
        if (ir.Hospital__c == null) {
            soql += ' AND Hospital__c = \'\'';
        } else {
            soql += ' AND Hospital__c = \'' + ir.Hospital__c + '\'';
        }

        if (activeOn) {
            soql += ' AND Status = \'使用中\'';
        }
        // fxk 2021/8/4 新加 Start
        soql += ' and (Asset.CurrentContract_F__c = \'a0H100000156VLH\' OR  Asset.CurrentContract_F__r.Status__c != \'契約\' or (Asset.CurrentContract_F__r.Status__c = \'契約\' and Asset.CurrentContract_F_asset__r.Check_object__c = false) or (Asset.CurrentContract_F__r.Status__c = \'契約\' and Asset.CurrentContract_F__r.Effective_Status__c = \'无效\') or Asset.CurrentContract_F__c = null) ';
        // fxk 2021/8/4 新加 End
        if (assetSerialNumberList.size() > 0) {
            soql += ' AND SerialNumber not in ' + sqlTail;
        }
        return soql;
    }

    private String makeSoql() {
        String sqlTail = '(\'';
        for (Integer i = 0; i < assetSerialNumberList.size(); i++) {
            if (i < assetSerialNumberList.size() - 1) {
                sqlTail += assetSerialNumberList[i] + '\',\'';
            } else {
                sqlTail += assetSerialNumberList[i] + '\')';
            }
        }
        String soql = 'SELECT Id, Name, Asset_situation__c, SerialNumber, Department_Name__c, Installation_Site__c, InstallDate, Asset_Owner__c, Accumulation_Repair_Amount__c ' + ' , Maintenance_Price_Month__c, Room_Number__c, CurrentContract__c, CurrentContract__r.Management_Code__c, Status, After_repair_last_internal_check_day__c, Final_Examination_Date__c ' + ' , Hospital__r.Name, Hospital__r.Id, Hospital__c, Department_Class__r.Id, Department_Class__r.Name, Department_Class__c, Account.Id, Account.Name ' + ' FROM Asset WHERE Status != \'廃棄\' AND Status != \'未使用\' AND Category5__c != \'竞争对手\' ';
        if (ir.Hospital__c == null) {
            soql += ' AND Hospital__c = \'\'';
        } else {
            soql += ' AND Hospital__c = \'' + ir.Hospital__c + '\'';
        }
        if (activeOn) {
            soql += ' AND Status = \'使用中\'';
        }
        // fxk 2021/8/4 新加 Start
        soql += ' and (Asset.CurrentContract_F__r.Status__c != \'契約\' or (Asset.CurrentContract_F__r.Status__c = \'契約\' and Asset.CurrentContract_F_asset__r.Check_object__c = false) or Asset.CurrentContract_F__c = null) ';

        // fxk 2021/8/4 新加 End
        if (assetSerialNumberList.size() > 0) {
            soql += ' AND SerialNumber not in ' + sqlTail;
        }
        soql += ' limit ' + System.Label.Asset_Maxcount;
        soql += ' OFFSET ' + (countorder - 1) * Integer.valueOf(System.Label.Asset_Maxcount);
        return soql;
    }
    private String makeSoql(Boolean CountSizes) {
        String soql = ' SELECT count(Id) CntNum ' + ' FROM Asset WHERE Status != \'廃棄\' AND Status != \'未使用\' AND Category5__c != \'竞争对手\'';
        if (ir.Hospital__c == null) {
            soql += ' AND Hospital__c = \'\'';
        } else {
            soql += ' AND Hospital__c = \'' + ir.Hospital__c + '\'';
        }

        if (activeOn) {
            soql += ' AND Status = \'使用中\'';
        }
        // fxk 2021/8/4 新加 Start
        soql += ' and (Asset.CurrentContract_F__r.Status__c != \'契約\' or (Asset.CurrentContract_F__r.Status__c = \'契約\' and Asset.CurrentContract_F_asset__r.Check_object__c = false) or Asset.CurrentContract_F__c = null) ';
        // fxk 2021/8/4 新加 End
        return soql;
    }

    // 拼接检索条件sql文
    private String makeTextSql(String txt1, String con, String val) {
        String soql = '';
        if (String.isBlank(con)) {
            con = 'equals';
        }
        // containsの場合、日報画面の病院検索を真似し、spaceで分けて、and検索
        // equalsの場合、SF標準の検索を真似し、「,」で分けて、or検索
        if (!String.isBlank(txt1)) {
            if ((con == 'contains' || con == 'notcontains') && val.contains(' ')) {
                String[] vals = val.split(' ');
                String cSql = '';
                for (String v: vals) {
                    cSql += this.makeTextSqlStr(txt1, con, v);
                }
                if (con == 'contains') {
                    soql += cSql;
                } else {
                    // notcontains
                    cSql = cSql.replaceAll(' and ', ') and (NOT ');
                    soql += cSql.substring(1) + ') ';
                }
            } else if ((con == 'equals' || con == 'notequals') && val.contains(',')) {
                String[] vals = val.split(',');
                if (vals.size() > 0) {
                    String txt = txt1.substring(2); // S:Name 、最初の２文字がタイプです
                    soql += ' and ( ';
                    for (String v: vals) {
                        if (con == 'equals') {
                            soql += txt + ' = \'' + v + '\' or ';
                        } else {
                            // notequals
                            soql += txt + ' <> \'' + v + '\' and ';
                        }
                    }
                    soql = soql.substring(0, soql.length() - 4);
                    soql += ')';
                }
            } else {
                String cSql = this.makeTextSqlStr(txt1, con, val);
                if (con != 'notcontains') {
                    soql += this.makeTextSqlStr(txt1, con, val);
                } else {
                    // notcontains
                    if (!String.isBlank(cSql)) {
                        cSql = cSql.substring(5); // ' and ' の5文字を外す
                        soql += ' and (NOT ' + cSql + ') ';
                    }
                }
            }
        }
        return soql;
    }

    /**
    * 文字列検索文を作成
    */
    private String makeTextSqlStr(String txt1, String con, String val) {
        String soql = '';
        if (!String.isBlank(txt1)) {
            String txt = txt1.substring(2);
            String colType = txt1.substring(0, 2);
            String tmpVal = val;
            // 空白の場合''にする
            if (String.isBlank(tmpVal)) {
                if (con == 'equals') {
                    //soql += ' and ' + txt + ' = ' + tmpVal;
                    soql += ' and ' + txt + ' = null';
                } else if (con == 'notequals') {
                    soql += ' and ' + txt + ' <> null';
                } else {
                    // 空白の場合、contains, notcontains と starts withは無視
                }
            } else {
                soql += ' and ' + txt;
                if (con == 'equals') {
                    if (colType == 'S:') {
                        soql += ' = \'' + tmpVal + '\'';
                    } else {
                        soql += ' = ' + tmpVal + ' ';
                    }
                } else if (con == 'notequals') {
                    if (colType == 'S:') {
                        soql += ' <> \'' + tmpVal + '\'';
                    } else {
                        soql += ' <> ' + tmpVal + ' ';
                    }
                } else if (con == 'contains' || con == 'notcontains') {
                    soql += ' like \'%' + String.escapeSingleQuotes(tmpVal.replaceAll('%', '\\%')) + '%\'';
                } else if (con == 'starts with') {
                    soql += ' like \'' + String.escapeSingleQuotes(tmpVal.replaceAll('%', '\\%')) + '%\'';
                } else {
                    if (colType == 'S:') {
                        soql += ' ' + con + '\'' + tmpVal + '\'';
                    } else {
                        soql += ' ' + con + ' ' + tmpVal + ' ';
                    }
                }
            }
        }
        return soql;
    }

    //
    private void getSortedUnCheckedInfoList(List < Asset > assetList) {
        Boolean overLimit = false;
        //Map<Id, AssetInfo> unCheckMap = new Map<Id, AssetInfo>();
        // 已经打勾的未选明细
        Map < Id,
        AssetInfo > markUpUnCheckMap = new Map < Id,
        AssetInfo > ();
        for (AssetInfo unCheckinfo: unCheckedInfoList) {
            //unCheckMap.put(unCheckinfo.rec.Id, unCheckinfo);
            // 打勾，视为优先显示明细
            if (unCheckinfo.rec_checkBox_c == true) {
                markUpUnCheckMap.put(unCheckinfo.rec.Id, unCheckinfo);
            }
        }

        // 优先显示明细放在最前面
        unCheckedInfoList = new List < AssetInfo > ();
        for (AssetInfo asInfo: markUpUnCheckMap.values()) {
            unCheckedInfoList.add(asInfo);
        }

        Integer selectCnt = unCheckedInfoList.size();
        for (Asset asset: assetList) {
            // 201を超えた場合前200のみを出す
            if (unCheckedInfoList.size() >= SELECT_LIMIT) {
                overLimit = true;
                break;
            }
            if (markUpUnCheckMap.containsKey(asset.Id) == false) {
                //unCheckedInfoList.add(unCheckMap.get(asset.Id));
                unCheckedInfoList.add(new AssetInfo(unCheckedInfoList.size(), asset));
            }
        }

        // 显示数据条数信息
        //if (overLimit) {
        //    ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '数据超过' + Select_Limit + '条，只显示前' + Select_Limit + '条'));
        //} else {
        //    ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '共有' + getRaesInfoListSize() + '条数据'));
        //}
    }

    class SectionBean {
        public String title {
            get;
            private set;
        }
        public Integer column {
            get;
            private set;
        }
        public Boolean showHeader {
            get;
            private set;
        }
        public String id {
            get;
            private set;
        }
        public List < SectionItem > leftSectionList {
            get;
            private set;
        }
        public List < SectionItem > rightSectionList {
            get;
            private set;
        }
        public Boolean isTop {
            get;
            set;
        }

        // leftとrightのサイズ違う場合、最後空のSectionItemを追加
        public List < SectionItem > getSectionItemList() {
            List < SectionItem > sectionItemList = new List < SectionItem > ();
            Integer lCnt = leftSectionList.size();
            Integer rCnt = rightSectionList.size();
            if (column == 1) {
                return leftSectionList;
            } else {
                for (Integer i = 0; i < Math.max(lCnt, rCnt); i++) {
                    if (lCnt <= i) {
                        sectionItemList.add(new SectionItem());
                    } else {
                        sectionItemList.add(leftSectionList[i]);
                    }
                    if (rCnt <= i) {
                        sectionItemList.add(new SectionItem());
                    } else {
                        sectionItemList.add(rightSectionList[i]);
                    }
                }
            }
            return sectionItemList;
        }

        public SectionBean(String jsonSection) {
            leftSectionList = new List < SectionItem > ();
            rightSectionList = new List < SectionItem > ();
            Map < String,
            Object > m = (Map < String, Object > ) JSON.deserializeUntyped(jsonSection);
            id = String.valueOf(m.get('id'));
            title = '';
            if (m.get('title') != null) {
                title = String.valueOf(m.get('title'));
            }
            column = 1;
            if (m.get('column') != null) {
                column = Integer.valueOf(m.get('column'));
            }
            showHeader = true;
            if (m.get('showHeader') != null) {
                showHeader = Boolean.valueOf(m.get('showHeader'));
            }
        }
    }

    public class SectionItem {
        public String api {
            get;
            private set;
        }
        public List < String > apiList {
            get;
            private set;
        }
        public Map < String,
        String > apiLabelMap {
            get;
            private set;
        }
        public Map < String,
        String > apiStyleMap {
            get;
            private set;
        }
        public Map < String,
        Boolean > apiRequireMap {
            get;
            private set;
        }
        public Map < String,
        Boolean > apiInputMap {
            get;
            private set;
        }
        public String sectionId {
            get;
            private set;
        }
        public Boolean right {
            get;
            private set;
        }
        public Boolean isDummy {
            get;
            private set;
        }
        public Boolean isCustomize {
            get;
            private set;
        }
        public String customizeLable {
            get;
            private set;
        }
        public Boolean isCustomizeStyle {
            get;
            private set;
        }
        public Boolean isInput {
            get;
            private set;
        }
        public Boolean isRequired {
            get;
            private set;
        }
        public String width {
            get;
            private set;
        }
        public String height {
            get;
            private set;
        }
        public Integer index {
            get;
            private set;
        }

        public SectionItem() {
            isDummy = true;
        }
        public SectionItem(String jsonField, Integer idx) {
            isDummy = false;
            Map < String,
            Object > m = (Map < String, Object > ) JSON.deserializeUntyped(jsonField);
            apiList = new List < String > ();
            apiLabelMap = new Map < String,
            String > ();
            apiStyleMap = new Map < String,
            String > ();
            apiRequireMap = new Map < String,
            Boolean > ();
            apiInputMap = new Map < String,
            Boolean > ();
            index = idx;
            if (m.get('api') instanceof Map < String, Object > ) {
                Map < String,
                Object > aMap = (Map < String, Object > ) m.get('api');
                if (aMap.get('columns') instanceof List < Object > &&aMap.get('lables') instanceof List < Object > ) {
                    List < Object > cList = (List < Object > ) aMap.get('columns');
                    List < Object > lList = (List < Object > ) aMap.get('lables');
                    List < Object > sList = new List < Object > ();
                    List < Object > rList = new List < Object > ();
                    List < Object > iList = new List < Object > ();
                    if (aMap.get('styles') instanceof List < Object > ) {
                        sList = (List < Object > ) aMap.get('styles');
                        isCustomizeStyle = true;
                    } else {
                        isCustomizeStyle = false;
                    }
                    if (aMap.get('require') instanceof List < Object > ) {
                        rList = (List < Object > ) aMap.get('require');
                    }
                    if (aMap.get('isInput') instanceof List < Object > ) {
                        iList = (List < Object > ) aMap.get('isInput');
                    }
                    if (cList.size() != lList.size()) {
                        ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.ERROR, 'Error: Invalid CustomSettings about columns and labels.');
                        ApexPages.addMessage(myMsg);
                        return;
                    }

                    for (Integer i = 0; i < cList.size(); i++) {
                        apiList.add(String.valueOf(cList[i]));
                        apiLabelMap.put(String.valueOf(cList[i]), String.valueOf(lList[i]));
                        if (sList != null && sList.size() > 0 && sList[i] != null) {
                            apiStyleMap.put(String.valueOf(cList[i]), String.valueOf(sList[i]));
                        } else {
                            apiStyleMap.put(String.valueOf(cList[i]), '');
                        }
                        // require
                        if (rList != null && rList.size() > 0 && rList[i] != null) {
                            apiRequireMap.put(String.valueOf(cList[i]), Boolean.valueOf(rList[i]));
                        } else {
                            apiRequireMap.put(String.valueOf(cList[i]), false);
                        }
                        // input
                        if (iList != null && iList.size() > 0 && iList[i] != null) {
                            apiInputMap.put(String.valueOf(cList[i]), Boolean.valueOf(iList[i]));
                        } else {
                            apiInputMap.put(String.valueOf(cList[i]), false);
                        }
                    }
                } else {
                    apiList.add(String.valueOf(aMap.get('columns')));
                    apiLabelMap.put(String.valueOf(aMap.get('columns')), String.valueOf(aMap.get('lables')));
                    apiStyleMap.put(String.valueOf(aMap.get('columns')), '');
                }

                isCustomize = true;
            } else {
                api = String.valueOf(m.get('api'));
                apiList.add(String.valueOf(api));
                isCustomize = false;
            }
            if (m.get('lable') != null) {
                customizeLable = String.valueOf(m.get('lable'));
                if (String.isBlank(customizeLable)) {
                    customizeLable = null;
                }
            }
            if (m.get('width') != null) {
                width = String.valueOf(m.get('width'));
            }
            if (m.get('height') != null) {
                height = String.valueOf(m.get('height'));
            }
            sectionId = String.valueOf(m.get('sectionId'));
            if (m.get('right') != null) {
                right = Boolean.valueOf(m.get('right'));
            } else {
                right = false;
            }
            if (m.get('isInput') != null) {
                isInput = Boolean.valueOf(m.get('isInput'));
            } else {
                isInput = false;
            }
            if (m.get('require') != null) {
                isRequired = Boolean.valueOf(m.get('require'));
            } else {
                isRequired = false;
            }
        }
        public Boolean isRight() {
            return this.right;
        }
        public String getSectionId() {
            return this.sectionId;
        }
        public String getApi() {
            return this.api;
        }
        public List < String > getApiList() {
            return this.apiList;
        }
    }

    public class AssetInfo {
        public Integer lineNo {
            get;
            private set;
        }
        public Boolean rec_checkBox_c {
            get;
            set;
        }
        public Asset rec {
            get;
            set;
        }
        public Inspection_Item__c ah {
            get;
            set;
        }
        public Boolean isNew {
            get;
            private set;
        }
        public Boolean isManual {
            get;
            set;
        }
        public Id getRecId() {
            Id rtn = null;
            if (rec != null) {
                rtn = rec.Id;
            }
            return rtn;
        }
        public void setRecId(Id value) {
            // なにもしない
        }

        // Manual専用（空行）
        public AssetInfo(Integer lineNo) {
            this.lineNo = lineNo;
            this.rec = null;
            this.ah = new Inspection_Item__c();
            this.isManual = true;
            this.rec_checkBox_c = false;
            this.isNew = true;
            //设备状态默认全OK add by rentx 20210826 start
            this.ah.ItemStatus__c = 'OK';
            //设备状态默认全OK add by rentx 20210826 end 
        }
        // Manual専用（製品選択済み）
        public AssetInfo(Integer lineNo, Inspection_Item__c ah) {
            this.lineNo = lineNo;
            this.rec = null;
            this.ah = ah;
            this.isManual = true;
            this.rec_checkBox_c = false;

            //add by rentx 20210831 start 默认OK
            this.ah.ItemStatus__c = ah.ItemStatus__c == '' ? 'OK' : ah.ItemStatus__c;
            //add by rentx 20210831 end 默认OK
        }
        // チェックされてない
        public AssetInfo(Integer lineNo, Asset record) {
            this.lineNo = lineNo;
            this.rec = record;
            this.ah = new Inspection_Item__c(AssetId__c = record.Id, SerialNumber__c = record.SerialNumber, Maintance_Static_His__c = record.CurrentContract__c);
            this.isManual = false;
            this.rec_checkBox_c = false;
            this.isNew = true;
            //设备状态默认全OK add by rentx 20210826 start
            this.ah.ItemStatus__c = 'OK';
            //设备状态默认全OK add by rentx 20210826 end 
        }
        //チェックされてる。報告書が既にある、明細を新追加する
        public AssetInfo(Integer lineNo, Asset record, Inspection_Report__c ir) {
            this.lineNo = lineNo;
            this.rec = record;
            this.ah = new Inspection_Item__c(AssetId__c = record.Id, Inspection_ReportId__c = ir.Id, SerialNumber__c = record.SerialNumber, Maintance_Static_His__c = record.CurrentContract__c);
            this.isManual = false;
            this.rec_checkBox_c = true;
            this.isNew = true;
            //设备状态默认全OK add by rentx 20210826 start
            this.ah.ItemStatus__c = 'OK';
            //设备状态默认全OK add by rentx 20210826 end 
        }

        //チェックされてる。報告書も明細も既にある
        public AssetInfo(Integer lineNo, Asset record, Inspection_Item__c ah) {
            this.lineNo = lineNo;
            this.rec = record;
            this.ah = ah;
            this.isManual = false;
            this.rec_checkBox_c = true;
            //add by rentx 20210831 start 默认OK
            this.ah.ItemStatus__c = ah.ItemStatus__c == '' ? 'OK' : ah.ItemStatus__c;
            //add by rentx 20210831 end 默认OK

        }
    }

    WebService static Inspection_Report__c getInsInfotById(String strId) {
        return [select Name from Inspection_Report__c where Id = :strId];
    }
}