!210 订单列表:列表重构: 完善订单发货、修改地址、订单调价、订单备注

Merge pull request !210 from puhui999/dev-to-dev
This commit is contained in:
芋道源码
2023-08-22 14:13:12 +00:00
committed by Gitee
20 changed files with 1439 additions and 1281 deletions

View File

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

View File

@ -19,6 +19,11 @@ export const getDeliveryExpress = async (id: number) => {
return await request.get({ url: '/trade/delivery/express/get?id=' + id }) 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) => { export const createDeliveryExpress = async (data: DeliveryExpressVO) => {
return await request.post({ url: '/trade/delivery/express/create', data }) return await request.post({ url: '/trade/delivery/express/create', data })

View File

@ -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 }) 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 }) 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) => { export const createDeliveryPickUpStore = async (data: DeliveryPickUpStoreVO) => {
return await request.post({ url: '/trade/delivery/pick-up-store/create', data }) 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) => { export const deleteDeliveryPickUpStore = async (id: number) => {
return await request.delete({ url: '/trade/delivery/pick-up-store/delete?id=' + id }) 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 })
}

View File

@ -1,12 +1,121 @@
import request from '@/config/axios' import request from '@/config/axios'
// 获得交易订单分页 export interface OrderVO {
// TODO @xiaobai改成 getOrderPage id?: number | null // 订单编号
export const getOrderList = (params: PageParam) => { no?: string // 订单流水号
return request.get({ url: '/trade/order/page', params }) createTime?: Date | null // 下单时间
} type?: number | null // 订单类型
terminal?: number | null // 订单来源
// 获得交易订单详情 userId?: number | null // 用户编号
export const getOrderDetail = (id: number) => { userIp?: string // 用户 IP
return request.get({ url: '/trade/order/get-detail?id=' + id }) 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 })
}

View File

@ -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
}

View File

@ -5,32 +5,32 @@ const { t } = useI18n()
* redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击 * redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击
* name:'router-name' 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 * name:'router-name' 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
* meta : { * meta : {
hidden: true 当设置 true 的时候该路由不会再侧边栏出现 如404login等页面(默认 false) hidden: true 当设置 true 的时候该路由不会再侧边栏出现 如404login等页面(默认 false)
alwaysShow: true 当你一个路由下面的 children 声明的路由大于1个时自动会变成嵌套的模式 alwaysShow: true 当你一个路由下面的 children 声明的路由大于1个时自动会变成嵌套的模式
只有一个时,会将那个子路由当做根路由显示在侧边栏, 只有一个时,会将那个子路由当做根路由显示在侧边栏,
若你想不管路由下面的 children 声明的个数都显示你的根路由, 若你想不管路由下面的 children 声明的个数都显示你的根路由,
你可以设置 alwaysShow: true这样它就会忽略之前定义的规则 你可以设置 alwaysShow: true这样它就会忽略之前定义的规则
一直显示根路由(默认 false) 一直显示根路由(默认 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[] = [ const remainingRouter: AppRouteRecordRaw[] = [
{ {
@ -349,7 +349,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
{ {
path: '/property', path: '/property',
component: Layout, component: Layout,
name: 'property', name: 'Property',
meta: { meta: {
hidden: true hidden: true
}, },
@ -411,6 +411,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', path: '/pay',
component: Layout, component: Layout,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

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

View File

@ -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>

File diff suppressed because it is too large Load Diff