feat: 新增用车需求服务及线索管理全功能
- 新增后台用车服务配置模块,支持维护服务简介、优势与使用流程 - 新增需求线索管理页面,支持筛选、查看与更新用车线索状态 - 新增小程序用车需求页面,优化登录路径与回跳逻辑 - 优化车型卡片跳转与用车需求提交功能 - 新增服务端API与数据处理逻辑,完善权限校验 - 更新全站配置与API文档,新增相关测试用例
This commit is contained in:
1 parent
b7a81964c9
commit
d42f69bd47
36 files changed
+1290
-33
No files matched your search
@@ -366,6 +366,23 @@ def test_admin_login_returns_token_and_user():
|
||||
{"submitLabel": "提交出行需求", "destinationLabel": "目的地/玩法", "chips": [" 贵州 ", "", "黄果树"]},
|
||||
{"submitLabel": "提交出行需求", "destinationLabel": "目的地/玩法", "chips": ["贵州", "黄果树"]},
|
||||
),
|
||||
(
|
||||
"vehicleService",
|
||||
{
|
||||
"introTitle": "旅游专属用车",
|
||||
"intro": "提交需求后由管家联系确认。",
|
||||
"serviceSections": [{"title": "包车", "description": "行程灵活"}],
|
||||
"advantages": ["车型匹配", "服务省心"],
|
||||
"processSteps": [{"title": "提交需求", "description": "填写日期和地点"}],
|
||||
},
|
||||
{
|
||||
"introTitle": "旅游专属用车",
|
||||
"intro": "提交需求后由管家联系确认。",
|
||||
"serviceSections": [{"title": "包车", "description": "行程灵活"}],
|
||||
"advantages": ["车型匹配", "服务省心"],
|
||||
"processSteps": [{"title": "提交需求", "description": "填写日期和地点"}],
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_site_config_create_modules_defaults_fields_and_audits(module, payload, expected):
|
||||
@@ -382,7 +399,7 @@ def test_site_config_create_modules_defaults_fields_and_audits(module, payload,
|
||||
for key, value in expected.items():
|
||||
assert body[key] == value
|
||||
assert body["isActive"] is True
|
||||
if module == "demandForm":
|
||||
if module in {"demandForm", "vehicleService"}:
|
||||
assert "sortOrder" not in body
|
||||
else:
|
||||
assert body["sortOrder"] == 5
|
||||
|
||||
@@ -1,6 +1,48 @@
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from app.schemas import LeadCreateIn
|
||||
|
||||
|
||||
def test_lead_phone_is_normalized():
|
||||
lead = LeadCreateIn(phone=" 187 8617 4929 ")
|
||||
assert lead.phone == "187 8617 4929"
|
||||
|
||||
|
||||
def test_vehicle_lead_normalizes_nested_demand():
|
||||
lead = LeadCreateIn(
|
||||
leadType="vehicle",
|
||||
contactName=" Damon ",
|
||||
phone=" 13800000000 ",
|
||||
vehicleDemand={
|
||||
"serviceType": "charter",
|
||||
"charterDuration": "fullDay",
|
||||
"travelDate": "2026-08-25",
|
||||
"pickupTime": "09:00",
|
||||
"pickupLocation": " 贵阳北站 ",
|
||||
"dropoffLocation": " 黄果树景区 ",
|
||||
"peopleCount": 5,
|
||||
"luggageCount": 3,
|
||||
"vehicleOptionId": "vehicle-option-uuid",
|
||||
"vehicleOptionTitle": "多人商务车",
|
||||
"specialRequirements": " 需要儿童座椅 ",
|
||||
},
|
||||
sourcePage="home-vehicle",
|
||||
)
|
||||
|
||||
assert lead.leadType == "vehicle"
|
||||
assert lead.contactName == "Damon"
|
||||
assert lead.vehicleDemand.travelDate.isoformat() == "2026-08-25"
|
||||
assert lead.vehicleDemand.pickupLocation == "贵阳北站"
|
||||
assert lead.vehicleDemand.specialRequirements == "需要儿童座椅"
|
||||
|
||||
|
||||
def test_vehicle_lead_requires_vehicle_demand():
|
||||
with pytest.raises(ValidationError):
|
||||
LeadCreateIn(leadType="vehicle", phone="13800000000")
|
||||
|
||||
|
||||
def test_generic_lead_remains_guest_compatible():
|
||||
lead = LeadCreateIn(phone="13800000000", destination="贵州")
|
||||
assert lead.leadType == "general"
|
||||
assert lead.vehicleDemand is None
|
||||
@@ -0,0 +1,98 @@
|
||||
from datetime import datetime
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.auth import optional_customer
|
||||
from app.database import get_db
|
||||
from app.main import create_app
|
||||
from app.models import Customer, Lead
|
||||
|
||||
|
||||
class FakeDb:
|
||||
def __init__(self):
|
||||
self.added = []
|
||||
self.committed = False
|
||||
|
||||
def add(self, item):
|
||||
self.added.append(item)
|
||||
|
||||
def commit(self):
|
||||
self.committed = True
|
||||
|
||||
def refresh(self, item):
|
||||
if not item.id:
|
||||
item.id = "lead-vehicle-test"
|
||||
|
||||
|
||||
def test_vehicle_lead_requires_customer_token():
|
||||
db = FakeDb()
|
||||
app = create_app()
|
||||
app.dependency_overrides[get_db] = lambda: db
|
||||
app.dependency_overrides[optional_customer] = lambda: None
|
||||
try:
|
||||
response = TestClient(app).post(
|
||||
"/api/public/leads",
|
||||
json={
|
||||
"leadType": "vehicle",
|
||||
"phone": "13800000000",
|
||||
"vehicleDemand": {
|
||||
"serviceType": "transfer",
|
||||
"travelDate": "2026-08-25",
|
||||
"pickupLocation": "贵阳北站",
|
||||
"dropoffLocation": "黄果树景区",
|
||||
"peopleCount": 5,
|
||||
},
|
||||
},
|
||||
)
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 401
|
||||
assert response.json()["data"] is None
|
||||
|
||||
|
||||
def test_vehicle_lead_persists_customer_and_summary_fields():
|
||||
db = FakeDb()
|
||||
customer = Customer(id="customer-test", phone="13800000000")
|
||||
app = create_app()
|
||||
app.dependency_overrides[get_db] = lambda: db
|
||||
app.dependency_overrides[optional_customer] = lambda: customer
|
||||
try:
|
||||
response = TestClient(app).post(
|
||||
"/api/public/leads",
|
||||
json={
|
||||
"leadType": "vehicle",
|
||||
"contactName": "Damon",
|
||||
"phone": "13800000000",
|
||||
"note": "需要儿童座椅",
|
||||
"sourcePage": "home-vehicle",
|
||||
"vehicleDemand": {
|
||||
"serviceType": "charter",
|
||||
"charterDuration": "fullDay",
|
||||
"travelDate": "2026-08-25",
|
||||
"pickupTime": "09:00",
|
||||
"pickupLocation": "贵阳北站",
|
||||
"dropoffLocation": "黄果树景区",
|
||||
"peopleCount": 5,
|
||||
"luggageCount": 3,
|
||||
"vehicleOptionId": "vehicle-option-1",
|
||||
"vehicleOptionTitle": "多人商务车",
|
||||
"specialRequirements": "需要儿童座椅",
|
||||
},
|
||||
},
|
||||
)
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 201
|
||||
lead = next(item for item in db.added if isinstance(item, Lead))
|
||||
assert lead.customerId == "customer-test"
|
||||
assert lead.destination == "黄果树景区"
|
||||
assert lead.peopleCount == 5
|
||||
assert lead.travelDate == datetime(2026, 8, 25)
|
||||
assert lead.vehicleDemand["vehicleOptionTitle"] == "多人商务车"
|
||||
assert response.json() == {
|
||||
"code": 201,
|
||||
"msg": "success",
|
||||
"data": {"id": lead.id, "status": "new"},
|
||||
}
|
||||
Reference in new issue
Block a user