ff-ui-plus 2.0.7

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 (319) hide show
  1. package/.nvmrc +1 -0
  2. package/.prettierrc.cjs +41 -0
  3. package/.stylelintignore +5 -0
  4. package/LICENSE +21 -0
  5. package/README.md +265 -0
  6. package/commitlint.config.cjs +162 -0
  7. package/global.d.ts +27 -0
  8. package/index.html +16 -0
  9. package/lib.sh +9 -0
  10. package/lint-staged.config.cjs +8 -0
  11. package/package.json +149 -0
  12. package/packages/components/adaptive-page/index.ts +5 -0
  13. package/packages/components/adaptive-page/src/index.vue +85 -0
  14. package/packages/components/adaptive-page/src/type.ts +9 -0
  15. package/packages/components/adaptive-page/style/css.ts +1 -0
  16. package/packages/components/adaptive-page/style/index.ts +1 -0
  17. package/packages/components/button/index.ts +5 -0
  18. package/packages/components/button/src/index.vue +41 -0
  19. package/packages/components/button/src/type.ts +11 -0
  20. package/packages/components/button/style/css.ts +1 -0
  21. package/packages/components/button/style/index.ts +1 -0
  22. package/packages/components/chart/index.ts +5 -0
  23. package/packages/components/chart/src/index.vue +121 -0
  24. package/packages/components/chart/src/type.ts +7 -0
  25. package/packages/components/chart/style/css.ts +1 -0
  26. package/packages/components/chart/style/index.ts +1 -0
  27. package/packages/components/checkbox/index.ts +3 -0
  28. package/packages/components/checkbox/src/checkbox.d.ts +5 -0
  29. package/packages/components/checkbox/src/index.vue +67 -0
  30. package/packages/components/checkbox/style/css.ts +1 -0
  31. package/packages/components/checkbox/style/index.ts +1 -0
  32. package/packages/components/date-picker/index.ts +5 -0
  33. package/packages/components/date-picker/src/index.vue +228 -0
  34. package/packages/components/date-picker/src/type.ts +22 -0
  35. package/packages/components/date-picker/style/css.ts +1 -0
  36. package/packages/components/date-picker/style/index.ts +1 -0
  37. package/packages/components/detail/index.ts +5 -0
  38. package/packages/components/detail/src/index.vue +102 -0
  39. package/packages/components/detail/src/renderLabel.vue +15 -0
  40. package/packages/components/detail/src/renderTooltip.vue +15 -0
  41. package/packages/components/detail/src/type.ts +28 -0
  42. package/packages/components/detail/style/css.ts +1 -0
  43. package/packages/components/detail/style/index.ts +1 -0
  44. package/packages/components/form/index.ts +5 -0
  45. package/packages/components/form/src/index.vue +407 -0
  46. package/packages/components/form/src/renderBtn.vue +15 -0
  47. package/packages/components/form/src/renderComp.vue +15 -0
  48. package/packages/components/form/src/type.ts +26 -0
  49. package/packages/components/form/style/css.ts +1 -0
  50. package/packages/components/form/style/index.ts +1 -0
  51. package/packages/components/index.ts +20 -0
  52. package/packages/components/input/index.ts +5 -0
  53. package/packages/components/input/src/index.vue +225 -0
  54. package/packages/components/input/src/type.ts +14 -0
  55. package/packages/components/input/style/css.ts +1 -0
  56. package/packages/components/input/style/index.ts +1 -0
  57. package/packages/components/layout-page/index.ts +4 -0
  58. package/packages/components/layout-page/src/index.vue +74 -0
  59. package/packages/components/layout-page/style/css.ts +1 -0
  60. package/packages/components/layout-page/style/index.ts +1 -0
  61. package/packages/components/layout-page-item/index.ts +3 -0
  62. package/packages/components/layout-page-item/src/index.vue +16 -0
  63. package/packages/components/layout-page-item/style/css.ts +1 -0
  64. package/packages/components/layout-page-item/style/index.ts +1 -0
  65. package/packages/components/module-form/index.ts +4 -0
  66. package/packages/components/module-form/src/index.vue +243 -0
  67. package/packages/components/module-form/src/moduleDetail.vue +61 -0
  68. package/packages/components/module-form/src/moduleForm.vue +88 -0
  69. package/packages/components/module-form/src/type.ts +16 -0
  70. package/packages/components/module-form/style/css.ts +1 -0
  71. package/packages/components/module-form/style/index.ts +1 -0
  72. package/packages/components/package.json +9 -0
  73. package/packages/components/query-condition/index.ts +4 -0
  74. package/packages/components/query-condition/src/index.vue +478 -0
  75. package/packages/components/query-condition/src/moreChoose.vue +159 -0
  76. package/packages/components/query-condition/src/renderComp.vue +15 -0
  77. package/packages/components/query-condition/src/type.ts +22 -0
  78. package/packages/components/query-condition/src/useComputed.ts +94 -0
  79. package/packages/components/query-condition/style/css.ts +1 -0
  80. package/packages/components/query-condition/style/index.ts +1 -0
  81. package/packages/components/radio/index.ts +3 -0
  82. package/packages/components/radio/src/index.vue +73 -0
  83. package/packages/components/radio/src/radio.d.ts +12 -0
  84. package/packages/components/radio/style/css.ts +1 -0
  85. package/packages/components/radio/style/index.ts +1 -0
  86. package/packages/components/select/index.ts +4 -0
  87. package/packages/components/select/src/index.vue +240 -0
  88. package/packages/components/select/src/type.ts +43 -0
  89. package/packages/components/select/style/css.ts +1 -0
  90. package/packages/components/select/style/index.ts +1 -0
  91. package/packages/components/select-icon/index.ts +4 -0
  92. package/packages/components/select-icon/src/index.vue +128 -0
  93. package/packages/components/select-icon/style/css.ts +1 -0
  94. package/packages/components/select-icon/style/index.ts +1 -0
  95. package/packages/components/select-table/index.ts +4 -0
  96. package/packages/components/select-table/src/ClickOutside.ts +106 -0
  97. package/packages/components/select-table/src/index.vue +851 -0
  98. package/packages/components/select-table/src/renderCol.vue +20 -0
  99. package/packages/components/select-table/src/type.ts +56 -0
  100. package/packages/components/select-table/src/useVirtualized.ts +86 -0
  101. package/packages/components/select-table/style/css.ts +1 -0
  102. package/packages/components/select-table/style/index.ts +1 -0
  103. package/packages/components/step-wizard/index.ts +4 -0
  104. package/packages/components/step-wizard/src/index.vue +99 -0
  105. package/packages/components/step-wizard/src/type.ts +17 -0
  106. package/packages/components/step-wizard/style/css.ts +1 -0
  107. package/packages/components/step-wizard/style/index.ts +1 -0
  108. package/packages/components/table/index.ts +5 -0
  109. package/packages/components/table/src/ColumnSet.vue +176 -0
  110. package/packages/components/table/src/TTableColumn.vue +100 -0
  111. package/packages/components/table/src/densitySet.vue +91 -0
  112. package/packages/components/table/src/firstColumn.vue +132 -0
  113. package/packages/components/table/src/index.vue +926 -0
  114. package/packages/components/table/src/operator.vue +246 -0
  115. package/packages/components/table/src/renderCol.vue +20 -0
  116. package/packages/components/table/src/renderHeader.vue +18 -0
  117. package/packages/components/table/src/singleEdit.vue +354 -0
  118. package/packages/components/table/src/singleEditCell.vue +303 -0
  119. package/packages/components/table/src/tableProps.ts +162 -0
  120. package/packages/components/table/src/useExpose.ts +74 -0
  121. package/packages/components/table/src/useVirtualized.ts +70 -0
  122. package/packages/components/table/style/css.ts +1 -0
  123. package/packages/components/table/style/index.ts +1 -0
  124. package/packages/components/tabs/index.ts +4 -0
  125. package/packages/components/tabs/src/index.vue +50 -0
  126. package/packages/components/tabs/style/css.ts +1 -0
  127. package/packages/components/tabs/style/index.ts +1 -0
  128. package/packages/components/timer-btn/index.ts +4 -0
  129. package/packages/components/timer-btn/src/index.vue +57 -0
  130. package/packages/components/timer-btn/style/css.ts +1 -0
  131. package/packages/components/timer-btn/style/index.ts +1 -0
  132. package/packages/components/utils/index.ts +142 -0
  133. package/packages/components/utils/install.ts +16 -0
  134. package/packages/eslint-config/build.config.ts +16 -0
  135. package/packages/eslint-config/dist/index.cjs +122 -0
  136. package/packages/eslint-config/dist/index.d.cts +92 -0
  137. package/packages/eslint-config/dist/index.d.mts +92 -0
  138. package/packages/eslint-config/dist/index.d.ts +92 -0
  139. package/packages/eslint-config/dist/index.mjs +120 -0
  140. package/packages/eslint-config/package.json +34 -0
  141. package/packages/eslint-config/src/index.ts +121 -0
  142. package/packages/ff-ui-plus/component.ts +55 -0
  143. package/packages/ff-ui-plus/defaults.ts +4 -0
  144. package/packages/ff-ui-plus/index.ts +9 -0
  145. package/packages/ff-ui-plus/make-installer.ts +10 -0
  146. package/packages/ff-ui-plus/package.json +117 -0
  147. package/packages/ff-ui-plus/version.ts +1 -0
  148. package/packages/hooks/index.ts +1 -0
  149. package/packages/hooks/package.json +9 -0
  150. package/packages/hooks/useLocale.ts +53 -0
  151. package/packages/locale/index.ts +11 -0
  152. package/packages/locale/lang/en.ts +157 -0
  153. package/packages/locale/lang/zh-cn.ts +155 -0
  154. package/packages/locale/package.json +12 -0
  155. package/packages/resolver/package.json +23 -0
  156. package/packages/resolver/src/index.ts +99 -0
  157. package/packages/theme-chalk/build.ts +76 -0
  158. package/packages/theme-chalk/dist/index.css +1 -0
  159. package/packages/theme-chalk/dist/src/adaptive-page.scss +48 -0
  160. package/packages/theme-chalk/dist/src/button.scss +23 -0
  161. package/packages/theme-chalk/dist/src/chart.scss +10 -0
  162. package/packages/theme-chalk/dist/src/checkbox.scss +0 -0
  163. package/packages/theme-chalk/dist/src/date-picker.scss +3 -0
  164. package/packages/theme-chalk/dist/src/detail.scss +7 -0
  165. package/packages/theme-chalk/dist/src/form.scss +104 -0
  166. package/packages/theme-chalk/dist/src/index.scss +19 -0
  167. package/packages/theme-chalk/dist/src/input.scss +0 -0
  168. package/packages/theme-chalk/dist/src/layout-page-item.scss +10 -0
  169. package/packages/theme-chalk/dist/src/layout-page.scss +37 -0
  170. package/packages/theme-chalk/dist/src/module-form.scss +335 -0
  171. package/packages/theme-chalk/dist/src/query-condition.scss +132 -0
  172. package/packages/theme-chalk/dist/src/radio.scss +0 -0
  173. package/packages/theme-chalk/dist/src/select-icon.scss +61 -0
  174. package/packages/theme-chalk/dist/src/select-table.scss +71 -0
  175. package/packages/theme-chalk/dist/src/select.scss +7 -0
  176. package/packages/theme-chalk/dist/src/step-wizard.scss +51 -0
  177. package/packages/theme-chalk/dist/src/table.scss +381 -0
  178. package/packages/theme-chalk/dist/src/tabs.scss +20 -0
  179. package/packages/theme-chalk/dist/src/timer-btn.scss +21 -0
  180. package/packages/theme-chalk/dist/t-adaptive-page.css +1 -0
  181. package/packages/theme-chalk/dist/t-button.css +1 -0
  182. package/packages/theme-chalk/dist/t-chart.css +1 -0
  183. package/packages/theme-chalk/dist/t-checkbox.css +0 -0
  184. package/packages/theme-chalk/dist/t-date-picker.css +1 -0
  185. package/packages/theme-chalk/dist/t-detail.css +1 -0
  186. package/packages/theme-chalk/dist/t-form.css +1 -0
  187. package/packages/theme-chalk/dist/t-input.css +0 -0
  188. package/packages/theme-chalk/dist/t-layout-page-item.css +1 -0
  189. package/packages/theme-chalk/dist/t-layout-page.css +1 -0
  190. package/packages/theme-chalk/dist/t-module-form.css +1 -0
  191. package/packages/theme-chalk/dist/t-query-condition.css +1 -0
  192. package/packages/theme-chalk/dist/t-radio.css +0 -0
  193. package/packages/theme-chalk/dist/t-select-icon.css +1 -0
  194. package/packages/theme-chalk/dist/t-select-table.css +1 -0
  195. package/packages/theme-chalk/dist/t-select.css +1 -0
  196. package/packages/theme-chalk/dist/t-step-wizard.css +1 -0
  197. package/packages/theme-chalk/dist/t-table.css +1 -0
  198. package/packages/theme-chalk/dist/t-tabs.css +1 -0
  199. package/packages/theme-chalk/dist/t-timer-btn.css +1 -0
  200. package/packages/theme-chalk/mixins/config.scss +8 -0
  201. package/packages/theme-chalk/mixins/function.scss +71 -0
  202. package/packages/theme-chalk/mixins/mixins.scss +79 -0
  203. package/packages/theme-chalk/package.json +21 -0
  204. package/packages/theme-chalk/src/adaptive-page.scss +48 -0
  205. package/packages/theme-chalk/src/button.scss +23 -0
  206. package/packages/theme-chalk/src/chart.scss +10 -0
  207. package/packages/theme-chalk/src/checkbox.scss +0 -0
  208. package/packages/theme-chalk/src/date-picker.scss +3 -0
  209. package/packages/theme-chalk/src/detail.scss +7 -0
  210. package/packages/theme-chalk/src/form.scss +104 -0
  211. package/packages/theme-chalk/src/index.scss +19 -0
  212. package/packages/theme-chalk/src/input.scss +0 -0
  213. package/packages/theme-chalk/src/layout-page-item.scss +10 -0
  214. package/packages/theme-chalk/src/layout-page.scss +37 -0
  215. package/packages/theme-chalk/src/module-form.scss +335 -0
  216. package/packages/theme-chalk/src/query-condition.scss +132 -0
  217. package/packages/theme-chalk/src/radio.scss +0 -0
  218. package/packages/theme-chalk/src/select-icon.scss +61 -0
  219. package/packages/theme-chalk/src/select-table.scss +71 -0
  220. package/packages/theme-chalk/src/select.scss +7 -0
  221. package/packages/theme-chalk/src/step-wizard.scss +51 -0
  222. package/packages/theme-chalk/src/table.scss +381 -0
  223. package/packages/theme-chalk/src/tabs.scss +20 -0
  224. package/packages/theme-chalk/src/timer-btn.scss +21 -0
  225. package/packages/types/global.ts +34 -0
  226. package/packages/types/index.ts +1 -0
  227. package/packages/types/package.json +10 -0
  228. package/packages/utils/build.config.ts +23 -0
  229. package/packages/utils/dist/cookie.cjs +1 -0
  230. package/packages/utils/dist/cookie.d.cts +16 -0
  231. package/packages/utils/dist/cookie.d.mts +16 -0
  232. package/packages/utils/dist/cookie.d.ts +16 -0
  233. package/packages/utils/dist/cookie.mjs +1 -0
  234. package/packages/utils/dist/day.cjs +1 -0
  235. package/packages/utils/dist/day.d.cts +37 -0
  236. package/packages/utils/dist/day.d.mts +37 -0
  237. package/packages/utils/dist/day.d.ts +37 -0
  238. package/packages/utils/dist/day.mjs +1 -0
  239. package/packages/utils/dist/file.cjs +1 -0
  240. package/packages/utils/dist/file.d.cts +61 -0
  241. package/packages/utils/dist/file.d.mts +61 -0
  242. package/packages/utils/dist/file.d.ts +61 -0
  243. package/packages/utils/dist/file.mjs +1 -0
  244. package/packages/utils/dist/index.cjs +1 -0
  245. package/packages/utils/dist/index.d.cts +13 -0
  246. package/packages/utils/dist/index.d.mts +13 -0
  247. package/packages/utils/dist/index.d.ts +13 -0
  248. package/packages/utils/dist/index.mjs +1 -0
  249. package/packages/utils/dist/is.cjs +1 -0
  250. package/packages/utils/dist/is.d.cts +117 -0
  251. package/packages/utils/dist/is.d.mts +117 -0
  252. package/packages/utils/dist/is.d.ts +117 -0
  253. package/packages/utils/dist/is.mjs +1 -0
  254. package/packages/utils/dist/letter.cjs +1 -0
  255. package/packages/utils/dist/letter.d.cts +12 -0
  256. package/packages/utils/dist/letter.d.mts +12 -0
  257. package/packages/utils/dist/letter.d.ts +12 -0
  258. package/packages/utils/dist/letter.mjs +1 -0
  259. package/packages/utils/dist/number.cjs +1 -0
  260. package/packages/utils/dist/number.d.cts +23 -0
  261. package/packages/utils/dist/number.d.mts +23 -0
  262. package/packages/utils/dist/number.d.ts +23 -0
  263. package/packages/utils/dist/number.mjs +1 -0
  264. package/packages/utils/dist/openExe.cjs +1 -0
  265. package/packages/utils/dist/openExe.d.cts +9 -0
  266. package/packages/utils/dist/openExe.d.mts +9 -0
  267. package/packages/utils/dist/openExe.d.ts +9 -0
  268. package/packages/utils/dist/openExe.mjs +1 -0
  269. package/packages/utils/dist/storage.cjs +1 -0
  270. package/packages/utils/dist/storage.d.cts +46 -0
  271. package/packages/utils/dist/storage.d.mts +46 -0
  272. package/packages/utils/dist/storage.d.ts +46 -0
  273. package/packages/utils/dist/storage.mjs +1 -0
  274. package/packages/utils/dist/validate.cjs +1 -0
  275. package/packages/utils/dist/validate.d.cts +32 -0
  276. package/packages/utils/dist/validate.d.mts +32 -0
  277. package/packages/utils/dist/validate.d.ts +32 -0
  278. package/packages/utils/dist/validate.mjs +1 -0
  279. package/packages/utils/dist/ws.cjs +1 -0
  280. package/packages/utils/dist/ws.d.cts +86 -0
  281. package/packages/utils/dist/ws.d.mts +86 -0
  282. package/packages/utils/dist/ws.d.ts +86 -0
  283. package/packages/utils/dist/ws.mjs +1 -0
  284. package/packages/utils/package.json +42 -0
  285. package/packages/utils/src/cookie.ts +24 -0
  286. package/packages/utils/src/day.ts +66 -0
  287. package/packages/utils/src/file.ts +173 -0
  288. package/packages/utils/src/index.ts +10 -0
  289. package/packages/utils/src/is.ts +159 -0
  290. package/packages/utils/src/letter.ts +15 -0
  291. package/packages/utils/src/number.ts +37 -0
  292. package/packages/utils/src/openExe.ts +45 -0
  293. package/packages/utils/src/storage.ts +77 -0
  294. package/packages/utils/src/validate.ts +55 -0
  295. package/packages/utils/src/ws.ts +191 -0
  296. package/pnpm-workspace.yaml +3 -0
  297. package/publish.sh +37 -0
  298. package/resolver.sh +9 -0
  299. package/scripts/build/all.ts +152 -0
  300. package/scripts/build/build.config.ts +10 -0
  301. package/scripts/build/dist/index.cjs +7 -0
  302. package/scripts/build/dist/index.d.ts +2 -0
  303. package/scripts/build/dist/index.mjs +12 -0
  304. package/scripts/build/index.ts +63 -0
  305. package/scripts/build/modules.ts +141 -0
  306. package/scripts/build/package.json +14 -0
  307. package/scripts/release/gen-version.ts +12 -0
  308. package/scripts/release/index.ts +209 -0
  309. package/scripts/utils/excludeFiles.ts +14 -0
  310. package/scripts/utils/index.ts +88 -0
  311. package/scripts/utils/main.ts +14 -0
  312. package/scripts/utils/paths.ts +40 -0
  313. package/scripts/utils/plugin.ts +61 -0
  314. package/tsconfig.base.json +23 -0
  315. package/tsconfig.vitest.json +11 -0
  316. package/tsconfig.web.json +18 -0
  317. package/typings/env.d.ts +22 -0
  318. package/typings/index.d.ts +161 -0
  319. package/vitest.config.ts +22 -0
