tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/controller/ProvincialAgentController.java
@@ -1,4 +1,5 @@ package com.tcm.training.admin.agent.controller; import com.tcm.training.admin.agent.dto.ProvincialAgentSaveRequest; import com.tcm.training.admin.agent.service.ProvincialAgentAppService; import com.tcm.training.admin.agent.vo.ProvincialAgentDetailVO; @@ -7,13 +8,42 @@ import com.tcm.training.admin.common.PageResponse; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @Validated @RestController @RequestMapping({"/api/v1","/api"}) @Validated @RestController @RequestMapping({"/api/v1", "/api"}) public class ProvincialAgentController { private final ProvincialAgentAppService service; public ProvincialAgentController(ProvincialAgentAppService service){this.service=service;} @GetMapping("/provincial-agents") public ApiResponse<PageResponse<ProvincialAgentListItemVO>> page(@RequestParam(defaultValue="1") int page,@RequestParam(defaultValue="10") int pageSize,@RequestParam(required=false) String agentName,@RequestParam(required=false) String province){return ApiResponse.ok(service.page(page,pageSize,agentName,province));} @GetMapping("/provincial-agents/{id}") public ApiResponse<ProvincialAgentDetailVO> detail(@PathVariable Long id){return ApiResponse.ok(service.detail(id));} @PostMapping("/provincial-agents") public ApiResponse<ProvincialAgentDetailVO> create(@Valid @RequestBody ProvincialAgentSaveRequest r){return ApiResponse.ok(service.create(r));} @PutMapping("/provincial-agents/{id}") public ApiResponse<ProvincialAgentDetailVO> update(@PathVariable Long id,@Valid @RequestBody ProvincialAgentSaveRequest r){return ApiResponse.ok(service.update(id,r));} @DeleteMapping("/provincial-agents/{id}") public ApiResponse<Void> delete(@PathVariable Long id){service.delete(id);return ApiResponse.ok(null);} private final ProvincialAgentAppService service; public ProvincialAgentController(ProvincialAgentAppService service) { this.service = service; } @GetMapping("/provincial-agents") public ApiResponse<PageResponse<ProvincialAgentListItemVO>> page(@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int pageSize, @RequestParam(required = false) String agentName, @RequestParam(required = false) String regionCode) { return ApiResponse.ok(service.page(page, pageSize, agentName, regionCode)); } @GetMapping("/provincial-agents/{id}") public ApiResponse<ProvincialAgentDetailVO> detail(@PathVariable Long id) { return ApiResponse.ok(service.detail(id)); } @PostMapping("/provincial-agents") public ApiResponse<ProvincialAgentDetailVO> create(@Valid @RequestBody ProvincialAgentSaveRequest r) { return ApiResponse.ok(service.create(r)); } @PutMapping("/provincial-agents/{id}") public ApiResponse<ProvincialAgentDetailVO> update(@PathVariable Long id, @Valid @RequestBody ProvincialAgentSaveRequest r) { return ApiResponse.ok(service.update(id, r)); } @DeleteMapping("/provincial-agents/{id}") public ApiResponse<Void> delete(@PathVariable Long id) { service.delete(id); return ApiResponse.ok(null); } } tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/dto/ProvincialAgentSaveRequest.java
@@ -15,20 +15,29 @@ @NotBlank(message = "请输入代理负责人") @Size(max = 50, message = "代理负责人不能超过50个字") private String agentName; @NotBlank(message = "请选择负责省份") private String province; @Size(max = 100) private String bankName; @Size(max = 30) private String accountNumber; @Size(max = 50) private String accountHolder; @Size(max = 100) private String branchName; @Size(max = 200) private String contactInfo; @Size(max = 255) private String address; @Valid private List<RegionItem> regions = new ArrayList<RegionItem>(); @Size(max = 100) private String bankName; @Size(max = 30) private String accountNumber; @Size(max = 50) private String accountHolder; @Size(max = 100) private String branchName; @Size(max = 200) private String contactInfo; @Size(max = 255) private String address; @Valid @Size(min = 1, message = "请选择负责省份") private List<RegionItem> regions = new ArrayList<RegionItem>(); @Getter @Setter @Getter @Setter public static class RegionItem { @NotBlank(message = "区域编码不能为空") private String regionCode; @Size(max = 100) private String regionName; @NotBlank(message = "区域编码不能为空") private String regionCode; @Size(max = 100) private String regionName; private Integer regionLevel; } } tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/service/ProvincialAgentAppService.java
@@ -1,6 +1,7 @@ package com.tcm.training.admin.agent.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.tcm.training.admin.agent.dto.ProvincialAgentSaveRequest; @@ -10,7 +11,11 @@ import com.tcm.training.admin.agent.mapper.ProvincialAgentMapper; import com.tcm.training.admin.agent.vo.ProvincialAgentDetailVO; import com.tcm.training.admin.agent.vo.ProvincialAgentListItemVO; import com.tcm.training.admin.app.register.entity.SysRegion; import com.tcm.training.admin.app.register.mapper.SysRegionMapper; import com.tcm.training.admin.common.PageResponse; import com.tcm.training.admin.live.entity.Clinic; import com.tcm.training.admin.live.mapper.ClinicMapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,18 +26,31 @@ public class ProvincialAgentAppService { private final ProvincialAgentMapper agentMapper; private final AgentRegionMapper regionMapper; private final SysRegionMapper sysRegionMapper; private final ClinicMapper clinicMapper; public ProvincialAgentAppService(ProvincialAgentMapper agentMapper, AgentRegionMapper regionMapper) { public ProvincialAgentAppService(ProvincialAgentMapper agentMapper, AgentRegionMapper regionMapper, SysRegionMapper sysRegionMapper, ClinicMapper clinicMapper) { this.agentMapper = agentMapper; this.regionMapper = regionMapper; this.sysRegionMapper = sysRegionMapper; this.clinicMapper = clinicMapper; } public PageResponse<ProvincialAgentListItemVO> page(int page, int pageSize, String agentName, String province) { LambdaQueryWrapper<ProvincialAgent> q = new LambdaQueryWrapper<ProvincialAgent>().eq(ProvincialAgent::getDeleted, 0) .like(agentName != null && !agentName.trim().isEmpty(), ProvincialAgent::getAgentName, trim(agentName)) .like(province != null && !province.trim().isEmpty(), ProvincialAgent::getProvince, trim(province)) public PageResponse<ProvincialAgentListItemVO> page(int page, int pageSize, String agentName, String regionCode) { LambdaQueryWrapper<ProvincialAgent> query = new LambdaQueryWrapper<ProvincialAgent>() .eq(ProvincialAgent::getDeleted, 0) .like(trim(agentName) != null, ProvincialAgent::getAgentName, trim(agentName)) .orderByDesc(ProvincialAgent::getCreatedAt).orderByDesc(ProvincialAgent::getId); IPage<ProvincialAgent> result = agentMapper.selectPage(new Page<ProvincialAgent>(page, pageSize), q); if (trim(regionCode) != null) { List<Long> ids = new ArrayList<Long>(); for (AgentRegion region : regionMapper.selectList(new LambdaQueryWrapper<AgentRegion>() .eq(AgentRegion::getRegionCode, trim(regionCode)))) ids.add(region.getAgentId()); if (ids.isEmpty()) return PageResponse.of(new ArrayList<ProvincialAgentListItemVO>(), 0, page, pageSize); query.in(ProvincialAgent::getId, ids); } IPage<ProvincialAgent> result = agentMapper.selectPage(new Page<ProvincialAgent>(page, pageSize), query); List<ProvincialAgentListItemVO> list = new ArrayList<ProvincialAgentListItemVO>(); for (ProvincialAgent item : result.getRecords()) list.add(toList(item)); return PageResponse.of(list, result.getTotal(), result.getCurrent(), result.getSize()); @@ -44,21 +62,26 @@ @Transactional public ProvincialAgentDetailVO create(ProvincialAgentSaveRequest request) { ProvincialAgent a = new ProvincialAgent(); fill(a, request); a.setDeleted(0); agentMapper.insert(a); saveRegions(a, request); return detail(a.getId()); boolean firstAgent = agentMapper.selectCount(new LambdaQueryWrapper<ProvincialAgent>() .eq(ProvincialAgent::getDeleted, 0)) == 0; ProvincialAgent agent = new ProvincialAgent(); fill(agent, request); agent.setDeleted(0); agentMapper.insert(agent); saveRegions(agent, request); if (firstAgent) { clinicMapper.update(null, new LambdaUpdateWrapper<Clinic>().set(Clinic::getAgentId, agent.getId())); } return detail(agent.getId()); } @Transactional public ProvincialAgentDetailVO update(Long id, ProvincialAgentSaveRequest request) { ProvincialAgent a = require(id); fill(a, request); agentMapper.updateById(a); ProvincialAgent agent = require(id); fill(agent, request); agentMapper.updateById(agent); regionMapper.delete(new LambdaQueryWrapper<AgentRegion>().eq(AgentRegion::getAgentId, id)); saveRegions(a, request); saveRegions(agent, request); return detail(id); } @@ -68,88 +91,117 @@ agentMapper.deleteById(id); } private void fill(ProvincialAgent a, ProvincialAgentSaveRequest r) { a.setAgentName(trim(r.getAgentName())); a.setProvince(trim(r.getProvince())); a.setBankName(trim(r.getBankName())); a.setAccountNumber(trim(r.getAccountNumber())); a.setAccountHolder(trim(r.getAccountHolder())); a.setBranchName(trim(r.getBranchName())); a.setContactInfo(trim(r.getContactInfo())); a.setAddress(trim(r.getAddress())); private void fill(ProvincialAgent agent, ProvincialAgentSaveRequest request) { agent.setAgentName(trim(request.getAgentName())); agent.setProvince(""); agent.setBankName(trim(request.getBankName())); agent.setAccountNumber(trim(request.getAccountNumber())); agent.setAccountHolder(trim(request.getAccountHolder())); agent.setBranchName(trim(request.getBranchName())); agent.setContactInfo(trim(request.getContactInfo())); agent.setAddress(trim(request.getAddress())); } private void saveRegions(ProvincialAgent a, ProvincialAgentSaveRequest r) { if (r.getRegions() == null) return; for (ProvincialAgentSaveRequest.RegionItem x : r.getRegions()) { if (x == null || trim(x.getRegionCode()) == null) continue; AgentRegion ar = new AgentRegion(); ar.setAgentId(a.getId()); ar.setAgentName(a.getAgentName()); ar.setRegionCode(trim(x.getRegionCode())); ar.setRegionName(trim(x.getRegionName())); ar.setRegionLevel(x.getRegionLevel()); regionMapper.insert(ar); private void saveRegions(ProvincialAgent agent, ProvincialAgentSaveRequest request) { if (request.getRegions() == null) return; for (ProvincialAgentSaveRequest.RegionItem item : request.getRegions()) { if (item == null || trim(item.getRegionCode()) == null) continue; RegionInfo info = resolveRegion(item.getRegionCode()); AgentRegion region = new AgentRegion(); region.setAgentId(agent.getId()); region.setAgentName(agent.getAgentName()); region.setRegionCode(trim(item.getRegionCode())); region.setRegionName(info.name); region.setRegionLevel(info.path.size()); regionMapper.insert(region); } } private ProvincialAgent require(Long id) { ProvincialAgent a = agentMapper.selectOne(new LambdaQueryWrapper<ProvincialAgent>().eq(ProvincialAgent::getId, id).eq(ProvincialAgent::getDeleted, 0).last("limit 1")); if (a == null) throw new IllegalArgumentException("省代理不存在"); return a; ProvincialAgent agent = agentMapper.selectOne(new LambdaQueryWrapper<ProvincialAgent>() .eq(ProvincialAgent::getId, id).eq(ProvincialAgent::getDeleted, 0).last("limit 1")); if (agent == null) throw new IllegalArgumentException("省代理不存在"); return agent; } private ProvincialAgentListItemVO toList(ProvincialAgent a) { ProvincialAgentListItemVO v = new ProvincialAgentListItemVO(); v.setId(a.getId()); v.setAgentName(a.getAgentName()); v.setProvince(a.getProvince()); v.setContactInfo(a.getContactInfo()); v.setAddress(a.getAddress()); List<AgentRegion> rs = regions(a.getId()); v.setRegionCount(rs.size()); private ProvincialAgentListItemVO toList(ProvincialAgent agent) { ProvincialAgentListItemVO vo = new ProvincialAgentListItemVO(); vo.setId(agent.getId()); vo.setAgentName(agent.getAgentName()); vo.setContactInfo(agent.getContactInfo()); vo.setAddress(agent.getAddress()); vo.setCreatedAt(agent.getCreatedAt()); List<AgentRegion> regions = regions(agent.getId()); vo.setRegionCount(regions.size()); List<String> names = new ArrayList<String>(); for (AgentRegion r : rs) names.add(r.getRegionName() == null ? r.getRegionCode() : r.getRegionName()); v.setRegionNames(names); v.setCreatedAt(a.getCreatedAt()); return v; for (AgentRegion region : regions) names.add(resolveRegion(region.getRegionCode()).name); vo.setRegionNames(names); return vo; } private ProvincialAgentDetailVO toDetail(ProvincialAgent a) { ProvincialAgentDetailVO v = new ProvincialAgentDetailVO(); ProvincialAgentListItemVO base = toList(a); v.setId(base.getId()); v.setAgentName(base.getAgentName()); v.setProvince(base.getProvince()); v.setContactInfo(base.getContactInfo()); v.setAddress(base.getAddress()); v.setRegionCount(base.getRegionCount()); v.setRegionNames(base.getRegionNames()); v.setCreatedAt(base.getCreatedAt()); v.setBankName(a.getBankName()); v.setAccountNumber(a.getAccountNumber()); v.setAccountHolder(a.getAccountHolder()); v.setBranchName(a.getBranchName()); v.setUpdatedAt(a.getUpdatedAt()); List<ProvincialAgentDetailVO.RegionVO> out = new ArrayList<ProvincialAgentDetailVO.RegionVO>(); for (AgentRegion r : regions(a.getId())) { ProvincialAgentDetailVO.RegionVO x = new ProvincialAgentDetailVO.RegionVO(); x.setRegionCode(r.getRegionCode()); x.setRegionName(r.getRegionName()); x.setRegionLevel(r.getRegionLevel()); out.add(x); private ProvincialAgentDetailVO toDetail(ProvincialAgent agent) { ProvincialAgentDetailVO vo = new ProvincialAgentDetailVO(); ProvincialAgentListItemVO base = toList(agent); vo.setId(base.getId()); vo.setAgentName(base.getAgentName()); vo.setContactInfo(base.getContactInfo()); vo.setAddress(base.getAddress()); vo.setRegionCount(base.getRegionCount()); vo.setRegionNames(base.getRegionNames()); vo.setCreatedAt(base.getCreatedAt()); vo.setBankName(agent.getBankName()); vo.setAccountNumber(agent.getAccountNumber()); vo.setAccountHolder(agent.getAccountHolder()); vo.setBranchName(agent.getBranchName()); vo.setUpdatedAt(agent.getUpdatedAt()); List<ProvincialAgentDetailVO.RegionVO> values = new ArrayList<ProvincialAgentDetailVO.RegionVO>(); for (AgentRegion region : regions(agent.getId())) { RegionInfo info = resolveRegion(region.getRegionCode()); ProvincialAgentDetailVO.RegionVO value = new ProvincialAgentDetailVO.RegionVO(); value.setRegionCode(region.getRegionCode()); value.setRegionName(info.name); value.setRegionLevel(info.path.size()); value.setRegionPath(info.path); values.add(value); } v.setRegions(out); return v; vo.setRegions(values); return vo; } private List<AgentRegion> regions(Long id) { return regionMapper.selectList(new LambdaQueryWrapper<AgentRegion>().eq(AgentRegion::getAgentId, id).orderByAsc(AgentRegion::getId)); return regionMapper.selectList(new LambdaQueryWrapper<AgentRegion>() .eq(AgentRegion::getAgentId, id).orderByAsc(AgentRegion::getId)); } private String trim(String s) { if (s == null) return null; String x = s.trim(); return x.isEmpty() ? null : x; private RegionInfo resolveRegion(String code) { List<String> path = new ArrayList<String>(); List<String> names = new ArrayList<String>(); SysRegion current = sysRegionMapper.selectByCode(code); while (current != null) { path.add(0, current.getCode()); names.add(0, current.getName()); current = current.getParentId() == null || current.getParentId() == 0 ? null : sysRegionMapper.selectById(current.getParentId()); } if (path.isEmpty()) { path.add(code); names.add(code); } return new RegionInfo(path, String.join("", names)); } } private String trim(String value) { if (value == null) return null; String trimmed = value.trim(); return trimmed.isEmpty() ? null : trimmed; } private static class RegionInfo { private final List<String> path; private final String name; private RegionInfo(List<String> path, String name) { this.path = path; this.name = name; } } } tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/vo/ProvincialAgentDetailVO.java
@@ -2,12 +2,26 @@ import lombok.Getter; import lombok.Setter; import java.time.LocalDateTime; import java.util.List; @Getter @Setter @Getter @Setter public class ProvincialAgentDetailVO extends ProvincialAgentListItemVO { private String bankName; private String accountNumber; private String accountHolder; private String branchName; private LocalDateTime updatedAt; private List<RegionVO> regions; @Getter @Setter public static class RegionVO { private String regionCode; private String regionName; private Integer regionLevel; } private String bankName; private String accountNumber; private String accountHolder; private String branchName; private LocalDateTime updatedAt; private List<RegionVO> regions; @Getter @Setter public static class RegionVO { private String regionCode; private String regionName; private Integer regionLevel; private List<String> regionPath; } } tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/vo/ProvincialAgentListItemVO.java
@@ -2,12 +2,18 @@ import lombok.Getter; import lombok.Setter; import java.time.LocalDateTime; import java.util.List; @Getter @Setter @Getter @Setter public class ProvincialAgentListItemVO { private Long id; private String agentName; private String province; private String contactInfo; private String address; private Integer regionCount; private List<String> regionNames; private LocalDateTime createdAt; private Long id; private String agentName; private String contactInfo; private String address; private Integer regionCount; private List<String> regionNames; private LocalDateTime createdAt; } tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/entity/Clinic.java
@@ -23,6 +23,9 @@ private String name; @TableField("agent_id") private Long agentId; @TableField("contact_name") private String contactName; tcm-training-admin/src/pages/member/agent/index.tsx
@@ -5,13 +5,148 @@ import React, { useEffect, useState } from 'react'; import { createAgent, deleteAgent, getAgentDetail, getAgentPage, updateAgent } from './service'; type Region={regionCode:string|string[];regionName?:string;regionLevel?:number}; type Item={id:number;agentName:string;province:string;contactInfo?:string;address?:string;regionNames?:string[];regionCount:number;createdAt?:string}; const AgentPage:React.FC=()=>{const access=useAccess();const [search]=Form.useForm();const [form]=Form.useForm();const [list,setList]=useState<Item[]>([]);const [pagination,setPagination]=useState({page:1,pageSize:10,total:0});const [loading,setLoading]=useState(false);const [open,setOpen]=useState(false);const [detail,setDetail]=useState<any>();const [editing,setEditing]=useState<number>();const canView=access['member:agent:view']; const load=async(page=1,pageSize=pagination.pageSize)=>{setLoading(true);try{const r=await getAgentPage({page,pageSize,...search.getFieldsValue()});setList(r.data?.list||[]);setPagination({page:Number(r.data?.page||page),pageSize:Number(r.data?.pageSize||pageSize),total:Number(r.data?.total||0)});}finally{setLoading(false);}};useEffect(()=>{if(!canView){history.replace('/Welcome');return;}load();},[canView]); const edit=async(id?:number)=>{setEditing(id);setOpen(true);if(id){const r=await getAgentDetail(id);const d=r.data;setDetail(d);form.setFieldsValue({...d,regions:d.regions||[]});}else{setDetail(undefined);form.resetFields();form.setFieldsValue({regions:[{}]});}}; const submit=async()=>{const v=await form.validateFields();const regions=(v.regions||[]).filter((x:Region)=>x?.regionCode).map((x:Region)=>{const path=Array.isArray(x.regionCode)?x.regionCode:[x.regionCode];return {...x,regionCode:path[path.length-1],regionName:x.regionName||path[path.length-1],regionLevel:path.length};});const data={...v,regions};try{if(editing)await updateAgent(editing,data);else await createAgent(data);message.success(editing?'保存成功':'新增成功');setOpen(false);load(editing?pagination.page:1);}catch(e){message.error((e as Error).message||'保存失败');}}; const columns=[{title:'序号',width:70,render:(_:any,__ :any,i:number)=>(pagination.page-1)*pagination.pageSize+i+1},{title:'代理负责人',dataIndex:'agentName'},{title:'负责省份',dataIndex:'province'},{title:'负责区域',render:(_:any,r:Item)=>(r.regionNames||[]).join('、')||'-'},{title:'联系信息',dataIndex:'contactInfo',render:(v:string)=>v||'-'},{title:'创建时间',dataIndex:'createdAt',width:180},{title:'操作',render:(_:any,r:Item)=><Space><Button type="link" onClick={()=>{getAgentDetail(r.id).then(x=>{setDetail(x.data);setOpen(true);setEditing(undefined);});}}>详情</Button>{access['member:agent:edit']&&<Button type="link" onClick={()=>edit(r.id)}>编辑</Button>}{access['member:agent:delete']&&<Button type="link" danger onClick={()=>Modal.confirm({title:'确定删除该省代理吗?',onOk:async()=>{await deleteAgent(r.id);message.success('删除成功');load();}})}>删除</Button>}</Space>}]; return <div style={{padding:24}}><h2>省代理管理</h2><Form form={search} layout="inline" onFinish={()=>load(1)}><Form.Item name="agentName" label="代理负责人"><Input allowClear placeholder="请输入"/></Form.Item><Form.Item name="province" label="负责省份"><Input allowClear placeholder="请输入"/></Form.Item><Button onClick={()=>{search.resetFields();load(1)}}>重置</Button><Button type="primary" htmlType="submit" style={{marginLeft:8}}>查询</Button></Form><div style={{margin:'16px 0'}}>{access['member:agent:add']&&<Button type="primary" icon={<PlusOutlined/>} onClick={()=>edit()}>新增</Button>}</div><Table rowKey="id" columns={columns as any} dataSource={list} loading={loading} pagination={false}/><Pagination style={{marginTop:16,textAlign:'right'}} current={pagination.page} pageSize={pagination.pageSize} total={pagination.total} showSizeChanger onChange={load}/> <Modal open={open} title={detail&&!editing?'省代理详情':editing?'编辑省代理':'新增省代理'} width={760} onCancel={()=>{setOpen(false);setDetail(undefined)}} footer={detail&&!editing?null:<><Button onClick={()=>setOpen(false)}>取消</Button><Button type="primary" onClick={submit}>确定</Button></>}> {detail&&!editing?<Descriptions bordered column={2} items={[['代理负责人',detail.agentName],['负责省份',detail.province],['负责区域',(detail.regionNames||[]).join('、')||'-'],['开户银行',detail.bankName],['银行账号',detail.accountNumber],['账户名称',detail.accountHolder],['开户支行',detail.branchName],['联系信息',detail.contactInfo],['详细地址',detail.address]].map(([label,children])=>({label,children:children||'-'}))}/>:<Form form={form} labelCol={{span:5}}><Form.Item name="agentName" label="代理负责人" rules={[{required:true,message:'请输入代理负责人'}]}><Input maxLength={50}/></Form.Item><Form.Item name="province" label="负责省份" rules={[{required:true,message:'请输入负责省份'}]}><Input maxLength={20}/></Form.Item><Form.List name="regions">{(fields,{add,remove})=><>{fields.map(({key,name,...rest})=><Space key={key} align="baseline"><Form.Item {...rest} name={[name,'regionCode']} rules={[{required:true,message:'请选择区域'}]}><RegionCascader/></Form.Item><Form.Item {...rest} name={[name,'regionName']} hidden><Input/></Form.Item><Button onClick={()=>remove(name)}>删除</Button></Space>)}<Button type="dashed" onClick={()=>add({})}>添加区域</Button></>}</Form.List><Form.Item name="bankName" label="开户银行"><Input/></Form.Item><Form.Item name="accountNumber" label="银行账号"><Input/></Form.Item><Form.Item name="accountHolder" label="账户名称"><Input/></Form.Item><Form.Item name="branchName" label="开户支行"><Input/></Form.Item><Form.Item name="contactInfo" label="联系信息"><Input/></Form.Item><Form.Item name="address" label="详细地址"><Input.TextArea rows={3}/></Form.Item></Form>} </Modal></div>};export default AgentPage; type RegionValue = { regionCode?: string[]; regionName?: string }; type AgentItem = { id: number; agentName: string; contactInfo?: string; address?: string; regionNames?: string[]; createdAt?: string }; const AgentPage: React.FC = () => { const access = useAccess(); const [searchForm] = Form.useForm<{ regionPath?: string[]; agentName?: string }>(); const [form] = Form.useForm(); const [list, setList] = useState<AgentItem[]>([]); const [pagination, setPagination] = useState({ page: 1, pageSize: 10, total: 0 }); const [loading, setLoading] = useState(false); const [open, setOpen] = useState(false); const [detail, setDetail] = useState<any>(); const [editingId, setEditingId] = useState<number>(); const canView = access['member:agent:view']; const load = async (page = 1, pageSize = pagination.pageSize) => { const search = searchForm.getFieldsValue(); setLoading(true); try { const response = await getAgentPage({ page, pageSize, agentName: search.agentName?.trim() || undefined, regionCode: search.regionPath?.[search.regionPath.length - 1], }); setList(response.data?.list || []); setPagination({ page: Number(response.data?.page || page), pageSize: Number(response.data?.pageSize || pageSize), total: Number(response.data?.total || 0), }); } finally { setLoading(false); } }; useEffect(() => { if (!canView) history.replace('/Welcome'); else void load(); }, [canView]); const openForm = async (id?: number) => { setEditingId(id); setDetail(undefined); setOpen(true); form.resetFields(); if (!id) { form.setFieldsValue({ regions: [{}] }); return; } const response = await getAgentDetail(id); form.setFieldsValue({ ...response.data, regions: (response.data?.regions || []).map((region: any) => ({ ...region, regionCode: region.regionPath, })), }); }; const openDetail = async (id: number) => { const response = await getAgentDetail(id); setEditingId(undefined); setDetail(response.data); setOpen(true); }; const submit = async () => { const values = await form.validateFields(); const regions = (values.regions || []).map((region: RegionValue) => ({ regionCode: region.regionCode?.[region.regionCode.length - 1], })); try { if (editingId) await updateAgent(editingId, { ...values, regions }); else await createAgent({ ...values, regions }); message.success(editingId ? '保存成功' : '新增成功'); setOpen(false); await load(editingId ? pagination.page : 1); } catch (error) { message.error((error as Error)?.message || '保存失败'); } }; const columns = [ { title: '序号', width: 70, render: (_: any, __: any, index: number) => (pagination.page - 1) * pagination.pageSize + index + 1 }, { title: '代理负责人', dataIndex: 'agentName' }, { title: '负责省份', render: (_: any, record: AgentItem) => (record.regionNames || []).join('、') || '-' }, { title: '联系信息', dataIndex: 'contactInfo', render: (value: string) => value || '-' }, { title: '详细地址', dataIndex: 'address', render: (value: string) => value || '-' }, { title: '创建时间', dataIndex: 'createdAt', width: 180 }, { title: '操作', width: 180, render: (_: any, record: AgentItem) => <Space size={0}> {access['member:agent:detail'] && <Button type="link" onClick={() => openDetail(record.id)}>详情</Button>} {access['member:agent:edit'] && <Button type="link" onClick={() => openForm(record.id)}>编辑</Button>} {access['member:agent:delete'] && <Button type="link" danger onClick={() => Modal.confirm({ title: '确定删除该省代理吗?', onOk: async () => { await deleteAgent(record.id); message.success('删除成功'); await load(); }, })}>删除</Button>} </Space>, }, ]; return <div style={{ padding: 24 }}> <h2>省代理管理</h2> <Form form={searchForm} layout="inline" onFinish={() => load(1)}> <Form.Item name="regionPath" label="负责省份"><RegionCascader allowClear changeOnSelect placeholder="全部" /></Form.Item> <Form.Item name="agentName" label="代理负责人"><Input allowClear placeholder="请输入" /></Form.Item> <Button onClick={() => { searchForm.resetFields(); void load(1); }}>重置</Button> <Button type="primary" htmlType="submit" style={{ marginLeft: 8 }}>查询</Button> </Form> <div style={{ margin: '16px 0' }}>{access['member:agent:add'] && <Button type="primary" icon={<PlusOutlined />} onClick={() => openForm()}>新增</Button>}</div> <Table rowKey="id" columns={columns as any} dataSource={list} loading={loading} pagination={false} /> <Pagination style={{ marginTop: 16, textAlign: 'right' }} current={pagination.page} pageSize={pagination.pageSize} total={pagination.total} showSizeChanger onChange={load} /> <Modal open={open} title={detail ? '省代理详情' : editingId ? '编辑省代理' : '新增省代理'} width={760} onCancel={() => setOpen(false)} footer={detail ? null : <><Button onClick={() => setOpen(false)}>取消</Button><Button type="primary" onClick={submit}>确定</Button></>}> {detail ? <Descriptions bordered column={2} items={[ ['代理负责人', detail.agentName], ['负责省份', (detail.regionNames || []).join('、')], ['开户银行', detail.bankName], ['银行账号', detail.accountNumber], ['账户名称', detail.accountHolder], ['开户支行', detail.branchName], ['联系信息', detail.contactInfo], ['详细地址', detail.address], ].map(([label, children]) => ({ label, children: children || '-' }))} /> : <Form form={form} labelCol={{ span: 5 }}> <Form.Item name="agentName" label="代理负责人" rules={[{ required: true, message: '请输入代理负责人' }]}><Input maxLength={50} /></Form.Item> <Form.List name="regions" rules={[{ validator: async (_, value) => { if (!value?.length) throw new Error('请选择负责省份'); } }]}> {(fields, { add, remove }, { errors }) => <Form.Item label="负责省份" required> {fields.map(({ key, name, ...rest }) => <Space key={key} align="baseline"> <Form.Item {...rest} name={[name, 'regionCode']} rules={[{ required: true, message: '请选择负责省份' }]}><RegionCascader changeOnSelect /></Form.Item> {fields.length > 1 && <Button onClick={() => remove(name)}>删除</Button>} </Space>)} <Button type="dashed" onClick={() => add({})}>添加负责省份</Button> <Form.ErrorList errors={errors} /> </Form.Item>} </Form.List> <Form.Item name="bankName" label="开户银行"><Input maxLength={100} /></Form.Item> <Form.Item name="accountNumber" label="银行账号"><Input maxLength={30} /></Form.Item> <Form.Item name="accountHolder" label="账户名称"><Input maxLength={50} /></Form.Item> <Form.Item name="branchName" label="开户支行"><Input maxLength={100} /></Form.Item> <Form.Item name="contactInfo" label="联系信息"><Input maxLength={200} /></Form.Item> <Form.Item name="address" label="详细地址"><Input.TextArea rows={3} maxLength={255} /></Form.Item> </Form>} </Modal> </div>; }; export default AgentPage;