diff --git a/backend/app/schemas/pl/vehicle_fuel.py b/backend/app/schemas/pl/vehicle_fuel.py index 36f56b21b..092a6078b 100644 --- a/backend/app/schemas/pl/vehicle_fuel.py +++ b/backend/app/schemas/pl/vehicle_fuel.py @@ -22,7 +22,7 @@ class VehicleFuelRegisterCreate(BaseModel): register_date: date = Field(..., alias="registerDate") registrant_id: Optional[str] = Field(default=None, alias="registrantId") license_plate: str = Field(..., alias="licensePlate") - odometer_km: Optional[Decimal] = Field(default=None, alias="odometerKm") + odometer_km: Decimal = Field(..., alias="odometerKm") fuel_liters: Decimal = Field(..., alias="fuelLiters") attachment_urls: Optional[str] = Field(default=None, alias="attachmentUrls") remark: Optional[str] = None @@ -45,8 +45,10 @@ class VehicleFuelRegisterCreate(BaseModel): @field_validator("odometer_km") @classmethod - def validate_odometer_km(cls, v: Optional[Decimal]) -> Optional[Decimal]: - if v is not None and v < 0: + def validate_odometer_km(cls, v: Decimal) -> Decimal: + if v is None: + raise ValueError("期初公里数不能为空") + if v < 0: raise ValueError("期初公里数不能为负数") return v diff --git a/backend/app/services/pl_vehicle_fuel_service.py b/backend/app/services/pl_vehicle_fuel_service.py index 059a51145..3378633f4 100644 --- a/backend/app/services/pl_vehicle_fuel_service.py +++ b/backend/app/services/pl_vehicle_fuel_service.py @@ -168,6 +168,15 @@ def to_read( ) +def fuel_register_list_order(): + """列表与导出:按加油日期倒序;同一天再按创建时间、主键倒序。""" + return ( + PlVehicleFuelRegister.register_date.desc(), + PlVehicleFuelRegister.create_time.desc(), + PlVehicleFuelRegister.id.desc(), + ) + + def list_registers( db: Session, tenant_no: str, @@ -260,11 +269,7 @@ def list_registers( cap = int(max_page_size) if max_page_size else 500 page_size = min(max(1, page_size), cap) rows = ( - # 与 seqNo 倒序一致:序号大的在前(create_time ASC,id ASC → seqNo;列表取反) - query.order_by( - PlVehicleFuelRegister.create_time.desc(), - PlVehicleFuelRegister.id.desc(), - ) + query.order_by(*fuel_register_list_order()) .offset((page - 1) * page_size) .limit(page_size) .all() diff --git a/backend/tests/test_pl_vehicle_fuel_list_filters.py b/backend/tests/test_pl_vehicle_fuel_list_filters.py index a0f8e07bf..22024c912 100644 --- a/backend/tests/test_pl_vehicle_fuel_list_filters.py +++ b/backend/tests/test_pl_vehicle_fuel_list_filters.py @@ -47,3 +47,11 @@ def test_fuel_register_filters(): def test_empty(): assert build_fuel_register_column_filters() == [] + + +def test_fuel_register_list_order_by_register_date_desc(): + from app.services.pl_vehicle_fuel_service import fuel_register_list_order + + compiled = " ".join(_compile(clause) for clause in fuel_register_list_order()) + assert compiled.index("register_date desc") < compiled.index("create_time desc") + assert compiled.index("create_time desc") < compiled.index("pl_vehicle_fuel_register.id desc") diff --git a/backend/tests/test_vehicle_fuel_schema.py b/backend/tests/test_vehicle_fuel_schema.py index 6408b58bf..c0d04dbbd 100644 --- a/backend/tests/test_vehicle_fuel_schema.py +++ b/backend/tests/test_vehicle_fuel_schema.py @@ -54,9 +54,36 @@ def test_create_accepts_shanxia_factory(): "registerDate": "2026-09-12", "licensePlate": "皖A12345", "fuelLiters": "1176", + "odometerKm": "0", } ) assert body.fuel_category == "shanxia_factory" + assert body.odometer_km == Decimal("0") + + +def test_create_rejects_missing_odometer(): + with pytest.raises(ValidationError): + VehicleFuelRegisterCreate.model_validate( + { + "fuelCategory": "bailian", + "registerDate": "2026-09-12", + "licensePlate": "皖A12345", + "fuelLiters": "10", + } + ) + + +def test_create_rejects_negative_odometer(): + with pytest.raises(ValidationError): + VehicleFuelRegisterCreate.model_validate( + { + "fuelCategory": "bailian", + "registerDate": "2026-09-12", + "licensePlate": "皖A12345", + "fuelLiters": "10", + "odometerKm": "-1", + } + ) def test_calc_fuel_tons(): diff --git a/miniprogram/pages/pl/fuel-register/form.vue b/miniprogram/pages/pl/fuel-register/form.vue index dfe37afbd..e69016e18 100644 --- a/miniprogram/pages/pl/fuel-register/form.vue +++ b/miniprogram/pages/pl/fuel-register/form.vue @@ -80,13 +80,14 @@ - 期初公里数/KM + 期初公里数/KM* @@ -267,6 +268,7 @@ const form = reactive({ const fieldErr = reactive({ registerDate: false, licensePlate: false, + odometerKm: false, fuelLiters: false }) @@ -334,6 +336,7 @@ function onDateChange(e) { function onOdometerInput(e) { form.odometerKm = e.detail.value + fieldErr.odometerKm = false } function onLitersInput(e) { @@ -439,6 +442,7 @@ function previewAt(idx) { function validate() { fieldErr.registerDate = false fieldErr.licensePlate = false + fieldErr.odometerKm = false fieldErr.fuelLiters = false if (!form.fuelCategory) { uni.showToast({ title: '请选择加油类别', icon: 'none' }) @@ -454,6 +458,18 @@ function validate() { uni.showToast({ title: '请选择车牌号', icon: 'none' }) return false } + const odoRaw = String(form.odometerKm ?? '').trim() + if (!odoRaw) { + fieldErr.odometerKm = true + uni.showToast({ title: '请输入期初公里数', icon: 'none' }) + return false + } + const odo = Number(odoRaw) + if (Number.isNaN(odo) || odo < 0) { + fieldErr.odometerKm = true + uni.showToast({ title: '期初公里数须为非负数字', icon: 'none' }) + return false + } const litersRaw = String(form.fuelLiters ?? '').trim() if (!litersRaw) { fieldErr.fuelLiters = true diff --git a/web-admin/src/views/pl/vehicle-fuel-register/FuelRegisterListPage.vue b/web-admin/src/views/pl/vehicle-fuel-register/FuelRegisterListPage.vue index 9959903aa..8e94a7c16 100644 --- a/web-admin/src/views/pl/vehicle-fuel-register/FuelRegisterListPage.vue +++ b/web-admin/src/views/pl/vehicle-fuel-register/FuelRegisterListPage.vue @@ -2,16 +2,7 @@