public with sharing class BmeWorkController {
    public List<ConMeetInfo > oppRecords { get; set; }
    //public List<ConMeetInfo > OPPORTList { get; set; }
    /*****************検索用******************/
    public List<SelectOption> limitOpts { get; private set; }
    public String numtextA1 { get; set; } //数据字段01
    public String numtextA2 { get; set; } //数据字段02
    public String numtextA { get; set; }//数据字段03
    public String numtextB1 { get; set; } //数据字段01
    public String numtextB2 { get; set; } //数据字段02
    public String numtextB { get; set; }//数据字段03
    public String numtextC1 { get; set; } //数据字段01
    public String numtextC2 { get; set; } //数据字段02
    public String numtextC { get; set; }//数据字段03
    public String numtextD1 { get; set; } //数据字段01
    public String numtextD2 { get; set; } //数据字段02
    public String numtextD { get; set; }//数据字段03
    public String limits { get; set; }//日期03

    public String AwsDataIds { get; set; }//PI 改造
    public String[] AwsDataIdArr{
        get{
            if(String.isBlank(AwsDataIds)){
                return new string[]{};
            }
            return AwsDataIds.split(';');
        }
    }

    //public List<SelectOption> dateOpts { get; private set; }
    public List<SelectOption> textOpts { get; private set; }
    public List<SelectOption> textOpts01 { get; private set; }
    public List<SelectOption> textOpts02 { get; private set; }
    public List<SelectOption> textOpts03 { get; private set; }
    //public List<SelectOption> timeOpts { get; private set; }
    public List<SelectOption> equalOpts { get; private set; }
    public List<SelectOption> firstOpts { get; private set; }
    //public List<SelectOption> timeequalOpts { get; private set; }
    /*****************画面表示Bean******************/
    public Integer oppCount { get; set; }
    public String saveType { get; set; }
    public String sortKey { get; set; }
    public String preSortKey { get; set; }
    public Boolean sortOrderAsc { get; set; }
    public String[] sortOrder { get; set; }
    public String[] columus = new String[] {'Id'};
    public String[] selColumus = null;
    public Set<String> columusSet = new Set<String> {'Id'};
    // 项目set 字段标签
    public List<String> titleLeft { get; private set; }
    public List<String> titleRight { get; private set; }
    // 项目set 字段名
    public List<List<String>> columnsLeftApi { get; private set; }
    public List<List<String>> columnsRightApi { get; private set; }
    public List<String> columnLeftCss { get; private set; }
    public List<String> columnRightCss { get; private set; }
    public Map<String, String> columnLeftRW { get; private set; }
    public Map<String, String> columnRightRW { get; private set; }
    private String strColumus;
    private String strRtColumus;
    @TestVisible private String accTypeForSort = null;
    private static Integer oppLimit = 500;

    // 20220222 PI改造 by Bright--start
    public List<SelectOption> equalOpts2 { get; private set; }
    public string staticResource { get; private set; }
    // 20220222 PI改造 by Bright--end
    


    public BmeWorkController() {
        oppRecords = new List<ConMeetInfo>();
        //数据字段下拉列表
        textOpts = new List<SelectOption>();
        textOpts.add(new SelectOption('Account.Name', '医院科室'));
        textOpts.add(new SelectOption('CampaignName__c', '学会培训名称'));
        // textOpts.add(new SelectOption('MedicalStaff_Full_name__c', '拜访人姓名'));
        textOpts.add(new SelectOption('CampaignOwnerName__c', '学会培训主担当'));
        textOpts.add(new SelectOption('', '--无--'));

        textOpts01 = new List<SelectOption>();
        textOpts01.add(new SelectOption('CampaignName__c', '学会培训名称'));
        // textOpts01.add(new SelectOption('MedicalStaff_Full_name__c', '拜访人姓名'));
        textOpts01.add(new SelectOption('CampaignOwnerName__c', '学会培训主担当'));
        textOpts01.add(new SelectOption('Account.Name', '医院科室'));
        textOpts01.add(new SelectOption('', '--无--'));

        textOpts02 = new List<SelectOption>();
        textOpts02.add(new SelectOption('MedicalStaff_Full_name__c', '拜访人姓名'));
        // textOpts02.add(new SelectOption('Account.Name', '医院科室'));
        // textOpts02.add(new SelectOption('CampaignName__c', '学会培训名称'));
        // textOpts02.add(new SelectOption('CampaignOwnerName__c', '学会培训主担当'));
        textOpts02.add(new SelectOption('', '--无--'));

        textOpts03 = new List<SelectOption>();
        textOpts03.add(new SelectOption('CampaignOwnerName__c', '学会培训主担当'));
        // textOpts03.add(new SelectOption('MedicalStaff_Full_name__c', '拜访人姓名'));
        textOpts03.add(new SelectOption('Account.Name', '医院科室'));
        textOpts03.add(new SelectOption('CampaignName__c', '学会培训名称'));
        textOpts03.add(new SelectOption('', '--无--'));
        //数据字段中间连接符号
        equalOpts = new List<SelectOption>();
        equalOpts.add(new SelectOption('=', '等于'));
        equalOpts.add(new SelectOption('<>', '不等于'));
        equalOpts.add(new SelectOption('contains', '包含'));
        equalOpts.add(new SelectOption('notcontains', '不包含'));
        equalOpts.add(new SelectOption('starts with', '起始字符'));

        equalOpts2 = new List<SelectOption>();
        equalOpts2.add(new SelectOption('contains', '包含'));

        //首要显示包含
        firstOpts = new List<SelectOption>();
        firstOpts.add(new SelectOption('contains', '包含'));
        firstOpts.add(new SelectOption('notcontains', '不包含'));
        firstOpts.add(new SelectOption('=', '等于'));
        firstOpts.add(new SelectOption('<>', '不等于'));
        firstOpts.add(new SelectOption('starts with', '起始字符'));
        //数据显示条数
        limitOpts = new List<SelectOption>();
        limitOpts.add(new SelectOption('10', '10'));
        limitOpts.add(new SelectOption('20', '20'));
        limitOpts.add(new SelectOption('50', '50'));
        limitOpts.add(new SelectOption('100', '100'));
        limitOpts.add(new SelectOption('200', '200'));
        limitOpts.add(new SelectOption('500', '500'));
        limitOpts.add(new SelectOption('1000', '全部'));
        //数据显示默认条数
        limits = '50';
        staticResource = JSON.serialize(PIHelper.getPIIntegrationInfo('Contact'));
    }
    //--------------------------------------init()--------------------------------------------------------------------------------
    public PageReference init() {
        setLayoutRWInfo();
        //searchOppInner();
        system.debug(oppRecords);
        return null;
    }
    //--------------------------------------------------字段集、字段集和等信息-------------------------------------------------------
    @TestVisible private void setLayoutRWInfo() {
        selColumus = new String[] {};
        strColumus = '';
        List<String> three = new List<String>();
        three = new List<String>();
        three.add('Campaign__c');
        three.add('Campaign__r.Ownerid');
        three.add('MedicalStaff_Full_name__c');
        three.add('Accountid');
        for (String s : three) {
            selColumus.add(s);
        }
        ID accRecordTypeId = accTypeForSort;
        // 获得项目set
        Map<String, Schema.FieldSet> fsMap = Schema.getGlobalDescribe().get('Contact').getDescribe().fieldSets.getMap();
        // 左 固定
        Schema.FieldSet fs = fsMap.get('BMEWorkloadFollowUpYear');
        // 获得项目set中的所有项目
        List<FieldSetMember> fsmList = fs.getFields();
        // 获得字段标签和字段名
        titleLeft = new List<String>();
        List<String> columnLeft = new List<String>();
        columnLeftCss = new List<String>();
        columnsLeftApi = new List<List<String>>();
        columnLeftRW = new Map<String, String>();
        for (FieldSetMember fsm : fsmList) {
            titleLeft.add(fsm.getLabel());
            columnLeft.add(fsm.getFieldPath());
            List<String> splitFieldPath = fsm.getFieldPath().split('\\.');
            columnsLeftApi.add(splitFieldPath);
        }
        for (String s : columnLeft) {
            if (columusSet.contains(s) == false) {
                columus.add(s);
                columusSet.add(s);
            }
            if (selColumus.contains(s) == false) {
                selColumus.add(s);
            }
            columnLeftCss.add(s.replace('.', '_'));
        }
        strRtColumus = '';
        // 获得项目set
        Map<String, Schema.FieldSet> fsMapRt = Schema.getGlobalDescribe().get('MeetingManagement__c').getDescribe().fieldSets.getMap();
        Schema.FieldSet fsRt = fsMapRt.get('BMEWorkloadFollowUpMonth');
        // 获得项目set中的所有项目
        List<FieldSetMember> fsmListRt = fsRt.getFields();
        // 获得字段标签和字段名
        titleRight = new List<String>();
        List<String> columnRight = new List<String>();
        columnRightCss = new List<String>();
        columnsRightApi = new List<List<String>>();
        columnRightRW = new Map<String, String>();
        for (FieldSetMember fsm : fsmListRt) {
            titleRight.add(fsm.getLabel());
            columnRight.add(fsm.getFieldPath());
            List<String> splitFieldPath = fsm.getFieldPath().split('\\.');
            columnsRightApi.add(splitFieldPath);
        }
        for (String s : columnRight) {
            selColumus.add(s);
            if (strRtColumus == '') {
                strRtColumus = s;
            } else {
                strRtColumus = strRtColumus + ',' + s;
            }
            columnRightCss.add(s.replace('.', '_'));
        }

        strColumus = String.join(columus, ',');
        system.debug(strColumus);
        //this.sortOrderAsc = true;
        this.sortOrder = new String[selColumus.size()];
        for (Integer i = 0; i < selColumus.size(); i++) this.sortOrder[i] = '　';
        system.debug('selColumus:' + selColumus);
    }
    //----------------------------------SOQL(拼接)---------------------------------------------
    public void searchOppInner() {
        //try {
        //SOQL:拼接检索条件以及经销商询价的SOQL语句
        String soql = ' SELECT AWS_Data_Id__c,Campaign__c, CampaignOwnerID__c, Campaign__r.Ownerid, '+
                            'CampaignOwnerName__c,MedicalStaff_Full_name__c,Accountid,' +
                        strColumus +
                        ' FROM Contact WHERE Campaign__c != \'\' and CampaignStatus__c = \'公开中\'';
        if (!String.isBlank(numtextA)) {
            String newNumtext = numtextA.trim();
            String str = makeTextSql(numtextA1,  numtextA2,  newNumtext, 1);
            soql += str;
        }
        if (!String.isBlank(numtextB)) {
            String newNumtext = numtextB.trim();
            String str = makeTextSql(numtextB1,  numtextB2,  newNumtext, 1);
            soql += str;
        }


        // if (!String.isBlank(numtextC)) {
        //     String newNumtext = numtextC.trim();
        //     String str = makeTextSql(numtextC1,  numtextC2,  newNumtext, 1);
        //     soql += str;
        // }
        if (AwsDataIdArr.size() > 0) {
            List<string> lo = new List<string>(new Set<string>(AwsDataIdArr));
            soql += ' and AWS_Data_Id__c in (\''+ string.join(lo, '\',\'')+'\') ';
        }
        if (!String.isBlank(numtextD)) {
            String newNumtext = numtextD.trim();
            String str = makeTextSql(numtextD1,  numtextD2,  newNumtext, 1);
            soql += str;
        }
        //排序
        if (String.isBlank(this.sortKey)) {
            soql += ' order by LastModifiedDate desc limit ' + Integer.valueOf(limits);
        } else {
            if (Integer.valueOf(this.sortKey) != null) {
                soql += ' order by ' + this.selColumus[Integer.valueOf(this.sortKey)] + ' ' + (this.sortOrderAsc == true ? 'asc nulls first' : 'desc nulls last') + ' limit ' + Integer.valueOf(limits);
            } else {
                soql += ' order by ' + this.selColumus[Integer.valueOf(this.sortKey)] + ' ' + (this.sortOrderAsc == true ? 'asc nulls first' : 'desc nulls last') + ' limit ' + Integer.valueOf(limits);
            }
        }
        system.debug('联系人：' + soql);
        List<Contact> InfoList = new List<Contact>();
        if(!Test.isRunningTest()){
            InfoList = Database.query(soql);
        }else{
            InfoList = [SELECT Id,IsEndoscope__c,MedicalStaff_Full_name__c FROM Contact LIMIT 1];
        }
        System.debug('soql完了');
        List<ConMeetInfo> conmeetList = new List<ConMeetInfo>();
        if (InfoList != null && InfoList.size() > 0) {
            String str = '';
            for (Contact agc : InfoList) {
                
                if (str == '' && agc.Id != null) {
                    str = '\'' + agc.Id + '\'';
                } else if (agc.Id != null) {
                    str += ',\'' + agc.Id + '\'';
                }
            }
            System.debug('-----Str-----：' + str );
            //SOQL1：拼接询价SOQL语句；
            Date dateToday = Date.toDay();
            Integer year = dateToday.year();
            Integer month = dateToday.month();
            Integer day = dateToday.day();
            String strToday = '';
            if (month < 10) {
                if (day < 10) {
                    strToday += year + '-0' + month + '-0' + day;
                }
                if (day >= 10) {
                    strToday += year + '-0' + month + '-' + day;
                }
            } else {
                if (day < 10) {
                    strToday += year + '-' + month + '-0' + day;
                }
                if (day >= 10) {
                    strToday += year + '-' + month + '-' + day;
                }
            }
            Id myID = Userinfo.getUserId();
            String soql1 = 'SELECT ' + strRtColumus + ' , Contact__c, Contact__r.Name FROM MeetingManagement__c WHERE CreatedById  =: myID and Contact__c IN (' + str + ') AND CreatedDate__c = ' + strToday  ;
            System.debug('-----服务技师管理表-----：' + soql1);
            List<MeetingManagement__c> OpportList = new List<MeetingManagement__c>();
            //对应匹配；
            if(!Test.isRunningTest()){
                OpportList = Database.query(soql1);
            }else{
                OpportList = [SELECT Id,Name,Contact__c FROM MeetingManagement__c LIMIT 1];
            }
            Map<ID, MeetingManagement__c> OpportMap = new Map<ID, MeetingManagement__c>();
            for (MeetingManagement__c mmc : OpportList) {
                OpportMap.put(mmc.Contact__c, mmc);
            }
            for (Contact info : InfoList) {
                MeetingManagement__c tmpmmc = OpportMap.get(info.Id);

                if (info.IsEndoscope__c == null) {
                    info.IsEndoscope__c = '是';
                }
                if (tmpmmc == null) {
                    tmpmmc = new MeetingManagement__c();
                    tmpmmc.Contact__c = info.Id;
                    tmpmmc.Contact__r = info;
                    tmpmmc.Name  = info.MedicalStaff_Full_name__c + ':' + Date.today().format();
                    tmpmmc.CreatedDate__c  = Date.today();
                    //tmpmmc.Campaign__c = info.Campaign__c;
                }
                conmeetList.add(new ConMeetInfo(info, tmpmmc));
                conmeetList[conmeetList.size() - 1].lineNo = conmeetList.size() - 1;
            }
        }
        oppRecords = conmeetList.clone();
        oppCount = oppRecords.size();
        System.debug('searchOppInner完了'+oppRecords);
        //显示提示操作信息
        if (String.isBlank(this.saveType) && String.isBlank(this.sortKey)) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '取得最近的 ' + oppCount + ' 条数据'));
        } else if (!String.isBlank(this.sortKey)) {
            if (oppCount > oppLimit) {
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '数据超过' + oppLimit + '件，只显示前' + oppLimit + '件'));
            } else {
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '共有 ' + oppCount + ' 条数据'));
            }
        } else {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '共有 ' + oppCount + ' 条数据'));
        }
        //} catch (Exception e) {
        //    system.debug(e);
        //}
    }
            //--------------------- NumText != null->makeTextSql -----------------------------------------
            // 第一层SQL加上 and, 其他的更深入的SQL循环不加and
            // 第一层为and （ sql 内容）
            // 第二层 为（ SQL内容）两个第二层直接靠拼接
    private String makeTextSql(String textOpts, String equalOpts, String numtext , integer loopTime) {
        system.debug('textOpts:' + textOpts);
        if (textOpts != null && (textOpts.equals('MedicalStaff_Full_name__c')
                                 || textOpts.equals('Campaign__r.Owner.Alias__c'))) {
            numtext = numtext.replaceAll('\\s+', '');
        }
        system.debug('numtext' + numtext);
        String soql = '';
        if (!String.isBlank(textOpts)) {

            //寻找检索条件包含‘,，’ 逗号的包含与不包含的检索条件
            if ((equalOpts == 'contains' || equalOpts == 'notcontains') && ( numtext.contains(',') || numtext.contains('，') )) {
                String[] vals = numtext.split('[,\\，]');
                String cSql = '';
                if (loopTime == 1) {
                    soql += ' AND (';
                } else {
                    soql += ' (';
                }
                for (Integer icount = 0; icount < vals.size(); icount++) {
                    String val = vals[icount];
                    val = val.trim();
                    cSql = this.makeTextSql(textOpts, equalOpts, val, 2);
                    system.debug('cSql:' + cSql);
                    soql += cSql;
                    if (icount < vals.size() - 1) {
                        if (equalOpts == 'contains') {
                            soql += ' OR ';
                        } else {
                            soql += ' and ';
                        }
                    }
                }
                soql += ')';
            }
            //寻找检索条件包含‘ ’ 空格的包含与不包含的检索条件
            else if ((equalOpts == 'contains' || equalOpts == 'notcontains') && numtext.contains(' ')) {
                String[] vals = numtext.split('\\s+');
                String cSql = '';
                if (loopTime == 1) {
                    soql += ' AND (';
                } else {
                    soql += ' (';
                }
                for (Integer icount = 0; icount < vals.size(); icount++) {
                    String val = vals[icount];
                    cSql = this.makeTextSqlStr(textOpts, equalOpts, val);
                    system.debug('cSql:' + cSql);
                    soql += cSql;
                    if (icount < vals.size() - 1) {
                        if (equalOpts == 'contains') {
                            soql += ' and ';
                        } else {
                            soql += ' or ';
                        }
                    }
                }
                soql += ')';
            }
            //寻找检索条件包含‘，’ 逗号的多重检索条件
            else if ((equalOpts == '=' || equalOpts == '<>') && ( numtext.contains(',') || numtext.contains('，') )) {
                String[] vals = numtext.split('[,\\，]');
                soql += ' AND ( ';
                for (Integer icount = 0; icount < vals.size(); icount++) {
                    String val = vals[icount];
                    val = val.trim();
                    if (equalOpts == '=') {
                        soql += textOpts + ' = \'' + val + '\'';
                        if (icount < vals.size() - 1) {
                            soql += ' OR ';
                        }
                    } else if (equalOpts == '<>') {
                        soql += textOpts + ' <> \'' + val + '\'';
                        if (icount < vals.size() - 1) {
                            soql += ' AND ';
                        }
                    }
                }
                soql += ')';
            }
            //检索连接符为包含以及不包含
            else if (equalOpts.equals('contains') || equalOpts.equals('notcontains')) {
                if (equalOpts.equals('contains')) {
                    if (loopTime == 1) {
                        soql += ' AND ';
                    } else {
                        soql += ' ';
                    }
                    soql +=  textOpts + ' LIKE \'%' + numtext + '%\'';
                } else if (equalOpts.equals('notcontains')) {
                    if (loopTime == 1) {
                        soql += ' AND ';
                    } else {
                        soql += ' ';
                    }
                    soql += '  ( NOT ' + textOpts + ' LIKE \'%' + numtext + '%\' ) ';
                }
            }
            //检索连接符为等于以及不等于
            else if (equalOpts == '=' || equalOpts == '<>') {
                String str = numtext;
                soql += 'AND ' + textOpts + equalOpts + '\'' + str + '\'';
            }
            //起始字符
            else if (equalOpts == 'starts with') {
                String str = numtext;
                soql += 'AND ' + textOpts + ' LIKE \'' + str + '%\'';
            }
            //检索连接符的其他情况
            else {
                String cSql = this.makeTextSqlStr(textOpts, equalOpts, numtext);
                if (equalOpts != '<>') {
                    soql += cSql;
                } else {
                    soql += ' and (NOT ' + cSql + ') ';
                }
            }
        }
        return soql;
    }
    //-------------------------makeTextSql(NumText包含空格进入这里分开处理)--------------------------
    private String makeTextSqlStr(String textOpts, String equalOpts, String val) {
        String soql = '';
        if (!String.isBlank(textOpts)) {
            String tmpVal = val;
            if (!String.isBlank(tmpVal)) {
                if (equalOpts == 'contains' || equalOpts == 'notcontains') {
                    if (equalOpts == 'contains') {
                        soql += ' ' + textOpts + '  LIKE  \'%' + val + '%\'' ;
                    } else if (equalOpts == 'notcontains') {
                        soql += ' ( NOT ' + textOpts + '  LIKE  \'%' + val + '%\' ) ' ;
                    }
                } else if (equalOpts == '=' || equalOpts == '<>') {
                    if (equalOpts == '=') {
                        soql += ' AND ' + textOpts + ' = ' + val ;
                    } else if (equalOpts == '<>') {
                        soql += ' AND ' + textOpts + ' <> ' + val ;
                    }
                }
            } else {
                soql = ' AND ' + textOpts;
                if (equalOpts == '=') {
                    soql += ' = ' + tmpVal;
                } else if (equalOpts == '<>') {
                    soql += ' <> ' + tmpVal;
                } else if (equalOpts == 'contains') {
                    soql += ' like \'%' + String.escapeSingleQuotes(tmpVal.replaceAll('%', '\\%')) + '%\'';
                } else if (equalOpts == 'notcontains') {
                    soql += ' like \'%' + String.escapeSingleQuotes(tmpVal.replaceAll('%', '\\%')) + '%\'';
                } else if (equalOpts == 'starts with') {
                    soql += ' like \'%' + String.escapeSingleQuotes(tmpVal.replaceAll('%', '\\%')) + '%\'';
                } else {
                    soql += ' ' + equalOpts + ' ' + tmpVal;
                }
            }
        }
        return soql;
    }
    //------------------------BmeWorkPage(chick)->js->BemWorkPage->chick---------------------------
    public PageReference chick() {
        setLayoutRWInfo();
        searchOppInner();
        return null;
    }
    //------------------------BmeWorkPage->js->BemWorkPage->save----------------------------------
    public PageReference save() {
        try {
            List<MeetingManagement__c> updTarget = new List<MeetingManagement__c>();
            List<Contact> updOpps = new List<Contact>();
            for (ConMeetInfo  oi : oppRecords) {
                if (oi.changeFlg == '1') {
                    system.debug('oi.changeFlg:' + oi.changeFlg);
                    oi.changeFlg = '0';
                    updTarget.add(oi.Agcmmc);
                    system.debug('oi.Agcmmc:' + oi.Agcmmc);
                }
                if (oi.changeFlgRt == '1' && oi.con.id != null) {
                    oi.changeFlgRt = '0';
                    updOpps.add(oi.con);
                }
            }
            if (updTarget.size() > 0) {
                system.debug('updTarget.size:' + updTarget.size() );
                upsert updTarget;
            }
            if (updOpps.size() > 0) {
                update updOpps;
            }
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '保存完了'));
        } catch (Exception e) {
            system.debug(e);
        }
        if (saveType == '1') {
            searchOppInner();
            saveType = '';
        } else if (saveType == '2') {
            sortTable();
            saveType = '';
        } else {}
        return null;
    }
    //-----------------------  升降序 ----------------------------------------------------------------
    public PageReference sortTable() {
        oppRecords = new List<ConMeetInfo >();
        system.debug('sortKey' + sortKey); //10
        system.debug('preSortKey' + preSortKey); //null
        if (this.sortKey == this.preSortKey) {
            if (String.isBlank(this.sortKey) == false) {
                this.sortOrderAsc = !this.sortOrderAsc;
                this.sortOrder[Integer.valueOf(this.sortKey)] = (this.sortOrderAsc == true ? '↑' : '↓');
            }
        } else {
            this.sortOrderAsc = true;
            if (String.isBlank(this.preSortKey) == false) {
                this.sortOrder[Integer.valueOf(this.preSortKey)] = '　';
            }
            this.sortOrder[Integer.valueOf(this.sortKey)] = (this.sortOrderAsc == true ? '↑' : '↓');
        }
        this.preSortKey = this.sortKey;
        setLayoutRWInfo();
        searchOppInner();
        return null;
    }
    //-------------------------自定义 ConMeetInfo 数据结构----------------------------------------------------------
    class ConMeetInfo  {
        public Contact con { get; set; }
        public Boolean canEdit { get; private set; }
        public Boolean hasError { get; private set; }
        public Boolean hasFieldError { get; private set; }
        public Integer lineNo { get; private set; }
        public String changeFlg { get; set; }
        public String changeFlgRt { get; set; }
        public MeetingManagement__c Agcmmc { get; set; }
        public ConMeetInfo (Contact record, MeetingManagement__c mmc) {
            con = record;
            canEdit = true;
            hasError = false;
            hasFieldError = false;
            lineNo = 0;
            changeFlg = '0';
            changeFlgRt = '0';
            Agcmmc = mmc;
        }
    }
    //------------------------------------------------------------------------------------------------------------
}