|
|
@@ -41,8 +41,11 @@
|
|
|
<el-select v-model="forms.paymentStatus" :empty-values="[null, undefined]" :value-on-clear="null" clearable
|
|
|
style="width: 100px">
|
|
|
<el-option label="全部" value=""></el-option>
|
|
|
- <el-option label="待支付" value="Pending"></el-option>
|
|
|
+ <el-option label="未支付" value="Unpaid"></el-option>
|
|
|
+ <el-option label="部分支付" value="Partial"></el-option>
|
|
|
<el-option label="已支付" value="Paid"></el-option>
|
|
|
+ <el-option label="退款中" value="Refunding"></el-option>
|
|
|
+ <el-option label="已退款" value="Refunded"></el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="" label-width="20px">
|
|
|
@@ -105,18 +108,18 @@
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="progress" label="进度" width="180">
|
|
|
+ <!-- <el-table-column prop="progress" label="进度" width="180">
|
|
|
<template #default="scope">
|
|
|
<el-progress :percentage="scope.row.progress"></el-progress>
|
|
|
</template>
|
|
|
- </el-table-column>
|
|
|
+ </el-table-column> -->
|
|
|
|
|
|
<el-table-column fixed="right" label="操作" width="320">
|
|
|
<template #default="scope">
|
|
|
<!-- <el-button type="primary" link size="small" @click="edit(scope.row)">编辑</el-button> -->
|
|
|
<!-- <el-button type="success" link size="small" @click="audit(scope.row)">审核</el-button> -->
|
|
|
<el-button type="info" link size="small" @click="attachment(scope.row)">附件</el-button>
|
|
|
- <el-button type="warning" v-if="userAccountId === 'testuser'" link size="small"
|
|
|
+ <el-button type="warning" v-if="userAccountId === 'testuser' && orderCanPay(scope.row)" link size="small"
|
|
|
@click="payment(scope.row)">收款</el-button>
|
|
|
<el-button type="info" link size="small" @click="editSchedule(scope.row)">行程</el-button>
|
|
|
<el-button type="primary" link size="small" @click="editTourists(scope.row)">游客</el-button>
|
|
|
@@ -232,9 +235,10 @@
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
|
|
|
- <el-table-column label="数量" width="80" align="right">
|
|
|
+ <el-table-column label="游客数量" width="180" align="right">
|
|
|
<template #default="scope">
|
|
|
- <div>{{ Number(scope.row.quantity) || 0 }}</div>
|
|
|
+ <el-input-number v-model.number="scope.row.quantity" :min="1"
|
|
|
+ style="width:160px"></el-input-number>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
|
|
|
@@ -259,17 +263,15 @@
|
|
|
|
|
|
<el-row style="margin-top:10px;">
|
|
|
<el-col :span="12">
|
|
|
- <el-form-item label="产品小计" label-width="120px">
|
|
|
- <div style="line-height:36px;">¥{{((formData.details || []).reduce((s, p) => s +
|
|
|
- (Number(p.unitPrice) || 0) * (Number(p.quantity) || 0), 0)).toFixed(2)}}</div>
|
|
|
+ <el-form-item label="当天产品小计" label-width="120px">
|
|
|
+ <div style="line-height:36px;">¥{{ currentDayTotal }}</div>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <!-- <el-col :span="12">
|
|
|
+ <el-col :span="12">
|
|
|
<el-form-item label="订单总金额" label-width="120px">
|
|
|
- <el-input-number v-model.number="formData.totalAmount" :precision="2" :min="0"
|
|
|
- style="width:160px;"></el-input-number>
|
|
|
+ <div style="line-height:36px;">¥{{ totalPrice }}</div>
|
|
|
</el-form-item>
|
|
|
- </el-col> -->
|
|
|
+ </el-col>
|
|
|
</el-row>
|
|
|
</div>
|
|
|
<div v-else style="text-align: center">
|
|
|
@@ -443,7 +445,7 @@
|
|
|
<el-collapse-item title="附件" name="attachments">
|
|
|
<el-row :gutter="10" style="margin-bottom: 10px">
|
|
|
<el-col :span="24">
|
|
|
- <el-button type="primary" size="small" @click="downloadTemplate">下载模板</el-button>
|
|
|
+ <el-button type="primary" size="small" @click="downloadTemplate">下载游客信息模板</el-button>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
<el-row :gutter="10">
|
|
|
@@ -452,7 +454,7 @@
|
|
|
:data="uploadParams" :headers="headers" accept=".xls,.xlsx" :limit="10" :on-success="uploadSuccess"
|
|
|
:file-list="fileList" :on-error="uploadError" :on-remove="removeFile" :before-upload="beforeUpload"
|
|
|
@on-preview="downloadFile">
|
|
|
- <el-button type="primary" size="small">上传<i class="el-icon-plus"></i></el-button>
|
|
|
+ <el-button type="primary" size="small">上传游客信息模板<i class="el-icon-plus"></i></el-button>
|
|
|
</el-upload>
|
|
|
|
|
|
<div class="file-list">
|
|
|
@@ -813,13 +815,13 @@
|
|
|
|
|
|
<el-dialog title="上传附件" v-model="attachDialogVisible" width="700px" append-to-body @close="currentOrderId = ''">
|
|
|
<div style="margin-bottom:12px;">
|
|
|
- <el-button type="primary" size="small" @click="downloadTemplate">下载模板</el-button>
|
|
|
+ <el-button type="primary" size="small" @click="downloadTemplate">下载游客信息模板</el-button>
|
|
|
</div>
|
|
|
|
|
|
<el-upload ref="orderUploadRef" action="/api/BaseUploader/Basic" :show-file-list="false" :data="uploadParams"
|
|
|
:headers="headers" accept=".xls,.xlsx" :limit="10" :on-success="uploadSuccess" :file-list="fileList"
|
|
|
:on-error="uploadError" :on-remove="removeFile" :before-upload="beforeUpload" @on-preview="downloadFile">
|
|
|
- <el-button type="primary" size="small">上传<i class="el-icon-plus"></i></el-button>
|
|
|
+ <el-button type="primary" size="small">上传游客信息模板<i class="el-icon-plus"></i></el-button>
|
|
|
</el-upload>
|
|
|
|
|
|
<div class="file-list" style="margin: 10px 0">
|
|
|
@@ -871,6 +873,32 @@
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
|
|
|
+ <el-dialog title="收款二维码" v-model="onlinePaymentDialogVisible" width="420px" append-to-body
|
|
|
+ @close="cancelOnlinePayment">
|
|
|
+ <div style="text-align:center; padding: 10px 0;">
|
|
|
+ <div style="margin-bottom:8px; font-size:16px;">
|
|
|
+ 收款金额:<strong style="color:#f56c6c">¥{{ (paymentForm.amount || 0).toFixed(2) }}</strong>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div style="margin-bottom:10px; color:#666;">请使用支付客户端扫码支付</div>
|
|
|
+ <div style="display:flex; justify-content:center; align-items:center;">
|
|
|
+ <canvas id="payment-qr-code" style="width: 280px; height: 280px"></canvas>
|
|
|
+ </div>
|
|
|
+ <div style="margin-top:8px; color:#999; font-size:12px;">
|
|
|
+ 订单号:{{ paymentForm.orderNo || '—' }}
|
|
|
+ <el-button type="text" size="mini"
|
|
|
+ @click="() => { navigator.clipboard?.writeText(paymentForm.orderNo || '') }">复制</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button @click="onlinePaymentDialogVisible = false">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="submitOnlinePayment">支付完成</el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
</el-card>
|
|
|
</template>
|
|
|
<script>
|
|
|
@@ -900,6 +928,22 @@ import { getTravelAgencies } from '@/api/travelAgency';
|
|
|
import moment from 'moment/moment';
|
|
|
import { ProductTypes, FileTypeMap } from '@/constant';
|
|
|
import utils from '@/utils/util';
|
|
|
+import QRCode from 'qrcode';
|
|
|
+import { getAuthUrl } from '@/api/pay';
|
|
|
+
|
|
|
+const QRCodeOpts = {
|
|
|
+ errorCorrectionLevel: 'H', //容错级别
|
|
|
+ type: 'image/png', //生成的二维码类型
|
|
|
+ quality: 0.3, //二维码质量
|
|
|
+ margin: 0, //二维码留白边距
|
|
|
+ width: 280, //宽
|
|
|
+ height: 280, //高
|
|
|
+ text: 'http://www.xxx.com', //二维码内容
|
|
|
+ color: {
|
|
|
+ dark: '#333333', //前景色
|
|
|
+ light: '#fff', //背景色
|
|
|
+ },
|
|
|
+};
|
|
|
|
|
|
export default {
|
|
|
name: "OrderManage",
|
|
|
@@ -928,7 +972,7 @@ export default {
|
|
|
{ label: "游玩天数", prop: "travelDays" },
|
|
|
{ label: "人数", prop: "touristCount" },
|
|
|
{ label: "金额", prop: "totalAmount" },
|
|
|
- { label: "金额", prop: "paidAmount" },
|
|
|
+ { label: "已付金额", prop: "paidAmount" },
|
|
|
{ label: "订单状态", prop: "status" },
|
|
|
{ label: "审核状态", prop: "auditStatus" },
|
|
|
{ label: "支付状态", prop: "paymentStatus" },
|
|
|
@@ -1081,6 +1125,7 @@ export default {
|
|
|
method: 'Online',
|
|
|
orderNo: '',
|
|
|
},
|
|
|
+ onlinePaymentDialogVisible: false,
|
|
|
};
|
|
|
},
|
|
|
methods: {
|
|
|
@@ -1268,6 +1313,52 @@ export default {
|
|
|
orderNo: '',
|
|
|
};
|
|
|
},
|
|
|
+ submitPayment() {
|
|
|
+ if (this.paymentForm.method === 'Online') {
|
|
|
+ // 在线支付,生成二维码
|
|
|
+ this.onlinePaymentDialogVisible = true;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.generateWeChatQRCode();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // TODO
|
|
|
+ this.$message.success('收款成功');
|
|
|
+ this.paymentDialogVisible = false;
|
|
|
+ this.getOrderList();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async generateWeChatQRCode() {
|
|
|
+ const { orderNo, amount } = this.paymentForm;
|
|
|
+ const qrCodeContainer = document.getElementById('payment-qr-code');
|
|
|
+ qrCodeContainer.innerHTML = '';
|
|
|
+ const state = { amount };
|
|
|
+ const redirectUrl = encodeURIComponent(`${window.location.origin}/payment/detail/${orderNo}`); // 回调地址,获取到 code 之后重定向的 URL
|
|
|
+ // const res = await getAuthUrl(redirectUrl, JSON.stringify(state));
|
|
|
+ // const authUrl = res?.data?.authUrl?.replaceAll('ljyx.', 'ljyxweb.');
|
|
|
+ // const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx55b78e406222f02c&redirect_uri=https://ljyxweb.hhtrip.com.cn/payment/detail/${orderNo}&response_type=code&scope=snsapi_base&state=${JSON.stringify(state)}&connect_redirect=1#wechat_redirect`
|
|
|
+ const authUrl = `${window.location.origin}/WxPortal/GetAuthUrl?redirectUrl=${redirectUrl}&state=${encodeURIComponent(JSON.stringify(state))}&snsapi=0`;
|
|
|
+ console.log('---auth url---', decodeURIComponent(authUrl));
|
|
|
+ // if (!authUrl) {
|
|
|
+ // this.$message.error('二维码加载失败');
|
|
|
+ // return;
|
|
|
+ // };
|
|
|
+ // 将获取到的数据(val)画到msg(canvas)上
|
|
|
+ QRCode.toCanvas(qrCodeContainer, authUrl, QRCodeOpts, (error) => {
|
|
|
+ if (error) {
|
|
|
+ console.log('二维码加载失败', error);
|
|
|
+ this.$message.error('二维码加载失败');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ cancelOnlinePayment() {
|
|
|
+ this.onlinePaymentDialogVisible = false;
|
|
|
+ document.getElementById('payment-qr-code').innerHTML = '';
|
|
|
+ },
|
|
|
+ submitOnlinePayment() {
|
|
|
+ this.$message.success('支付成功');
|
|
|
+ this.onlinePaymentDialogVisible = false;
|
|
|
+ this.getOrderList();
|
|
|
+ },
|
|
|
del(row) {
|
|
|
this.$confirm("此操作将删除选择数据, 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", })
|
|
|
.then(() => {
|
|
|
@@ -1351,7 +1442,7 @@ export default {
|
|
|
handelPtSelect(selectedRows, row) {
|
|
|
this.productList.forEach((product) => {
|
|
|
if (selectedRows.find((sr) => sr.id === product.id)) {
|
|
|
- this.tempSelectedProducts.push(({ id: product.id, productName: product.productName }))
|
|
|
+ this.tempSelectedProducts.push(({ id: product.id, productName: product.productName, useDate: this.currUseDate }))
|
|
|
} else {
|
|
|
this.tempSelectedProducts = this.tempSelectedProducts.filter((item) => item.id !== product.id);
|
|
|
}
|
|
|
@@ -1361,7 +1452,7 @@ export default {
|
|
|
handlePtSelectAll(selectedRows) {
|
|
|
this.productList.forEach((product) => {
|
|
|
if (selectedRows.find((sr) => sr.id === product.id)) {
|
|
|
- this.tempSelectedProducts.push(({ id: product.id, productName: product.productName }))
|
|
|
+ this.tempSelectedProducts.push(({ id: product.id, productName: product.productName, useDate: this.currUseDate }))
|
|
|
} else {
|
|
|
this.tempSelectedProducts = this.tempSelectedProducts.filter((item) => item.id !== product.id);
|
|
|
}
|
|
|
@@ -1382,13 +1473,15 @@ export default {
|
|
|
}
|
|
|
|
|
|
this.tempSelectedProducts.forEach((item) => {
|
|
|
- if (!this.formData.details.find((d) => d.productID === item.id)) {
|
|
|
+ const product = this.productList.find(p => p.id === item.id);
|
|
|
+
|
|
|
+ if (!this.formData.details.find((d) => d.productID === item.id && d.useDate === item.useDate) && product) {
|
|
|
this.formData.details.push({
|
|
|
- productID: item.id,
|
|
|
- productName: item.productName,
|
|
|
- productCode: item.productCode,
|
|
|
- productType: ProductTypes[item.type] || item.type,
|
|
|
- unitPrice: item.price,
|
|
|
+ productID: product.id,
|
|
|
+ productName: product.productName,
|
|
|
+ productCode: product.productCode,
|
|
|
+ productType: ProductTypes[product.type] || product.type,
|
|
|
+ unitPrice: product.price,
|
|
|
useDate: this.currUseDate,
|
|
|
quantity: 1,
|
|
|
remark: ''
|
|
|
@@ -1491,6 +1584,9 @@ export default {
|
|
|
}
|
|
|
return texts[status] || status
|
|
|
},
|
|
|
+ orderCanPay(row) {
|
|
|
+ return row.paymentStatus !== 'Paid';
|
|
|
+ },
|
|
|
handleAgencyChange(agencyId) {
|
|
|
const agency = this.agencyOptions.find(item => item.id === agencyId)
|
|
|
if (agency) {
|
|
|
@@ -1509,7 +1605,7 @@ export default {
|
|
|
getScheduleList(orderId) {
|
|
|
// 调用API获取行程列表
|
|
|
getScheduleByOrderId(orderId).then(res => {
|
|
|
- console.log(res, 111);
|
|
|
+ console.log(res, 'scheduleList');
|
|
|
this.scheduleList = res.data;
|
|
|
});
|
|
|
},
|
|
|
@@ -1644,6 +1740,16 @@ export default {
|
|
|
},
|
|
|
},
|
|
|
computed: {
|
|
|
+ currentDayTotal() {
|
|
|
+ const { formData, currUseDate } = this;
|
|
|
+ return ((formData.details || []).filter((d) => d.useDate === currUseDate).reduce((s, p) => s +
|
|
|
+ (Number(p.unitPrice) || 0) * (Number(p.quantity) || 0), 0)).toFixed(2)
|
|
|
+ },
|
|
|
+ totalPrice() {
|
|
|
+ const { formData } = this;
|
|
|
+ return ((formData.details || []).reduce((s, p) => s +
|
|
|
+ (Number(p.unitPrice) || 0) * (Number(p.quantity) || 0), 0)).toFixed(2)
|
|
|
+ },
|
|
|
travelInfo() {
|
|
|
return {
|
|
|
travelStartDate: this.formData.travelStartDate,
|