From 03198557f72c9dfed54e7e7c6690ca72e7adc365 Mon Sep 17 00:00:00 2001 From: v6ole Date: Sun, 12 Jul 2026 21:43:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=A2=E6=88=B7=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=AA=E4=BA=BA=E7=94=A8=E6=88=B7=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=EF=BC=8C=E5=8F=8CTab=E5=88=86=E7=A6=BB=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - customers 表新增 customer_type 列 (unit/individual) - 列表按个人优先排序,支持 customer_type 筛选 - PC端 el-radio-group 切换:单位客户 | 个人用户 - 个人用户表单: 仅姓名+备注,隐藏行业/地址/业务/月费/客户经理/联系人 - 所有业务模块客户搜索下拉中个人用户置顶 Co-Authored-By: Claude --- backend/app/api/customers.py | 5 ++- backend/app/main.py | 4 +++ backend/app/models/customer.py | 1 + backend/app/schemas/customer.py | 4 +++ frontend/src/views/desktop/CustomerManage.vue | 33 +++++++++++++++---- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/backend/app/api/customers.py b/backend/app/api/customers.py index d516300..9cca076 100644 --- a/backend/app/api/customers.py +++ b/backend/app/api/customers.py @@ -50,6 +50,7 @@ async def list_customers( industry: Optional[str] = Query(None), service: Optional[str] = Query(None), manager_id: Optional[str] = Query(None), + customer_type: Optional[str] = Query(None), page: int = Query(1, ge=1), page_size: int = Query(100, ge=1, le=1000), current_user: dict = Depends(get_current_user), @@ -60,6 +61,8 @@ async def list_customers( base_query = select(Customer) + if customer_type: + base_query = base_query.where(Customer.customer_type == customer_type) if industry: base_query = base_query.where(Customer.industry.ilike(f"%{industry}%")) if service: @@ -89,7 +92,7 @@ async def list_customers( # Paginate offset = (page - 1) * page_size - query = base_query.order_by(Customer.name).offset(offset).limit(page_size) + query = base_query.order_by(Customer.customer_type, Customer.name).offset(offset).limit(page_size) result = await db.execute(query) items = result.scalars().all() diff --git a/backend/app/main.py b/backend/app/main.py index 028c2ef..52b6997 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -42,6 +42,10 @@ async def lifespan(app: FastAPI): await conn.run_sync(lambda c: c.exec_driver_sql( "ALTER TABLE customers ADD COLUMN IF NOT EXISTS last_visit_manager_id UUID" )) + # v0.9 — customer_type for unit vs individual + await conn.run_sync(lambda c: c.exec_driver_sql( + "ALTER TABLE customers ADD COLUMN IF NOT EXISTS customer_type VARCHAR(20) DEFAULT 'unit'" + )) # New columns for v0.4 await conn.run_sync(lambda c: c.exec_driver_sql( "ALTER TABLE visits ADD COLUMN IF NOT EXISTS companion_names TEXT[] DEFAULT '{}'" diff --git a/backend/app/models/customer.py b/backend/app/models/customer.py index 1e6a654..4f47b68 100644 --- a/backend/app/models/customer.py +++ b/backend/app/models/customer.py @@ -11,6 +11,7 @@ class Customer(Base): id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name: Mapped[str] = mapped_column(String(200), index=True) + customer_type: Mapped[str] = mapped_column(String(20), default="unit") # unit / individual industry: Mapped[str] = mapped_column(String(100), default="") address: Mapped[str] = mapped_column(String(500), default="") in_use_services: Mapped[str] = mapped_column(Text, default="") diff --git a/backend/app/schemas/customer.py b/backend/app/schemas/customer.py index d779751..a5f8e72 100644 --- a/backend/app/schemas/customer.py +++ b/backend/app/schemas/customer.py @@ -45,6 +45,7 @@ class ContactOut(BaseModel): # ── Customer ── class CustomerCreate(BaseModel): name: str + customer_type: str = "unit" industry: str = "" address: str = "" in_use_services: str = "" @@ -56,6 +57,7 @@ class CustomerCreate(BaseModel): class CustomerUpdate(BaseModel): name: Optional[str] = None + customer_type: Optional[str] = None industry: Optional[str] = None address: Optional[str] = None in_use_services: Optional[str] = None @@ -67,6 +69,7 @@ class CustomerUpdate(BaseModel): class CustomerOut(BaseModel): id: uuid.UUID name: str + customer_type: str = "unit" industry: str address: str in_use_services: str @@ -84,6 +87,7 @@ class CustomerOut(BaseModel): class CustomerListOut(BaseModel): id: uuid.UUID name: str + customer_type: str = "unit" industry: str in_use_services: str primary_manager_name: Optional[str] = None diff --git a/frontend/src/views/desktop/CustomerManage.vue b/frontend/src/views/desktop/CustomerManage.vue index 3b4cfd0..fd359f6 100644 --- a/frontend/src/views/desktop/CustomerManage.vue +++ b/frontend/src/views/desktop/CustomerManage.vue @@ -15,6 +15,7 @@ const search = ref('') const filterIndustry = ref('') const filterService = ref('') const filterManagerId = ref('') +const customerType = ref('unit') // 'unit' or 'individual' const customers = ref([]) const currentPage = ref(1) const pageSize = ref(25) @@ -23,7 +24,7 @@ const dialogVisible = ref(false) const dialogTitle = ref('新建客户') const editId = ref('') const form = ref({ - name: '', industry: '', address: '', in_use_services: '', + name: '', customer_type: 'unit', industry: '', address: '', in_use_services: '', fee_amount: '', fee_unit: '元/月', remarks: '', contacts: [] as any[], @@ -68,6 +69,7 @@ async function loadCustomers() { if (filterIndustry.value) params.industry = filterIndustry.value if (filterService.value) params.service = filterService.value if (filterManagerId.value) params.manager_id = filterManagerId.value + if (customerType.value) params.customer_type = customerType.value const res = await customersApi.list(params) customers.value = res.data.items total.value = res.data.total @@ -101,7 +103,7 @@ function parseMonthlyFee(fee: string) { } function resetForm() { - form.value = { name: '', industry: '', address: '', in_use_services: '', fee_amount: '', fee_unit: '元/月', remarks: '', contacts: [], assignee_id: '' } + form.value = { name: '', customer_type: customerType.value, industry: '', address: '', in_use_services: '', fee_amount: '', fee_unit: '元/月', remarks: '', contacts: [], assignee_id: '' } feeCustomUnit.value = '' existingContacts.value = [] } @@ -128,7 +130,7 @@ async function openEdit(customer: any) { const res = await customersApi.get(customer.id) const c = res.data resetForm() - form.value.name = c.name; form.value.industry = c.industry; form.value.address = c.address + form.value.name = c.name; form.value.customer_type = c.customer_type || 'unit'; form.value.industry = c.industry; form.value.address = c.address form.value.in_use_services = c.in_use_services; form.value.remarks = c.remarks || '' parseMonthlyFee(c.monthly_fee) existingContacts.value = c.contacts || [] @@ -141,7 +143,7 @@ async function handleSubmit() { const monthly_fee = buildMonthlyFee() try { if (editId.value) { - const body: any = { name: form.value.name, industry: form.value.industry, address: form.value.address, in_use_services: form.value.in_use_services, monthly_fee, remarks: form.value.remarks } + const body: any = { name: form.value.name, customer_type: form.value.customer_type, industry: form.value.industry, address: form.value.address, in_use_services: form.value.in_use_services, monthly_fee, remarks: form.value.remarks } if (form.value.assignee_id) body.assignee_id = form.value.assignee_id await customersApi.update(editId.value, body) for (const c of form.value.contacts) { @@ -149,7 +151,7 @@ async function handleSubmit() { } ElMessage.success('已更新') } else { - await customersApi.create({ name: form.value.name, industry: form.value.industry, address: form.value.address, in_use_services: form.value.in_use_services, monthly_fee, remarks: form.value.remarks, contacts: form.value.contacts, assignee_id: form.value.assignee_id || undefined }) + await customersApi.create({ name: form.value.name, customer_type: form.value.customer_type, industry: form.value.industry, address: form.value.address, in_use_services: form.value.in_use_services, monthly_fee, remarks: form.value.remarks, contacts: form.value.contacts, assignee_id: form.value.assignee_id || undefined }) ElMessage.success('已创建') } dialogVisible.value = false @@ -329,6 +331,14 @@ async function handleImport() {
+ +
+ + 单位客户 + 个人用户 + +
+ @@ -363,7 +373,12 @@ async function handleImport() { - + + + + @@ -389,7 +404,8 @@ async function handleImport() { - + + +