This commit is contained in:
2025-01-02 10:44:07 +08:00
parent 33709c76be
commit b3c77526a7
24 changed files with 2153 additions and 259 deletions

View File

@@ -16,7 +16,7 @@
<!-- built files will be auto injected -->
</body><script src="<%=BASE_URL %>/tinymce/tinymce.min.js"></script>
<script src="https://www.paypal.com/sdk/js?client-id=ARyoAhBNlTMDEBb6QvJYmK0gA4cfSS6WY0Vr2uJhX3NOe7V9qVCJuNwuRHRO09WGcTgS5AkuTIgRZDcx"></script>
</html>

BIN
src/assets/img/paypal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
src/assets/img/success.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
src/assets/img/zhifubao.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -191,10 +191,7 @@ export default {
index: '1',
title: this.$t('sidebar.author'),
subs: [
{
index: 'PendingPaymentAuthor',
title: this.$t('sidebar.author4')
},
{
index: 'articleList',
title: this.$t('sidebar.author1')
@@ -206,7 +203,10 @@ export default {
{
index: 'articleAdd',
title: this.$t('sidebar.author2')
}
} , {
index: 'orderListAuthor',
title: this.$t('sidebar.author4')
},
]
}
// ,{

View File

@@ -2,12 +2,17 @@
//记得切换
//正式
// const mediaUrl = '/public/';
// const baseUrl = '/';
const mediaUrl = '/public/';
const baseUrl = '/';
const mediaUrl = 'https://submission.tmrjournals.com/public/';
const baseUrl = '/api';
// const mediaUrl = 'https://submission.tmrjournals.com/public/';
// const baseUrl = '/api';
const paypalInfo= {
sandbox: 'ARyoAhBNlTMDEBb6QvJYmK0gA4cfSS6WY0Vr2uJhX3NOe7V9qVCJuNwuRHRO09WGcTgS5AkuTIgRZDcx',//沙盒环境
production: ''
}
//本地(正式环境 )
@@ -27,6 +32,7 @@ const baseUrl = '/api';
export default {
baseUrl,
mediaUrl,
paypalInfo
};
</script>

View File

@@ -149,7 +149,7 @@ const en = {
author: 'Author',
author1: 'My manuscripts',
author2: 'Submit manuscript',
author4: 'Pending payment',
author4: 'Order List',
author3: 'Manuscripts in Draft',
editor: 'Editor',
editor1: 'Paper Editing System',
@@ -380,7 +380,19 @@ const en = {
journal:'Journal',
Paymentamount:'Payment Amount',
Paymentstatus:'Payment Status',
subtotal:'Subtotal',
payment:'Online Payment',
payDetail:'Payment Details',
total:'Total price',
youhui:'Discount',
submitOrder:'Submit Order',
state0:'Obligation',
state1:'Payment successful',
state2:'Cancelled',
paymentmethod:'Payment Method',
Disbursements:'Disbursements',
Confirmorderinformation:'Confirm order information',
orderDetail:'Order information',
}
}

View File

@@ -143,7 +143,7 @@ const zh = {
author1: '我的稿件',
author2: '新增稿件',
author3: '草稿箱',
author4: '待缴费',
author4: '订单列表',
editor: '编辑',
editor1: '待审稿件',
editormanage: '编辑管理',
@@ -373,7 +373,19 @@ const zh = {
journal:'期刊',
Paymentamount:'缴费金额',
Paymentstatus:'缴费状态',
subtotal:'小计',
payment:'在线缴费',
payDetail:'付款详情',
total:'总价',
youhui:'优惠',
submitOrder:'提交订单',
state0:'待付款',
state1:'已缴费',
state2:'已取消',
paymentmethod:'付款方式',
Disbursements:'已付款',
Confirmorderinformation:'确认订单信息',
orderDetail:'订单信息',
}
}

View File

@@ -1,5 +1,6 @@
<template>
<div class="container" >
<el-row :gutter="20" >
<el-alert v-if="alertShow"
:title="'Dear '+ user_name + ' Congratulations! , The information will be hidden after ' + hideSec + ' seconds'"
@@ -12,6 +13,7 @@
</el-col>
</el-row>
<!-- 内容 -->
<el-row :gutter="20" class="content_box mt20">
<!-- 文章引用 -->
<el-col :class="['item', 'borderBottom', Ainfo.refer_state.state? 'passborder' : 'notPassborder']">
@@ -19,6 +21,19 @@
<span v-if="Ainfo.refer_state.state" class="el-icon-check pass status"> Complete</span>
<span v-else class="el-icon-pie-chart notPass status"> Pending</span>
</h5>
<div class="con">
<h4>Manuscript payment </h4>
<p class="mt10"><common-paypal-button style="width: 150px;"
:amount="40.00"
:orderId="4477"
@payment-success="handlePaymentSuccess"
@payment-error="handlePaymentError"
/></p>
</div>
<div class="con">
<h4>HTML Proofread </h4>

View File

@@ -107,13 +107,15 @@
"
>
<i class="el-icon-s-grid" style="color: #fff"></i> {{ $t('articleListEditor.JournalInstallment') }}
</p> <p
</p>
<p
@click="
openJournal({
...scope.row
})
"
style=" background-color: #c2d4ff;
style="
background-color: #c2d4ff;
color: #4665b0;
cursor: pointer;
@@ -126,7 +128,6 @@
<i class="el-icon-connection" style="color: #4665b0"></i> {{ $t('menu.ClassificationmanagementInfo') }}
</p>
<p
@click="
openJournalAgreement({
@@ -144,13 +145,23 @@
<el-dialog :title="$t('GroupClassification.edit')" :visible.sync="editDialogVisible" width="600px" :before-close="handleEditClose">
<el-form ref="detail_form" :model="detailForm" :rules="rules" label-width="165px">
<el-form-item label="Journal :">
<p style="display: flex;align-items: center;justify-content: space-between;">
<p style="display: flex; align-items: center; justify-content: space-between">
<span>{{ detailForm.title }}</span>
<span style="border-radius: 4px;padding: 0 4px;line-height: 24px;height: 24px;box-sizing: border-box;border: 1px solid rgb(0, 102, 153) !important; color: rgb(0, 102, 153);font-size: 12px">
{{ getCycle(currentJournal.cycle) }}
</span>
<span
style="
border-radius: 4px;
padding: 0 4px;
line-height: 24px;
height: 24px;
box-sizing: border-box;
border: 1px solid rgb(0, 102, 153) !important;
color: rgb(0, 102, 153);
font-size: 12px;
"
>
{{ getCycle(currentJournal.cycle) }}
</span>
</p>
</el-form-item>
<!-- <el-form-item label="Cover Image :" prop="image">
<el-upload class="avatar-uploader" ref="upIconIMg"
@@ -177,6 +188,10 @@
<el-input-number v-model="detailForm.kfen" :min="0" v-if="source == 'all'"></el-input-number>
<span v-else>{{ detailForm.kfen }}</span>
</el-form-item>
<el-form-item label="Fee :" prop="fee">
<el-input-number v-model="detailForm.fee" :min="0" v-if="source == 'all'"></el-input-number>
<span v-else>{{ detailForm.fee }}</span>
</el-form-item>
<!-- 简介 -->
<el-form-item label="Introduction :" prop="scope">
<el-input type="textarea" rows="5" v-model="detailForm.scope"></el-input>
@@ -188,7 +203,7 @@
</span>
</el-dialog>
<el-drawer
append-to-body
append-to-body
destroy-on-close
:title="$t('GroupClassification.Journal') + ' : ' + currentJournal.title"
:visible.sync="drawer"
@@ -207,10 +222,14 @@
:before-close="handleCloseJournalInstallment"
size="90%"
>
<commonJournalInstallment ref="commonJournalInstallmentRef" :journal="currentJournal" :urlList="urlList"></commonJournalInstallment>
<commonJournalInstallment
ref="commonJournalInstallmentRef"
:journal="currentJournal"
:urlList="urlList"
></commonJournalInstallment>
</el-drawer>
<el-drawer
append-to-body
append-to-body
destroy-on-close
:title="$t('GroupClassification.Journal') + ' : ' + currentJournal.title"
:visible.sync="drawerAgreement"
@@ -519,16 +538,15 @@ export default {
});
},
openJournalInstallment(data) {
// this.$router.push({
// path: '/JournalInstallment',
// query: {
// journal_id: data.journal_id
// }
// this.$router.push({
// path: '/JournalInstallment',
// query: {
// journal_id: data.journal_id
// }
// })
// })
var that = this;
var that = this;
this.currentJournal = data;
this.drawerJournalInstallment = true;
this.$nextTick(() => {
@@ -545,6 +563,7 @@ export default {
email: data.email,
epassword: data.epassword,
kfen: data.kfen,
fee: data.fee,
scope: data.scope
};
this.editDialogVisible = true;

View File

@@ -1,36 +0,0 @@
<template>
<div>
<PendingPayment ref="PendingPayment" :list="articles">
<template slot="tableItem">
</template>
</PendingPayment>
</div>
</template>
<script>
import PendingPayment from '@/components/page/components/pendingPayment/index.vue';
export default {
components: {
PendingPayment
},
data() {
return {
articles: [
{ id: 1, title: '稿件1', author: '作者1', amount: 100, status: '未缴费' },
{ id: 2, title: '稿件2', author: '作者2', amount: 200, status: '未缴费' },
{ id: 3, title: '稿件3', author: '作者3', amount: 300, status: '未缴费' },
// 更多稿件数据...
]
};
},
methods: {
payArticle(article) {
// 在这里实现缴费逻辑例如调用后端API进行缴费
// 缴费成功后更新article.status为'已缴费'
article.status = '已缴费';
this.$message.success(`已成功为稿件 ${article.title} 缴费`);
}
}
};
</script>

View File

@@ -1,5 +1,7 @@
<template>
<div>
<div class="tab_post">
<div v-for="(item, index) in tabsList" @click="jumpTab(index, item)" :class="tabName == item.refName ? 'P_style' : ''">
<h5>

View File

@@ -56,7 +56,9 @@
<el-badge is-dot :hidden="item.editor_act==1?false:true">
{{item.title}}
</el-badge>
</p>
<p style="margin-bottom: 8px;">
<font style="color: #666b7a;">ID : </font>
{{item.accept_sn}}
@@ -75,12 +77,15 @@
</font>
<b style="font-weight: normal;margin: 0 0 0 5px;">{{item.ctime}}</b>
</p>
<div class="man_state" :style="item.state,'3' | stateChange">
<b :style="item.state,'4' | stateChange">
{{item.state,'tst' | stateChange}}
</b>
</div>
<div class="man_btn">
<span @click="esy_mtps(item.article_id)">
<i class="el-icon-collection"></i>Manuscript Tracking
</span>
@@ -100,7 +105,18 @@
<!-- </el-badge> -->
</span>
</span>
</div>
<el-button v-if="item.state == 6&&item.is_buy==0" size="mini" type="primary" style="position: absolute;top: 38%;right: 10px;background: #ff5000 !important;border-color: #ff5000 !important;" @click="goOrderConfirmation(item)">Payment</el-button>
<el-button v-if="item.is_buy==1" size="mini" type="text" style="position: absolute;top: 38%;right: 10px;color: #ff5000 !important;">{{ $t('pendingPayment.state1') }}</el-button>
<!-- v-if="item.state == 6&&item.is_buy==0" -->
<!-- <common-paypal-button
:amount="item.article_id"
:orderId="item.article_id"
@payment-success="handlePaymentSuccess"
@payment-error="handlePaymentError"
/> -->
</div>
<div class="man_progess" v-if="item.state==4" :style="item.state,'2' | stateChange">
@@ -530,6 +546,22 @@
});
},
goOrderConfirmation(data){
this.$router.push({
path: '/OrderConfirmation',
query: {
id: data.article_id
}
});
},
goOrderConfirmationDetail(data){
this.$router.push({
path: '/OrderDetail',
query: {
id: data.article_id
}
});
},
// 点击稿件内容文件
esy_deta(e) {
this.$api

View File

@@ -0,0 +1,800 @@
<template>
<div class="order-confirmation-box">
<div id="paypal-container" style="display: none">
<div id="paypal-payment-button" style="width: 100%; height: 50px"></div>
</div>
<div class="order-confirmation">
<el-descriptions :title="$t('pendingPayment.Confirmorderinformation')" column="2">
<el-descriptions-item label="ID">{{ articleInfo.accept_sn }}</el-descriptions-item>
<el-descriptions-item :label=" $t('pendingPayment.journal')">{{ journalInfo.title }} </el-descriptions-item>
<el-descriptions-item :span="2" style="width: 100%;" :label="$t('pendingPayment.title')"><p>{{ articleInfo.title }}</p></el-descriptions-item>
</el-descriptions>
</div>
<div
id="settlementContainer"
class="trade-container type-of-affix-right-panel-to-bottom bg-white overflow-hidden flex-col rounded-t-16"
>
<div class="SettlementHeader">
<div class="title1">{{ $t('pendingPayment.payDetail') }}</div>
</div>
<div class="settlementPanelContainer">
<div class="priceWrap">
<div class="priceLine priceLine_total">
<div class="priceTotal_title">{{ $t('pendingPayment.total') }}</div>
<div class="priceRight">
<div class="trade-price-container price">
<span class="trade-price-symbol priceTotal_unit">$</span>
<span class="trade-price-integer priceTotal_num">{{ formatAmount(total) }}</span>
</div>
</div>
</div>
<div class="priceLine priceLine_total">
<div class="priceTotal_title" style="font-weight: 400">{{ $t('pendingPayment.youhui') }}</div>
<div class="priceRight" style="font-weight: 400; color: #7c889c">
<div class="trade-price-container price">
<span class="trade-price-symbol priceTotal_unit" style="font-weight: 400; color: #7c889c">$</span>
<span class="trade-price-integer priceTotal_num" style="font-weight: 400; color: #7c889c">0</span>
</div>
</div>
</div>
<div id="paymentCard" class="trade-container type-of-normal rounded-8 mx-16 bg-gray mt-24 mb-24 pb-20 pt-20">
<div class="SettlementOption">
<div class="title">
<label class="ant-checkbox-wrapper">
<span>
<div class="option">
<img
src="https://img.alicdn.com/imgextra/i2/O1CN01Ao5ka31RmZsasktnV_!!6000000002154-2-tps-88-88.png"
class="optionIcon"
/>
<div class="titleArea">
<div class="clamp-wrap clamp-ellipsis optionTitle" style="-webkit-line-clamp: unset">
{{ $t('pendingPayment.paymentmethod') }}
</div>
<div
class="clamp-wrap clamp-ellipsis optionSubTitle"
style="-webkit-line-clamp: unset"
></div>
</div>
</div>
</span>
</label>
</div>
<div class="SettlementInstallmentOptionArea">
<div class="optionArea">
<div
class="installmentOption"
:class="selectedPaymentMethod == 'PayPal' ? 'isSelect' : ''"
@click="selectPaymentMethod('PayPal')"
>
<div
class="ant-row trade-layout-row"
style="height: 100%; align-items: center; justify-content: flex-start"
>
<div class="trade-layout-leaf">
<div class="iconWrapper">
<img src="@/assets/img/paypal.png" class="icon" />
</div>
</div>
<div
class="ant-col trade-layout-col"
style="width: 74%; align-items: flex-start; justify-content: flex-start"
>
<div class="trade-layout-leaf" style="width: 100%">
<div class="clamp-wrap clamp-ellipsis mainTitle" style="-webkit-line-clamp: unset">
PayPal
</div>
</div>
</div>
<div v-if="selectedPaymentMethod === 'PayPal'" class="checkmark"></div>
</div>
</div>
<!-- <div
class="installmentOption"
:class="selectedPaymentMethod == 'Alipay' ? 'isSelect' : ''"
@click="selectPaymentMethod('Alipay')"
>
<div
class="ant-row trade-layout-row"
style="height: 100%; align-items: center; justify-content: flex-start"
>
<div class="trade-layout-leaf">
<div class="iconWrapper">
<img src="@/assets/img/zhifubao.png" class="icon" />
</div>
</div>
<div
class="ant-col trade-layout-col"
style="width: 74%; align-items: flex-start; justify-content: flex-start"
>
<div class="trade-layout-leaf" style="width: 100%">
<div class="clamp-wrap clamp-ellipsis mainTitle" style="-webkit-line-clamp: unset">
支付宝
</div>
</div>
</div>
<div v-if="selectedPaymentMethod === 'Alipay'" class="checkmark"></div>
</div>
</div> -->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="SettlementSubmit">
<div class="price">
<p class="title2">{{ $t('pendingPayment.Disbursements') }}</p>
<div class="totalPrice">
<div class="trade-price-container">
<span class="trade-price-symbol totalPrice_unit"><span class="currency">$</span></span>
<span class="trade-price-integer totalPrice_num">{{ formatAmount(total) }}</span>
</div>
</div>
</div>
<div class="btnBox">
<div class="btn" @click="submit">{{ $t('pendingPayment.submitOrder') }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
orderInfo: {},
articleInfo: {},
journalInfo: {},
total: '',
selectedPaymentMethod: 'PayPal', // 默认选中 PayPal
articleId: this.$route.query.id,
urlList: {
detail: 'api/Order/preOrderDetail',
createdOrder: 'api/Order/creatArticleOrder',
completeOrder: 'api/Order/completeOrder',
},
orderId: '1234567890', // 订单号
orderItems: [], // 订单明细
totalAmount: '130.00', // 订单总价
needInvoice: false, // 是否需要发票
invoiceTitle: '', // 发票抬头
invoiceContent: '' // 发票内容
};
},
methods: {
submit() {
// 假设 PayPal 按钮的容器有 id="paypal-button-container"
const paypalButtonContainer = document.getElementById('paypal-container');
// 删除所有 PayPal 按钮
if (paypalButtonContainer) {
paypalButtonContainer.innerHTML = '';
paypalButtonContainer.innerHTML = '<div id="paypal-payment-button"></div>';
}
if (process.env.NODE_ENV === 'development') {
console.log('当前是开发环境');
} else if (process.env.NODE_ENV === 'production') {
console.log('当前是生产环境');
} else if (process.env.NODE_ENV === 'test') {
console.log('当前是测试环境');
}
if (this.selectedPaymentMethod == 'PayPal') {
this.getPayPal();
}
},
getPayPal(id) {
var that = this;
window.paypal
.Buttons({
style: {
layout: 'horizontal', // 水平布局
shape: 'rect', // 矩形形状
label: 'paypal', // 显示 PayPal 标签
tagline: false, // 隐藏标语
color: 'blue', // 按钮颜色为蓝色
size: 'small' // 按钮大小为大
},
onInit: () => {
// 支付按钮加载完成 通知原生关闭loading
console.log('--------1.支付按钮加载完成 关闭loading--------');
// 自动点击 执行支付
console.log('--------2.自动点击 执行支付--------');
// 如果按钮获取到 就 自动执行点击 否则显示按钮
const paypalButton = window.frames[1].document.querySelector('.paypal-button');
if (paypalButton) paypalButton.click();
else {
document.querySelector('#paypal-container').style.display = 'block';
// document.querySelector('#loading').style.display = 'none';
}
},
createOrder: (data, actions) => {
return this.$api
.post(this.urlList.createdOrder, {
article_id: this.articleId
})
.then((res) => {
console.log('res at line 222:', res);
that.orderInfo=res.data.detail
document.querySelector('#paypal-container').style.display = 'none';
return res.data.paypal.jsonResponse.id;
});
},
onApprove(data, actions) {
return actions.order.capture().then((details) => {
console.log('details at line 232:', details.id)
const loading = that.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
setTimeout(() => {
loading.close();
that.$router.replace({ name: 'OrderConfirmation' });
// 跳转到新的路由
that.$api
.post(that.urlList.completeOrder, {
order_id: that.orderInfo.order_id
})
.then((res) => {
});
that.$router.push({
path: '/success',
query: {
id: that.articleId
}
});
}, 500);
});
},
onError(error) {
console.error('支付失败:', error);
that.$message.error('Payment error, please contact the journal editor!');
}
})
.render('#paypal-payment-button')
.then(() => {})
.catch((err) => {
console.error('Error rendering PayPal button:', err);
});
document.querySelector('.paypal-overlay').addEventListener('click', function (event) {
event.stopPropagation();
});
},
getDetail() {
this.$api
.post(this.urlList.detail, {
article_id: this.articleId
})
.then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) {
this.articleInfo = res.data.article_detail;
this.journalInfo = res.data.journal_detail;
// this.orderItems = [
// {
// ...this.articleInfo,
// fee: this.journalInfo.fee,
// journal: this.journalInfo.title
// }
// ];
this.total = this.journalInfo.fee;
}
});
},
formatAmount(amount) {
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
selectPaymentMethod(method) {
console.log('method at line 191:', method);
this.selectedPaymentMethod = method;
this.$forceUpdate();
},
payWithAlipay() {
// 实现支付宝支付逻辑
alert('使用支付宝支付');
},
payWithPayPal() {
// 实现PayPal支付逻辑
alert('使用PayPal支付');
}
},
created() {
this.getDetail();
},
activated() {
this.getDetail();
}
};
</script>
<style scoped>
.order-confirmation {
text-align: left;
padding: 20px;
background-color: #fff;
/* border: 1px solid #ccc; */
border-radius: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* margin: 20px auto; */
margin-top: 20;
box-sizing: border-box;
}
h3 {
margin-bottom: 20px;
}
.order-confirmation-box {
width: 1040px;
margin: 0 auto;
height: 100%;
padding-top: 20px;
box-sizing: border-box;
/* background-color: #f3f6f8; */
}
.orderHeader {
align-items: center;
background-color: #f3f6f8;
border-radius: 8px;
color: #11192d;
display: flex;
flex-direction: row;
font-size: 14px;
height: 48px;
padding: 0 16px;
text-align: center;
}
.grey {
width: 100%;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
background-color: #f3f6f8;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
::v-deep .el-table th {
background-color: #f3f6f8 !important;
color: #11192d !important;
}
::v-deep .el-table {
border-top-left-radius: 8px !important;
border-top-right-radius: 8px !important;
}
.price-24 {
font-size: 30px;
height: 30px;
line-height: 34px;
}
.trade-price-container {
float: right;
font-weight: bold;
/* width: 100%; */
/* align-items: flex-end; */
display: flex;
flex-direction: row;
align-items: center;
}
.trade-price-label,
.trade-price-symbol {
color: #ff5000;
font-size: 16px;
height: 16px;
line-height: 16px;
}
.trade-price-symbol {
/* font-family: AlibabaSans102v1TaoBao-Bold */
}
.trade-price-decimal,
.trade-price-integer,
.trade-price-point {
color: #ff5000;
/* font-family: AlibabaSans102v1TaoBao-Bold; */
font-size: 26px;
height: 26px;
line-height: 26px;
}
.super-text,
.trade-tips {
color: #50607a;
font-size: 12px;
}
#settlementContainer {
background-image: linear-gradient(180deg, #ffebe0, #fff 100px);
}
.rounded-t-16 {
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}
.bg-white {
background-color: #fff;
margin-top: 20px;
}
.SettlementHeader {
align-items: center;
display: flex;
flex-direction: row;
margin-bottom: 2px;
padding: 24px 16px;
}
.title1 {
color: #11192d;
font-size: 16px;
font-weight: 600;
height: 16px;
line-height: 16px;
margin-right: 8px;
}
.goodNum {
align-items: baseline;
color: #11192d;
display: flex;
flex-direction: row;
font-size: 14px;
font-weight: 400;
line-height: 16px;
}
.goodNum p {
color: #11192d;
font-size: 18px;
font-weight: 600;
line-height: 16px;
margin: 0 2px;
text-align: center;
}
.priceWrap {
padding: 0 16px;
}
.priceWrap .priceLine {
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: 12px;
}
.priceWrap .priceLine .priceTotal_title {
color: #11192d;
font-size: 14px;
font-weight: 600;
}
.priceWrap .priceLine .priceRight {
align-items: flex-end;
display: flex;
flex-direction: row;
padding-right: 16px;
position: relative;
}
.priceWrap .priceLine .priceRight img {
height: 8px;
position: absolute;
right: 0;
top: 6px;
width: 8px;
}
.priceWrap .priceLine .priceRight img.arrow_up {
transform: rotate(180deg);
}
.priceWrap .priceLine .priceRight .price {
align-items: baseline;
}
.priceWrap .priceLine_total {
margin-bottom: 16px;
}
.priceWrap .priceTotal_unit {
color: #11192d;
font-size: 12px;
font-weight: 700;
line-height: 14px;
margin-right: 2px;
}
.priceWrap .priceTotal_num {
color: #11192d;
font-size: 18px;
font-weight: 700;
line-height: 18px;
}
.priceWrap .pricePromotion_pre {
color: #ff5000;
font-size: 14px;
font-weight: 600;
line-height: 14px;
}
.priceWrap .pricePromotion_unit {
color: #ff5000;
font-size: 12px;
font-weight: 700;
line-height: 14px;
margin: 0 2px 0 4px;
}
.priceWrap .pricePromotion_num {
color: #ff5000;
font-size: 18px;
font-weight: 700;
line-height: 18px;
}
.rounded-8 {
border-radius: 8px;
}
.SettlementOption--Qu5uk29m {
margin-bottom: 16px;
}
.SettlementOption--Qu5uk29m:last-child {
margin-bottom: 0;
}
.option {
align-items: center;
display: flex;
flex-direction: row;
white-space: nowrap;
word-break: keep-all;
}
.optionIcon {
height: 16px;
margin-right: 8px;
width: 16px;
}
.titleArea {
display: flex;
flex-direction: column;
overflow: hidden;
}
.optionArea {
-moz-column-gap: 8px;
column-gap: 8px;
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.optionSubTitle {
color: #7c889c;
font-size: 12px;
}
.optionTitle {
color: #11192d;
font-size: 14px;
font-weight: 600;
line-height: 14px;
}
.bg-gray {
background-color: #f3f6f8;
}
.pb-20 {
padding-bottom: 20px;
}
.installmentOption {
background-color: #fff;
border-radius: 4px;
cursor: pointer;
height: 30px;
margin-bottom: 8px;
padding: 9px 16px;
width: calc(25% - 36px);
position: relative;
}
.trade-layout-row {
display: flex;
flex-direction: row;
}
.trade-layout-col {
display: flex;
flex-direction: column;
}
.icon {
height: 16px;
margin-right: 8px;
width: 16px;
}
.iconWrapper {
align-items: center;
display: flex;
height: 100%;
}
.title {
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 0 16px 12px;
}
.title .ant-checkbox-wrapper {
flex-grow: 1;
overflow: hidden;
}
.title .ant-checkbox + span {
overflow: hidden;
width: 100%;
}
.title .ant-checkbox {
top: 0;
}
.SettlementInstallmentOptionArea,
.SettlementInstallmentOptionAreaExpanded {
cursor: pointer;
display: flex;
flex-direction: column;
padding: 0 16px;
}
.pt-20 {
padding-top: 20px;
}
.settlementPanelContainer {
border-bottom: 1px solid #f0f3f5;
padding-bottom: 24px;
}
.SettlementSubmit {
align-items: center;
background-color: #fff;
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
box-shadow: 0 -1px 0 0 #f0f3f5;
box-sizing: border-box;
display: flex;
height: 80px;
padding: 16px;
}
.SettlementSubmit,
.SettlementSubmit .price {
justify-content: space-between;
}
.SettlementSubmit .title2 {
color: #11192d;
font-size: 14px;
font-weight: 400;
height: 14px;
line-height: 14px;
}
.SettlementSubmit .totalPrice {
align-items: flex-end;
display: flex;
height: 38px;
}
.SettlementSubmit .totalPrice_unit {
color: #ff5000;
font-size: 14px;
}
.SettlementSubmit .totalPrice_num {
color: #ff5000;
font-size: 24px;
line-height: 24px;
}
.SettlementSubmit .btnBox {
align-items: center;
display: flex;
}
.SettlementSubmit .back {
background-color: #fff;
border: 1px solid #e5e8ec;
border-radius: 8px;
color: #7c889c;
cursor: pointer;
flex: 0 0 56px;
font-size: 16px;
font-weight: 600;
height: 46px;
line-height: 46px;
position: relative;
text-align: center;
transition: all 0.3s ease;
width: 56px;
}
.SettlementSubmit .back:hover:after {
background-color: rgba(0, 0, 0, 0.03);
border-radius: 8px;
content: ' ';
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 1;
}
.SettlementSubmit .btn {
background-color: #ff5000;
border-radius: 8px;
color: #fff;
cursor: pointer;
flex: 0 0 160px;
font-size: 16px;
font-weight: 600;
height: 48px;
line-height: 48px;
margin-left: 12px;
position: relative;
text-align: center;
transition: all 0.3s ease;
width: 160px;
}
.SettlementSubmit .btn:hover:after {
background-color: rgba(0, 0, 0, 0.03);
border-radius: 8px;
content: ' ';
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 1;
}
.btn_disabled {
color: hsla(0, 0%, 100%, 0.5) !important;
pointer-events: none !important;
}
.btn_loading {
background-color: #f5f5f5;
}
.checkmark {
position: absolute;
right: 5px;
top: 16px;
font-size: 20px;
color: #ff5000;
}
.isSelect {
border: 0.5px solid #ff5000;
}
.tableInfo{
font-size: 14px;
}
</style>

View File

@@ -0,0 +1,800 @@
<template>
<div class="order-confirmation-box">
<div id="paypal-container" style="display: none">
<div id="paypal-payment-button" style="width: 100%; height: 50px"></div>
</div>
<div class="order-confirmation">
<el-descriptions :title="$t('pendingPayment.orderDetail')" column="2">
<el-descriptions-item label="ID">{{ articleInfo.accept_sn }}</el-descriptions-item>
<el-descriptions-item :label=" $t('pendingPayment.journal')">{{ journalInfo.title }} </el-descriptions-item>
<el-descriptions-item :span="2" style="width: 100%;" :label="$t('pendingPayment.title')"><p>{{ articleInfo.title }}</p></el-descriptions-item>
</el-descriptions>
</div>
<div
id="settlementContainer"
class="trade-container type-of-affix-right-panel-to-bottom bg-white overflow-hidden flex-col rounded-t-16"
>
<div class="SettlementHeader">
<div class="title1">{{ $t('pendingPayment.payDetail') }}</div>
</div>
<div class="settlementPanelContainer">
<div class="priceWrap">
<div class="priceLine priceLine_total">
<div class="priceTotal_title">{{ $t('pendingPayment.total') }}</div>
<div class="priceRight">
<div class="trade-price-container price">
<span class="trade-price-symbol priceTotal_unit"><span class="currency">$</span></span>
<span class="trade-price-integer priceTotal_num">{{ formatAmount(total) }}</span>
</div>
</div>
</div>
<div class="priceLine priceLine_total">
<div class="priceTotal_title" style="font-weight: 400">{{ $t('pendingPayment.youhui') }}</div>
<div class="priceRight" style="font-weight: 400; color: #7c889c">
<div class="trade-price-container price">
<span class="trade-price-symbol priceTotal_unit" style="font-weight: 400; color: #7c889c">$</span>
<span class="trade-price-integer priceTotal_num" style="font-weight: 400; color: #7c889c">0</span>
</div>
</div>
</div>
<div id="paymentCard" class="trade-container type-of-normal rounded-8 mx-16 bg-gray mt-24 mb-24 pb-20 pt-20">
<div class="SettlementOption">
<div class="title">
<label class="ant-checkbox-wrapper">
<span>
<div class="option">
<img
src="https://img.alicdn.com/imgextra/i2/O1CN01Ao5ka31RmZsasktnV_!!6000000002154-2-tps-88-88.png"
class="optionIcon"
/>
<div class="titleArea">
<div class="clamp-wrap clamp-ellipsis optionTitle" style="-webkit-line-clamp: unset">
{{ $t('pendingPayment.paymentmethod') }}
</div>
<div
class="clamp-wrap clamp-ellipsis optionSubTitle"
style="-webkit-line-clamp: unset"
></div>
</div>
</div>
</span>
</label>
</div>
<div class="SettlementInstallmentOptionArea">
<div class="optionArea">
<div
class="installmentOption"
:class="selectedPaymentMethod == 'PayPal' ? 'isSelect' : ''"
@click="selectPaymentMethod('PayPal')"
>
<div
class="ant-row trade-layout-row"
style="height: 100%; align-items: center; justify-content: flex-start"
>
<div class="trade-layout-leaf">
<div class="iconWrapper">
<img src="@/assets/img/paypal.png" class="icon" />
</div>
</div>
<div
class="ant-col trade-layout-col"
style="width: 74%; align-items: flex-start; justify-content: flex-start"
>
<div class="trade-layout-leaf" style="width: 100%">
<div class="clamp-wrap clamp-ellipsis mainTitle" style="-webkit-line-clamp: unset">
PayPal
</div>
</div>
</div>
<div v-if="selectedPaymentMethod === 'PayPal'" class="checkmark"></div>
</div>
</div>
<!-- <div
class="installmentOption"
:class="selectedPaymentMethod == 'Alipay' ? 'isSelect' : ''"
@click="selectPaymentMethod('Alipay')"
>
<div
class="ant-row trade-layout-row"
style="height: 100%; align-items: center; justify-content: flex-start"
>
<div class="trade-layout-leaf">
<div class="iconWrapper">
<img src="@/assets/img/zhifubao.png" class="icon" />
</div>
</div>
<div
class="ant-col trade-layout-col"
style="width: 74%; align-items: flex-start; justify-content: flex-start"
>
<div class="trade-layout-leaf" style="width: 100%">
<div class="clamp-wrap clamp-ellipsis mainTitle" style="-webkit-line-clamp: unset">
支付宝
</div>
</div>
</div>
<div v-if="selectedPaymentMethod === 'Alipay'" class="checkmark"></div>
</div>
</div> -->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="SettlementSubmit">
<div class="price">
<p class="title2">{{ $t('pendingPayment.Disbursements') }}</p>
<div class="totalPrice">
<div class="trade-price-container">
<span class="trade-price-symbol totalPrice_unit"><span class="currency">$</span></span>
<span class="trade-price-integer totalPrice_num">{{ formatAmount(total) }}</span>
</div>
</div>
</div>
<div class="btnBox">
<div class="btn">{{ $t('pendingPayment.submitOrder') }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
orderInfo: {},
articleInfo: {},
journalInfo: {},
total: '',
selectedPaymentMethod: 'PayPal', // 默认选中 PayPal
articleId: this.$route.query.id,
urlList: {
detail: 'api/Order/preOrderDetail',
createdOrder: 'api/Order/creatArticleOrder',
completeOrder: 'api/Order/completeOrder',
},
orderId: '1234567890', // 订单号
orderItems: [], // 订单明细
totalAmount: '130.00', // 订单总价
needInvoice: false, // 是否需要发票
invoiceTitle: '', // 发票抬头
invoiceContent: '' // 发票内容
};
},
methods: {
submit() {
// 假设 PayPal 按钮的容器有 id="paypal-button-container"
const paypalButtonContainer = document.getElementById('paypal-container');
// 删除所有 PayPal 按钮
if (paypalButtonContainer) {
paypalButtonContainer.innerHTML = '';
paypalButtonContainer.innerHTML = '<div id="paypal-payment-button"></div>';
}
if (process.env.NODE_ENV === 'development') {
console.log('当前是开发环境');
} else if (process.env.NODE_ENV === 'production') {
console.log('当前是生产环境');
} else if (process.env.NODE_ENV === 'test') {
console.log('当前是测试环境');
}
if (this.selectedPaymentMethod == 'PayPal') {
this.getPayPal();
}
},
getPayPal(id) {
var that = this;
window.paypal
.Buttons({
style: {
layout: 'horizontal', // 水平布局
shape: 'rect', // 矩形形状
label: 'paypal', // 显示 PayPal 标签
tagline: false, // 隐藏标语
color: 'blue', // 按钮颜色为蓝色
size: 'small' // 按钮大小为大
},
onInit: () => {
// 支付按钮加载完成 通知原生关闭loading
console.log('--------1.支付按钮加载完成 关闭loading--------');
// 自动点击 执行支付
console.log('--------2.自动点击 执行支付--------');
// 如果按钮获取到 就 自动执行点击 否则显示按钮
const paypalButton = window.frames[1].document.querySelector('.paypal-button');
if (paypalButton) paypalButton.click();
else {
document.querySelector('#paypal-container').style.display = 'block';
// document.querySelector('#loading').style.display = 'none';
}
},
createOrder: (data, actions) => {
return this.$api
.post(this.urlList.createdOrder, {
article_id: this.articleId
})
.then((res) => {
console.log('res at line 222:', res);
that.orderInfo=res.data.detail
document.querySelector('#paypal-container').style.display = 'none';
return res.data.paypal.jsonResponse.id;
});
},
onApprove(data, actions) {
return actions.order.capture().then((details) => {
console.log('details at line 232:', details.id)
const loading = that.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
setTimeout(() => {
loading.close();
that.$router.replace({ name: 'OrderConfirmation' });
// 跳转到新的路由
that.$api
.post(that.urlList.completeOrder, {
order_id: that.orderInfo.order_id
})
.then((res) => {
});
that.$router.push({
path: '/success',
query: {
id: that.articleId
}
});
}, 500);
});
},
onError(error) {
console.error('支付失败:', error);
that.$message.error('Payment error, please contact the journal editor!');
}
})
.render('#paypal-payment-button')
.then(() => {})
.catch((err) => {
console.error('Error rendering PayPal button:', err);
});
document.querySelector('.paypal-overlay').addEventListener('click', function (event) {
event.stopPropagation();
});
},
getDetail() {
this.$api
.post(this.urlList.detail, {
article_id: this.articleId
})
.then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) {
this.articleInfo = res.data.article_detail;
this.journalInfo = res.data.journal_detail;
// this.orderItems = [
// {
// ...this.articleInfo,
// fee: this.journalInfo.fee,
// journal: this.journalInfo.title
// }
// ];
this.total = this.journalInfo.fee;
}
});
},
formatAmount(amount) {
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
selectPaymentMethod(method) {
console.log('method at line 191:', method);
this.selectedPaymentMethod = method;
this.$forceUpdate();
},
payWithAlipay() {
// 实现支付宝支付逻辑
alert('使用支付宝支付');
},
payWithPayPal() {
// 实现PayPal支付逻辑
alert('使用PayPal支付');
}
},
created() {
this.getDetail();
},
activated() {
this.getDetail();
}
};
</script>
<style scoped>
.order-confirmation {
text-align: left;
padding: 20px;
background-color: #fff;
/* border: 1px solid #ccc; */
border-radius: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* margin: 20px auto; */
margin-top: 20;
box-sizing: border-box;
}
h3 {
margin-bottom: 20px;
}
.order-confirmation-box {
width: 1040px;
margin: 0 auto;
height: 100%;
padding-top: 20px;
box-sizing: border-box;
/* background-color: #f3f6f8; */
}
.orderHeader {
align-items: center;
background-color: #f3f6f8;
border-radius: 8px;
color: #11192d;
display: flex;
flex-direction: row;
font-size: 14px;
height: 48px;
padding: 0 16px;
text-align: center;
}
.grey {
width: 100%;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
background-color: #f3f6f8;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
::v-deep .el-table th {
background-color: #f3f6f8 !important;
color: #11192d !important;
}
::v-deep .el-table {
border-top-left-radius: 8px !important;
border-top-right-radius: 8px !important;
}
.price-24 {
font-size: 30px;
height: 30px;
line-height: 34px;
}
.trade-price-container {
float: right;
font-weight: bold;
/* width: 100%; */
/* align-items: flex-end; */
display: flex;
flex-direction: row;
align-items: center;
}
.trade-price-label,
.trade-price-symbol {
color: #ff5000;
font-size: 16px;
height: 16px;
line-height: 16px;
}
.trade-price-symbol {
/* font-family: AlibabaSans102v1TaoBao-Bold */
}
.trade-price-decimal,
.trade-price-integer,
.trade-price-point {
color: #ff5000;
/* font-family: AlibabaSans102v1TaoBao-Bold; */
font-size: 26px;
height: 26px;
line-height: 26px;
}
.super-text,
.trade-tips {
color: #50607a;
font-size: 12px;
}
#settlementContainer {
background-image: linear-gradient(180deg, #ffebe0, #fff 100px);
}
.rounded-t-16 {
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}
.bg-white {
background-color: #fff;
margin-top: 20px;
}
.SettlementHeader {
align-items: center;
display: flex;
flex-direction: row;
margin-bottom: 2px;
padding: 24px 16px;
}
.title1 {
color: #11192d;
font-size: 16px;
font-weight: 600;
height: 16px;
line-height: 16px;
margin-right: 8px;
}
.goodNum {
align-items: baseline;
color: #11192d;
display: flex;
flex-direction: row;
font-size: 14px;
font-weight: 400;
line-height: 16px;
}
.goodNum p {
color: #11192d;
font-size: 18px;
font-weight: 600;
line-height: 16px;
margin: 0 2px;
text-align: center;
}
.priceWrap {
padding: 0 16px;
}
.priceWrap .priceLine {
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: 12px;
}
.priceWrap .priceLine .priceTotal_title {
color: #11192d;
font-size: 14px;
font-weight: 600;
}
.priceWrap .priceLine .priceRight {
align-items: flex-end;
display: flex;
flex-direction: row;
padding-right: 16px;
position: relative;
}
.priceWrap .priceLine .priceRight img {
height: 8px;
position: absolute;
right: 0;
top: 6px;
width: 8px;
}
.priceWrap .priceLine .priceRight img.arrow_up {
transform: rotate(180deg);
}
.priceWrap .priceLine .priceRight .price {
align-items: baseline;
}
.priceWrap .priceLine_total {
margin-bottom: 16px;
}
.priceWrap .priceTotal_unit {
color: #11192d;
font-size: 12px;
font-weight: 700;
line-height: 14px;
margin-right: 2px;
}
.priceWrap .priceTotal_num {
color: #11192d;
font-size: 18px;
font-weight: 700;
line-height: 18px;
}
.priceWrap .pricePromotion_pre {
color: #ff5000;
font-size: 14px;
font-weight: 600;
line-height: 14px;
}
.priceWrap .pricePromotion_unit {
color: #ff5000;
font-size: 12px;
font-weight: 700;
line-height: 14px;
margin: 0 2px 0 4px;
}
.priceWrap .pricePromotion_num {
color: #ff5000;
font-size: 18px;
font-weight: 700;
line-height: 18px;
}
.rounded-8 {
border-radius: 8px;
}
.SettlementOption--Qu5uk29m {
margin-bottom: 16px;
}
.SettlementOption--Qu5uk29m:last-child {
margin-bottom: 0;
}
.option {
align-items: center;
display: flex;
flex-direction: row;
white-space: nowrap;
word-break: keep-all;
}
.optionIcon {
height: 16px;
margin-right: 8px;
width: 16px;
}
.titleArea {
display: flex;
flex-direction: column;
overflow: hidden;
}
.optionArea {
-moz-column-gap: 8px;
column-gap: 8px;
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.optionSubTitle {
color: #7c889c;
font-size: 12px;
}
.optionTitle {
color: #11192d;
font-size: 14px;
font-weight: 600;
line-height: 14px;
}
.bg-gray {
background-color: #f3f6f8;
}
.pb-20 {
padding-bottom: 20px;
}
.installmentOption {
background-color: #fff;
border-radius: 4px;
cursor: pointer;
height: 30px;
margin-bottom: 8px;
padding: 9px 16px;
width: calc(25% - 36px);
position: relative;
}
.trade-layout-row {
display: flex;
flex-direction: row;
}
.trade-layout-col {
display: flex;
flex-direction: column;
}
.icon {
height: 16px;
margin-right: 8px;
width: 16px;
}
.iconWrapper {
align-items: center;
display: flex;
height: 100%;
}
.title {
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 0 16px 12px;
}
.title .ant-checkbox-wrapper {
flex-grow: 1;
overflow: hidden;
}
.title .ant-checkbox + span {
overflow: hidden;
width: 100%;
}
.title .ant-checkbox {
top: 0;
}
.SettlementInstallmentOptionArea,
.SettlementInstallmentOptionAreaExpanded {
cursor: pointer;
display: flex;
flex-direction: column;
padding: 0 16px;
}
.pt-20 {
padding-top: 20px;
}
.settlementPanelContainer {
border-bottom: 1px solid #f0f3f5;
padding-bottom: 24px;
}
.SettlementSubmit {
align-items: center;
background-color: #fff;
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
box-shadow: 0 -1px 0 0 #f0f3f5;
box-sizing: border-box;
display: flex;
height: 80px;
padding: 16px;
}
.SettlementSubmit,
.SettlementSubmit .price {
justify-content: space-between;
}
.SettlementSubmit .title2 {
color: #11192d;
font-size: 14px;
font-weight: 400;
height: 14px;
line-height: 14px;
}
.SettlementSubmit .totalPrice {
align-items: flex-end;
display: flex;
height: 38px;
}
.SettlementSubmit .totalPrice_unit {
color: #ff5000;
font-size: 14px;
}
.SettlementSubmit .totalPrice_num {
color: #ff5000;
font-size: 24px;
line-height: 24px;
}
.SettlementSubmit .btnBox {
align-items: center;
display: flex;
}
.SettlementSubmit .back {
background-color: #fff;
border: 1px solid #e5e8ec;
border-radius: 8px;
color: #7c889c;
cursor: pointer;
flex: 0 0 56px;
font-size: 16px;
font-weight: 600;
height: 46px;
line-height: 46px;
position: relative;
text-align: center;
transition: all 0.3s ease;
width: 56px;
}
.SettlementSubmit .back:hover:after {
background-color: rgba(0, 0, 0, 0.03);
border-radius: 8px;
content: ' ';
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 1;
}
.SettlementSubmit .btn {
background-color: #ff5000;
border-radius: 8px;
color: #fff;
cursor: pointer;
flex: 0 0 160px;
font-size: 16px;
font-weight: 600;
height: 48px;
line-height: 48px;
margin-left: 12px;
position: relative;
text-align: center;
transition: all 0.3s ease;
width: 160px;
}
.SettlementSubmit .btn:hover:after {
background-color: rgba(0, 0, 0, 0.03);
border-radius: 8px;
content: ' ';
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 1;
}
.btn_disabled {
color: hsla(0, 0%, 100%, 0.5) !important;
pointer-events: none !important;
}
.btn_loading {
background-color: #f5f5f5;
}
.checkmark {
position: absolute;
right: 5px;
top: 16px;
font-size: 20px;
color: #ff5000;
}
.isSelect {
border: 0.5px solid #ff5000;
}
.tableInfo{
font-size: 14px;
}
</style>

View File

@@ -0,0 +1,84 @@
<template>
<div ref="paypalButtonContainer"></div>
</template>
<script>
import { defineComponent, onMounted, ref } from "vue";
export default defineComponent({
name: "PayPalButton",
props: {
amount: {
type: String,
required: true,
},
clientId: {
type: String,
required: true,
},
},
setup(props) {
const paypalButtonContainer = ref(null);
// 动态加载 PayPal SDK
onMounted(() => {
if (!window.paypal) {
const script = document.createElement("script");
script.src = `https://www.paypal.com/sdk/js?client-id=${props.clientId}`;
script.async = true;
script.onload = () => renderPayPalButton();
document.body.appendChild(script);
} else {
renderPayPalButton();
}
});
// 渲染 PayPal 按钮
const renderPayPalButton = () => {
window.paypal.Buttons({
style: {
layout: 'horizontal',
shape: 'rect',
label: 'paypal',
tagline: false
},
createOrder(data, actions) {
// return actions.order.create({
// purchase_units: [
// {
// amount: {
// value: props.amount, // 订单金额
// },
// },
// ],
// });
return '6VT20279NK3463528'
},
onApprove(data, actions) {
return actions.order.capture().then((details) => {
console.log("支付成功!", details);
alert(`支付成功!支付者:${details.payer.name.given_name}`);
});
},
onError(error) {
console.error("支付失败:", error);
alert("支付失败,请重试!");
},
}).render(paypalButtonContainer.value);
};
return {
paypalButtonContainer,
};
},
});
</script>
<style scoped>
/* Add custom styles for the PayPal button if needed */
</style>

View File

@@ -1,68 +0,0 @@
<template>
<div>
<PayPal
currency="USD"
:client="paypal"
:amount="amount"
:env="env"
@payment-authorized="onPaymentSuccess"
@payment-completed="onPaymentError"
>
</PayPal>
</div>
</template>
<script>
import PayPal from 'vue-paypal-checkout';
export default {
data() {
return {
paypal: {
sandbox: 'Ab8SeEuhkLGp6Fts9V3Cti0UcXQhITRWZkiHDM3U1fDY9YrrRc5IOcYHPfV6qROhmh0hvgysqrfOCSUr',
production: 'Ad-9iuPrN9U8zQxfcog7QweDSJsDY6ns2I5WaPjuuN_4ToE5LEGASm09j9x7VC0fbQkTmnpFtrZYpHEE'
},
// myItems: [
// {
// name: 'hat',
// quantity: '1',
// price: '5',
// currency: 'USD'
// },
// {
// name: 'handbag',
// // description: "Black handbag.",
// quantity: '1',
// price: '5',
// currency: 'USD'
// }
// ],
amount: '9.99', // Amount to be paid
env: 'sandbox'
};
},
components: {
PayPal
},
methods: {
onPaymentSuccess(payment) {
try {
console.log('Payment successful!', payment);
this.$emit('payment-success', payment);
} catch (error) {
console.error('Error in onPaymentSuccess callback:', error);
}
},
onPaymentError(error) {
try {
console.error('Payment error:', error);
this.$emit('payment-error', error);
} catch (err) {
console.error('Error in onPaymentError callback:', err);
}
}
}
};
</script>
<style scoped></style>

View File

@@ -1,126 +1,69 @@
<template>
<div>
<PayPal
currency="USD"
:client="paypal"
:amount="amount"
:env="env"
:commit="true"
@payment-authorized="onPaymentSuccess"
@payment-completed="onPaymentCompleted"
@payment-cancelled="onPaymentCancel"
locale="en_US"
:button-style="myStyle"
:token="paymentToken"
:paypal-button="paypalButton"
>
</PayPal>
<!-- 动态生成一个唯一的ID以确保每个PayPal按钮都有一个独立的容器 -->
<div >
<div :id="'paypal-button-container-' + orderId" ref="paypalButtonContainer"></div>
</div>
</template>
<!-- paymentID= "PAY-3L661344P7749433KLD2R5ZQ" -->
<script>
import PayPal from 'vue-paypal-checkout';
export default {
data() {
return {
myStyle: {
label: 'checkout',
size: 'responsive',
shape: 'pill',
color: 'blue'
},
paymentToken: '2S842212TP193105C', // 存储自定义的 token
paypal: {
sandbox: 'Ab8SeEuhkLGp6Fts9V3Cti0UcXQhITRWZkiHDM3U1fDY9YrrRc5IOcYHPfV6qROhmh0hvgysqrfOCSUr',
production: 'Ad-9iuPrN9U8zQxfcog7QweDSJsDY6ns2I5WaPjuuN_4ToE5LEGASm09j9x7VC0fbQkTmnpFtrZYpHEE'
},
// myItems: [
// {
// name: 'hat',
// quantity: '1',
// price: '5',
// currency: 'USD'
// },
// {
// name: 'handbag',
// // description: "Black handbag.",
// quantity: '1',
// price: '5',
// currency: 'USD'
// }
// ],
amount: '9.99', // Amount to be paid
env: 'sandbox'
};
import { defineComponent, onMounted, ref, watch } from 'vue';
export default defineComponent({
name: 'PayPalButton',
props: {
amount: {
type: String,
required: true
},
clientId: {
type: String,
required: true,
default:'ARyoAhBNlTMDEBb6QvJYmK0gA4cfSS6WY0Vr2uJhX3NOe7V9qVCJuNwuRHRO09WGcTgS5AkuTIgRZDcx'
},
orderId: {
// type: String,
// required: true
}
},
components: {
PayPal
},
created() {
// this.fetchCustomToken();
mounted() {
this.getPayPal();
},
methods: {
// 配置 PayPal 按钮(传递自定义的 token
paypalButton(data, actions) {
return actions.payment.create({
transactions: [
{
amount: {
total: '20.00',
currency: 'USD'
},
custom: this.paymentToken // 将自定义 token 作为 custom 数据传递
getPayPal() {
var that = this;
window.paypal
.Buttons({
style: {
layout: 'horizontal', // 水平布局
shape: 'rect', // 矩形形状
label: 'paypal', // 显示 PayPal 标签
tagline: false, // 隐藏标语
color: 'blue', // 按钮颜色为蓝色
size: 'small' // 按钮大小为大
},
createOrder: (data, actions) => {
return '6XN58648LW618025W';
},
onApprove(data, actions) {
return actions.order.capture().then((details) => {
console.log('支付成功!', details);
that.$emit('payment-success', details); // 触发成功事件
});
},
onError(error) {
console.error('支付失败:', error);
that.$emit('payment-error', error); // 触发失败事件
}
]
});
},
async fetchCustomToken() {
try {
this.customToken = '2S842212TP193105C'; // 假设返回的 JSON 里有 token 字段
} catch (error) {}
},
onPaymentSuccess(payment) {
try {
console.log('Payment successful Button!', payment);
// this.$emit('payment-success', payment);
// const token = this.paymentToken;
// // 使用token进行支付处理
// paypal.payment.execute(token, (error, payment) => {
// console.log('payment at line 73:', payment)
// if (error) {
// // 处理错误
// console.error('Error in onPaymentSuccess callback:', error);
// } else {
// // 处理支付成功的情况
// console.log('Payment successful Button!', payment);
// }
// });
} catch (error) {
console.error('Error in onPaymentSuccess callback:', error);
}
},
onPaymentCompleted(error) {
try {
console.error('Payment paymentCompleted Button:', error);
this.$emit('payment-error', error);
} catch (err) {
console.error('Error in paymentCompleted callback:', err);
}
},
onPaymentCancel(error) {
try {
console.error('Payment cancel Button:', error);
this.$emit('payment-error', error);
} catch (err) {
console.error('Error in onPaymentCancel callback:', err);
}
})
.render('#paypal-button-container-' + that.orderId);
}
}
};
});
</script>
<style scoped></style>
<style scoped>
/* 可以添加自定义样式 */
</style>

View File

@@ -14,21 +14,18 @@
<el-table-column label="" width="140">
<template slot-scope="scope">
<PayPalButton @payment-success="handlePaymentSuccess" @payment-error="handlePaymentError" />
<!-- <el-button @click="payArticle(scope.row)" plain type="danger" size="mini">{{ $t('pendingPayment.payment') }}</el-button> -->
</template>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import PayPalButton from './PayPalButton.vue';
export default {
components: {
PayPalButton
},
props: {
list: {

View File

@@ -0,0 +1,118 @@
<template>
<div class="success-box" v-if="articleInfo.accept_sn">
<div class="payment-success">
<div style="display: flex; align-items: center;margin-bottom: 10px;">
<h2 style="margin: 0 auto;display: flex; align-items: center">
<img src="@/assets/img/success.png" alt="" style="margin-right: 20px; width: 128px; height: 128px" />Payment Successful
</h2>
</div>
<p>Thank you for your payment. Your order has been successfully processed.</p>
<p>
Article ID:
<span style="color: #333; font-weight: 600"> {{ articleInfo.accept_sn }}</span>
</p>
<p>
Total Amount: <span style="color: #ff5000"><span class="currency">$</span></span
><span style="color: #ff5000; font-size: 24px; line-height: 24px">{{ formatAmount(total) }}</span>
</p>
<!-- <p>Payment Method: {{ paymentMethod }}</p> -->
<p>You will receive an email confirmation shortly.</p>
<button @click="goBack">Back to Order List</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
urlList: {
detail: 'api/Order/preOrderDetail',
createdOrder: 'api/Order/creatArticleOrder'
},
articleInfo: {},
journalInfo: {},
total: '',
articleId: this.$route.query.id
};
},
created() {
this.getDetail();
},
methods: {
formatAmount(amount) {
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
getDetail() {
this.$api
.post(this.urlList.detail, {
article_id: this.articleId
})
.then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) {
this.articleInfo = res.data.article_detail;
this.journalInfo = res.data.journal_detail;
this.total = this.journalInfo.fee;
}
});
},
goBack() {
this.$router.replace({ name: 'success' });
// 跳转到新的路由
this.$router.push({
path: '/orderListAuthor'
});
}
}
};
</script>
<style scoped>
.payment-success {
margin-top: 40px;
margin: 0 auto;
text-align: center;
padding: 20px;
background-color: #fff;
border: 1px solid #c3e6cb;
border-radius: 16px;
color: #155724;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
width: 600px;
}
h2 {
margin-bottom: 20px;
}
p {
margin-bottom: 10px;
}
button {
padding: 10px 20px;
background-color: #00c286;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
margin-top: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* 按钮添加阴影效果 */
}
button:hover {
background-color: #00c286;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); /* 按钮悬停时的阴影效果 */
}
.success-box {
display: flex;
align-items: center;
/* justify-content: center; */
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,119 @@
<template>
<div>
<el-select v-model="state" @change="getList" placeholder="Please select status"
style="margin-bottom:10px;width: 200px;">
<!-- <el-option :key="0" label="All status" :value="0"></el-option> -->
<el-option :key="1" :label="$t('pendingPayment.state0')" :value="0"></el-option>
<el-option :key="1" :label="$t('pendingPayment.state1')" :value="1"></el-option>
<el-option :key="2" :label="$t('pendingPayment.state2')" :value="2"></el-option>
</el-select>
<el-table :data="orderList" style="width: 100%">
<el-table-column prop="id" label="ID" width="300"><template slot-scope="scope">
<p><span>ID</span>{{ scope.row.article_detail.accept_sn }}</p>
<p><span>{{ $t('pendingPayment.journal') }}</span>{{ scope.row.journal_detail.title }}</p>
</template></el-table-column>
<el-table-column prop="title" :label="$t('pendingPayment.title')"><template slot-scope="scope">
{{ scope.row.article_detail.title }}
</template>
</el-table-column>
<el-table-column prop="real_fee" :label="$t('pendingPayment.Paymentamount')" width="140">
<template slot-scope="scope">
<span class="currency">$</span> {{ formatAmount(scope.row.real_fee) }}
</template>
</el-table-column>
<el-table-column prop="status" :label="$t('pendingPayment.Paymentstatus')" width="140">
<template slot-scope="scope">
<span v-if="scope.row.state==0" style="color: #ff5000;">{{ $t('pendingPayment.state0') }}</span>
<span v-if="scope.row.state==1" style="color: #00c286;">{{ $t('pendingPayment.state1') }}</span>
<span v-if="scope.row.state==2" style="color: #b0b0b0;">{{ $t('pendingPayment.state2') }}</span>
</template>
</el-table-column>
<el-table-column label="" width="140">
<template slot-scope="scope">
<el-button size="mini" style="background: #ff5000 !important;border-color: #ff5000 !important;" type="primary" v-if="scope.row.state==0" @click="goOrderConfirmation(scope.row)">Payment</el-button>
<!-- <el-button size="mini" type="primary" v-if="scope.row.state==1" @click="goOrderDetail(scope.row)">Detail</el-button> -->
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import PendingPayment from '@/components/page/components/pendingPayment/index.vue';
export default {
components: {
PendingPayment
},
data() {
return {
state:0,
user_id: localStorage.getItem('U_id'),
urlList: {
list:'api/Order/getUserOrder'
},
orderList: [
// 更多稿件数据...
]
};
},
methods: {
goOrderConfirmation(data){
this.$router.push({
path: '/OrderConfirmation',
query: {
id: data.article_id
}
});
},
goOrderDetail(data){
this.$router.push({
path: '/OrderDetail',
query: {
id: data.article_id
}
});
},
formatAmount(amount) {
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
getList(){
this.$api
.post(this.urlList.list, {
user_id: this.user_id,
state:this.state
})
.then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) {
this.orderList = res.data.list;
}
});
},
payArticle(article) {
// 在这里实现缴费逻辑例如调用后端API进行缴费
// 缴费成功后更新article.status为'已缴费'
article.status = '已缴费';
this.$message.success(`已成功为稿件 ${article.title} 缴费`);
}
},
created(){
this.getList()
},
activated(){
this.getList()
},
};
</script>
<style scoped>
.currency {
font-weight: bold;
/* margin-right: 5px; */
}</style>

View File

@@ -695,6 +695,15 @@
</div>
</div>
</el-tab-pane>
<el-tab-pane label="User Order">
<PendingPayment ref="PendingPayment" :list="orderList">
<template slot="tableItem">
</template>
</PendingPayment>
</el-tab-pane>
</el-tabs>
</div>
@@ -1101,9 +1110,13 @@
</template>
<script>
import PendingPayment from '@/components/page/components/pendingPayment/index.vue';
export default {
data() {
return {
orderList:[ { id: 1, title: '稿件1', author: '作者1', amount: 100, status: '未缴费',orderId:'6VT20279NK3463528' },
{ id: 2, title: '稿件2', author: '作者2', amount: 200, status: '未缴费',orderId:'6VT20279NK3463528' },
{ id: 3, title: '稿件3', author: '作者3', amount: 300, status: '未缴费' ,orderId:'6VT20279NK3463528' },],
citeLoading: false,
wosLoading: false,
authorList: [],
@@ -1357,6 +1370,9 @@ export default {
}
};
},
components: {
PendingPayment
},
mounted() {},
created() {
this.getSelectData();

View File

@@ -73,6 +73,8 @@ Vue.component("Editor", Editor);
import commonTable from '@/components/page/components/table/table.vue'
Vue.component('common-table', commonTable);
import commonPayPalButton from '@/components/page/components/pendingPayment/PayPalButton.vue'
Vue.component('common-paypal-button', commonPayPalButton);
import commonTiff from '@/components/page/components/table/tiff.vue'
Vue.component('common-tiff', commonTiff);
import commonContent from '@/components/page/components/table/content.vue'

View File

@@ -327,10 +327,31 @@ export default new Router({
}
},
{
path: '/PendingPaymentAuthor',
component: () => import('../components/page/PendingPaymentAuthor.vue'),
path: '/OrderConfirmation',
component: () => import('../components/page/components/pendingPayment/OrderConfirmation.vue'),
meta: {
title: 'Pending Payment'
title: 'Order Confirmation'
}
},
{
path: '/OrderDetail',
component: () => import('../components/page/components/pendingPayment/OrderDetail.vue'),
meta: {
title: 'Order Detail'
}
},
{
path: '/success',
component: () => import('../components/page/components/pendingPayment/success.vue'),
meta: {
title: 'Success'
}
},
{
path: '/orderListAuthor',
component: () => import('../components/page/orderListAuthor.vue'),
meta: {
title: 'Order List'
}
},
{