Files
hjc-web/app/components/HjcTenderFiles.vue
T
weicw1996 2e847b5e09 feat(hjc-web): 新建订单详情页,订单列表与详情支持下载已支付订单的标书
此前 PC 没有订单详情页,标书下载只有两句文案(`.scratch/hjc-web-order-detail/01`)。

- 新增 `app/pages/tender/orders/[id].vue`:订单状态、标书附件、待支付操作区、
  标书/支付/购买人信息;取数走 `useRequestFetch()`(裸 `$fetch` 在 SSR 不转发 Cookie,
  会把用户登出)
- `app/pages/tender/orders.vue` → `orders/index.vue`:Nuxt 里同名 file+目录会生成父子路由,
  详情页会被父页吞掉,必须让列表页是 `index.vue`
- 列表页每张卡片加「标书附件」(仅已支付)与「查看详情」,不整卡可点(卡内已有按钮与链接)
- 新增 `app/components/HjcTenderFiles.vue` 与代理 `server/api/tender/order-detail.get.ts`
- 附件地址来自后端按 `payStatus=1` 下发的 `tenderFiles`,前端不做权限判断、不自己拼地址

规格与验收:`.scratch/hjc-tender-download/`
2026-09-17 18:09:27 +08:00

78 lines
2.2 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>
<ul v-if="files.length" class="space-y-2">
<li
v-for="(file, idx) in files"
:key="file.url + idx"
class="flex items-center gap-3 rounded-lg border border-gray-200 px-4 py-2.5"
>
<!-- 用内联 SVG避免为一个小图标引入图标库依赖 PageAttachments.vue -->
<span class="shrink-0 text-blue-600" aria-hidden="true">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<path d="M14 2v6h6" />
</svg>
</span>
<a
:href="file.url"
target="_blank"
rel="noopener"
class="min-w-0 flex-1 truncate text-sm text-blue-600 hover:underline"
:title="nameOf(file)"
>
{{ nameOf(file) }}
</a>
<!--
附件是第三方 OSS 直链`download` 属性跨域不生效直接新标签打开
PDF/图片由浏览器预览其余类型浏览器自己下载)。
-->
<a
:href="file.url"
target="_blank"
rel="noopener"
class="shrink-0 text-sm text-blue-600 hover:underline"
>
下载
</a>
</li>
</ul>
</template>
<script setup lang="ts">
import type { HjcTenderFile } from '~/types/tender'
/**
* 标书附件列表(订单列表页与订单详情页共用)。
*
* 只渲染后端下发的 `tenderFiles`:地址本身是付费内容,未支付订单后端不下发,
* 所以这里**不做任何权限判断**,也不从项目字段里自己拼地址。
*/
const props = withDefaults(
defineProps<{
files?: HjcTenderFile[] | null
}>(),
{
files: () => []
}
)
/** 过滤掉没有地址的脏数据(后端已保证,前端再兜一层,避免渲染出死链) */
const files = computed<HjcTenderFile[]>(() =>
(props.files || []).filter((f) => !!f && typeof f.url === 'string' && f.url.length > 0)
)
function nameOf(file: HjcTenderFile) {
return file.name || '标书附件'
}
</script>