AgreementPrefillInline.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. <template>
  2. {{ label }}
  3. <Field
  4. :name="name"
  5. :model-value="textValue"
  6. :type="numberMode ? 'number' : 'text'"
  7. :show-label="false"
  8. :show-bottom-border="false"
  9. :placeholder="placeholder"
  10. :max-length="maxLength"
  11. :field-style="mergedFieldStyle"
  12. :input-style="mergedInputStyle"
  13. :input-flex="1"
  14. @update:model-value="onUpdate"
  15. />
  16. {{ suffix }}
  17. </template>
  18. <script setup lang="ts">
  19. import { computed } from 'vue';
  20. import { useTheme, type ViewStyle, type TextStyle } from '@/components/theme/ThemeDefine';
  21. import Field from '@/components/form/Field.vue';
  22. const props = withDefaults(
  23. defineProps<{
  24. /** 绑定值:字符串或与 `number-mode` 搭配的数字 */
  25. modelValue?: string | number | null;
  26. /** 为 true 时对外 `update:modelValue` 发出数字(解析失败为 0) */
  27. numberMode?: boolean;
  28. placeholder?: string;
  29. /** 输入框左侧短说明,如「带徒」 */
  30. label?: string;
  31. /** 输入框右侧固定文案,如「人」「场」 */
  32. suffix?: string;
  33. maxLength?: number;
  34. /** 与 Form 的 `rules` 键一致,用于联表校验 */
  35. name?: string;
  36. /** 主题间距键,默认 sm */
  37. gap?: string;
  38. fieldStyle?: ViewStyle;
  39. inputStyle?: TextStyle;
  40. }>(),
  41. {
  42. modelValue: '',
  43. numberMode: false,
  44. placeholder: '请填写',
  45. label: '',
  46. suffix: '',
  47. maxLength: 20,
  48. gap: 'sm',
  49. fieldStyle: () => ({}),
  50. inputStyle: () => ({}),
  51. name: undefined,
  52. },
  53. );
  54. const emit = defineEmits<{
  55. 'update:modelValue': [value: string | number];
  56. }>();
  57. const themeContext = useTheme();
  58. const mergedFieldStyle = computed<ViewStyle>(() => ({
  59. display: 'inline-block',
  60. paddingVertical: themeContext.resolveThemeSize('AgreementPrefillFieldPaddingV', 6),
  61. paddingHorizontal: themeContext.resolveThemeSize('AgreementPrefillFieldPaddingH', 12),
  62. borderRadius: themeContext.resolveThemeSize('AgreementPrefillFieldRadius', '10rpx'),
  63. backgroundColor: themeContext.resolveThemeColor('AgreementPrefillFieldBg', 'light'),
  64. borderWidth: '1rpx',
  65. borderStyle: 'solid',
  66. borderColor: themeContext.resolveThemeColor('AgreementPrefillFieldBorder', 'border.cell'),
  67. minWidth: themeContext.resolveThemeSize('AgreementPrefillFieldMinWidth', '80rpx'),
  68. maxWidth: themeContext.resolveThemeSize('AgreementPrefillFieldMaxWidth', '100rpx'),
  69. ...props.fieldStyle,
  70. }));
  71. const mergedInputStyle = computed<TextStyle>(() => ({
  72. textAlign: 'center',
  73. fontSize: themeContext.resolveThemeSize('AgreementPrefillInputFontSize', 28),
  74. ...props.inputStyle,
  75. }));
  76. const textValue = computed(() =>
  77. props.modelValue === null || props.modelValue === undefined ? '' : String(props.modelValue),
  78. );
  79. function onUpdate(raw: string) {
  80. if (props.numberMode) {
  81. const n = parseInt(raw.replace(/\D/g, ''), 10);
  82. emit('update:modelValue', Number.isFinite(n) ? n : 0);
  83. } else {
  84. emit('update:modelValue', raw);
  85. }
  86. }
  87. </script>