ソースを参照

!210 订单列表:列表重构: 完善订单发货、修改地址、订单调价、订单备注
Merge pull request !210 from puhui999/dev-to-dev

芋道源码 2 年 前
コミット
69a66b2a06

+ 6 - 4
src/api/mall/promotion/bargain/bargainActivity.ts

@@ -7,18 +7,20 @@ export interface BargainActivityVO {
   startTime?: Date
   endTime?: Date
   status?: number
-  spuId?: number
   userSize?: number // 达到该人数,才能砍到低价
   bargainCount?: number // 最大帮砍次数
   totalLimitCount?: number // 最大购买次数
-  stock?: number // 活动总库存
+  spuId: number
+  skuId: number
+  bargainFirstPrice: number // 砍价起始价格,单位分
+  bargainPrice: number // 砍价底价
+  stock: number // 活动库存
   randomMinPrice?: number // 用户每次砍价的最小金额,单位:分
   randomMaxPrice?: number // 用户每次砍价的最大金额,单位:分
   successCount?: number // 砍价成功数量
-  products?: BargainProductVO[]
 }
 
-// 砍价活动所需属性
+// 砍价活动所需属性。 选择的商品和属性的时候使用方便使用活动的通用封装
 export interface BargainProductVO {
   spuId: number
   skuId: number

+ 5 - 0
src/api/mall/trade/delivery/express/index.ts

@@ -19,6 +19,11 @@ export const getDeliveryExpress = async (id: number) => {
   return await request.get({ url: '/trade/delivery/express/get?id=' + id })
 }
 
+// 获得快递公司精简信息列表
+export const getSimpleDeliveryExpressList = () => {
+  return request.get({ url: '/trade/delivery/express/list-all-simple' })
+}
+
 // 新增快递公司
 export const createDeliveryExpress = async (data: DeliveryExpressVO) => {
   return await request.post({ url: '/trade/delivery/express/create', data })

+ 6 - 6
src/api/mall/trade/delivery/pickUpStore/index.ts

@@ -16,7 +16,7 @@ export interface DeliveryPickUpStoreVO {
 }
 
 // 查询自提门店列表
-export const getDeliveryPickUpStorePage = async (params: DeliveryPickUpStorePageReqVO) => {
+export const getDeliveryPickUpStorePage = async (params) => {
   return await request.get({ url: '/trade/delivery/pick-up-store/page', params })
 }
 
@@ -25,6 +25,11 @@ export const getDeliveryPickUpStore = async (id: number) => {
   return await request.get({ url: '/trade/delivery/pick-up-store/get?id=' + id })
 }
 
+// 查询自提门店精简列表
+export const getListAllSimple = async () => {
+  return await request.get({ url: '/trade/delivery/pick-up-store/list-all-simple' })
+}
+
 // 新增自提门店
 export const createDeliveryPickUpStore = async (data: DeliveryPickUpStoreVO) => {
   return await request.post({ url: '/trade/delivery/pick-up-store/create', data })
@@ -39,8 +44,3 @@ export const updateDeliveryPickUpStore = async (data: DeliveryPickUpStoreVO) =>
 export const deleteDeliveryPickUpStore = async (id: number) => {
   return await request.delete({ url: '/trade/delivery/pick-up-store/delete?id=' + id })
 }
-
-// 导出自提门店 Excel
-export const exportDeliveryPickUpStoreApi = async (params) => {
-  return await request.download({ url: '/trade/delivery/pick-up-store/export-excel', params })
-}

+ 121 - 12
src/api/mall/trade/order/index.ts

@@ -1,12 +1,121 @@
-import request from '@/config/axios'
-
-// 获得交易订单分页
-// TODO @xiaobai:改成 getOrderPage
-export const getOrderList = (params: PageParam) => {
-  return request.get({ url: '/trade/order/page', params })
-}
-
-// 获得交易订单详情
-export const getOrderDetail = (id: number) => {
-  return request.get({ url: '/trade/order/get-detail?id=' + id })
-}
+import request from '@/config/axios'
+
+export interface OrderVO {
+  id?: number | null // 订单编号
+  no?: string // 订单流水号
+  createTime?: Date | null // 下单时间
+  type?: number | null // 订单类型
+  terminal?: number | null // 订单来源
+  userId?: number | null // 用户编号
+  userIp?: string // 用户 IP
+  userRemark?: string // 用户备注
+  status?: number | null // 订单状态
+  productCount?: number | null // 购买的商品数量
+  finishTime?: Date | null // 订单完成时间
+  cancelTime?: Date | null // 订单取消时间
+  cancelType?: number | null // 取消类型
+  remark?: string // 商家备注
+  payOrderId: number | null // 支付订单编号
+  payed?: boolean // 是否已支付
+  payTime?: Date | null // 付款时间
+  payChannelCode?: string // 支付渠道
+  originalPrice?: number | null // 商品原价(总)
+  orderPrice?: number | null // 订单原价(总)
+  discountPrice?: number | null // 订单优惠(总)
+  deliveryPrice?: number | null // 运费金额
+  adjustPrice?: number | null // 订单调价(总)
+  payPrice?: number | null // 应付金额(总)
+  deliveryType?: number | null // 发货方式
+  deliveryTemplateId?: number | null // 配送模板编号
+  logisticsId?: number | null | null // 发货物流公司编号
+  logisticsNo?: string // 发货物流单号
+  deliveryStatus?: number | null // 发货状态
+  deliveryTime?: Date | null // 发货时间
+  receiveTime?: Date | null // 收货时间
+  receiverName?: string // 收件人名称
+  receiverMobile?: string // 收件人手机
+  receiverAreaId?: number | null // 收件人地区编号
+  receiverPostCode?: number | null // 收件人邮编
+  receiverDetailAddress?: string // 收件人详细地址
+  afterSaleStatus?: number | null // 售后状态
+  refundPrice?: number | null // 退款金额
+  couponId?: number | null // 优惠劵编号
+  couponPrice?: number | null // 优惠劵减免金额
+  pointPrice?: number | null // 积分抵扣的金额
+  receiverAreaName?: string //收件人地区名字
+  items?: OrderItemRespVO[] // 订单项列表
+  //用户信息
+  user?: {
+    id?: number | null
+    nickname?: string
+    avatar?: string
+  }
+}
+
+export interface OrderItemRespVO {
+  // ========== 订单项基本信息 ==========
+  id?: number | null // 编号
+  userId?: number | null // 用户编号
+  orderId?: number | null // 订单编号
+  // ========== 商品基本信息 ==========
+  spuId?: number | null // 商品 SPU 编号
+  spuName?: string //商品 SPU 名称
+  skuId?: number | null // 商品 SKU 编号
+  picUrl?: string //商品图片
+  count?: number | null //购买数量
+  // ========== 价格 + 支付基本信息 ==========
+  originalPrice?: number | null //商品原价(总)
+  originalUnitPrice?: number | null //商品原价(单)
+  discountPrice?: number | null //商品优惠(总)
+  payPrice?: number | null //商品实付金额(总)
+  orderPartPrice?: number | null //子订单分摊金额(总)
+  orderDividePrice?: number | null //分摊后子订单实付金额(总)
+  // ========== 营销基本信息 ==========
+  // TODO 芋艿:在捉摸一下
+  // ========== 售后基本信息 ==========
+  afterSaleStatus?: number | null // 售后状态
+  properties?: ProductPropertiesVO[] //属性数组
+}
+
+export interface ProductPropertiesVO {
+  propertyId?: number | null // 属性的编号
+  propertyName?: string // 属性的名称
+  valueId?: number | null //属性值的编号
+  valueName?: string // 属性值的名称
+}
+
+// 查询交易订单列表
+export const getOrderPage = async (params) => {
+  return await request.get({ url: `/trade/order/page`, params })
+}
+
+// 查询交易订单详情
+export const getOrder = async (id: number | null) => {
+  return await request.get({ url: `/trade/order/get-detail?id=` + id })
+}
+
+export interface DeliveryVO {
+  id: number // 订单编号
+  logisticsId: number | null // 物流公司编号
+  logisticsNo: string // 物流编号
+}
+
+// 订单发货
+export const delivery = async (data: DeliveryVO) => {
+  return await request.post({ url: `/trade/order/delivery`, data })
+}
+
+// 订单备注
+export const remark = async (data) => {
+  return await request.post({ url: `/trade/order/remark`, data })
+}
+
+// 订单调价
+export const adjustPrice = async (data) => {
+  return await request.post({ url: `/trade/order/adjust-price`, data })
+}
+
+// 修改订单地址
+export const adjustAddress = async (data) => {
+  return await request.post({ url: `/trade/order/adjust-address`, data })
+}

+ 0 - 228
src/api/mall/trade/order/type/orderType.ts

@@ -1,228 +0,0 @@
-// TODO @xiaobai:这个放到 order/index.ts  里哈
-// TODO @xiaobai:注释放到变量后面,这样简洁一点
-// TODO @xiaobai:这个改成 TradeOrderRespVO
-export interface TradeOrderPageItemRespVO {
-  // 订单编号
-  id?: number
-  // 订单流水号
-  no?: string
-  // 下单时间
-  createTime?: Date
-  // 订单类型
-  type?: number
-  // 订单来源
-  terminal?: number
-  // 用户编号
-  userId?: number
-  // 用户 IP
-  userIp?: string
-  // 用户备注
-  userRemark?: string
-  // 订单状态
-  status?: number
-  // 购买的商品数量
-  productCount?: number
-  // 订单完成时间
-  finishTime?: Date
-  // 订单取消时间
-  cancelTime?: Date
-  // 取消类型
-  cancelType?: number
-  // 商家备注
-  remark?: string
-  // 支付订单编号
-  payOrderId: number
-  // 是否已支付
-  payed?: boolean
-  // 付款时间
-  payTime?: Date
-  // 支付渠道
-  payChannelCode?: string
-  // 商品原价(总)
-  originalPrice?: number
-  // 订单原价(总)
-  orderPrice?: number
-  // 订单优惠(总)
-  discountPrice?: number
-  // 运费金额
-  deliveryPrice?: number
-  // 订单调价(总)
-  adjustPrice?: number
-  // 应付金额(总)
-  payPrice?: number
-  // 配送模板编号
-  deliveryTemplateId?: number
-  // 发货物流公司编号
-  logisticsId?: number
-  // 发货物流单号
-  logisticsNo?: string
-  // 发货状态
-  deliveryStatus?: number
-  // 发货时间
-  deliveryTime?: Date
-  // 收货时间
-  receiveTime?: Date
-  // 收件人名称
-  receiverName?: string
-  // 收件人手机
-  receiverMobile?: string
-  // 收件人地区编号
-  receiverAreaId?: number
-  // 收件人邮编
-  receiverPostCode?: number
-  // 收件人详细地址
-  receiverDetailAddress?: string
-  // 售后状态
-  afterSaleStatus?: number
-  // 退款金额
-  refundPrice?: number
-  // 优惠劵编号
-  couponId?: number
-  // 优惠劵减免金额
-  couponPrice?: number
-  // 积分抵扣的金额
-  pointPrice?: number
-  //收件人地区名字
-  receiverAreaName?: string
-  // 订单项列表
-  items?: TradeOrderItemBaseVO[]
-  //用户信息
-  user?: MemberUserRespDTO
-}
-
-// TODO @xiaobai:这个改成 TradeOrderItemRespVO
-/**
- * 交易订单项 Base VO,提供给添加、修改、详细的子 VO 使用
- * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
- */
-export interface TradeOrderItemBaseVO {
-  // ========== 订单项基本信息 ==========
-  /**
-   * 编号
-   */
-  id?: number
-  /**
-   * 用户编号
-   */
-  userId?: number
-  /**
-   * 订单编号
-   */
-  orderId?: number
-  // ========== 商品基本信息 ==========
-  /**
-   * 商品 SPU 编号
-   */
-  spuId?: number
-  /**
-   * 商品 SPU 名称
-   */
-  spuName?: string
-  /**
-   * 商品 SKU 编号
-   */
-  skuId?: number
-  /**
-   * 商品图片
-   */
-  picUrl?: string
-  /**
-   * 购买数量
-   */
-  count?: number
-  // ========== 价格 + 支付基本信息 ==========
-  /**
-   * 商品原价(总)
-   */
-  originalPrice?: number
-  /**
-   * 商品原价(单)
-   */
-  originalUnitPrice?: number
-  /**
-   * 商品优惠(总)
-   */
-  discountPrice?: number
-  /**
-   * 商品实付金额(总)
-   */
-  payPrice?: number
-  /**
-   * 子订单分摊金额(总)
-   */
-  orderPartPrice?: number
-  /**
-   * 分摊后子订单实付金额(总)
-   */
-  orderDividePrice?: number
-  // ========== 营销基本信息 ==========
-  // TODO 芋艿:在捉摸一下
-  // ========== 售后基本信息 ==========
-  /**
-   * 售后状态
-   */
-  afterSaleStatus?: number
-  //属性数组
-  properties?: ProductPropertyValueDetailRespVO[]
-}
-
-/**
- * 管理后台 - 商品属性值的明细 Response VO
- */
-export interface ProductPropertyValueDetailRespVO {
-  /**
-   * 属性的编号
-   */
-  propertyId?: number
-  /**
-   * 属性的名称
-   */
-  propertyName?: string
-  /**
-   * 属性值的编号
-   */
-  valueId?: number
-  /**
-   * 属性值的名称
-   */
-  valueName?: string
-}
-
-/**
- * 订单详情查询 请求
- */
-export interface TradeOrderPageReqVO {
-  pageNo: number
-  pageSize: number
-  no?: string
-  userId?: string
-  userNickname?: string
-  userMobile?: string
-  receiverName?: string
-  receiverMobile?: string
-  terminal?: string
-  type?: number
-  status?: number
-  payChannelCode?: string
-  createTime?: [Date, Date]
-  spuName?: string
-  itemCount?: string
-  all?: string
-}
-
-//用户信息
-export interface MemberUserRespDTO {
-  id?: number
-  nickname?: string
-  status?: number
-  avatar?: string
-  mobile?: string
-}
-//订单详情选中type
-export interface SelectType {
-  queryParams: TradeOrderPageReqVO
-  selectTotal: number //选中的数量
-  selectAllFlag: boolean //全选标识
-  selectData: Map<number, Set<string>> //存放涉及选中得页面以及每页选中得数据订单号  全选时根据条件查询 排除取消的list订单
-  unSelectList: Set<string> //登记取消的list 全选标识为true 时登记单独取消的list,再次选中时排除, 全选标识为false 时清空list
-}

+ 33 - 17
src/router/modules/remaining.ts

@@ -5,32 +5,32 @@ const { t } = useI18n()
  * redirect: noredirect        当设置 noredirect 的时候该路由在面包屑导航中不可被点击
  * name:'router-name'          设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
  * meta : {
-    hidden: true              当设置 true 的时候该路由不会再侧边栏出现 如404,login等页面(默认 false)
+ hidden: true              当设置 true 的时候该路由不会再侧边栏出现 如404,login等页面(默认 false)
 
-    alwaysShow: true          当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式,
-                              只有一个时,会将那个子路由当做根路由显示在侧边栏,
-                              若你想不管路由下面的 children 声明的个数都显示你的根路由,
-                              你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,
-                              一直显示根路由(默认 false)
+ alwaysShow: true          当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式,
+ 只有一个时,会将那个子路由当做根路由显示在侧边栏,
+ 若你想不管路由下面的 children 声明的个数都显示你的根路由,
+ 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,
+ 一直显示根路由(默认 false)
 
-    title: 'title'            设置该路由在侧边栏和面包屑中展示的名字
+ title: 'title'            设置该路由在侧边栏和面包屑中展示的名字
 
-    icon: 'svg-name'          设置该路由的图标
+ icon: 'svg-name'          设置该路由的图标
 
-    noCache: true             如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
+ noCache: true             如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
 
-    breadcrumb: false         如果设置为false,则不会在breadcrumb面包屑中显示(默认 true)
+ breadcrumb: false         如果设置为false,则不会在breadcrumb面包屑中显示(默认 true)
 
-    affix: true               如果设置为true,则会一直固定在tag项中(默认 false)
+ affix: true               如果设置为true,则会一直固定在tag项中(默认 false)
 
-    noTagsView: true          如果设置为true,则不会出现在tag中(默认 false)
+ noTagsView: true          如果设置为true,则不会出现在tag中(默认 false)
 
-    activeMenu: '/dashboard'  显示高亮的路由路径
+ activeMenu: '/dashboard'  显示高亮的路由路径
 
-    followAuth: '/dashboard'  跟随哪个路由进行权限过滤
+ followAuth: '/dashboard'  跟随哪个路由进行权限过滤
 
-    canTo: true               设置为true即使hidden为true,也依然可以进行路由跳转(默认 false)
-  }
+ canTo: true               设置为true即使hidden为true,也依然可以进行路由跳转(默认 false)
+ }
  **/
 const remainingRouter: AppRouteRecordRaw[] = [
   {
@@ -349,7 +349,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
   {
     path: '/property',
     component: Layout,
-    name: 'property',
+    name: 'Property',
     meta: {
       hidden: true
     },
@@ -412,6 +412,22 @@ const remainingRouter: AppRouteRecordRaw[] = [
     ]
   },
   {
+    path: '/trade/order',
+    component: Layout,
+    name: 'Detail',
+    meta: {
+      hidden: true
+    },
+    children: [
+      {
+        path: 'detail/:orderId(\\d+)',
+        component: () => import('@/views/mall/trade/order/components/OrderDetailForm.vue'),
+        name: 'TradeOrderDetailForm',
+        meta: { title: '订单详情', icon: '', activeMenu: '/trade/trade/order' }
+      }
+    ]
+  },
+  {
     path: '/pay',
     component: Layout,
     name: 'pay',

+ 5 - 2
src/utils/dict.ts

@@ -130,7 +130,7 @@ export enum DICT_TYPE {
   BPM_OA_LEAVE_TYPE = 'bpm_oa_leave_type',
 
   // ========== PAY 模块 ==========
-  PAY_CHANNEL_CODE = 'pay_channel_code', // 支付渠道编码类型
+  PAY_CHANNEL_CODE_TYPE = 'pay_channel_code_type', // 支付渠道编码类型
   PAY_ORDER_STATUS = 'pay_order_status', // 商户支付订单状态
   PAY_REFUND_STATUS = 'pay_refund_status', // 退款订单状态
   PAY_NOTIFY_STATUS = 'pay_notify_status', // 商户支付回调状态
@@ -164,5 +164,8 @@ export enum DICT_TYPE {
   PROMOTION_COUPON_STATUS = 'promotion_coupon_status', // 优惠劵的状态
   PROMOTION_COUPON_TAKE_TYPE = 'promotion_coupon_take_type', // 优惠劵的领取方式
   PROMOTION_ACTIVITY_STATUS = 'promotion_activity_status', // 优惠活动的状态
-  PROMOTION_CONDITION_TYPE = 'promotion_condition_type' // 营销的条件类型枚举
+  PROMOTION_CONDITION_TYPE = 'promotion_condition_type', // 营销的条件类型枚举
+
+  // ========== MALL - 物流模块 ==========
+  DELIVERY_TYPE = 'delivery_type' // 配送方式
 }

+ 1 - 4
src/views/Login/components/LoginForm.vue

@@ -21,8 +21,8 @@
             v-model="loginData.loginForm.tenantName"
             :placeholder="t('login.tenantNamePlaceholder')"
             :prefix-icon="iconHouse"
-            type="primary"
             link
+            type="primary"
           />
         </el-form-item>
       </el-col>
@@ -148,8 +148,6 @@ import { ElLoading } from 'element-plus'
 import LoginFormTitle from './LoginFormTitle.vue'
 import type { RouteLocationNormalizedLoaded } from 'vue-router'
 
-import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
-const { wsCache } = useCache()
 import { useIcon } from '@/hooks/web/useIcon'
 
 import * as authUtil from '@/utils/auth'
@@ -246,7 +244,6 @@ const handleLogin = async (params) => {
     if (!res) {
       return
     }
-    wsCache.delete(CACHE_KEY.USER) // 清除上次登录用户信息
     ElLoading.service({
       lock: true,
       text: '正在加载系统中...',

+ 2 - 2
src/views/infra/codegen/PreviewCode.vue

@@ -45,9 +45,9 @@
             <el-button class="float-right" text type="primary" @click="copy(item.code)">
               {{ t('common.copy') }}
             </el-button>
-            <div>
+            <el-scrollbar height="600px">
               <pre><code v-dompurify-html="highlightedCode(item)" class="hljs"></code></pre>
-            </div>
+            </el-scrollbar>
           </el-tab-pane>
         </el-tabs>
       </el-card>

+ 5 - 4
src/views/mall/product/spu/components/SkuList.vue

@@ -334,7 +334,7 @@ const validateSku = () => {
   for (const sku of formData.value!.skus!) {
     // 作为活动组件的校验
     if (props.isActivityComponent) {
-      for (const rule of props.ruleConfig) {
+      for (const rule of props?.ruleConfig) {
         const arg = getValue(sku, rule.name)
         if (!rule.rule(arg)) {
           validate = false // 只要有一个不通过则直接不通过
@@ -534,9 +534,10 @@ watch(
   }
 )
 const activitySkuListRef = ref<InstanceType<typeof ElTable>>()
-const clearSelection = () => {
-  activitySkuListRef.value.clearSelection()
+
+const getSkuTableRef = () => {
+  return activitySkuListRef.value
 }
 // 暴露出生成 sku 方法,给添加属性成功时调用
-defineExpose({ generateTableData, validateSku, clearSelection })
+defineExpose({ generateTableData, validateSku, getSkuTableRef })
 </script>

+ 20 - 7
src/views/mall/promotion/bargain/activity/BargainActivityForm.vue

@@ -51,7 +51,7 @@
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
-  <SpuSelect ref="spuSelectRef" :isSelectSku="true" @confirm="selectSpu" />
+  <SpuSelect ref="spuSelectRef" :isSelectSku="true" :radio="true" @confirm="selectSpu" />
 </template>
 <script lang="ts" setup>
 import * as BargainActivityApi from '@/api/mall/promotion/bargain/bargainActivity'
@@ -87,12 +87,12 @@ const ruleConfig: RuleConfig[] = [
   },
   {
     name: 'productConfig.bargainPrice',
-    rule: (arg) => arg > 0,
+    rule: (arg) => arg >= 0,
     message: '商品砍价底价不能小于0 !!!'
   },
   {
     name: 'productConfig.stock',
-    rule: (arg) => arg > 1,
+    rule: (arg) => arg >= 1,
     message: '商品活动库存不能小于1 !!!'
   }
 ]
@@ -164,7 +164,20 @@ const open = async (type: string, id?: number) => {
       // 用户每次砍价金额分转元, 分转元
       data.randomMinPrice = formatToFraction(data.randomMinPrice)
       data.randomMaxPrice = formatToFraction(data.randomMaxPrice)
-      await getSpuDetails(data.spuId!, data.products?.map((sku) => sku.skuId), data.products)
+      // 对齐活动商品处理结构
+      await getSpuDetails(
+        data.spuId!,
+        [data.skuId],
+        [
+          {
+            spuId: data.spuId!,
+            skuId: data.skuId,
+            bargainFirstPrice: data.bargainFirstPrice, // 砍价起始价格,单位分
+            bargainPrice: data.bargainPrice, // 砍价底价
+            stock: data.stock // 活动库存
+          }
+        ]
+      )
       formRef.value.setValues(data)
     } finally {
       formLoading.value = false
@@ -201,12 +214,12 @@ const submitForm = async () => {
     // 用户每次砍价金额分转元, 元转分
     data.randomMinPrice = convertToInteger(data.randomMinPrice)
     data.randomMaxPrice = convertToInteger(data.randomMaxPrice)
-    data.products = products
+    const formData = { ...data, ...products[0] }
     if (formType.value === 'create') {
-      await BargainActivityApi.createBargainActivity(data)
+      await BargainActivityApi.createBargainActivity(formData)
       message.success(t('common.createSuccess'))
     } else {
-      await BargainActivityApi.updateBargainActivity(data)
+      await BargainActivityApi.updateBargainActivity(formData)
       message.success(t('common.updateSuccess'))
     }
     dialogVisible.value = false

+ 5 - 0
src/views/mall/promotion/combination/record/index.vue

@@ -0,0 +1,5 @@
+<template>
+  <div></div>
+</template>
+
+<script lang="ts" name="CombinationRecord" setup></script>

+ 26 - 7
src/views/mall/promotion/components/SpuSelect.vue

@@ -127,7 +127,8 @@ defineOptions({ name: 'PromotionSpuSelect' })
 const props = defineProps({
   // 默认不需要(不需要的情况下只返回 spu,需要的情况下返回 选中的 spu 和 sku 列表)
   // 其它活动需要选择商品和商品属性导入此组件即可,需添加组件属性 :isSelectSku='true'
-  isSelectSku: propTypes.bool.def(false) // 是否需要选择 sku 属性
+  isSelectSku: propTypes.bool.def(false), // 是否需要选择 sku 属性
+  radio: propTypes.bool.def(false) // 是否单选 sku
 })
 
 const message = useMessage() // 消息弹窗
@@ -146,7 +147,7 @@ const queryParams = ref({
 }) // 查询参数
 const propertyList = ref<PropertyAndValues[]>([]) // 商品属性列表
 const spuListRef = ref<InstanceType<typeof ElTable>>()
-const skuListRef = ref() // 商品属性选择 Ref
+const skuListRef = ref<InstanceType<typeof SkuList>>() // 商品属性选择 Ref
 const spuData = ref<ProductSpuApi.Spu>() // 商品详情
 const isExpand = ref(false) // 控制 SKU 列表显示
 const expandRowKeys = ref<number[]>() // 控制展开行需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组。
@@ -155,12 +156,30 @@ const expandRowKeys = ref<number[]>() // 控制展开行需要设置 row-key 属
 const selectedSpuId = ref<number>(0) // 选中的商品 spuId
 const selectedSkuIds = ref<number[]>([]) // 选中的商品 skuIds
 const selectSku = (val: ProductSpuApi.Sku[]) => {
+  const skuTable = skuListRef.value?.getSkuTableRef()
   if (selectedSpuId.value === 0) {
     message.warning('请先选择商品再选择相应的规格!!!')
-    skuListRef.value.clearSelection()
+    skuTable?.clearSelection()
     return
   }
-  selectedSkuIds.value = val.map((sku) => sku.id!)
+  if (val.length === 0) {
+    selectedSkuIds.value = []
+    return
+  }
+  if (props.radio) {
+    // 只选择一个
+    selectedSkuIds.value = [val.map((sku) => sku.id!)[0]]
+    // 如果大于1个
+    if (val.length > 1) {
+      // 清空选择
+      skuTable?.clearSelection()
+      // 变更为最后一次选择的
+      skuTable?.toggleRowSelection(val.pop(), true)
+      return
+    }
+  } else {
+    selectedSkuIds.value = val.map((sku) => sku.id!)
+  }
 }
 const selectSpu = (val: ProductSpuApi.Spu[]) => {
   if (val.length === 0) {
@@ -176,9 +195,9 @@ const selectSpu = (val: ProductSpuApi.Spu[]) => {
   // 如果大于1个
   if (val.length > 1) {
     // 清空选择
-    spuListRef.value.clearSelection()
+    spuListRef.value?.clearSelection()
     // 变更为最后一次选择的
-    spuListRef.value.toggleRowSelection(val.pop(), true)
+    spuListRef.value?.toggleRowSelection(val.pop(), true)
     return
   }
   expandChange(val[0], val)
@@ -194,7 +213,7 @@ const expandChange = async (row: ProductSpuApi.Spu, expandedRows?: ProductSpuApi
       expandRowKeys.value = [selectedSpuId.value]
       return
     }
-    // 如果展开 skuList 则选择此对应的 spu 不需要重新获取渲染 skuList
+    // 如果展开 skuList 则选择此对应的 spu 不需要重新获取渲染 skuList
     if (isExpand.value && spuData.value?.id === row.id) {
       return
     }

+ 31 - 49
src/views/mall/trade/delivery/pickUpStore/index.vue

@@ -1,27 +1,27 @@
 <template>
   <!-- 搜索工作栏 -->
   <ContentWrap>
-    <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
+    <el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px">
       <el-form-item label="门店手机" prop="phone">
         <el-input
           v-model="queryParams.phone"
-          placeholder="请输门店手机"
+          class="!w-240px"
           clearable
+          placeholder="请输门店手机"
           @keyup.enter="handleQuery"
-          class="!w-240px"
         />
       </el-form-item>
       <el-form-item label="门店名称" prop="name">
         <el-input
           v-model="queryParams.name"
-          placeholder="请输门店名称"
+          class="!w-240px"
           clearable
+          placeholder="请输门店名称"
           @keyup.enter="handleQuery"
-          class="!w-240px"
         />
       </el-form-item>
       <el-form-item label="门店状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="门店状态" clearable class="!w-240px">
+        <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="门店状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
@@ -33,32 +33,30 @@
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="datetimerange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
           class="!w-240px"
+          end-placeholder="结束日期"
+          start-placeholder="开始日期"
+          type="datetimerange"
+          value-format="YYYY-MM-DD HH:mm:ss"
         />
       </el-form-item>
       <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="openForm('create')"
-          v-hasPermi="['trade:delivery:pick-up-store:create']"
-        >
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
         </el-button>
         <el-button
-          type="success"
+          v-hasPermi="['trade:delivery:pick-up-store:create']"
           plain
-          @click="handleExport"
-          :loading="exportLoading"
-          v-hasPermi="['trade:delivery:pick-up-store:export']"
+          type="primary"
+          @click="openForm('create')"
         >
-          <Icon icon="ep:download" class="mr-5px" /> 导出
+          <Icon class="mr-5px" icon="ep:plus" />
+          新增
         </el-button>
       </el-form-item>
     </el-form>
@@ -75,34 +73,34 @@
       </el-table-column>
       <el-table-column label="门店名称" prop="name" />
       <el-table-column label="门店手机" prop="phone" />
-      <el-table-column label="门店详细地址" align="center" prop="detailAddress" />
-      <el-table-column label="开启状态" align="center" prop="status">
+      <el-table-column align="center" label="门店详细地址" prop="detailAddress" />
+      <el-table-column align="center" label="开启状态" prop="status">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
         </template>
       </el-table-column>
       <el-table-column
-        label="创建时间"
+        :formatter="dateFormatter"
         align="center"
+        label="创建时间"
         prop="createTime"
         width="180"
-        :formatter="dateFormatter"
       />
-      <el-table-column label="操作" align="center">
+      <el-table-column align="center" label="操作">
         <template #default="scope">
           <el-button
+            v-hasPermi="['trade:delivery:pick-up-store:update']"
             link
             type="primary"
             @click="openForm('update', scope.row.id)"
-            v-hasPermi="['trade:delivery:pick-up-store:update']"
           >
             编辑
           </el-button>
           <el-button
+            v-hasPermi="['trade:delivery:pick-up-store:delete']"
             link
             type="danger"
             @click="handleDelete(scope.row.id)"
-            v-hasPermi="['trade:delivery:pick-up-store:delete']"
           >
             删除
           </el-button>
@@ -113,18 +111,17 @@
   <!-- 表单弹窗:添加/修改 -->
   <DeliveryPickUpStoreForm ref="formRef" @success="getList" />
 </template>
-<script setup lang="ts" name="DeliveryPickUpStore">
+<script lang="ts" name="DeliveryPickUpStore" setup>
 import * as DeliveryPickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore'
 import DeliveryPickUpStoreForm from './PickUpStoreForm.vue'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
-import download from '@/utils/download'
+
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 
 const total = ref(0) // 列表的总页数
 const loading = ref(true) // 列表的加载中
-const exportLoading = ref(false) // 导出的加载中
 const list = ref<any[]>([]) // 列表的数据
 const queryParams = reactive({
   pageNo: 1,
@@ -179,21 +176,6 @@ const resetQuery = () => {
   handleQuery()
 }
 
-/** 导出按钮操作 */
-const handleExport = async () => {
-  try {
-    // 导出的二次确认
-    await message.exportConfirm()
-    // 发起导出
-    exportLoading.value = true
-    const data = await DeliveryPickUpStoreApi.exportDeliveryPickUpStoreApi(queryParams)
-    download.excel(data, '自提门店.xls')
-  } catch {
-  } finally {
-    exportLoading.value = false
-  }
-}
-
 /** 初始化 **/
 onMounted(() => {
   getList()

+ 94 - 0
src/views/mall/trade/order/components/DeliveryOrderForm.vue

@@ -0,0 +1,94 @@
+<template>
+  <Dialog v-model="dialogVisible" title="订单发货" width="25%">
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
+      <el-form-item label="发货方式">
+        <el-radio-group v-model="radio">
+          <el-radio border label="1">快递物流</el-radio>
+          <el-radio border label="2">无需发货</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <template v-if="radio === '1'">
+        <el-form-item label="物流公司">
+          <el-select v-model="formData.logisticsId" placeholder="请选择" style="width: 100%">
+            <el-option
+              v-for="item in deliveryExpressList"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="物流单号">
+          <el-input v-model="formData.logisticsNo" />
+        </el-form-item>
+      </template>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
+import * as TradeOrderApi from '@/api/mall/trade/order'
+
+defineOptions({ name: 'DeliveryOrderForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const radio = ref('1')
+const formData = ref<TradeOrderApi.DeliveryVO>({
+  id: 0, // 订单编号
+  logisticsId: null, // 物流公司编号
+  logisticsNo: '' // 物流编号
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (orderId: number) => {
+  resetForm()
+  // 设置数据
+  formData.value.id = orderId
+  dialogVisible.value = true
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = unref(formData)
+    if (radio.value === '2') {
+      data.logisticsId = 0
+      data.logisticsNo = ''
+    }
+    await TradeOrderApi.delivery(data)
+    message.success(t('common.updateSuccess'))
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success', true)
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: 0, // 订单编号
+    logisticsId: null, // 物流公司编号
+    logisticsNo: '' // 物流编号
+  }
+  formRef.value?.resetFields()
+}
+const deliveryExpressList = ref([])
+onMounted(async () => {
+  deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList()
+})
+</script>

+ 80 - 0
src/views/mall/trade/order/components/OrderAdjustAddressForm.vue

@@ -0,0 +1,80 @@
+<template>
+  <Dialog v-model="dialogVisible" title="修改订单收货地址" width="35%">
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="120px">
+      <el-form-item label="收件人名称">
+        <el-input v-model="formData.receiverName" />
+      </el-form-item>
+      <el-form-item label="收件人手机">
+        <el-input v-model="formData.receiverMobile" />
+      </el-form-item>
+      <el-form-item label="收件人地区编号">
+        <el-input v-model="formData.receiverAreaId" />
+      </el-form-item>
+      <el-form-item label="收件人详细地址">
+        <el-input v-model="formData.receiverDetailAddress" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+import * as TradeOrderApi from '@/api/mall/trade/order'
+import { copyValueToTarget } from '@/utils'
+
+defineOptions({ name: 'OrderAdjustAddressForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formData = ref({
+  id: 0, // 订单编号
+  receiverName: '', // 收件人名称
+  receiverMobile: '', // 收件人手机
+  receiverAreaId: null, //收件人地区编号
+  receiverDetailAddress: '' //收件人详细地址
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (row: TradeOrderApi.OrderVO) => {
+  resetForm()
+  // 设置数据
+  copyValueToTarget(formData.value, row)
+  dialogVisible.value = true
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = unref(formData)
+    await TradeOrderApi.adjustAddress(data)
+    message.success(t('common.updateSuccess'))
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success', true)
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: 0, // 订单编号
+    receiverName: '', // 收件人名称
+    receiverMobile: '', // 收件人手机
+    receiverAreaId: null, //收件人地区编号
+    receiverDetailAddress: '' //收件人详细地址
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 89 - 0
src/views/mall/trade/order/components/OrderAdjustPriceForm.vue

@@ -0,0 +1,89 @@
+<template>
+  <Dialog v-model="dialogVisible" title="订单调价" width="25%">
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="100px">
+      <el-form-item label="应付金额(总)">
+        <el-input v-model="formData.payPrice" disabled />
+      </el-form-item>
+      <el-form-item label="订单调价">
+        <el-input-number v-model="formData.adjustPrice" :precision="2" :step="0.1" class="w-100%" />
+        <el-tag class="mt-10px" type="warning">订单调价。 正数,加价;负数,减价</el-tag>
+      </el-form-item>
+      <el-form-item label="调价后">
+        <el-input v-model="formData.newPayPrice" disabled />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+import * as TradeOrderApi from '@/api/mall/trade/order'
+import { convertToInteger, formatToFraction } from '@/utils'
+import { cloneDeep } from 'lodash-es'
+
+defineOptions({ name: 'OrderAdjustPriceForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formData = ref({
+  id: 0, // 订单编号
+  adjustPrice: 0, // 订单调价
+  payPrice: '', // 应付金额(总)
+  newPayPrice: '' // 调价后应付金额(总)
+})
+watch(
+  () => formData.value.adjustPrice,
+  (data: number) => {
+    formData.value.newPayPrice = formData.value.payPrice.replace('元', '') * 1 + data + '元'
+  }
+)
+
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (row: TradeOrderApi.OrderVO) => {
+  resetForm()
+  formData.value.id = row.id
+  // 设置数据
+  formData.value.adjustPrice = formatToFraction(row.adjustPrice)
+  formData.value.payPrice = formatToFraction(row.payPrice) + '元'
+  dialogVisible.value = true
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = cloneDeep(unref(formData))
+    data.adjustPrice = convertToInteger(data.adjustPrice)
+    delete data.payPrice
+    delete data.newPayPrice
+    await TradeOrderApi.adjustPrice(data)
+    message.success(t('common.updateSuccess'))
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success', true)
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: 0, // 订单编号
+    adjustPrice: 0, // 订单调价
+    payPrice: '', // 应付金额(总)
+    newPayPrice: '' // 调价后应付金额(总)
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 400 - 365
src/views/mall/trade/order/tradeOrderDetail.vue

@@ -1,365 +1,400 @@
-<template>
-  <ContentWrap>
-    <!-- 订单信息 -->
-    <el-descriptions title="订单信息">
-      <el-descriptions-item label="订单号: ">{{ order.no }}</el-descriptions-item>
-      <el-descriptions-item label="配送方式: ">物流配送</el-descriptions-item>
-      <!-- TODO 芋艿:待实现 -->
-      <el-descriptions-item label="营销活动: ">物流配送</el-descriptions-item>
-      <!-- TODO 芋艿:待实现 -->
-      <el-descriptions-item label="订单类型: ">
-        <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="order.type" />
-      </el-descriptions-item>
-      <el-descriptions-item label="收货人: ">{{ order.receiverName }}</el-descriptions-item>
-      <el-descriptions-item label="买家留言: ">{{ order.userRemark }}</el-descriptions-item>
-      <el-descriptions-item label="订单来源: ">
-        <dict-tag :type="DICT_TYPE.TERMINAL" :value="order.terminal" />
-      </el-descriptions-item>
-      <el-descriptions-item label="联系电话: ">{{ order.receiverMobile }}</el-descriptions-item>
-      <el-descriptions-item label="商家备注: ">{{ order.remark }}</el-descriptions-item>
-      <el-descriptions-item label="支付单号: ">{{ order.payOrderId }}</el-descriptions-item>
-      <el-descriptions-item label="付款方式: ">
-        <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE_TYPE" :value="order.payChannelCode" />
-      </el-descriptions-item>
-      <!-- <el-descriptions-item label="买家: ">{{ order.user.nickname }}</el-descriptions-item> -->
-      <!-- TODO 芋艿:待实现:跳转会员 -->
-      <el-descriptions-item label="收货地址: ">
-        {{ order.receiverAreaName }} {{ order.receiverDetailAddress }}
-        <el-link
-          v-clipboard:copy="order.receiverAreaName + ' ' + order.receiverDetailAddress"
-          v-clipboard:success="clipboardSuccess"
-          icon="ep:document-copy"
-          type="primary"
-        />
-      </el-descriptions-item>
-    </el-descriptions>
-
-    <!-- 订单状态 -->
-    <el-descriptions title="订单状态" :column="1">
-      <el-descriptions-item label="订单状态: ">
-        <!-- TODO xiaobai:status 一定有值哈,不用判断 -->
-        <dict-tag
-          v-if="order.status !== ''"
-          :type="DICT_TYPE.TRADE_ORDER_STATUS"
-          :value="order.status"
-        />
-      </el-descriptions-item>
-      <el-descriptions-item label-class-name="no-colon">
-        <el-button type="primary" size="small">调整价格</el-button>
-        <!-- TODO 芋艿:待实现 -->
-        <el-button type="primary" size="small">备注</el-button>
-        <!-- TODO 芋艿:待实现 -->
-        <el-button type="primary" size="small">发货</el-button>
-        <!-- TODO 芋艿:待实现 -->
-        <el-button type="primary" size="small">关闭订单</el-button>
-        <!-- TODO 芋艿:待实现 -->
-        <el-button type="primary" size="small">修改地址</el-button>
-        <!-- TODO 芋艿:待实现 -->
-        <el-button type="primary" size="small">打印电子面单</el-button>
-        <!-- TODO 芋艿:待实现 -->
-        <el-button type="primary" size="small">打印发货单</el-button>
-        <!-- TODO 芋艿:待实现 -->
-        <el-button type="primary" size="small">确认收货</el-button>
-        <!-- TODO 芋艿:待实现 -->
-      </el-descriptions-item>
-      <el-descriptions-item>
-        <template #label><span style="color: red">提醒: </span></template>
-        买家付款成功后,货款将直接进入您的商户号(微信、支付宝)<br />
-        请及时关注你发出的包裹状态,确保可以配送至买家手中 <br />
-        如果买家表示没收到货或货物有问题,请及时联系买家处理,友好协商
-      </el-descriptions-item>
-    </el-descriptions>
-
-    <!-- 物流信息 TODO -->
-
-    <!-- 商品信息 -->
-    <el-descriptions title="商品信息">
-      <el-descriptions-item labelClassName="no-colon">
-        <el-row :gutter="20">
-          <el-col :span="15">
-            <el-table :data="order.items" border>
-              <el-table-column prop="spuName" label="商品" width="auto">
-                <template #default="{ row }">
-                  {{ row.spuName }}
-                  <el-tag
-                    size="medium"
-                    v-for="property in row.properties"
-                    :key="property.propertyId"
-                  >
-                    {{ property.propertyName }}: {{ property.valueName }}</el-tag
-                  >
-                </template>
-              </el-table-column>
-              <el-table-column prop="price" label="商品原价(元)" width="150">
-                <template #default="{ row }"> ¥{{ (row.price / 100.0).toFixed(2) }} </template>
-              </el-table-column>
-              <el-table-column prop="count" label="数量" width="100" />
-              <el-table-column prop="payPrice" label="合计(元)" width="150">
-                <template #default="{ row }"> ¥{{ (row.payPrice / 100.0).toFixed(2) }} </template>
-              </el-table-column>
-              <el-table-column prop="afterSaleStatus" label="售后状态" width="auto">
-                <template #default="{ row }">
-                  <dict-tag
-                    :type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS"
-                    :value="row.afterSaleStatus"
-                  />
-                </template>
-              </el-table-column>
-            </el-table>
-          </el-col>
-          <el-col :span="10" />
-        </el-row>
-      </el-descriptions-item>
-      <!-- 占位 -->
-      <!-- <el-descriptions-item v-for="item in 5" label-class-name="no-colon" :key="item" /> -->
-    </el-descriptions>
-    <el-descriptions column="6">
-      <el-descriptions-item label="商品总额: ">
-        <!-- TODO xiaobai: 是不是 (item.payPrice / 100.0).toFixed(2) -->
-        ¥{{ parseFloat((order.totalPrice / 100.0) as unknown as string).toFixed(2) }}
-      </el-descriptions-item>
-      <el-descriptions-item label="运费金额: ">
-        ¥{{ parseFloat((order.deliveryPrice / 100.0) as unknown as string).toFixed(2) }}
-      </el-descriptions-item>
-      <el-descriptions-item label="订单调价: ">
-        ¥{{
-          parseFloat((order.adjustPrice / 100.0) as unknown as string).toFixed(2)
-        }}</el-descriptions-item
-      >
-
-      <el-descriptions-item>
-        <template #label><span style="color: red">商品优惠: </span></template>
-        <!-- 没理解TODO  order.totalPrice - order.totalPrice -->
-        ¥{{
-          parseFloat(((order.totalPrice - order.totalPrice) / 100.0) as unknown as string).toFixed(
-            2
-          )
-        }}
-      </el-descriptions-item>
-      <el-descriptions-item>
-        <template #label><span style="color: red">订单优惠: </span></template>
-        ¥{{ parseFloat((order.discountPrice / 100.0) as unknown as string).toFixed(2) }}
-      </el-descriptions-item>
-      <el-descriptions-item>
-        <template #label><span style="color: red">积分抵扣: </span></template>
-        ¥{{ parseFloat((order.pointPrice / 100.0) as unknown as string).toFixed(2) }}
-      </el-descriptions-item>
-
-      <el-descriptions-item v-for="item in 5" label-class-name="no-colon" :key="item" />
-      <!-- 占位 -->
-      <el-descriptions-item label="应付金额: ">
-        ¥{{ (order.payPrice / 100.0).toFixed(2) }}
-      </el-descriptions-item>
-    </el-descriptions>
-
-    <!-- TODO 芋艿:需要改改 -->
-    <div v-for="group in detailGroups" :key="group.title">
-      <el-descriptions v-bind="group.groupProps" :title="group.title">
-        <!-- 订单操作日志 -->
-        <el-descriptions-item v-if="group.key === 'orderLog'" labelClassName="no-colon">
-          <el-timeline>
-            <el-timeline-item
-              v-for="activity in detailInfo[group.key]"
-              :key="activity.timestamp"
-              :timestamp="activity.timestamp"
-            >
-              {{ activity.content }}
-            </el-timeline-item>
-          </el-timeline>
-        </el-descriptions-item>
-
-        <!-- 物流信息 -->
-        <!-- TODO @xiaobai:改成一个包裹哈;目前只允许发货一次 -->
-        <el-descriptions-item v-if="group.key === 'expressInfo'" labelClassName="no-colon">
-          <!-- 循环包裹物流信息 -->
-          <div v-show="(pkgInfo = detailInfo[group.key]) !== null" style="border: 1px dashed">
-            <!-- 包裹详情 -->
-            <el-descriptions class="m-5">
-              <el-descriptions-item
-                v-for="(pkgChild, pkgCIdx) in group.children"
-                v-bind="pkgChild.childProps"
-                :key="`pkgChild_${pkgCIdx}`"
-                :label="pkgChild.label"
-              >
-                <!-- 包裹商品列表 -->
-                <template v-if="pkgChild.valueKey === 'goodsList' && pkgInfo[pkgChild.valueKey]">
-                  <div
-                    v-for="(goodInfo, goodInfoIdx) in pkgInfo[pkgChild.valueKey]"
-                    :key="`goodInfo_${goodInfoIdx}`"
-                    style="display: flex"
-                  >
-                    <el-image
-                      style="width: 100px; height: 100px; flex: none"
-                      :src="goodInfo.imgUrl"
-                    />
-                    <el-descriptions :column="1">
-                      <el-descriptions-item labelClassName="no-colon">{{
-                        goodInfo.name
-                      }}</el-descriptions-item>
-                      <el-descriptions-item label="数量">{{ goodInfo.count }}</el-descriptions-item>
-                    </el-descriptions>
-                  </div>
-                </template>
-
-                <!-- 包裹物流详情 -->
-                <template v-else-if="pkgChild.valueKey === 'wlxq'">
-                  <el-row :gutter="10">
-                    <el-col :span="6" :offset="1">
-                      <el-timeline>
-                        <el-timeline-item
-                          v-for="(activity, index) in pkgInfo[pkgChild.valueKey]"
-                          :key="index"
-                          :timestamp="activity.timestamp"
-                        >
-                          {{ activity.content }}
-                        </el-timeline-item>
-                      </el-timeline>
-                    </el-col>
-                  </el-row>
-                </template>
-                <template v-else>
-                  {{ pkgInfo[pkgChild.valueKey] }}
-                </template>
-              </el-descriptions-item>
-            </el-descriptions>
-          </div>
-        </el-descriptions-item>
-      </el-descriptions>
-    </div>
-  </ContentWrap>
-</template>
-<script lang="ts" name="TradeOrderDetail" setup>
-// TODO @xiaobai:在 order 下创建一个 order/detail,然后改名为 index.vue
-import { DICT_TYPE } from '@/utils/dict'
-import * as TradeOrderApi from '@/api/mall/trade/order'
-const message = useMessage() // 消息弹窗
-
-const { query } = useRoute()
-const queryParams = reactive({
-  id: query.id
-})
-const dialogVisible = ref(false)
-const loading = ref(false)
-const order = ref<any>({
-  items: [],
-  user: {}
-}) // 详情数据
-
-const detailGroups = ref([
-  {
-    title: '物流信息',
-    key: 'expressInfo',
-    children: [
-      { label: '发货时间: ', valueKey: 'fhsj' },
-      { label: '物流公司: ', valueKey: 'wlgs' },
-      { label: '运单号: ', valueKey: 'ydh' },
-      { label: '物流状态: ', valueKey: 'wlzt', childProps: { span: 3 } },
-      { label: '物流详情: ', valueKey: 'wlxq' }
-    ]
-  },
-  {
-    title: '订单操作日志',
-    key: 'orderLog'
-  }
-])
-
-const detailInfo = ref({
-  expressInfo:
-    // 物流信息
-    {
-      label: '包裹1',
-      name: 'bg1',
-      fhsj: '2022-11-03 16:50:45',
-      wlgs: '极兔',
-      ydh: '2132123',
-      wlzt: '不支持此快递公司',
-      wlxq: [
-        {
-          content: '正在派送途中,请您准备签收(派件人:王涛,电话:13854563814)',
-          timestamp: '2018-04-15 15:00:16'
-        },
-        {
-          content: '快件到达 【烟台龙口东江村委营业点】',
-          timestamp: '2018-04-13 14:54:19'
-        },
-        {
-          content: '快件已发车',
-          timestamp: '2018-04-11 12:55:52'
-        },
-        {
-          content: '快件已发车',
-          timestamp: '2018-04-11 12:55:52'
-        },
-        {
-          content: '快件已发车',
-          timestamp: '2018-04-11 12:55:52'
-        }
-      ]
-    },
-  orderLog: [
-    // 订单操作日志
-    {
-      content: '买家【乌鸦】关闭了订单',
-      timestamp: '2018-04-15 15:00:16'
-    },
-    {
-      content: '买家【乌鸦】下单了',
-      timestamp: '2018-04-15 15:00:16'
-    }
-  ],
-  goodsInfo: [] // 商品详情tableData
-})
-// 暂考虑一次性加载详情页面所有数据 TODO
-const getlist = async () => {
-  dialogVisible.value = true
-  loading.value = true
-  try {
-    const res = await TradeOrderApi.getOrderDetail(queryParams.id as unknown as number)
-    order.value = res
-    console.log(order)
-  } catch {
-    message.error('获取详情数据失败')
-  } finally {
-    loading.value = false
-  }
-}
-onMounted(async () => {
-  await getlist()
-})
-const clipboardSuccess = () => {
-  message.success('复制成功')
-}
-</script>
-<style lang="scss" scoped>
-:deep(.el-descriptions) {
-  &:not(:nth-child(1)) {
-    margin-top: 20px;
-  }
-
-  .el-descriptions__title {
-    display: flex;
-    align-items: center;
-
-    &::before {
-      display: inline-block;
-      width: 3px;
-      height: 20px;
-      margin-right: 10px;
-      background-color: #409eff;
-      content: '';
-    }
-  }
-
-  .el-descriptions-item__container {
-    margin: 0 10px;
-
-    .no-colon {
-      margin: 0;
-
-      &::after {
-        content: '';
-      }
-    }
-  }
-}
-</style>
+<template>
+  <ContentWrap>
+    <!-- 订单信息 -->
+    <el-descriptions title="订单信息">
+      <el-descriptions-item label="订单号: ">{{ orderInfo.no }}</el-descriptions-item>
+      <el-descriptions-item label="配送方式: ">
+        <dict-tag :type="DICT_TYPE.DELIVERY_TYPE" :value="orderInfo.deliveryType" />
+      </el-descriptions-item>
+      <!-- TODO 营销活动待实现     -->
+      <el-descriptions-item label="营销活动: ">秒杀活动</el-descriptions-item>
+      <el-descriptions-item label="订单类型: ">
+        <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="orderInfo.type" />
+      </el-descriptions-item>
+      <el-descriptions-item label="收货人: ">{{ orderInfo.receiverName }}</el-descriptions-item>
+      <el-descriptions-item label="买家留言: ">{{ orderInfo.userRemark }}</el-descriptions-item>
+      <el-descriptions-item label="订单来源: ">
+        <dict-tag :type="DICT_TYPE.TERMINAL" :value="orderInfo.terminal" />
+      </el-descriptions-item>
+      <el-descriptions-item label="联系电话: ">{{ orderInfo.receiverMobile }}</el-descriptions-item>
+      <el-descriptions-item label="商家备注: ">{{ orderInfo.remark }}</el-descriptions-item>
+      <el-descriptions-item label="支付单号: ">{{ orderInfo.payOrderId }}</el-descriptions-item>
+      <el-descriptions-item label="付款方式: ">
+        <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE_TYPE" :value="orderInfo.payChannelCode" />
+      </el-descriptions-item>
+      <!-- <el-descriptions-item label="买家: ">{{ orderInfo.user.nickname }}</el-descriptions-item> -->
+      <!-- TODO 芋艿:待实现:跳转会员 -->
+      <el-descriptions-item label="收货地址: ">
+        {{ orderInfo.receiverAreaName }} {{ orderInfo.receiverDetailAddress }}
+        <el-link
+          v-clipboard:copy="orderInfo.receiverAreaName + ' ' + orderInfo.receiverDetailAddress"
+          v-clipboard:success="clipboardSuccess"
+          icon="ep:document-copy"
+          type="primary"
+        />
+      </el-descriptions-item>
+    </el-descriptions>
+
+    <!-- 订单状态 -->
+    <el-descriptions :column="1" title="订单状态">
+      <el-descriptions-item label="订单状态: ">
+        <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="orderInfo.status" />
+      </el-descriptions-item>
+      <el-descriptions-item label-class-name="no-colon">
+        <el-button size="small" type="primary" @click="openForm('adjustPrice')">调整价格</el-button>
+        <el-button size="small" type="primary" @click="openForm('remark')">备注</el-button>
+        <el-button size="small" type="primary" @click="openForm('delivery')">发货</el-button>
+        <el-button size="small" type="primary" @click="openForm('adjustAddress')">
+          修改地址
+        </el-button>
+        <!-- TODO 后台商家也需要收货功能吗? -->
+        <el-button size="small" type="primary">确认收货</el-button>
+      </el-descriptions-item>
+      <el-descriptions-item>
+        <template #label><span style="color: red">提醒: </span></template>
+        买家付款成功后,货款将直接进入您的商户号(微信、支付宝)<br />
+        请及时关注你发出的包裹状态,确保可以配送至买家手中 <br />
+        如果买家表示没收到货或货物有问题,请及时联系买家处理,友好协商
+      </el-descriptions-item>
+    </el-descriptions>
+
+    <!-- 商品信息 -->
+    <el-descriptions title="商品信息">
+      <el-descriptions-item labelClassName="no-colon">
+        <el-row :gutter="20">
+          <el-col :span="15">
+            <el-table :data="orderInfo.items" border>
+              <el-table-column label="商品" prop="spuName" width="auto">
+                <template #default="{ row }">
+                  {{ row.spuName }}
+                  <el-tag v-for="property in row.properties" :key="property.propertyId">
+                    {{ property.propertyName }}: {{ property.valueName }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="商品原价(元)" prop="price" width="150">
+                <template #default="{ row }">{{ formatToFraction(row.price) }}</template>
+              </el-table-column>
+              <el-table-column label="数量" prop="count" width="100" />
+              <el-table-column label="合计(元)" prop="payPrice" width="150">
+                <template #default="{ row }">{{ formatToFraction(row.payPrice) }}</template>
+              </el-table-column>
+              <el-table-column label="售后状态" prop="afterSaleStatus" width="120">
+                <template #default="{ row }">
+                  <dict-tag
+                    :type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS"
+                    :value="row.afterSaleStatus"
+                  />
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-col>
+          <el-col :span="10" />
+        </el-row>
+      </el-descriptions-item>
+    </el-descriptions>
+    <el-descriptions :column="6">
+      <el-descriptions-item label="商品总额: ">
+        {{ formatToFraction(orderInfo.totalPrice) }}元
+      </el-descriptions-item>
+      <el-descriptions-item label="运费金额: ">
+        {{ formatToFraction(orderInfo.deliveryPrice) }}元
+      </el-descriptions-item>
+      <el-descriptions-item label="订单调价: ">
+        {{ formatToFraction(orderInfo.adjustPrice) }}元
+      </el-descriptions-item>
+
+      <el-descriptions-item>
+        <template #label><span style="color: red">商品优惠: </span></template>
+        {{ formatToFraction(orderInfo.couponPrice) }}元
+      </el-descriptions-item>
+      <el-descriptions-item>
+        <template #label><span style="color: red">订单优惠: </span></template>
+        {{ formatToFraction(orderInfo.discountPrice) }}元
+      </el-descriptions-item>
+      <el-descriptions-item>
+        <template #label><span style="color: red">积分抵扣: </span></template>
+        {{ formatToFraction(orderInfo.pointPrice) }}元
+      </el-descriptions-item>
+
+      <el-descriptions-item v-for="item in 5" :key="item" label-class-name="no-colon" />
+      <!-- 占位 -->
+      <el-descriptions-item label="应付金额: ">
+        {{ formatToFraction(orderInfo.payPrice) }}元
+      </el-descriptions-item>
+    </el-descriptions>
+
+    <!-- TODO 芋艿:需要改改 -->
+    <div v-for="group in detailGroups" :key="group.title">
+      <el-descriptions :title="group.title" v-bind="group.groupProps">
+        <!-- 订单操作日志 -->
+        <el-descriptions-item v-if="group.key === 'orderLog'" labelClassName="no-colon">
+          <el-timeline>
+            <el-timeline-item
+              v-for="activity in detailInfo[group.key]"
+              :key="activity.timestamp"
+              :timestamp="activity.timestamp"
+            >
+              {{ activity.content }}
+            </el-timeline-item>
+          </el-timeline>
+        </el-descriptions-item>
+
+        <!-- 物流信息 TODO 等物流接口搞定重构一下 -->
+        <!-- TODO @xiaobai:改成一个包裹哈;目前只允许发货一次 -->
+        <el-descriptions-item v-if="group.key === 'expressInfo'" labelClassName="no-colon">
+          <!-- 循环包裹物流信息 -->
+          <div v-show="(pkgInfo = detailInfo[group.key]) !== null" style="border: 1px dashed">
+            <!-- 包裹详情 -->
+            <el-descriptions class="m-5">
+              <el-descriptions-item
+                v-for="(pkgChild, pkgCIdx) in group.children"
+                :key="`pkgChild_${pkgCIdx}`"
+                :label="pkgChild.label"
+                v-bind="pkgChild.childProps"
+              >
+                <!-- 包裹商品列表 -->
+                <template v-if="pkgChild.valueKey === 'goodsList' && pkgInfo[pkgChild.valueKey]">
+                  <div
+                    v-for="(goodInfo, goodInfoIdx) in pkgInfo[pkgChild.valueKey]"
+                    :key="`goodInfo_${goodInfoIdx}`"
+                    style="display: flex"
+                  >
+                    <el-image
+                      :src="goodInfo.imgUrl"
+                      style="width: 100px; height: 100px; flex: none"
+                    />
+                    <el-descriptions :column="1">
+                      <el-descriptions-item labelClassName="no-colon"
+                        >{{ goodInfo.name }}
+                      </el-descriptions-item>
+                      <el-descriptions-item label="数量"
+                        >{{ goodInfo.count }}
+                      </el-descriptions-item>
+                    </el-descriptions>
+                  </div>
+                </template>
+
+                <!-- 包裹物流详情 -->
+                <template v-else-if="pkgChild.valueKey === 'wlxq'">
+                  <el-row :gutter="10">
+                    <el-col :offset="1" :span="6">
+                      <el-timeline>
+                        <el-timeline-item
+                          v-for="(activity, index) in pkgInfo[pkgChild.valueKey]"
+                          :key="index"
+                          :timestamp="activity.timestamp"
+                        >
+                          {{ activity.content }}
+                        </el-timeline-item>
+                      </el-timeline>
+                    </el-col>
+                  </el-row>
+                </template>
+                <template v-else>
+                  {{ pkgInfo[pkgChild.valueKey] }}
+                </template>
+              </el-descriptions-item>
+            </el-descriptions>
+          </div>
+        </el-descriptions-item>
+      </el-descriptions>
+    </div>
+  </ContentWrap>
+  <DeliveryOrderForm ref="deliveryFormRef" @success="getDetail" />
+  <OrderRemarksForm ref="remarksFormRef" @success="getDetail" />
+  <OrderAdjustAddressForm ref="adjustAddressFormRef" @success="getDetail" />
+  <OrderAdjustPriceForm ref="adjustPriceFormRef" @success="getDetail" />
+</template>
+<script lang="ts" setup>
+import * as TradeOrderApi from '@/api/mall/trade/order'
+import { formatToFraction } from '@/utils'
+import { DICT_TYPE } from '@/utils/dict'
+import OrderRemarksForm from '@/views/mall/trade/order/components/OrderRemarksForm.vue'
+import DeliveryOrderForm from '@/views/mall/trade/order/components/DeliveryOrderForm.vue'
+import OrderAdjustAddressForm from '@/views/mall/trade/order/components/OrderAdjustAddressForm.vue'
+import OrderAdjustPriceForm from '@/views/mall/trade/order/components/OrderAdjustPriceForm.vue'
+
+defineOptions({ name: 'TradeOrderDetailForm' })
+
+const message = useMessage() // 消息弹窗
+const { params } = useRoute() // 查询参数
+const orderInfo = ref<TradeOrderApi.OrderVO>({
+  no: '',
+  createTime: null,
+  type: null,
+  terminal: null,
+  userId: null,
+  userIp: '',
+  userRemark: '',
+  status: null,
+  productCount: null,
+  finishTime: null,
+  cancelTime: null,
+  cancelType: null,
+  remark: '',
+  payOrderId: null,
+  payed: false,
+  payTime: null,
+  payChannelCode: '',
+  originalPrice: null,
+  orderPrice: null,
+  discountPrice: null,
+  deliveryPrice: null,
+  adjustPrice: null,
+  payPrice: null,
+  deliveryTemplateId: null,
+  logisticsId: null,
+  logisticsNo: '',
+  deliveryStatus: null,
+  deliveryTime: null,
+  receiveTime: null,
+  receiverName: '',
+  receiverMobile: '',
+  receiverAreaId: null,
+  receiverPostCode: null,
+  receiverDetailAddress: '',
+  afterSaleStatus: null,
+  refundPrice: null,
+  couponPrice: null,
+  pointPrice: null,
+  receiverAreaName: '',
+  items: [],
+  user: {}
+})
+
+const detailGroups = ref([
+  {
+    title: '物流信息',
+    key: 'expressInfo',
+    children: [
+      { label: '发货时间: ', valueKey: 'fhsj' },
+      { label: '物流公司: ', valueKey: 'wlgs' },
+      { label: '运单号: ', valueKey: 'ydh' },
+      { label: '物流状态: ', valueKey: 'wlzt', childProps: { span: 3 } },
+      { label: '物流详情: ', valueKey: 'wlxq' }
+    ]
+  },
+  {
+    title: '订单操作日志',
+    key: 'orderLog'
+  }
+])
+
+const detailInfo = ref({
+  // 物流信息
+  expressInfo: {
+    label: '包裹1',
+    name: 'bg1',
+    fhsj: '2022-11-03 16:50:45',
+    wlgs: '极兔',
+    ydh: '2132123',
+    wlzt: '不支持此快递公司',
+    wlxq: [
+      {
+        content: '正在派送途中,请您准备签收(派件人:王涛,电话:13854563814)',
+        timestamp: '2018-04-15 15:00:16'
+      },
+      {
+        content: '快件到达 【烟台龙口东江村委营业点】',
+        timestamp: '2018-04-13 14:54:19'
+      },
+      {
+        content: '快件已发车',
+        timestamp: '2018-04-11 12:55:52'
+      },
+      {
+        content: '快件已发车',
+        timestamp: '2018-04-11 12:55:52'
+      },
+      {
+        content: '快件已发车',
+        timestamp: '2018-04-11 12:55:52'
+      }
+    ]
+  },
+  orderLog: [
+    // 订单操作日志
+    {
+      content: '买家【乌鸦】关闭了订单',
+      timestamp: '2018-04-15 15:00:16'
+    },
+    {
+      content: '买家【乌鸦】下单了',
+      timestamp: '2018-04-15 15:00:16'
+    }
+  ],
+  goodsInfo: [] // 商品详情tableData
+})
+
+const deliveryFormRef = ref() // 发货表单 Ref
+const remarksFormRef = ref() // 订单备注表单 Ref
+const adjustAddressFormRef = ref() // 收货地址表单 Ref
+const adjustPriceFormRef = ref() // 订单调价表单 Ref
+const openForm = (type: string) => {
+  switch (type) {
+    case 'remark':
+      remarksFormRef.value?.open(orderInfo.value)
+      break
+    case 'delivery':
+      deliveryFormRef.value?.open(orderInfo.value.id)
+      break
+    case 'adjustAddress':
+      adjustAddressFormRef.value?.open(orderInfo.value)
+      break
+    case 'adjustPrice':
+      adjustPriceFormRef.value?.open(orderInfo.value)
+      break
+  }
+}
+
+/** 获得详情 */
+const getDetail = async () => {
+  const id = params.orderId as unknown as number
+  if (id) {
+    const res = (await TradeOrderApi.getOrder(id)) as TradeOrderApi.OrderVO
+    orderInfo.value = res
+  }
+}
+
+onMounted(async () => {
+  await getDetail()
+})
+
+const clipboardSuccess = () => {
+  message.success('复制成功')
+}
+</script>
+<style lang="scss" scoped>
+:deep(.el-descriptions) {
+  &:not(:nth-child(1)) {
+    margin-top: 20px;
+  }
+
+  .el-descriptions__title {
+    display: flex;
+    align-items: center;
+
+    &::before {
+      display: inline-block;
+      width: 3px;
+      height: 20px;
+      margin-right: 10px;
+      background-color: #409eff;
+      content: '';
+    }
+  }
+
+  .el-descriptions-item__container {
+    margin: 0 10px;
+
+    .no-colon {
+      margin: 0;
+
+      &::after {
+        content: '';
+      }
+    }
+  }
+}
+</style>

+ 66 - 0
src/views/mall/trade/order/components/OrderRemarksForm.vue

@@ -0,0 +1,66 @@
+<template>
+  <Dialog v-model="dialogVisible" title="商家备注" width="25%">
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
+      <el-form-item label="备注">
+        <el-input v-model="formData.remark" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+import * as TradeOrderApi from '@/api/mall/trade/order'
+
+defineOptions({ name: 'OrderRemarksForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formData = ref({
+  id: 0, // 订单编号
+  remark: '' // 订单备注
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (row: TradeOrderApi.OrderVO) => {
+  resetForm()
+  // 设置数据
+  formData.value.id = row.id
+  formData.value.remark = row.remark
+  dialogVisible.value = true
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = unref(formData)
+    console.log(data)
+    await TradeOrderApi.remark(data)
+    message.success(t('common.updateSuccess'))
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success', true)
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: 0, // 订单编号
+    remark: '' // 订单备注
+  }
+  formRef.value?.resetFields()
+}
+</script>

ファイルの差分が大きいため隠しています
+ 442 - 572
src/views/mall/trade/order/index.vue