完善配送订单列表可读信息
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// 功能描述:实现配送点范围内的合同、合同气瓶和配送订单接口。
|
// 功能描述:实现配送点范围内的合同、合同气瓶和配送订单接口。
|
||||||
// 版本:v1.2.0。
|
// 版本:v1.3.0。
|
||||||
package delivery
|
package delivery
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -364,10 +364,30 @@ func scopedOrder(ctx *gin.Context, identity string, pointID uint64) (models.Gaso
|
|||||||
|
|
||||||
func ListOrder(ctx *gin.Context) {
|
func ListOrder(ctx *gin.Context) {
|
||||||
point, _, ok := currentScope(ctx)
|
point, _, ok := currentScope(ctx)
|
||||||
if ok {
|
if !ok {
|
||||||
listScoped(ctx, &models.GasorderBasic{}, common.ActiveRecords(db().Model(&models.GasorderBasic{})).
|
return
|
||||||
Where("delivery_basic_id = ?", point.ID), "gasorder_basic.created_at desc")
|
|
||||||
}
|
}
|
||||||
|
page, size := common.PageSize(ctx)
|
||||||
|
query := common.ApplyKeywordFilter(ctx,
|
||||||
|
common.ActiveRecords(db().Model(&models.GasorderBasic{})).Where("delivery_basic_id = ?", point.ID),
|
||||||
|
&models.GasorderBasic{},
|
||||||
|
)
|
||||||
|
var total int64
|
||||||
|
if err := query.Count(&total).Error; err != nil {
|
||||||
|
infra.Response.Error(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var orders []models.GasorderBasic
|
||||||
|
if err := query.Order("gasorder_basic.created_at desc").Offset((page - 1) * size).Limit(size).Find(&orders).Error; err != nil {
|
||||||
|
infra.Response.Error(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response, err := platformgasorder.BuildGasorderListResponse(ctx, orders)
|
||||||
|
if err != nil {
|
||||||
|
infra.Response.Error(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
infra.Response.Success(ctx, gin.H{"total": total, "list": response})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetOrder(ctx *gin.Context) {
|
func GetOrder(ctx *gin.Context) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// 功能描述:为平台配送订单列表与详情补充关联名称、地址和合同气瓶摘要。
|
// 功能描述:为平台配送订单列表与详情补充关联名称、地址和合同气瓶摘要。
|
||||||
// 版本:v1.1.0
|
// 版本:v1.2.0
|
||||||
package gasorder
|
package gasorder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -62,18 +62,27 @@ func ListGasorderBasic(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
displays, err := buildGasorderListDisplays(orders)
|
response, err := BuildGasorderListResponse(ctx, orders)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
infra.Response.Success(ctx, gin.H{"total": total, "list": response})
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildGasorderListResponse 为已经完成数据范围筛选的订单构造安全、可读的管理端列表响应。
|
||||||
|
// 调用方必须先限定自身可见订单;本函数只补充派生名称、气瓶摘要并恢复订单地址快照。
|
||||||
|
func BuildGasorderListResponse(ctx *gin.Context, orders []models.GasorderBasic) (any, error) {
|
||||||
|
displays, err := buildGasorderListDisplays(orders)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
response, err := common.PublicResourceResponse(displays)
|
response, err := common.PublicResourceResponse(displays)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
return nil, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
protected := common.ProtectPreciseLocation(ctx, &models.GasorderBasic{}, response)
|
protected := common.ProtectPreciseLocation(ctx, &models.GasorderBasic{}, response)
|
||||||
infra.Response.Success(ctx, gin.H{"total": total, "list": restoreGasorderListAddresses(protected, orders)})
|
return restoreGasorderListAddresses(protected, orders), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildGasorderListDisplays 批量读取创建方与有效订单气瓶,避免列表逐行查询。
|
// buildGasorderListDisplays 批量读取创建方与有效订单气瓶,避免列表逐行查询。
|
||||||
|
|||||||
40
docs/操作日志_配送点订单列表可读信息_20260825.md
Normal file
40
docs/操作日志_配送点订单列表可读信息_20260825.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# 操作日志:配送点订单列表可读信息
|
||||||
|
|
||||||
|
操作时间:2026-08-25
|
||||||
|
操作类型:扩展、修改
|
||||||
|
影响模块:5176 配送订单列表、配送订单列表接口
|
||||||
|
|
||||||
|
## 操作前状态
|
||||||
|
|
||||||
|
- 收货地址快照经过通用位置保护后,列表显示为 `-`。
|
||||||
|
- 合同气瓶属于订单明细集合,通用列表响应没有可读摘要。
|
||||||
|
- 5173 已有受控地址恢复和气瓶摘要,但 5176 仍使用通用列表函数。
|
||||||
|
|
||||||
|
## 具体操作
|
||||||
|
|
||||||
|
1. 把 5173 已有订单列表展示构造过程封装为共享函数。
|
||||||
|
2. 配送端先限定当前配送点订单,再调用共享函数生成安全响应。
|
||||||
|
3. 前端字段声明读取 `address` 和 `contract_products_summary` 派生字段。
|
||||||
|
4. 合同气瓶摘要增加订单详情入口,空值统一显示“未填写”。
|
||||||
|
5. 增加静态契约检查,防止以后退回裸关联字段或横线展示。
|
||||||
|
|
||||||
|
## 行为变化
|
||||||
|
|
||||||
|
- 变更前:收货地址和合同气瓶均显示 `-`。
|
||||||
|
- 变更后:地址显示订单快照;气瓶显示可读摘要并可进入订单详情。
|
||||||
|
- 兼容性:不修改数据库、创建订单请求和既有路由,只扩展已鉴权列表响应。
|
||||||
|
|
||||||
|
## 验证结果
|
||||||
|
|
||||||
|
- `go test ./api/internal/logic/delivery ./api/internal/logic/platform/gasorder`:通过。
|
||||||
|
- `npm.cmd run type:check`:通过。
|
||||||
|
- `npm.cmd run resource-pages:check`:通过,详情 17、新建 9、编辑 5。
|
||||||
|
- `npm.cmd run contract:check`:通过,18 个资源。
|
||||||
|
- `npm.cmd run build`:通过,2648 个模块完成生产构建。
|
||||||
|
- 后端已重新构建并恢复监听 `12426`,旧程序已备份为 `platform-api.before-order-list-20260825-232713.exe`。
|
||||||
|
|
||||||
|
## 风险评估
|
||||||
|
|
||||||
|
- 地址属于敏感数据:仅对当前配送点已授权订单恢复快照,不影响公共接口。
|
||||||
|
- 气瓶当前名称可能随设备档案改名变化;类型和编码仍使用订单快照。
|
||||||
|
- 完整气瓶信息继续以订单详情为准,列表只提供紧凑摘要。
|
||||||
43
docs/项目文档_配送点订单列表可读信息_v1.0.md
Normal file
43
docs/项目文档_配送点订单列表可读信息_v1.0.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# 项目文档:配送点订单列表可读信息 v1.0
|
||||||
|
|
||||||
|
## 1. 项目概述
|
||||||
|
|
||||||
|
5176 配送点管理端订单列表复用 5173 的受控展示规则,在当前配送点数据范围内显示订单收货地址快照和合同气瓶摘要。数据库、订单创建协议及通用敏感字段保护规则保持不变。
|
||||||
|
|
||||||
|
## 2. 核心实现
|
||||||
|
|
||||||
|
```text
|
||||||
|
backend/api/internal/logic/
|
||||||
|
├── delivery/order.go # 先限定当前配送点,再构造订单列表响应
|
||||||
|
└── platform/gasorder/order_list_display.go # 统一生成地址和气瓶可读摘要
|
||||||
|
frontend/delivery_admin/src/
|
||||||
|
├── api/resources.ts # 声明列表派生展示字段
|
||||||
|
└── views/shared/ResourceListPage.vue # 渲染只读摘要和详情入口
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 展示规则
|
||||||
|
|
||||||
|
- 收货地址显示订单创建时保存的地址快照;空快照显示“未填写”。
|
||||||
|
- 合同气瓶显示第一只气瓶的当前智能气阀名称和下单时类型快照;多只气瓶追加“等 N 个”。
|
||||||
|
- 合同气瓶摘要可进入订单详情查看完整明细。
|
||||||
|
- 地址和气瓶摘要均为只读派生字段,不参与新建或业务动作提交。
|
||||||
|
|
||||||
|
## 4. 安全边界
|
||||||
|
|
||||||
|
- 配送端必须先按当前登录账号所属配送点筛选订单,再调用共享展示构造器。
|
||||||
|
- 地址恢复只作用于已经鉴权、已经完成配送点范围过滤的订单分页结果。
|
||||||
|
- 气瓶摘要只按当前页订单主键批量查询,不接受前端提供任意订单主键。
|
||||||
|
- 通用资源响应的地址、经纬度保护规则不变。
|
||||||
|
|
||||||
|
## 5. 验证
|
||||||
|
|
||||||
|
```text
|
||||||
|
go test ./api/internal/logic/delivery ./api/internal/logic/platform/gasorder
|
||||||
|
npm.cmd run type:check
|
||||||
|
npm.cmd run resource-pages:check
|
||||||
|
npm.cmd run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 变更记录
|
||||||
|
|
||||||
|
- v1.0(2026-08-25):修复配送点订单列表收货地址和合同气瓶显示为横线的问题。
|
||||||
@@ -138,5 +138,9 @@ assert(recordPage.includes('if (saving.value) return'), '订单保存缺少显
|
|||||||
assert(orderCreation.includes('productAmount + deliveryFee - discountAmount'), '订单金额预估公式不正确');
|
assert(orderCreation.includes('productAmount + deliveryFee - discountAmount'), '订单金额预估公式不正确');
|
||||||
assert(orderCreation.includes("优惠金额必须小于商品金额与配送费之和"), '优惠金额缺少应付金额正数校验');
|
assert(orderCreation.includes("优惠金额必须小于商品金额与配送费之和"), '优惠金额缺少应付金额正数校验');
|
||||||
assert(orderPreview.includes('金额仅供预览'), '订单金额预估未声明服务端最终计算');
|
assert(orderPreview.includes('金额仅供预览'), '订单金额预估未声明服务端最终计算');
|
||||||
|
assert(definitions.includes("listDisplayKey: 'address'"), '订单列表收货地址未使用受控地址快照');
|
||||||
|
assert(definitions.includes("listDisplayKey: 'contract_products_summary'"), '订单列表合同气瓶未使用可读摘要');
|
||||||
|
assert(listPage.includes('function displayListField'), '资源列表未支持后端派生展示字段');
|
||||||
|
assert(listPage.includes('field.listDetailLink'), '订单气瓶摘要缺少详情入口');
|
||||||
|
|
||||||
console.log(`独立资源页面契约通过:详情 ${listResources.length},新建 ${creatable.size},编辑 ${editable.size}`);
|
console.log(`独立资源页面契约通过:详情 ${listResources.length},新建 ${creatable.size},编辑 ${editable.size}`);
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ export type ResourceField = {
|
|||||||
listCopyable?: boolean;
|
listCopyable?: boolean;
|
||||||
/** 关联选项优先展示的业务字段。 */
|
/** 关联选项优先展示的业务字段。 */
|
||||||
relationOptionLabelKey?: string;
|
relationOptionLabelKey?: string;
|
||||||
|
/** 列表使用后端派生的只读展示字段,不改变提交字段。 */
|
||||||
|
listDisplayKey?: string;
|
||||||
|
/** 列表摘要可直接进入当前记录详情。 */
|
||||||
|
listDetailLink?: boolean;
|
||||||
/** 合同气瓶等关系的组合展示方式。 */
|
/** 合同气瓶等关系的组合展示方式。 */
|
||||||
relationOptionDisplay?: 'product-name-type';
|
relationOptionDisplay?: 'product-name-type';
|
||||||
/** 为默认候选追加中文标识,并在加载完成后自动选择。 */
|
/** 为默认候选追加中文标识,并在加载完成后自动选择。 */
|
||||||
@@ -564,6 +568,9 @@ const deliveryOverrides: ResourceUiDefinition[] = [
|
|||||||
}),
|
}),
|
||||||
relation('user_address_identity', '/user_address', true, {
|
relation('user_address_identity', '/user_address', true, {
|
||||||
label: '收货地址',
|
label: '收货地址',
|
||||||
|
listDisplayKey: 'address',
|
||||||
|
listDetailLink: false,
|
||||||
|
emptyText: '未填写',
|
||||||
placeholder: '请先选择配送合同,再选择该合同用户的收货地址',
|
placeholder: '请先选择配送合同,再选择该合同用户的收货地址',
|
||||||
relationOptionLabelKey: 'address',
|
relationOptionLabelKey: 'address',
|
||||||
relationOptionDefaultKey: 'is_default',
|
relationOptionDefaultKey: 'is_default',
|
||||||
@@ -581,6 +588,9 @@ const deliveryOverrides: ResourceUiDefinition[] = [
|
|||||||
required: true,
|
required: true,
|
||||||
type: 'identity-list',
|
type: 'identity-list',
|
||||||
relation: '/gasorder_contract_product',
|
relation: '/gasorder_contract_product',
|
||||||
|
listDisplayKey: 'contract_products_summary',
|
||||||
|
listDetailLink: true,
|
||||||
|
emptyText: '未填写',
|
||||||
placeholder: '请输入智能气阀名称、气瓶类型或气瓶编码搜索',
|
placeholder: '请输入智能气阀名称、气瓶类型或气瓶编码搜索',
|
||||||
relationOptionDisplay: 'product-name-type',
|
relationOptionDisplay: 'product-name-type',
|
||||||
relationEmptyText: '该合同暂无可用气瓶,请先为合同绑定气瓶',
|
relationEmptyText: '该合同暂无可用气瓶,请先为合同绑定气瓶',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- 功能描述:展示配送点标准资源列表并导航到独立记录页。版本:v1.1.0。 -->
|
<!-- 功能描述:展示配送点标准资源列表并导航到独立记录页。版本:v1.2.0。 -->
|
||||||
<template>
|
<template>
|
||||||
<a-card :title="listTitle" :bordered="false">
|
<a-card :title="listTitle" :bordered="false">
|
||||||
<template v-if="isCredentialList" #extra>
|
<template v-if="isCredentialList" #extra>
|
||||||
@@ -75,11 +75,15 @@
|
|||||||
@click="previewListContractAttachment(record)"
|
@click="previewListContractAttachment(record)"
|
||||||
>查看附件</a-button>
|
>查看附件</a-button>
|
||||||
<span v-else-if="field.type === 'contract-file'">暂无附件</span>
|
<span v-else-if="field.type === 'contract-file'">暂无附件</span>
|
||||||
|
<a-link v-else-if="field.listDetailLink" @click="openRecord('detail', record)">
|
||||||
|
{{ displayListField(field, record) }}
|
||||||
|
</a-link>
|
||||||
|
<template v-else-if="field.listDisplayKey">{{ displayListField(field, record) }}</template>
|
||||||
<IdentityText
|
<IdentityText
|
||||||
v-else-if="(field.type === 'identity' || field.listCopyable) && fieldValue(field, record)"
|
v-else-if="(field.type === 'identity' || field.listCopyable) && fieldValue(field, record)"
|
||||||
:value="fieldValue(field, record)"
|
:value="fieldValue(field, record)"
|
||||||
/>
|
/>
|
||||||
<template v-else>{{ displayResourceValue(definition, field.key, record[field.key] ?? record[`${field.key}_masked`]) }}</template>
|
<template v-else>{{ displayListField(field, record) }}</template>
|
||||||
</template>
|
</template>
|
||||||
</a-table-column>
|
</a-table-column>
|
||||||
<a-table-column title="状态" :width="100">
|
<a-table-column title="状态" :width="100">
|
||||||
@@ -245,6 +249,19 @@ function fieldValue(field: ResourceField, row: ResourceRow) {
|
|||||||
return String(row[field.key] ?? row[`${field.key}_masked`] ?? '');
|
return String(row[field.key] ?? row[`${field.key}_masked`] ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 优先使用后端受控派生字段展示列表摘要,空值使用字段业务文案。 */
|
||||||
|
function displayListField(field: ResourceField, row: ResourceRow) {
|
||||||
|
if (field.listDisplayKey) {
|
||||||
|
const value = row[field.listDisplayKey];
|
||||||
|
return value == null || value === '' ? (field.emptyText ?? '-') : String(value);
|
||||||
|
}
|
||||||
|
return displayResourceValue(
|
||||||
|
props.definition,
|
||||||
|
field.key,
|
||||||
|
row[field.key] ?? row[`${field.key}_masked`],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** 加载当前列表和来源关系筛选。 */
|
/** 加载当前列表和来源关系筛选。 */
|
||||||
async function load() {
|
async function load() {
|
||||||
avatarLoader.reset();
|
avatarLoader.reset();
|
||||||
|
|||||||
Reference in New Issue
Block a user