This commit is contained in:
van
2026-04-07 17:29:30 +08:00
parent a2263eeef9
commit 8addb6080c
9 changed files with 835 additions and 89 deletions

View File

@@ -0,0 +1,313 @@
<template>
<div class="app-container mobile-fadan">
<el-card class="box-card">
<el-form :model="form" label-position="top" class="fadan-form">
<el-form-item label="分销标记(默认 F">
<el-input v-model="form.mark" placeholder="一般为 F" clearable />
</el-form-item>
<el-form-item label="型号" required>
<el-input v-model="form.model" placeholder="必填" clearable />
</el-form-item>
<el-form-item label="下单地址" required>
<el-input v-model="form.address" type="textarea" :rows="3" placeholder="必填,与中控「生」指令第 6 行一致" clearable />
</el-form-item>
<el-form-item label="转链链接(可空)">
<el-input v-model="form.link" type="textarea" :rows="2" placeholder="可空;留空则后台按型号尝试自动填充京粉链接" clearable />
</el-form-item>
<el-form-item label="数量">
<el-input-number v-model="form.qty" :min="1" :max="99" controls-position="right" style="width: 100%;" />
</el-form-item>
<el-divider content-position="left">选填已下单时一并写入录单表</el-divider>
<el-form-item label="下单人">
<el-input v-model="form.buyer" placeholder="选填" clearable />
</el-form-item>
<el-form-item label="下单付款(元)">
<el-input v-model="form.paymentText" placeholder="选填,如 2999.00" clearable />
</el-form-item>
<el-form-item label="后返金额(元)">
<el-input v-model="form.rebateText" placeholder="选填" clearable />
</el-form-item>
<el-form-item label="物流链接">
<el-input v-model="form.logisticsLink" type="textarea" :rows="2" placeholder="选填" clearable />
</el-form-item>
<div class="btn-row">
<el-button type="primary" size="medium" :loading="loading" @click="generate">录单</el-button>
<el-button size="medium" @click="resetForm">重置表单</el-button>
<el-button v-if="resultText" size="medium" @click="copyResult">复制录单</el-button>
</div>
</el-form>
<template v-if="resultText">
<el-divider content-position="left">录单结果</el-divider>
<el-input v-model="resultText" type="textarea" :rows="16" readonly class="result-area" />
</template>
</el-card>
<el-dialog
title="地址/单号重复验证"
:visible.sync="verifyDialogVisible"
width="92%"
:close-on-click-modal="false"
:close-on-press-escape="false"
append-to-body
>
<div class="verify-body">
<el-alert :title="verifyMessage" type="warning" :closable="false" />
<div class="verify-code">{{ verifyCode }}</div>
<el-input v-model="verifyInput" placeholder="请输入上方四位验证码" maxlength="4" @keyup.enter.native="handleVerify" />
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="verifyDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="verifyLoading" @click="handleVerify">确认录单</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { executeInstruction, executeInstructionWithForce } from '@/api/system/instruction'
export default {
name: 'MobileFadan',
data() {
return {
form: {
mark: 'F',
model: '',
address: '',
link: '',
qty: 1,
buyer: '',
paymentText: '',
rebateText: '',
logisticsLink: ''
},
loading: false,
resultText: '',
resultListFromLast: [],
verifyDialogVisible: false,
verifyCode: '',
verifyInput: '',
verifyMessage: '',
verifyLoading: false,
pendingCommand: ''
}
},
methods: {
buildCommand() {
const mark = (this.form.mark || 'F').trim()
const model = (this.form.model || '').trim()
const address = (this.form.address || '').trim()
if (!model) {
this.$modal.msgError('请填写型号')
return null
}
if (!address) {
this.$modal.msgError('请填写地址')
return null
}
const link = (this.form.link || '').trim()
const qty = Number(this.form.qty) > 0 ? Number(this.form.qty) : 1
const lines = ['生', mark, model, link, String(qty), address]
return lines.join('\n')
},
injectOptional(raw) {
if (!raw) return raw
let t = String(raw).replace(/\r\n/g, '\n')
const buyer = (this.form.buyer || '').trim()
const pay = (this.form.paymentText || '').trim()
const rebate = (this.form.rebateText || '').trim()
const logistics = (this.form.logisticsLink || '').trim()
if (buyer) {
t = t.replace(/(下单人(需填):)\n\n/, `$1\n${buyer}\n\n`)
}
if (pay) {
t = t.replace(/(下单付款(注意核对):)\n\n/, `$1\n${pay}\n\n`)
}
if (rebate) {
t = t.replace(/(后返金额(注意核对):)\n\n/, `$1\n${rebate}\n\n`)
}
if (logistics) {
t = t.replace(/(物流链接(需填):)\n\n/, `$1\n${logistics}\n\n`)
}
return t
},
extractFirstResponse(data) {
if (Array.isArray(data)) {
return data.length ? data.join('\n\n\n') : ''
}
if (typeof data === 'string') {
return data
}
return ''
},
checkDuplicateError(resultList) {
if (!resultList || !resultList.length) return false
for (let i = 0; i < resultList.length; i++) {
const s = resultList[i]
if (typeof s === 'string' && (
s.includes('ERROR_CODE:ADDRESS_DUPLICATE') ||
s.includes('ERROR_CODE:ORDER_NUMBER_DUPLICATE')
)) {
return true
}
}
return false
},
showVerifyDialog(cmd) {
this.pendingCommand = cmd
this.verifyCode = String(Math.floor(1000 + Math.random() * 9000))
this.verifyInput = ''
let hasOrder = false
let hasAddr = false
const list = this.resultListFromLast || []
list.forEach(s => {
if (typeof s !== 'string') return
if (s.includes('ERROR_CODE:ORDER_NUMBER_DUPLICATE')) hasOrder = true
if (s.includes('ERROR_CODE:ADDRESS_DUPLICATE')) hasAddr = true
})
if (hasOrder && hasAddr) {
this.verifyMessage = '检测到订单编号与地址可能重复,输入验证码后可强制录单'
} else if (hasOrder) {
this.verifyMessage = '检测到订单编号可能重复,输入验证码后可强制录单'
} else {
this.verifyMessage = '检测到地址可能重复,输入验证码后可强制录单'
}
this.verifyDialogVisible = true
},
generate() {
const cmd = this.buildCommand()
if (!cmd) return
this.loading = true
this.resultText = ''
executeInstruction({ command: cmd }).then(res => {
this.loading = false
if (res && (res.code === 200 || res.msg === '操作成功')) {
const list = Array.isArray(res.data) ? res.data : (res.data ? [String(res.data)] : [])
if (this.checkDuplicateError(list)) {
this.resultListFromLast = list
this.showVerifyDialog(cmd)
return
}
const merged = this.injectOptional(this.extractFirstResponse(res.data))
this.resultText = merged
this.$modal.msgSuccess('已录单')
} else {
this.$modal.msgError((res && res.msg) || '录单失败')
}
}).catch(() => {
this.loading = false
this.$modal.msgError('请求失败')
})
},
handleVerify() {
if (!this.verifyInput || this.verifyInput.length !== 4) {
this.$modal.msgError('请输入四位验证码')
return
}
if (this.verifyInput !== this.verifyCode) {
this.$modal.msgError('验证码不正确')
this.verifyInput = ''
return
}
this.verifyLoading = true
executeInstructionWithForce({ command: this.pendingCommand }).then(res => {
this.verifyLoading = false
this.verifyDialogVisible = false
if (res && (res.code === 200 || res.msg === '操作成功')) {
const merged = this.injectOptional(this.extractFirstResponse(res.data))
this.resultText = merged
this.$modal.msgSuccess('已强制录单')
} else {
this.$modal.msgError((res && res.msg) || '执行失败')
}
}).catch(() => {
this.verifyLoading = false
this.$modal.msgError('请求失败')
})
},
resetForm() {
this.form = {
mark: 'F',
model: '',
address: '',
link: '',
qty: 1,
buyer: '',
paymentText: '',
rebateText: '',
logisticsLink: ''
}
this.resultText = ''
},
copyResult() {
const t = this.resultText || ''
if (!t) return
if (navigator.clipboard) {
navigator.clipboard.writeText(t).then(() => {
this.$modal.msgSuccess('已复制')
}).catch(() => this.fallbackCopy(t))
} else {
this.fallbackCopy(t)
}
},
fallbackCopy(text) {
const ta = document.createElement('textarea')
ta.value = text
document.body.appendChild(ta)
ta.focus()
ta.select()
try {
document.execCommand('copy')
this.$modal.msgSuccess('已复制')
} catch (e) {
this.$modal.msgError('复制失败')
}
document.body.removeChild(ta)
}
}
}
</script>
<style scoped>
.mobile-fadan {
padding-bottom: 16px;
}
.box-card {
margin: 0 12px 20px;
}
.fadan-form ::v-deep .el-form-item {
margin-bottom: 14px;
}
.btn-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 8px;
}
.result-area ::v-deep .el-textarea__inner {
font-family: Consolas, 'Courier New', monospace;
font-size: 13px;
}
.verify-body .verify-code {
text-align: center;
font-size: 26px;
font-weight: 700;
color: #409eff;
margin: 16px 0;
}
@media (max-width: 768px) {
.box-card {
margin: 0 8px 16px;
}
}
</style>