@smallwei/avue 3.8.1 → 3.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/README.md +206 -86
  2. package/dist/avue.js +37301 -0
  3. package/dist/avue.js.map +1 -0
  4. package/dist/avue.min.js +6 -0
  5. package/dist/avue.min.mjs +2 -0
  6. package/dist/avue.mjs +2 -0
  7. package/dist/index.css +1 -0
  8. package/es/avue.min.mjs +2 -0
  9. package/es/avue.min.ts +2 -0
  10. package/es/avue.mjs +2 -0
  11. package/es/avue.ts +2 -0
  12. package/es/core/create.mjs +8 -0
  13. package/es/core/create.ts +16 -0
  14. package/es/core/dataformat.mjs +184 -0
  15. package/es/core/dataformat.ts +190 -0
  16. package/es/core/detail.mjs +74 -0
  17. package/es/core/detail.ts +81 -0
  18. package/es/core/dic.mjs +213 -0
  19. package/es/core/dic.ts +235 -0
  20. package/es/core/locale.mjs +8 -0
  21. package/es/core/locale.ts +9 -0
  22. package/es/core/packages.mjs +61 -0
  23. package/es/core/packages.ts +62 -0
  24. package/es/core/slot.mjs +32 -0
  25. package/es/core/slot.ts +30 -0
  26. package/es/global/variable.mjs +80 -0
  27. package/es/global/variable.ts +84 -0
  28. package/es/icon.mjs +9 -0
  29. package/es/icon.ts +11 -0
  30. package/es/index.mjs +127 -0
  31. package/es/index.ts +177 -0
  32. package/es/locale/browser/en.mjs +288 -0
  33. package/es/locale/browser/zh-cn.mjs +288 -0
  34. package/es/locale/browser/zh.mjs +288 -0
  35. package/es/locale/index.mjs +141 -0
  36. package/es/locale/index.ts +196 -0
  37. package/es/locale/lang/en.mjs +282 -0
  38. package/es/locale/lang/en.ts +282 -0
  39. package/es/locale/lang/zh-cn.mjs +282 -0
  40. package/es/locale/lang/zh-cn.ts +282 -0
  41. package/es/locale/lang/zh.mjs +282 -0
  42. package/es/locale/lang/zh.ts +282 -0
  43. package/es/packages/core/common/event.mjs +58 -0
  44. package/es/packages/core/common/event.ts +56 -0
  45. package/es/packages/core/common/init.mjs +134 -0
  46. package/es/packages/core/common/init.ts +133 -0
  47. package/es/packages/core/common/props.mjs +239 -0
  48. package/es/packages/core/common/props.ts +240 -0
  49. package/es/packages/core/components/dialog-form/index.mjs +29 -0
  50. package/es/packages/core/components/dialog-form/index.ts +29 -0
  51. package/es/packages/core/components/dialog-form/index.vue +108 -0
  52. package/es/packages/core/components/form/custom.mjs +41 -0
  53. package/es/packages/core/components/form/custom.ts +41 -0
  54. package/es/packages/core/components/form/index.vue +176 -0
  55. package/es/packages/core/components/icon/index.vue +37 -0
  56. package/es/packages/core/components/image-preview/index.mjs +34 -0
  57. package/es/packages/core/components/image-preview/index.ts +37 -0
  58. package/es/packages/core/components/image-preview/index.vue +215 -0
  59. package/es/packages/core/directive/contextmenu.mjs +92 -0
  60. package/es/packages/core/directive/contextmenu.ts +103 -0
  61. package/es/packages/core/directive/permission.mjs +19 -0
  62. package/es/packages/core/directive/permission.ts +18 -0
  63. package/es/packages/data/box/index.vue +66 -0
  64. package/es/packages/data/card/index.vue +62 -0
  65. package/es/packages/data/cardText/index.vue +56 -0
  66. package/es/packages/data/countdown/index.vue +81 -0
  67. package/es/packages/data/dashboard/index.vue +72 -0
  68. package/es/packages/data/display/index.vue +63 -0
  69. package/es/packages/data/icons/index.vue +68 -0
  70. package/es/packages/data/imgText/index.vue +72 -0
  71. package/es/packages/data/list/index.vue +69 -0
  72. package/es/packages/data/notice/index.vue +63 -0
  73. package/es/packages/data/operaText/index.vue +62 -0
  74. package/es/packages/data/panel/index.vue +62 -0
  75. package/es/packages/data/pay/index.vue +92 -0
  76. package/es/packages/data/price/index.vue +55 -0
  77. package/es/packages/data/product/index.vue +106 -0
  78. package/es/packages/data/profile/index.vue +91 -0
  79. package/es/packages/data/progress/index.vue +64 -0
  80. package/es/packages/data/rank/index.vue +92 -0
  81. package/es/packages/data/rotate/index.vue +69 -0
  82. package/es/packages/data/statistic/index.vue +71 -0
  83. package/es/packages/data/tabs/index.vue +64 -0
  84. package/es/packages/data/task/index.vue +82 -0
  85. package/es/packages/data/weather/index.vue +103 -0
  86. package/es/packages/element-plus/array/index.vue +115 -0
  87. package/es/packages/element-plus/article/index.vue +73 -0
  88. package/es/packages/element-plus/card/index.vue +103 -0
  89. package/es/packages/element-plus/cascader/index.vue +132 -0
  90. package/es/packages/element-plus/chat/index.vue +513 -0
  91. package/es/packages/element-plus/checkbox/index.vue +84 -0
  92. package/es/packages/element-plus/comment/index.vue +76 -0
  93. package/es/packages/element-plus/count-up/index.vue +107 -0
  94. package/es/packages/element-plus/crud/column/column-default.vue +128 -0
  95. package/es/packages/element-plus/crud/column/column-dynamic.vue +86 -0
  96. package/es/packages/element-plus/crud/column/column-menu.vue +267 -0
  97. package/es/packages/element-plus/crud/column/column-slot.vue +348 -0
  98. package/es/packages/element-plus/crud/column/column.vue +119 -0
  99. package/es/packages/element-plus/crud/column/menu.vue +78 -0
  100. package/es/packages/element-plus/crud/config.mjs +74 -0
  101. package/es/packages/element-plus/crud/config.ts +74 -0
  102. package/es/packages/element-plus/crud/dialog/dialog-column.vue +102 -0
  103. package/es/packages/element-plus/crud/dialog/dialog-excel.vue +204 -0
  104. package/es/packages/element-plus/crud/dialog/dialog-filter.vue +159 -0
  105. package/es/packages/element-plus/crud/dialog/dialog-form.vue +352 -0
  106. package/es/packages/element-plus/crud/grid/index.vue +271 -0
  107. package/es/packages/element-plus/crud/grid/item.vue +39 -0
  108. package/es/packages/element-plus/crud/index.vue +1018 -0
  109. package/es/packages/element-plus/crud/menu/header-menu.vue +175 -0
  110. package/es/packages/element-plus/crud/menu/header-search.vue +228 -0
  111. package/es/packages/element-plus/crud/menu/table-page.vue +108 -0
  112. package/es/packages/element-plus/date/index.vue +81 -0
  113. package/es/packages/element-plus/draggable/index.vue +444 -0
  114. package/es/packages/element-plus/dynamic/index.vue +353 -0
  115. package/es/packages/element-plus/flow/index.vue +339 -0
  116. package/es/packages/element-plus/flow/node.vue +84 -0
  117. package/es/packages/element-plus/form/config.mjs +6 -0
  118. package/es/packages/element-plus/form/config.ts +6 -0
  119. package/es/packages/element-plus/form/index.vue +954 -0
  120. package/es/packages/element-plus/form/menu.vue +63 -0
  121. package/es/packages/element-plus/group/index.vue +90 -0
  122. package/es/packages/element-plus/input/index.vue +1264 -0
  123. package/es/packages/element-plus/input-color/index.vue +70 -0
  124. package/es/packages/element-plus/input-cron/index.vue +363 -0
  125. package/es/packages/element-plus/input-icon/index.vue +143 -0
  126. package/es/packages/element-plus/input-map/index.vue +311 -0
  127. package/es/packages/element-plus/input-number/index.vue +91 -0
  128. package/es/packages/element-plus/input-table/index.vue +279 -0
  129. package/es/packages/element-plus/input-tag/index.vue +79 -0
  130. package/es/packages/element-plus/input-tree/index.vue +194 -0
  131. package/es/packages/element-plus/license/index.vue +155 -0
  132. package/es/packages/element-plus/login/index.vue +203 -0
  133. package/es/packages/element-plus/mention/index.vue +117 -0
  134. package/es/packages/element-plus/radio/index.vue +38 -0
  135. package/es/packages/element-plus/rate/index.vue +51 -0
  136. package/es/packages/element-plus/search/index.vue +129 -0
  137. package/es/packages/element-plus/select/index.vue +292 -0
  138. package/es/packages/element-plus/sign/index.vue +230 -0
  139. package/es/packages/element-plus/slider/index.vue +66 -0
  140. package/es/packages/element-plus/switch/index.vue +72 -0
  141. package/es/packages/element-plus/tabs/index.vue +62 -0
  142. package/es/packages/element-plus/text-ellipsis/index.vue +104 -0
  143. package/es/packages/element-plus/time/index.vue +81 -0
  144. package/es/packages/element-plus/title/index.vue +30 -0
  145. package/es/packages/element-plus/tree/index.vue +460 -0
  146. package/es/packages/element-plus/upload/index.vue +728 -0
  147. package/es/packages/element-plus/verify/index.vue +62 -0
  148. package/es/packages/element-plus/video/index.vue +90 -0
  149. package/es/plugin/ali/index.mjs +4 -0
  150. package/es/plugin/ali/index.ts +6 -0
  151. package/es/plugin/clipboard/index.mjs +61 -0
  152. package/es/plugin/clipboard/index.ts +67 -0
  153. package/es/plugin/export/_blob.mjs +151 -0
  154. package/es/plugin/export/_blob.ts +176 -0
  155. package/es/plugin/export/_export2Excel.mjs +141 -0
  156. package/es/plugin/export/_export2Excel.ts +166 -0
  157. package/es/plugin/export/index.mjs +263 -0
  158. package/es/plugin/export/index.ts +274 -0
  159. package/es/plugin/logs/index.mjs +46 -0
  160. package/es/plugin/logs/index.ts +66 -0
  161. package/es/plugin/print/index.mjs +145 -0
  162. package/es/plugin/print/index.ts +155 -0
  163. package/es/plugin/qiniu/index.mjs +78 -0
  164. package/es/plugin/qiniu/index.ts +88 -0
  165. package/es/plugin/screenshot/index.mjs +8 -0
  166. package/es/plugin/screenshot/index.ts +9 -0
  167. package/es/plugin/video/index.mjs +52 -0
  168. package/es/plugin/video/index.ts +60 -0
  169. package/es/plugin/watermark/index.mjs +114 -0
  170. package/es/plugin/watermark/index.ts +127 -0
  171. package/es/plugin/watermark/watermark.mjs +109 -0
  172. package/es/plugin/watermark/watermark.ts +121 -0
  173. package/es/ui/data/index.mjs +49 -0
  174. package/es/ui/data/index.ts +51 -0
  175. package/es/ui/element-plus/index.mjs +87 -0
  176. package/es/ui/element-plus/index.ts +89 -0
  177. package/es/ui/index.mjs +4 -0
  178. package/es/ui/index.ts +6 -0
  179. package/es/utils/bem.mjs +29 -0
  180. package/es/utils/bem.ts +36 -0
  181. package/es/utils/mock.mjs +137 -0
  182. package/es/utils/mock.ts +151 -0
  183. package/es/utils/util.mjs +370 -0
  184. package/es/utils/util.ts +392 -0
  185. package/es/utils/validate.mjs +18 -0
  186. package/es/utils/validate.ts +23 -0
  187. package/es/version.mjs +1 -0
  188. package/es/version.ts +1 -0
  189. package/lib/avue.js +11 -31398
  190. package/lib/avue.min.js +11 -6
  191. package/lib/avue.min.ts +2 -0
  192. package/lib/avue.ts +2 -0
  193. package/lib/core/create.js +14 -0
  194. package/lib/core/create.ts +16 -0
  195. package/lib/core/dataformat.js +194 -0
  196. package/lib/core/dataformat.ts +190 -0
  197. package/lib/core/detail.js +81 -0
  198. package/lib/core/detail.ts +81 -0
  199. package/lib/core/dic.js +220 -0
  200. package/lib/core/dic.ts +235 -0
  201. package/lib/core/locale.js +10 -0
  202. package/lib/core/locale.ts +9 -0
  203. package/lib/core/packages.js +66 -0
  204. package/lib/core/packages.ts +62 -0
  205. package/lib/core/slot.js +34 -0
  206. package/lib/core/slot.ts +30 -0
  207. package/lib/global/variable.js +83 -0
  208. package/lib/global/variable.ts +84 -0
  209. package/lib/icon.js +44 -0
  210. package/lib/icon.ts +11 -0
  211. package/lib/index.css +1 -1
  212. package/lib/index.js +134 -0
  213. package/lib/index.ts +177 -0
  214. package/lib/locale/browser/en.js +288 -0
  215. package/lib/locale/browser/zh-cn.js +288 -0
  216. package/lib/locale/browser/zh.js +288 -0
  217. package/lib/locale/index.js +153 -47
  218. package/lib/locale/index.ts +196 -0
  219. package/lib/locale/lang/en.js +284 -100
  220. package/lib/locale/lang/en.ts +282 -0
  221. package/lib/locale/lang/zh-cn.js +284 -0
  222. package/lib/locale/lang/zh-cn.ts +282 -0
  223. package/lib/locale/lang/zh.js +284 -100
  224. package/lib/locale/lang/zh.ts +282 -0
  225. package/lib/packages/core/common/event.js +61 -0
  226. package/lib/packages/core/common/event.ts +56 -0
  227. package/lib/packages/core/common/init.js +140 -0
  228. package/lib/packages/core/common/init.ts +133 -0
  229. package/lib/packages/core/common/props.js +245 -0
  230. package/lib/packages/core/common/props.ts +240 -0
  231. package/lib/packages/core/components/dialog-form/index.js +35 -0
  232. package/lib/packages/core/components/dialog-form/index.ts +29 -0
  233. package/lib/packages/core/components/dialog-form/index.vue +108 -0
  234. package/lib/packages/core/components/form/custom.js +43 -0
  235. package/lib/packages/core/components/form/custom.ts +41 -0
  236. package/lib/packages/core/components/form/index.vue +176 -0
  237. package/lib/packages/core/components/icon/index.vue +37 -0
  238. package/lib/packages/core/components/image-preview/index.js +40 -0
  239. package/lib/packages/core/components/image-preview/index.ts +37 -0
  240. package/lib/packages/core/components/image-preview/index.vue +215 -0
  241. package/lib/packages/core/directive/contextmenu.js +94 -0
  242. package/lib/packages/core/directive/contextmenu.ts +103 -0
  243. package/lib/packages/core/directive/permission.js +21 -0
  244. package/lib/packages/core/directive/permission.ts +18 -0
  245. package/lib/packages/data/box/index.vue +66 -0
  246. package/lib/packages/data/card/index.vue +62 -0
  247. package/lib/packages/data/cardText/index.vue +56 -0
  248. package/lib/packages/data/countdown/index.vue +81 -0
  249. package/lib/packages/data/dashboard/index.vue +72 -0
  250. package/lib/packages/data/display/index.vue +63 -0
  251. package/lib/packages/data/icons/index.vue +68 -0
  252. package/lib/packages/data/imgText/index.vue +72 -0
  253. package/lib/packages/data/list/index.vue +69 -0
  254. package/lib/packages/data/notice/index.vue +63 -0
  255. package/lib/packages/data/operaText/index.vue +62 -0
  256. package/lib/packages/data/panel/index.vue +62 -0
  257. package/lib/packages/data/pay/index.vue +92 -0
  258. package/lib/packages/data/price/index.vue +55 -0
  259. package/lib/packages/data/product/index.vue +106 -0
  260. package/lib/packages/data/profile/index.vue +91 -0
  261. package/lib/packages/data/progress/index.vue +64 -0
  262. package/lib/packages/data/rank/index.vue +92 -0
  263. package/lib/packages/data/rotate/index.vue +69 -0
  264. package/lib/packages/data/statistic/index.vue +71 -0
  265. package/lib/packages/data/tabs/index.vue +64 -0
  266. package/lib/packages/data/task/index.vue +82 -0
  267. package/lib/packages/data/weather/index.vue +103 -0
  268. package/lib/packages/element-plus/array/index.vue +115 -0
  269. package/lib/packages/element-plus/article/index.vue +73 -0
  270. package/lib/packages/element-plus/card/index.vue +103 -0
  271. package/lib/packages/element-plus/cascader/index.vue +132 -0
  272. package/lib/packages/element-plus/chat/index.vue +513 -0
  273. package/lib/packages/element-plus/checkbox/index.vue +84 -0
  274. package/lib/packages/element-plus/comment/index.vue +76 -0
  275. package/lib/packages/element-plus/count-up/index.vue +107 -0
  276. package/lib/packages/element-plus/crud/column/column-default.vue +128 -0
  277. package/lib/packages/element-plus/crud/column/column-dynamic.vue +86 -0
  278. package/lib/packages/element-plus/crud/column/column-menu.vue +267 -0
  279. package/lib/packages/element-plus/crud/column/column-slot.vue +348 -0
  280. package/lib/packages/element-plus/crud/column/column.vue +119 -0
  281. package/lib/packages/element-plus/crud/column/menu.vue +78 -0
  282. package/lib/packages/element-plus/crud/config.js +76 -0
  283. package/lib/packages/element-plus/crud/config.ts +74 -0
  284. package/lib/packages/element-plus/crud/dialog/dialog-column.vue +102 -0
  285. package/lib/packages/element-plus/crud/dialog/dialog-excel.vue +204 -0
  286. package/lib/packages/element-plus/crud/dialog/dialog-filter.vue +159 -0
  287. package/lib/packages/element-plus/crud/dialog/dialog-form.vue +352 -0
  288. package/lib/packages/element-plus/crud/grid/index.vue +271 -0
  289. package/lib/packages/element-plus/crud/grid/item.vue +39 -0
  290. package/lib/packages/element-plus/crud/index.vue +1018 -0
  291. package/lib/packages/element-plus/crud/menu/header-menu.vue +175 -0
  292. package/lib/packages/element-plus/crud/menu/header-search.vue +228 -0
  293. package/lib/packages/element-plus/crud/menu/table-page.vue +108 -0
  294. package/lib/packages/element-plus/date/index.vue +81 -0
  295. package/lib/packages/element-plus/draggable/index.vue +444 -0
  296. package/lib/packages/element-plus/dynamic/index.vue +353 -0
  297. package/lib/packages/element-plus/flow/index.vue +339 -0
  298. package/lib/packages/element-plus/flow/node.vue +84 -0
  299. package/lib/packages/element-plus/form/config.js +8 -0
  300. package/lib/packages/element-plus/form/config.ts +6 -0
  301. package/lib/packages/element-plus/form/index.vue +954 -0
  302. package/lib/packages/element-plus/form/menu.vue +63 -0
  303. package/lib/packages/element-plus/group/index.vue +90 -0
  304. package/lib/packages/element-plus/input/index.vue +1264 -0
  305. package/lib/packages/element-plus/input-color/index.vue +70 -0
  306. package/lib/packages/element-plus/input-cron/index.vue +363 -0
  307. package/lib/packages/element-plus/input-icon/index.vue +143 -0
  308. package/lib/packages/element-plus/input-map/index.vue +311 -0
  309. package/lib/packages/element-plus/input-number/index.vue +91 -0
  310. package/lib/packages/element-plus/input-table/index.vue +279 -0
  311. package/lib/packages/element-plus/input-tag/index.vue +79 -0
  312. package/lib/packages/element-plus/input-tree/index.vue +194 -0
  313. package/lib/packages/element-plus/license/index.vue +155 -0
  314. package/lib/packages/element-plus/login/index.vue +203 -0
  315. package/lib/packages/element-plus/mention/index.vue +117 -0
  316. package/lib/packages/element-plus/radio/index.vue +38 -0
  317. package/lib/packages/element-plus/rate/index.vue +51 -0
  318. package/lib/packages/element-plus/search/index.vue +129 -0
  319. package/lib/packages/element-plus/select/index.vue +292 -0
  320. package/lib/packages/element-plus/sign/index.vue +230 -0
  321. package/lib/packages/element-plus/slider/index.vue +66 -0
  322. package/lib/packages/element-plus/switch/index.vue +72 -0
  323. package/lib/packages/element-plus/tabs/index.vue +62 -0
  324. package/lib/packages/element-plus/text-ellipsis/index.vue +104 -0
  325. package/lib/packages/element-plus/time/index.vue +81 -0
  326. package/lib/packages/element-plus/title/index.vue +30 -0
  327. package/lib/packages/element-plus/tree/index.vue +460 -0
  328. package/lib/packages/element-plus/upload/index.vue +728 -0
  329. package/lib/packages/element-plus/verify/index.vue +62 -0
  330. package/lib/packages/element-plus/video/index.vue +90 -0
  331. package/lib/plugin/ali/index.js +8 -0
  332. package/lib/plugin/ali/index.ts +6 -0
  333. package/lib/plugin/clipboard/index.js +64 -0
  334. package/lib/plugin/clipboard/index.ts +67 -0
  335. package/lib/plugin/export/_blob.js +151 -0
  336. package/lib/plugin/export/_blob.ts +176 -0
  337. package/lib/plugin/export/_export2Excel.js +145 -0
  338. package/lib/plugin/export/_export2Excel.ts +166 -0
  339. package/lib/plugin/export/index.js +268 -0
  340. package/lib/plugin/export/index.ts +274 -0
  341. package/lib/plugin/logs/index.js +48 -0
  342. package/lib/plugin/logs/index.ts +66 -0
  343. package/lib/plugin/print/index.js +147 -0
  344. package/lib/plugin/print/index.ts +155 -0
  345. package/lib/plugin/qiniu/index.js +82 -0
  346. package/lib/plugin/qiniu/index.ts +88 -0
  347. package/lib/plugin/screenshot/index.js +14 -0
  348. package/lib/plugin/screenshot/index.ts +9 -0
  349. package/lib/plugin/video/index.js +55 -0
  350. package/lib/plugin/video/index.ts +60 -0
  351. package/lib/plugin/watermark/index.js +121 -0
  352. package/lib/plugin/watermark/index.ts +127 -0
  353. package/lib/plugin/watermark/watermark.js +111 -0
  354. package/lib/plugin/watermark/watermark.ts +121 -0
  355. package/lib/ui/data/index.js +54 -0
  356. package/lib/ui/data/index.ts +51 -0
  357. package/lib/ui/element-plus/index.js +92 -0
  358. package/lib/ui/element-plus/index.ts +89 -0
  359. package/lib/ui/index.js +9 -0
  360. package/lib/ui/index.ts +6 -0
  361. package/lib/utils/bem.js +31 -0
  362. package/lib/utils/bem.ts +36 -0
  363. package/lib/utils/mock.js +142 -0
  364. package/lib/utils/mock.ts +151 -0
  365. package/lib/utils/util.js +403 -0
  366. package/lib/utils/util.ts +392 -0
  367. package/lib/utils/validate.js +21 -0
  368. package/lib/utils/validate.ts +23 -0
  369. package/lib/version.js +4 -0
  370. package/lib/version.ts +1 -0
  371. package/package.json +24 -11
  372. package/types/index.d.ts +141 -0
  373. package/types/shims-aliases.d.ts +4 -0
  374. package/types/shims-vue.d.ts +6 -0
  375. package/lib/avue.js.map +0 -1
  376. package/lib/locale/format.js +0 -44
