Files
pj_admin_cloud/src/views/hard/components/print-task-dialog.vue
T
2026-09-08 15:25:06 +08:00

148 lines
6.1 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>
<el-dialog v-model="visible" :title="title" width="520px" draggable :close-on-click-modal="false">
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px" v-loading="loading">
<el-form-item label="订单号">
<el-input :model-value="orderLabel" disabled />
</el-form-item>
<el-form-item label="凭证类型">
<el-tag :type="options.printType === '2' ? 'warning' : 'primary'">
{{ options.printType === "2" ? "兑换券" : "发票" }}
</el-tag>
</el-form-item>
<el-form-item v-if="showSourceSelection" label="来源终端" prop="sourceHardId">
<el-select v-model="form.sourceHardId" class="w-full" filterable placeholder="请选择已绑定尔印打印机的业务终端">
<el-option v-for="source in sources" :key="source.id" :label="source.name" :value="String(source.id)" />
</el-select>
<div v-if="sources.length === 0" class="mt-1 text-xs text-[var(--el-color-danger)]">
该商户没有已绑定尔印打印机的业务终端,请先在设备管理完成绑定。
</div>
</el-form-item>
<el-form-item v-if="requiresReason" label="重打原因" prop="reprintReason">
<el-input v-model="form.reprintReason" type="textarea" :rows="3" maxlength="200" show-word-limit
placeholder="请填写本次人工重打原因" />
</el-form-item>
<el-alert v-if="options.action === 'retry'" type="info" :closable="false" show-icon
title="重试原任务不会增加打印序号;终端只处理新的重试版本。" />
</el-form>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" :loading="submitting" :disabled="sourceUnavailable" @click="submit">
提交打印任务
</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="HardPrintTaskDialog">
import * as hardInvoiceApi from "/@/api/hard/hard-invoice"
import * as printerApi from "/@/api/hard/hard-printer"
import { useMessage, useMessageBox } from "/@/hooks/message"
type PrintAction = "create" | "retry" | "reprint"
interface PrintDialogOptions {
action: PrintAction
printType: "1" | "2"
orderId: string | number
merchantId?: string | number
taskId?: string | number
sourceHardId?: string | number | null
orderNo?: string
printNo?: string | number | null
}
const emit = defineEmits(["submitted"])
const visible = ref(false)
const loading = ref(false)
const submitting = ref(false)
const formRef = ref()
const sources = ref<any[]>([])
const options = reactive<PrintDialogOptions>({ action: "create", printType: "1", orderId: "" })
/** 来源设备使用字符串保存,避免选择或自动回填时破坏后端 Long 主键精度。 */
const form = reactive<{ sourceHardId: printerApi.HardwareId | null; reprintReason: string }>({
sourceHardId: null,
reprintReason: "",
})
/** 已打印任务再次出纸必须记录原因;失败任务重试不改变打印次数。 */
const requiresReason = computed(() => options.action === "reprint" || Boolean(options.printNo && options.action === "create"))
const showSourceSelection = computed(() => options.action !== "reprint" && !(options.action === "retry" && options.sourceHardId))
const sourceUnavailable = computed(() => showSourceSelection.value && !loading.value && sources.value.length === 0)
const orderLabel = computed(() => options.orderNo || String(options.orderId || "--"))
const title = computed(() => {
if (options.action === "retry") return "重试失败打印任务"
if (options.action === "reprint") return `重打${options.printType === "2" ? "兑换券" : "发票"}`
return `${requiresReason.value ? "再次打印" : "打印"}${options.printType === "2" ? "兑换券" : "发票"}`
})
const rules = computed(() => ({
sourceHardId: showSourceSelection.value ? [{ required: true, message: "请选择来源业务终端", trigger: "change" }] : [],
reprintReason: requiresReason.value ? [{ required: true, message: "请填写重打原因", trigger: "blur" }] : [],
}))
/** 打开任务弹窗,并根据商户的有效绑定自动选择唯一来源终端。 */
const open = async (input: PrintDialogOptions) => {
Object.assign(options, input)
form.sourceHardId = null
form.reprintReason = ""
sources.value = []
visible.value = true
await nextTick()
formRef.value?.clearValidate?.()
if (!showSourceSelection.value) return
if (!input.merchantId) {
useMessage().error("订单缺少商户信息,无法选择打印终端")
return
}
loading.value = true
try {
const response: any = await printerApi.listBoundSources(String(input.merchantId))
sources.value = response.data || []
const preferred = sources.value.find((source) => input.sourceHardId != null
&& String(source.id) === String(input.sourceHardId))
if (preferred) form.sourceHardId = String(preferred.id)
else if (sources.value.length === 1) form.sourceHardId = String(sources.value[0].id)
} catch (error: any) {
useMessage().error(error?.msg || "读取可用打印终端失败")
} finally {
loading.value = false
}
}
/** 校验、二次确认并提交任务;响应只代表任务受理,不代表打印机已经出纸。 */
const submit = async () => {
const valid = await formRef.value?.validate?.().catch(() => false)
if (valid === false) return
if (requiresReason.value) {
try {
await useMessageBox().confirm(`确认提交第 ${Number(options.printNo || 0) + 1} 次打印?提交后将保留操作原因。`)
} catch {
return
}
}
submitting.value = true
try {
if (options.action === "retry") {
await hardInvoiceApi.retry({ historyId: options.taskId, sourceHardId: form.sourceHardId || undefined })
} else if (options.action === "reprint") {
await hardInvoiceApi.reprint({ historyId: options.taskId, reprintReason: form.reprintReason.trim() })
} else {
await hardInvoiceApi.print({
orderId: options.orderId,
printType: options.printType,
sourceHardId: form.sourceHardId || undefined,
reprintReason: form.reprintReason.trim() || undefined,
})
}
visible.value = false
useMessage().success("打印任务已提交")
emit("submitted")
} catch (error: any) {
useMessage().error(error?.msg || "打印任务提交失败")
} finally {
submitting.value = false
}
}
defineExpose({ open })
</script>