Browse Source

doc: 添加文档注释

dulip3ng 3 weeks ago
parent
commit
533a639cb9
1 changed files with 687 additions and 3 deletions
  1. 687 3
      README.md

+ 687 - 3
README.md

@@ -62,7 +62,7 @@ nebula>tests>page_test目录下任选一个test开头测试文件
 | HeadPage   | 单据头    | click_button()<br/>change_sheet()<br/>set_value()<br/>set_checked()<br/>set_text_in_head_body()<br/>set_base_in_head_body()<br/>get_value()                                                                                                                                             |v1.0.0|
 | BodyPage   | 单据体    | change_sheet()<br/>click_button()<br/>click_line()<br/>set_value()<br/>get_row_count()<br/>get_value()<br/>set_checked()<br/>set_text_in_body_head()<br/>set_select_in_body_head()<br/>set_base_in_body_head()<br/>get_text_in_body_head()<br/>get_select_in_body_head()<br/>get_base_in_body_head() |v1.0.0|
 | ListPage   | 单据列表   | wait_list_loaded()<br/>click_button()<br/>check_line_by_rows()<br/>open_bill_by_row()<br/>get_value()<br/>get_bill_no()<br/>get_row_count()<br/>check_line_by_field_value()<br/>field_filter()                                                                                          |v1.0.0|
-| FilterPage | 过滤框    |check_entity()<br/>filter()|v1.0.0|
+| FilterPage | 过滤框    |check_all_org()<br/>uncheck_all_org()<br/>check_org()<br/>click_tool_bar_button()<br/>set_condition()<br/>set_operator()<br/>set_logic()<br/>set_condition_value()<br/>click_ok_button()<br/>set_condition_row()<br/>filter()|v1.0.0|
 | PushPage   | 选单下推页面 |push_draw_bill()|v1.0.0|
 
 ## API说明
@@ -233,7 +233,7 @@ head_page.set_value("维度选择", "内销", "袖长身长")
 + <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
     
     字段值
-+ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_type</span> str(可选)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_type</span> FieldType(可选)
     
     字段类型
   + FieldType.TEXT 文本
@@ -241,6 +241,7 @@ head_page.set_value("维度选择", "内销", "袖长身长")
   + FieldType.BASE 基础资料
   + FieldType.TEXTAREA 大文本
   + FieldType.MULTISELECT 多选基础资料
+
 >field_type参数绝大多数情况下不需要,此参数仅用于特殊情况下验证字段类型解析是否正常运行
 
 #### set_checked()
@@ -319,9 +320,692 @@ head_page.get_value("衬衣订单号")
   + FieldType.BASE 基础资料
   + FieldType.TEXTAREA 大文本
   + FieldType.MULTISELECT 多选基础资料
