From 3df055ea1038e0bbcbbbf80ccbeea43c82952932 Mon Sep 17 00:00:00 2001
From: hejianhao <15708179461@qq.com>
Date: 星期二, 18 八月 2026 12:51:56 +0800
Subject: [PATCH] feat0806: 优化代理搜索条件
---
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/dto/ProvincialAgentSaveRequest.java | 5 +
tcm-training-admin-backend/sql/20260806_admin.sql | 1
tcm-training-admin/src/pages/member/agent/index.tsx | 128 +++++++++++++++---------------------------
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/entity/ProvincialAgent.java | 2
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/vo/ProvincialAgentListItemVO.java | 4 +
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/controller/ProvincialAgentController.java | 4
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/service/ProvincialAgentAppService.java | 34 +++++++++--
7 files changed, 87 insertions(+), 91 deletions(-)
diff --git a/tcm-training-admin-backend/sql/20260806_admin.sql b/tcm-training-admin-backend/sql/20260806_admin.sql
index 0a0a676..362b675 100644
--- a/tcm-training-admin-backend/sql/20260806_admin.sql
+++ b/tcm-training-admin-backend/sql/20260806_admin.sql
@@ -10,6 +10,7 @@
account_holder VARCHAR(50) COMMENT '账户名称/户名(即开户人姓名或公司名称)',
branch_name VARCHAR(100) COMMENT '开户支行名称(如:成都高新支行)',
contact_info VARCHAR(200) COMMENT '联系信息(可填电话、邮箱、手机号等)',
+ status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1启用,0禁用,2注销',
address VARCHAR(255) COMMENT '详细地址(如:成都市高新区天府大道XX号)',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
`created_by` varchar(64) NOT NULL DEFAULT '系统初始化' COMMENT '创建人',
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/controller/ProvincialAgentController.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/controller/ProvincialAgentController.java
index 0cbfbef..1b58d36 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/controller/ProvincialAgentController.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/controller/ProvincialAgentController.java
@@ -22,8 +22,8 @@
}
@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));
+ public ApiResponse<PageResponse<ProvincialAgentListItemVO>> page(@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int pageSize, @RequestParam(required = false) String regionCode, @RequestParam(required = false) String clinicName, @RequestParam(required = false) String contactInfo, @RequestParam(required = false) Integer status) {
+ return ApiResponse.ok(service.page(page, pageSize, regionCode, clinicName, contactInfo, status));
}
@GetMapping("/provincial-agents/{id}")
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/dto/ProvincialAgentSaveRequest.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/dto/ProvincialAgentSaveRequest.java
index d16c331..0973955 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/dto/ProvincialAgentSaveRequest.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/dto/ProvincialAgentSaveRequest.java
@@ -5,6 +5,8 @@
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
@@ -27,6 +29,9 @@
private String contactInfo;
@Size(max = 255)
private String address;
+ @Min(value = 0, message = "状态值不正确")
+ @Max(value = 2, message = "状态值不正确")
+ private Integer status;
@Valid
@Size(min = 1, message = "请选择负责省份")
private List<RegionItem> regions = new ArrayList<RegionItem>();
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/entity/ProvincialAgent.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/entity/ProvincialAgent.java
index a5b9a03..4711ecf 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/entity/ProvincialAgent.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/entity/ProvincialAgent.java
@@ -37,6 +37,8 @@
@TableField("contact_info")
private String contactInfo;
+ private Integer status;
+
@TableField("address")
private String address;
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/service/ProvincialAgentAppService.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/service/ProvincialAgentAppService.java
index ebcb162..b91d688 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/service/ProvincialAgentAppService.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/service/ProvincialAgentAppService.java
@@ -37,17 +37,27 @@
this.clinicMapper = clinicMapper;
}
- public PageResponse<ProvincialAgentListItemVO> page(int page, int pageSize, String agentName, String regionCode) {
+ public PageResponse<ProvincialAgentListItemVO> page(int page, int pageSize, String regionCode,
+ String clinicName, String contactInfo, Integer status) {
LambdaQueryWrapper<ProvincialAgent> query = new LambdaQueryWrapper<ProvincialAgent>()
.eq(ProvincialAgent::getDeleted, 0)
- .like(trim(agentName) != null, ProvincialAgent::getAgentName, trim(agentName))
- .orderByAsc(ProvincialAgent::getCreatedAt).orderByDesc(ProvincialAgent::getId);
+ .like(trim(contactInfo) != null, ProvincialAgent::getContactInfo, trim(contactInfo))
+ .eq(status != null, ProvincialAgent::getStatus, status)
+ .orderByAsc(ProvincialAgent::getCreatedAt).orderByAsc(ProvincialAgent::getId);
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);
+ .eq(AgentRegion::getRegionCode, trim(regionCode)))) ids.add(region.getAgentId());
+ if (ids.isEmpty()) return emptyPage(page, pageSize);
+ query.in(ProvincialAgent::getId, ids);
+ }
+ if (trim(clinicName) != null) {
+ List<Long> ids = new ArrayList<Long>();
+ for (Clinic clinic : clinicMapper.selectList(new LambdaQueryWrapper<Clinic>()
+ .like(Clinic::getName, trim(clinicName)))) {
+ if (clinic.getAgentId() != null && !ids.contains(clinic.getAgentId())) ids.add(clinic.getAgentId());
+ }
+ if (ids.isEmpty()) return emptyPage(page, pageSize);
query.in(ProvincialAgent::getId, ids);
}
IPage<ProvincialAgent> result = agentMapper.selectPage(new Page<ProvincialAgent>(page, pageSize), query);
@@ -56,6 +66,9 @@
return PageResponse.of(list, result.getTotal(), result.getCurrent(), result.getSize());
}
+ private PageResponse<ProvincialAgentListItemVO> emptyPage(int page, int pageSize) {
+ return PageResponse.of(new ArrayList<ProvincialAgentListItemVO>(), 0, page, pageSize);
+ }
public ProvincialAgentDetailVO detail(Long id) {
return toDetail(require(id));
}
@@ -99,6 +112,7 @@
agent.setAccountHolder(trim(request.getAccountHolder()));
agent.setBranchName(trim(request.getBranchName()));
agent.setContactInfo(trim(request.getContactInfo()));
+ agent.setStatus(request.getStatus() == null ? 1 : request.getStatus());
agent.setAddress(trim(request.getAddress()));
}
@@ -130,10 +144,14 @@
vo.setContactInfo(agent.getContactInfo());
vo.setAddress(agent.getAddress());
vo.setCreatedAt(agent.getCreatedAt());
+ vo.setStatus(agent.getStatus());
+ vo.setClinicCount(clinicMapper.selectCount(new LambdaQueryWrapper<Clinic>().eq(Clinic::getAgentId, agent.getId())));
List<AgentRegion> regions = regions(agent.getId());
vo.setRegionCount(regions.size());
List<String> names = new ArrayList<String>();
- for (AgentRegion region : regions) names.add(resolveRegion(region.getRegionCode()).name);
+ for (AgentRegion region : regions) {
+ names.add(resolveRegion(region.getRegionCode()).name);
+ }
vo.setRegionNames(names);
return vo;
}
@@ -148,6 +166,8 @@
vo.setRegionCount(base.getRegionCount());
vo.setRegionNames(base.getRegionNames());
vo.setCreatedAt(base.getCreatedAt());
+ vo.setStatus(base.getStatus());
+ vo.setClinicCount(base.getClinicCount());
vo.setBankName(agent.getBankName());
vo.setAccountNumber(agent.getAccountNumber());
vo.setAccountHolder(agent.getAccountHolder());
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/vo/ProvincialAgentListItemVO.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/vo/ProvincialAgentListItemVO.java
index 6f7bbfd..676f3f8 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/vo/ProvincialAgentListItemVO.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/agent/vo/ProvincialAgentListItemVO.java
@@ -16,4 +16,8 @@
private Integer regionCount;
private List<String> regionNames;
private LocalDateTime createdAt;
+
+ private Integer status;
+
+ private Long clinicCount;
}
diff --git a/tcm-training-admin/src/pages/member/agent/index.tsx b/tcm-training-admin/src/pages/member/agent/index.tsx
index ae7946a..e64bb1c 100644
--- a/tcm-training-admin/src/pages/member/agent/index.tsx
+++ b/tcm-training-admin/src/pages/member/agent/index.tsx
@@ -1,16 +1,19 @@
import RegionCascader from '@/components/RegionCascader';
import { PlusOutlined } from '@ant-design/icons';
import { history, useAccess } from '@umijs/max';
-import { Button, Descriptions, Form, Input, Modal, Pagination, Space, Table, message } from 'antd';
+import { Button, Descriptions, Form, Input, Modal, Pagination, Select, Space, Table, message } from 'antd';
import React, { useEffect, useState } from 'react';
import { createAgent, deleteAgent, getAgentDetail, getAgentPage, updateAgent } from './service';
-type RegionValue = { regionCode?: string[]; regionName?: string };
-type AgentItem = { id: number; agentName: string; contactInfo?: string; address?: string; regionNames?: string[]; createdAt?: string };
+type RegionValue = { regionCode?: string[] };
+type SearchValues = { regionPath?: string[]; clinicName?: string; contactInfo?: string; status?: number };
+type AgentItem = { id: number; agentName: string; contactInfo?: string; address?: string; regionNames?: string[]; clinicCount?: number; status?: number; createdAt?: string };
+const statusOptions = [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }, { label: '注销', value: 2 }];
+const statusText = (value?: number) => value === 1 ? '启用' : value === 2 ? '注销' : '禁用';
const AgentPage: React.FC = () => {
const access = useAccess();
- const [searchForm] = Form.useForm<{ regionPath?: string[]; agentName?: string }>();
+ const [searchForm] = Form.useForm<SearchValues>();
const [form] = Form.useForm();
const [list, setList] = useState<AgentItem[]>([]);
const [pagination, setPagination] = useState({ page: 1, pageSize: 10, total: 0 });
@@ -25,128 +28,89 @@
setLoading(true);
try {
const response = await getAgentPage({
- page,
- pageSize,
- agentName: search.agentName?.trim() || undefined,
+ page, pageSize,
regionCode: search.regionPath?.[search.regionPath.length - 1],
+ clinicName: search.clinicName?.trim() || undefined,
+ contactInfo: search.contactInfo?.trim() || undefined,
+ status: search.status,
});
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);
- }
+ 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]);
+ 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;
- }
+ setEditingId(id); setDetail(undefined); setOpen(true); form.resetFields();
+ if (!id) { form.setFieldsValue({ regions: [{}], status: 1 }); return; }
const response = await getAgentDetail(id);
- form.setFieldsValue({
- ...response.data,
- regions: (response.data?.regions || []).map((region: any) => ({
- ...region,
- regionCode: region.regionPath,
- })),
- });
+ 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 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],
- }));
+ 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 || '保存失败');
- }
+ 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: '负责人', dataIndex: 'agentName' },
+ { title: '电话', dataIndex: 'contactInfo', render: (value: string) => value || '-' },
{ title: '负责省份', render: (_: any, record: AgentItem) => (record.regionNames || []).join('、') || '-' },
- { title: '联系信息', dataIndex: 'contactInfo', render: (value: string) => value || '-' },
{ title: '详细地址', dataIndex: 'address', render: (value: string) => value || '-' },
+ { title: '下级诊所数', dataIndex: 'clinicCount', width: 110, render: (value: number) => value ?? 0 },
+ { title: '状态', dataIndex: 'status', width: 90, render: statusText },
{ title: '创建时间', dataIndex: 'createdAt', width: 180 },
- {
- title: '操作',
- width: 180,
- render: (_: any, record: AgentItem, index: number) => <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'] && !(pagination.page === 1 && index === 0) && <Button type="link" danger onClick={() => Modal.confirm({
- title: '确定删除该省代理吗?',
- onOk: async () => { await deleteAgent(record.id); message.success('删除成功'); await load(); },
- })}>删除</Button>}
- </Space>,
- },
+ { title: '操作', width: 180, render: (_: any, record: AgentItem, index: number) => <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'] && !(pagination.page === 1 && index === 0) && <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>
+ <Form.Item name="regionPath" label="诊所区域"><RegionCascader allowClear changeOnSelect placeholder="全部" /></Form.Item>
+ <Form.Item name="clinicName" label="诊所名称"><Input allowClear placeholder="请输入" /></Form.Item>
+ <Form.Item name="contactInfo" label="电话"><Input allowClear placeholder="请输入" /></Form.Item>
+ <Form.Item name="status" label="状态"><Select allowClear placeholder="请选择" style={{ width: 120 }} options={statusOptions} /></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} />
+ <Table rowKey="id" columns={columns as any} dataSource={list} loading={loading} pagination={false} scroll={{ x: 1200 }} />
<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 || '-' }))} /> :
+ ['负责人', detail.agentName], ['电话', detail.contactInfo], ['负责省份', (detail.regionNames || []).join('、')],
+ ['详细地址', detail.address], ['下级诊所数', detail.clinicCount], ['状态', statusText(detail.status)],
+ ['开户银行', detail.bankName], ['银行账号', detail.accountNumber], ['账户名称', detail.accountHolder], ['开户支行', detail.branchName],
+ ].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="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} />
+ {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="contactInfo" label="电话"><Input maxLength={200} /></Form.Item>
+ <Form.Item name="address" label="详细地址"><Input.TextArea rows={3} maxLength={255} /></Form.Item>
+ <Form.Item name="status" label="状态" rules={[{ required: true, message: '请选择状态' }]}><Select options={statusOptions} /></Form.Item>
<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;
\ No newline at end of file
--
Gitblit v1.7.1