head_page.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''
  4. @File : head_page.py
  5. @Time : 2024/11/07 15:19:33
  6. @Author : dulip3ng
  7. @Version : 1.0
  8. @Desc : None
  9. '''
  10. import re
  11. from playwright.sync_api import Page, expect, Error
  12. from pages.base_page import BasePage
  13. from pages.locator.head_page_locator import HeadPageLocator
  14. from common.field_type import FieldType
  15. class HeadPage(BasePage):
  16. def click_button(self, button_name:str, sub_button_name:str=None):
  17. """
  18. 点击单据头按钮
  19. :param button_name: 按钮名称
  20. :param sub_button_name: 子按钮名称
  21. :return: None
  22. """
  23. if not sub_button_name:
  24. self.page.locator(HeadPageLocator.BUTTON_ARGS_LOC % button_name).click()
  25. else:
  26. self.page.locator(HeadPageLocator.BUTTON_ARROW_ARGS_LOC % button_name).hover()
  27. self.page.locator(HeadPageLocator.SUB_BUTTON_ARGS_LOC % sub_button_name).click()
  28. def change_sheet(self, sheet_name:str):
  29. """
  30. 点击单据头页签
  31. :param sheet_name: 页签名称
  32. :return: None
  33. """
  34. self.page.locator(HeadPageLocator.SHEET_ARGS_LOC % sheet_name).click()
  35. def _set_text(self, field_name:str, value:str):
  36. """
  37. 单据头文本字段赋值
  38. :param field_name: 字段名
  39. :param value: 字段值
  40. :return: None
  41. """
  42. self.page.locator(HeadPageLocator.TEXT_FIELD_ARGS_LOC % field_name).fill(value)
  43. def _set_base(self, field_name:str, value:str):
  44. """
  45. 单据头基础资料字段赋值
  46. :param field_name: 字段名
  47. :param value: 字段值
  48. :return: None
  49. """
  50. # 直接点击BASE_FIELD_ARGS_LOC input元素可操作性检查不通过,被BASE_FIELD_SPAN_ARGS_LOC span劫持,这里直接对span进行点击
  51. self.page.locator(HeadPageLocator.BASE_FIELD_SPAN_ARGS_LOC % field_name).click()
  52. self.page.locator(HeadPageLocator.BASE_FIELD_ARGS_LOC % field_name).fill(value)
  53. # 输入空格弹出基础资料选项,fill方法会覆盖当前输入内容,使用press_sequentially方法模拟输入
  54. self.page.locator(HeadPageLocator.BASE_FIELD_ARGS_LOC % field_name).press_sequentially(" ")
  55. self.page.locator(HeadPageLocator.BASE_ITEM_ARGS_LOC % value).click()
  56. def _set_select(self, field_name:str, item_value:str):
  57. """
  58. 单据头下拉列表字段赋值
  59. :param field_name: 字段名
  60. :param item_value: 字段值
  61. :return: None
  62. """
  63. # Locator.click()普通点击无法弹出下拉选项值,使用force强制点击
  64. # 注意:force=True强制点击不执行非必要的元素可操作性检查
  65. self.page.locator(HeadPageLocator.SELECT_FIELD_ARGS_LOC % field_name).click(force=True)
  66. self.page.locator(HeadPageLocator.SELECT_ITEM_ARGS_LOC % item_value).click()
  67. def _set_textarea(self, field_name:str, value:str):
  68. """
  69. 单据头大文本框字段赋值
  70. :param field_name: 字段名
  71. :param value: 字段值
  72. :return: None
  73. """
  74. self.page.locator(HeadPageLocator.TEXTAREA_FIELD_ARGS_LOC % field_name).fill(value)
  75. def _set_multiselect(self, field_name:str, values:str):
  76. """
  77. 单据头多选下拉列表字段赋值
  78. :param field_name: 字段名
  79. :param values: 字段值
  80. :return: None
  81. """
  82. self.page.locator(HeadPageLocator.MULTISELECT_FIELD_ARGS_LOC % field_name).click()
  83. for item_value in values:
  84. self.page.locator(HeadPageLocator.MULTISELECT_ITEM_ARGS_LOC % item_value).click()
  85. self.page.locator(HeadPageLocator.MULTISELECT_OK_BTN_LOC).click()
  86. def set_value(self, field_name:str, *values:str, field_type: FieldType = None):
  87. """
  88. 单据头字段赋值统一方法,根据给定或自动识别的字段类型调用不同方法完成赋值
  89. :param field_name: 字段名
  90. :param value: 字段值
  91. :param field_type: 可选参数,字段类型,不填时自动识别字段类型
  92. :return: None
  93. """
  94. if not field_type:
  95. field_type = self.parse_field_type(field_name)
  96. match field_type:
  97. case FieldType.TEXT:
  98. self._set_text(field_name, values[0])
  99. case FieldType.SELECT:
  100. self._set_select(field_name, values[0])
  101. case FieldType.BASE:
  102. self._set_base(field_name, values[0])
  103. case FieldType.TEXTAREA:
  104. self._set_textarea(field_name, values[0])
  105. case FieldType.MULTISELECT:
  106. self._set_multiselect(field_name, values)
  107. def set_checked(self, field_name:str):
  108. """
  109. 单据头勾选复选框
  110. :param field_name: 复选框名
  111. :return: None
  112. """
  113. self.page.locator(HeadPageLocator.CHECKBOX_FIELD_ARGS_LOC % field_name).click()
  114. def set_text_in_head_body(self, field_name:str, value:str, row:int):
  115. """
  116. 单据头中的单据体文本字段赋值
  117. 如样品通知单-接收人页签
  118. :param field_name: 字段名
  119. :param value: 字段值
  120. :param row: 行号,从1开始
  121. :return: None
  122. """
  123. self.page.locator(HeadPageLocator.TRIGGER_IN_HEAD_BODY_FIELD_ARGS_LOC % (field_name, row-1)).click()
  124. self.page.locator(HeadPageLocator.TEXT_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row-1)).fill(value)
  125. def set_base_in_head_body(self, field_name:str, value:str, row: int):
  126. """
  127. 单据头中的单据体基础资料字段赋值
  128. 如样品通知单-接收人页签
  129. :param field_name: 字段名
  130. :param value: 字段值
  131. :param row: 行号,从1开始
  132. :return: None
  133. """
  134. self.page.locator(HeadPageLocator.TRIGGER_IN_HEAD_BODY_FIELD_ARGS_LOC % (field_name, row - 1)).click()
  135. self.page.locator(HeadPageLocator.BASE_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row - 1)).click()
  136. self.page.locator(HeadPageLocator.BASE_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row - 1)).fill(value)
  137. # 输入空格弹出基础资料选项,fill方法会覆盖当前输入内容,使用press_sequentially方法模拟输入
  138. self.page.locator(HeadPageLocator.BASE_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row - 1)).press_sequentially(" ")
  139. self.page.locator(HeadPageLocator.BASE_ITEM_ARGS_LOC % value).click()
  140. def _get_text_value(self, field_name:str) -> str:
  141. """
  142. 单据头文本字段取值
  143. 文本字段有两种形式,一种是可编辑状态,值存放在input元素中,另一种是锁定状态值存放在span元素中,
  144. 默认取input值,500ms超时未取到时取span中的值
  145. :param field_name: 字段名
  146. :return: 字段值
  147. """
  148. try:
  149. locator_input = self.page.locator(HeadPageLocator.TEXT_VALUE_INPUT_ARGS_LOC % field_name)
  150. expect(locator_input).to_be_visible(timeout=500)
  151. return locator_input.input_value()
  152. except AssertionError:
  153. locator_span = self.page.locator(HeadPageLocator.TEXT_VALUE_SPAN_ARGS_LOC % field_name)
  154. expect(locator_span).to_be_visible(timeout=500)
  155. return locator_span.inner_text()
  156. def _get_select_value(self, field_name:str) -> str:
  157. """
  158. 单据头下拉列表字段取值
  159. 下拉列表字段有两种形式,一种是可编辑状态,值存放在input元素中,另一种是锁定状态值存放在span元素中,
  160. 默认取input值,未找到时立即去span中的值
  161. 与取text不同的是text由两个xpath语句获取值,select由一个通用的xpath取值,所以判断方式不同
  162. :param field_name: 字段名
  163. :return: 字段值
  164. """
  165. try:
  166. locator = self.page.locator(HeadPageLocator.SELECT_VALUE_ARGS_LOC % field_name)
  167. return locator.input_value()
  168. except Error:
  169. return locator.inner_text()
  170. def _get_base_value(self, field_name:str) -> str:
  171. """
  172. 获取单据头基础资料字段值
  173. :param field_name: 字段名
  174. :return: 字段值
  175. """
  176. return self.page.locator(HeadPageLocator.BASE_VALUE_ARGS_LOC % field_name).inner_text()
  177. def _get_textarea_value(self, field_name:str):
  178. """
  179. 单据头大文本字段取值
  180. :param field_name: 字段名
  181. :return: 字段值
  182. """
  183. return self.page.locator(HeadPageLocator.TEXTAREA_FIELD_ARGS_LOC % field_name).input_value()
  184. def _get_multiselect_value(self, field_name:str):
  185. """
  186. 单据头多选下拉列表字段取值
  187. :param field_name: 字段名
  188. :return: 字段值
  189. """
  190. return self.page.locator(HeadPageLocator.MULTISELECT_VALUE_ARGS_LOC % field_name).inner_text()
  191. def get_value(self, field_name:str, field_type: FieldType=None) -> str:
  192. """
  193. 单据头字段取值统一方法,根据给定或自动识别的字段类型调用不同取值方法取值
  194. :param field_name: 字段名
  195. :param field_type: 可选参数,字段类型
  196. :return: 字段值
  197. """
  198. if not field_type:
  199. field_type = self.parse_field_type(field_name)
  200. match field_type:
  201. case FieldType.TEXT:
  202. return self._get_text_value(field_name)
  203. case FieldType.SELECT:
  204. return self._get_select_value(field_name)
  205. case FieldType.BASE:
  206. return self._get_base_value(field_name)
  207. case FieldType.MULTISELECT:
  208. return self._get_multiselect_value(field_name)
  209. case FieldType.TEXTAREA:
  210. return self._get_textarea_value(field_name)
  211. case _:
  212. return ""
  213. def _parse_field_type(self, field_name:str) -> FieldType:
  214. """
  215. 分析字段类型,set_value(), get_value()中调用的核心方法
  216. 注意:金蝶版本升级后可能不同字段类型判断依据有变化,字段类型是根据元素"data-attdata"属性值判断,
  217. 定位器可用性检查通过不代表分析字段类型可正常使用
  218. :param field_name: 字段名
  219. :return: 字段类型 FieldType
  220. """
  221. data_role = self.page.locator(HeadPageLocator.PARSE_FIELD_TYPE_ARGS_LOC % field_name).get_attribute("data-attdata")
  222. pattern = "xtype\":\"([a-zA-Z0-9]+)"
  223. match_strs = re.findall(pattern, data_role)
  224. if match_strs:
  225. match match_strs[0]:
  226. case "bosf7field":
  227. return FieldType.BASE
  228. case "kdeditcombo" | "kdcombo":
  229. return FieldType.SELECT
  230. case "kdmulticombo":
  231. return FieldType.MULTISELECT
  232. case "kdtextarea" | "kdlangtextarea" | "kdtabpage":
  233. return FieldType.TEXTAREA
  234. case _:
  235. return FieldType.TEXT
  236. return FieldType.UNKNOWN