From 255028e983894517f1f552f05e3ac3ff680b1867 Mon Sep 17 00:00:00 2001 From: czl231 <3286836406@qq.com> Date: Sun, 16 Aug 2026 01:17:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=95=86=E5=9F=8E=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E6=A8=A1=E6=8B=9F=E5=BF=AB=E7=85=A7=E4=B8=8E=E7=A9=BA?= =?UTF-8?q?=E5=80=BC=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/internal/seed/mock.go | 103 ++++++++++++++---- backend/api/internal/seed/mock_test.go | 9 +- .../操作日志_商城订单列表展示修复_20260816.md | 7 +- docs/项目文档_平台资源中文展示统一_v1.0.md | 2 +- .../check-resource-display-contracts.mjs | 14 +++ frontend/platform_admin/src/api/resources.ts | 11 +- 6 files changed, 117 insertions(+), 29 deletions(-) diff --git a/backend/api/internal/seed/mock.go b/backend/api/internal/seed/mock.go index 2c909e8..3315fc5 100644 --- a/backend/api/internal/seed/mock.go +++ b/backend/api/internal/seed/mock.go @@ -312,14 +312,18 @@ func MockData(database *gorm.DB) error { ecOrder := models.EcOrder{ Entity: entity(30, common.StatusEnable), OrderStatus: mockEcOrderPaidStatus(), OrderNo: "MOCK-ECORDER-001", - UserAccountID: user.ID, GasStationID: gas.ID, DeliveryPointID: delivery.ID, + RequestNo: "MOCK-REQ-ECORDER-001", UserAccountID: user.ID, + GasStationID: gas.ID, DeliveryPointID: delivery.ID, UserAddressID: address.ID, + Address: address.Address, Longitude: address.Longitude, Latitude: address.Latitude, + ContactName: user.Name, ContactPhone: user.Phone, Remark: "模拟已支付商城订单", ProductAmount: ecProduct.PriceAmount, PayableAmount: ecProduct.PriceAmount, TotalAmount: ecProduct.PriceAmount, PaidAt: &now, } + desiredEcOrder := ecOrder if err := put(tx, &ecOrder); err != nil { return err } - if err := repairMockEcOrder(tx, ecOrder, mockEcOrderPaidStatus(), ecProduct.PriceAmount, &now); err != nil { + if err := repairMockEcOrder(tx, desiredEcOrder, mockEcOrderPaidStatus(), ecProduct.PriceAmount, &now); err != nil { return err } @@ -728,15 +732,19 @@ func seedAdditionalCoreScenarios(database *gorm.DB, passwordHash string, now tim ecOrder := models.EcOrder{ Entity: entity(sequence+16, common.StatusEnable), OrderStatus: mockEcOrderPendingStatus(), - OrderNo: "MOCK-ECORDER-" + suffix, UserAccountID: user.ID, - GasStationID: gas.ID, DeliveryPointID: delivery.ID, + OrderNo: "MOCK-ECORDER-" + suffix, RequestNo: "MOCK-REQ-ECORDER-" + suffix, + UserAccountID: user.ID, GasStationID: gas.ID, DeliveryPointID: delivery.ID, + UserAddressID: address.ID, Address: address.Address, + Longitude: address.Longitude, Latitude: address.Latitude, + ContactName: user.Name, ContactPhone: user.Phone, Remark: "模拟待支付商城订单", ProductAmount: ecProduct.PriceAmount, PayableAmount: ecProduct.PriceAmount, TotalAmount: ecProduct.PriceAmount, } + desiredEcOrder := ecOrder if err := put(database, &ecOrder); err != nil { return err } - if err := repairMockEcOrder(database, ecOrder, mockEcOrderPendingStatus(), ecProduct.PriceAmount, nil); err != nil { + if err := repairMockEcOrder(database, desiredEcOrder, mockEcOrderPendingStatus(), ecProduct.PriceAmount, nil); err != nil { return err } @@ -786,7 +794,11 @@ func repairMockEcOrder(database *gorm.DB, order models.EcOrder, status int, amou Where("identity = ? AND order_no LIKE ?", order.Identity, "MOCK-ECORDER-%"). Updates(map[string]any{ "order_status": status, "product_amount": amount, "payable_amount": amount, - "total_amount": amount, "paid_at": paidAt, + "total_amount": amount, "paid_at": paidAt, "request_no": order.RequestNo, + "user_address_id": order.UserAddressID, "address": order.Address, + "longitude": order.Longitude, "latitude": order.Latitude, + "contact_name": order.ContactName, "contact_phone": order.ContactPhone, + "remark": order.Remark, }) if result.Error != nil { return fmt.Errorf("repair mock ec order: %w", result.Error) @@ -795,30 +807,57 @@ func repairMockEcOrder(database *gorm.DB, order models.EcOrder, status int, amou } type mockEcOrderRepairSpec struct { - identity string - orderNo string - status int - amount int64 - paidAt *time.Time + identity string + orderNo string + requestNo string + userIdentity string + addressIdentity string + contactName string + contactPhone string + address string + longitude string + latitude string + status int + amount int64 + paidAt *time.Time + remark string } // mockEcOrderRepairSpecs 返回固定 Mock 商城订单的文档化交易状态与金额。 func mockEcOrderRepairSpecs() []mockEcOrderRepairSpec { paidAt := time.Date(2026, time.July, 1, 9, 0, 0, 0, time.Local) specs := []mockEcOrderRepairSpec{{ - identity: entity(30, common.StatusEnable).Identity, - orderNo: "MOCK-ECORDER-001", - status: mockEcOrderPaidStatus(), - amount: 10300, - paidAt: &paidAt, + identity: entity(30, common.StatusEnable).Identity, + orderNo: "MOCK-ECORDER-001", + requestNo: "MOCK-REQ-ECORDER-001", + userIdentity: entity(7, common.StatusEnable).Identity, + addressIdentity: entity(8, common.StatusEnable).Identity, + contactName: "陈女士", + contactPhone: "13800000001", + address: "上海市浦东新区客户路 88 号", + longitude: "121.5500", + latitude: "31.2250", + status: mockEcOrderPaidStatus(), + amount: 10300, + paidAt: &paidAt, + remark: "模拟已支付商城订单", }} for scenario := 2; scenario <= 10; scenario++ { sequence := 1000 + scenario*100 specs = append(specs, mockEcOrderRepairSpec{ - identity: entity(sequence+16, common.StatusEnable).Identity, - orderNo: fmt.Sprintf("MOCK-ECORDER-%03d", scenario), - status: mockEcOrderPendingStatus(), - amount: int64(9500 + scenario*100), + identity: entity(sequence+16, common.StatusEnable).Identity, + orderNo: fmt.Sprintf("MOCK-ECORDER-%03d", scenario), + requestNo: fmt.Sprintf("MOCK-REQ-ECORDER-%03d", scenario), + userIdentity: entity(sequence+4, common.StatusEnable).Identity, + addressIdentity: entity(sequence+5, common.StatusEnable).Identity, + contactName: fmt.Sprintf("示例客户%d", scenario), + contactPhone: "138" + fmt.Sprintf("%08d", scenario), + address: fmt.Sprintf("上海市客户路 %d 号", scenario), + longitude: fmt.Sprintf("121.5%03d", scenario), + latitude: fmt.Sprintf("31.2%03d", scenario), + status: mockEcOrderPendingStatus(), + amount: int64(9500 + scenario*100), + remark: "模拟待支付商城订单", }) } return specs @@ -829,12 +868,34 @@ func RepairMockEcOrders(database *gorm.DB) (int64, error) { var repaired int64 err := database.Transaction(func(tx *gorm.DB) error { for _, spec := range mockEcOrderRepairSpecs() { + var user models.UserAccount + if err := tx.Where("identity = ?", spec.userIdentity).First(&user).Error; err != nil { + return fmt.Errorf("load mock ec order user %s: %w", spec.orderNo, err) + } + if err := tx.Model(&user).Updates(map[string]any{ + "name": spec.contactName, "phone": spec.contactPhone, + }).Error; err != nil { + return fmt.Errorf("repair mock ec order user %s: %w", spec.orderNo, err) + } + var address models.UserAddress + if err := tx.Where("identity = ?", spec.addressIdentity).First(&address).Error; err != nil { + return fmt.Errorf("load mock ec order address %s: %w", spec.orderNo, err) + } + if err := tx.Model(&address).Updates(map[string]any{ + "address": spec.address, "longitude": spec.longitude, "latitude": spec.latitude, + }).Error; err != nil { + return fmt.Errorf("repair mock ec order address %s: %w", spec.orderNo, err) + } result := tx.Model(&models.EcOrder{}). Where("identity = ? AND order_no = ?", spec.identity, spec.orderNo). Updates(map[string]any{ "order_status": spec.status, "product_amount": spec.amount, "payable_amount": spec.amount, "total_amount": spec.amount, - "paid_at": spec.paidAt, + "paid_at": spec.paidAt, "request_no": spec.requestNo, + "user_address_id": address.ID, "address": spec.address, + "longitude": spec.longitude, "latitude": spec.latitude, + "contact_name": spec.contactName, "contact_phone": spec.contactPhone, + "remark": spec.remark, }) if result.Error != nil { return fmt.Errorf("repair mock ec order %s: %w", spec.orderNo, result.Error) diff --git a/backend/api/internal/seed/mock_test.go b/backend/api/internal/seed/mock_test.go index 4c0b6a2..a5b6859 100644 --- a/backend/api/internal/seed/mock_test.go +++ b/backend/api/internal/seed/mock_test.go @@ -117,10 +117,17 @@ func TestMockEcOrderRepairSpecs(t *testing.T) { t.Fatalf("首条已支付 Mock 订单修复配置错误:%#v", specs[0]) } for _, spec := range specs[1:] { - if spec.status != 16 || spec.paidAt != nil || spec.amount <= 0 { + if spec.status != 16 || spec.paidAt != nil || spec.amount <= 0 || + spec.contactName == "" || spec.contactPhone == "" || spec.address == "" || + spec.longitude == "" || spec.latitude == "" { t.Fatalf("待支付 Mock 订单修复配置错误:%#v", spec) } } + last := specs[len(specs)-1] + if last.contactName != "示例客户10" || last.address != "上海市客户路 10 号" || + last.longitude != "121.5010" || last.latitude != "31.2010" { + t.Fatalf("第十组 Mock 快照格式错误:%#v", last) + } } // TestMockTrackPointSampleRequiredFields 验证演示轨迹点符合真实上报的必填字段和可读展示要求。 diff --git a/docs/操作日志_商城订单列表展示修复_20260816.md b/docs/操作日志_商城订单列表展示修复_20260816.md index 0b086df..e9bd471 100644 --- a/docs/操作日志_商城订单列表展示修复_20260816.md +++ b/docs/操作日志_商城订单列表展示修复_20260816.md @@ -19,8 +19,11 @@ 3. 将 Mock 待支付订单从 `10` 修复为 `16`,已支付订单从 `35` 修复为 `18`。 4. 补齐 Mock 订单商品金额、应付金额及已支付订单的支付时间。 5. 待支付订单的空支付时间明确显示为“未支付”,不再显示无语义短横线。 -6. 增加独立幂等修复命令,只更新固定十条商城 Mock 订单。 -7. 增加前端展示契约与后端种子测试,防止跨领域状态再次混入商城订单。 +6. 补齐 Mock 订单的请求流水号、地址、经纬度、联系人、联系电话和备注快照。 +7. 修复第十组既有 Mock 用户名称、电话、地址及经纬度的错误值。 +8. 待发货、未收货及无备注字段使用明确业务文案,不再统一显示短横线。 +9. 增加独立幂等修复命令,只更新固定十条商城 Mock 订单及其用户、地址快照来源。 +10. 增加前端展示契约与后端种子测试,防止跨领域状态再次混入商城订单。 ## 行为变化 diff --git a/docs/项目文档_平台资源中文展示统一_v1.0.md b/docs/项目文档_平台资源中文展示统一_v1.0.md index 8b2cfa6..dfb2db3 100644 --- a/docs/项目文档_平台资源中文展示统一_v1.0.md +++ b/docs/项目文档_平台资源中文展示统一_v1.0.md @@ -65,4 +65,4 @@ frontend/platform_admin/ - v1.2:树形资源统一改为树形表格,明确展示名称、排序、状态、系统标识和操作,唯一标识降级为复制入口。 - v1.2.1:补齐 Arco 表格 `columns` 插槽,修复树形表格容器存在但列和数据不渲染的问题。 - v1.3:购物车列表的用户与商品关系列统一展示可读名称,UUID 降级为复制和排障信息。 -- v1.4:商城订单列表统一展示用户名称,未支付时间明确显示“未支付”;Mock 订单改用商城独立交易状态,并补齐金额与支付时间。 +- v1.4:商城订单统一展示用户名称及空值业务文案;Mock 订单改用商城独立交易状态,并补齐金额、支付时间和下单快照。 diff --git a/frontend/platform_admin/scripts/check-resource-display-contracts.mjs b/frontend/platform_admin/scripts/check-resource-display-contracts.mjs index baa9c00..1e908c2 100644 --- a/frontend/platform_admin/scripts/check-resource-display-contracts.mjs +++ b/frontend/platform_admin/scripts/check-resource-display-contracts.mjs @@ -136,6 +136,20 @@ for (const invalidStatus of [10, 35]) { if (!orderDefinition.includes("f('paid_at', { emptyText: '未支付' })")) { throw new Error('商城订单空支付时间必须明确显示为未支付'); } +for (const displayContract of [ + "f('request_no', { emptyText: '未记录' })", + "f('contact_name', { emptyText: '未记录' })", + "f('contact_phone', { emptyText: '未记录' })", + "f('logistics_no', { emptyText: '未发货' })", + "f('logistics_company', { emptyText: '未发货' })", + "f('shipped_at', { emptyText: '未发货' })", + "f('received_at', { emptyText: '未收货' })", + "f('remark', { emptyText: '无备注' })", +]) { + if (!orderDefinition.includes(displayContract)) { + throw new Error(`商城订单详情缺少空值业务文案:${displayContract}`); + } +} if (/title="ID"|data-index="id"/.test(listPage)) { throw new Error('标准资源列表不得把数据库ID作为业务列展示'); diff --git a/frontend/platform_admin/src/api/resources.ts b/frontend/platform_admin/src/api/resources.ts index c2e9f7f..4076f76 100644 --- a/frontend/platform_admin/src/api/resources.ts +++ b/frontend/platform_admin/src/api/resources.ts @@ -706,7 +706,7 @@ export const resources: ResourceUiDefinition[] = [ f('quantity'), f('selected'), ]), define('ec_order', '商城订单', 'readonly', [ - f('order_no'), f('request_no'), f('order_status', { type: 'select', options: [ + f('order_no'), f('request_no', { emptyText: '未记录' }), f('order_status', { type: 'select', options: [ { label: '待支付', value: 16 }, { label: '已支付', value: 18 }, { label: '已取消', value: 22 }, @@ -716,9 +716,12 @@ export const resources: ResourceUiDefinition[] = [ displayRelationLabel: true, showIdentityCopy: true, }), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('user_address_identity', '/user_address'), - f('contact_name'), f('contact_phone'), f('product_amount'), f('discount_amount'), f('payable_amount'), - f('total_amount'), f('paid_at', { emptyText: '未支付' }), f('logistics_no'), f('logistics_company'), f('logistics_status'), - f('shipped_at'), f('received_at'), f('remark'), + f('contact_name', { emptyText: '未记录' }), f('contact_phone', { emptyText: '未记录' }), + f('product_amount'), f('discount_amount'), f('payable_amount'), + f('total_amount'), f('paid_at', { emptyText: '未支付' }), + f('logistics_no', { emptyText: '未发货' }), f('logistics_company', { emptyText: '未发货' }), + f('logistics_status'), f('shipped_at', { emptyText: '未发货' }), + f('received_at', { emptyText: '未收货' }), f('remark', { emptyText: '无备注' }), ]), define('ec_order_item', '商城订单明细', 'readonly', [ relation('ec_order_identity', '/ec_order'), relation('ec_product_identity', '/ec_product'),