HTableForm.js 13 KB

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