|
@@ -3,7 +3,7 @@ import NavHomeSelect from '@/assets/images/nav-home.select.png?url';
|
|
|
import { Toast } from '@/platform';
|
|
import { Toast } from '@/platform';
|
|
|
|
|
|
|
|
import { getCaptchaMethod, registerAccountMethod, registerFieldsMethod, dictionariesMethod, searchAccountMethod } from '@/request/api';
|
|
import { getCaptchaMethod, registerAccountMethod, registerFieldsMethod, dictionariesMethod, searchAccountMethod } from '@/request/api';
|
|
|
-import type { CascaderOption, Fields, Option, RegisterModel } from '@/request/model';
|
|
|
|
|
|
|
+import type { Field, Fields, Option, RegisterModel } from '@/request/model';
|
|
|
import { useRouteQuery } from '@vueuse/router';
|
|
import { useRouteQuery } from '@vueuse/router';
|
|
|
import { useCaptcha, useRequest, useSerialRequest } from 'alova/client';
|
|
import { useCaptcha, useRequest, useSerialRequest } from 'alova/client';
|
|
|
|
|
|
|
@@ -11,23 +11,26 @@ import type { FormInstance } from 'vant';
|
|
|
import { RadioGroup as vanRadioGroup } from 'vant';
|
|
import { RadioGroup as vanRadioGroup } from 'vant';
|
|
|
import PickerDialog from '@/components/PickerDialog.vue';
|
|
import PickerDialog from '@/components/PickerDialog.vue';
|
|
|
import CascaderDialog from '@/components/CascaderDialog.vue';
|
|
import CascaderDialog from '@/components/CascaderDialog.vue';
|
|
|
-import { useFlowStore } from '@/stores';
|
|
|
|
|
|
|
+import { useFlowStore, useVisitor } from '@/stores';
|
|
|
|
|
|
|
|
const formRef = useTemplateRef<FormInstance>('register-form');
|
|
const formRef = useTemplateRef<FormInstance>('register-form');
|
|
|
-const modelRef = ref<Partial<RegisterModel>>({ code: '' });
|
|
|
|
|
-const modelValueRef = ref<Partial<RegisterModel>>({});
|
|
|
|
|
-const model = computed(() => ({ ...modelRef.value, ...modelValueRef.value }));
|
|
|
|
|
|
|
+const modelLabel = ref<Partial<RegisterModel>>({ });
|
|
|
|
|
+const modelValue = ref<Partial<RegisterModel>>({ code: '' });
|
|
|
|
|
+const model = computed(() => ({ ...modelLabel.value, ...modelValue.value }));
|
|
|
|
|
|
|
|
const { data: fields, loading } = useSerialRequest([dictionariesMethod, (dictionaries) => registerFieldsMethod(dictionaries)]).onSuccess(({ data }) => {
|
|
const { data: fields, loading } = useSerialRequest([dictionariesMethod, (dictionaries) => registerFieldsMethod(dictionaries)]).onSuccess(({ data }) => {
|
|
|
const sex = data.find((field) => field.name === 'sex');
|
|
const sex = data.find((field) => field.name === 'sex');
|
|
|
if (sex) {
|
|
if (sex) {
|
|
|
const unknown = (<any>sex).component?.options?.find((option: any) => option.value === '2');
|
|
const unknown = (<any>sex).component?.options?.find((option: any) => option.value === '2');
|
|
|
- modelRef.value.sex = unknown?.value;
|
|
|
|
|
|
|
+ modelLabel.value.sex = unknown?.label;
|
|
|
|
|
+ modelValue.value.sex = unknown?.value;
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const flow = useFlowStore();
|
|
const flow = useFlowStore();
|
|
|
|
|
+const visitor = useVisitor();
|
|
|
const { loading: submitting, send: submit } = useRequest(registerAccountMethod, { immediate: false }).onSuccess(({ data }) => {
|
|
const { loading: submitting, send: submit } = useRequest(registerAccountMethod, { immediate: false }).onSuccess(({ data }) => {
|
|
|
|
|
+ visitor.updatePatient(modelLabel.value, data);
|
|
|
flow.router.push();
|
|
flow.router.push();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -35,36 +38,13 @@ const forbiddenFields = shallowRef<Record<string, boolean>>({});
|
|
|
const { loading: searching, send: search } = useRequest((data) => searchAccountMethod(data), {
|
|
const { loading: searching, send: search } = useRequest((data) => searchAccountMethod(data), {
|
|
|
immediate: false,
|
|
immediate: false,
|
|
|
}).onSuccess(({ data }) => {
|
|
}).onSuccess(({ data }) => {
|
|
|
- if (!fields.value.some(field => field.name === 'phone')) Reflect.deleteProperty(data, 'phone');
|
|
|
|
|
- const modelLabel = {} as Record<string, any>;
|
|
|
|
|
- const modelValue = {} as Record<string, any>;
|
|
|
|
|
- const forbidden = {} as Record<string, boolean>;
|
|
|
|
|
-
|
|
|
|
|
- for (const [key, value] of Object.entries(data)) {
|
|
|
|
|
- const field = fields.value?.find((field) => field.name === key);
|
|
|
|
|
- if (field) forbidden[key] = !!value && !['phone', 'cardno'].includes(key);
|
|
|
|
|
- if (typeof value === 'string' && field?.component?.name === 'picker') {
|
|
|
|
|
- const result = value.split(',').map((value) => {
|
|
|
|
|
- const [v, l] = value.split(':');
|
|
|
|
|
- return { value, label: l ?? (field.component as { options: Option[] })?.options?.find((option) => option.value === v)?.label ?? v };
|
|
|
|
|
- });
|
|
|
|
|
- modelValue[key] = result.map((t) => t.value).join(',');
|
|
|
|
|
- modelLabel[key] = result.map((t) => t.label).join(',');
|
|
|
|
|
- } else if (typeof value === 'object' && field?.component?.name === 'cascader') {
|
|
|
|
|
- modelLabel[key] = value.map((option) => option.label).join(' / ');
|
|
|
|
|
- modelValue[key] = value;
|
|
|
|
|
- } else {
|
|
|
|
|
- modelLabel[key] = value;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- forbiddenFields.value = forbidden;
|
|
|
|
|
- modelRef.value = { ...modelRef.value, ...modelLabel };
|
|
|
|
|
- modelValueRef.value = { ...modelValueRef.value, ...modelValue };
|
|
|
|
|
|
|
+ if (!fields.value.some((field) => field.name === 'phone')) Reflect.deleteProperty(data, 'phone');
|
|
|
|
|
+ setValues(data);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
let captchaLoaded = false;
|
|
let captchaLoaded = false;
|
|
|
const { loading: captchaLoading, countdown, send: getCaptcha } = useCaptcha(
|
|
const { loading: captchaLoading, countdown, send: getCaptcha } = useCaptcha(
|
|
|
- () => getCaptchaMethod(modelRef.value.phone!),
|
|
|
|
|
|
|
+ () => getCaptchaMethod(model.value.phone!),
|
|
|
{ initialCountdown: 60 },
|
|
{ initialCountdown: 60 },
|
|
|
).onSuccess(({ data }) => {
|
|
).onSuccess(({ data }) => {
|
|
|
captchaLoaded = true;
|
|
captchaLoaded = true;
|
|
@@ -73,7 +53,7 @@ const { loading: captchaLoading, countdown, send: getCaptcha } = useCaptcha(
|
|
|
const getCaptchaHandle = async () => {
|
|
const getCaptchaHandle = async () => {
|
|
|
try {
|
|
try {
|
|
|
await formRef.value?.validate('phone');
|
|
await formRef.value?.validate('phone');
|
|
|
- if ( !modelRef.value.phone ) throw { message: `请输入手机号码` };
|
|
|
|
|
|
|
+ if ( !model.value.phone ) throw { message: `请输入手机号码` };
|
|
|
await getCaptcha();
|
|
await getCaptcha();
|
|
|
const field = fields.value.find(field => field.name === 'code');
|
|
const field = fields.value.find(field => field.name === 'code');
|
|
|
if ( field?.keyboard ) { field.keyboard.show = true; }
|
|
if ( field?.keyboard ) { field.keyboard.show = true; }
|
|
@@ -87,7 +67,7 @@ const searchHandle = async (key: 'cardno' | 'code') => {
|
|
|
try {
|
|
try {
|
|
|
await formRef.value?.validate(key);
|
|
await formRef.value?.validate(key);
|
|
|
forbiddenFields.value = {};
|
|
forbiddenFields.value = {};
|
|
|
- const { cardno, phone, code } = modelRef.value;
|
|
|
|
|
|
|
+ const { cardno, phone, code } = model.value;
|
|
|
await search({ cardno, phone, code })
|
|
await search({ cardno, phone, code })
|
|
|
.then((data) => {
|
|
.then((data) => {
|
|
|
forbiddenFields.value[forbidden] = !!(data as any)[forbidden];
|
|
forbiddenFields.value[forbidden] = !!(data as any)[forbidden];
|
|
@@ -101,8 +81,8 @@ const searchHandle = async (key: 'cardno' | 'code') => {
|
|
|
|
|
|
|
|
function onKeyboardBlur(field: Fields[number]) {
|
|
function onKeyboardBlur(field: Fields[number]) {
|
|
|
if ( field?.name === 'phone' && !captchaLoaded ) { getCaptchaHandle(); }
|
|
if ( field?.name === 'phone' && !captchaLoaded ) { getCaptchaHandle(); }
|
|
|
- if ( field?.name === 'cardno' && modelRef.value.cardno ) { searchHandle('cardno'); }
|
|
|
|
|
- if ( field?.name === 'code' && modelRef.value.phone ) { searchHandle('code'); }
|
|
|
|
|
|
|
+ if ( field?.name === 'cardno' && model.value.cardno ) { searchHandle('cardno'); }
|
|
|
|
|
+ if ( field?.name === 'code' && model.value.phone ) { searchHandle('code'); }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function onSubmitHandle() {
|
|
function onSubmitHandle() {
|
|
@@ -120,7 +100,7 @@ watch(scan, key => {
|
|
|
if ( key ) {
|
|
if ( key ) {
|
|
|
try {
|
|
try {
|
|
|
const { model } = JSON.parse(sessionStorage.getItem(`scan_${ key }`) ?? '');
|
|
const { model } = JSON.parse(sessionStorage.getItem(`scan_${ key }`) ?? '');
|
|
|
- modelRef.value = { ...modelRef.value, ...model };
|
|
|
|
|
|
|
+ setValues(model);
|
|
|
} catch ( e: any ) {}
|
|
} catch ( e: any ) {}
|
|
|
}
|
|
}
|
|
|
}, { immediate: true });
|
|
}, { immediate: true });
|
|
@@ -137,27 +117,60 @@ const keyboardProps = reactive({
|
|
|
props: {},
|
|
props: {},
|
|
|
show: false,
|
|
show: false,
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
const pickerProps = reactive({
|
|
const pickerProps = reactive({
|
|
|
key: '',
|
|
key: '',
|
|
|
props: { options: [], selected: [] },
|
|
props: { options: [], selected: [] },
|
|
|
show: false,
|
|
show: false,
|
|
|
- handle(options: Option[]) {
|
|
|
|
|
- const key = (this ?? pickerProps).key;
|
|
|
|
|
- (modelRef.value as Record<string, any>)[key] = options.map(option => option.label).join(',');
|
|
|
|
|
- (modelValueRef.value as Record<string, any>)[key] = options.map(option => option.value).join(',');
|
|
|
|
|
- }
|
|
|
|
|
});
|
|
});
|
|
|
const cascaderProps = reactive({
|
|
const cascaderProps = reactive({
|
|
|
key: '',
|
|
key: '',
|
|
|
- props: { options: [], loading: false, },
|
|
|
|
|
|
|
+ props: { options: [], loading: false },
|
|
|
show: false,
|
|
show: false,
|
|
|
- handle(options: CascaderOption[]) {
|
|
|
|
|
- const key = (this ?? cascaderProps).key;
|
|
|
|
|
- (modelRef.value as Record<string, any>)[key] = options.map((option) => option.label).join(' / ');
|
|
|
|
|
- (modelValueRef.value as Record<string, any>)[key] = options;
|
|
|
|
|
- },
|
|
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+const handle = (value: any, field: Field | string) => {
|
|
|
|
|
+ field = ((key: Field | string): Field => (typeof key === 'string' ? fields.value.find((field) => field.name === key)! : key))(field);
|
|
|
|
|
+ const key = field.name!;
|
|
|
|
|
+ if (field.component?.name === 'radio') {
|
|
|
|
|
+ const option = field?.component?.options?.find((option) => option.value === value);
|
|
|
|
|
+ (modelLabel.value as any)[key] = option?.label;
|
|
|
|
|
+ (modelValue.value as any)[key] = option?.value;
|
|
|
|
|
+ } else if (field.component?.name === 'picker') {
|
|
|
|
|
+ if (typeof value === 'string') {
|
|
|
|
|
+ value = value.split(',').map((value) => {
|
|
|
|
|
+ const [v, l] = value.split(':');
|
|
|
|
|
+ return { value, label: l ?? (field.component as any).options?.find((option: Option) => option.value === v)?.label ?? v };
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ (modelLabel.value as any)[key] = value.map((option: Option) => option.label).join(',');
|
|
|
|
|
+ (modelValue.value as any)[key] = value.map((option: Option) => option.value).join(',');
|
|
|
|
|
+ } else if (field.component?.name === 'cascader') {
|
|
|
|
|
+ (modelLabel.value as any)[key] = value.map((option: Option) => option.label).join('/');
|
|
|
|
|
+ (modelValue.value as any)[key] = value;
|
|
|
|
|
+ } else if (field.component?.name === 'code') {
|
|
|
|
|
+ (modelValue.value as any)[key] = value;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ (modelLabel.value as any)[key] = value;
|
|
|
|
|
+ (modelValue.value as any)[key] = value;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+const setValues = (values: Record<string, any>) => {
|
|
|
|
|
+ forbiddenFields.value = {};
|
|
|
|
|
+ if (!values) {
|
|
|
|
|
+ modelLabel.value = {};
|
|
|
|
|
+ modelValue.value = {};
|
|
|
|
|
+ }
|
|
|
|
|
+ for (const [key, value] of Object.entries(values ?? {})) {
|
|
|
|
|
+ const field = fields.value?.find((field) => field.name === key);
|
|
|
|
|
+ if (field) {
|
|
|
|
|
+ forbiddenFields.value[key] = !!value && !['phone', 'cardno'].includes(key);
|
|
|
|
|
+ handle(value, field as any)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ (modelValue as any).value[key] = value;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function onFieldFocus(field: any) {
|
|
function onFieldFocus(field: any) {
|
|
|
if (forbiddenFields.value[field.name]) return;
|
|
if (forbiddenFields.value[field.name]) return;
|
|
|
if (field.keyboard) {
|
|
if (field.keyboard) {
|
|
@@ -178,7 +191,7 @@ function onFieldFocus(field: any) {
|
|
|
...field.component.props,
|
|
...field.component.props,
|
|
|
title: field.control.label,
|
|
title: field.control.label,
|
|
|
options: field.component.options,
|
|
options: field.component.options,
|
|
|
- selected: (modelValueRef.value as Record<string, string>)[field.name]?.split(','),
|
|
|
|
|
|
|
+ selected: (modelValue.value as Record<string, string>)[field.name]?.split(','),
|
|
|
};
|
|
};
|
|
|
} else if (field.component?.name === 'cascader') {
|
|
} else if (field.component?.name === 'cascader') {
|
|
|
cascaderProps.key = field.name;
|
|
cascaderProps.key = field.name;
|
|
@@ -197,7 +210,7 @@ function onFieldFocus(field: any) {
|
|
|
title: field.control.label,
|
|
title: field.control.label,
|
|
|
options: field.component.options,
|
|
options: field.component.options,
|
|
|
loading: false,
|
|
loading: false,
|
|
|
- selected: (modelValueRef.value as Record<string, { value: string }[]>)[field.name]?.map((option) => option.value),
|
|
|
|
|
|
|
+ selected: (modelValue.value as Record<string, { value: string }[]>)[field.name]?.map((option) => option.value),
|
|
|
};
|
|
};
|
|
|
})();
|
|
})();
|
|
|
} else {
|
|
} else {
|
|
@@ -212,6 +225,7 @@ function onFieldFocus(field: any) {
|
|
|
function onFieldBlur(field: any) {
|
|
function onFieldBlur(field: any) {
|
|
|
keyboardProps.show = false;
|
|
keyboardProps.show = false;
|
|
|
pickerProps.show = false;
|
|
pickerProps.show = false;
|
|
|
|
|
+ cascaderProps.show = false;
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
<template>
|
|
<template>
|
|
@@ -230,22 +244,21 @@ function onFieldBlur(field: any) {
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="page-content p-6 overflow-auto">
|
|
<div class="page-content p-6 overflow-auto">
|
|
|
- <van-form class="register-form" ref="register-form" colon required="auto"
|
|
|
|
|
- scroll-to-error scroll-to-error-position="center"
|
|
|
|
|
- @submit="onSubmitHandle()"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <van-form class="register-form" ref="register-form" colon required="auto" scroll-to-error scroll-to-error-position="center" @submit="onSubmitHandle()">
|
|
|
<van-cell-group :border="false">
|
|
<van-cell-group :border="false">
|
|
|
<template v-for="field in fields" :key="field.name">
|
|
<template v-for="field in fields" :key="field.name">
|
|
|
<template v-if="!field.control?.hide || (typeof field.control?.hide === 'function' && !field.control.hide(model))">
|
|
<template v-if="!field.control?.hide || (typeof field.control?.hide === 'function' && !field.control.hide(model))">
|
|
|
- <van-field v-model="modelRef[field.name]" :name="field.name" :id="field.name"
|
|
|
|
|
- :rules="field.rules" v-bind="field.control"
|
|
|
|
|
- :class="{'no-border': field.control?.border === false}"
|
|
|
|
|
- @focus="onFieldFocus(field)" @blur="onFieldBlur(field)"
|
|
|
|
|
- :readonly="field.control?.readonly" @click="onFieldFocus(field)"
|
|
|
|
|
- :disabled="forbiddenFields[field.name]"
|
|
|
|
|
|
|
+ <van-field
|
|
|
|
|
+ :model-value="field.control?.readonly ? modelLabel[field.name] : model[field.name]" @update:model-value="handle($event, field)"
|
|
|
|
|
+ :name="field.name" :id="field.name"
|
|
|
|
|
+ :rules="field.rules" v-bind="field.control"
|
|
|
|
|
+ :class="{'no-border': field.control?.border === false}"
|
|
|
|
|
+ @focus="onFieldFocus(field)" @blur="onFieldBlur(field)"
|
|
|
|
|
+ :readonly="field.control?.readonly" @click="onFieldFocus(field)"
|
|
|
|
|
+ :disabled="forbiddenFields[field.name]"
|
|
|
>
|
|
>
|
|
|
<template #input v-if="field.component?.name === 'radio'">
|
|
<template #input v-if="field.component?.name === 'radio'">
|
|
|
- <van-radio-group v-model="modelRef[field.name]" direction="horizontal" shape="dot" :disabled="forbiddenFields[field.name]">
|
|
|
|
|
|
|
+ <van-radio-group direction="horizontal" shape="dot" :disabled="forbiddenFields[field.name]" v-model="modelValue[field.name]" @change="handle($event, field)">
|
|
|
<van-radio v-for="option in field.component?.options" :key="option.value" :name="option.value">
|
|
<van-radio v-for="option in field.component?.options" :key="option.value" :name="option.value">
|
|
|
{{ option.label }}
|
|
{{ option.label }}
|
|
|
</van-radio>
|
|
</van-radio>
|
|
@@ -254,7 +267,7 @@ function onFieldBlur(field: any) {
|
|
|
<template #input v-else-if="field.component?.name === 'code'">
|
|
<template #input v-else-if="field.component?.name === 'code'">
|
|
|
<van-password-input
|
|
<van-password-input
|
|
|
style="width: 100%;"
|
|
style="width: 100%;"
|
|
|
- v-model:value="modelRef[field.name]" v-bind="(field.component as any)!.props"
|
|
|
|
|
|
|
+ v-model:value="modelValue[field.name]" v-bind="(field.component as any)!.props"
|
|
|
:focused="field.keyboard?.show" @focus="field.keyboard && (field.keyboard.show = true);fix('code')"
|
|
:focused="field.keyboard?.show" @focus="field.keyboard && (field.keyboard.show = true);fix('code')"
|
|
|
/>
|
|
/>
|
|
|
</template>
|
|
</template>
|
|
@@ -279,9 +292,9 @@ function onFieldBlur(field: any) {
|
|
|
<img v-else class="size-full" src="@/assets/images/next-step.svg" alt="提交" @click="formRef?.submit()">
|
|
<img v-else class="size-full" src="@/assets/images/next-step.svg" alt="提交" @click="formRef?.submit()">
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <van-number-keyboard v-bind="keyboardProps.props" :show="keyboardProps.show" v-model="modelRef[keyboardProps.key]"></van-number-keyboard>
|
|
|
|
|
- <PickerDialog v-bind="pickerProps.props" v-model:show="pickerProps.show" @selected="pickerProps.handle($event)"></PickerDialog>
|
|
|
|
|
- <CascaderDialog v-bind="cascaderProps.props" v-model:show="cascaderProps.show" @selected="cascaderProps.handle($event)"></CascaderDialog>
|
|
|
|
|
|
|
+ <van-number-keyboard v-bind="keyboardProps.props" :show="keyboardProps.show" v-model="modelValue[keyboardProps.key]" @update:model-value="handle($event, keyboardProps.key)"></van-number-keyboard>
|
|
|
|
|
+ <PickerDialog v-bind="pickerProps.props" v-model:show="pickerProps.show" @selected="handle($event, pickerProps.key)"></PickerDialog>
|
|
|
|
|
+ <CascaderDialog v-bind="cascaderProps.props" v-model:show="cascaderProps.show" @selected="handle($event, cascaderProps.key)"></CascaderDialog>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|