2e847b5e09
此前 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/`
78 lines
2.2 KiB
Vue
78 lines
2.2 KiB
Vue
<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>
|