@@ -0,0 +1,225 @@
1
+ <template>
2
+ <el-tooltip v-if="showTooltip" effect="dark" placement="bottom-start">
3
+ <template #content>
4
+ <div>{{ currencyFilter(modelValue) }}</div>
5
+ <div>{{ digitUppercase(modelValue) }}</div>
6
+ </template>
7
+ <el-input v-model="internalValue" v-bind="inputProps" @blur="handleBlur">
8
+ <template v-for="(_, name) in slots" :key="name" #[name]="data">
9
+ <slot :name="name" v-bind="data" />
10
+ </template>
11
+ <template v-if="showAppend" #append>
12
+ <span v-if="inputType === 'amount'">{{ appendTitleText }}</span>
13
+ <slot v-else name="append" />
14
+ </template>
15
+ </el-input>
16
+ </el-tooltip>
17
+ <el-input v-else v-model="internalValue" v-bind="inputProps" @blur="handleBlur">
18
+ <template v-for="(_, name) in slots" :key="name" #[name]="data">
19
+ <slot :name="name" v-bind="data" />
20
+ </template>
21
+ <template v-if="showAppend" #append>
22
+ <span v-if="inputType === 'amount'">{{ appendTitleText }}</span>
23
+ <slot v-else name="append" />
24
+ </template>
25
+ </el-input>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import { ElMessage } from "element-plus"
30
+ import { computed, useSlots, useAttrs } from "vue"
31
+ import { useLocale } from "@ff-ui-plus/hooks"
32
+ import type { FFInputSelfProps as FFInputProps } from "./type"
33
+
34
+ defineOptions({
35
+ name: "FInput"
36
+ })
37
+
38
+ const { t } = useLocale()
39
+ const attrs = useAttrs()
40
+ const props = withDefaults(defineProps<FFInputProps>(), {
41
+ modelValue: "",
42
+ placeholder: "",
43
+ decimalLimit: 2,
44
+ inputType: "text",
45
+ appendTitle: "",
46
+ showThousands: false,
47
+ isTip: false,
48
+ isShowErrorTip: false,
49
+ customErrorTip: ""
50
+ })
51
+
52
+ const emits = defineEmits<{
53
+ (e: "update:modelValue", value: string | number | null): void
54
+ }>()
55
+
56
+ const slots = useSlots()
57
+
58
+ // 常量
59
+ const REGEX = {
60
+ INTEGER: /^\d+$/,
61
+ PHONE: /^1[3456789]\d{9}$/,
62
+ ID_CARD: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
63
+ NUMBER: /((^[1-9]\d*)|^0)(\.\d+)?$/,
64
+ NUMBER_DECIMAL: /((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/
65
+ } as const
66
+
67
+ const CHINESE = {
68
+ DIGITS: ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"],
69
+ FRACTIONS: ["角", "分"],
70
+ UNITS: [
71
+ ["元", "万", "亿", "兆"],
72
+ ["", "拾", "佰", "仟"]
73
+ ]
74
+ } as const
75
+
76
+ // 计算属性
77
+ const showTooltip = computed(() => props.isTip && !props.showThousands)
78
+ const showAppend = computed(() => slots.append || props.inputType === "amount")
79
+ const placeholderText = computed(() => props.placeholder || t("plus.input.placeholder"))
80
+ const appendTitleText = computed(() => props.appendTitle || t("plus.input.appendTitle"))
81
+ const inputProps = computed(() => ({
82
+ placeholder: placeholderText.value,
83
+ clearable: true,
84
+ ...attrs
85
+ }))
86
+
87
+ // 获取当前输入类型的正则表达式
88
+ const getInputRegex = (): RegExp | null => {
89
+ if (props.inputType instanceof RegExp) {
90
+ return props.inputType
91
+ }
92
+ switch (props.inputType) {
93
+ case "integer":
94
+ return REGEX.INTEGER
95
+ case "phone":
96
+ return REGEX.PHONE
97
+ case "idCard":
98
+ return REGEX.ID_CARD
99
+ default:
100
+ return null
101
+ }
102
+ }
103
+
104
+ const internalValue = computed({
105
+ get() {
106
+ if (props.inputType === "integer" && props.modelValue != null) {
107
+ return typeof props.modelValue === "number" ? String(props.modelValue) : props.modelValue
108
+ }
109
+ return props.modelValue ?? ""
110
+ },
111
+ set(val: string | number | null) {
112
+ if (props.inputType === "integer") {
113
+ if (!val || val === "") {
114
+ emits("update:modelValue", null)
115
+ } else {
116
+ const str = String(val)
117
+ const regex = getInputRegex()
118
+ emits("update:modelValue", regex?.test(str) ? Number(str) : str)
119
+ }
120
+ } else {
121
+ emits("update:modelValue", val ?? "")
122
+ }
123
+ }
124
+ })
125
+
126
+ // 通用验证函数
127
+ const validate = (value: string, pattern: RegExp, errorKey?: string): string | null => {
128
+ if (pattern.test(value)) return value
129
+ if (props.isShowErrorTip) {
130
+ const errorMsg =
131
+ props.customErrorTip || (errorKey ? t(errorKey) : t("plus.input.validateError"))
132
+ ElMessage.error(errorMsg)
133
+ }
134
+ return null
135
+ }
136
+
137
+ // 格式化函数
138
+ const formatAmount = (value: number): string => {
139
+ if (!value) {
140
+ if (props.isShowErrorTip) {
141
+ const msg =
142
+ t("plus.input.format") +
143
+ (props.inputType === "amount" ? t("plus.input.amount") : t("plus.input.numbers"))
144
+ ElMessage.error(msg)
145
+ }
146
+ return ""
147
+ }
148
+ const fixed = value.toFixed(props.decimalLimit)
149
+ return props.showThousands ? fixed.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : fixed
150
+ }
151
+
152
+ const currencyFilter = (num: number | string | null, n = 2): string => {
153
+ if (!REGEX.NUMBER.test(String(num)) || (num == null && num !== 0)) return ""
154
+ const n2 = n > 0 && n <= 20 ? n : 2
155
+ const numStr = parseFloat(String(num).replace(/^\d\.-/g, "")).toFixed(n2)
156
+ const [int, dec] = numStr.split(".")
157
+ return `¥ ${int.replace(/\B(?=(\d{3})+(?!\d))/g, ",")}.${dec}`
158
+ }
159
+
160
+ const digitUppercase = (num: number | string | null): string => {
161
+ if (!REGEX.NUMBER_DECIMAL.test(String(num))) return t("plus.input.digitUppercase")
162
+ const isNegative = Number(num) < 0
163
+ const absNum = Math.abs(Number(num))
164
+ let result = ""
165
+
166
+ // 小数部分
167
+ CHINESE.FRACTIONS.forEach((fraction, index) => {
168
+ const digit = Math.floor(absNum * 10 * Math.pow(10, index)) % 10
169
+ result += (CHINESE.DIGITS[digit] + fraction).replace(/零./, "")
170
+ })
171
+ result = result || "整"
172
+
173
+ // 整数部分
174
+ let integerPart = Math.floor(absNum)
175
+ for (let i = 0; i < CHINESE.UNITS[0].length && integerPart > 0; i++) {
176
+ let section = ""
177
+ for (let j = 0; j < CHINESE.UNITS[1].length && integerPart > 0; j++) {
178
+ section = CHINESE.DIGITS[integerPart % 10] + CHINESE.UNITS[1][j] + section
179
+ integerPart = Math.floor(integerPart / 10)
180
+ }
181
+ result = section.replace(/(零.)*零$/, "").replace(/^$/, "零") + CHINESE.UNITS[0][i] + result
182
+ }
183
+
184
+ return (
185
+ (isNegative ? "欠" : "") +
186
+ result
187
+ .replace(/(零.)*零元/, "元")
188
+ .replace(/(零.)+/g, "零")
189
+ .replace(/^整$/, "零元整")
190
+ )
191
+ }
192
+
193
+ // 失焦处理
194
+ const handleBlur = (): void => {
195
+ const val = internalValue.value
196
+ let formatted: string | number | null = val
197
+
198
+ // 处理自定义正则
199
+ if (props.inputType instanceof RegExp) {
200
+ formatted = validate(String(val || ""), props.inputType) ?? ""
201
+ internalValue.value = formatted
202
+ return
203
+ }
204
+
205
+ switch (props.inputType) {
206
+ case "amount":
207
+ case "decimal":
208
+ formatted = formatAmount(Number(val))
209
+ break
210
+ case "phone":
211
+ formatted = validate(String(val || ""), REGEX.PHONE, "plus.input.validatePhone") ?? ""
212
+ break
213
+ case "integer": {
214
+ const result = validate(String(val || ""), REGEX.INTEGER, "plus.input.validateInteger")
215
+ formatted = result ? Number(result) : null
216
+ break
217
+ }
218
+ case "idCard":
219
+ formatted = validate(String(val || ""), REGEX.ID_CARD, "plus.input.validateIdCard") ?? ""
220
+ break
221
+ }
222
+
223
+ internalValue.value = formatted
224
+ }
225
+ </script>
@@ -0,0 +1,14 @@
1
+ import type { InputProps } from "element-plus"
2
+ import type { Mutable } from "element-plus/es/utils"
3
+ export interface FFInputSelfProps {
4
+ modelValue: string | number | null
5
+ placeholder?: string
6
+ decimalLimit?: number
7
+ inputType?: "text" | "amount" | "decimal" | "phone" | "integer" | "idCard" | RegExp
8
+ appendTitle?: string
9
+ showThousands?: boolean
10
+ isTip?: boolean
11
+ isShowErrorTip?: boolean
12
+ customErrorTip?: string
13
+ }
14
+ export type FFInputProps = FFInputSelfProps & Partial<Mutable<InputProps>>
@@ -0,0 +1 @@
1
+ import "@ff-ui-plus/theme-chalk/t-input.css"
@@ -0,0 +1 @@
1
+ import "@ff-ui-plus/theme-chalk/src/input.scss"
@@ -0,0 +1,4 @@
1
+ import LayoutPage from "./src/index.vue"
2
+ export type { TLayoutPageProps } from "./src/index.vue"
3
+
4
+ export const TLayoutPage = LayoutPage
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <div
3
+ ref="TLayoutPageRef"
4
+ class="t_layout_page"
5
+ :class="{ layout_page_no_margin: isNoMargin }"
6
+ @scroll="(e:any) => scrollTop = e.target.scrollTop"
7
+ >
8
+ <slot />
9
+ <div class="back_to_top" v-if="showGoTopButton">
10
+ <div v-if="isShowGoTopButton" @click="backToTop">
11
+ <el-icon v-bind="{ size: 24, ...$attrs }"><CaretTop /></el-icon>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </template>
16
+ <script setup lang="ts">
17
+ import { onActivated, onMounted, ref, watch } from "vue"
18
+ import { CaretTop } from "@element-plus/icons-vue"
19
+ defineOptions({
20
+ name: "TLayoutPage"
21
+ })
22
+ export interface TLayoutPageProps {
23
+ keepScrollDisabled?: boolean
24
+ isNoMargin?: boolean
25
+ showGoTopButton?: boolean
26
+ scrollToTop?: number
27
+ }
28
+
29
+ const props = withDefaults(defineProps<TLayoutPageProps>(), {
30
+ keepScrollDisabled: false,
31
+ isNoMargin: false,
32
+ showGoTopButton: true,
33
+ scrollToTop: 100
34
+ })
35
+ const isShowGoTopButton = ref(false)
36
+
37
+ const TLayoutPageRef = ref(null)
38
+ const scrollTop = ref(0)
39
+ watch(
40
+ () => scrollTop.value,
41
+ newVal => {
42
+ if (newVal > props.scrollToTop) {
43
+ isShowGoTopButton.value = true
44
+ } else {
45
+ isShowGoTopButton.value = false
46
+ }
47
+ }
48
+ )
49
+ const backToTop = () => {
50
+ scrollTop.value = 0
51
+ ;(TLayoutPageRef.value as any).scrollTo({
52
+ top: 0,
53
+ behavior: "smooth"
54
+ })
55
+ }
56
+ onMounted(() => {
57
+ const pageItems = (TLayoutPageRef.value as any).querySelectorAll(".t_layout_page_item")
58
+ if (pageItems.length === 2) {
59
+ pageItems[0].style.marginBottom = "8px"
60
+ }
61
+ if (pageItems.length > 2) {
62
+ pageItems.forEach((item: any) => {
63
+ item.style.marginBottom = "8px"
64
+ })
65
+ pageItems[pageItems.length - 1].style.marginBottom = "0"
66
+ }
67
+ })
68
+
69
+ onActivated(() => {
70
+ if (!props.keepScrollDisabled) {
71
+ ;(TLayoutPageRef.value as any).scrollTop = scrollTop
72
+ }
73
+ })
74
+ </script>
@@ -0,0 +1 @@
1
+ import "@ff-ui-plus/theme-chalk/t-layout-page.css"
@@ -0,0 +1 @@
1
+ import "@ff-ui-plus/theme-chalk/src/layout-page.scss"
@@ -0,0 +1,3 @@
1
+ import LayoutPageItem from "./src/index.vue"
2
+
3
+ export const TLayoutPageItem = LayoutPageItem
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <section class="t_layout_page_item" :class="{ page_item_no_margin: isNoMargin }">
3
+ <slot />
4
+ </section>
5
+ </template>
6
+ <script setup lang="ts" name="TLayoutPageItem">
7
+ defineOptions({
8
+ name: "TLayoutPageItem"
9
+ })
10
+ defineProps({
11
+ isNoMargin: {
12
+ type: Boolean,
13
+ default: false
14
+ }
15
+ })
16
+ </script>
@@ -0,0 +1 @@
1
+ import "@ff-ui-plus/theme-chalk/t-layout-page-item.css"
@@ -0,0 +1 @@
1
+ import "@ff-ui-plus/theme-chalk/src/layout-page-item.scss"
@@ -0,0 +1,4 @@
1
+ import ModuleForm from "./src/index.vue"
2
+ export * from "./src/type"
3
+
4
+ export const TModuleForm = ModuleForm
@@ -0,0 +1,243 @@
1
+ <template>
2
+ <div class="t_module_form" :style="{ marginBottom: footer !== null ? '60px' : '' }">
3
+ <div class="scroll_wrap">
4
+ <!-- 头部 -->
5
+ <el-page-header
6
+ v-if="!isShowHeader && (title || titleSlot)"
7
+ :title="title"
8
+ :class="{
9
+ noContent: !subTitle,
10
+ isShowBack: isShowBack
11
+ }"
12
+ @back="back"
13
+ >
14
+ <template v-if="titleSlot" #title>
15
+ <slot name="title" />
16
+ </template>
17
+ <template #content>
18
+ <div class="sub_title">{{ subTitle }}</div>
19
+ <div class="extra">
20
+ <slot name="extra" />
21
+ </div>
22
+ </template>
23
+ </el-page-header>
24
+ <!-- 表单页面 -->
25
+ <module-form v-if="handleType === 'edit'" v-bind="$attrs" ref="tForm">
26
+ <template v-for="(_index, name) in slots" #[name]="data">
27
+ <slot :name="name" v-bind="data" />
28
+ </template>
29
+ </module-form>
30
+ <!-- 详情页面 -->
31
+ <module-detail v-else v-bind="$attrs">
32
+ <template v-for="(_index, name) in slots" #[name]="data">
33
+ <slot :name="name" v-bind="data" />
34
+ </template>
35
+ </module-detail>
36
+ <!-- tabs -->
37
+ <div
38
+ v-if="tabs.length"
39
+ class="tabs"
40
+ :style="{ 'margin-top': isTabMargin ? `${tabMarginNum}px` : 0 }"
41
+ >
42
+ <el-tabs v-if="tabs && tabs.length > 1" v-model="activeName" @tab-change="tabsChange">
43
+ <el-tab-pane v-for="tab in tabs" :key="tab.key" :name="tab.key" :label="tab.title">
44
+ <slot :name="tab.key" />
45
+ </el-tab-pane>
46
+ </el-tabs>
47
+ <slot v-else :name="tabs && tabs[0].key" />
48
+ </div>
49
+ <slot name="default" />
50
+ </div>
51
+ <!-- 按钮 -->
52
+ <footer v-if="footer !== null" class="handle_wrap">
53
+ <slot name="footer" />
54
+ <div v-if="!slots.footer">
55
+ <el-button v-bind="cancelAttrs" @click="back">{{ cancelAttrs.btnTxt }}</el-button>
56
+ <el-button
57
+ v-if="handleType === 'edit'"
58
+ v-bind="saveAttrs"
59
+ :loading="loading"
60
+ @click="saveHandle"
61
+ >{{ saveAttrs.btnTxt }}</el-button
62
+ >
63
+ </div>
64
+ </footer>
65
+ </div>
66
+ </template>
67
+
68
+ <script setup lang="ts">
69
+ import { ref, useAttrs, useSlots, computed } from "vue"
70
+ import ModuleDetail from "@ff-ui-plus/components/module-form/src/moduleDetail.vue"
71
+ import ModuleForm from "@ff-ui-plus/components/module-form/src/moduleForm.vue"
72
+ import { useLocale } from "@ff-ui-plus/hooks"
73
+ import type { TModuleFormProps } from "./type"
74
+ defineOptions({
75
+ name: "TModuleForm"
76
+ })
77
+
78
+ const props = withDefaults(defineProps<TModuleFormProps>(), {
79
+ handleType: "edit",
80
+ isShowHeader: false,
81
+ titleSlot: false,
82
+ isShowBack: false,
83
+ isGoBackEvent: false,
84
+ btnSaveBind: () => ({}),
85
+ btnCancelBind: () => ({}),
86
+ isTabMargin: false,
87
+ tabMarginNum: 10,
88
+ title: "",
89
+ subTitle: "",
90
+ tabs: () => [],
91
+ submit: async () => false
92
+ })
93
+ const { t } = useLocale()
94
+ const attrs = useAttrs() as Record<string, any>
95
+ const slots = useSlots()
96
+ const activeName = ref(props.tabs && props.tabs[0]?.key)
97
+ const loading = ref(false)
98
+ // 保存按钮配置
99
+ const saveAttrs = computed(() => {
100
+ return {
101
+ type: "primary" as
102
+ | "primary"
103
+ | "default"
104
+ | "success"
105
+ | "warning"
106
+ | "danger"
107
+ | "info"
108
+ | "text"
109
+ | "",
110
+ btnTxt: t("plus.moduleForm.save"),
111
+ ...props.btnSaveBind
112
+ }
113
+ })
114
+ // 取消按钮配置
115
+ const cancelAttrs = computed(() => {
116
+ return { btnTxt: t("plus.moduleForm.back"), ...props.btnCancelBind }
117
+ })
118
+ // 获取ref
119
+ const tForm: any = ref<HTMLElement | null>(null)
120
+
121
+ // 抛出事件
122
+ const emits = defineEmits(["validateError", "back", "tabsChange"])
123
+ // 点击保存
124
+ const saveHandle = async () => {
125
+ return new Promise(async (resolve: any, reject: any) => {
126
+ const form: Record<string, any> = {}
127
+ const formError: Record<string, any> = {}
128
+ const formOpts: Record<string, any> = {}
129
+ let successLength = 0
130
+ loading.value = true
131
+ try {
132
+ // 过滤非插槽表单
133
+ Object.keys(attrs.formOpts).forEach(key => {
134
+ if (attrs.formOpts[key].opts) {
135
+ formOpts[key] = attrs.formOpts[key]
136
+ }
137
+ })
138
+ // 校验表单
139
+ for (const formIndex of Object.keys(formOpts)) {
140
+ const { valid } = await tForm.value.getChildRef(formIndex).selfValidate()
141
+ if (valid) {
142
+ successLength = successLength + 1
143
+ form[formIndex] = attrs.formOpts[formIndex].opts.formData
144
+ }
145
+ }
146
+ if (successLength === Object.keys(formOpts).length) {
147
+ // 所有表单都校验成功
148
+ const isSuccess = await props.submit(form)
149
+ resolve({ valid: true, formData: form }) // 返回表单数据
150
+ if (isSuccess) {
151
+ // 成功
152
+ back()
153
+ }
154
+ } else {
155
+ // 校验失败抛出事件
156
+ Object.keys(formOpts).forEach(key => {
157
+ if (Object.keys(form).length > 0) {
158
+ Object.keys(form).map(val => {
159
+ if (key !== val) {
160
+ formError[key] = formOpts[key]
161
+ }
162
+ })
163
+ } else {
164
+ formError[key] = formOpts[key]
165
+ }
166
+ })
167
+ reject({ valid: false, error: formError }) // 返回校验失败信息
168
+ emits("validateError", formError)
169
+ }
170
+ } catch (error) {
171
+ // 捕获异常并抛出校验失败事件
172
+ emits("validateError", { error })
173
+ reject({ valid: false, error })
174
+ } finally {
175
+ loading.value = false
176
+ }
177
+ })
178
+ }
179
+ // 点击头部返回或者取消
180
+ const back = () => {
181
+ if (props.isShowBack) {
182
+ return
183
+ }
184
+ emits("back")
185
+ if (!props.isGoBackEvent) {
186
+ history.go(-1)
187
+ }
188
+ }
189
+ // 获取默认选中tab
190
+ const setSelectedTab = (key: any) => {
191
+ activeName.value = key
192
+ }
193
+ // 切换tab
194
+ const tabsChange = (tab: any) => {
195
+ emits("tabsChange", tab)
196
+ }
197
+ // 清空表单
198
+ const resetFormFields = () => {
199
+ const formOpts: Record<string, any> = {}
200
+ // 过滤非插槽表单
201
+ Object.keys(attrs.formOpts).forEach(key => {
202
+ if (attrs.formOpts[key].opts) {
203
+ formOpts[key] = attrs.formOpts[key]
204
+ }
205
+ })
206
+ Object.keys(formOpts).forEach(formIndex => {
207
+ tForm.value.getChildRef(formIndex).resetFields()
208
+ })
209
+ }
210
+ // 清空校验规则
211
+ const clearValidate = () => {
212
+ const formOpts: Record<string, any> = {}
213
+ // 过滤非插槽表单
214
+ Object.keys(attrs.formOpts).forEach(key => {
215
+ if (attrs.formOpts[key].opts) {
216
+ formOpts[key] = attrs.formOpts[key]
217
+ }
218
+ })
219
+ Object.keys(formOpts).forEach(formIndex => {
220
+ tForm.value.getChildRef(formIndex).clearValidate()
221
+ })
222
+ }
223
+ const updateFormFields = () => {
224
+ const formOpts: Record<string, any> = {}
225
+ // 过滤非插槽表单
226
+ Object.keys(attrs.formOpts).forEach(key => {
227
+ if (attrs.formOpts[key].opts) {
228
+ formOpts[key] = attrs.formOpts[key]
229
+ }
230
+ })
231
+ Object.keys(formOpts).forEach(formIndex => {
232
+ tForm.value.getChildRef(formIndex).updateFields(false)
233
+ })
234
+ }
235
+ // 暴露方法出去
236
+ defineExpose({
237
+ clearValidate,
238
+ resetFormFields,
239
+ updateFormFields,
240
+ setSelectedTab,
241
+ saveHandle
242
+ })
243
+ </script>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <div class="t_detail">
3
+ <el-collapse v-model="defaultActiveKey">
4
+ <el-collapse-item
5
+ v-for="(val, index) in descData"
6
+ :class="{
7
+ noTitle: !val.title,
8
+ disabledStyle: val.disabled,
9
+ title_bold: titleBold
10
+ }"
11
+ :key="index"
12
+ :name="val.name"
13
+ :disabled="val.disabled"
14
+ >
15
+ <template #title>
16
+ {{ val.title }}
17
+ <div class="t_btn" v-if="val.btn">
18
+ <slot :name="val.btn"></slot>
19
+ </div>
20
+ </template>
21
+ <template v-if="val.slotName">
22
+ <slot :name="val.slotName"></slot>
23
+ </template>
24
+ <t-detail :descData="val.data" v-bind="attrs">
25
+ <template v-for="(_index, name) in slots" v-slot:[name]="data">
26
+ <slot :name="name" v-bind="data"></slot>
27
+ </template>
28
+ </t-detail>
29
+ </el-collapse-item>
30
+ </el-collapse>
31
+ </div>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ import { computed, useAttrs, useSlots } from "vue"
36
+ defineOptions({
37
+ name: "ModuleDetail"
38
+ })
39
+ const props: any = defineProps({
40
+ descData: {
41
+ type: Object,
42
+ default: () => ({})
43
+ },
44
+ // 是否Title文字加粗
45
+ titleBold: {
46
+ type: Boolean,
47
+ default: false
48
+ }
49
+ })
50
+ const slots = useSlots()
51
+ const attrs: any = useAttrs()
52
+ const defaultActiveKey = computed({
53
+ get() {
54
+ // console.log(333, Object.keys(props.descData))
55
+ return Object.keys(props.descData)
56
+ },
57
+ set(val) {
58
+ return val
59
+ }
60
+ })
61
+ </script>