完善客户信息编辑

This commit is contained in:
xianyi
2025-12-15 10:48:41 +08:00
parent 6ccf5fb2f7
commit 91a12b848e
3 changed files with 184 additions and 15 deletions

View File

@@ -18,6 +18,8 @@ import type {
TongyishuGetResponse, TongyishuGetResponse,
InputTongyishuSignSubmit, InputTongyishuSignSubmit,
TongyishuSignSubmitResponse, TongyishuSignSubmitResponse,
InputCustomerDetailEdit,
CustomerDetailEditResponse,
} from './types'; } from './types';
/** /**
@@ -156,3 +158,15 @@ export const submitTongyishuSign = (
).then(res => res.data); ).then(res => res.data);
}; };
/**
* 客户信息编辑
*/
export const editCustomerDetail = (
data: InputCustomerDetailEdit
): Promise<CustomerDetailEditResponse> => {
return request.post<CustomerDetailEditResponse>(
`${MEDICAL_EXAM_BASE_PATH}/customer-detail-edit`,
data
).then(res => res.data);
};

View File

@@ -336,3 +336,25 @@ export interface OutputTongyishuSignInfo {
*/ */
export type TongyishuSignSubmitResponse = CommonActionResult<OutputTongyishuSignInfo>; export type TongyishuSignSubmitResponse = CommonActionResult<OutputTongyishuSignInfo>;
/**
* 客户信息编辑入参
*/
export interface InputCustomerDetailEdit {
/** 婚姻状况10-未婚 20-已婚) */
marital_status: number;
/** 联系电话 */
phone: string;
}
/**
* 客户信息编辑出参
*/
export interface OutputCustomerDetailEdit {
// 空对象,无属性
}
/**
* 客户信息编辑响应
*/
export type CustomerDetailEditResponse = CommonActionResult<OutputCustomerDetailEdit>;

View File

@@ -8,7 +8,7 @@ import type {
OutputTongyishuFileInfo, OutputTongyishuFileInfo,
PhysicalExamProgressItem, PhysicalExamProgressItem,
} from '../../api'; } from '../../api';
import { getCustomerDetail, getPhysicalExamProgressDetail, signInMedicalExamCenter, getTongyishuPdf, submitTongyishuSign } from '../../api'; import { getCustomerDetail, getPhysicalExamProgressDetail, signInMedicalExamCenter, getTongyishuPdf, submitTongyishuSign, editCustomerDetail } from '../../api';
import type { SignaturePadHandle } from '../ui'; import type { SignaturePadHandle } from '../ui';
import { Button, Input, SignaturePad } from '../ui'; import { Button, Input, SignaturePad } from '../ui';
@@ -788,14 +788,28 @@ const ExamDetailInfo = ({
loading: boolean; loading: boolean;
}) => { }) => {
const basePhone = customerInfo?.phone || (client['mobile' as keyof ExamClient] as string | undefined) || ''; const basePhone = customerInfo?.phone || (client['mobile' as keyof ExamClient] as string | undefined) || '';
const baseMarital = const baseMaritalText =
customerInfo?.patient_marital_status_name || customerInfo?.patient_marital_status_name ||
(client['maritalStatus' as keyof ExamClient] as string | undefined) || (client['maritalStatus' as keyof ExamClient] as string | undefined) ||
'—'; '—';
// 将文本转换为数字10-未婚20-已婚
const getMaritalCodeFromText = (text: string): number => {
if (text.includes('未婚') || text === '未婚') return 10;
if (text.includes('已婚') || text === '已婚') return 20;
return 20; // 默认已婚
};
const baseMaritalCode = baseMaritalText === '—' ? 20 : getMaritalCodeFromText(baseMaritalText);
const [phone, setPhone] = useState(basePhone || '—'); const [phone, setPhone] = useState(basePhone || '—');
const [marital, setMarital] = useState(baseMarital); const [maritalCode, setMaritalCode] = useState(baseMaritalCode);
const [phoneEditing, setPhoneEditing] = useState(false); const [phoneEditing, setPhoneEditing] = useState(false);
const [maritalEditing, setMaritalEditing] = useState(false); const [maritalEditing, setMaritalEditing] = useState(false);
const [editLoading, setEditLoading] = useState(false);
const [editMessage, setEditMessage] = useState<string | null>(null);
const getMaritalText = (code: number): string => {
return code === 10 ? '未婚' : '已婚';
};
const customerChannel = client.customerType === '团客' ? '团体客户' : '散客客户'; const customerChannel = client.customerType === '团客' ? '团体客户' : '散客客户';
const familyDoctor = customerInfo?.family_doctor_name || (client['familyDoctor' as keyof ExamClient] as string | undefined) || '—'; const familyDoctor = customerInfo?.family_doctor_name || (client['familyDoctor' as keyof ExamClient] as string | undefined) || '—';
@@ -807,6 +821,70 @@ const ExamDetailInfo = ({
? addItemInfoList.map((i) => `${i.dept_name ?? ''} ${i.combination_name ?? ''}`.trim()).join('、') ? addItemInfoList.map((i) => `${i.dept_name ?? ''} ${i.combination_name ?? ''}`.trim()).join('、')
: client['addonSummary' as keyof ExamClient] || '—'; : client['addonSummary' as keyof ExamClient] || '—';
const handleSavePhone = async () => {
if (!phone || phone.trim() === '' || phone === '—') {
setEditMessage('请输入联系电话');
return;
}
setEditLoading(true);
setEditMessage(null);
try {
const res = await editCustomerDetail({
marital_status: maritalCode,
phone: phone.trim(),
});
if (res.Status === 200) {
setEditMessage('保存成功');
setPhoneEditing(false);
// 2秒后清除消息
setTimeout(() => setEditMessage(null), 2000);
} else {
setEditMessage(res.Message || '保存失败');
}
} catch (err) {
console.error('保存客户信息失败', err);
setEditMessage('保存失败,请稍后重试');
} finally {
setEditLoading(false);
}
};
const handleSaveMarital = async () => {
const phoneValue = phone === '—' ? '' : phone.trim();
if (!phoneValue) {
setEditMessage('联系电话不能为空');
return;
}
setEditLoading(true);
setEditMessage(null);
try {
const res = await editCustomerDetail({
marital_status: maritalCode,
phone: phoneValue,
});
if (res.Status === 200) {
setEditMessage('保存成功');
setMaritalEditing(false);
// 2秒后清除消息
setTimeout(() => setEditMessage(null), 2000);
} else {
setEditMessage(res.Message || '保存失败');
}
} catch (err) {
console.error('保存客户信息失败', err);
setEditMessage('保存失败,请稍后重试');
} finally {
setEditLoading(false);
}
};
const progressGroups = useMemo(() => { const progressGroups = useMemo(() => {
const checked: string[] = []; const checked: string[] = [];
const abandoned: string[] = []; const abandoned: string[] = [];
@@ -843,7 +921,12 @@ const ExamDetailInfo = ({
{loading ? '加载中…' : '基础信息:头像、姓名、证件号、手机号等(点击图标可进行编辑)'} {loading ? '加载中…' : '基础信息:头像、姓名、证件号、手机号等(点击图标可进行编辑)'}
</div> </div>
</div> </div>
{editMessage && (
<div className={`text-xs px-3 py-2 rounded-lg ${editMessage.includes('成功') ? 'bg-green-50 text-green-600' : 'bg-amber-50 text-amber-600'
}`}>
{editMessage}
</div>
)}
<div className='space-y-2 text-xs text-gray-700'> <div className='space-y-2 text-xs text-gray-700'>
<div className='font-medium text-gray-900'></div> <div className='font-medium text-gray-900'></div>
<div className='grid grid-cols-2 gap-x-8 gap-y-1'> <div className='grid grid-cols-2 gap-x-8 gap-y-1'>
@@ -868,9 +951,25 @@ const ExamDetailInfo = ({
className='w-28 rounded-xl border px-2 py-0.5 text-[11px] outline-none' className='w-28 rounded-xl border px-2 py-0.5 text-[11px] outline-none'
value={phone} value={phone}
onChange={(e) => setPhone(e.target.value)} onChange={(e) => setPhone(e.target.value)}
disabled={editLoading}
/> />
<button className='px-2 py-0.5 rounded-xl border text-[11px]' onClick={() => setPhoneEditing(false)}> <button
className='px-2 py-0.5 rounded-xl border text-[11px] disabled:opacity-50'
onClick={handleSavePhone}
disabled={editLoading}
>
{editLoading ? '保存中...' : '保存'}
</button>
<button
className='px-2 py-0.5 rounded-xl border text-[11px]'
onClick={() => {
setPhoneEditing(false);
setPhone(basePhone || '—');
setEditMessage(null);
}}
disabled={editLoading}
>
</button> </button>
</span> </span>
)} )}
@@ -891,20 +990,54 @@ const ExamDetailInfo = ({
<span></span> <span></span>
{!maritalEditing ? ( {!maritalEditing ? (
<span className='text-gray-900 flex items-center'> <span className='text-gray-900 flex items-center'>
{marital} {getMaritalText(maritalCode)}
<button className='ml-1 text-blue-500 text-[11px] hover:underline' onClick={() => setMaritalEditing(true)}> <button className='ml-1 text-blue-500 text-[11px] hover:underline' onClick={() => setMaritalEditing(true)}>
</button> </button>
</span> </span>
) : ( ) : (
<span className='flex items-center gap-1'> <span className='flex items-center gap-2'>
<input <label className='flex items-center gap-1 cursor-pointer'>
className='w-20 rounded-xl border px-2 py-0.5 text-[11px] outline-none' <input
value={marital} type='radio'
onChange={(e) => setMarital(e.target.value)} name='marital'
/> value='10'
<button className='px-2 py-0.5 rounded-xl border text-[11px]' onClick={() => setMaritalEditing(false)}> checked={maritalCode === 10}
onChange={(e) => setMaritalCode(Number(e.target.value))}
disabled={editLoading}
className='w-3 h-3'
/>
<span className='text-[11px]'></span>
</label>
<label className='flex items-center gap-1 cursor-pointer'>
<input
type='radio'
name='marital'
value='20'
checked={maritalCode === 20}
onChange={(e) => setMaritalCode(Number(e.target.value))}
disabled={editLoading}
className='w-3 h-3'
/>
<span className='text-[11px]'></span>
</label>
<button
className='px-2 py-0.5 rounded-xl border text-[11px] disabled:opacity-50'
onClick={handleSaveMarital}
disabled={editLoading}
>
{editLoading ? '保存中...' : '保存'}
</button>
<button
className='px-2 py-0.5 rounded-xl border text-[11px]'
onClick={() => {
setMaritalEditing(false);
setMaritalCode(baseMaritalCode);
setEditMessage(null);
}}
disabled={editLoading}
>
</button> </button>
</span> </span>
)} )}