一、前置条件-文本类字段 1.文本类字段设置前置条件一定要用三段式:前端看到文本类字段为空,数据库里有时储存的是一个空格符 ①文本不为空:文本<>null and 文本<> '' and 文本<> ' ' ②文本为空:文本==null Or 文本=='' Or 文本==' ' 2.判断文本是否包含某个值:文本.find('XXX')>=0 3..find('str'),返回目标字符的位置,>=0则代表字符存在(0表示第1位,1表示第2位,以此类推) 4..find('str')是python语句;like ‘%XXX%’是sql语句,作用同.find('str') 5.实体服务规则/字段值更新/校验规则不支持sql语句,所以不支持like '%XXX%' 6.过滤语句支持sql语句,所以支持用 like '%XXX%' 进阶用法 设置文本='1234567890', 则:截取文本前三位: 文本[0:3]= '123' 或者 文本[:3]= '123' 截取文本后三位:文本[-3:]= '890' 截取文本第三位: 文本[2]= '3' 截取文本倒数第三位:文本[-3]= '8' 截取所有文本:文本[:]='1234567890' 倒叙截取所有文本:文本[::-1]= '0987654321' 截取文本第三位到第五位:文本[2:5]= '345' 截取文本第三位到倒数第二位:文本[2:-2]= '345678' 截取文本倒数第五位到第八位:文本[-5:8]= '678' 截取文本倒数第七位到倒数第六位:文本[-7:-5]= '45' 二、前置条件-日期类字段 1.日期字段不能直接与字符串常量进行比较: 需要采用.ToString('yyyy-MM-dd')函数,把日期转换为字符串进行比较: F_JD_Date.ToString('yyyy-MM-dd') == '2016-07-07’ 2.判断日期是否大于今天:F_JD_Date>=@currentshortdate 3.取日期的年度:F_JD_Date.Date.Year 取日期的月份:F_JD_Date.Date.Month 取日期的天号:F_JD_Date.Date.Day 4.计算日期差: (F_JD_Date1 - F_JD_Date2).Days 计算月份差: (F_JD_Date1 - F_JD_Date2).Months 计算年度差: (F_JD_Date1 - F_JD_Date2).Years 5.增加天数:F_JD_Date2=F_JD_Date1.AddDays(-1) 增加月份:F_JD_Date2=F_JD_Date1.AddMonths(-1) 增加年份:F_JD_Date2=F_JD_Date1.AddYears(-1) 进阶应用 1.取每月第一天:FSTARTDate=FDate.AddDays(1-float((FDate.ToString("dd")))) 2.取每个月最后一天(复杂):FENDDate =FDate.AddDays(1-float((FDate.ToString("dd")))).AddMonths(+1).AddDays(-1) 长日期字段 1.长日期/时间/打印时间/ 与具体的时间作比较:F_JD_Date.ToString('yyyy-MM-dd hh:mm:ss') = '2016-07-07 10:05:33' 2.与当前时间作比较:F_JD_Date>@currentlongdate 前置条件-单选辅助资料字段 编码:F_JD_Assistant <>null And F_JD_Assistant.FNumber=='XXX' 名称:F_JD_Assistant <>null And F_JD_Assistant.FDataValue.ToString()== 'XXX' 【注意】因为多语言文本字段是按照语言隔离控制的,所以需要使用.ToString()函数,转换成纯文本。 前置条件-单选下拉列表字段 下拉列表不为空:F_JD_Combo<>null And F_JD_Combo<>'' AndF_JD_Combo<>' ' 下拉列表等XXX:F_JD_Combo=='XXX',XXX代表所查询的枚举项值 【注意】下拉列表不能用枚举项名称作为前置条件 前置条件-分组字段 编码:F_JD_Group <>null And F_JD_Group.FNumber==‘XXX’ 名称:F_JD_Group<>null And F_JD_Group.FName.ToString()=='XXX' 前置条件-复选框字段 判断复选框字段勾选:FPayBox 或者 FPayBox==1 或者 FPayBoxtrue 或者 FPayBox==True 判断复选框字段不勾选:FPayBox ==0 或者 FPayBoxfalse 或者 FPayBox==False 注意true,不要写成ture 前置条件-单据状态字段 单据状态<>null and 单据状态=='XXX',XXX代表所需要判断的状态值 前置条件-单据类型字段 单据类型为空:单据类型==null or 单据类型=='' or单据类型==' ' 单据类型不为空:单据类型<>null and单据类型<>'' and单据类型<>' ' 单据类型<>null And 单据类型.编码== 'XXX' 前置条件-数值型字段 数量1>数量2 或者 数量1>0 四舍五入:小数2 = round (小数1,精度位数) 向下取整:小数2= int (小数1) 向上取整:小数2= int ( round (小数1+ 0.4999999999 ) ) 前置条件-多类别基础资料列表字段(比如往来单位类型) 多类别基础资料列表==‘XXX’, XXX代表所需要判断的具体基础资料英文标识: ①客户:BD_Customer ②供应商:BD_Supplier ③员工:BD_Empinfo ④部门:BD_Departmnet ⑤其他往来单位:FIN_OTHERS ⑥组织架构:ORG_Organizations ⑦银行:BD_BANK(最好能记住) 前置条件-多类别基础资料字段(比如往来单位) 多类别基础资料列表=='XXX' and 多类别基础资料.FNumber=='XXX' 需要注意的是,多类别基础资料因为集合了多种基础资料,只能设置共性的属性作为条件。不能取到某种基础资料的特有属性作为条件。 如果一定要取特有属性作为条件,则需要添加基础资料字段,设置实体服务规则取值。再以新加字段的特有属性作为条件。 是否有源单 判断单据有源单:ISDRAW() 或者 ISDRAW()==true 或者 ISDRAW()==True 或者 ISDRAW()==1 判断单据无源单:ISDRAW()==false 或者 ISDRAW()==False 或者 ISDRAW()==0 注意不可缺少(),注意不能使用isdraw/IsDraw,注意不能使用TRUE/FALSE 或者可以变通的用单据体的源单类型或者源单编号字段结合遍历语句判断是有有源单 是否已下推 判断单据已经下推:ISPUSH ()或者ISPUSH ()==true或者ISPUSH ()==True或者ISPUSH ()==1 判断单据未下推:ISPUSH ()==false或者ISPUSH ()==False或者ISPUSH ()==0 注意不可缺少(),注意不能使用ispush/IsPush,注意不能使用TRUE/FALSE 或者可以变通的取下游单据反写的字段作为条件 组织字段 组织<>null And 组织.编码=='XXX' 组织==@currentorgid(当前登录组织) 用户/创建人/修改人/打印人字段 用户<>null And 用户.编码=='XXX’ 用户==@userid(当前登录用户) 前置条件-基础资料字段 1.基础资料字段,F_JD_Base返回的是一个复杂对象 BaseFieldDynamicRow,包含了很多的属性,不能与一个简单常量进行比较。如 F_JD_Base == '资料名称',达不到预期效果。需要明确的指定属性与常量值进行比较: 2.内码:F_JD_Base<>null andF_JD_Base.Id == 100001 3.使用编码:F_JD_Base<>null andF_JD_Base.FNumber =='GW0001' 或者 F_JD_Base<>null and F_JD_Base['Number']=='GW0001' 4.使用名称:F_JD_Base<>null andF_JD_Base.FName.ToString() == '采购员' 注意:写条件最好是一步一步来,写全写对,不要只写F_JD_Base.FNumber == 'GW0001' 基础资料字段.基础资料属性(比如申请部门.上级部门) 1.编码:F_JD_Base<>null andF_JD_Base.FProperty<>null and F_JD_Base.Fproperty.Number =='GW0001' 2.名称:F_JD_Base<>null andF_JD_Base.FProperty<>null and F_JD_Base.FProperty['Name'] =='GW0001' 3.注意:需要在申请部门字段上做上级部门的属性引用 基础资料字段.辅助资料属性(比如申请部门.部门属性) 编码:F_JD_Base<>null and F_JD_Base.FDeptProperty <>null andF_JD_Base. FDeptProperty ['Number'] == 'DP02_SYS' 基础资料字段.分组属性(比如申请部门.部门分组) 编码:F_JD_Base<>null and F_JD_Base.FGroup<>null andF_JD_Base.FGroup['Number']=='001' 名称:F_JD_Base<>null and F_JD_Base.FGroup<>null andF_JD_Base.FGroup['Name'].ToString()=='分组1' 多级引用属性做条件(比如申请部门.上级部门.部门属性) 不支持F_JD_Base.FProperty.FDeptProperty['Number']== 'DP02_SYS'多级属性引用作为条件的 标识与绑定实体属性的选择 ①F_JD_Base<>null and F_JD_Base.FNumber == ‘GW0001' FNumber取的是编码的标识 ②同样可以写作:F_JD_Base<>null andF_JD_Base['Number']== 'GW0001' ③F_JD_Base<>null and F_JD_Base.FProperty<>null andF_JD_Base.Fproperty.Number == 'GW0001' Number 取的是编码的绑定实体属性 ④同样可以写作: F_JD_Base<>null andF_JD_Base.FProperty<>null and F_JD_Base.Fproperty['Number']=='GW0001' 建议统一使用['Number']的格式 基础资料属性引用的作用归纳 ①需要基础资料字段做属性引用,基础资料属性字段,才可以选到被引用的属性。 ②实体服务规则/字段值更新事件的前置条件/赋值公式需要引用基础资料属性,否则会报错 ③工作流-流程设计器-流程线/(流程节点-审批动作-参与人方案)-高级 ④预算控制规则-控制单据-控制维度-字段取值来源 【反例】过滤语句与凭证模板的(科目影响因素/核算维度)取值不需要引用属性 写语句注意事项 1.符号的应用 ①写条件语句,等号用==;写赋值语句用=;写过滤语句用= ②不等号可以用<>,也可以用!= ③可以用A in ['xxx', 'xxx','xxx']来替换A=='xxx' or A=='xxx' or A=='xxx' 同理,A not in ['xxx', 'xxx','xxx']替换A<>'xxx'and A<>'xxx' and A<>'xxx' 2.互斥条件的写法: 原条件:A>0 and (B<>null or C in ['xxx', 'xxx']) 互斥条件:A<=0 or (B==null and C not in ['xxx', 'xxx']) 3.能做实体服务规则不做字段值更新事件,原因如下: ①满足条件即触发,不需点击触发 ②配置工作量少(以A=B+C举例) ③条件不满足亦可配置服务 ④易于后续维护与排查 4.粘贴网页/word/excel的语句到BOS编辑器,最好要通过txt文档中转,因为网页的语句可能会带有格式,导致BOS不能识别。 5.实体服务规则/字段值更新事件:A=B+C,需要在前置条件设置B==B and C==C;并且需要勾选B与C两个字段的“即时触发字段值更新事件” 6.给单据体字段赋值,需要在单据体上设置实体服务规则,或者单据体字段的字段值更新事件。不能是单据头的实体服务规则。 if…else语句 ①'赋值a' if (条件=='xxx')else '赋值b' ②'赋值a' if (条件1=='xxx')else ('赋值b' if (条件2=='xxx')else '赋值c') ③'赋值a' if (条件1=='xxx')else ('赋值b' if (条件2'==xxx')else ('赋值c' if (条件3=='xxx')else '赋值d')) 即时触发字段值更新事件的作用 ①为字段值更新事件/实体服务规则的前置条件字段触发前置条件。 ②影响新增修改单据时,数值型字段汇总到上级字段的功能实时触发更新。 ③手工新增/修改单据时,在单据体底端实时统计数值型字段的汇总值。 ④单选按钮组字段作为前置条件(包含字段值更新与实体服务规则),单选按钮字段需要勾选该属性才能生效。 【注意】自定义的字段,默认不勾选“即时触发字段值更新事件”。 计数遍历 len(filter(lambda x:x.FExpID<>null and x.FExpID.FName=='业务招待费', FEntity))>0 ①len:计数; ②filter:过滤;③ lambda:遍历;④ x:x. 固定写法;⑤ FExpID:费用项目字段的标识;⑥ FExpID.FName:费用项目.名称的标识 ;⑦ FEntity:费用报销单的明细单据体的标识 语句大意:先使用lambda函数对FEntity单据体做遍历操作,再使用filter函数,按照FExpID<>null andFExpID.FName=='业务招待费'作为条件,将满足条件的明细行过滤出来,最后len函数对满足条件的明细行做计数统计,得到的数值与0做比较返回true或者false。 求和遍历 FExpAmountSum=sum(map(lambda x:x.FExpenseAmount, FEntity) ① FExpAmountSum :单据头汇总金额字段的标识; ②sum:求和;③ map:映射;④ lambda:遍历;⑤ x:x. 固定写法;⑥ FExpenseAmount:单据体费用金额字段的标识;⑥FEntity:费用报销单的明细单据体的标识 语句大意:先使用lambda函数对FEntity单据体做遍历操作,再使用map函数,将FExpenseAmount字段从明细行映射挑选出来组成一个新的集合;最后使用sum函数对集合里面的所有元素做求和汇总,得到的数值赋值给FExpAmountSum字段。 求和遍历 经典案例 【需求】报销单申请报销金额不能超过收票金额之和(不能超发票金额报销) 【思路】在BOS为报销单设置保存校验规则,用sum(map(lambda语句求和汇总收票单信息单据体里的收票单金额,再与单据头的申请报销金额汇总字段,做单据合法性校验大小。 【语句】sum(map(lambda x : (x.FRecInv.FSUMALLAMOUNT),FRecInvInfo))<=FReqReimbAmountSum ①FRecInvInfo:费用报销单的收票信息单据体的标识;②FRecInv:收票信息单据体的收票单字段(基础资料)的标识;③FRecInv.FSUMALLAMOUNT:收票单.价税合计的标识。 求和遍历 进阶案例 【业务场景】求和汇总费用报销单费用项目.名称=业务招待费的明细行的费用金额。 【语句1】FExpAmountSum=sum(map(lambdax:x.FExpenseAmount if FExpID<>null and FExpID.FName=='业务招待费’ else 0 , FEntity) 语句大意:先使用lambda函数对FEntity单据体做遍历操作,再使用map函数,按照FExpID<>null andFExpID.FName==‘业务招待费'作为条件,将满足条件的FExpenseAmount字段从明细行映射挑选出来(若不满足条件,FExpenseAmount字段则为0),组成一个新的集合;最后使用sum函数对集合里面的元素做相加统计,得到的数值赋值给FExpAmountSum字段。 【语句2】FExpAmountSum=sum(map(lambda(x:x.FExpenseAmount,filter(lambda(y:y.FExpID<>null and y.FExpID.FName=='业务招待费'), FEntity))))>0 语句大意:先使用lambda函数对FEntity单据体做遍历操作,再使用filter函数,按照FExpID<>null andFExpID.FName==‘业务招待费'作为条件,将满足条件的明细行过滤出来;再使用lambda函数对这部分明细行做遍历操作;再使用map函数,将 FExpenseAmount字段从明细行映射挑选出来,组成一个新的集合;最后使用sum函数对集合里面的元素做相加统计,得到的数值赋值给FExpAmountSum字段。 拼接遍历 FCausa = '\n'.join(o for o in (set(map(lambda xformat(x.FRemark)),FEntity)))) ①FCausa :单据头事由字段的标识;②‘\n’:自动换行符;③.join:拼接;④ o for o in 固定写法;⑤ set:去重; ⑥map:映射;⑦lambda:遍历;⑧format:格式化字符串;⑨FRemark :单据体备注字段的标识;⑩ FEntity:费用报销单的明细单据体的标识 语句大意:先使用format函数对先对FRemark做格式化操作,得到纯文本。再使用lambda函数对FEntity单据体做遍历操作,再使用map函数,将格式化后的字符串从明细行映射挑选出来,组成一个新的集合;再使用set函数,对集合里的元素做去重操作,去重后按照原有的顺序组成新的集合。最后使用join函数对集合里面的元素,使用自动换行符'\n'做拼接操作,得到的字符串赋值给FCausa字段。 遍历语句注意事项 适用范围 1.支持单据头实体服务规则 2.支持表单服务策略与校验规则 3.不支持单据体实体服务规则 4.不支持字段值更新事件 多单据体遍历 不支持同时遍历多个单据体/子单据体 业务场景:同时对采购订单明细单据体的价税合计字段求和,同时对自定义的子单据体的金额字段求和,然后两者作大小比较 遍历语句 其他应用 基础资料单据体字段 如需对基础资料字段,单据体中属性进行比较,也需要使用lambda进行遍历: 【需求】判断申请人(基础资料员工)字段的任岗信息单据体上是否至少存在一行就任岗位.名称=财务经理的明细行。 【语句】len(filter(lambda xx['Post']['Name'].ToString() =='财务经理' ), FStaffId.PostEntity)) >0 语句说明: ①FStaffId:申请人字段的标识;② PostEntity:基础资料员工的员工任岗信息单据体的ORM实体名;③Post:基础资料员工的员工任岗信息单据体的就任岗位字段的绑定实体属性;④Name:Post的名称属性的绑定实体属性 前置条件-多选类字段 1.多选基础资料未录入:len( FMulBase )<= 0 或者 FMulBase.Count<=0 多选基础资料不为空:len( FMulBase ) > 0 或者FMulBase.Count>0 【注意】只能是Count,不能是count或者COUNT。 多选基础资料字段包含编码为001的值:len(filter(lambdaxx.Number=='001'),F_xkcw_MulBase))>0 多选基础资料字段不包含编码为001的值:len(filter(lambdaxx.Number=='001'),F_xkcw_MulBase))<=0 2.多选辅助资料字段为空:MulAssistant==null 多选辅助资料字段不为空:MulAssistant<>null 多选辅助资料字段包含编码为China的值: len(filter(lambda xx.F_xkcw_MulAssistant<>null andx.F_xkcw_MulAssistant.FNumber=='China'),F_xkcw_MulAssistant))>0 3.有选择某一个枚举项:多选下拉列表.find('枚举项值')!=-1 没有选择某一个枚举项:多选下拉列表.find('枚举项值')==-1 是否都有勾选两个枚举项:多选下拉列表.find('枚举项值a')!=-1 and 多选下拉列表.find('枚举项值b')!=-1 是否至少有勾选两个枚举项其一:多选下拉列表.find('枚举项值a')!=-1 or 多选下拉列表.find('枚举项值b')!=-1 两个枚举项都不勾选:多选下拉列表.find('枚举项值a')==-1 and 多选下拉列表.find('枚举项值b')==-1 两个枚举项至少其一不勾选:多选下拉列表.find('枚举项值a')==-1 or 多选下拉列表.find('枚举项值b')==-1 过滤语句 过滤与高级过滤 1.基础资料字段的特有功能 2.高级过滤的过滤条件可以直接粘贴语句的 3.均支持python与sql的语法 需求分析 【需求1】在采购增值税专用发票的收票信息页签,选择发票时,只能选择到查验状态=已查验的收票单 【语句】FISEXAMINE='1' FISEXAMINE:收票单.查验状态的标识 【需求2】在采购增值税专用发票选择物料时,只能选择到物料.默认供应商=单据头.供应商的物料。 【语句】FDefaultVendor=GetValue(FSUPPLIERID) FDefaultVendor:物料.默认供应商的标识 FSUPPLIERID:单据头.供应商的标识 【需求5】费用报销单,想要实现:当申请部门不为空时,往来单位供应商F8,按照供应商.负责部门=申请部门做过滤;当申请部门为空时,往来单位供应商F8,不做限制。 【语句用法】case when 条件语句 then 条件满足时的过滤语句 else 条件不满足时的过滤语句 end 特点:作用类同于if…else语句 【具体语句】FDeptId=CASE WHEN (GetValue(FRequestDeptID) <>0 andGetValue(FRequestDeptID) is not null) THEN GetValue(FRequestDeptID) ELSEFDeptID END 语句缺陷 【语句缺陷】1.不管前置条件是否满足,基础资料都必须使用FDeptId属性作为过滤的依据。若是想要实现当条件不满足时,使用非FDeptId属性作为过滤的依据,就没办法实现。 2.因为select与casewhen结合的语句,select子查询语句只能返回1个值(select若不与case when结合,是可以返回多个值的),但是截图里的语句需要用到in,会返回多个值。所以该语句会报错不能实现需求。 【需求6】当申请人字段(基础资料员工)不为空时,岗位信息字段(基础资料岗位信息)F8开窗选择(或者模糊查询选择、快速录入)时,只可选择申请人任岗的并且没被禁用的岗位。否则,岗位信息字段能选到所有的岗位。 【语句1】FPOSTID in (select FPOSTID fromT_BD_STAFF where FEMPINFOID = GetValue(申请人字段的标识) ANDFFORBIDSTATUS = 'A') 【语句2】FPOSTID in (select t1.FPOSTID fromT_BD_STAFF t1 inner join T_ORG_POST t2 on t1.FPOSTID = t2.FPOSTID wheret1.FEMPINFOID = GetValue(申请人字段的标识) AND t1.FFORBIDSTATUS= ‘A’) 【语句术语具体说明】 ①T_ORG_POST:基础资料岗位信息-单据头实体岗位信息的表名。②FPOSTID:基础资料岗位信息的主键字段名/岗位信息表T_ORG_POST的Id,也就是岗位信息本身。③FPOSTID:基础资料员工任岗信息-就任岗位字段的字段名。④T_BD_STAFF:基础资料员工任岗信息-单据头实体员工信息的表名。⑤FEMPINFOID:基础资料员工任岗信息-员工字段的字段名。⑥FFORBIDSTATUS:基础资料员工任岗信息-禁用状态字段的字段名。A是未禁用。 语句逻辑具体讲解 【语句大意】1.员工任岗表T_BD_STAFF定义为t1,岗位信息表T_ORG_POST定义为t2。 2.根据t1.FPOSTID = t2.FPOSTID的匹配关系将t1表与t2表通过inner join(内拼接)语句拼接成一个新表。 3.在新表里面按照条件t1.FEMPINFOID = GetValue(申请人字段的标识) AND FFORBIDSTATUS = 'A'过滤出符合条件的记录明细。 4.在这些记录里面映射出FPOSTID字段作为元素组成一个集合。 5.单据的岗位信息字段的属性FPOSTID与该集合的元素用in语句做匹配过滤。 【需求7】当部门字段不为空时,员工字段F8开窗选择时,只可选择在部门字段下勾了负责人岗位的岗位任岗的,并且没被禁用的员工。否则,员工F8开窗选择,能选到没被禁用的所有员工。 【举例】财务部 有三个岗位(财务总监,会计,出纳),其中财务总监勾选负责人岗位。部门字段选择财务部后,再选择员工字段,只能选择员工任岗为财务总监的员工。 【语句】FID in (select t1. FEMPINFOID from (T_BD_STAFF t1 inner joinT_HR_EMPINFO t2 on t1. FEMPINFOID = t2.FID) inner join T_ORG_HRPOST t3 onG.FPOSTID= t1.FPOSTID where t1. FDEPTID = GetValue(FRequestDeptID) ANDt1.FFORBIDSTATUS = 'A' and t3.FLEADERPOST ='1') 修改枚举项名称 【需求】想要修改报销单发票类型字段的普通发票的名称,以及新增发票类型。 【错误做法】直接在BOS拓展报销单,直接修改发票类型关联的枚举类型:发票类型(财务使用)的枚举项名称,与添加新的枚举项 【后果】系统每一次升级,都会还原系统预置的枚举项名称,并且丢失新加的枚举项信息 【正确做法】参照发票类型(财务使用),新建一个枚举类型,与预置的枚举项值保持一致(枚举项名称可以做修改),新增枚举项。发票类型字段关联新建的枚举类型。 BOS经典案例分析 差旅费报销单BOS打开报错 【原理】出差申请单与费用申请单and差旅费报销单与费用报销单在BOS的构造上,是继承与被继承的关系,所以在费用申请单及其拓展所做的一切配置,都会同步配置在出差申请单上。反之则不然。 【具体原因】上述报错截图是由于先在出差申请单上添加了一个标识为F_UVPC_Assistant1的字段。后来在费用申请单上,又人为手工的添加了一个同样标识为F_UVPC_Assistant1的字段,由于继承与被继承的关系,在出差申请单上也会同步新增一个标识为F_UVPC_Assistant1的字段。造成了出差申请单上字段标识重复。BOS重新打开出差申请单的拓展时,触发了字段标识唯一性的校验,从而会有上述的报错。 两个字段作比较 【需求】列表过滤想要进行两个金额字段的比较,比如过滤出A字段不等于B字段的单据,如何实现? 【方法】需要BOS后台为字段A/字段B配置过滤比较符号集:200 【用途】①单据列表过滤 ②数据规则授权 ③凭证模板的分录行生成条件 ④选单条件策略 自动下推服务 1.审核操作上自动下推服务 2.工作流的自动下推动作 3.子系统的管理参数 注意:三者只能择其一,不能重复设置 注意:自动下推是整单下推的。不能以单据体字段作为条件,控制只下推满足条件的明细行。 作者:cq_l 来源:金蝶云社区 著作权归作者所有。未经允许禁止转载,如需转载请联系作者获得授权。
|