Revert "feat: 客户管理新增个人用户类型,双Tab分离管理"

This reverts commit 03198557f7.
This commit is contained in:
2026-07-12 21:45:23 +08:00
parent 03198557f7
commit 835e5d38fd
5 changed files with 8 additions and 39 deletions
+1 -4
View File
@@ -50,7 +50,6 @@ 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),
@@ -61,8 +60,6 @@ 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:
@@ -92,7 +89,7 @@ async def list_customers(
# Paginate
offset = (page - 1) * page_size
query = base_query.order_by(Customer.customer_type, Customer.name).offset(offset).limit(page_size)
query = base_query.order_by(Customer.name).offset(offset).limit(page_size)
result = await db.execute(query)
items = result.scalars().all()
-4
View File
@@ -42,10 +42,6 @@ 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 '{}'"
-1
View File
@@ -11,7 +11,6 @@ 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="")
-4
View File
@@ -45,7 +45,6 @@ class ContactOut(BaseModel):
# ── Customer ──
class CustomerCreate(BaseModel):
name: str
customer_type: str = "unit"
industry: str = ""
address: str = ""
in_use_services: str = ""
@@ -57,7 +56,6 @@ 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
@@ -69,7 +67,6 @@ class CustomerUpdate(BaseModel):
class CustomerOut(BaseModel):
id: uuid.UUID
name: str
customer_type: str = "unit"
industry: str
address: str
in_use_services: str
@@ -87,7 +84,6 @@ 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
+7 -26
View File
@@ -15,7 +15,6 @@ const search = ref('')
const filterIndustry = ref('')
const filterService = ref('')
const filterManagerId = ref('')
const customerType = ref('unit') // 'unit' or 'individual'
const customers = ref<any[]>([])
const currentPage = ref(1)
const pageSize = ref(25)
@@ -24,7 +23,7 @@ const dialogVisible = ref(false)
const dialogTitle = ref('新建客户')
const editId = ref('')
const form = ref({
name: '', customer_type: 'unit', industry: '', address: '', in_use_services: '',
name: '', industry: '', address: '', in_use_services: '',
fee_amount: '', fee_unit: '元/月',
remarks: '',
contacts: [] as any[],
@@ -69,7 +68,6 @@ 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
@@ -103,7 +101,7 @@ function parseMonthlyFee(fee: string) {
}
function resetForm() {
form.value = { name: '', customer_type: customerType.value, industry: '', address: '', in_use_services: '', fee_amount: '', fee_unit: '元/月', remarks: '', contacts: [], assignee_id: '' }
form.value = { name: '', industry: '', address: '', in_use_services: '', fee_amount: '', fee_unit: '元/月', remarks: '', contacts: [], assignee_id: '' }
feeCustomUnit.value = ''
existingContacts.value = []
}
@@ -130,7 +128,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.customer_type = c.customer_type || 'unit'; form.value.industry = c.industry; form.value.address = c.address
form.value.name = c.name; 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 || []
@@ -143,7 +141,7 @@ async function handleSubmit() {
const monthly_fee = buildMonthlyFee()
try {
if (editId.value) {
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 }
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 }
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) {
@@ -151,7 +149,7 @@ async function handleSubmit() {
}
ElMessage.success('已更新')
} else {
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 })
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 })
ElMessage.success('已创建')
}
dialogVisible.value = false
@@ -331,14 +329,6 @@ async function handleImport() {
<div class="page-rule"></div>
</div>
<!-- Customer Type Tabs -->
<div style="margin-bottom:14px">
<el-radio-group v-model="customerType" @change="(v: string) => { customerType = v; onFilterChange() }">
<el-radio-button value="unit">单位客户</el-radio-button>
<el-radio-button value="individual">个人用户</el-radio-button>
</el-radio-group>
</div>
<!-- Search & Filter -->
<el-card style="margin-bottom: 16px;">
<el-row :gutter="12" align="middle">
@@ -373,12 +363,7 @@ async function handleImport() {
<el-table :data="customers" stripe v-column-resize @selection-change="onSelectionChange">
<el-table-column v-if="auth.isDirector" type="selection" width="50" />
<el-table-column type="index" label="序号" width="60" :index="(idx: number) => (currentPage - 1) * pageSize + idx + 1" />
<el-table-column label="类型" width="70">
<template #default="{ row }">
<el-tag size="small" :type="row.customer_type === 'individual' ? 'info' : ''" effect="plain">{{ row.customer_type === 'individual' ? '个人' : '单位' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="name" :label="customerType === 'individual' ? '姓名' : '单位名称'" min-width="180">
<el-table-column prop="name" label="单位名称" min-width="180">
<template #default="{ row }">
<el-link type="primary" @click="openDetail(row)">{{ row.name }}</el-link>
</template>
@@ -404,8 +389,7 @@ async function handleImport() {
<!-- Create/Edit Dialog -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="520px">
<el-form label-position="top">
<el-form-item :label="form.customer_type === 'individual' ? '姓名' : '单位名称'" required><el-input v-model="form.name" :placeholder="form.customer_type === 'individual' ? '请输入姓名' : '请输入单位名称'" @blur="checkName" /><el-alert v-if="duplicateHint" :title="duplicateHint" type="warning" :closable="false" style="margin-top:6px" /></el-form-item>
<template v-if="form.customer_type === 'unit'">
<el-form-item label="单位名称" required><el-input v-model="form.name" placeholder="请输入单位名称" @blur="checkName" /><el-alert v-if="duplicateHint" :title="duplicateHint" type="warning" :closable="false" style="margin-top:6px" /></el-form-item>
<el-form-item label="所属行业"><el-input v-model="form.industry" placeholder="如: 教育、医疗、政府..." /></el-form-item>
<el-form-item label="单位地址"><el-input v-model="form.address" /></el-form-item>
<el-form-item label="在用业务"><el-input v-model="form.in_use_services" placeholder="如: 云桌面、专线、视频会议" /></el-form-item>
@@ -420,9 +404,7 @@ async function handleImport() {
<el-col v-if="form.fee_unit === '自定义'" :span="8"><el-input v-model="feeCustomUnit" placeholder="单位" /></el-col>
</el-row>
</el-form-item>
</template>
<el-form-item label="备注"><el-input v-model="form.remarks" type="textarea" :rows="2" placeholder="备注信息..." /></el-form-item>
<template v-if="form.customer_type === 'unit'">
<el-form-item label="归属客户经理" v-if="auth.isDirector">
<el-select v-model="form.assignee_id" :placeholder="editId ? '留空则不修改' : '不选则默认分配给自己'" clearable style="width:100%">
<el-option v-for="m in managers" :key="m.id" :label="m.name" :value="m.id" />
@@ -442,7 +424,6 @@ async function handleImport() {
</div>
<el-button size="small" @click="form.contacts.push({name:'',phone:'',role_desc:''})">+ 添加联系人</el-button>
</el-form-item>
</template>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>