浏览代码

feat(system): 添加实物商城订单管理功能

- 新增订单主表API接口包括查询、详情、新增、修改、删除功能
- 新增订单明细表API接口包括查询、详情、新增、修改、删除功能
- 实现订单管理页面界面包含搜索、分页、表格展示功能
- 集成订单明细展开显示功能支持查看订单内商品详情
- 添加订单状态显示功能支持不同状态的颜色标识
- 实现订单地址修改、订单编辑、订单删除等交互功能
fugui001 2 周之前
父节点
当前提交
ec86804e1a

+ 63 - 0
src/api/system/physical/order/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { OrderVO, OrderForm, OrderQuery } from '@/api/system/physical/order/types';
+
+/**
+ * 查询商城订单主列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listOrder = (query?: OrderQuery): AxiosPromise<OrderVO[]> => {
+  return request({
+    url: '/physical/order/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询商城订单主详细
+ * @param id
+ */
+export const getOrder = (id: string | number): AxiosPromise<OrderVO> => {
+  return request({
+    url: '/physical/order/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增商城订单主
+ * @param data
+ */
+export const addOrder = (data: OrderForm) => {
+  return request({
+    url: '/physical/order',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改商城订单主
+ * @param data
+ */
+export const updateOrder = (data: OrderForm) => {
+  return request({
+    url: '/physical/order',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除商城订单主
+ * @param id
+ */
+export const delOrder = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/physical/order/' + id,
+    method: 'delete'
+  });
+};

+ 207 - 0
src/api/system/physical/order/types.ts

@@ -0,0 +1,207 @@
+import { OrderItemVO } from '@/api/system/physical/orderItem/types';
+
+export interface OrderVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 用户昵称
+   */
+  userNickname: string;
+
+  /**
+   * 真实姓名
+   */
+  userRealName: string;
+
+  /**
+   * 身份证号
+   */
+  userIdCard: string | number;
+
+  /**
+   * 账号ID(关联用户表)
+   */
+  userAccountId: string | number;
+
+  /**
+   * 用户收货地址(省市区+详细地址)
+   */
+  userAddress: string;
+
+  /**
+   * 订单编号(唯一)
+   */
+  orderSn: string;
+
+  /**
+   * 订单总金额(元)
+   */
+  totalAmount: number;
+
+  /**
+   * 订单状态:pending_payment=待支付, paid=已支付, shipped=已发货, completed=已完成, cancelled=已取消
+   */
+  status: string;
+
+  /**
+   * 创建人
+   */
+  createdBy: string;
+
+  /**
+   * 创建时间
+   */
+  createdAt: string;
+
+  /**
+   * 最后更新人
+   */
+  updatedBy: string;
+
+  /**
+   * 最后更新时间
+   */
+  updatedAt: string;
+
+  /**
+   * 商品列表
+   */
+  physicalOrderItemVoList?: OrderItemVO[];
+}
+
+export interface OrderForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 用户昵称
+   */
+  userNickname?: string;
+
+  /**
+   * 真实姓名
+   */
+  userRealName?: string;
+
+  /**
+   * 身份证号
+   */
+  userIdCard?: string | number;
+
+  /**
+   * 账号ID(关联用户表)
+   */
+  userAccountId?: string | number;
+
+  /**
+   * 用户收货地址(省市区+详细地址)
+   */
+  userAddress?: string;
+
+  /**
+   * 订单编号(唯一)
+   */
+  orderSn?: string;
+
+  /**
+   * 订单总金额(元)
+   */
+  totalAmount?: number;
+
+  /**
+   * 订单状态:pending_payment=待支付, paid=已支付, shipped=已发货, completed=已完成, cancelled=已取消
+   */
+  status?: string;
+
+  /**
+   * 创建人
+   */
+  createdBy?: string;
+
+  /**
+   * 创建时间
+   */
+  createdAt?: string;
+
+  /**
+   * 最后更新人
+   */
+  updatedBy?: string;
+
+  /**
+   * 最后更新时间
+   */
+  updatedAt?: string;
+}
+
+export interface OrderQuery extends PageQuery {
+  /**
+   * 用户昵称
+   */
+  userNickname?: string;
+
+  /**
+   * 真实姓名
+   */
+  userRealName?: string;
+
+  /**
+   * 身份证号
+   */
+  userIdCard?: string | number;
+
+  /**
+   * 账号ID(关联用户表)
+   */
+  userAccountId?: string | number;
+
+  /**
+   * 用户收货地址(省市区+详细地址)
+   */
+  userAddress?: string;
+
+  /**
+   * 订单编号(唯一)
+   */
+  orderSn?: string;
+
+  /**
+   * 订单总金额(元)
+   */
+  totalAmount?: number;
+
+  /**
+   * 订单状态:pending_payment=待支付, paid=已支付, shipped=已发货, completed=已完成, cancelled=已取消
+   */
+  status?: string;
+
+  /**
+   * 创建人
+   */
+  createdBy?: string;
+
+  /**
+   * 创建时间
+   */
+  createdAt?: string;
+
+  /**
+   * 最后更新人
+   */
+  updatedBy?: string;
+
+  /**
+   * 最后更新时间
+   */
+  updatedAt?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/system/physical/orderItem/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { OrderItemVO, OrderItemForm, OrderItemQuery } from '@/api/system/physical/orderItem//types';
+
+/**
+ * 查询商城订单明细列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listOrderItem = (query?: OrderItemQuery): AxiosPromise<OrderItemVO[]> => {
+  return request({
+    url: '/physical/orderItem/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询商城订单明细详细
+ * @param id
+ */
+export const getOrderItem = (id: string | number): AxiosPromise<OrderItemVO> => {
+  return request({
+    url: '/physical/orderItem/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增商城订单明细
+ * @param data
+ */
+export const addOrderItem = (data: OrderItemForm) => {
+  return request({
+    url: '/physical/orderItem',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改商城订单明细
+ * @param data
+ */
+export const updateOrderItem = (data: OrderItemForm) => {
+  return request({
+    url: '/physical/orderItem',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除商城订单明细
+ * @param id
+ */
+export const delOrderItem = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/physical/orderItem/' + id,
+    method: 'delete'
+  });
+};

+ 170 - 0
src/api/system/physical/orderItem/types.ts

@@ -0,0 +1,170 @@
+export interface OrderItemVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 所属订单ID,外键关联 physical_order.id
+   */
+  orderId: string | number;
+
+  /**
+   * 商品ID,外键关联 physical_merchant_item.id
+   */
+  itemId: string | number;
+
+  /**
+   * 商品名称
+   */
+  name: string;
+
+  /**
+   * 单价(元)
+   */
+  price: number;
+
+  /**
+   * 数量
+   */
+  quantity: number;
+
+  /**
+   * 小计 = 单价 × 数量
+   */
+  totalPrice: number;
+
+  /**
+   * 所属商家ID,外键关联 merchant_partner.id
+   */
+  merchantId: string | number;
+
+  /**
+   * 商家名称(冗余字段,避免查联)
+   */
+  merchantName: string;
+
+  /**
+   * 创建时间
+   */
+  createdAt: string;
+
+  /**
+   * 最后更新时间
+   */
+  updatedAt: string;
+}
+
+export interface OrderItemForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 所属订单ID,外键关联 physical_order.id
+   */
+  orderId?: string | number;
+
+  /**
+   * 商品ID,外键关联 physical_merchant_item.id
+   */
+  itemId?: string | number;
+
+  /**
+   * 商品名称
+   */
+  name?: string;
+
+  /**
+   * 单价(元)
+   */
+  price?: number;
+
+  /**
+   * 数量
+   */
+  quantity?: number;
+
+  /**
+   * 小计 = 单价 × 数量
+   */
+  totalPrice?: number;
+
+  /**
+   * 所属商家ID,外键关联 merchant_partner.id
+   */
+  merchantId?: string | number;
+
+  /**
+   * 商家名称(冗余字段,避免查联)
+   */
+  merchantName?: string;
+
+  /**
+   * 创建时间
+   */
+  createdAt?: string;
+
+  /**
+   * 最后更新时间
+   */
+  updatedAt?: string;
+}
+
+export interface OrderItemQuery extends PageQuery {
+  /**
+   * 所属订单ID,外键关联 physical_order.id
+   */
+  orderId?: string | number;
+
+  /**
+   * 商品ID,外键关联 physical_merchant_item.id
+   */
+  itemId?: string | number;
+
+  /**
+   * 商品名称
+   */
+  name?: string;
+
+  /**
+   * 单价(元)
+   */
+  price?: number;
+
+  /**
+   * 数量
+   */
+  quantity?: number;
+
+  /**
+   * 小计 = 单价 × 数量
+   */
+  totalPrice?: number;
+
+  /**
+   * 所属商家ID,外键关联 merchant_partner.id
+   */
+  merchantId?: string | number;
+
+  /**
+   * 商家名称(冗余字段,避免查联)
+   */
+  merchantName?: string;
+
+  /**
+   * 创建时间
+   */
+  createdAt?: string;
+
+  /**
+   * 最后更新时间
+   */
+  updatedAt?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 341 - 0
src/views/system/physical/order/index.vue

@@ -0,0 +1,341 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="用户昵称" prop="userNickname">
+              <el-input v-model="queryParams.userNickname" placeholder="请输入用户昵称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="真实姓名" prop="userRealName">
+              <el-input v-model="queryParams.userRealName" placeholder="请输入真实姓名" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="账号ID" prop="userAccountId">
+              <el-input v-model="queryParams.userAccountId" placeholder="请输入账号ID" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="订单编号" prop="orderSn">
+              <el-input v-model="queryParams.orderSn" placeholder="请输入订单编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <!--          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['physical:order:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['physical:order:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['physical:order:remove']">删除</el-button>
+          </el-col>-->
+          <!--          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:order:export']">导出</el-button>
+          </el-col>-->
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="orderList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="编号" align="center" prop="id" v-if="true" />
+        <el-table-column type="expand" label="商品明细" width="80">
+          <template #default="props">
+            <div class="order-items-expand">
+              <el-table :data="props.row.physicalOrderItemVoList || []" border style="width: 100%" size="small">
+                <el-table-column label="商品名称" prop="name" min-width="150" />
+                <el-table-column label="单价 (元)" prop="price" width="100" align="right">
+                  <template #default="scope">
+                    <span>¥{{ scope.row.price }}</span>
+                  </template>
+                </el-table-column>
+                <el-table-column label="数量" prop="quantity" width="80" align="center" />
+                <el-table-column label="小计" prop="totalPrice" width="100" align="right">
+                  <template #default="scope">
+                    <span class="text-primary">¥{{ scope.row.totalPrice }}</span>
+                  </template>
+                </el-table-column>
+                <el-table-column label="所属商家" prop="merchantName" min-width="120" />
+              </el-table>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="用户昵称" align="center" prop="userNickname" />
+        <el-table-column label="真实姓名" align="center" prop="userRealName" />
+        <el-table-column label="身份证号" align="center" prop="userIdCard" />
+        <el-table-column label="账号ID" align="center" prop="userAccountId" />
+        <el-table-column label="用户收货地址" align="center" prop="userAddress" />
+        <el-table-column label="订单编号" align="center" prop="orderSn" />
+        <el-table-column label="订单总金额" align="center" prop="totalAmount" />
+        <el-table-column label="订单状态" align="center" prop="status" width="100">
+          <template #default="scope">
+            <el-tag :type="getOrderStatusType(scope.row.status)">
+              {{ getOrderStatusText(scope.row.status) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="创建人" align="center" prop="createdBy" />
+        <el-table-column label="创建时间" align="center" prop="createdAt" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改地址" placement="top">
+              <el-button link type="success" icon="Edit" v-hasPermi="['physical:order:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['physical:order:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['physical:order:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改商城订单主对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="orderFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="用户昵称" prop="userNickname">
+          <el-input v-model="form.userNickname" placeholder="请输入用户昵称" />
+        </el-form-item>
+        <el-form-item label="真实姓名" prop="userRealName">
+          <el-input v-model="form.userRealName" placeholder="请输入真实姓名" />
+        </el-form-item>
+        <el-form-item label="身份证号" prop="userIdCard">
+          <el-input v-model="form.userIdCard" placeholder="请输入身份证号" />
+        </el-form-item>
+        <el-form-item label="账号ID" prop="userAccountId">
+          <el-input v-model="form.userAccountId" placeholder="请输入账号ID" />
+        </el-form-item>
+        <el-form-item label="用户收货地址" prop="userAddress">
+          <el-input v-model="form.userAddress" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="订单编号" prop="orderSn">
+          <el-input v-model="form.orderSn" placeholder="请输入订单编号" />
+        </el-form-item>
+        <el-form-item label="订单总金额" prop="totalAmount">
+          <el-input v-model="form.totalAmount" placeholder="请输入订单总金额" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Order" lang="ts">
+import { listOrder, getOrder, delOrder, addOrder, updateOrder } from '@/api/system/physical/order';
+import { OrderVO, OrderQuery, OrderForm } from '@/api/system/physical/order/types';
+import { OrderItemVO } from '@/api/system/physical/orderItem/types';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const orderList = ref<OrderVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const orderFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: OrderForm = {
+  id: undefined,
+  userNickname: undefined,
+  userRealName: undefined,
+  userIdCard: undefined,
+  userAccountId: undefined,
+  userAddress: undefined,
+  orderSn: undefined,
+  totalAmount: undefined,
+  status: undefined,
+  createdBy: undefined,
+  createdAt: undefined,
+  updatedBy: undefined,
+  updatedAt: undefined
+};
+const data = reactive<PageData<OrderForm, OrderQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    userNickname: undefined,
+    userRealName: undefined,
+    userIdCard: undefined,
+    userAccountId: undefined,
+    userAddress: undefined,
+    orderSn: undefined,
+    totalAmount: undefined,
+    status: undefined,
+    createdBy: undefined,
+    createdAt: undefined,
+    updatedBy: undefined,
+    updatedAt: undefined,
+    params: {}
+  },
+  rules: {
+    id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
+    userNickname: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
+    userAccountId: [{ required: true, message: '账号ID不能为空', trigger: 'blur' }],
+    userAddress: [{ required: true, message: '用户收货地址不能为空', trigger: 'blur' }],
+    orderSn: [{ required: true, message: '订单编号不能为空', trigger: 'blur' }],
+    totalAmount: [{ required: true, message: '订单总金额不能为空', trigger: 'blur' }],
+    status: [
+      {
+        required: true,
+        message: '订单状态:pending_payment=待支付, paid=已支付, shipped=已发货, completed=已完成, cancelled=已取消不能为空',
+        trigger: 'change'
+      }
+    ],
+    createdBy: [{ required: true, message: '创建人不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询商城订单主列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listOrder(queryParams.value);
+  orderList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  orderFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: OrderVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加商城订单主';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: OrderVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getOrder(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改商城订单主';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  orderFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateOrder(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addOrder(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: OrderVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除商城订单主编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delOrder(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'physical/order/export',
+    {
+      ...queryParams.value
+    },
+    `order_${new Date().getTime()}.xlsx`
+  );
+};
+/** 获取订单状态文本 */
+const getOrderStatusText = (status: string): string => {
+  const statusMap: Record<string, string> = {
+    pending_payment: '待支付',
+    paid: '已支付',
+    shipped: '已发货',
+    completed: '已完成',
+    cancelled: '已取消'
+  };
+  return statusMap[status] || status;
+};
+
+/** 获取订单状态标签类型 */
+const getOrderStatusType = (status: string): 'success' | 'warning' | 'info' | 'danger' | '' => {
+  const typeMap: Record<string, 'success' | 'warning' | 'info' | 'danger' | ''> = {
+    pending_payment: 'warning',
+    paid: 'success',
+    shipped: 'success',
+    completed: 'success',
+    cancelled: 'info'
+  };
+  return typeMap[status] || '';
+};
+
+// ... existing code ...
+onMounted(() => {
+  getList();
+});
+</script>