HTableForm.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. import { createApp } from 'vue/dist/vue.esm-bundler.js'
  2. import { getTokenHeader } from '~src/api/request/header'
  3. import { isArray, isNullES, toParse } from 'js-fast-way'
  4. //自定义组件或二次封装的组件
  5. import HcTableFormUpload from '~com/plugins/table-form/hc-form-upload.vue'
  6. import HcFormSelectSearch from '~com/plugins/table-form/hc-form-select-search.vue'
  7. import HcFormSelectSearch2 from '~com/plugins/table-form/hc-form-select-search2.vue'
  8. import HcFormCheckboxGroup from '~com/plugins/table-form/hc-form-checkbox-group.vue'
  9. import ElTimePicker from '~com/plugins/table-form/hc-time-picker.vue'
  10. import ElDatePicker from '~com/plugins/table-form/hc-date-picker-1.vue'
  11. import ElRadioGroup from '~com/plugins/table-form/hc-form-radio-group.vue'
  12. import HcEchart from '~com/plugins/table-form/echart.vue'
  13. //修改过的组件
  14. import { ElOption, ElSelect } from 'z-element-plus'
  15. import ElementPlus from 'element-plus'
  16. import zhCn from 'element-plus/es/locale/lang/zh-cn'
  17. const components = {
  18. ElSelect, ElOption, ElDatePicker, ElTimePicker, HcTableFormUpload, ElRadioGroup,
  19. HcFormSelectSearch, HcFormSelectSearch2, HcFormCheckboxGroup, HcEchart,
  20. }
  21. //表单渲染
  22. export default class HTableForm {
  23. static tableFormApp = null
  24. static tableFormVM = null
  25. static createForm({ template, tableForm, keys, appId, pid, onRight, onBlur, onLeftClick, onFormDataChange, onChartRefs }) {
  26. const _this = this
  27. const app = createApp({
  28. //自定义组件,需要把饿了么的组件,或者自定义组件手动传递进来绑定,否则渲染时,自定义组件不会生效
  29. components,
  30. data() {
  31. return {
  32. getTokenHeader: getTokenHeader(),
  33. formData: tableForm,
  34. }
  35. },
  36. //监听数据,伪双向绑定(v-model)
  37. watch: {
  38. formData: {
  39. handler(obj) {
  40. tableForm = obj
  41. this.formDataChange(obj)
  42. },
  43. deep: true,
  44. },
  45. },
  46. methods: {
  47. //表单数据改变
  48. formDataChange(obj) {
  49. if (onFormDataChange) {
  50. onFormDataChange(obj)
  51. }
  52. },
  53. //改变表单数据
  54. setFormData(obj) {
  55. this.formData = obj
  56. },
  57. //鼠标右键菜单
  58. contextmenuClick(a, b, c, d, e, f, event) {
  59. event.preventDefault()
  60. },
  61. //鼠标右键事件
  62. RightClick(a, b, c, d, e, f, event) {
  63. setTimeout(() => {
  64. const KeyName = event?.target?.getAttribute('keyname') || ''
  65. if (onRight) {
  66. event.preventDefault()
  67. onRight(event, KeyName)
  68. }
  69. }, 100)
  70. },
  71. //焦点事件
  72. getInformation() {
  73. },
  74. //日期选择事件
  75. datePickerChange(val, key) {
  76. this.formData[key] = val
  77. },
  78. //上传完成
  79. formUploadSuccess({ src, key }) {
  80. this.formData[key] = src
  81. },
  82. //删除上传的文件
  83. delTableFormFile(key) {
  84. this.formData[key] = ''
  85. },
  86. //失去焦点事件
  87. getRegularExpression(event, reg, msg, a, b, leng, type, c, d) {
  88. const KeyName = event?.target?.getAttribute('keyname') || ''
  89. if (onBlur) {
  90. onBlur(event, KeyName, reg, this.formData[KeyName], msg, leng, type, c, d)
  91. }
  92. },
  93. //远程搜索处理
  94. formRemoteChange(data) {
  95. Object.keys(data).forEach(key => {
  96. this.formData[key] = data[key]
  97. })
  98. },
  99. //多选框处理
  100. checkboxGroupChange({ key, val }) {
  101. this.formData[key] = val
  102. },
  103. //键盘事件 上键
  104. keyupShiftUp(event) {
  105. _this.setKeyupData(event, 'up', keys, pid)
  106. },
  107. //键盘事件 下键
  108. keyupShiftDown(event) {
  109. _this.setKeyupData(event, 'down', keys, pid)
  110. },
  111. //键盘事件 左键
  112. keyupShiftLeft(event) {
  113. _this.setKeyupData(event, 'left', keys, pid)
  114. },
  115. //键盘事件 右键
  116. keyupShiftRight(event) {
  117. _this.setKeyupData(event, 'right', keys, pid)
  118. },
  119. //日期时间框键盘事件
  120. dateKeydown({ type, name }) {
  121. _this.setKeyupData(name, type, keys, pid)
  122. },
  123. //输入左键点击事件
  124. inputLeftClick(event, key) {
  125. setTimeout(() => {
  126. if (onLeftClick) {
  127. onLeftClick(key)
  128. }
  129. }, 100)
  130. },
  131. setChartRefs(el, pKeyId, key) {
  132. if (onChartRefs) onChartRefs(el, pKeyId, key)
  133. },
  134. },
  135. //html标签数据
  136. template,
  137. })
  138. // 饿了么UI框架
  139. app.use(ElementPlus, {
  140. locale: zhCn,
  141. })
  142. const vm = app.mount(appId)
  143. this.tableFormApp = app
  144. this.tableFormVM = vm
  145. return { app, vm }
  146. }
  147. //处理日期范围数据
  148. static setPickerKey(data) {
  149. const pickerKey = data['pickerKey'] || ''
  150. if (pickerKey) {
  151. const pickerKeys = pickerKey.split(',')
  152. for (let i = 0; i < pickerKeys.length; i++) {
  153. const val = data[pickerKeys[i]] || ''
  154. if (val) {
  155. const dataVal = val.replace(/'/g, '"')
  156. data[pickerKeys[i]] = toParse(dataVal) || []
  157. } else {
  158. data[pickerKeys[i]] = []
  159. }
  160. }
  161. }
  162. return data
  163. }
  164. //处理日期时间框的切换事件
  165. static setByClassKeyup(keys, pid = '') {
  166. try {
  167. let poppers = document.getElementsByClassName('hc-table-form-date-picker')
  168. for (let i = 0; i < poppers.length; i++) {
  169. let item = poppers[i], key = ''
  170. const ids = item.getAttribute('class').split('-form-id-')
  171. if (ids.length >= 1) {
  172. key = ids[1]
  173. }
  174. if (ids) {
  175. let panels = item.getElementsByClassName('el-picker-panel__content')
  176. this.setElementsEvent(panels, key, keys, pid)
  177. }
  178. }
  179. } catch (e) {
  180. console.log(e)
  181. }
  182. }
  183. //设置事件
  184. static setElementsEvent(elements, key, keys, pid = '') {
  185. if (elements.length > 0) {
  186. const _this = this
  187. elements[0].addEventListener('keydown', e => {
  188. e.stopPropagation()
  189. if (e.key === 'ArrowUp') {
  190. _this.setKeyupData({ target: { id: key } }, 'up', keys, pid)
  191. } else if (e.key === 'ArrowDown') {
  192. _this.setKeyupData({ target: { id: key } }, 'down', keys, pid)
  193. } else if (e.key === 'ArrowLeft') {
  194. _this.setKeyupData({ target: { id: key } }, 'left', keys, pid)
  195. } else if (e.key === 'ArrowRight') {
  196. _this.setKeyupData({ target: { id: key } }, 'right', keys, pid)
  197. }
  198. }, {
  199. capture: true,
  200. })
  201. }
  202. }
  203. //计算上下左右快捷键的
  204. static setKeyupData({ target }, type, keys, pid = '') {
  205. const key = target.id
  206. //处理快捷键数据和事件
  207. if (key && type && isArray(keys)) {
  208. //计算当前的位置
  209. let left = -1, top = -1
  210. for (let i = 0; i < keys.length; i++) {
  211. if (isArray(keys[i])) {
  212. const index = keys[i].findIndex(id => id === key)
  213. if (index !== -1) {
  214. left = index
  215. top = i
  216. break
  217. }
  218. }
  219. }
  220. if (type === 'up') {
  221. //向上移动
  222. if (top > 0) {
  223. let keyId = ''
  224. const tops = keys[top - 1]
  225. const keyLength = tops.length - 1
  226. if (keyLength < left) {
  227. keyId = tops[keyLength]
  228. } else {
  229. keyId = tops[left]
  230. }
  231. this.setElementFocus(keyId, pid)
  232. }
  233. } else if (type === 'down') {
  234. //向下移动
  235. const tops = keys.length - 1
  236. if (tops > top) {
  237. let keyId = ''
  238. const tops = keys[top + 1]
  239. const keyLength = tops.length - 1
  240. if (keyLength < left) {
  241. keyId = tops[keyLength]
  242. } else {
  243. keyId = tops[left]
  244. }
  245. this.setElementFocus(keyId, pid)
  246. }
  247. } else if (type === 'left') {
  248. //向左移动
  249. if (left > 0) {
  250. const keyId = keys[top][left - 1]
  251. this.setElementFocus(keyId, pid)
  252. }
  253. } else if (type === 'right') {
  254. //向右移动
  255. const lefts = keys[top]
  256. const leftLength = lefts.length - 1
  257. if (leftLength > left) {
  258. const keyId = lefts[left + 1]
  259. this.setElementFocus(keyId, pid)
  260. }
  261. }
  262. }
  263. }
  264. //设置元素焦点
  265. static setElementFocus(key, pid) {
  266. if (key) {
  267. try {
  268. this.getQuerySelector(key, pid)?.focus()
  269. } catch { /* empty */ }
  270. }
  271. }
  272. //获取表单元素
  273. static async getQuerySelector(key, pid = '') {
  274. let dom
  275. if (pid) {
  276. dom = document.querySelector(`#${pid} #${key.toString()}`)
  277. } else {
  278. dom = document.getElementById(key.toString())
  279. }
  280. return dom
  281. }
  282. //设置表单样式
  283. static async setFormStyle(key, name = 'hc-red-border', pid = '', add = false) {
  284. const dom = await this.getQuerySelector(key, pid)
  285. const parent = dom?.parentElement ?? ''
  286. if (dom?.tagName === 'INPUT') {
  287. const parentElement = parent?.parentElement ?? ''
  288. this.setFormClass(parentElement, name, add)
  289. } else if (dom?.tagName === 'TEXTAREA') {
  290. this.setFormClass(dom, name, add)
  291. }
  292. }
  293. static setFormClass(dom, name = 'hc-red-border', add = false) {
  294. const classStr = dom.getAttribute('class')
  295. const classArr = classStr.split(' ')
  296. const index = classArr.indexOf(name)
  297. if (index === -1 && add) {
  298. classArr.push(name)
  299. } else if (index !== -1 && add === false) {
  300. classArr.splice(index, 1)
  301. }
  302. dom.setAttribute('class', classArr.join(' '))
  303. }
  304. //设置选中样式
  305. static setCheckKeyStyle(key, pid = '', remove = false) {
  306. if (remove) {
  307. this.setFormStyle(key, 'hc-green-border', pid).then()
  308. } else {
  309. this.setFormStyle(key, 'hc-green-border', pid, true).then()
  310. }
  311. }
  312. //设置全局按键监听
  313. static setOnEventKey({ onCtrlDown, onCtrlDownC, onCtrlDownV, onCtrlUp }) {
  314. //全局按键按下监听
  315. document.onkeydown = (event) => {
  316. if (onCtrlDown || onCtrlDownC || onCtrlDownV) {
  317. const { key, ctrlKey, metaKey } = event
  318. const isCtrl = window.isMac ? metaKey : window.isWin ? ctrlKey : false
  319. //window.$HcLog('全局按键', 'isCtrl', isCtrl)
  320. //按下ctrl键 或 control 键
  321. if (onCtrlDown && isCtrl && key === window?.isCtrl) {
  322. onCtrlDown(event)
  323. }
  324. //按下复制快捷键
  325. if (onCtrlDownC && isCtrl && key === 'c') {
  326. onCtrlDownC(event)
  327. }
  328. //按下粘贴快捷键
  329. if (onCtrlDownV && isCtrl && key === 'v') {
  330. onCtrlDownV(event)
  331. }
  332. }
  333. }
  334. //全局键盘放开监听
  335. document.onkeyup = (event) => {
  336. if (onCtrlUp) {
  337. const { key, ctrlKey, metaKey } = event
  338. const isCtrl = window.isMac ? metaKey : window.isWin ? ctrlKey : false
  339. if (!isCtrl && key === window?.isCtrl) {
  340. onCtrlUp(event)
  341. }
  342. }
  343. }
  344. }
  345. //卸载全局按键监听
  346. static unmountEventKey() {
  347. document.onkeydown = null
  348. document.onkeyup = null
  349. }
  350. //卸载实例
  351. static unmountFormApp() {
  352. if (this.tableFormApp) {
  353. this.tableFormApp?.unmount()
  354. this.tableFormApp = null
  355. }
  356. }
  357. }