@@ -0,0 +1,1264 @@
1
+ <template>
2
+ <div :class="b()">
3
+ <!-- 手机号输入(带国际区号,需要特殊布局) -->
4
+ <template v-if="isPhone">
5
+ <div class="avue-input__phone">
6
+ <el-select v-model="phoneCode"
7
+ class="avue-input__phone-code"
8
+ :size="size"
9
+ :disabled="disabled"
10
+ :placeholder="phoneCodePlaceholderText"
11
+ filterable
12
+ style="width: 120px;">
13
+ <el-option v-for="item in phoneCodeList"
14
+ :key="item.code"
15
+ :label="item.label"
16
+ :value="item.code">
17
+ <span style="float: left">{{ item.name }}</span>
18
+ <span style="float: right; color: #8492a6; font-size: 12px">{{ item.code }}</span>
19
+ </el-option>
20
+ </el-select>
21
+ <el-input class="avue-input__phone-input"
22
+ :size="size"
23
+ :clearable="clearableVal"
24
+ v-model="phoneNumber"
25
+ @keyup.enter="isSearch?appendClick(text):''"
26
+ @click="handleClick"
27
+ :maxlength="phoneMaxLength"
28
+ :prefix-icon="prefixIcon"
29
+ :suffix-icon="suffixIcon"
30
+ :readonly="readonly"
31
+ :placeholder="phonePlaceholderText"
32
+ @focus="handleFocus"
33
+ @blur="handlePhoneBlur"
34
+ :disabled="disabled"
35
+ style="flex: 1;">
36
+ </el-input>
37
+ </div>
38
+ </template>
39
+
40
+ <!-- 验证码输入(分段输入框) -->
41
+ <template v-else-if="isCode">
42
+ <div class="avue-input__code">
43
+ <input v-for="(val, index) in codeValues"
44
+ :key="index"
45
+ type="text"
46
+ maxlength="1"
47
+ class="avue-input__code-item"
48
+ :class="{ 'is-disabled': disabled }"
49
+ :value="val"
50
+ :disabled="disabled"
51
+ :readonly="readonly"
52
+ @input="handleCodeInput($event, index)"
53
+ @keydown="handleCodeKeydown($event, index)"
54
+ @paste="handleCodePaste($event)"
55
+ @focus="handleFocus"
56
+ @blur="handleBlur"
57
+ :ref="el => codeRefs[index] = el" />
58
+ </div>
59
+ </template>
60
+
61
+ <!-- 车牌号输入(省份选择 + 车牌号) -->
62
+ <template v-else-if="isPlate">
63
+ <div class="avue-input__plate">
64
+ <el-select v-model="plateProvince"
65
+ class="avue-input__plate-province"
66
+ :size="size"
67
+ :disabled="disabled"
68
+ style="width: 70px;">
69
+ <el-option v-for="item in resolvedPlateProvinceList"
70
+ :key="item"
71
+ :label="item"
72
+ :value="item" />
73
+ </el-select>
74
+ <el-input class="avue-input__plate-number"
75
+ :size="size"
76
+ :clearable="clearableVal"
77
+ v-model="plateNumber"
78
+ @click="handleClick"
79
+ :maxlength="7"
80
+ :readonly="readonly"
81
+ :placeholder="platePlaceholderText"
82
+ @focus="handleFocus"
83
+ @blur="handlePlateBlur"
84
+ @input="handlePlateInput"
85
+ :disabled="disabled"
86
+ style="flex: 1;">
87
+ </el-input>
88
+ </div>
89
+ </template>
90
+
91
+ <!-- IP地址输入(4段输入框) -->
92
+ <template v-else-if="isIp">
93
+ <div class="avue-input__ip">
94
+ <template v-for="(seg, index) in ipSegments" :key="index">
95
+ <input type="text"
96
+ class="avue-input__ip-segment"
97
+ :class="{ 'is-disabled': disabled }"
98
+ maxlength="3"
99
+ :value="seg"
100
+ :disabled="disabled"
101
+ :readonly="readonly"
102
+ @input="handleIpInput($event, index)"
103
+ @keydown="handleIpKeydown($event, index)"
104
+ @focus="handleFocus"
105
+ @blur="handleBlur"
106
+ :ref="el => ipRefs[index] = el" />
107
+ <span v-if="index < 3" class="avue-input__ip-dot">.</span>
108
+ </template>
109
+ </div>
110
+ </template>
111
+
112
+ <!-- MAC地址输入(6段输入框) -->
113
+ <template v-else-if="isMac">
114
+ <div class="avue-input__mac">
115
+ <template v-for="(seg, index) in macSegments" :key="index">
116
+ <input type="text"
117
+ class="avue-input__mac-segment"
118
+ :class="{ 'is-disabled': disabled }"
119
+ maxlength="2"
120
+ :value="seg"
121
+ :disabled="disabled"
122
+ :readonly="readonly"
123
+ @input="handleMacInput($event, index)"
124
+ @keydown="handleMacKeydown($event, index)"
125
+ @focus="handleFocus"
126
+ @blur="handleBlur"
127
+ :ref="el => macRefs[index] = el" />
128
+ <span v-if="index < 5" class="avue-input__mac-sep">{{ macSeparator }}</span>
129
+ </template>
130
+ </div>
131
+ </template>
132
+
133
+ <!-- 统一输入框(货币、银行卡、身份证、邮箱、社会信用代码、默认类型) -->
134
+ <template v-else>
135
+ <el-input :class="inputClass"
136
+ :size="size"
137
+ :clearable="clearableVal"
138
+ v-model="inputValue"
139
+ @keyup.enter="isSearch?appendClick(text):''"
140
+ @click="handleClick"
141
+ :type="inputType"
142
+ :maxlength="inputMaxlength"
143
+ :minlength="minlength"
144
+ :show-password="typeParam=='password'?showPassword:false"
145
+ :rows="rows"
146
+ :autosize="{ minRows: minRows, maxRows: maxRows}"
147
+ :prefix-icon="inputPrefixIcon"
148
+ :suffix-icon="inputSuffixIcon"
149
+ :readonly="readonly"
150
+ :placeholder="inputPlaceholder"
151
+ :show-word-limit="isDefault && showWordLimit"
152
+ @focus="onFocus"
153
+ @blur="onBlur"
154
+ @input="onInput"
155
+ :disabled="disabled"
156
+ :autocomplete="autocomplete"
157
+ :formatter="isDefault ? formatters : undefined"
158
+ :parser="isDefault ? parser : undefined">
159
+ <!-- 前置内容 -->
160
+ <template #prepend v-if="showPrepend">
161
+ <span @click="prependClick && prependClick(text)">{{ prependText }}</span>
162
+ </template>
163
+ <!-- 后置内容 -->
164
+ <template #append v-if="showAppend">
165
+ <span @click="appendClick && appendClick(text)">{{ appendText }}</span>
166
+ </template>
167
+ <template #append v-else-if="isSearch">
168
+ <el-button icon="el-icon-search" @click="appendClick(text)"></el-button>
169
+ </template>
170
+ <!-- 后缀内容 - 银行卡类型 -->
171
+ <template #suffix v-if="isBankCard && showBankCardType && bankCardType">
172
+ <span class="avue-input__bank-card-type">{{ bankCardType }}</span>
173
+ </template>
174
+ <!-- 后缀内容 - 身份证信息 -->
175
+ <template #suffix v-else-if="isIdCard && showIdCardInfo && idCardInfo">
176
+ <el-tooltip :content="idCardInfoText" placement="top">
177
+ <span class="avue-input__id-card-info">
178
+ {{ idCardValid ? '✓' : '✗' }}
179
+ </span>
180
+ </el-tooltip>
181
+ </template>
182
+ <!-- 后缀内容 - 邮箱验证 -->
183
+ <template #suffix v-else-if="isEmail && emailValid !== null">
184
+ <span class="avue-input__email-valid">{{ emailValid ? '✓' : '✗' }}</span>
185
+ </template>
186
+ <!-- 后缀内容 - 社会信用代码验证 -->
187
+ <template #suffix v-else-if="isUscc && usccValid !== null">
188
+ <span class="avue-input__uscc-valid">{{ usccValid ? '✓' : '✗' }}</span>
189
+ </template>
190
+ </el-input>
191
+ </template>
192
+ </div>
193
+ </template>
194
+
195
+ <script>
196
+ import create from "../../../core/create.js";
197
+ import props from "../../core/common/props.js";
198
+ import event from "../../core/common/event.js";
199
+ import locale from "../../../core/locale.js";
200
+
201
+ const defaultPhoneCodeOptions = [
202
+ { code: '+86', flag: '🇨🇳', nameKey: 'input.countries.cn' },
203
+ { code: '+852', flag: '🇭🇰', nameKey: 'input.countries.hk' },
204
+ { code: '+853', flag: '🇲🇴', nameKey: 'input.countries.mo' },
205
+ { code: '+886', flag: '🇹🇼', nameKey: 'input.countries.tw' },
206
+ { code: '+1', flag: '🇺🇸', nameKey: 'input.countries.usca' },
207
+ { code: '+44', flag: '🇬🇧', nameKey: 'input.countries.uk' },
208
+ { code: '+81', flag: '🇯🇵', nameKey: 'input.countries.jp' },
209
+ { code: '+82', flag: '🇰🇷', nameKey: 'input.countries.kr' },
210
+ { code: '+65', flag: '🇸🇬', nameKey: 'input.countries.sg' },
211
+ { code: '+61', flag: '🇦🇺', nameKey: 'input.countries.au' },
212
+ { code: '+49', flag: '🇩🇪', nameKey: 'input.countries.de' },
213
+ { code: '+33', flag: '🇫🇷', nameKey: 'input.countries.fr' },
214
+ { code: '+39', flag: '🇮🇹', nameKey: 'input.countries.it' },
215
+ { code: '+7', flag: '🇷🇺', nameKey: 'input.countries.ru' },
216
+ { code: '+91', flag: '🇮🇳', nameKey: 'input.countries.in' },
217
+ { code: '+55', flag: '🇧🇷', nameKey: 'input.countries.br' },
218
+ { code: '+34', flag: '🇪🇸', nameKey: 'input.countries.es' },
219
+ { code: '+31', flag: '🇳🇱', nameKey: 'input.countries.nl' },
220
+ { code: '+41', flag: '🇨🇭', nameKey: 'input.countries.ch' },
221
+ { code: '+46', flag: '🇸🇪', nameKey: 'input.countries.se' },
222
+ { code: '+60', flag: '🇲🇾', nameKey: 'input.countries.my' },
223
+ { code: '+66', flag: '🇹🇭', nameKey: 'input.countries.th' },
224
+ { code: '+84', flag: '🇻🇳', nameKey: 'input.countries.vn' },
225
+ { code: '+62', flag: '🇮🇩', nameKey: 'input.countries.id' },
226
+ { code: '+63', flag: '🇵🇭', nameKey: 'input.countries.ph' }
227
+ ];
228
+
229
+ // 货币符号映射
230
+ const currencySymbols = {
231
+ CNY: '¥',
232
+ USD: '$',
233
+ EUR: '€',
234
+ GBP: '£',
235
+ JPY: '¥',
236
+ HKD: 'HK$',
237
+ KRW: '₩',
238
+ SGD: 'S$',
239
+ AUD: 'A$',
240
+ CAD: 'C$'
241
+ };
242
+
243
+ export default create({
244
+ name: "input",
245
+ mixins: [props(), event(), locale],
246
+ emits: ['update:modelValue', 'click', 'focus', 'blur', 'change', 'id-card-valid', 'code-complete', 'uscc-valid'],
247
+ data() {
248
+ return {
249
+ // 手机号相关
250
+ phoneCode: '+86',
251
+ phoneNumber: '',
252
+ // 货币相关
253
+ currencyDisplay: '',
254
+ currencyEditing: false,
255
+ // 银行卡相关
256
+ bankCardDisplay: '',
257
+ bankCardType: '',
258
+ // 身份证相关
259
+ idCardDisplay: '',
260
+ idCardValid: null,
261
+ idCardInfo: null,
262
+ // 邮箱相关
263
+ emailDisplay: '',
264
+ emailValid: null,
265
+ showEmailSuggestions: false,
266
+ // 验证码相关
267
+ codeValues: [],
268
+ codeRefs: [],
269
+ // 车牌号相关
270
+ plateProvince: '',
271
+ plateNumber: '',
272
+ // IP地址相关
273
+ ipSegments: ['', '', '', ''],
274
+ ipRefs: [],
275
+ // MAC地址相关
276
+ macSegments: ['', '', '', '', '', ''],
277
+ macRefs: [],
278
+ // 社会信用代码相关
279
+ usccDisplay: '',
280
+ usccValid: null
281
+ };
282
+ },
283
+ props: {
284
+ showPassword: {
285
+ type: Boolean,
286
+ default: true
287
+ },
288
+ showWordLimit: {
289
+ type: Boolean,
290
+ default: false
291
+ },
292
+ target: {
293
+ type: String,
294
+ default: ' _blank'
295
+ },
296
+ prefixIcon: {
297
+ type: String
298
+ },
299
+ suffixIcon: {
300
+ type: String
301
+ },
302
+ prependClick: {
303
+ type: Function
304
+ },
305
+ prepend: {
306
+ type: String
307
+ },
308
+ appendClick: {
309
+ type: Function
310
+ },
311
+ formatters: {
312
+ type: Function
313
+ },
314
+ parser: {
315
+ type: Function
316
+ },
317
+ append: {
318
+ type: String
319
+ },
320
+ minlength: [String, Number],
321
+ maxlength: [String, Number],
322
+ rows: Number,
323
+ minRows: {
324
+ type: Number,
325
+ default: 5
326
+ },
327
+ maxRows: {
328
+ type: Number,
329
+ default: 10
330
+ },
331
+ autocomplete: {
332
+ type: String
333
+ },
334
+ // ========== 手机号相关配置 ==========
335
+ // 默认区号
336
+ defaultPhoneCode: {
337
+ type: String,
338
+ default: '+86'
339
+ },
340
+ // 区号列表
341
+ phoneCodeOptions: {
342
+ type: Array,
343
+ default: () => []
344
+ },
345
+ // 手机号最大长度
346
+ phoneMaxLength: {
347
+ type: Number,
348
+ default: 11
349
+ },
350
+ // 区号选择器占位符
351
+ phoneCodePlaceholder: {
352
+ type: String,
353
+ default: ''
354
+ },
355
+ // 手机号输入框占位符
356
+ phonePlaceholder: {
357
+ type: String,
358
+ default: ''
359
+ },
360
+
361
+ // ========== 货币相关配置 ==========
362
+ // 货币类型
363
+ currency: {
364
+ type: String,
365
+ default: 'CNY'
366
+ },
367
+ // 自定义货币符号
368
+ currencySymbolCustom: {
369
+ type: String,
370
+ default: ''
371
+ },
372
+ // 货币单位(如:元、万元)
373
+ currencyUnit: {
374
+ type: String,
375
+ default: ''
376
+ },
377
+ // 小数位数
378
+ currencyPrecision: {
379
+ type: Number,
380
+ default: 2
381
+ },
382
+ // 货币占位符
383
+ currencyPlaceholder: {
384
+ type: String,
385
+ default: ''
386
+ },
387
+ // 最小值
388
+ currencyMin: {
389
+ type: Number,
390
+ default: undefined
391
+ },
392
+ // 最大值
393
+ currencyMax: {
394
+ type: Number,
395
+ default: undefined
396
+ },
397
+
398
+ // ========== 银行卡相关配置 ==========
399
+ // 分隔符
400
+ bankCardSeparator: {
401
+ type: String,
402
+ default: ' '
403
+ },
404
+ // 分段长度
405
+ bankCardSegment: {
406
+ type: Number,
407
+ default: 4
408
+ },
409
+ // 银行卡最大长度(不含分隔符)
410
+ bankCardMaxDigits: {
411
+ type: Number,
412
+ default: 19
413
+ },
414
+ // 银行卡占位符
415
+ bankCardPlaceholder: {
416
+ type: String,
417
+ default: ''
418
+ },
419
+ // 是否显示银行卡类型
420
+ showBankCardType: {
421
+ type: Boolean,
422
+ default: true
423
+ },
424
+
425
+ // ========== 身份证相关配置 ==========
426
+ // 身份证占位符
427
+ idCardPlaceholder: {
428
+ type: String,
429
+ default: ''
430
+ },
431
+ // 是否显示身份证信息
432
+ showIdCardInfo: {
433
+ type: Boolean,
434
+ default: true
435
+ },
436
+ // 是否实时校验
437
+ idCardRealtimeValidate: {
438
+ type: Boolean,
439
+ default: true
440
+ },
441
+
442
+ // ========== 邮箱相关配置 ==========
443
+ emailPlaceholder: {
444
+ type: String,
445
+ default: ''
446
+ },
447
+ // 邮箱后缀建议列表
448
+ emailSuffixes: {
449
+ type: Array,
450
+ default: () => ['@qq.com', '@163.com', '@126.com', '@gmail.com', '@outlook.com', '@hotmail.com', '@sina.com', '@sohu.com', '@foxmail.com', '@icloud.com']
451
+ },
452
+ // 是否显示邮箱建议
453
+ showEmailSuffix: {
454
+ type: Boolean,
455
+ default: true
456
+ },
457
+
458
+ // ========== 验证码相关配置 ==========
459
+ codePlaceholder: {
460
+ type: String,
461
+ default: ''
462
+ },
463
+ // 验证码长度
464
+ codeLength: {
465
+ type: Number,
466
+ default: 6
467
+ },
468
+ // 验证码分隔符
469
+ codeSeparator: {
470
+ type: String,
471
+ default: ''
472
+ },
473
+
474
+ // ========== 车牌号相关配置 ==========
475
+ platePlaceholder: {
476
+ type: String,
477
+ default: ''
478
+ },
479
+ // 默认省份
480
+ defaultPlateProvince: {
481
+ type: String,
482
+ default: ''
483
+ },
484
+ // 省份列表
485
+ plateProvinceList: {
486
+ type: Array,
487
+ default: () => []
488
+ },
489
+
490
+ // ========== IP地址相关配置 ==========
491
+ ipPlaceholder: {
492
+ type: String,
493
+ default: ''
494
+ },
495
+ // IP版本 (4 或 6)
496
+ ipVersion: {
497
+ type: Number,
498
+ default: 4
499
+ },
500
+
501
+ // ========== MAC地址相关配置 ==========
502
+ macPlaceholder: {
503
+ type: String,
504
+ default: ''
505
+ },
506
+ // MAC分隔符
507
+ macSeparator: {
508
+ type: String,
509
+ default: ':'
510
+ },
511
+
512
+ // ========== 社会信用代码相关配置 ==========
513
+ usccPlaceholder: {
514
+ type: String,
515
+ default: ''
516
+ },
517
+ // 是否实时校验
518
+ usccRealtimeValidate: {
519
+ type: Boolean,
520
+ default: true
521
+ }
522
+ },
523
+ computed: {
524
+ isSearch() {
525
+ return this.type === 'search';
526
+ },
527
+ isPhone() {
528
+ return this.type === 'phone';
529
+ },
530
+ isCurrency() {
531
+ return this.type === 'currency';
532
+ },
533
+ isBankCard() {
534
+ return this.type === 'bankCard' || this.type === 'bank-card';
535
+ },
536
+ isIdCard() {
537
+ return this.type === 'idCard' || this.type === 'id-card';
538
+ },
539
+ isEmail() {
540
+ return this.type === 'email';
541
+ },
542
+ isCode() {
543
+ return this.type === 'code';
544
+ },
545
+ isPlate() {
546
+ return this.type === 'plate';
547
+ },
548
+ isIp() {
549
+ return this.type === 'ip';
550
+ },
551
+ isMac() {
552
+ return this.type === 'mac';
553
+ },
554
+ isUscc() {
555
+ return this.type === 'uscc';
556
+ },
557
+ isDefault() {
558
+ return !this.isPhone && !this.isCurrency && !this.isBankCard && !this.isIdCard &&
559
+ !this.isEmail && !this.isCode && !this.isPlate && !this.isIp && !this.isMac && !this.isUscc;
560
+ },
561
+ typeParam() {
562
+ if (this.type === "textarea") {
563
+ return "textarea";
564
+ } else if (this.type === "password") {
565
+ return "password";
566
+ } else {
567
+ return "text";
568
+ }
569
+ },
570
+ // ========== 统一输入框计算属性 ==========
571
+ inputClass() {
572
+ if (this.isCurrency) return this.b('currency');
573
+ if (this.isBankCard) return this.b('bank-card');
574
+ if (this.isIdCard) return [this.b('id-card'), this.idCardValid === false ? this.b('id-card--invalid') : ''];
575
+ return '';
576
+ },
577
+ inputValue: {
578
+ get() {
579
+ if (this.isCurrency) return this.currencyDisplay;
580
+ if (this.isBankCard) return this.bankCardDisplay;
581
+ if (this.isIdCard) return this.idCardDisplay;
582
+ if (this.isEmail) return this.emailDisplay;
583
+ if (this.isUscc) return this.usccDisplay;
584
+ return this.text;
585
+ },
586
+ set(val) {
587
+ if (this.isCurrency) this.currencyDisplay = val;
588
+ else if (this.isBankCard) this.bankCardDisplay = val;
589
+ else if (this.isIdCard) this.idCardDisplay = val;
590
+ else if (this.isEmail) this.emailDisplay = val;
591
+ else if (this.isUscc) this.usccDisplay = val;
592
+ else this.text = val;
593
+ }
594
+ },
595
+ inputType() {
596
+ if (this.isEmail) return 'email';
597
+ return this.isDefault ? this.typeParam : 'text';
598
+ },
599
+ inputMaxlength() {
600
+ if (this.isBankCard) return this.bankCardMaxLength;
601
+ if (this.isIdCard) return 18;
602
+ if (this.isUscc) return 18;
603
+ return this.maxlength;
604
+ },
605
+ inputPrefixIcon() {
606
+ return this.prefixIcon;
607
+ },
608
+ inputSuffixIcon() {
609
+ if (this.isIdCard) return this.idCardSuffixIcon;
610
+ return this.suffixIcon;
611
+ },
612
+ inputPlaceholder() {
613
+ if (this.isCurrency) return this.currencyPlaceholder || this.t('input.currencyPlaceholder');
614
+ if (this.isBankCard) return this.bankCardPlaceholder || this.t('input.bankCardPlaceholder');
615
+ if (this.isIdCard) return this.idCardPlaceholder || this.t('input.idCardPlaceholder');
616
+ if (this.isEmail) return this.emailPlaceholder || this.t('input.emailPlaceholder');
617
+ if (this.isUscc) return this.usccPlaceholder || this.t('input.usccPlaceholder');
618
+ return this.placeholder;
619
+ },
620
+ phoneCodePlaceholderText() {
621
+ return this.phoneCodePlaceholder || this.t('input.phoneCodePlaceholder');
622
+ },
623
+ phonePlaceholderText() {
624
+ return this.phonePlaceholder || this.t('input.phonePlaceholder');
625
+ },
626
+ platePlaceholderText() {
627
+ return this.platePlaceholder || this.t('input.platePlaceholder');
628
+ },
629
+ showPrepend() {
630
+ if (this.isCurrency) return !!this.currencySymbol;
631
+ return !!this.prepend;
632
+ },
633
+ prependText() {
634
+ if (this.isCurrency) return this.currencySymbol;
635
+ return this.prepend;
636
+ },
637
+ showAppend() {
638
+ if (this.isCurrency) return !!this.currencyUnit;
639
+ return !!this.append;
640
+ },
641
+ appendText() {
642
+ if (this.isCurrency) return this.currencyUnit;
643
+ return this.append;
644
+ },
645
+ showSuffix() {
646
+ return (this.isBankCard && this.showBankCardType && this.bankCardType) ||
647
+ (this.isIdCard && this.showIdCardInfo && this.idCardInfo) ||
648
+ (this.isEmail && this.emailValid !== null) ||
649
+ (this.isUscc && this.usccValid !== null);
650
+ },
651
+ // ========== 原有计算属性 ==========
652
+ // 手机区号列表
653
+ phoneCodeList() {
654
+ const list = this.phoneCodeOptions.length > 0 ? this.phoneCodeOptions : defaultPhoneCodeOptions;
655
+ return list.map((item) => {
656
+ const flag = item.flag || '';
657
+ const name = item.name || (item.nameKey ? this.t(item.nameKey) : item.code);
658
+ return {
659
+ ...item,
660
+ name,
661
+ label: item.label || [flag, item.code].filter(Boolean).join(' ')
662
+ };
663
+ });
664
+ },
665
+ localizedPlateProvinces() {
666
+ const provinces = this.t('input.plateProvinces');
667
+ return Array.isArray(provinces) ? provinces : [];
668
+ },
669
+ resolvedPlateProvinceList() {
670
+ return this.plateProvinceList.length > 0 ? this.plateProvinceList : this.localizedPlateProvinces;
671
+ },
672
+ resolvedDefaultPlateProvince() {
673
+ return this.defaultPlateProvince || this.resolvedPlateProvinceList[0] || '';
674
+ },
675
+ // 货币符号
676
+ currencySymbol() {
677
+ if (this.currencySymbolCustom) {
678
+ return this.currencySymbolCustom;
679
+ }
680
+ return currencySymbols[this.currency] || '¥';
681
+ },
682
+ // 银行卡最大长度(含分隔符)
683
+ bankCardMaxLength() {
684
+ const digits = this.bankCardMaxDigits;
685
+ const separatorCount = Math.floor((digits - 1) / this.bankCardSegment);
686
+ return digits + separatorCount;
687
+ },
688
+ // 身份证后缀图标
689
+ idCardSuffixIcon() {
690
+ if (this.suffixIcon) return this.suffixIcon;
691
+ if (this.idCardValid === true) return 'el-icon-success';
692
+ if (this.idCardValid === false) return 'el-icon-warning';
693
+ return '';
694
+ },
695
+ // 身份证信息文本
696
+ idCardInfoText() {
697
+ if (!this.idCardInfo) return '';
698
+ return `${this.idCardInfo.region} | ${this.idCardInfo.birthday} | ${this.idCardInfo.gender}`;
699
+ }
700
+ },
701
+ watch: {
702
+ modelValue: {
703
+ immediate: true,
704
+ handler(val) {
705
+ this.initSpecialValue(val);
706
+ }
707
+ },
708
+ phoneCode(val) {
709
+ this.updatePhoneValue();
710
+ },
711
+ phoneNumber(val) {
712
+ // 只允许数字
713
+ this.phoneNumber = val.replace(/\D/g, '');
714
+ this.updatePhoneValue();
715
+ },
716
+ defaultPhoneCode: {
717
+ immediate: true,
718
+ handler(val) {
719
+ if (!this.modelValue) {
720
+ this.phoneCode = val;
721
+ }
722
+ }
723
+ }
724
+ },
725
+ methods: {
726
+ // ========== 统一事件处理 ==========
727
+ onFocus(event) {
728
+ if (this.isCurrency) {
729
+ this.handleCurrencyFocus(event);
730
+ } else {
731
+ this.handleFocus(event);
732
+ }
733
+ },
734
+ onBlur(event) {
735
+ if (this.isCurrency) {
736
+ this.handleCurrencyBlur(event);
737
+ } else if (this.isIdCard) {
738
+ this.handleIdCardBlur(event);
739
+ } else if (this.isEmail) {
740
+ this.handleEmailBlur(event);
741
+ } else if (this.isUscc) {
742
+ this.handleUsccBlur(event);
743
+ } else {
744
+ this.handleBlur(event);
745
+ }
746
+ },
747
+ onInput(val) {
748
+ if (this.isCurrency) {
749
+ this.handleCurrencyInput(val);
750
+ } else if (this.isBankCard) {
751
+ this.handleBankCardInput(val);
752
+ } else if (this.isIdCard) {
753
+ this.handleIdCardInput(val);
754
+ } else if (this.isEmail) {
755
+ this.handleEmailInput(val);
756
+ } else if (this.isUscc) {
757
+ this.handleUsccInput(val);
758
+ }
759
+ },
760
+ // 初始化特殊类型的值
761
+ initSpecialValue(val) {
762
+ if (this.isPhone) {
763
+ this.initPhoneValue(val);
764
+ } else if (this.isCurrency) {
765
+ this.initCurrencyValue(val);
766
+ } else if (this.isBankCard) {
767
+ this.initBankCardValue(val);
768
+ } else if (this.isIdCard) {
769
+ this.initIdCardValue(val);
770
+ } else if (this.isEmail) {
771
+ this.initEmailValue(val);
772
+ } else if (this.isCode) {
773
+ this.initCodeValue(val);
774
+ } else if (this.isPlate) {
775
+ this.initPlateValue(val);
776
+ } else if (this.isIp) {
777
+ this.initIpValue(val);
778
+ } else if (this.isMac) {
779
+ this.initMacValue(val);
780
+ } else if (this.isUscc) {
781
+ this.initUsccValue(val);
782
+ }
783
+ },
784
+
785
+ // ========== 手机号相关方法 ==========
786
+ initPhoneValue(val) {
787
+ if (!val) {
788
+ this.phoneCode = this.defaultPhoneCode;
789
+ this.phoneNumber = '';
790
+ return;
791
+ }
792
+ // 支持格式:+86-13800138000 或 +8613800138000 或纯手机号
793
+ const str = String(val);
794
+ const match = str.match(/^(\+\d+)[-\s]?(\d+)$/);
795
+ if (match) {
796
+ this.phoneCode = match[1];
797
+ this.phoneNumber = match[2];
798
+ } else {
799
+ this.phoneNumber = str.replace(/\D/g, '');
800
+ }
801
+ },
802
+ updatePhoneValue() {
803
+ const value = this.phoneNumber ? `${this.phoneCode}-${this.phoneNumber}` : '';
804
+ this.text = value;
805
+
806
+ },
807
+ handlePhoneBlur(event) {
808
+ this.handleBlur(event);
809
+ },
810
+
811
+ // ========== 货币相关方法 ==========
812
+ initCurrencyValue(val) {
813
+ if (val === undefined || val === null || val === '') {
814
+ this.currencyDisplay = '';
815
+ return;
816
+ }
817
+ const num = parseFloat(val);
818
+ if (!isNaN(num)) {
819
+ this.currencyDisplay = this.formatCurrency(num);
820
+ }
821
+ },
822
+ formatCurrency(value) {
823
+ if (value === undefined || value === null || value === '') return '';
824
+ const num = parseFloat(value);
825
+ if (isNaN(num)) return '';
826
+ // 格式化为千分位
827
+ const fixed = num.toFixed(this.currencyPrecision);
828
+ const parts = fixed.split('.');
829
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
830
+ return parts.join('.');
831
+ },
832
+ parseCurrency(value) {
833
+ if (!value) return '';
834
+ // 移除千分位分隔符
835
+ return value.replace(/,/g, '');
836
+ },
837
+ handleCurrencyFocus(event) {
838
+ this.currencyEditing = true;
839
+ // 编辑时显示原始数字
840
+ if (this.text) {
841
+ this.currencyDisplay = this.text;
842
+ }
843
+ this.handleFocus(event);
844
+ },
845
+ handleCurrencyBlur(event) {
846
+ this.currencyEditing = false;
847
+ const rawValue = this.parseCurrency(this.currencyDisplay);
848
+ let num = parseFloat(rawValue);
849
+
850
+ // 范围限制
851
+ if (!isNaN(num)) {
852
+ if (this.currencyMin !== undefined && num < this.currencyMin) {
853
+ num = this.currencyMin;
854
+ }
855
+ if (this.currencyMax !== undefined && num > this.currencyMax) {
856
+ num = this.currencyMax;
857
+ }
858
+ this.text = num.toFixed(this.currencyPrecision);
859
+ this.currencyDisplay = this.formatCurrency(num);
860
+ } else {
861
+ this.text = '';
862
+ this.currencyDisplay = '';
863
+ }
864
+
865
+
866
+ this.handleBlur(event);
867
+ },
868
+ handleCurrencyInput(val) {
869
+ // 只允许数字、小数点和逗号
870
+ this.currencyDisplay = val.replace(/[^\d.,]/g, '');
871
+ },
872
+
873
+ // ========== 银行卡相关方法 ==========
874
+ initBankCardValue(val) {
875
+ if (!val) {
876
+ this.bankCardDisplay = '';
877
+ this.bankCardType = '';
878
+ return;
879
+ }
880
+ const digits = String(val).replace(/\D/g, '');
881
+ this.bankCardDisplay = this.formatBankCard(digits);
882
+ this.detectBankCardType(digits);
883
+ },
884
+ formatBankCard(value) {
885
+ if (!value) return '';
886
+ const digits = value.replace(/\D/g, '');
887
+ const chunks = [];
888
+ for (let i = 0; i < digits.length; i += this.bankCardSegment) {
889
+ chunks.push(digits.slice(i, i + this.bankCardSegment));
890
+ }
891
+ return chunks.join(this.bankCardSeparator);
892
+ },
893
+ handleBankCardInput(val) {
894
+ // 只允许数字和分隔符
895
+ const digits = val.replace(/\D/g, '').slice(0, this.bankCardMaxDigits);
896
+ this.bankCardDisplay = this.formatBankCard(digits);
897
+ this.text = digits;
898
+ this.detectBankCardType(digits);
899
+ this.$emit('bank-card-change', { value: digits, display: this.bankCardDisplay, type: this.bankCardType });
900
+ },
901
+ detectBankCardType(cardNumber) {
902
+ if (!cardNumber || cardNumber.length < 6) {
903
+ this.bankCardType = '';
904
+ return;
905
+ }
906
+ // 根据 BIN 码判断银行卡类型(简化版)
907
+ const bin = cardNumber.slice(0, 6);
908
+ const bin4 = cardNumber.slice(0, 4);
909
+
910
+ // 常见银行卡 BIN 码判断
911
+ if (/^62/.test(bin)) {
912
+ this.bankCardType = this.t('input.bankCardTypes.unionpay');
913
+ } else if (/^4/.test(bin)) {
914
+ this.bankCardType = 'VISA';
915
+ } else if (/^5[1-5]/.test(bin) || /^2[2-7]/.test(bin)) {
916
+ this.bankCardType = 'MasterCard';
917
+ } else if (/^3[47]/.test(bin)) {
918
+ this.bankCardType = 'American Express';
919
+ } else if (/^35/.test(bin)) {
920
+ this.bankCardType = 'JCB';
921
+ } else if (/^6011|65/.test(bin)) {
922
+ this.bankCardType = 'Discover';
923
+ } else {
924
+ this.bankCardType = '';
925
+ }
926
+ },
927
+
928
+ // ========== 身份证相关方法 ==========
929
+ initIdCardValue(val) {
930
+ if (!val) {
931
+ this.idCardDisplay = '';
932
+ this.idCardValid = null;
933
+ this.idCardInfo = null;
934
+ return;
935
+ }
936
+ this.idCardDisplay = String(val).toUpperCase();
937
+ if (this.idCardRealtimeValidate) {
938
+ this.validateIdCard(this.idCardDisplay);
939
+ }
940
+ },
941
+ handleIdCardInput(val) {
942
+ // 只允许数字和 X
943
+ this.idCardDisplay = val.replace(/[^\dXx]/g, '').toUpperCase().slice(0, 18);
944
+ this.text = this.idCardDisplay;
945
+
946
+ if (this.idCardRealtimeValidate && this.idCardDisplay.length === 18) {
947
+ this.validateIdCard(this.idCardDisplay);
948
+ } else {
949
+ this.idCardValid = null;
950
+ this.idCardInfo = null;
951
+ }
952
+
953
+ this.$emit('id-card-change', {
954
+ value: this.idCardDisplay,
955
+ valid: this.idCardValid,
956
+ info: this.idCardInfo
957
+ });
958
+ },
959
+ handleIdCardBlur(event) {
960
+ if (this.idCardDisplay && this.idCardDisplay.length === 18) {
961
+ this.validateIdCard(this.idCardDisplay);
962
+ }
963
+ this.$emit('id-card-valid', { valid: this.idCardValid, info: this.idCardInfo });
964
+ this.handleBlur(event);
965
+ },
966
+ validateIdCard(idCard) {
967
+ if (!idCard || idCard.length !== 18) {
968
+ this.idCardValid = false;
969
+ this.idCardInfo = null;
970
+ return false;
971
+ }
972
+
973
+ // 加权因子
974
+ const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
975
+ // 校验码对照表
976
+ const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
977
+
978
+ // 计算校验和
979
+ let sum = 0;
980
+ for (let i = 0; i < 17; i++) {
981
+ const digit = parseInt(idCard.charAt(i), 10);
982
+ if (isNaN(digit)) {
983
+ this.idCardValid = false;
984
+ this.idCardInfo = null;
985
+ return false;
986
+ }
987
+ sum += digit * weights[i];
988
+ }
989
+
990
+ // 验证校验码
991
+ const checkCode = checkCodes[sum % 11];
992
+ const valid = idCard.charAt(17).toUpperCase() === checkCode;
993
+
994
+ this.idCardValid = valid;
995
+
996
+ if (valid) {
997
+ // 解析身份证信息
998
+ const regionCode = idCard.slice(0, 6);
999
+ const birthYear = idCard.slice(6, 10);
1000
+ const birthMonth = idCard.slice(10, 12);
1001
+ const birthDay = idCard.slice(12, 14);
1002
+ const genderCode = parseInt(idCard.charAt(16), 10);
1003
+
1004
+ this.idCardInfo = {
1005
+ region: this.getRegionName(regionCode),
1006
+ birthday: `${birthYear}-${birthMonth}-${birthDay}`,
1007
+ gender: genderCode % 2 === 0 ? this.t('input.genders.female') : this.t('input.genders.male'),
1008
+ age: this.calculateAge(birthYear, birthMonth, birthDay)
1009
+ };
1010
+ } else {
1011
+ this.idCardInfo = null;
1012
+ }
1013
+
1014
+ return valid;
1015
+ },
1016
+ getRegionName(code) {
1017
+ const regions = this.t('input.regions');
1018
+ const provinceCode = code.slice(0, 2);
1019
+ return (regions && regions[provinceCode]) || this.t('input.unknownRegion');
1020
+ },
1021
+ calculateAge(year, month, day) {
1022
+ const birthDate = new Date(year, month - 1, day);
1023
+ const today = new Date();
1024
+ let age = today.getFullYear() - birthDate.getFullYear();
1025
+ const monthDiff = today.getMonth() - birthDate.getMonth();
1026
+ if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
1027
+ age--;
1028
+ }
1029
+ return age;
1030
+ },
1031
+
1032
+ // ========== 邮箱相关方法 ==========
1033
+ initEmailValue(val) {
1034
+ this.emailDisplay = val || '';
1035
+ if (val) {
1036
+ this.emailValid = this.validateEmail(val);
1037
+ }
1038
+ },
1039
+ handleEmailInput(val) {
1040
+ this.emailDisplay = val;
1041
+ this.text = val;
1042
+ this.emailValid = val ? this.validateEmail(val) : null;
1043
+
1044
+ },
1045
+ handleEmailBlur(event) {
1046
+ this.emailValid = this.emailDisplay ? this.validateEmail(this.emailDisplay) : null;
1047
+ this.handleBlur(event);
1048
+ },
1049
+ validateEmail(email) {
1050
+ const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
1051
+ return regex.test(email);
1052
+ },
1053
+
1054
+ // ========== 验证码相关方法 ==========
1055
+ initCodeValue(val) {
1056
+ const str = String(val || '');
1057
+ this.codeValues = Array(this.codeLength).fill('').map((_, i) => str[i] || '');
1058
+ },
1059
+ handleCodeInput(event, index) {
1060
+ const val = event.target.value.replace(/\D/g, '');
1061
+ this.codeValues[index] = val.slice(-1);
1062
+ this.updateCodeValue();
1063
+ // 自动跳转下一格
1064
+ if (val && index < this.codeLength - 1) {
1065
+ this.$nextTick(() => {
1066
+ if (this.codeRefs[index + 1]) {
1067
+ this.codeRefs[index + 1].focus();
1068
+ }
1069
+ });
1070
+ }
1071
+ },
1072
+ handleCodeKeydown(event, index) {
1073
+ // 退格键处理
1074
+ if (event.key === 'Backspace' && !this.codeValues[index] && index > 0) {
1075
+ this.$nextTick(() => {
1076
+ if (this.codeRefs[index - 1]) {
1077
+ this.codeRefs[index - 1].focus();
1078
+ }
1079
+ });
1080
+ }
1081
+ },
1082
+ handleCodePaste(event) {
1083
+ event.preventDefault();
1084
+ const paste = (event.clipboardData || window.clipboardData).getData('text').replace(/\D/g, '');
1085
+ const chars = paste.slice(0, this.codeLength).split('');
1086
+ chars.forEach((char, i) => {
1087
+ this.codeValues[i] = char;
1088
+ });
1089
+ this.updateCodeValue();
1090
+ // 聚焦到最后一个填入的位置
1091
+ const focusIndex = Math.min(chars.length, this.codeLength - 1);
1092
+ this.$nextTick(() => {
1093
+ if (this.codeRefs[focusIndex]) {
1094
+ this.codeRefs[focusIndex].focus();
1095
+ }
1096
+ });
1097
+ },
1098
+ updateCodeValue() {
1099
+ const value = this.codeValues.join(this.codeSeparator);
1100
+ this.text = this.codeValues.join('');
1101
+
1102
+ if (this.codeValues.every(v => v)) {
1103
+ this.$emit('code-complete', { value: this.text });
1104
+ }
1105
+ },
1106
+
1107
+ // ========== 车牌号相关方法 ==========
1108
+ initPlateValue(val) {
1109
+ if (!val) {
1110
+ this.plateProvince = this.resolvedDefaultPlateProvince;
1111
+ this.plateNumber = '';
1112
+ return;
1113
+ }
1114
+ const str = String(val);
1115
+ if (str.length > 0) {
1116
+ this.plateProvince = str[0];
1117
+ this.plateNumber = str.slice(1).toUpperCase();
1118
+ }
1119
+ },
1120
+ handlePlateInput(val) {
1121
+ this.plateNumber = val.toUpperCase().replace(/[^A-Z0-9]/g, '');
1122
+ this.updatePlateValue();
1123
+ },
1124
+ handlePlateBlur(event) {
1125
+ this.updatePlateValue();
1126
+ this.handleBlur(event);
1127
+ },
1128
+ updatePlateValue() {
1129
+ const value = this.plateProvince + this.plateNumber;
1130
+ this.text = value;
1131
+
1132
+ },
1133
+
1134
+ // ========== IP地址相关方法 ==========
1135
+ initIpValue(val) {
1136
+ if (!val) {
1137
+ this.ipSegments = ['', '', '', ''];
1138
+ return;
1139
+ }
1140
+ const parts = String(val).split('.');
1141
+ this.ipSegments = parts.slice(0, 4).map(p => p || '');
1142
+ while (this.ipSegments.length < 4) {
1143
+ this.ipSegments.push('');
1144
+ }
1145
+ },
1146
+ handleIpInput(event, index) {
1147
+ let val = event.target.value.replace(/\D/g, '');
1148
+ // 限制范围 0-255
1149
+ if (val !== '' && parseInt(val, 10) > 255) {
1150
+ val = '255';
1151
+ }
1152
+ this.ipSegments[index] = val;
1153
+ this.updateIpValue();
1154
+ // 自动跳转
1155
+ if (val.length === 3 || (val.length > 0 && parseInt(val, 10) >= 26)) {
1156
+ if (index < 3 && this.ipRefs[index + 1]) {
1157
+ this.$nextTick(() => this.ipRefs[index + 1].focus());
1158
+ }
1159
+ }
1160
+ },
1161
+ handleIpKeydown(event, index) {
1162
+ if (event.key === '.' && index < 3) {
1163
+ event.preventDefault();
1164
+ if (this.ipRefs[index + 1]) {
1165
+ this.ipRefs[index + 1].focus();
1166
+ }
1167
+ }
1168
+ if (event.key === 'Backspace' && !this.ipSegments[index] && index > 0) {
1169
+ if (this.ipRefs[index - 1]) {
1170
+ this.ipRefs[index - 1].focus();
1171
+ }
1172
+ }
1173
+ },
1174
+ updateIpValue() {
1175
+ const value = this.ipSegments.join('.');
1176
+ this.text = value;
1177
+
1178
+ },
1179
+
1180
+ // ========== MAC地址相关方法 ==========
1181
+ initMacValue(val) {
1182
+ if (!val) {
1183
+ this.macSegments = ['', '', '', '', '', ''];
1184
+ return;
1185
+ }
1186
+ const str = String(val).replace(/[^A-Fa-f0-9]/g, '');
1187
+ this.macSegments = [];
1188
+ for (let i = 0; i < 6; i++) {
1189
+ this.macSegments.push(str.slice(i * 2, i * 2 + 2).toUpperCase());
1190
+ }
1191
+ },
1192
+ handleMacInput(event, index) {
1193
+ let val = event.target.value.replace(/[^A-Fa-f0-9]/g, '').toUpperCase();
1194
+ this.macSegments[index] = val.slice(0, 2);
1195
+ this.updateMacValue();
1196
+ // 自动跳转
1197
+ if (val.length >= 2 && index < 5) {
1198
+ this.$nextTick(() => {
1199
+ if (this.macRefs[index + 1]) {
1200
+ this.macRefs[index + 1].focus();
1201
+ }
1202
+ });
1203
+ }
1204
+ },
1205
+ handleMacKeydown(event, index) {
1206
+ if ((event.key === ':' || event.key === '-') && index < 5) {
1207
+ event.preventDefault();
1208
+ if (this.macRefs[index + 1]) {
1209
+ this.macRefs[index + 1].focus();
1210
+ }
1211
+ }
1212
+ if (event.key === 'Backspace' && !this.macSegments[index] && index > 0) {
1213
+ if (this.macRefs[index - 1]) {
1214
+ this.macRefs[index - 1].focus();
1215
+ }
1216
+ }
1217
+ },
1218
+ updateMacValue() {
1219
+ const value = this.macSegments.join(this.macSeparator);
1220
+ this.text = this.macSegments.join('');
1221
+
1222
+ },
1223
+
1224
+ // ========== 社会信用代码相关方法 ==========
1225
+ initUsccValue(val) {
1226
+ this.usccDisplay = val || '';
1227
+ if (val && String(val).length === 18) {
1228
+ this.usccValid = this.validateUscc(val);
1229
+ }
1230
+ },
1231
+ handleUsccInput(val) {
1232
+ this.usccDisplay = val.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 18);
1233
+ this.text = this.usccDisplay;
1234
+ if (this.usccRealtimeValidate && this.usccDisplay.length === 18) {
1235
+ this.usccValid = this.validateUscc(this.usccDisplay);
1236
+ } else {
1237
+ this.usccValid = null;
1238
+ }
1239
+
1240
+ },
1241
+ handleUsccBlur(event) {
1242
+ if (this.usccDisplay && this.usccDisplay.length === 18) {
1243
+ this.usccValid = this.validateUscc(this.usccDisplay);
1244
+ this.$emit('uscc-valid', { valid: this.usccValid });
1245
+ }
1246
+ this.handleBlur(event);
1247
+ },
1248
+ validateUscc(code) {
1249
+ if (!code || code.length !== 18) return false;
1250
+ // 统一社会信用代码校验规则
1251
+ const chars = '0123456789ABCDEFGHJKLMNPQRTUWXY';
1252
+ const weights = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];
1253
+ let sum = 0;
1254
+ for (let i = 0; i < 17; i++) {
1255
+ const charIndex = chars.indexOf(code[i]);
1256
+ if (charIndex === -1) return false;
1257
+ sum += charIndex * weights[i];
1258
+ }
1259
+ const checkIndex = (31 - (sum % 31)) % 31;
1260
+ return chars[checkIndex] === code[17];
1261
+ }
1262
+ }
1263
+ });
1264
+ </script>