+
+>field_type参数绝大多数情况下不需要,此参数仅用于特殊情况下验证字段类型解析是否正常运行
+
+**返回**
++ str 
+
+  字段值
+
+### BodyPage类
+单据体
+#### change_sheet()
+v1.0.0添加
+
+切换单据体页签
+
+**用法**
+```python
+body_page.change_sheet("明细信息")
+body_page.change_sheet("物料信息", 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">sheet_name</span> str
+    
+    页签名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">order</span> int(可选)
+    
+    页签序号,存在同名页签时需提供,从1开始(精确匹配)
+
+#### click_button()
+v1.0.0添加
+
+点击单据体按钮或子按钮
+
+**用法**
+```python
+body_page.click_button("新增行")
+body_page.click_button("新增行", "复制行")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">button_name</span> str
+    
+    按钮名称(精确匹配)
+
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">sub_button_name</span> str(可选)
+    
+    子按钮名称(精确匹配)
+
+#### click_line()
+v1.0.0添加
+
+选中单据体行
+
+**用法**
+```python
+body_page.click_line(1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    单据体行号(从1开始)
+
+#### set_value()
+v1.0.0添加
+
+单据体字段赋值
+
+**用法**
+```python
+body_page.set_value("衬衣订单号", "26024001", 1)
+body_page.set_value("成品仓库", "CPCK001", 1, 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    字段值
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">order</span> int(可选)
+    
+    序号,存在同名字段时指明第几个(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_type</span> FieldType(可选)
+    
+  字段类型
+  + FieldType.TEXT 文本
+  + FieldType.SELECT 下拉列表
+  + FieldType.BASE 基础资料
+
 >field_type参数绝大多数情况下不需要,此参数仅用于特殊情况下验证字段类型解析是否正常运行
 
+#### get_row_count()
+v1.0.0添加
+
+获取单据体总行数
+
+**用法**
+```python
+body_page.get_row_count()
+```
+**返回**
++ str
+
+  行数
+
+#### get_value()
+v1.0.0添加
+
+单据体字段取值
+
+**用法**
+```python
+body_page.get_value("成品仓库", 1)
+body_page.get_value("成品仓库", 1, 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">order</span> int(可选)
+
+    序号,存在同名字段时指明第几个(从1开始)
+    
+**返回**
++ str
+
+  字段值
+
+#### set_checked()
+v1.0.0添加
+
+点击单据页签的"x"图标关闭单据
+
+**用法**
+```python
+body_page.set_checked("控制发货数量", 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    复选框字段名称(精确匹配)
+
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
+
+#### set_text_in_body_head()
+v1.0.0添加
+
+单据体中单据头形式文本字段赋值,如:销售订单->物料数据->面料规格
+
+**用法**
+```python
+body_page.set_text_in_body_head("面料规格", "50/60")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    字段值
+
+#### set_select_in_body_head()
+v1.0.0添加
+
+单据体中单据头形式下拉列表字段赋值,如:销售订单->物料数据->货主类型
+
+**用法**
+```python
+body_page.set_select_in_body_head("货主类型", "供应商")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    字段值
+
+#### set_base_in_body_head()
+v1.0.0添加
+
+单据体中单据头形式基础资料字段赋值,如:销售订单->物料数据->面料来源
+
+**用法**
+```python
+body_page.set_base_in_body_head("面料来源", "自备")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    字段值
+
+#### get_text_in_body_head()
+v1.0.0添加
+
+单据体中单据头形式文本字段取值,如:销售订单->物料数据->面料规格
+
+**用法**
+```python
+body_page.get_text_in_body_head("面料规格")
+body_page.get_text_in_body_head("面料规格", 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">order</span> int(可选)
+    
+    序号,存在同名字段时指明第几个(从1开始)
+
+**返回**
++ str
+
+  字段值
+
+#### get_select_in_body_head()
+v1.0.0添加
+
+单据体中单据头形式下拉列表字段取值,如:销售订单->物料数据->货主类型
+
+**用法**
+```python
+body_page.get_select_in_body_head("货主类型")
+body_page.get_select_in_body_head("货主类型", 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">order</span> int(可选)
+    
+    序号,存在同名字段时指明第几个(从1开始)
+
+**返回**
++ str
+
+  字段值
+
+#### get_base_in_body_head()
+v1.0.0添加
+
+单据体中单据头形式下拉列表字段取值,如:销售订单->物料数据->货主类型
+
+**用法**
+```python
+body_page.get_base_in_body_head("面料来源")
+body_page.get_base_in_body_head("面料来源", 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">order</span> int(可选)
+    
+    序号,存在同名字段时指明第几个(从1开始)
+
+**返回**
++ str
+
+  字段值
+
+### ListPage类
+单据列表页面
+#### wait_list_loaded()
+v1.0.0添加
+
+等待页面加载完成,当页面加载出第一行第一列表格时,停止等待
+
+>注意:
+> 
+> 1. 有时表格加载完成但界面仍存在wait_loading转圈图标,不做处理由playwright自动处理后续元素可操作性检查
+> 2. 默认等待时间受 expect.set_options(timeout=)全局控制
+> 3. 此方法只能检测有数据的列表是否加载完成,因为无数据时不会出现td表格元素,无法区分是否加载完成
+
+**用法**
+```python
+list_page.wait_list_loaded()
+```
+#### click_button()
+v1.0.0添加
+
+点击列表按钮、子按钮或孙子按钮
+
+**用法**
+```python
+list_page.click_button("新增")
+list_page.click_button("新增", "复制")
+list_page.click_button("选项", "套打", "套打设置")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">button_name</span> str
+    
+    按钮名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">sub_button</span> str(可选)
+    
+    子按钮名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">grandson_button</span> str(可选)
+    
+    孙子按钮名称(精确匹配)
+
+#### check_line_by_rows()
+v1.0.0添加
+
+勾选指定行
+
+**用法**
+```python
+list_page.check_line_by_rows(1)
+list_page.check_line_by_rows(1,2,3)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">rows</span> int
+    
+    行号(从1开始,可填多个)
+
+#### open_bill_by_row()
+v1.0.0添加
+
+根据行号打开单据
+
+>此方法是通过点击行号的单据编号字段打开单据,确保该行单据编号字段有值
+
+**用法**
+```python
+list_page.open_bill_by_row(1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
+
+#### get_value()
+v1.0.0添加
+
+获取列表字段值
+
+**用法**
+```python
+list_page.get_value("衬衣订单号", 1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
+
 **返回**
 + str
-  
   字段值
+
+#### get_bill_no()
+v1.0.0添加
+
+根据行号获取单据编号字段值
+
+>需确保给定行号单据编号字段有值
+
+**用法**
+```python
+list_page.get_bill_no(1)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
+
+**返回**
++ str
+  单据编号
+
+#### get_row_count()
+v1.0.0添加
+
+获取列表总行数
+
+**用法**
+```python
+list_page.get_row_count()
+```
+**返回**
++ str
+  列表行数
+
+#### check_line_by_field_value()
+v1.0.0添加
+
+根据给定字段名、字段值勾选对应行
+
+>当列表中存在多个相同字段值行时,只勾选第一行
+
+**用法**
+```python
+list_page.check_line_by_field_value("衬衣订单号", "26022021")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    字段值(精确匹配)
+
+#### field_filter()
+v1.0.0添加
+
+字段过滤,点击列表列名右侧小漏斗,进行列表简单过滤
+
+**用法**
+```python
+list_page.field_filter("销售类别", "内销")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_name</span> str
+    
+    字段名(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    字段值(精确匹配)
+
+### FilterPage类
+单据过滤页面
+#### check_all_org()
+v1.0.0添加
+
+勾选“所有组织”复选框,如果已经是勾选状态则不操作
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.check_all_org()
+```
+
+#### uncheck_all_org()
+v1.0.0添加
+
+取消勾选所有组织复选框,如果已经未勾选状态则不操作
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.uncheck_all_org()
+```
+
+#### check_org()
+v1.0.0添加
+
+根据给定组织编码或名称,勾选组织多选列表
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.check_org("100.1")
+filter_page.check_org("100.1", "鲁泰纺织股份")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">orgs</span> str
+    
+    组织代码或名称,可传多个(模糊匹配)
+
+#### check_entity()
+v1.0.0添加
+
+勾选指定实体类型
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+>注意:
+>1. 未进行勾选状态判断,未勾选状态下调用一次为勾选,再次调用为取消勾选
+>2. 综合过滤方法filter()中不执行此操作,如确需调整过滤条件所在实体,在调用filter()方法前调用此方法
+
+**用法**
+```python
+filter_page.check_entity("明细信息")
+filter_page.check_entity("明细信息", "财务信息")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">entitys_name</span> str
+    
+    实体类型名称,可传多个(精确匹配)
+
+#### click_tool_bar_button()
+v1.0.0添加
+
+点击过滤框页面菜单行按钮
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.click_tool_bar_button("删除全部")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">button_name</span> str
+    
+    按钮名称(精确匹配)
+
+#### set_condition()
+v1.0.0添加
+
+按行设置过滤条件项
+
+>注意:
+>1. 绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+>2. 部分单据中存在相同字段名在不同页签的情况,此时模糊匹配无法找到正确选项值,推荐使用条件项全称精确匹配
+
+**用法**
+```python
+filter_page.set_condition(1, "基本信息-衬衣订单号")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">condition_name</span> str
+    
+    条件项全称(模糊匹配)
+
+#### set_operator()
+v1.0.0添加
+
+设置过滤条件操作符号
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.set_operator(1, "包含")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">operator</span> str
+    
+    操作符名称(精确匹配)
+
+#### set_logic()
+v1.0.0添加
+
+设置逻辑符号,如并且
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.set_logic(1, "并且")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    逻辑操作符名称(精确匹配)
+
+#### set_condition_value()
+v1.0.0添加
+
+条件值字段赋值
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.set_condition_value(1, "26024001")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">value</span> str
+    
+    条件值(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">field_type</span> FieldType(可选)
+    
+  字段类型
+  + FieldType.TEXT 文本
+  + FieldType.SELECT 下拉列表
+  + FieldType.BASE 基础资料
+  + FieldType.DATE 日期
+  + FieldType.TEXTAREA 大文本
+
+>field_type参数绝大多数情况下不需要,此参数仅用于特殊情况下验证字段类型解析是否正常运行
+
+#### click_ok_button()
+v1.0.0添加
+
+点击确定按钮,开始过滤
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.click_ok_button()
+```
+
+#### set_condition_row()
+v1.0.0添加
+
+设置一行过滤条件
+
+>绝大多数情况下调用filter()方法即可实现过滤,无需主动调用此方法,推荐使用filter()方法
+
+**用法**
+```python
+filter_page.set_condition_row(1, "创建日期", operator="今天")
+filter_page.set_condition_row(1, "衬衣订单号", "26024001")
+filter_page.set_condition_row(1, "衬衣订单号", "26024", "包含")
+filter_page.set_condition_row(1, "衬衣订单号", "26024", "包含", "或者")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">row</span> int
+    
+    行号(从1开始)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">condition_name</span> str
+    
+    过滤条件名(模糊匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">condition_value</span> str(可选)
+    
+    过滤条件值(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">operator</span> str(可选)
+    
+    操作符名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">logic</span> str(可选)
+    
+    逻辑符名称(精确匹配)
+
+#### filter()
+v1.0.0添加
+
+根据条件对象进行过滤,默认勾选全部组织
+
+**用法**
+```python
+cond1 = ConditionRow(1, "基本信息-衬衣订单号", "123456", "包含", "或者")
+cond2 = ConditionRow(2, "单据状态", "已审核")
+filter_page.filter(cond1, cond2)
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">condition_row</span> ConditionRow
+    
+    条件行对象(可传多个)
+  + ConditionRow
+    + row: int 行号(从1开始)
+    + condition_name: str 条件名称
+    + condition_value: typing.Optional[str] = None 条件值名称(可选)
+    + operator: typing.Optional[str] = None 操作符名称(可选)
+    + logic: typing.Optional[str] = None 逻辑符名称(可选)
+
+### PushPage类
+选单下推页面
+#### push_draw_bill()
+v1.0.0添加
+
+设置单据、单据类型、转换规则、目标组织进行下推操作
+
+**用法**
+```python
+push_page.push_draw_bill("生产订单")
+push_page.push_draw_bill("生产订单", "犀牛销售订单2生产订单", "直接入库-普通生产", "制衣事业部")
+```
+**参数**
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">bill_name</span> str
+    
+    下游单据名称(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">rule_name</span> str(可选)
+    
+    转换规则(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">bill_type</span> str(可选)
+    
+    单据类型(精确匹配)
++ <span style="background-color: #f6f7f8; border:.1rem solid #0000001a;border-radius:4px">org_name</span> str(可选)
+    
+    目标组织名称(精确匹配)