register.model.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import { toCamelCase } from '@/tools';
  2. import type { FieldRule, NumberKeyboardProps, PasswordInputProps } from 'vant';
  3. export type Option = { label: string; value: string; checked?: boolean; disabled?: boolean; editable?: boolean; single?: boolean; }
  4. export type Dictionaries = Map<string, Option[]>;
  5. export interface RegisterModel {
  6. cardno: string;
  7. phone: string;
  8. code: string;
  9. name: string;
  10. sex: string;
  11. age: number;
  12. height: number;
  13. weight: number;
  14. isEasyAllergy: boolean;
  15. womenSpecialPeriod: string;
  16. job: string;
  17. }
  18. export interface Field {
  19. control: {
  20. label: string; placeholder?: string;
  21. type?: string; min?: number; max?: number; minlength?: number; maxlength?: number;
  22. clearable?: boolean; border?: boolean; readonly?: boolean;
  23. hide?: boolean | ((model: Record<string, any>) => boolean);
  24. };
  25. component?:
  26. | { name: 'picker', options: Option[] , props?: Partial<{ multiple: boolean; }> }
  27. | { name: 'radio', options: Option[] }
  28. | { name: 'code', props?: Partial<PasswordInputProps> }
  29. ;
  30. keyboard?: { show: boolean; } & Partial<NumberKeyboardProps>;
  31. suffix?: string;
  32. rules: FieldRule[];
  33. }
  34. export type FieldKey = keyof RegisterModel;
  35. export type Fields = ( Field & { name: FieldKey } )[];
  36. const Fields: Record<FieldKey, Field> = {
  37. height: {
  38. control: {
  39. label: '身高', placeholder: '请输入身高',
  40. type: 'number', min: 1, max: 300, clearable: true, readonly: true,
  41. maxlength: 5,
  42. },
  43. keyboard: { show: false, title: '身高', extraKey: '.', closeButtonText: '完成' },
  44. suffix: 'cm',
  45. rules: [],
  46. },
  47. weight: {
  48. control: {
  49. label: '体重', placeholder: '请输入体重',
  50. type: 'number', min: 1, max: 300, clearable: true, readonly: true,
  51. maxlength: 5,
  52. },
  53. keyboard: { show: false, title: '体重', extraKey: '.', closeButtonText: '完成' },
  54. suffix: 'kg',
  55. rules: [],
  56. },
  57. age: {
  58. control: {
  59. label: '年龄', placeholder: '请输入年龄',
  60. type: 'digit', min: 0, max: 300, clearable: true, readonly: true,
  61. maxlength: 3,
  62. },
  63. keyboard: { show: false, title: '年龄', closeButtonText: '完成' },
  64. suffix: '岁',
  65. rules: [],
  66. },
  67. sex: {
  68. control: { label: '性别', border: false },
  69. component: {
  70. name: 'radio' as const,
  71. options: 'sys_user_sex' as unknown as any,
  72. },
  73. rules: [],
  74. },
  75. womenSpecialPeriod: {
  76. control: {
  77. label: '女性特殊期', readonly: true,
  78. hide(model) { return model?.sex !== '1'; },
  79. },
  80. component: {
  81. name: 'picker' as const,
  82. options: 'women_special_period' as unknown as any,
  83. props: { multiple: false },
  84. },
  85. rules: [],
  86. },
  87. job: {
  88. control: { label: '职业', readonly: true },
  89. component: {
  90. name: 'picker' as const,
  91. options: 'job' as unknown as any,
  92. props: { multiple: false },
  93. },
  94. rules: [],
  95. },
  96. isEasyAllergy: {
  97. control: { label: '容易过敏', border: false },
  98. component: {
  99. name: 'radio' as const,
  100. options: 'sys_yes_no' as unknown as any,
  101. },
  102. rules: [],
  103. },
  104. name: {
  105. control: {
  106. label: '姓名', placeholder: '请输入姓名',
  107. type: 'text', maxlength: 10, clearable: true,
  108. },
  109. rules: [],
  110. },
  111. cardno: {
  112. control: {
  113. label: '身份证号', placeholder: '请输入身份证号',
  114. type: 'text', maxlength: 18, minlength: 18, clearable: true, readonly: true,
  115. },
  116. keyboard: { show: false, title: '身份证号', extraKey: 'X', closeButtonText: '完成' },
  117. rules: [
  118. {
  119. validator: (value: string) => value && value.length === 18,
  120. message: '请输入正确的身份证',
  121. trigger: 'onBlur',
  122. },
  123. ],
  124. },
  125. phone: {
  126. control: {
  127. label: '手机号码', placeholder: '请输入手机号码',
  128. type: 'tel', maxlength: 11, minlength: 11, clearable: true, readonly: true,
  129. },
  130. keyboard: { show: false, title: '手机号码', closeButtonText: '完成' },
  131. rules: [
  132. {
  133. validator: (value: string) => value && value.length === 11,
  134. message: '请输入正确的手机号码',
  135. trigger: 'onBlur',
  136. },
  137. ],
  138. },
  139. code: {
  140. control: {
  141. label: '验证码', placeholder: '请输入验证码',
  142. type: 'digit', maxlength: 6, minlength: 6, clearable: true,
  143. border: false,
  144. },
  145. component: {
  146. name: 'code' as const,
  147. props: { mask: false },
  148. },
  149. keyboard: { show: false, title: '验证码', closeButtonText: '完成' },
  150. rules: [
  151. {
  152. validator: (value: string) => value && value.length === 6,
  153. message: '请输入验证码',
  154. trigger: [ 'onChange', 'onBlur' ],
  155. },
  156. ],
  157. },
  158. };
  159. export function fromRegisterFields(options: string[], dictionaries?: Dictionaries): Fields {
  160. dictionaries ??= new Map([
  161. ['sys_yes_no', [{ label: '是', value: 'Y' }, { label: '否', value: 'N' }]],
  162. ['sys_user_sex', [{ label: '男', value: '0' }, { label: '女', value: '1' }]]
  163. ]);
  164. const getOptions = (options?: Option[] | string): Option[] => {
  165. if (options == null) options = [];
  166. if (typeof options === 'string') options = dictionaries?.get(options) ?? [];
  167. return options.map((option) => Object.assign({
  168. editable: option.label === `其他`,
  169. single: option.label === `无`,
  170. } ,option));
  171. };
  172. // 修正 phone,code
  173. const k1 = 'phone';
  174. const k2 = 'code';
  175. const index = options.findIndex(key => key.startsWith(k1));
  176. if ( index !== -1 && !options.find(key => key.startsWith(k2)) ) {
  177. const value = options[ index ].replace(k1, k2);
  178. options.splice(index + 1, 0, value);
  179. }
  180. return options.map(option => {
  181. const values = option.split(':');
  182. const name = toCamelCase(values[ 0 ]);
  183. const field = Fields[ name as unknown as FieldKey ] ?? {
  184. control: { label: name, type: 'text' },
  185. rules: [],
  186. };
  187. if ((field.component as any)?.options) (field.component as any) = { ...field.component, options: getOptions((field.component as any).options) }
  188. if ( values[ 1 ] === 'required' ) field.rules.push({ required: true, message: field.control.placeholder ?? '请补充完整' });
  189. return { ...field, name } as Fields[number];
  190. });
  191. }