plus-ui/src/views/oms/order/index.vue
2025-06-17 18:05:38 +08:00

769 lines
27 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container" v-if="show">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px" size="default" class="ry_form">
<el-form-item label="订单类型" prop="orderType">
<DictRadio
v-model="queryParams.type"
radioData="oms_order_type"
:radioList="orderTypeMap"
size="small"
:show-all="'all'"
@change="handleQuery"
>
</DictRadio>
</el-form-item>
<el-form-item label="订单状态" prop="status">
<DictRadio
v-if="orderStatusMap.length > 0"
:radioList="orderStatusMap"
v-model="queryParams.status"
radioData="oms_order_status"
size="small"
:show-all="'all'"
:filter="['11', '12', '13', '14']"
@change="handleQuery"
></DictRadio>
</el-form-item>
<el-form-item label="提现状态" prop="withdrawStatus">
<DictRadio
v-if="orderWithdrawMap.length > 0"
v-model="queryParams.withdrawStatus"
radioData="oms_withdraw_staus"
:radioList="orderWithdrawMap"
size="small"
:show-all="'all'"
@change="handleQuery"
>
</DictRadio>
</el-form-item>
<el-form-item label="退款状态" prop="aftersaleStatus">
<DictRadio
v-if="orderAftersaleMap.length > 0"
v-model="queryParams.aftersaleStatus"
radioData="oms_aftersale_status"
:radioList="orderAftersaleMap"
size="small"
:show-all="'all'"
@change="handleQuery"
>
</DictRadio>
</el-form-item>
<el-form-item label="订单编号" prop="id">
<el-input v-model.trim="queryParams.orderSn" placeholder="请输入订单编号" clearable size="small" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="交易流水号" prop="orderSn">
<el-input v-model.trim="queryParams.userPhone" placeholder="请输入交易流水号" clearable size="small" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="会员手机号" prop="userPhone">
<el-input v-model.trim="queryParams.userPhone" placeholder="请输入会员手机号" clearable size="small" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="省市区" prop="provinces">
<address-selector v-model="queryParams.provinces" size="small"></address-selector>
</el-form-item>
<el-form-item label="下单时间" prop="Time">
<el-date-picker
v-model="queryParams.Time"
type="datetimerange"
:picker-options="pickerOptions"
range-separator="至"
size="small"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="['00:00:00', '23:59:59']"
align="right"
@change="handleChange"
>
</el-date-picker>
</el-form-item>
<el-form-item class="flex_one tr">
<el-button type="primary" icon="Search" size="small" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" size="small" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="omsOrderList" border cell-class-name="my-cell">
<el-table-column label="推广人信息&买家信息" width="156">
<template v-slot="scope">
<div>{{ scope.row.memberNickname }}</div>
<div>{{ scope.row.memberPhoneEncrypted }}</div>
</template>
</el-table-column>
<!-- <el-table-column label="买家信息" width="116">
<template v-slot="scope">
<div>{{ scope.row.memberUsername }}</div>
<div>{{ scope.row.memberPhoneEncrypted }}</div>
</template>
</el-table-column>-->
<el-table-column label="卖家信息" width="116">
<template v-slot="scope">
<div>{{ scope.row.tenantContactName }}</div>
<div>{{ scope.row.tenantContactPhone }}</div>
</template>
</el-table-column>
<!-- <el-table-column label="代理信息" width="116">
<template v-slot="scope">
<div>代理人姓名:{{ scope.row.deliverySn }}</div>
<div>代理区域:{{ scope.row.deliverySn }}</div>
<div>代理手机号:{{ scope.row.deliverySn }}</div>
</template>
</el-table-column>-->
<!-- <el-table-column label="商品信息">
<template v-slot="scope">
<div>{{ scope.row.productName }}</div>
</template>
</el-table-column>-->
<el-table-column label="核销码" width="130">
<el-image src="" style="width: 100px; height: 100px" />
</el-table-column>
<el-table-column label="商品规格" prop="productList" width="280">
<template v-slot="scope">
<div v-for="item in scope.row.productList" class="product-container">
<el-popover placement="right" trigger="hover">
<el-image :src="item.pic" style="width: 350px; height: 350px" />
<template v-slot:reference>
<el-image class="small-img product-item" :src="item.pic" style="width: 40px; height: 40px" />
</template>
</el-popover>
<div class="product-item" style="margin-left: 5px">
<div class="sp-data">
<span v-for="(value, key) in JSON.parse(item.spData)">{{ key }}{{ value }}&nbsp;</span>
</div>
<div class="product-item quantity">
<span style="margin-right: 10px">¥{{ item.salePrice }}</span>
<span>x{{ item.buyNum }}</span>
</div>
</div>
</div>
</template>
</el-table-column>
<!-- <el-table-column label="分佣信息" prop="couponAmount" width="80"> </el-table-column>-->
<el-table-column label="订单类型" prop="couponAmount" width="100">
<template v-slot="scope">
<el-tag type="primary">
{{ getEmulistLabelById(scope.row.type, orderTypeMap) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="交易编号" prop="id" width="120" align="center">
<template v-slot="scope">
<el-link type="primary" icon="Copy" link @click="copy(scope.row.id)" :underline="false">
{{ scope.row.id }}
<el-icon><CopyDocument /></el-icon>
</el-link>
</template>
</el-table-column>
<el-table-column label="订单编号" prop="orderSn" width="80"> </el-table-column>
<el-table-column label="订单状态" prop="status" width="160">
<template v-slot="scope">
<div>
<el-tag style="margin-right: 10px">
{{ getEmulistLabelById(scope.row.status, orderStatusMap) }}
</el-tag>
</div>
<div v-if="scope.row.deliverySn">
物流单号:{{ scope.row.deliverySn }}
<el-link @click="copy(scope.row.deliverySn)" :underline="false"><i class="el-icon-document-copy el-icon--right"></i></el-link>
</div>
<div v-if="scope.row.deliveryTime">发货时间{{ parseTime(scope.row.deliveryTime, '') }}</div>
</template>
</el-table-column>
<el-table-column label="退款状态" prop="aftersaleStatus" width="100">
<template v-slot="scope">
<el-tag type="primary">
{{ getEmulistLabelById(scope.row.aftersaleStatus, orderAftersaleMap) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="提现状态" prop="withdrawStatus" width="100">
<template v-slot="scope">
<el-tag type="primary">
{{ getEmulistLabelById(scope.row.withdrawStatus, orderWithdrawMap) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="收件信息" prop="receiverName" width="280">
<template v-slot="scope">
<div>
<span>{{ scope.row.decrypt ? scope.row.receiverName : getHiddenName(scope.row.receiverName) }} {{ scope.row.receiverPhone }}</span>
<el-button size="small" text type="primary" @click="handleWatch(scope.row)" style="margin-left: 10px">查看 </el-button>
<el-button size="small" text type="primary" @click="handleUpdate(scope.row)">修改 </el-button>
</div>
<div>
<span>{{ scope.row.receiverProvince }}{{ scope.row.receiverCity }}{{ scope.row.receiverDistrict }}</span>
<span>{{ scope.row.decrypt ? scope.row.receiverDetailAddress : getHiddenDetailAddress(scope.row.receiverDetailAddress) }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="备注留言" prop="note" width="160">
<template v-slot="scope">
<div>
<span v-if="scope.row.merchantNote" class="note-title" style="margin-right: 10px">平台备注</span>
<el-button size="small" text type="primary" @click="handleSaveNote(scope.row)"
>{{ scope.row.merchantNote ? '修改' : '添加平台备注' }}
</el-button>
</div>
<div v-if="scope.row.merchantNote">{{ scope.row.merchantNote }}</div>
<div v-if="scope.row.note" class="note-title">买家备注</div>
<div v-if="scope.row.note">{{ scope.row.note }}</div>
</template>
</el-table-column>
<el-table-column label="下单时间/支付时间" prop="payTime" width="140">
<template v-slot="scope">
<div v-if="scope.row.createTime">{{ parseTime(scope.row.createTime, '{mm}-{dd} {hh}:{ii}') }} 下单</div>
<div v-if="scope.row.payTime">{{ parseTime(scope.row.payTime, '{mm}-{dd} {hh}:{ii}') }} 支付</div>
</template>
</el-table-column>
<el-table-column label="优惠券" prop="couponAmount" width="80">
<template v-slot="scope">
<div v-if="scope.row.couponAmount">{{ scope.row.couponAmount }}</div>
<div v-else></div>
</template>
</el-table-column>
<el-table-column label="合计" prop="totalAmount" width="140">
<template v-slot="scope">
<div>
<span>总数 </span>
<span style="color: red">{{ scope.row.buyNum }}</span>
</div>
<div>实付 {{ scope.row.payAmount }}</div>
</template>
</el-table-column>
<el-table-column label="操作" class-name="small-padding fixed-width" width="150" align="center" fixed="right">
<template v-slot="scope">
<el-button size="small" text type="primary" @click="goDetail(scope.row)" v-hasPermi="['oms:order:query']">详情 </el-button>
<el-button size="small" text type="primary" @click="showLog(scope.row.id)" v-hasPermi="['oms:order:log']">记录 </el-button>
<el-button size="small" text type="primary" @click="handleDelivery(scope.row)">核销 </el-button>
</template>
</el-table-column>
</el-table>
<pagination v-if="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 核销对话框 -->
<el-dialog :title="deliveryObj.title" v-model="deliveryObj.open" width="500px" append-to-body>
<el-form ref="deliveryForm" :model="deliveryObj.form" :rules="deliveryObj.rules" label-width="100px">
<!-- <el-form-item label="快递公司" prop="expressName">
<el-select v-model="deliveryObj.form.expressName" placeholder="请选择快递公司" clearable size="small" filterable>
&lt;!&ndash; <el-option v-for="(item, index) in experssList" :label="item.expressName" :value="item.expressCode"/>&ndash;&gt;
<el-option label="顺丰速运" value="1" />
<el-option label="申通快递" value="2" />
<el-option label="圆通快递" value="2" />
</el-select>
</el-form-item>-->
<el-form-item label="商家ID" prop="usedMerchantId">
<el-input v-model="deliveryObj.form.usedMerchantId" placeholder="请输入待核销商家ID" controls-position="right" :min="0" />
</el-form-item>
</el-form>
<template v-slot:footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDelivery('deliveryForm')"> </el-button>
<el-button @click="cancelDelivery"> </el-button>
</div>
</template>
</el-dialog>
<!-- 保存商家备注对话框 -->
<el-dialog :title="noteObj.title" v-model="noteObj.open" width="500px" append-to-body>
<el-form ref="noteForm" :model="noteObj.form" label-width="100px">
<el-form-item label="备注" prop="merchantNote">
<el-input type="textarea" v-model="noteObj.form.merchantNote" controls-position="right" :min="0" :rows="3" />
</el-form-item>
</el-form>
<template v-slot:footer>
<div class="dialog-footer">
<el-button type="primary" size="small" @click="submitNoteForm()"> 确认修改 </el-button>
<el-button size="small" @click="cancelNote"> </el-button>
</div>
</template>
</el-dialog>
<!-- 日志 -->
<el-dialog :title="logObj.title" v-model="logObj.open" width="500px" append-to-body>
<el-timeline v-if="logObj.logList.length">
<el-timeline-item v-for="item in logObj.logList" placement="top" :timestamp="parseTime(item.createTime, '')">
<el-card>
<h4>{{ getLogEvent(item.status) }}</h4>
<br />
<h4>操作人{{ item.operName }}</h4>
<h4>操作时间{{ item.operTime }}</h4>
<br v-if="item.note" />
<h4 v-if="item.note">备注{{ item.note }}</h4>
</el-card>
</el-timeline-item>
</el-timeline>
<el-empty v-else description="暂无日志数据!" />
</el-dialog>
<el-dialog title="修改收件信息" v-model="modifyReceiverInfo.open" width="500px" append-to-body :close-on-click-modal="false">
<el-form ref="modifyReceiverInfoForm" :model="modifyReceiverInfo.form" label-width="100px" :rules="modifyReceiverInfo.rules">
<el-form-item label="收件人姓名" prop="receiverName">
<el-input v-model="modifyReceiverInfo.form.receiverName" />
</el-form-item>
<el-form-item label="收件人电话" prop="receiverPhone">
<el-input v-model="modifyReceiverInfo.form.receiverPhone" />
</el-form-item>
<el-form-item label="省市区" prop="fullArea">
<AddressSelector v-model="modifyReceiverInfo.form.fullArea" style="width: 100%" />
</el-form-item>
<el-form-item label="详细地址" prop="receiverDetailAddress">
<el-input v-model="modifyReceiverInfo.form.receiverDetailAddress" />
</el-form-item>
</el-form>
<template v-slot:footer>
<div class="dialog-footer">
<el-button type="primary" size="small" @click="asyncOk"> 确认修改 </el-button>
<el-button size="small" @click="modifyReceiverInfo.open = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import {
addOmsOrder,
deliverProduct,
getDecryptPhone,
listOmsOrder,
saveMerchantNote,
updateOmsOrder,
updateReceiverAddress,
viewLog
} from '@/api/oms/order';
import AddressSelector from '@/views/components/AddressSelector/index.vue';
import dateUtil, { dateFormat } from '@/utils/DateUtil';
import { useUserStore } from '@/store/modules/user';
export default {
name: 'OmsOrder',
dicts: ['oms_order_status', 'oms_pay_type'],
components: {
AddressSelector
},
data() {
const validArea = (rule, value, callback) => {
const fullArea = this.modifyReceiverInfo.form.fullArea;
if (fullArea.length < 3) {
callback(new Error('请选择省市区'));
} else {
callback();
}
};
return {
show: false,
// 遮罩层
loading: true,
pickerOptions: {
shortcuts: dateUtil.getTimeShort2()
},
orderStatusMap: [],
orderTypeMap: [],
orderWithdrawMap: [],
orderAftersaleMap: [],
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 订单表表格数据
omsOrderList: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
payType: null,
type: null,
aftersaleStatus: null,
withdrawStatus: null,
status: null,
Time: [],
provinces: [],
receiverProvince: null,
receiverCity: null,
receiverDistrict: null,
orderSn: null,
productName: null,
userPhone: null,
startTime: null,
endTime: null
},
// 表单参数
form: {},
// 表单校验
rules: {
memberId: [{ required: true, message: 'MEMBER_ID不能为空', trigger: 'blur' }],
receiverName: [{ required: true, message: '收货人姓名不能为空', trigger: 'blur' }],
receiverPhone: [{ required: true, message: '收货人电话不能为空', trigger: 'blur' }]
},
showMoreCondition: false,
deliveryObj: {
title: '核销',
form: {
codeValue: null,
usedMerchantId: null
},
open: false,
rules: {
usedMerchantId: [{ required: true, message: '商家ID不能为空', trigger: 'blur' }]
}
},
noteObj: {
title: null,
form: {
id: null,
merchantNote: null
},
open: false
},
logObj: {
title: '日志',
logList: null,
open: false,
loading: false
},
modifyReceiverInfo: {
open: false,
form: {},
rules: {
receiverName: [{ required: true, message: '收件人姓名不能为空', trigger: 'blur' }],
receiverPhone: [{ required: true, message: '收件人电话不能为空', trigger: 'blur' }],
fullArea: [{ required: true, validator: validArea, trigger: 'change' }],
receiverDetailAddress: [{ required: true, message: '详细地址不能为空', trigger: 'blur' }]
}
}
};
},
computed: {
userId: {
get() {
return useUserStore().userId;
}
}
},
async mounted() {
this.show = true;
const orderStatusMap = await this.getDictionaryByKey('oms_order_status');
const orderTypeMap = await this.getDictionaryByKey('oms_order_type');
const orderWithdrawMap = await this.getDictionaryByKey('oms_withdraw_staus');
const orderAftersaleMap = await this.getDictionaryByKey('oms_aftersale_status');
this.orderStatusMap = orderStatusMap;
this.orderTypeMap = orderTypeMap;
this.orderWithdrawMap = orderWithdrawMap;
this.orderAftersaleMap = orderAftersaleMap;
const { phone, status, today } = this.$route.query;
if (phone) {
this.queryParams.userPhone = phone;
}
if (status) {
this.queryParams.status = status;
}
if (today) {
this.setToday();
}
this.getList();
},
methods: {
/** 日期组件设置为今天 */
setToday() {
const temp = new Date();
this.queryParams.Time[0] = dateFormat(new Date(temp.setHours(0, 0, 0, 0)), 'yyyy-MM-dd hh:mm:ss');
this.queryParams.Time[1] = dateFormat(new Date(temp.setHours(23, 59, 59, 0)), 'yyyy-MM-dd hh:mm:ss');
},
/** 查询订单表列表 */
getList() {
if (this.queryParams.Time) {
this.queryParams.startTime = this.queryParams.Time[0];
this.queryParams.endTime = this.queryParams.Time[1];
}
this.loading = true;
const { pageNum, pageSize } = this.queryParams;
const query = { ...this.queryParams, pageNum: undefined, pageSize: undefined };
if (query.provinces) {
const [receiverProvince, receiverCity, receiverDistrict] = query.provinces;
query.receiverProvince = receiverProvince;
query.receiverCity = receiverCity;
query.receiverDistrict = receiverDistrict;
} else {
query.receiverProvince = null;
query.receiverCity = null;
query.receiverDistrict = null;
}
const pageReq = { current: pageNum - 1, size: pageSize };
listOmsOrder(query, pageReq).then((response) => {
const { records, total } = response.data || {};
this.omsOrderList = records;
this.total = total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
id: null,
memberId: null,
memberUsername: null,
totalAmount: null,
purchasePrice: null,
payAmount: null,
freightAmount: null,
payType: null,
status: 0,
aftersaleStatus: 0,
deliveryCompany: null,
deliverySn: null,
autoConfirmDay: null,
receiverName: null,
receiverPhone: null,
receiverPostCode: null,
receiverProvince: null,
receiverCity: null,
receiverDistrict: null,
receiverDetailAddress: null,
note: null,
confirmStatus: 0,
deleteStatus: 0,
paymentTime: null,
deliveryTime: null,
receiveTime: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加订单表';
},
/** 修改按钮操作 */
async handleUpdate(row) {
await this.handleWatch(row);
const { receiverCity, receiverDistrict, receiverProvince } = row;
row.fullArea = [receiverProvince, receiverCity, receiverDistrict];
this.modifyReceiverInfo.form = row;
this.modifyReceiverInfo.open = true;
},
handleWatch(row) {
getDecryptPhone(row.id).then((response) => {
const { data } = response;
if (data) {
row.receiverPhone = data;
row.decrypt = true;
}
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.id != null) {
updateOmsOrder(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
} else {
addOmsOrder(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
}
}
});
},
//时间搜索条件change方法
handleChange(value) {
if (!value) {
this.queryParams.startTime = null;
this.queryParams.endTime = null;
}
},
getOrderStatusTag(status) {
switch (status) {
case 0:
case 1:
return 'info';
case 2:
return 'primary';
case 3:
return 'success';
case 4:
return 'warning';
case 5:
return 'danger';
}
},
getOrderStatusText(status) {
const { label = '' } =
this.orderStatusMap.find((item) => {
return item.value == status;
}) || {};
return label || '未知';
},
getLogEvent(status) {
switch (status) {
case 0:
return '用户下单';
case 1:
return '用户支付成功';
case 2:
return '平台发货';
case 3:
return '用户确认收货';
case 4:
return '取消订单';
case 5:
return '无效订单';
}
},
goDetail(row) {
const id = row.id;
this.$router.push({ path: '/order/detail', query: { id } });
},
copy(data) {
const url = data;
const oInput = document.createElement('input');
oInput.value = url;
document.body.appendChild(oInput);
oInput.select(); // 选择对象;
console.log(oInput.value);
document.execCommand('Copy'); // 执行浏览器复制命令
this.$modal.msgSuccess('复制成功');
oInput.remove();
},
handleDelivery(row) {
this.deliveryObj.form.codeValue = row.id;
this.deliveryObj.open = true;
},
submitDelivery() {
this.$refs['deliveryForm'].validate((valid) => {
if (valid) {
deliverProduct(this.deliveryObj.form).then((resp) => {
this.$modal.msgSuccess('核销成功');
this.cancelDelivery();
this.getList();
});
}
});
},
cancelDelivery() {
this.deliveryObj.open = false;
this.deliveryObj.form.codeValue = null;
this.deliveryObj.form.usedMerchantId = null;
},
handleSaveNote(row) {
const merchantNote = row.merchantNote;
if (merchantNote) {
this.noteObj.title = '修改平台备注';
} else {
this.noteObj.title = '添加平台备注';
}
this.noteObj.form.id = row.id;
this.noteObj.form.merchantNote = row.merchantNote;
this.noteObj.open = true;
},
//备注保存
submitNoteForm() {
saveMerchantNote(this.noteObj.form).then((resp) => {
this.$modal.msgSuccess('修改成功');
this.cancelNote();
this.getList();
});
},
cancelNote() {
this.noteObj.open = false;
this.noteObj.form.id = null;
this.noteObj.form.merchantNote = null;
},
showLog(orderId) {
this.logObj.loading = true;
viewLog(orderId).then((response) => {
const { data = [] } = response;
this.logObj.logList = data || [];
this.logObj.open = true;
this.logObj.loading = false;
});
},
asyncOk() {
this.$refs['modifyReceiverInfoForm'].validate((valid) => {
if (valid) {
const { id, receiverName, fullArea, receiverPhone, receiverDetailAddress } = this.modifyReceiverInfo.form;
const [receiverProvince, receiverCity, receiverDistrict] = fullArea;
updateReceiverAddress({
id,
receiverCity,
receiverDetailAddress,
receiverDistrict,
receiverName,
receiverPhone,
receiverProvince
}).then((resp) => {
this.$modal.msgSuccess('修改成功');
this.getList();
this.modifyReceiverInfo.open = false;
});
}
});
}
}
};
</script>
<style lang="scss">
.product-container {
display: flex;
flex-direction: row;
align-items: center;
width: 340px;
.product-item {
margin: auto;
width: 290px;
.sp-data {
font-size: 13px;
}
.quantity {
font-weight: bold;
font-size: 13px;
}
}
}
.note-title {
font-weight: bold;
}
.el-table .my-cell {
vertical-align: top;
}
.el-link.el-link--default {
color: #409eff;
}
.el-select {
width: 100%;
}
</style>