plus-ui/src/views/oms/order/index.vue

720 lines
25 KiB
Vue
Raw Normal View History

<template>
<div class="app-container" v-if="show">
2025-06-10 17:16:41 +08:00
<el-form-item label="订单类型" prop="orderType">
<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 :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px" size="default" class="ry_form">
<el-form-item label="订单状态" prop="status">
<DictRadio
v-if="orderStatusMap.length > 0"
:radioList="orderStatusMap"
v-model="queryParams.status"
2025-06-05 09:42:18 +08:00
radioData="oms_order_status"
size="small"
:show-all="'all'"
:filter="['11', '12', '13', '14']"
@change="handleQuery"
></DictRadio>
</el-form-item>
2025-06-10 17:16:41 +08:00
<el-form-item label="提现状态" prop="orderType">
<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="orderType">
<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="orderSn">
2025-06-05 16:33:36 +08:00
<el-input v-model.trim="queryParams.orderSn" placeholder="请输入订单编号" clearable size="small" @keyup.enter="handleQuery" />
</el-form-item>
2025-06-10 17:16:41 +08:00
<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="userPhone">
2025-06-05 16:33:36 +08:00
<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">
2025-06-10 17:16:41 +08:00
<el-table-column label="达人信息" prop="couponAmount" width="80"> </el-table-column>
<el-table-column label="买家信息" prop="couponAmount" width="80"> </el-table-column>
<el-table-column label="卖家信息" prop="couponAmount" width="80"> </el-table-column>
<el-table-column label="代理信息" prop="couponAmount" width="80"> </el-table-column>
<el-table-column label="商品信息" prop="couponAmount" width="80"> </el-table-column>
<el-table-column label="分佣信息" prop="couponAmount" width="80"> </el-table-column>
<el-table-column label="代理信息" prop="couponAmount" width="80"> </el-table-column>
<el-table-column label="订单状态" prop="status" width="160">
<template v-slot="scope">
<div>
<el-tag :type="getOrderStatusTag(scope.row.status)" style="margin-right: 10px">
{{ getOrderStatusText(scope.row.status) }}
</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="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" type="text" @click="handleWatch(scope.row)" style="margin-left: 10px">查看 </el-button>
<el-button size="small" type="text" @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="receiverName" width="160">
<template v-slot="scope">
<p>{{ scope.row.nickName }}</p>
<p>{{ scope.row.mark }}</p>
</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" type="text" @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="商品规格" 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="orderSn" width="120" fixed="right">
<template v-slot="scope">
<el-link type="text" icon="Copy" link @click="copy(scope.row.orderSn)" :underline="false">
{{ scope.row.orderSn }}
<el-icon><CopyDocument /></el-icon>
</el-link>
</template>
</el-table-column>
<el-table-column label="操作" class-name="small-padding fixed-width" width="220" fixed="right">
<template v-slot="scope">
<el-button size="small" type="text" @click="goDetail(scope.row)" v-hasPermi="['oms:order:query']">详情 </el-button>
<el-button size="small" type="text" @click="showLog(scope.row.id)" v-hasPermi="['oms:order:log']">日志 </el-button>
<el-button
size="small"
type="text"
@click="handleDelivery(scope.row)"
:disabled="scope.row.status !== 1 && scope.row.status !== 2 && scope.row.status !== 3"
2025-06-10 17:16:41 +08:00
>核销
</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>
<!-- <el-option v-for="(item, index) in experssList" :label="item.expressName" :value="item.expressCode"/>-->
<el-option label="顺丰速运" value="1" />
<el-option label="申通快递" value="2" />
<el-option label="圆通快递" value="2" />
</el-select>
</el-form-item>
<el-form-item label="快递单号" prop="expressSn">
<el-input v-model="deliveryObj.form.expressSn" placeholder="请输入快递单号" 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.orderStatus) }}</h4>
<br />
<h4>操作人{{ item.operateMan }}</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: [],
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 订单表表格数据
omsOrderList: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
payType: 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: {
orderId: null,
expressName: null,
expressSn: null
},
open: false,
rules: {
expressName: [{ required: true, message: '快递公司不能为空', trigger: 'change' }],
expressSn: [{ required: true, message: '快递单号不能为空', 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() {
2025-06-06 11:48:43 +08:00
this.show = true;
const orderStatusMap = await this.getDictionaryByKey('oms_order_status');
this.orderStatusMap = orderStatusMap;
2025-06-06 11:48:43 +08:00
const { phone, status, today } = this.$route.query;
if (phone) {
this.queryParams.userPhone = phone;
}
if (status) {
this.queryParams.status = status;
}
if (today) {
this.setToday();
}
2025-06-06 11:48:43 +08:00
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;
}
2025-06-09 10:23:29 +08:00
const pageReq = { current: pageNum - 1, size: pageSize };
listOmsOrder(query, pageReq).then((response) => {
2025-06-09 10:23:29 +08:00
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.orderId = 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.orderId = null;
this.deliveryObj.form.expressName = null;
this.deliveryObj.form.expressSn = 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) => {
2025-06-09 10:23:29 +08:00
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>