Files
ruoyi-vue/src/views/public/order-submit/index.vue
2026-01-03 12:03:12 +08:00

502 lines
14 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="public-order-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>订单提交台</span>
<span class="header-desc">请按照格式提交订单信息</span>
</div>
<el-form :model="form" label-width="80px" label-position="top">
<el-form-item>
<template slot="label">
<span>输入订单信息</span>
<el-tag type="warning" size="mini" style="margin-left: 10px;">只能提交今天的订单</el-tag>
</template>
<el-input
v-model="form.command"
type="textarea"
:rows="12"
:placeholder="getPlaceholder()"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitOrder" :loading="loading" size="medium">
<i class="el-icon-upload"></i> 提交订单
</el-button>
<el-button @click="clearAll" size="medium">
<i class="el-icon-delete"></i> 清空
</el-button>
</el-form-item>
</el-form>
<el-divider>响应结果</el-divider>
<div v-if="resultList.length === 0" style="padding: 12px 0;">
<el-empty description="暂无响应" />
</div>
<div v-else>
<div v-for="(msg, idx) in resultList" :key="idx" class="msg-block">
<div class="msg-header">
<span> {{ idx + 1 }} </span>
<el-button size="mini" type="success" @click="copyOne(msg)">复制此段</el-button>
</div>
<el-input :value="msg" type="textarea" :rows="8" readonly />
</div>
<div style="margin-top: 8px;">
<el-button size="mini" type="primary" @click="copyAll">复制全部</el-button>
</div>
</div>
<!-- 使用说明 -->
<el-divider>使用说明</el-divider>
<div class="usage-guide">
<el-collapse>
<el-collapse-item title="订单格式说明" name="1">
<div class="guide-content">
<p><strong>请严格按照以下格式填写订单信息</strong></p>
<pre class="format-example">
{{ getTodayDate() }} 001
备注测试订单
分销标记H-TF
型号ZQD180F-EB200
链接https://item.jd.com/...
下单付款1650
后返金额50
地址张三13800138000上海市浦东新区张江高科技园区...
物流链接https://...
订单号1234567890
下单人张三</pre>
<p class="tips"><i class="el-icon-warning"></i> 重要提示订单日期必须是今天{{ getTodayDate() }}每个字段都不能省略</p>
</div>
</el-collapse-item>
<el-collapse-item title="注意事项" name="2">
<div class="guide-content">
<ul>
<li><strong style="color: #E6A23C;">只能提交今天的订单历史订单不允许提交</strong></li>
<li>请确保订单信息准确无误</li>
<li>每次只能提交一个订单</li>
<li>提交成功后会显示确认信息</li>
<li>如遇错误请检查格式和日期是否正确</li>
<li>限流策略每半小时最多提交120个订单</li>
</ul>
</div>
</el-collapse-item>
</el-collapse>
</div>
</el-card>
<!-- 地址重复验证码弹窗 -->
<el-dialog
title="地址重复验证"
:visible.sync="verifyDialogVisible"
width="400px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div style="text-align: center;">
<el-alert
:title="verifyMessage"
type="warning"
:closable="false"
style="margin-bottom: 20px;"
/>
<div style="font-size: 24px; font-weight: bold; color: #409EFF; margin: 20px 0;">
{{ verifyCode }}
</div>
<el-input
v-model="verifyInput"
placeholder="请输入上方四位数字验证码"
maxlength="4"
style="width: 200px;"
@keyup.enter.native="handleVerify"
/>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="verifyDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleVerify" :loading="verifyLoading">确认</el-button>
</div>
</el-dialog>
<!-- 页尾导航 -->
<PublicFooterNav />
</div>
</template>
<script>
import { submitPublicOrder, submitPublicOrderWithForce } from '@/api/public/order'
import PublicFooterNav from '@/components/PublicFooterNav'
export default {
name: 'PublicOrderSubmit',
components: {
PublicFooterNav
},
data() {
return {
form: { command: '' },
loading: false,
resultList: [],
// 验证码相关
verifyDialogVisible: false,
verifyCode: '',
verifyInput: '',
verifyMessage: '',
verifyLoading: false,
pendingCommand: '' // 待执行的命令(验证通过后执行)
}
},
methods: {
getPlaceholder() {
const today = new Date().toISOString().split('T')[0]
return `请按照以下格式输入订单信息(注意:订单日期必须是今天 ${today}
单:
${today} 001
备注:测试订单
分销标记H-TF
型号ZQD180F-EB200
链接https://...
下单付款1650
后返金额50
地址张三13800138000上海市浦东新区...
物流链接https://...
订单号1234567890
下单人:张三`
},
copyOne(text) {
if (!text) return
this.doCopy(text)
},
copyAll() {
if (!this.resultList || this.resultList.length === 0) return
const text = this.resultList.join('\n\n')
this.doCopy(text)
},
doCopy(text) {
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
this.$message.success('复制成功')
}).catch(() => {
this.fallbackCopyText(text)
})
} else {
this.fallbackCopyText(text)
}
},
fallbackCopyText(text) {
const ta = document.createElement('textarea')
ta.value = text
document.body.appendChild(ta)
ta.focus()
ta.select()
try {
document.execCommand('copy')
this.$message.success('复制成功')
} catch (e) {
this.$message.error('复制失败')
}
document.body.removeChild(ta)
},
submitOrder() {
const cmd = (this.form.command || '').trim()
if (!cmd) {
this.$message.error('请输入订单信息')
return
}
// 检查是否以"单:"开头
if (!cmd.startsWith('单:') && !cmd.startsWith('单:')) {
this.$message.error('订单信息必须以"单:"开头')
return
}
this.loading = true
submitPublicOrder({ command: cmd }).then(res => {
this.loading = false
if (res && (res.code === 200 || res.msg === '操作成功')) {
const data = res.data
if (Array.isArray(data)) {
this.resultList = data
} else if (typeof data === 'string') {
this.resultList = data ? [data] : []
} else {
this.resultList = []
}
// 检查是否是地址重复错误
if (this.checkAddressDuplicate(this.resultList)) {
// 显示验证码弹窗
this.showVerifyDialog(cmd)
return
}
// 检查是否有警告信息
this.checkWarningAlert(this.resultList)
// 如果没有警告,显示成功提示
if (!this.hasWarning(this.resultList)) {
this.$message.success('订单提交成功')
}
} else {
this.$message.error(res && res.msg ? res.msg : '提交失败')
this.resultList = []
}
}).catch(error => {
this.loading = false
const errorMsg = error.response?.data?.msg || error.message || '提交失败,请稍后重试'
this.$message.error(errorMsg)
this.resultList = []
})
},
// 检查是否是地址重复错误
checkAddressDuplicate(resultList) {
if (!resultList || resultList.length === 0) return false
for (let i = 0; i < resultList.length; i++) {
const result = resultList[i]
if (typeof result === 'string' && result.startsWith('ERROR_CODE:ADDRESS_DUPLICATE')) {
return true
}
}
return false
},
// 显示验证码弹窗
showVerifyDialog(command) {
// 生成四位随机数字验证码
this.verifyCode = String(Math.floor(1000 + Math.random() * 9000))
this.verifyInput = ''
this.verifyMessage = '检测到地址重复,请输入验证码以强制生成表单'
this.pendingCommand = command
this.verifyDialogVisible = true
},
// 处理验证码验证
handleVerify() {
if (!this.verifyInput || this.verifyInput.length !== 4) {
this.$message.error('请输入四位数字验证码')
return
}
if (this.verifyInput !== this.verifyCode) {
this.$message.error('验证码错误,请重新输入')
this.verifyInput = ''
return
}
// 验证通过使用forceGenerate参数重新提交
this.verifyLoading = true
submitPublicOrderWithForce({ command: this.pendingCommand }).then(res => {
this.verifyLoading = false
this.verifyDialogVisible = false
if (res && (res.code === 200 || res.msg === '操作成功')) {
const data = res.data
if (Array.isArray(data)) {
this.resultList = data
} else if (typeof data === 'string') {
this.resultList = data ? [data] : []
} else {
this.resultList = []
}
// 检查是否有警告信息
this.checkWarningAlert(this.resultList)
// 如果没有警告,显示成功提示
if (!this.hasWarning(this.resultList)) {
this.$message.success('订单提交成功(已强制生成)')
}
} else {
this.$message.error(res && res.msg ? res.msg : '提交失败')
this.resultList = []
}
}).catch(error => {
this.verifyLoading = false
const errorMsg = error.response?.data?.msg || error.message || '提交失败,请稍后重试'
this.$message.error(errorMsg)
this.resultList = []
})
},
clearAll() {
this.form.command = ''
this.resultList = []
},
checkWarningAlert(resultList) {
if (!resultList || resultList.length === 0) return
// 检查是否有以[炸弹]开头的警告消息
const warningMessages = resultList
.filter(msg => {
return msg && typeof msg === 'string' && msg.trim().includes('[炸弹]')
})
.map(msg => {
// 移除所有的[炸弹]标记
return msg.trim().replace(/\[炸弹\]\s*/g, '').trim()
})
if (warningMessages.length > 0) {
// 显示警告弹窗
this.$alert(warningMessages.join('\n\n'), '⚠️ 警告提示', {
confirmButtonText: '我已知晓',
type: 'warning',
center: true,
customClass: 'warning-alert-dialog',
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
dangerouslyUseHTMLString: false
}).catch(() => {})
}
},
hasWarning(resultList) {
if (!resultList || resultList.length === 0) return false
return resultList.some(msg => msg && typeof msg === 'string' && msg.trim().includes('[炸弹]'))
},
getTodayDate() {
return new Date().toISOString().split('T')[0]
}
}
}
</script>
<style scoped>
.public-order-container {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
padding-bottom: calc(80px + 20px); /* 为页尾导航留出空间 */
display: flex;
align-items: center;
justify-content: center;
}
.box-card {
max-width: 1000px;
width: 100%;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
.clearfix {
display: flex;
align-items: center;
justify-content: space-between;
}
.clearfix span:first-child {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.header-desc {
font-size: 12px;
color: #909399;
font-weight: normal;
}
.msg-block {
margin-bottom: 12px;
}
.msg-header {
display: flex;
align-items: center;
justify-content: space-between;
margin: 6px 0;
font-weight: 500;
color: #606266;
}
.usage-guide {
margin-top: 20px;
}
.guide-content {
padding: 10px;
}
.guide-content p {
margin: 10px 0;
line-height: 1.8;
color: #606266;
}
.format-example {
background-color: #f5f7fa;
padding: 15px;
border-radius: 4px;
border-left: 3px solid #409eff;
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
overflow-x: auto;
margin: 15px 0;
}
.tips {
color: #e6a23c;
font-size: 13px;
padding: 10px;
background-color: #fdf6ec;
border-radius: 4px;
border: 1px solid #f5dab1;
}
.guide-content ul {
list-style: none;
padding: 0;
}
.guide-content ul li {
padding: 8px 0;
color: #606266;
line-height: 1.6;
}
.guide-content ul li:before {
content: "•";
color: #409eff;
font-weight: bold;
display: inline-block;
width: 1em;
margin-left: 10px;
}
</style>
<style>
/* 全局样式:警告弹窗 */
.warning-alert-dialog {
width: 80vw !important;
max-width: 800px !important;
min-width: 400px !important;
}
.warning-alert-dialog .el-message-box__header {
padding: 20px 20px 15px !important;
}
.warning-alert-dialog .el-message-box__title {
font-size: 18px !important;
font-weight: 700 !important;
}
.warning-alert-dialog .el-message-box__message {
font-size: 15px !important;
font-weight: 600 !important;
color: #e6a23c !important;
white-space: pre-wrap !important;
word-break: break-word !important;
line-height: 1.8 !important;
max-height: 60vh !important;
overflow-y: auto !important;
padding: 15px 20px !important;
}
.warning-alert-dialog .el-message-box__btns {
text-align: center !important;
padding: 15px 20px 20px !important;
}
.warning-alert-dialog .el-message-box__btns .el-button {
padding: 12px 40px !important;
font-size: 14px !important;
font-weight: 600 !important;
}
</style>