订单列表
订单列表
用户订单分页查询
creator { id }
: 包含创建者的ID信息,可以按照创建者ID来筛选订单。
使用这个规格(Specification)进行查询时,可以根据用户提供的参数,灵活查询满足条件的所有订单记录,比如按订单备注部分文本、创建和修改时间范围以及创建者ID来过滤订单。
specification ProductOrderSpec {
#allScalars
like/i(remark)
like/i(id)
ge(createdTime)
le(createdTime)
ge(editedTime)
le(editedTime)
creator {
id
}
}
ProductOrderFetcher.COMPLEX_FETCHER
:创建了一个名为COMPLEX_FETCHER
的复杂加载器,用于加载商品订单的详细信息。.allScalarFields()
:表示加载所有标量字段(如字符串、数字等基本属性)。.items(ProductOrderItemFetcher.$...)
:针对每个商品订单中的items
(即商品订单项列表),进一步加载其相关联的详细信息:.productSku(ProductSkuFetcher.$...)
:加载每个商品订单项对应的ProductSku
(商品SKU)信息,并进一步加载它的所有标量字段以及与其关联的:.product(ProductFetcher.$.allScalarFields())
:加载商品SKU所属的商品详细信息。
.skuCount()
:加载商品订单项的数量。
.address(AddressFetcher.$.allScalarFields())
:加载与订单关联的地址信息及其所有标量字段。.payment(PaymentFetcher.$.allScalarFields())
:加载与订单关联的支付详情及其所有标量字段。.creator(UserFetcher.$.phone().nickname())
和.editor(UserFetcher.$.phone().nickname())
:分别加载创建和编辑此订单的用户的电话号码和昵称。
COMPLEX_FETCHER
能够根据需要一次性从数据库加载商品订单及其相关实体(如商品SKU、商品、地址、支付详情、用户信息等)的完整信息,以提高数据读取效率,减少网络请求次数。
public interface ProductOrderRepository extends JRepository<ProductOrder, String> {
ProductOrderFetcher COMPLEX_FETCHER = ProductOrderFetcher.$.allScalarFields()
.items(ProductOrderItemFetcher.$
.productSku(ProductSkuFetcher.$
.allScalarFields()
.product(ProductFetcher.$.allScalarFields()))
.skuCount())
.address(AddressFetcher.$.allScalarFields())
.payment(PaymentFetcher.$.allScalarFields())
.creator(UserFetcher.$.phone().nickname())
.editor(UserFetcher.$.phone().nickname());
}
方法参数:
@RequestBody QueryRequest<ProductOrderSpec> queryRequest
:通过@RequestBody
注解接收请求体中的JSON数据,并将其反序列化为QueryRequest
对象,其中泛型类型是ProductOrderSpec
,即订单查询规格对象,包含了查询条件和分页信息等。
在方法内部:
- 创建一个
TargetOf_creator
对象(ProductOrderSpec中定义的Creator),并使用StpUtil.getLoginIdAsString()
获取当前登录用户的ID(SaToken)。 - 将这个用户ID设置到订单查询规格的创建者字段上,这样在执行查询时,将会筛选出由当前登录用户创建的订单。
- 创建一个
调用
productOrderService.query(queryRequest)
:传入已设置好查询条件和分页信息的queryRequest
对象,用于执行数据库查询操作。返回值类型为
Page<@FetchBy(value = "COMPLEX_FETCHER") ProductOrder>
:返回的是一个分页结果集,并用@FetcherBy
声明返回类型,这样前端在同步API时可以根据COMPLEX_FETCHER
中查询的内容获得类型,即订单的详细信息,如商品SKU、地址、支付详情以及与订单创建和编辑相关的用户信息等。
用户ID查询其创建的商品订单记录
@RestController
@RequestMapping("productOrder")
@AllArgsConstructor
@DefaultFetcherOwner(ProductOrderRepository.class)
public class ProductOrderController {
private final ProductOrderService productOrderService;
@PostMapping("user")
public Page<@FetchBy(value = "COMPLEX_FETCHER") ProductOrder> queryByUser(
@RequestBody QueryRequest<ProductOrderSpec> queryRequest) {
TargetOf_creator targetOfCreator = new TargetOf_creator();
targetOfCreator.setId(StpUtil.getLoginIdAsString());
queryRequest.getQuery().setCreator(targetOfCreator);
return productOrderService.query(queryRequest);
}
}
路由配置
export default defineAppConfig({
pages: [
"pages/index/index",
"pages/user/index",
"pages/address/address-list",
"pages/address/address-save",
"pages/order/order-create",
"pages/order/order-list",
],
});
订单列表页面
小程序端字典
import type { DictSpec, Page } from "@/apis/__generated/model/static";
import type { DictDto } from "@/apis/__generated/model/dto";
import { api } from "@/utils/api-instance";
const dictMap: Record<
number,
Promise<Page<DictDto["DictRepository/COMPLEX_FETCHER"]>>
> = {};
export const queryDict = (dictSpec: DictSpec) => {
if (!dictSpec.dictId) return;
let res = dictMap[dictSpec.dictId];
if (res) return res;
res = api.dictController.query({
body: {
pageNum: 1,
pageSize: 1000,
likeMode: "ANYWHERE",
query: dictSpec,
sorts: [{ property: "dictId", direction: "ASC" }],
},
});
dictMap[dictSpec.dictId] = res;
return res;
};
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import type { DictDto } from "@/apis/__generated/model/dto";
import { queryDict } from "@/components/dict/dict";
const props = withDefaults(defineProps<{ dictId: number; value?: string }>(), {
value: "",
});
const options = ref<DictDto["DictRepository/COMPLEX_FETCHER"][]>([]);
onMounted(async () => {
const res = queryDict({ dictId: props.dictId });
if (res) {
options.value = (await res).content;
}
});
const keyName = computed(() => {
const option = options.value.find((option) => {
return option.keyEnName === props.value;
});
return option ? option.keyName : "";
});
</script>
<template>
<div>{{ keyName }}</div>
</template>
<style scoped lang="scss"></style>
订单展示
<div class="order-list-page">
:定义一个包裹整个订单列表内容的容器,类名为"order-list-page"。使用
v-for
指令遍历从pageData.content
获取的所有订单数据:<div class="order" v-for="order in pageData.content" :key="order.id">
这里对每个订单项创建一个新的
.order
元素。在循环内部,使用自定义组件
order-row
来展示每个订单的详细信息,并将当前订单对象作为属性值传递给该组件:<order-row :order="order" @click="switchPage('./order-details?id=' + order.id)">
当用户点击这个订单行时,会触发
switchPage
事件处理器方法,跳转到对应的订单详情页,URL中包含了当前订单ID。根据订单状态动态显示按钮:
- 如果满足
showCancel(order.status)
条件,则显示“取消订单”按钮。 - 如果订单状态为
'TO_BE_PAID'
,则显示“立即支付”按钮。
- 如果满足
<template>
<div class="order-list-page">
<div class="order" v-for="order in pageData.content" :key="order.id">
<order-row
:order="order"
@click="switchPage('./order-details?id=' + order.id)"
>
<nut-button size="small" plain v-if="showCancel(order.status)"
>取消订单</nut-button
>
<nut-button
size="small"
type="danger"
plain
v-if="order.status === 'TO_BE_PAID'"
>立即支付</nut-button
>
</order-row>
</div>
</div>
</template>
导入所需模块:
usePageHelper
:来自项目内部的工具函数,通常用来处理分页数据的获取、加载更多等功能。api
:导入自定义API实例,封装了与后端接口交互的方法。OrderRow
:导入自定义组件OrderRow.vue
,用于在订单列表中展示每个订单的详情行。ProductOrderStatus
:从后端生成的类型文件中导入订单状态枚举。switchPage
:一个跳转页面的通用工具函数。
使用
usePageHelper
钩子来获取当前用户相关的订单数据,并进行分页处理:const { pageData } = usePageHelper( api.productOrderController.queryByUser, api.productOrderController, {}, );
这里传入了两个参数:
- 第一个参数是调用后端查询当前用户订单的API方法(
queryByUser
)。 - 第二个
api.productOrderController
用于绑定查询方法的上下文, 即this
指向当前组件实例。 - 第三个参数是一个空对象,代表请求时需要传递给API的初始查询参数。
- 第一个参数是调用后端查询当前用户订单的API方法(
定义一个辅助函数
showCancel
,根据订单状态判断是否显示“取消订单”按钮:const showCancel = (status: ProductOrderStatus) => { return status === "TO_BE_PAID" || status === "TO_BE_DELIVERED"; };
当订单状态为“待支付”或“待发货”时,此函数会返回
true
,表示允许用户操作取消订单。
import { usePageHelper } from "@/utils/page";
import { api } from "@/utils/api-instance";
import OrderRow from "@/components/order/order-row.vue";
import { ProductOrderStatus } from "@/apis/__generated/model/enums";
import { switchPage } from "@/utils/common";
const { pageData } = usePageHelper(
api.productOrderController.queryByUser,
api.productOrderController,
{},
);
const showCancel = (status: ProductOrderStatus) => {
return status === "TO_BE_PAID" || status === "TO_BE_DELIVERED";
};
page {
background-color: #f5f5f5;
}