feat(tender): 我的订单加「去支付」「取消订单」入口,并新建收银台
hjc-web 此前**没有收银台**——支付步骤内嵌在购标流程(BuyDocument 的 step='pay')里, 买家一旦离开就再也回不到未完成的支付。本提交补上按订单号付款的独立页面。 - 新建 /tender/pay 收银台:只认订单号,金额取自**订单本身**(by-no)而非支付响应 (支付一失败页面就会停在 0.00);进入先判状态,已支付/已取消/已退款**不发**统一下单, 就地显示结论——既无意义,也会多撞一次跨端 OUT_TRADE_NO_USED - 订单列表:待支付卡片加两个按钮 + 手搓 Tailwind 二次确认弹窗(照 ConsultDialog 的风格, 不用 antd 的 Modal:买家页无先例,视觉与站点自建风格不一致) - 状态口径改读 orderStatus(原先只看 payStatus,取消后会把已取消显示成「待支付」 并带上「去支付」),抽 app/utils/orderStatus.ts,与 hjc-h5 刻意保持同一套优先级 - 新增两个 Nitro 代理 order-by-no.get.ts / cancel.post.ts,照既有 my-orders / pay-status 的范式原样透传 ApiResult - 标书详情「购买人数」改读 buyerCount(后端实时统计的已付款订单数) - 跨端 OUT_TRADE_NO_USED:识别后端回带的 data.wechatCode 并给可行动提示, 不匹配 message 字符串(包装方式一改就会静默失效)
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<Teleport to="body">
|
||||
<Transition name="hjc-confirm-fade">
|
||||
<div
|
||||
v-if="open"
|
||||
class="fixed inset-0 z-[110] flex items-center justify-center p-4"
|
||||
@click.self="onCancel"
|
||||
>
|
||||
<!-- 遮罩 -->
|
||||
<div class="absolute inset-0 bg-black/50" />
|
||||
|
||||
<!-- 弹窗卡片:照 ConsultDialog.vue 的手搓 Tailwind 风格,不用 antd 的 Modal
|
||||
(ant-design-vue 虽已装且自动导入,但买家页没有先例,视觉与站点自建风格不一致) -->
|
||||
<Transition name="hjc-confirm-pop" appear>
|
||||
<div
|
||||
v-if="open"
|
||||
class="relative w-full max-w-sm rounded-2xl bg-white p-6 shadow-2xl"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
:aria-label="title"
|
||||
>
|
||||
<h2 class="text-lg font-bold text-gray-900">{{ title }}</h2>
|
||||
<p v-if="content" class="mt-2 text-sm leading-relaxed text-gray-600">{{ content }}</p>
|
||||
|
||||
<div class="mt-6 flex justify-end gap-3">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-md border border-gray-300 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 disabled:opacity-50"
|
||||
:disabled="loading"
|
||||
@click="onCancel"
|
||||
>
|
||||
{{ cancelText }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-md bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700 disabled:opacity-50"
|
||||
:disabled="loading"
|
||||
@click="emit('confirm')"
|
||||
>
|
||||
{{ loading ? loadingText : confirmText }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 通用二次确认弹窗(破坏性操作用)。
|
||||
*
|
||||
* 与 ConsultDialog.vue 同款实现路径:`ClientOnly` + `Teleport to="body"` + 手搓 Tailwind。
|
||||
* 组件本身不持有任何业务状态——开合由父组件通过 `open` 控制,结果通过 `confirm`/`cancel` 事件回传,
|
||||
* 这样"点遮罩不发请求"这类行为天然成立(父组件只在 confirm 里发请求)。
|
||||
*/
|
||||
const props = withDefaults(defineProps<{
|
||||
open: boolean
|
||||
title: string
|
||||
content?: string
|
||||
confirmText?: string
|
||||
cancelText?: string
|
||||
loadingText?: string
|
||||
/** 确认动作进行中:两个按钮都禁用,防连点 */
|
||||
loading?: boolean
|
||||
}>(), {
|
||||
content: '',
|
||||
confirmText: '确定',
|
||||
cancelText: '再想想',
|
||||
loadingText: '处理中...',
|
||||
loading: false
|
||||
})
|
||||
|
||||
const emit = defineEmits<{ confirm: []; cancel: [] }>()
|
||||
|
||||
function onCancel() {
|
||||
if (props.loading) return
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
/** ESC 关闭;打开时锁背景滚动,关闭时复位 */
|
||||
function onKeydown(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape' && props.open) onCancel()
|
||||
}
|
||||
|
||||
watch(() => props.open, (isOpen) => {
|
||||
if (!import.meta.client) return
|
||||
document.body.style.overflow = isOpen ? 'hidden' : ''
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', onKeydown)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKeydown)
|
||||
if (import.meta.client) document.body.style.overflow = ''
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hjc-confirm-fade-enter-active,
|
||||
.hjc-confirm-fade-leave-active {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
.hjc-confirm-fade-enter-from,
|
||||
.hjc-confirm-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hjc-confirm-pop-enter-active {
|
||||
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
|
||||
}
|
||||
.hjc-confirm-pop-leave-active {
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
.hjc-confirm-pop-enter-from {
|
||||
transform: scale(0.95) translateY(10px);
|
||||
opacity: 0;
|
||||
}
|
||||
.hjc-confirm-pop-leave-to {
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user