|
|
@@ -4,6 +4,7 @@ import { Plus, Edit, Trash2, Search, Eye } from 'lucide-react';
|
|
|
import { format } from 'date-fns';
|
|
|
import { Input } from '@d8d/shared-ui-components/components/ui/input';
|
|
|
import { Button } from '@d8d/shared-ui-components/components/ui/button';
|
|
|
+import { Label } from '@d8d/shared-ui-components/components/ui/label';
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@d8d/shared-ui-components/components/ui/card';
|
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@d8d/shared-ui-components/components/ui/table';
|
|
|
import { Skeleton } from '@d8d/shared-ui-components/components/ui/skeleton';
|
|
|
@@ -21,6 +22,9 @@ import { DISABILITY_LEVELS, getDisabilityLevelLabel } from '@d8d/allin-enums';
|
|
|
import { AreaSelect } from '@d8d/area-management-ui/components';
|
|
|
import PhotoUploadField, { type PhotoItem } from './PhotoUploadField';
|
|
|
import PhotoPreview from './PhotoPreview';
|
|
|
+import BankCardManagement, { type BankCardItem } from './BankCardManagement';
|
|
|
+import RemarkManagement, { type RemarkItem } from './RemarkManagement';
|
|
|
+import VisitManagement, { type VisitItem } from './VisitManagement';
|
|
|
|
|
|
interface DisabilityPersonSearchParams {
|
|
|
page: number;
|
|
|
@@ -38,6 +42,13 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
const [personToView, setPersonToView] = useState<number | null>(null);
|
|
|
const [createPhotos, setCreatePhotos] = useState<PhotoItem[]>([]);
|
|
|
const [updatePhotos, setUpdatePhotos] = useState<PhotoItem[]>([]);
|
|
|
+ const [createBankCards, setCreateBankCards] = useState<BankCardItem[]>([]);
|
|
|
+ const [updateBankCards, setUpdateBankCards] = useState<BankCardItem[]>([]);
|
|
|
+ const [createRemarks, setCreateRemarks] = useState<RemarkItem[]>([]);
|
|
|
+ const [updateRemarks, setUpdateRemarks] = useState<RemarkItem[]>([]);
|
|
|
+ const [createVisits, setCreateVisits] = useState<VisitItem[]>([]);
|
|
|
+ const [updateVisits, setUpdateVisits] = useState<VisitItem[]>([]);
|
|
|
+ const [currentUserId] = useState<number>(1); // 假设当前用户ID为1,实际应从认证状态获取
|
|
|
|
|
|
// 表单实例 - 创建表单
|
|
|
const createForm = useForm<CreateDisabledPersonRequest>({
|
|
|
@@ -57,9 +68,11 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
detailedAddress: '',
|
|
|
nation: '',
|
|
|
isMarried: 0,
|
|
|
- canDirectContact: 0,
|
|
|
+ canDirectContact: 1, // 默认值改为1(是),与原系统一致
|
|
|
isInBlackList: 0,
|
|
|
- jobStatus: 0
|
|
|
+ jobStatus: 0,
|
|
|
+ idValidDate: undefined,
|
|
|
+ disabilityValidDate: undefined
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@@ -105,7 +118,7 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
// 创建残疾人
|
|
|
const createMutation = useMutation({
|
|
|
mutationFn: async (data: CreateDisabledPersonRequest) => {
|
|
|
- // 准备聚合数据,包含照片
|
|
|
+ // 准备聚合数据,包含照片、银行卡、备注、回访信息
|
|
|
const aggregatedData = {
|
|
|
personInfo: data,
|
|
|
photos: createPhotos
|
|
|
@@ -114,6 +127,33 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
photoType: photo.photoType,
|
|
|
fileId: photo.fileId!,
|
|
|
canDownload: photo.canDownload
|
|
|
+ })),
|
|
|
+ bankCards: createBankCards
|
|
|
+ .filter(card => card.fileId !== null && card.bankName && card.subBankName && card.cardNumber && card.cardholderName)
|
|
|
+ .map(card => ({
|
|
|
+ subBankName: card.subBankName,
|
|
|
+ bankName: card.bankName,
|
|
|
+ cardNumber: card.cardNumber,
|
|
|
+ cardholderName: card.cardholderName,
|
|
|
+ fileId: card.fileId!,
|
|
|
+ isDefault: card.isDefault
|
|
|
+ })),
|
|
|
+ remarks: createRemarks
|
|
|
+ .filter(remark => remark.remarkContent)
|
|
|
+ .map(remark => ({
|
|
|
+ remarkContent: remark.remarkContent,
|
|
|
+ isSpecialNeeds: remark.isSpecialNeeds,
|
|
|
+ operatorId: remark.operatorId
|
|
|
+ })),
|
|
|
+ visits: createVisits
|
|
|
+ .filter(visit => visit.visitContent && visit.visitDate)
|
|
|
+ .map(visit => ({
|
|
|
+ visitDate: visit.visitDate,
|
|
|
+ visitType: visit.visitType,
|
|
|
+ visitContent: visit.visitContent,
|
|
|
+ visitResult: visit.visitResult,
|
|
|
+ nextVisitDate: visit.nextVisitDate,
|
|
|
+ visitorId: visit.visitorId
|
|
|
}))
|
|
|
};
|
|
|
|
|
|
@@ -129,6 +169,9 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
setIsModalOpen(false);
|
|
|
createForm.reset();
|
|
|
setCreatePhotos([]); // 重置照片状态
|
|
|
+ setCreateBankCards([]); // 重置银行卡状态
|
|
|
+ setCreateRemarks([]); // 重置备注状态
|
|
|
+ setCreateVisits([]); // 重置回访状态
|
|
|
refetch();
|
|
|
},
|
|
|
onError: (error) => {
|
|
|
@@ -163,6 +206,9 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
canDirectContact: formData.canDirectContact,
|
|
|
isInBlackList: formData.isInBlackList,
|
|
|
jobStatus: formData.jobStatus,
|
|
|
+ // 日期字段
|
|
|
+ idValidDate: formData.idValidDate,
|
|
|
+ disabilityValidDate: formData.disabilityValidDate,
|
|
|
id: data.id // 确保包含ID
|
|
|
};
|
|
|
|
|
|
@@ -174,6 +220,33 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
photoType: photo.photoType,
|
|
|
fileId: photo.fileId!,
|
|
|
canDownload: photo.canDownload
|
|
|
+ })),
|
|
|
+ bankCards: updateBankCards
|
|
|
+ .filter(card => card.fileId !== null && card.bankName && card.subBankName && card.cardNumber && card.cardholderName)
|
|
|
+ .map(card => ({
|
|
|
+ subBankName: card.subBankName,
|
|
|
+ bankName: card.bankName,
|
|
|
+ cardNumber: card.cardNumber,
|
|
|
+ cardholderName: card.cardholderName,
|
|
|
+ fileId: card.fileId!,
|
|
|
+ isDefault: card.isDefault
|
|
|
+ })),
|
|
|
+ remarks: updateRemarks
|
|
|
+ .filter(remark => remark.remarkContent)
|
|
|
+ .map(remark => ({
|
|
|
+ remarkContent: remark.remarkContent,
|
|
|
+ isSpecialNeeds: remark.isSpecialNeeds,
|
|
|
+ operatorId: remark.operatorId
|
|
|
+ })),
|
|
|
+ visits: updateVisits
|
|
|
+ .filter(visit => visit.visitContent && visit.visitDate)
|
|
|
+ .map(visit => ({
|
|
|
+ visitDate: visit.visitDate,
|
|
|
+ visitType: visit.visitType,
|
|
|
+ visitContent: visit.visitContent,
|
|
|
+ visitResult: visit.visitResult,
|
|
|
+ nextVisitDate: visit.nextVisitDate,
|
|
|
+ visitorId: visit.visitorId
|
|
|
}))
|
|
|
};
|
|
|
|
|
|
@@ -189,6 +262,9 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
toast.success('残疾人更新成功');
|
|
|
setIsModalOpen(false);
|
|
|
setUpdatePhotos([]); // 重置照片状态
|
|
|
+ setUpdateBankCards([]); // 重置银行卡状态
|
|
|
+ setUpdateRemarks([]); // 重置备注状态
|
|
|
+ setUpdateVisits([]); // 重置回访状态
|
|
|
refetch();
|
|
|
},
|
|
|
onError: (error) => {
|
|
|
@@ -226,6 +302,9 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
setIsCreateForm(true);
|
|
|
createForm.reset();
|
|
|
setCreatePhotos([]); // 重置创建照片状态
|
|
|
+ setCreateBankCards([]); // 重置创建银行卡状态
|
|
|
+ setCreateRemarks([]); // 重置创建备注状态
|
|
|
+ setCreateVisits([]); // 重置创建回访状态
|
|
|
setIsModalOpen(true);
|
|
|
};
|
|
|
|
|
|
@@ -233,29 +312,72 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
const handleEditOpen = (person: any) => {
|
|
|
setIsCreateForm(false);
|
|
|
updateForm.reset(person);
|
|
|
- setUpdatePhotos([]); // 先重置,然后加载已有照片
|
|
|
+ setUpdatePhotos([]); // 先重置,然后加载已有数据
|
|
|
+ setUpdateBankCards([]);
|
|
|
+ setUpdateRemarks([]);
|
|
|
+ setUpdateVisits([]);
|
|
|
|
|
|
- // 加载聚合数据获取照片信息
|
|
|
+ // 加载聚合数据获取照片、银行卡、备注、回访信息
|
|
|
if (person.id) {
|
|
|
disabilityClientManager.get().getAggregatedDisabledPerson[':id']['$get']({
|
|
|
param: { id: person.id }
|
|
|
}).then(async (res) => {
|
|
|
if (res.status === 200) {
|
|
|
const aggregatedData = await res.json();
|
|
|
+
|
|
|
+ // 加载照片信息
|
|
|
if (aggregatedData && aggregatedData.photos) {
|
|
|
- // 转换照片数据格式
|
|
|
const photos: PhotoItem[] = aggregatedData.photos.map((photo: any) => ({
|
|
|
photoType: photo.photoType,
|
|
|
fileId: photo.fileId,
|
|
|
canDownload: photo.canDownload,
|
|
|
- tempId: `existing-${photo.id || Date.now()}`
|
|
|
+ tempId: `existing-photo-${photo.id || Date.now()}`
|
|
|
}));
|
|
|
setUpdatePhotos(photos);
|
|
|
}
|
|
|
+
|
|
|
+ // 加载银行卡信息
|
|
|
+ if (aggregatedData && aggregatedData.bankCards) {
|
|
|
+ const bankCards: BankCardItem[] = aggregatedData.bankCards.map((card: any) => ({
|
|
|
+ subBankName: card.subBankName,
|
|
|
+ bankName: card.bankName,
|
|
|
+ cardNumber: card.cardNumber,
|
|
|
+ cardholderName: card.cardholderName,
|
|
|
+ fileId: card.fileId,
|
|
|
+ isDefault: card.isDefault,
|
|
|
+ tempId: `existing-bankcard-${card.id || Date.now()}`
|
|
|
+ }));
|
|
|
+ setUpdateBankCards(bankCards);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载备注信息
|
|
|
+ if (aggregatedData && aggregatedData.remarks) {
|
|
|
+ const remarks: RemarkItem[] = aggregatedData.remarks.map((remark: any) => ({
|
|
|
+ remarkContent: remark.remarkContent,
|
|
|
+ isSpecialNeeds: remark.isSpecialNeeds,
|
|
|
+ operatorId: remark.operatorId,
|
|
|
+ tempId: `existing-remark-${remark.id || Date.now()}`
|
|
|
+ }));
|
|
|
+ setUpdateRemarks(remarks);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载回访信息
|
|
|
+ if (aggregatedData && aggregatedData.visits) {
|
|
|
+ const visits: VisitItem[] = aggregatedData.visits.map((visit: any) => ({
|
|
|
+ visitDate: visit.visitDate,
|
|
|
+ visitType: visit.visitType,
|
|
|
+ visitContent: visit.visitContent,
|
|
|
+ visitResult: visit.visitResult,
|
|
|
+ nextVisitDate: visit.nextVisitDate,
|
|
|
+ visitorId: visit.visitorId,
|
|
|
+ tempId: `existing-visit-${visit.id || Date.now()}`
|
|
|
+ }));
|
|
|
+ setUpdateVisits(visits);
|
|
|
+ }
|
|
|
}
|
|
|
}).catch(error => {
|
|
|
- console.error('加载照片数据失败:', error);
|
|
|
- toast.error('加载照片数据失败');
|
|
|
+ console.error('加载聚合数据失败:', error);
|
|
|
+ toast.error('加载数据失败');
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -586,6 +708,73 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
</FormItem>
|
|
|
)}
|
|
|
/>
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={createForm.control}
|
|
|
+ name="canDirectContact"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>是否可直接联系</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <select
|
|
|
+ className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
+ {...field}
|
|
|
+ value={field.value?.toString()}
|
|
|
+ onChange={(e) => field.onChange(Number(e.target.value))}
|
|
|
+ >
|
|
|
+ <option value="1">是</option>
|
|
|
+ <option value="0">否</option>
|
|
|
+ </select>
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={createForm.control}
|
|
|
+ name="jobStatus"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>在职状态</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <select
|
|
|
+ className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
+ {...field}
|
|
|
+ value={field.value?.toString()}
|
|
|
+ onChange={(e) => field.onChange(Number(e.target.value))}
|
|
|
+ >
|
|
|
+ <option value="0">未在职</option>
|
|
|
+ <option value="1">已在职</option>
|
|
|
+ </select>
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={createForm.control}
|
|
|
+ name="isInBlackList"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>是否在黑名单</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <select
|
|
|
+ className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
+ {...field}
|
|
|
+ value={field.value?.toString()}
|
|
|
+ onChange={(e) => field.onChange(Number(e.target.value))}
|
|
|
+ >
|
|
|
+ <option value="0">否</option>
|
|
|
+ <option value="1">是</option>
|
|
|
+ </select>
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
</div>
|
|
|
|
|
|
{/* 第二部分:大字段脱离网格布局,各自独占一行 */}
|
|
|
@@ -604,6 +793,49 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
)}
|
|
|
/>
|
|
|
|
|
|
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
|
+ <FormField
|
|
|
+ control={createForm.control}
|
|
|
+ name="idValidDate"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>身份证有效期</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <Input
|
|
|
+ type="date"
|
|
|
+ placeholder="选择身份证有效期"
|
|
|
+ {...field}
|
|
|
+ value={field.value ? new Date(field.value).toISOString().split('T')[0] : ''}
|
|
|
+ onChange={(e) => field.onChange(e.target.value ? new Date(e.target.value) : undefined)}
|
|
|
+ />
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={createForm.control}
|
|
|
+ name="disabilityValidDate"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>残疾证有效期</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <Input
|
|
|
+ type="date"
|
|
|
+ placeholder="选择残疾证有效期"
|
|
|
+ {...field}
|
|
|
+ value={field.value ? new Date(field.value).toISOString().split('T')[0] : ''}
|
|
|
+ onChange={(e) => field.onChange(e.target.value ? new Date(e.target.value) : undefined)}
|
|
|
+ />
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
<div>
|
|
|
<FormLabel>居住地址 *</FormLabel>
|
|
|
<div className="space-y-4 mt-2">
|
|
|
@@ -643,6 +875,33 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
maxPhotos={5}
|
|
|
/>
|
|
|
</div>
|
|
|
+
|
|
|
+ <div className="col-span-full">
|
|
|
+ <BankCardManagement
|
|
|
+ value={createBankCards}
|
|
|
+ onChange={setCreateBankCards}
|
|
|
+ maxCards={5}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="col-span-full">
|
|
|
+ <RemarkManagement
|
|
|
+ value={createRemarks}
|
|
|
+ onChange={setCreateRemarks}
|
|
|
+ maxRemarks={10}
|
|
|
+ currentUserId={currentUserId}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="col-span-full">
|
|
|
+ <VisitManagement
|
|
|
+ value={createVisits}
|
|
|
+ onChange={setCreateVisits}
|
|
|
+ maxVisits={10}
|
|
|
+ currentUserId={currentUserId}
|
|
|
+ visitTypes={['电话回访', '上门回访', '视频回访', '其他']}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</form>
|
|
|
</Form>
|
|
|
@@ -813,6 +1072,77 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
</FormItem>
|
|
|
)}
|
|
|
/>
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="canDirectContact"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>是否可直接联系</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <select
|
|
|
+ className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
+ {...field}
|
|
|
+ value={field.value?.toString()}
|
|
|
+ onChange={(e) => field.onChange(Number(e.target.value))}
|
|
|
+ >
|
|
|
+ <option value="1">是</option>
|
|
|
+ <option value="0">否</option>
|
|
|
+ </select>
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="jobStatus"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>在职状态</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <select
|
|
|
+ className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
+ {...field}
|
|
|
+ value={field.value?.toString()}
|
|
|
+ onChange={(e) => field.onChange(Number(e.target.value))}
|
|
|
+ >
|
|
|
+ <option value="0">未在职</option>
|
|
|
+ <option value="1">已在职</option>
|
|
|
+ </select>
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="isInBlackList"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>是否在黑名单</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <select
|
|
|
+ className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
+ {...field}
|
|
|
+ value={field.value?.toString()}
|
|
|
+ onChange={(e) => field.onChange(Number(e.target.value))}
|
|
|
+ >
|
|
|
+ <option value="0">否</option>
|
|
|
+ <option value="1">是</option>
|
|
|
+ </select>
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
</div>
|
|
|
|
|
|
{/* 第二部分:大字段脱离网格布局,各自独占一行 */}
|
|
|
@@ -831,6 +1161,49 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
)}
|
|
|
/>
|
|
|
|
|
|
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="idValidDate"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>身份证有效期</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <Input
|
|
|
+ type="date"
|
|
|
+ placeholder="选择身份证有效期"
|
|
|
+ {...field}
|
|
|
+ value={field.value ? (field.value instanceof Date ? field.value : new Date(field.value)).toISOString().split('T')[0] : ''}
|
|
|
+ onChange={(e) => field.onChange(e.target.value ? new Date(e.target.value) : undefined)}
|
|
|
+ />
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="disabilityValidDate"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>残疾证有效期</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <Input
|
|
|
+ type="date"
|
|
|
+ placeholder="选择残疾证有效期"
|
|
|
+ {...field}
|
|
|
+ value={field.value ? (field.value instanceof Date ? field.value : new Date(field.value)).toISOString().split('T')[0] : ''}
|
|
|
+ onChange={(e) => field.onChange(e.target.value ? new Date(e.target.value) : undefined)}
|
|
|
+ />
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
<div>
|
|
|
<FormLabel>居住地址 *</FormLabel>
|
|
|
<div className="space-y-4 mt-2">
|
|
|
@@ -870,6 +1243,36 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
maxPhotos={5}
|
|
|
/>
|
|
|
</div>
|
|
|
+
|
|
|
+ {/* 银行卡管理 */}
|
|
|
+ <div className="col-span-full">
|
|
|
+ <BankCardManagement
|
|
|
+ value={updateBankCards}
|
|
|
+ onChange={setUpdateBankCards}
|
|
|
+ maxCards={5}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 备注管理 */}
|
|
|
+ <div className="col-span-full">
|
|
|
+ <RemarkManagement
|
|
|
+ value={updateRemarks}
|
|
|
+ onChange={setUpdateRemarks}
|
|
|
+ maxRemarks={10}
|
|
|
+ currentUserId={currentUserId}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 回访管理 */}
|
|
|
+ <div className="col-span-full">
|
|
|
+ <VisitManagement
|
|
|
+ value={updateVisits}
|
|
|
+ onChange={setUpdateVisits}
|
|
|
+ maxVisits={10}
|
|
|
+ currentUserId={currentUserId}
|
|
|
+ visitTypes={['电话回访', '上门回访', '视频回访', '其他']}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</form>
|
|
|
@@ -953,6 +1356,18 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
{viewData.personInfo.isMarried === 1 ? '已婚' : viewData.personInfo.isMarried === 0 ? '未婚' : '未知'}
|
|
|
</p>
|
|
|
</div>
|
|
|
+ <div>
|
|
|
+ <label className="text-sm font-medium">身份证有效期</label>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {viewData.personInfo.idValidDate ? format(new Date(viewData.personInfo.idValidDate), 'yyyy-MM-dd') : '未填写'}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <label className="text-sm font-medium">残疾证有效期</label>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {viewData.personInfo.disabilityValidDate ? format(new Date(viewData.personInfo.disabilityValidDate), 'yyyy-MM-dd') : '未填写'}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
<div>
|
|
|
<label className="text-sm font-medium">创建时间</label>
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
@@ -985,6 +1400,144 @@ const DisabilityPersonManagement: React.FC = () => {
|
|
|
/>
|
|
|
</div>
|
|
|
)}
|
|
|
+
|
|
|
+ {/* 银行卡信息 */}
|
|
|
+ {viewData.bankCards && viewData.bankCards.length > 0 && (
|
|
|
+ <div className="mt-6 pt-6 border-t">
|
|
|
+ <h3 className="text-lg font-medium mb-4">银行卡信息</h3>
|
|
|
+ <div className="space-y-4">
|
|
|
+ {viewData.bankCards.map((card: any, index: number) => (
|
|
|
+ <Card key={card.id || index}>
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
+ <div>
|
|
|
+ <Label>银行名称</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{card.bankName}</p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <Label>发卡支行</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{card.subBankName}</p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <Label>银行卡号</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{card.cardNumber}</p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <Label>持卡人姓名</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{card.cardholderName}</p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <Label>是否默认</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {card.isDefault === 1 ? '是' : '否'}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ {card.file?.fullUrl && (
|
|
|
+ <div className="md:col-span-2">
|
|
|
+ <Label>银行卡照片</Label>
|
|
|
+ <div className="mt-2">
|
|
|
+ <img
|
|
|
+ src={card.file.fullUrl}
|
|
|
+ alt="银行卡照片"
|
|
|
+ className="max-w-xs rounded-md border"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 备注信息 */}
|
|
|
+ {viewData.remarks && viewData.remarks.length > 0 && (
|
|
|
+ <div className="mt-6 pt-6 border-t">
|
|
|
+ <h3 className="text-lg font-medium mb-4">备注信息</h3>
|
|
|
+ <div className="space-y-4">
|
|
|
+ {viewData.remarks.map((remark: any, index: number) => (
|
|
|
+ <Card key={remark.id || index}>
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <div className="space-y-2">
|
|
|
+ <div className="flex justify-between items-start">
|
|
|
+ <div>
|
|
|
+ <Label>备注内容</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{remark.remarkContent}</p>
|
|
|
+ </div>
|
|
|
+ {remark.isSpecialNeeds === 1 && (
|
|
|
+ <span className="inline-flex items-center rounded-full bg-amber-100 px-2 py-1 text-xs font-medium text-amber-800">
|
|
|
+ 特殊需求
|
|
|
+ </span>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ <div className="text-xs text-muted-foreground">
|
|
|
+ <p>操作人ID:{remark.operatorId}</p>
|
|
|
+ <p>备注时间:{format(new Date(remark.remarkTime), 'yyyy-MM-dd HH:mm:ss')}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 回访信息 */}
|
|
|
+ {viewData.visits && viewData.visits.length > 0 && (
|
|
|
+ <div className="mt-6 pt-6 border-t">
|
|
|
+ <h3 className="text-lg font-medium mb-4">回访记录</h3>
|
|
|
+ <div className="space-y-4">
|
|
|
+ {viewData.visits.map((visit: any, index: number) => (
|
|
|
+ <Card key={visit.id || index}>
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
+ <div>
|
|
|
+ <Label>回访日期</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {format(new Date(visit.visitDate), 'yyyy-MM-dd')}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <Label>回访类型</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{visit.visitType}</p>
|
|
|
+ </div>
|
|
|
+ <div className="md:col-span-2">
|
|
|
+ <Label>回访内容</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{visit.visitContent}</p>
|
|
|
+ </div>
|
|
|
+ {visit.visitResult && (
|
|
|
+ <div>
|
|
|
+ <Label>回访结果</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{visit.visitResult}</p>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {visit.nextVisitDate && (
|
|
|
+ <div>
|
|
|
+ <Label>下次回访日期</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {format(new Date(visit.nextVisitDate), 'yyyy-MM-dd')}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <div>
|
|
|
+ <Label>回访人ID</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">{visit.visitorId}</p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <Label>记录时间</Label>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {format(new Date(visit.visitTime), 'yyyy-MM-dd HH:mm:ss')}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
</div>
|
|
|
</div>
|
|
|
)}
|