108 lines
3.8 KiB
TypeScript
108 lines
3.8 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
|
||
import { getOperatorRemarkInfo, saveOperatorRemarkInfo } from '../../api';
|
||
|
||
interface NoteModalProps {
|
||
noteText: string;
|
||
onNoteChange: (v: string) => void;
|
||
onClose: () => void;
|
||
}
|
||
|
||
export const NoteModal = ({ noteText, onNoteChange, onClose }: NoteModalProps) => {
|
||
const [loading, setLoading] = useState(false);
|
||
const [saving, setSaving] = useState(false);
|
||
const [message, setMessage] = useState<string | null>(null);
|
||
|
||
const operatorId = typeof window !== 'undefined' ? localStorage.getItem('operatorId') || '' : '';
|
||
const operatorName = typeof window !== 'undefined' ? localStorage.getItem('operatorName') || '未知' : '未知';
|
||
|
||
// 初始化拉取备注
|
||
useEffect(() => {
|
||
if (!operatorId) return;
|
||
setLoading(true);
|
||
setMessage(null);
|
||
getOperatorRemarkInfo({ operator_id: operatorId })
|
||
.then((res) => {
|
||
if (res.Status === 200 && res.Data?.remark_content) {
|
||
onNoteChange(res.Data.remark_content);
|
||
} else if (res.Message) {
|
||
setMessage(res.Message);
|
||
}
|
||
})
|
||
.catch((err) => {
|
||
console.error('获取备注失败', err);
|
||
setMessage('获取备注失败,请稍后重试');
|
||
})
|
||
.finally(() => setLoading(false));
|
||
}, [operatorId, onNoteChange]);
|
||
|
||
const handleSave = async () => {
|
||
if (!operatorId || !operatorName) {
|
||
setMessage('缺少操作员信息,无法保存');
|
||
return;
|
||
}
|
||
if (!noteText.trim()) {
|
||
setMessage('备注内容不能为空');
|
||
return;
|
||
}
|
||
setSaving(true);
|
||
setMessage(null);
|
||
try {
|
||
const res = await saveOperatorRemarkInfo({
|
||
operator_id: operatorId,
|
||
operator_name: operatorName,
|
||
remark_content: noteText.trim(),
|
||
});
|
||
if (res.Status === 200) {
|
||
setMessage('保存成功');
|
||
} else {
|
||
setMessage(res.Message || '保存失败');
|
||
}
|
||
} catch (err) {
|
||
console.error('保存备注失败', err);
|
||
setMessage('保存失败,请稍后重试');
|
||
} finally {
|
||
setSaving(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className='fixed inset-0 z-40 flex items-center justify-center bg-black/30'>
|
||
<div className='w-[560px] max-w-[95vw] bg-white rounded-3xl shadow-xl overflow-hidden text-sm'>
|
||
<div className='px-4 py-3 border-b flex items-center justify-between'>
|
||
<div className='font-semibold'>备注窗</div>
|
||
<button className='text-xs text-gray-500' onClick={onClose} disabled={saving || loading}>
|
||
关闭
|
||
</button>
|
||
</div>
|
||
<div className='px-4 py-4 bg-gray-50/60'>
|
||
<div className='space-y-3 text-xs text-gray-700'>
|
||
<div>体检客户服务备注(仅内部可见)</div>
|
||
<textarea
|
||
className='w-full rounded-2xl border px-3 py-2 text-xs outline-none focus:ring-2 focus:ring-gray-200 min-h-[96px]'
|
||
placeholder='例如:客户有既往疾病史、沟通偏好、特殊关怀需求等,可在此记录。'
|
||
value={noteText}
|
||
onChange={(e) => onNoteChange(e.target.value)}
|
||
disabled={loading || saving}
|
||
/>
|
||
{message && <div className='text-[11px] text-amber-600'>{message}</div>}
|
||
<div className='flex items-center justify-end gap-2'>
|
||
<button
|
||
className='px-4 py-1.5 rounded-2xl border text-xs disabled:opacity-50'
|
||
onClick={handleSave}
|
||
disabled={saving || loading}
|
||
>
|
||
{saving ? '保存中...' : '保存'}
|
||
</button>
|
||
</div>
|
||
{/* <div className='text-right text-[11px] text-gray-500'>
|
||
备注内容会同步至客户详情页,供前台和导检护士查看。
|
||
</div> */}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|