diff --git a/src/api/mall/trade/order/index.ts b/src/api/mall/trade/order/index.ts index 80669c57..c77e939b 100644 --- a/src/api/mall/trade/order/index.ts +++ b/src/api/mall/trade/order/index.ts @@ -41,15 +41,22 @@ export interface OrderVO { refundPrice?: number | null // 退款金额 couponId?: number | null // 优惠劵编号 couponPrice?: number | null // 优惠劵减免金额 + vipPrice?: number | null // VIP 减免金额 pointPrice?: number | null // 积分抵扣的金额 receiverAreaName?: string //收件人地区名字 items?: OrderItemRespVO[] // 订单项列表 - // 用户信息 + // 下单用户信息 user?: { id?: number | null nickname?: string avatar?: string } + // 推广用户信息 + brokerageUser?: { + id?: number | null + nickname?: string + avatar?: string + } // 订单操作日志 logs?: OrderLogRespVO[] } @@ -114,21 +121,21 @@ export interface DeliveryVO { } // 订单发货 -export const delivery = async (data: DeliveryVO) => { +export const deliveryOrder = async (data: DeliveryVO) => { return await request.put({ url: `/trade/order/delivery`, data }) } // 订单备注 -export const updateRemark = async (data: any) => { +export const updateOrderRemark = async (data: any) => { return await request.put({ url: `/trade/order/update-remark`, data }) } // 订单调价 -export const updatePrice = async (data: any) => { +export const updateOrderPrice = async (data: any) => { return await request.put({ url: `/trade/order/update-price`, data }) } // 修改订单地址 -export const updateAddress = async (data: any) => { +export const updateOrderAddress = async (data: any) => { return await request.put({ url: `/trade/order/update-address`, data }) } diff --git a/src/api/system/area/index.ts b/src/api/system/area/index.ts index b7da941f..e91a4997 100644 --- a/src/api/system/area/index.ts +++ b/src/api/system/area/index.ts @@ -5,14 +5,6 @@ export const getAreaTree = async () => { return await request.get({ url: '/system/area/tree' }) } -export const getChildrenArea = async (id: number) => { - return await request.get({ url: '/system/area/get-children?id=' + id }) -} - -export const getAreaListByIds = async (ids) => { - return await request.get({ url: '/system/area/get-by-ids?ids=' + ids }) -} - // 获得 IP 对应的地区名 export const getAreaByIp = async (ip: string) => { return await request.get({ url: '/system/area/get-by-ip?ip=' + ip }) diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index b6f76a73..d8172d27 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -405,7 +405,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ meta: { title: '订单详情', icon: 'ep:view', activeMenu: '/mall/trade/order' } }, { - path: 'after-sale/detail/:orderId(\\d+)', + path: 'after-sale/detail/:id(\\d+)', component: () => import('@/views/mall/trade/afterSale/detail/index.vue'), name: 'TradeAfterSaleDetail', meta: { title: '退款详情', icon: 'ep:view', activeMenu: '/mall/trade/after-sale' } diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 8c57ecd3..a3dc4c2c 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -375,3 +375,17 @@ export const BrokerageWithdrawTypeEnum = { name: '支付宝' } } + +/** + * 配送方式枚举 + */ +export const DeliveryTypeEnum = { + EXPRESS: { + type: 1, + name: '快递发货' + }, + PICK_UP: { + type: 2, + name: '到店自提' + } +} diff --git a/src/views/mall/trade/afterSale/detail/index.vue b/src/views/mall/trade/afterSale/detail/index.vue index 557e6b6e..50c759d5 100644 --- a/src/views/mall/trade/afterSale/detail/index.vue +++ b/src/views/mall/trade/afterSale/detail/index.vue @@ -6,7 +6,6 @@ <el-descriptions-item label="配送方式: "> <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="formData.order.deliveryType" /> </el-descriptions-item> - <!-- TODO 营销活动待实现 --> <el-descriptions-item label="订单类型: "> <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="formData.order.type" /> </el-descriptions-item> @@ -29,8 +28,7 @@ <el-descriptions-item label="付款方式: "> <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="formData.order.payChannelCode" /> </el-descriptions-item> - <!-- TODO 芋艿:待实现:跳转会员 --> - <!-- <el-descriptions-item label="买家: ">{{ formData.user.nickname }}</el-descriptions-item> --> + <el-descriptions-item label="买家: ">{{ formData?.user?.nickname }}</el-descriptions-item> </el-descriptions> <!-- 售后信息 --> @@ -46,7 +44,7 @@ <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_WAY" :value="formData.way" /> </el-descriptions-item> <el-descriptions-item label="退款金额: "> - {{ floatToFixed2(formData.refundPrice) }} + {{ fenToYuan(formData.refundPrice) }} </el-descriptions-item> <el-descriptions-item label="退款原因: ">{{ formData.applyReason }}</el-descriptions-item> <el-descriptions-item label="补充描述: "> @@ -92,7 +90,7 @@ <el-descriptions-item labelClassName="no-colon"> <el-row :gutter="20"> <el-col :span="15"> - <el-table :data="formData.items" border> + <el-table :data="[formData.orderItem]" border> <el-table-column label="商品" prop="spuName" width="auto"> <template #default="{ row }"> {{ row.spuName }} @@ -102,19 +100,11 @@ </template> </el-table-column> <el-table-column label="商品原价" prop="price" width="150"> - <template #default="{ row }">{{ floatToFixed2(row.price) }}元</template> + <template #default="{ row }">{{ fenToYuan(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 }">{{ floatToFixed2(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> + <template #default="{ row }">{{ fenToYuan(row.payPrice) }} 元</template> </el-table-column> </el-table> </el-col> @@ -122,6 +112,8 @@ </el-row> </el-descriptions-item> </el-descriptions> + + <!-- 操作日志 --> <el-descriptions title="售后日志"> <el-descriptions-item labelClassName="no-colon"> <el-timeline> @@ -153,7 +145,7 @@ </template> <script lang="ts" setup> import * as AfterSaleApi from '@/api/mall/trade/afterSale/index' -import { floatToFixed2 } from '@/utils' +import { fenToYuan } from '@/utils' import { DICT_TYPE, getDictLabel, getDictObj } from '@/utils/dict' import { formatDate } from '@/utils/formatTime' import UpdateAuditReasonForm from '@/views/mall/trade/afterSale/form/AfterSaleDisagreeForm.vue' @@ -191,7 +183,7 @@ const getUserTypeColor = (type: number) => { /** 获得详情 */ const getDetail = async () => { - const id = params.orderId as unknown as number + const id = params.id as unknown as number if (id) { const res = await AfterSaleApi.getAfterSale(id) // 没有表单信息则关闭页面返回 @@ -204,44 +196,56 @@ const getDetail = async () => { } /** 同意售后 */ -const agree = () => { - message.confirm('是否同意售后?').then(() => { - AfterSaleApi.agree(formData.value.id) +const agree = async () => { + try { + // 二次确认 + await message.confirm('是否同意售后?') + await AfterSaleApi.agree(formData.value.id) + // 提示成功 message.success(t('common.success')) - getDetail() - }) + await getDetail() + } catch {} } /** 拒绝售后 */ -const disagree = () => { +const disagree = async () => { updateAuditReasonFormRef.value?.open(formData.value) } /** 确认收货 */ -const receive = () => { - message.confirm('是否确认收货?').then(() => { - AfterSaleApi.receive(formData.value.id) +const receive = async () => { + try { + // 二次确认 + await message.confirm('是否确认收货?') + await AfterSaleApi.receive(formData.value.id) + // 提示成功 message.success(t('common.success')) - getDetail() - }) + await getDetail() + } catch {} } /** 拒绝收货 */ -const refuse = () => { - message.confirm('是否拒绝收货?').then(() => { - AfterSaleApi.refuse(formData.value.id) +const refuse = async () => { + try { + // 二次确认 + await message.confirm('是否拒绝收货?') + await AfterSaleApi.refuse(formData.value.id) + // 提示成功 message.success(t('common.success')) - getDetail() - }) + await getDetail() + } catch {} } /** 确认退款 */ -const refund = () => { - message.confirm('是否确认退款?').then(() => { - AfterSaleApi.refund(formData.value.id) +const refund = async () => { + try { + // 二次确认 + await message.confirm('是否确认退款?') + await AfterSaleApi.refund(formData.value.id) + // 提示成功 message.success(t('common.success')) - getDetail() - }) + await getDetail() + } catch {} } /** 图片预览 */ diff --git a/src/views/mall/trade/afterSale/index.vue b/src/views/mall/trade/afterSale/index.vue index 689f751a..c6a5380c 100644 --- a/src/views/mall/trade/afterSale/index.vue +++ b/src/views/mall/trade/afterSale/index.vue @@ -135,17 +135,16 @@ </el-table-column> <el-table-column align="center" label="订单金额" prop="refundPrice"> <template #default="scope"> - <span>{{ floatToFixed2(scope.row.refundPrice) }}元</span> + <span>{{ fenToYuan(scope.row.refundPrice) }} 元</span> </template> </el-table-column> - <!-- TODO 芋艿:未来要加个会员链接 --> <el-table-column align="center" label="买家" prop="user.nickname" /> <el-table-column align="center" label="申请时间" prop="createTime" width="180"> <template #default="scope"> <span>{{ formatDate(scope.row.createTime) }}</span> </template> </el-table-column> - <el-table-column align="center" label="售后状态"> + <el-table-column align="center" label="售后状态" width="100"> <template #default="scope"> <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_STATUS" :value="scope.row.status" /> </template> @@ -177,7 +176,7 @@ import { formatDate } from '@/utils/formatTime' import { createImageViewer } from '@/components/ImageViewer' import { TabsPaneContext } from 'element-plus' import { cloneDeep } from 'lodash-es' -import { floatToFixed2 } from '@/utils' +import { fenToYuan } from '@/utils' defineOptions({ name: 'TradeAfterSale' }) @@ -240,7 +239,7 @@ const tabClick = async (tab: TabsPaneContext) => { /** 处理退款 */ const openAfterSaleDetail = (id: number) => { - push({ name: 'TradeAfterSaleDetail', params: { orderId: id } }) + push({ name: 'TradeAfterSaleDetail', params: { id } }) } /** 查看订单详情 */ diff --git a/src/views/mall/trade/config/index.vue b/src/views/mall/trade/config/index.vue index f79871c3..7905871b 100644 --- a/src/views/mall/trade/config/index.vue +++ b/src/views/mall/trade/config/index.vue @@ -64,6 +64,9 @@ 商城商品满多少金额即可包邮,单位:元 </el-text> </el-form-item> + <el-form-item label="启用门店自提" prop="deliveryPickUpEnabled"> + <el-switch v-model="formData.deliveryPickUpEnabled" style="user-select: none" /> + </el-form-item> </el-tab-pane> <!-- 分销 --> <el-tab-pane label="分销"> @@ -206,7 +209,6 @@ <script setup lang="ts"> import * as ConfigApi from '@/api/mall/trade/config' -import { BrokerageBindModeEnum, BrokerageEnabledConditionEnum } from '@/utils/constants' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' defineOptions({ name: 'TradeConfig' }) @@ -221,6 +223,7 @@ const formData = ref({ afterSaleReturnReasons: [], deliveryExpressFreeEnabled: false, deliveryExpressFreePrice: 0, + deliveryPickUpEnabled: false, brokerageEnabled: false, brokerageEnabledCondition: undefined, brokerageBindMode: undefined, diff --git a/src/views/mall/trade/delivery/express/ExpressForm.vue b/src/views/mall/trade/delivery/express/ExpressForm.vue index 84b5f8ed..f7d5dac7 100644 --- a/src/views/mall/trade/delivery/express/ExpressForm.vue +++ b/src/views/mall/trade/delivery/express/ExpressForm.vue @@ -7,17 +7,17 @@ label-width="120px" v-loading="formLoading" > - <el-form-item label="快递公司编码" prop="code"> + <el-form-item label="公司编码" prop="code"> <el-input v-model="formData.code" placeholder="请输入快递编码" /> </el-form-item> - <el-form-item label="快递公司名称" prop="name"> + <el-form-item label="公司名称" prop="name"> <el-input v-model="formData.name" placeholder="请输入快递名称" /> </el-form-item> - <el-form-item label="快递公司 logo" prop="logo"> + <el-form-item label="公司 logo" prop="logo"> <UploadImg v-model="formData.logo" :limit="1" :is-show-tip="false" /> <div style="font-size: 10px" class="pl-10px">推荐 180x180 图片分辨率</div> </el-form-item> - <el-form-item label="分类排序" prop="sort"> + <el-form-item label="排序" prop="sort"> <el-input-number v-model="formData.sort" controls-position="right" :min="0" /> </el-form-item> <el-form-item label="开启状态" prop="status"> diff --git a/src/views/mall/trade/delivery/express/index.vue b/src/views/mall/trade/delivery/express/index.vue index 7e3f755e..707b7272 100644 --- a/src/views/mall/trade/delivery/express/index.vue +++ b/src/views/mall/trade/delivery/express/index.vue @@ -53,11 +53,11 @@ <!-- 列表 --> <ContentWrap> <el-table v-loading="loading" :data="list"> - <el-table-column label="快递公司编号" prop="code" /> - <el-table-column label="快递公司名称" prop="name" /> - <el-table-column label="快递公司 logo " prop="logo"> + <el-table-column label="公司编码" prop="code" /> + <el-table-column label="公司名称" prop="name" /> + <el-table-column label="公司 logo " prop="logo"> <template #default="scope"> - <img v-if="scope.row.logo" :src="scope.row.logo" alt="快递公司logo" class="h-100px" /> + <img v-if="scope.row.logo" :src="scope.row.logo" alt="公司logo" class="h-40px" /> </template> </el-table-column> <el-table-column label="排序" align="center" prop="sort" /> diff --git a/src/views/mall/trade/delivery/expressTemplate/ExpressTemplateForm.vue b/src/views/mall/trade/delivery/expressTemplate/ExpressTemplateForm.vue index d05f9ca7..09bbc76e 100644 --- a/src/views/mall/trade/delivery/expressTemplate/ExpressTemplateForm.vue +++ b/src/views/mall/trade/delivery/expressTemplate/ExpressTemplateForm.vue @@ -1,5 +1,5 @@ <template> - <Dialog :title="dialogTitle" v-model="dialogVisible" width="80%"> + <Dialog :title="dialogTitle" v-model="dialogVisible" width="1300px"> <el-form ref="formRef" :model="formData" @@ -21,23 +21,19 @@ </el-radio> </el-radio-group> </el-form-item> - <el-form-item label="运费" prop="templateCharge"> - <el-table border style="width: 100%" :data="formData.templateCharge"> - <el-table-column align="center" label="区域" width="180"> + <el-form-item label="运费" prop="charges"> + <el-table border style="width: 100%" :data="formData.charges"> + <el-table-column align="center" label="区域" width="360"> <template #default="{ row }"> - <!-- 区域数据太多,用赖加载方式,要不然性能有问题 --> - <el-tree-select + <el-cascader v-model="row.areaIds" - :load="loadChargeArea" - :props="defaultProps" - node-key="id" - multiple - check-strictly - show-checkbox - lazy - check-on-click-node - :render-after-expand="false" - :cache-data="areaCache" + :options="areaTree" + :props="defaultProps2" + class="w-1/1" + clearable + placeholder="请选择商品分类" + filterable + collapse-tags /> </template> </el-table-column> @@ -85,23 +81,19 @@ <Icon icon="ep:plus" class="mr-5px" /> 添加区域 </el-button> </el-form-item> - <el-form-item label="包邮区域" prop="templateFree"> - <el-table border style="width: 100%" :data="formData.templateFree"> - <el-table-column align="center" label="区域"> + <el-form-item label="包邮区域" prop="frees"> + <el-table border style="width: 100%" :data="formData.frees"> + <el-table-column align="center" label="区域" width="360"> <template #default="{ row }"> - <!-- 区域数据太多,用赖加载方式,要不然性能有问题 --> - <el-tree-select + <el-cascader v-model="row.areaIds" - multiple - lazy - :load="loadFreeArea" - :props="defaultProps" - node-key="id" - check-strictly - show-checkbox - check-on-click-node - :render-after-expand="true" - :cache-data="areaCache" + :options="areaTree" + :props="defaultProps2" + class="w-1/1" + clearable + placeholder="请选择商品分类" + filterable + collapse-tags /> </template> </el-table-column> @@ -140,13 +132,18 @@ <script lang="ts" setup> import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import * as DeliveryExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate' +import * as AreaApi from '@/api/system/area' import { defaultProps } from '@/utils/tree' import { yuanToFen, fenToYuan } from '@/utils' -import { getChildrenArea, getAreaListByIds } from '@/api/system/area' import { cloneDeep } from 'lodash-es' const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 +const defaultProps2 = { + ...defaultProps, + multiple: true +} + const dialogVisible = ref(false) // 弹窗的是否展示 const dialogTitle = ref('') // 弹窗的标题 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 @@ -156,8 +153,8 @@ const formData = ref({ name: '', chargeMode: 1, sort: 0, - templateCharge: [], - templateFree: [] + charges: [], + frees: [] }) const columnTitleMap = new Map() const columnTitle = ref({ @@ -171,9 +168,6 @@ const formRules = reactive({ sort: [{ required: true, message: '分类排序不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref -const areaCache = ref([]) // 由于区域节点懒加载,已选区域节点需要缓存展示 -// TODO @jason:配送的时候,只允许选择省市级别,不允许选择区;如果这样的话,是不是打开弹窗,直接把城市都请求过来; -// TODO @jaosn:因为只有省市两级,感觉就不用特殊做全国逻辑;选择全国,就默认把子节点都选择上;另外,选择父节点,要把子节点选中哈; /** 打开弹窗 */ const open = async (type: string, id?: number) => { @@ -187,30 +181,14 @@ const open = async (type: string, id?: number) => { formLoading.value = true formData.value = await DeliveryExpressTemplateApi.getDeliveryExpressTemplate(id) columnTitle.value = columnTitleMap.get(formData.value.chargeMode) - const chargeAreaIds = [] - const freeAreaIds = [] - formData.value.templateCharge.forEach((item) => { - for (let i = 0; i < item.areaIds.length; i++) { - if (!chargeAreaIds.includes(item.areaIds[i])) { - chargeAreaIds.push(item.areaIds[i]) - } - } - //前端价格以元展示 + formData.value.charges.forEach((item) => { + // 前端价格以元展示 item.startPrice = fenToYuan(item.startPrice) item.extraPrice = fenToYuan(item.extraPrice) }) - formData.value.templateFree.forEach((item) => { - for (let i = 0; i < item.areaIds.length; i++) { - if (!chargeAreaIds.includes(item.areaIds[i]) && !freeAreaIds.includes(item.areaIds[i])) { - freeAreaIds.push(item.areaIds[i]) - } - } + formData.value.frees.forEach((item) => { item.freePrice = fenToYuan(item.freePrice) }) - // 已选的区域节点 - const areaIds = chargeAreaIds.concat(freeAreaIds) - // 区域节点,懒加载方式。已选节点需要缓存展示 - areaCache.value = await getAreaListByIds(areaIds.join(',')) } } finally { formLoading.value = false @@ -228,14 +206,13 @@ const submitForm = async () => { // 提交请求 formLoading.value = true try { - const data = formData.value as DeliveryExpressTemplateApi.DeliveryExpressTemplateVO + const data = cloneDeep(formData.value) as DeliveryExpressTemplateApi.DeliveryExpressTemplateVO // 前端价格以元展示,提交到后端。用分计算 - // TODO @jason:不能直接这样改,要复制出来改。不然后端操作失败,数据已经被改了 - data.templateCharge.forEach((item) => { + data.charges.forEach((item) => { item.startPrice = yuanToFen(item.startPrice) item.extraPrice = yuanToFen(item.extraPrice) }) - data.templateFree.forEach((item) => { + data.frees.forEach((item) => { item.freePrice = yuanToFen(item.freePrice) }) if (formType.value === 'create') { @@ -259,7 +236,7 @@ const resetForm = () => { id: undefined, name: '', chargeMode: 1, - templateCharge: [ + charges: [ { areaIds: [1], startCount: 2, @@ -268,7 +245,7 @@ const resetForm = () => { extraPrice: 10 } ], - templateFree: [], + frees: [], sort: 0 } columnTitle.value = columnTitleMap.get(1) @@ -279,37 +256,10 @@ const resetForm = () => { const changeChargeMode = (chargeMode: number) => { columnTitle.value = columnTitleMap.get(chargeMode) } -const defaultArea = [{ id: 1, name: '全国', disabled: false }] /** 初始化数据 */ -// TODO @jason:是不是不用写这样一个初始化方法,columnTitleMap 直接就可以了呀 -// const columnTitleMap = { -// '1': { -// startCountTitle: '首件', -// extraCountTitle: '续件', -// freeCountTitle: '包邮件数' -// }, -// '2': { -// startCountTitle: '首件重量(kg)', -// extraCountTitle: '续件重量(kg)', -// freeCountTitle: '包邮重量(kg)' -// }, -// '3': { -// startCountTitle: '首件体积(m³)', -// extraCountTitle: '续件体积(m³)', -// freeCountTitle: '包邮体积(m³)' -// } -// } +const areaTree = ref([]) const initData = async () => { - // TODO 从服务端全量加载数据, 后面看懒加载是不是可以从前端获取数据。 目前从后端获取数据 - // formLoading.value = true - // try { - // const data = await getAreaTree() - // areaTree = data - // console.log('areaTree', areaTree) - // } finally { - // formLoading.value = false - // } // 表头标题和计费方式的映射 columnTitleMap.set(1, { startCountTitle: '首件', @@ -326,77 +276,14 @@ const initData = async () => { extraCountTitle: '续件体积(m³)', freeCountTitle: '包邮体积(m³)' }) + // 加载区域数据 + areaTree.value = await AreaApi.getAreaTree() } -/** 懒加载运费区域树 */ -const loadChargeArea = async (node, resolve) => { - //已选区域需要禁止再次选择 - const areaIds = [] - formData.value.templateCharge.forEach((item) => { - if (item.areaIds.length > 0) { - item.areaIds.forEach((areaId) => areaIds.push(areaId)) - } - }) - if (node.isLeaf) return resolve([]) - const length = node.data.length - if (length === 0) { - const data = cloneDeep(defaultArea) - const item = data[0] - if (areaIds.includes(item.id)) { - // TODO 禁止选中的区域有些问题, 导致修改时候不能重新选择 不知道如何处理。 暂时注释掉 @芋艿 有空瞅瞅 - // TODO @jason:先不做这个功能哈。 - //item.disabled = true - } - resolve(data) - } else { - const id = node.data.id - const data = await getChildrenArea(id) - data.forEach((item) => { - if (areaIds.includes(item.id)) { - //item.disabled = true - } - }) - resolve(data) - } -} - -/** 懒加载包邮区域树 */ -const loadFreeArea = async (node, resolve) => { - if (node.isLeaf) return resolve([]) - //已选区域需要禁止再次选择 - const areaIds = [] - formData.value.templateFree.forEach((item) => { - if (item.areaIds.length > 0) { - item.areaIds.forEach((areaId) => areaIds.push(areaId)) - } - }) - const length = node.data.length - if (length === 0) { - // 为空,从全国开始选择。全国 id == 1 - const data = cloneDeep(defaultArea) - const item = data[0] - if (areaIds.includes(item.id)) { - //item.disabled = true - } - resolve(data) - } else { - const id = node.data.id - const data = await getChildrenArea(id) - // 已选区域需要禁止再次选择 - data.forEach((item) => { - if (areaIds.includes(item.id)) { - // TODO 禁止选中的区域有些问题, 导致修改时候不能重新选择 不知道如何处理。 暂时注释掉 @芋艿 有空瞅瞅 - // TODO @jason:先不做这个功能哈。 - //item.disabled = true - } - }) - resolve(data) - } -} /** 添加计费区域 */ const addChargeArea = () => { const data = formData.value - data.templateCharge.push({ + data.charges.push({ areaIds: [], startCount: 1, startPrice: 1, @@ -408,13 +295,13 @@ const addChargeArea = () => { /** 删除计费区域 */ const deleteChargeArea = (index) => { const data = formData.value - data.templateCharge.splice(index, 1) + data.charges.splice(index, 1) } /** 添加包邮区域 */ const addFreeArea = () => { const data = formData.value - data.templateFree.push({ + data.frees.push({ areaIds: [], freeCount: 1, freePrice: 1 @@ -424,7 +311,7 @@ const addFreeArea = () => { /** 删除包邮区域 */ const deleteFreeArea = (index) => { const data = formData.value - data.templateFree.splice(index, 1) + data.frees.splice(index, 1) } /** 初始化 **/ diff --git a/src/views/mall/trade/delivery/expressTemplate/index.vue b/src/views/mall/trade/delivery/expressTemplate/index.vue index 5a4cb7bb..2844e924 100644 --- a/src/views/mall/trade/delivery/expressTemplate/index.vue +++ b/src/views/mall/trade/delivery/expressTemplate/index.vue @@ -51,14 +51,14 @@ <!-- 列表 --> <ContentWrap> <el-table v-loading="loading" :data="list"> - <el-table-column label="编号" prop="id" /> - <el-table-column label="模板名称" prop="name" /> - <el-table-column label="计费方式" prop="chargeMode" align="center"> + <el-table-column label="编号" min-width="60" prop="id" /> + <el-table-column label="模板名称" min-width="100" prop="name" /> + <el-table-column label="计费方式" prop="chargeMode" min-width="100" align="center"> <template #default="scope"> <dict-tag :type="DICT_TYPE.EXPRESS_CHARGE_MODE" :value="scope.row.chargeMode" /> </template> </el-table-column> - <el-table-column label="排序" prop="sort" /> + <el-table-column label="排序" min-width="100" prop="sort" /> <el-table-column label="创建时间" align="center" diff --git a/src/views/mall/trade/delivery/pickUpStore/PickUpStoreForm.vue b/src/views/mall/trade/delivery/pickUpStore/PickUpStoreForm.vue index cb9358ad..59005588 100644 --- a/src/views/mall/trade/delivery/pickUpStore/PickUpStoreForm.vue +++ b/src/views/mall/trade/delivery/pickUpStore/PickUpStoreForm.vue @@ -51,7 +51,7 @@ <el-row> <el-col :span="12"> <el-form-item label="门店所在地区" prop="areaId"> - <el-cascader v-model="formData.areaId" :options="areaList" :props="areaTreeProps" /> + <el-cascader v-model="formData.areaId" :options="areaList" :props="defaultProps" /> </el-form-item> </el-col> <el-col :span="12"> @@ -99,7 +99,7 @@ </el-col> </el-row> <el-form-item label="获取经纬度"> - <el-button type="primary" @click="mapDialogVisible.value = true">获取</el-button> + <el-button type="primary" @click="mapDialogVisible = true">获取</el-button> </el-form-item> </el-form> <template #footer> @@ -121,8 +121,9 @@ import * as DeliveryPickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { CommonStatusEnum } from '@/utils/constants' +import { defaultProps } from '@/utils/tree' import { getAreaTree } from '@/api/system/area' -import * as ConfigApi from '@/api/infra/config' +import * as ConfigApi from '@/api/mall/trade/config' const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 @@ -161,12 +162,6 @@ const formRules = reactive({ status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref -const areaTreeProps = { - children: 'children', - label: 'name', - value: 'id', - emitPath: false -} const areaList = ref() // 区域树 const tencentLbsUrl = ref('') // 腾讯位置服务 url @@ -244,16 +239,8 @@ const selectAddress = function (loc: any): void { mapDialogVisible.value = false } -/** 初始化数据 */ -const initData = async () => { - formLoading.value = true - try { - const data = await getAreaTree() - areaList.value = data - } finally { - formLoading.value = false - } - // TODO @jason:要不创建一个 initTencentLbsMap +/** 初始化腾讯地图 */ +const initTencentLbsMap = async () => { window.selectAddress = selectAddress window.addEventListener( 'message', @@ -267,17 +254,16 @@ const initData = async () => { }, false ) - const data = await ConfigApi.getConfigKey('tencent.lbs.key') - let key = '' - if (data && data.length > 0) { - key = data - } + const data = await ConfigApi.getTradeConfig() + const key = data.tencentLbsKey tencentLbsUrl.value = `https://apis.map.qq.com/tools/locpicker?type=1&key=${key}&referer=myapp` } /** 初始化 **/ -onMounted(() => { - initData() +onMounted(async () => { + areaList.value = await getAreaTree() + // 加载地图 + await initTencentLbsMap() }) </script> <style lang="scss"> diff --git a/src/views/mall/trade/delivery/pickUpStore/index.vue b/src/views/mall/trade/delivery/pickUpStore/index.vue index 2bf29d57..6ffb3c42 100644 --- a/src/views/mall/trade/delivery/pickUpStore/index.vue +++ b/src/views/mall/trade/delivery/pickUpStore/index.vue @@ -65,16 +65,21 @@ <!-- 列表 --> <ContentWrap> <el-table v-loading="loading" :data="list"> - <el-table-column label="编号" prop="id" /> - <el-table-column label="门店 logo" prop="logo"> + <el-table-column label="编号" min-width="80" prop="id" /> + <el-table-column label="门店 logo" min-width="100" prop="logo"> <template #default="scope"> - <img v-if="scope.row.logo" :src="scope.row.logo" alt="门店 logo" class="h-100px" /> + <img v-if="scope.row.logo" :src="scope.row.logo" alt="门店 logo" class="h-50px" /> </template> </el-table-column> - <el-table-column label="门店名称" prop="name" /> - <el-table-column label="门店手机" prop="phone" /> - <el-table-column align="center" label="门店详细地址" prop="detailAddress" /> - <el-table-column align="center" label="开启状态" prop="status"> + <el-table-column label="门店名称" min-width="150" prop="name" /> + <el-table-column label="门店手机" min-width="100" prop="phone" /> + <el-table-column label="地址" min-width="100" prop="detailAddress" /> + <el-table-column label="营业时间" min-width="180"> + <template #default="scope"> + {{ scope.row.openingTime }} ~ {{ scope.row.closingTime }} + </template> + </el-table-column> + <el-table-column align="center" label="开启状态" min-width="100" prop="status"> <template #default="scope"> <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> </template> diff --git a/src/views/mall/trade/order/detail/index.vue b/src/views/mall/trade/order/detail/index.vue index e61b482a..b52876d7 100644 --- a/src/views/mall/trade/order/detail/index.vue +++ b/src/views/mall/trade/order/detail/index.vue @@ -3,35 +3,21 @@ <!-- 订单信息 --> <el-descriptions title="订单信息"> <el-descriptions-item label="订单号: ">{{ formData.no }}</el-descriptions-item> - <el-descriptions-item label="配送方式: "> - <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="formData.deliveryType!" /> - </el-descriptions-item> - <!-- TODO 营销活动待实现 --> - <el-descriptions-item label="营销活动: ">秒杀活动</el-descriptions-item> + <el-descriptions-item label="买家: ">{{ formData?.user?.nickname }}</el-descriptions-item> <el-descriptions-item label="订单类型: "> <dict-tag :type="DICT_TYPE.TRADE_ORDER_TYPE" :value="formData.type!" /> </el-descriptions-item> - <el-descriptions-item label="收货人: ">{{ formData.receiverName }}</el-descriptions-item> - <el-descriptions-item label="买家留言: ">{{ formData.userRemark }}</el-descriptions-item> <el-descriptions-item label="订单来源: "> <dict-tag :type="DICT_TYPE.TERMINAL" :value="formData.terminal!" /> </el-descriptions-item> - <el-descriptions-item label="联系电话: ">{{ formData.receiverMobile }}</el-descriptions-item> + <el-descriptions-item label="买家留言: ">{{ formData.userRemark }}</el-descriptions-item> <el-descriptions-item label="商家备注: ">{{ formData.remark }}</el-descriptions-item> <el-descriptions-item label="支付单号: ">{{ formData.payOrderId }}</el-descriptions-item> <el-descriptions-item label="付款方式: "> <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="formData.payChannelCode!" /> </el-descriptions-item> - <!-- <el-descriptions-item label="买家: ">{{ formData.user.nickname }}</el-descriptions-item> --> - <!-- TODO @puhui999:待实现:跳转会员 --> - <el-descriptions-item label="收货地址: "> - {{ formData.receiverAreaName }} {{ formData.receiverDetailAddress }} - <el-link - v-clipboard:copy="formData.receiverAreaName + ' ' + formData.receiverDetailAddress" - v-clipboard:success="clipboardSuccess" - icon="ep:document-copy" - type="primary" - /> + <el-descriptions-item label="推广用户: " v-if="formData.brokerageUser"> + {{ formData.brokerageUser?.nickname }} </el-descriptions-item> </el-descriptions> @@ -45,10 +31,18 @@ 调整价格 </el-button> <el-button type="primary" @click="remark">备注</el-button> - <el-button v-if="formData.status! === 10" type="primary" @click="delivery"> + <el-button + v-if="formData.status! === 10 && formData.deliveryType === DeliveryTypeEnum.EXPRESS.type" + type="primary" + @click="delivery" + > 发货 </el-button> - <el-button v-if="formData.status! === 10" type="primary" @click="updateAddress"> + <el-button + v-if="formData.status! === 10 && formData.deliveryType === DeliveryTypeEnum.EXPRESS.type" + type="primary" + @click="updateAddress" + > 修改地址 </el-button> </el-descriptions-item> @@ -95,64 +89,91 @@ </el-row> </el-descriptions-item> </el-descriptions> - <el-descriptions :column="6"> + <el-descriptions :column="4"> + <!-- 第一层 --> <el-descriptions-item label="商品总额: "> - {{ fenToYuan(formData.totalPrice!) }}元 + {{ fenToYuan(formData.totalPrice!) }} 元 </el-descriptions-item> <el-descriptions-item label="运费金额: "> - {{ fenToYuan(formData.deliveryPrice!) }}元 + {{ fenToYuan(formData.deliveryPrice!) }} 元 </el-descriptions-item> <el-descriptions-item label="订单调价: "> - {{ fenToYuan(formData.adjustPrice!) }}元 + {{ fenToYuan(formData.adjustPrice!) }} 元 </el-descriptions-item> - + <el-descriptions-item v-for="item in 1" :key="item" label-class-name="no-colon" /> + <!-- 第二层 --> <el-descriptions-item> - <template #label><span style="color: red">商品优惠: </span></template> - {{ fenToYuan(formData.couponPrice!) }}元 + <template #label><span style="color: red">优惠劵优惠: </span></template> + {{ fenToYuan(formData.couponPrice!) }} 元 </el-descriptions-item> <el-descriptions-item> - <template #label><span style="color: red">订单优惠: </span></template> - {{ fenToYuan(formData.discountPrice!) }}元 + <template #label><span style="color: red">VIP 优惠: </span></template> + {{ fenToYuan(formData.vipPrice!) }} 元 + </el-descriptions-item> + <el-descriptions-item> + <template #label><span style="color: red">活动优惠: </span></template> + {{ fenToYuan(formData.discountPrice!) }} 元 </el-descriptions-item> <el-descriptions-item> <template #label><span style="color: red">积分抵扣: </span></template> - {{ fenToYuan(formData.pointPrice!) }}元 + {{ fenToYuan(formData.pointPrice!) }} 元 </el-descriptions-item> - - <el-descriptions-item v-for="item in 5" :key="item" label-class-name="no-colon" /> - <!-- 占位 --> + <!-- 第三层 --> + <el-descriptions-item v-for="item in 3" :key="item" label-class-name="no-colon" /> <el-descriptions-item label="应付金额: "> - {{ fenToYuan(formData.payPrice!) }}元 + {{ fenToYuan(formData.payPrice!) }} 元 </el-descriptions-item> </el-descriptions> - <!-- TODO 芋艿:需要改改 --> - <el-descriptions :column="4" title="物流信息"> - <el-descriptions-item label="物流公司: "> - {{ deliveryExpressList.find((item) => item.id === formData.logisticsId)?.name }} - </el-descriptions-item> - <el-descriptions-item label="运单号: ">{{ formData.logisticsNo }}</el-descriptions-item> - <el-descriptions-item label="发货时间: "> - {{ formatDate(formData.deliveryTime!) }} - </el-descriptions-item> - <el-descriptions-item label="物流状态: "> - <!-- TODO 物流状态怎么获取? --> - <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="formData.deliveryStatus!" /> - </el-descriptions-item> - <!-- 占位 4 --> - <el-descriptions-item v-for="item in 4" :key="item" label-class-name="no-colon" /> - <el-descriptions-item label="物流详情: "> - <el-timeline> - <el-timeline-item - v-for="(express, index) in expressTrackList" - :key="index" - :timestamp="formatDate(express.time)" - > - {{ express.content }} - </el-timeline-item> - </el-timeline> + <!-- 物流信息 --> + <el-descriptions :column="4" title="收货信息"> + <el-descriptions-item label="配送方式: "> + <dict-tag :type="DICT_TYPE.TRADE_DELIVERY_TYPE" :value="formData.deliveryType!" /> </el-descriptions-item> + <el-descriptions-item label="收货人: ">{{ formData.receiverName }}</el-descriptions-item> + <el-descriptions-item label="联系电话: ">{{ formData.receiverMobile }}</el-descriptions-item> + <!-- 快递配送 --> + <div v-if="formData.deliveryType === DeliveryTypeEnum.EXPRESS.type"> + <el-descriptions-item label="收货地址: " v-if="formData.receiverDetailAddress"> + {{ formData.receiverAreaName }} {{ formData.receiverDetailAddress }} + <el-link + v-clipboard:copy="formData.receiverAreaName + ' ' + formData.receiverDetailAddress" + v-clipboard:success="clipboardSuccess" + icon="ep:document-copy" + type="primary" + /> + </el-descriptions-item> + <el-descriptions-item label="物流公司: " v-if="formData.logisticsId"> + {{ deliveryExpressList.find((item) => item.id === formData.logisticsId)?.name }} + </el-descriptions-item> + <el-descriptions-item label="运单号: " v-if="formData.logisticsId"> + {{ formData.logisticsNo }} + </el-descriptions-item> + <el-descriptions-item label="发货时间: " v-if="formatDate.deliveryTime"> + {{ formatDate(formData.deliveryTime) }} + </el-descriptions-item> + <el-descriptions-item v-for="item in 2" :key="item" label-class-name="no-colon" /> + <el-descriptions-item label="物流详情: " v-if="expressTrackList.length > 0"> + <el-timeline> + <el-timeline-item + v-for="(express, index) in expressTrackList" + :key="index" + :timestamp="formatDate(express.time)" + > + {{ express.content }} + </el-timeline-item> + </el-timeline> + </el-descriptions-item> + </div> + <!-- 自提门店 --> + <div v-if="formData.deliveryType === DeliveryTypeEnum.PICK_UP.type"> + <el-descriptions-item label="自提门店: " v-if="formData.pickUpStoreId"> + {{ pickUpStore.name }} + </el-descriptions-item> + </div> </el-descriptions> + + <!-- 订单日志 --> <el-descriptions title="订单操作日志"> <el-descriptions-item labelClassName="no-colon"> <el-timeline> @@ -196,6 +217,8 @@ import OrderUpdateAddressForm from '@/views/mall/trade/order/form/OrderUpdateAdd import OrderUpdatePriceForm from '@/views/mall/trade/order/form/OrderUpdatePriceForm.vue' import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' import { useTagsViewStore } from '@/store/modules/tagsView' +import { DeliveryTypeEnum } from '@/utils/constants' +import * as DeliveryPickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' defineOptions({ name: 'TradeOrderDetail' }) @@ -271,10 +294,20 @@ const clipboardSuccess = () => { /** 初始化 **/ const deliveryExpressList = ref([]) // 物流公司 const expressTrackList = ref([]) // 物流详情 +const pickUpStore = ref({}) // 自提门店 onMounted(async () => { await getDetail() - deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList() - expressTrackList.value = await TradeOrderApi.getExpressTrackList(formData.value.id!) + // 如果配送方式为快递,则查询物流公司 + if (formData.value.deliveryType === DeliveryTypeEnum.EXPRESS.type) { + deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList() + if (form.value.logisticsId) { + expressTrackList.value = await TradeOrderApi.getExpressTrackList(formData.value.id!) + } + } else if (formData.value.deliveryType === DeliveryTypeEnum.PICK_UP.type) { + pickUpStore.value = await DeliveryPickUpStoreApi.getDeliveryPickUpStore( + formData.value.pickUpStoreId + ) + } }) </script> <style lang="scss" scoped> @@ -312,7 +345,7 @@ onMounted(async () => { // 时间线样式调整 :deep(.el-timeline) { - margin: 10px 0px 0px 160px; + margin: 10px 0 0 160px; .el-timeline-item__wrapper { position: relative; diff --git a/src/views/mall/trade/order/form/OrderDeliveryForm.vue b/src/views/mall/trade/order/form/OrderDeliveryForm.vue index 14f9411d..2411f1ce 100644 --- a/src/views/mall/trade/order/form/OrderDeliveryForm.vue +++ b/src/views/mall/trade/order/form/OrderDeliveryForm.vue @@ -54,7 +54,7 @@ const open = async (row: TradeOrderApi.OrderVO) => { resetForm() // 设置数据 copyValueToTarget(formData.value, row) - if (row.logisticsId === null || row.logisticsId === 0) { + if (row.logisticsId === 0) { expressType.value = 'none' } dialogVisible.value = true @@ -73,7 +73,7 @@ const submitForm = async () => { data.logisticsId = 0 data.logisticsNo = '' } - await TradeOrderApi.delivery(data) + await TradeOrderApi.deliveryOrder(data) message.success(t('common.updateSuccess')) dialogVisible.value = false // 发送操作成功的事件 diff --git a/src/views/mall/trade/order/form/OrderUpdateAddressForm.vue b/src/views/mall/trade/order/form/OrderUpdateAddressForm.vue index 0ec6c631..9c857064 100644 --- a/src/views/mall/trade/order/form/OrderUpdateAddressForm.vue +++ b/src/views/mall/trade/order/form/OrderUpdateAddressForm.vue @@ -69,7 +69,7 @@ const submitForm = async () => { formLoading.value = true try { const data = unref(formData) - await TradeOrderApi.updateAddress(data) + await TradeOrderApi.updateOrderAddress(data) message.success(t('common.updateSuccess')) dialogVisible.value = false // 发送操作成功的事件 diff --git a/src/views/mall/trade/order/form/OrderUpdatePriceForm.vue b/src/views/mall/trade/order/form/OrderUpdatePriceForm.vue index cad0f9ae..eb932ffa 100644 --- a/src/views/mall/trade/order/form/OrderUpdatePriceForm.vue +++ b/src/views/mall/trade/order/form/OrderUpdatePriceForm.vue @@ -69,7 +69,7 @@ const submitForm = async () => { data.adjustPrice = convertToInteger(data.adjustPrice) delete data.payPrice delete data.newPayPrice - await TradeOrderApi.updatePrice(data) + await TradeOrderApi.updateOrderPrice(data) message.success(t('common.updateSuccess')) dialogVisible.value = false // 发送操作成功的事件 diff --git a/src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue b/src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue index bbc45a2c..8be1b603 100644 --- a/src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue +++ b/src/views/mall/trade/order/form/OrderUpdateRemarkForm.vue @@ -49,7 +49,7 @@ const submitForm = async () => { formLoading.value = true try { const data = unref(formData) - await TradeOrderApi.updateRemark(data) + await TradeOrderApi.updateOrderRemark(data) message.success(t('common.updateSuccess')) dialogVisible.value = false // 发送操作成功的事件