feat(tender): 汇吉采标书购买 阶段3 - C端标书列表/详情/购买入口
- server/api/tender/{list.get,detail.get,order.post}.ts 代理到 mp-api /api/hjc/bid-project|order
- app/types/tender.ts 前端视图模型
- app/templates/template-07/pages/{TenderList,TenderDetail,BuyDocument}.vue(Tailwind,仿 Product 页)
- app/pages/tender/index.vue + tender/[id].vue + buy.vue 路由,经 useTemplate 加载
- useTemplate.ts 注册 TenderList/TenderDetail/BuyDocument(全部模板安全可选)
- 附 BUY_TENDER_MAP_REPORT.md(hjc-web 结构映射参考)
This commit is contained in:
@@ -1,11 +1,112 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>sdfsdfsdsdfbuy---</div>
|
||||
<div class="container mx-auto px-4 py-10">
|
||||
<NuxtLink to="/tender" class="text-sm text-blue-600 hover:underline">← 返回标书中心</NuxtLink>
|
||||
|
||||
<div v-if="tender" class="mx-auto mt-6 max-w-2xl rounded-lg border border-gray-200 p-6">
|
||||
<h1 class="text-xl font-bold text-gray-900">购买标书</h1>
|
||||
<div class="mt-4 rounded-md bg-gray-50 p-4 text-sm">
|
||||
<p class="font-semibold text-gray-800">{{ tender.projectName }}</p>
|
||||
<p class="mt-1 text-gray-500">项目编号:{{ tender.projectNo }}</p>
|
||||
<p class="mt-2 text-blue-600">
|
||||
信息服务费:<span class="text-2xl font-bold">¥{{ formatMoney(tender.tenderPrice) }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form class="mt-6 space-y-4" @submit.prevent="submit">
|
||||
<div>
|
||||
<label class="text-sm text-gray-600">购买联系人</label>
|
||||
<input v-model="form.contactName" class="mt-1 w-full rounded-md border border-gray-300 px-4 py-2 text-sm" placeholder="姓名" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600">联系电话</label>
|
||||
<input v-model="form.contactPhone" class="mt-1 w-full rounded-md border border-gray-300 px-4 py-2 text-sm" placeholder="手机号" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600">联系邮箱</label>
|
||||
<input v-model="form.contactEmail" type="email" class="mt-1 w-full rounded-md border border-gray-300 px-4 py-2 text-sm" placeholder="邮箱" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm text-gray-600">购买数量</label>
|
||||
<input v-model.number="form.quantity" type="number" min="1" class="mt-1 w-full rounded-md border border-gray-300 px-4 py-2 text-sm" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full rounded-md bg-blue-600 py-3 text-white font-medium hover:bg-blue-700 disabled:opacity-50"
|
||||
:disabled="submitting"
|
||||
>
|
||||
{{ submitting ? '提交中...' : '提交订单并支付' }}
|
||||
</button>
|
||||
|
||||
<p v-if="tip" class="text-center text-sm text-gray-500">{{ tip }}</p>
|
||||
<p v-if="error" class="text-center text-sm text-red-500">{{ error }}</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div v-else-if="notFound" class="py-20 text-center text-gray-500">项目不存在</div>
|
||||
<SiteLoading v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<script setup lang="ts">
|
||||
import type { Tender } from '~/types/tender'
|
||||
|
||||
</style>
|
||||
const route = useRoute()
|
||||
const id = route.query.id as string
|
||||
const tender = shallowRef<Tender | null>(null)
|
||||
const notFound = ref(false)
|
||||
const submitting = ref(false)
|
||||
const tip = ref('')
|
||||
const error = ref('')
|
||||
|
||||
const form = reactive({
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
contactEmail: '',
|
||||
quantity: 1
|
||||
})
|
||||
|
||||
function formatMoney(n?: number | string) {
|
||||
return Number(n ?? 0).toFixed(2)
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
error.value = ''
|
||||
tip.value = ''
|
||||
submitting.value = true
|
||||
try {
|
||||
const res: any = await $fetch('/api/tender/order', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
projectId: Number(id),
|
||||
quantity: form.quantity || 1,
|
||||
contactName: form.contactName,
|
||||
contactPhone: form.contactPhone,
|
||||
contactEmail: form.contactEmail
|
||||
}
|
||||
})
|
||||
if (res && res.orderNo) {
|
||||
tip.value = `下单成功,订单号:${res.orderNo},请扫码支付`
|
||||
// TODO(阶段3b): 调 /api/tender/pay 获取微信二维码(需登录态)
|
||||
} else {
|
||||
error.value = res?.message || '下单失败'
|
||||
}
|
||||
} catch (e: any) {
|
||||
error.value = e?.data?.message || e?.message || '下单失败'
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!id) {
|
||||
notFound.value = true
|
||||
} else {
|
||||
const res: any = await $fetch(`/api/tender/detail?id=${id}`)
|
||||
if (res && res.id) tender.value = res
|
||||
else notFound.value = true
|
||||
}
|
||||
} catch {
|
||||
notFound.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user