Files
art-design-uniapp/pages/borrow/borrow_detils.vue
T
2026-02-06 14:39:37 +08:00

495 lines
10 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>
<view class="home-page">
<uni-nav-bar
leftText=" "
:fixed="true"
leftIcon="back"
:border="false"
@clickLeft="leftClick"
color="#fff"
backgroundColor="rgb(79 137 247)"
:statusBar="true"
title="详情"
></uni-nav-bar>
<view class="content-wrapper">
<view class="detail-card">
<!-- 状态丝带 -->
<view class="status-ribbon" :class="statusMeta.cls">
<text class="ribbon-text">{{ statusMeta.text }}</text>
</view>
<!-- 头部信息 -->
<view class="card-header">
<view class="header-left">
<text class="order-no">{{ detail.order_no || ('#' + id) }}</text>
<text class="sub-line">
申请人:{{ detail.applicant_name || '—' }}
<text class="dot">·</text>
提交:{{ detail.created_at || '—' }}
</text>
</view>
</view>
<!-- 使用时间 -->
<view class="section">
<text class="section-title">借用时间</text>
<view class="kv">
<text class="kv-label">开始</text>
<text class="kv-value">{{ detail.use_start_date || '—' }}</text>
</view>
<view class="kv">
<text class="kv-label">结束</text>
<text class="kv-value">{{ detail.use_end_date || '—' }}</text>
</view>
</view>
<!-- 物品列表 -->
<view class="section">
<view class="section-title-row">
<text class="section-title">物品明细</text>
<text class="section-sub" v-if="Array.isArray(detail.item)">
共 {{ detail.item.length }} 条
</text>
</view>
<view v-if="Array.isArray(detail.item) && detail.item.length" class="items">
<view class="item-card" v-for="(it, idx) in detail.item" :key="it.id || idx">
<view class="item-top">
<text class="item-name">{{ it.item_name_snap || '—' }}</text>
<text class="item-tag" v-if="String(it.is_consumable_snap) === '1'">耗材</text>
</view>
<view class="item-grid">
<view class="grid-cell">
<text class="g-label">申请</text>
<text class="g-val">{{ safeNum(it.request_qty) }}</text>
</view>
<view class="grid-cell">
<text class="g-label">归还</text>
<text class="g-val">{{ safeNum(it.returned_qty) }}</text>
</view>
</view>
<view class="item-remark" v-if="it.remark">
<text class="remark-label">备注</text>
<text class="remark-value">{{ it.remark }}</text>
</view>
</view>
</view>
<view v-else class="empty-hint">暂无物品明细</view>
</view>
<!-- 借用事由/备注 -->
<view class="section">
<text class="section-title">借用说明</text>
<view class="text-block">
<text class="text-label">借用事由</text>
<text class="text-value">{{ detail.borrow_reason || '—' }}</text>
</view>
<view class="text-block" v-if="detail.remark">
<text class="text-label">备注</text>
<text class="text-value">{{ detail.remark }}</text>
</view>
</view>
<!-- 附件 -->
<view class="section">
<view class="section-title-row">
<text class="section-title">附件</text>
<text class="section-sub" v-if="Array.isArray(detail.attachment)">
{{ detail.attachment.length || 0 }} 张
</text>
</view>
<view v-if="Array.isArray(detail.attachment) && detail.attachment.length" class="attach-grid">
<view
class="attach-item"
v-for="(a, index) in detail.attachment"
:key="a.id || index"
@click="previewAttachment(index)"
>
<image class="attach-img" :src="a.file_path_pull" mode="aspectFill"></image>
</view>
</view>
<view v-else class="empty-hint">暂无附件</view>
</view>
<!-- 底部操作(可选:与列表页一致) -->
<view class="bottom-actions" v-if="showBottomAction">
<button class="primary-btn" @click="goAction">{{ bottomActionText }}</button>
</view>
</view>
</view>
</view>
</template>
<script>
import { request, showToast } from '@/api/apiT.js'
export default {
data() {
return {
id: '',
detail: {}
}
},
computed: {
// 状态映射
statusMeta() {
const status = String(this.detail.status)
const isReturned = String(this.detail.is_returned) === '1'
const statusMap = {
'10': { text: '待审核', cls: 'ribbon-pendingReview' },
'11': { text: '审批中', cls: 'ribbon-pendingReview' },
'12': { text: '待归还', cls: 'ribbon-notReturned' },
'13': { text: '借用拒绝', cls: 'ribbon-notReturned' },
'14': { text: '归还待审核', cls: 'ribbon-pendingReview' },
'15': { text: '归还审批中', cls: 'ribbon-pendingReview' },
'16': { text: '部分归还', cls: 'ribbon-notReturned' },
'17': { text: '已归还', cls: 'ribbon-returned' },
'18': { text: '归还拒绝', cls: 'ribbon-notReturned' },
'19': { text: '损耗品', cls: 'ribbon-notReturned' }
}
if (isReturned) return { text: '已归还', cls: 'ribbon-returned' }
return statusMap[status] || { text: '未知状态', cls: 'ribbon-notReturned' }
},
showBottomAction() {
// 仅在“待归还”和“部分归还”时展示按钮
const status = String(this.detail.status)
const isReturned = String(this.detail.is_returned) === '1'
if (isReturned) return false
return ['12', '16'].includes(status)
},
bottomActionText() {
// 待归还和部分归还状态显示“去归还”按钮
return '去归还'
}
},
onLoad(options) {
this.id = options.id || ''
this.getDetails()
},
methods: {
leftClick() {
uni.navigateBack({})
},
getDetails() {
if (!this.id) return
request({
url: 'mobile/inv/requisition/show',
method: 'get',
data: { id: this.id }
}).then((res) => {
if (res?.data?.code !== 200) {
showToast({ title: res?.data?.msg || '获取详情失败' })
return
}
const d = res.data.data || {}
// 兜底,避免 v-for 报错
d.item = Array.isArray(d.item) ? d.item : []
d.attachment = Array.isArray(d.attachment) ? d.attachment : []
this.detail = d
})
},
safeNum(v) {
const n = Number(v)
return Number.isFinite(n) ? n : 0
},
previewAttachment(index) {
const urls = (this.detail.attachment || [])
.map((a) => a.file_path_pull)
.filter(Boolean)
if (!urls.length) return
uni.previewImage({
current: urls[index] || urls[0],
urls
})
},
goAction() {
// 待归还和部分归还状态点击按钮导航到归还页面
uni.navigateTo({
url: '/pages/borrow/return?id=' + this.id
})
}
}
}
</script>
<style lang="scss">
.home-page {
min-height: 100vh;
background: linear-gradient(180.05deg, #3074f7 0.04%, #f4f6f8 34.07%);
box-sizing: border-box;
padding: 0 28rpx 120rpx;
}
.content-wrapper {
margin-top: 20rpx;
}
.detail-card {
position: relative;
background: #fff;
border-radius: 12rpx;
padding: 28rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
overflow: hidden;
}
.card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
padding-top: 10rpx;
margin-bottom: 18rpx;
}
.header-left {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.order-no {
font-size: 32rpx;
font-weight: 700;
color: #222;
}
.sub-line {
font-size: 24rpx;
color: #8a8a8a;
}
.dot {
padding: 0 10rpx;
color: #c0c0c0;
}
.section {
margin-top: 22rpx;
padding-top: 10rpx;
border-top: 1rpx solid #f2f2f2;
}
.section-title-row {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 10rpx;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.section-sub {
font-size: 24rpx;
color: #9a9a9a;
}
.kv {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8rpx 0;
}
.kv-label {
font-size: 26rpx;
color: #666;
}
.kv-value {
font-size: 26rpx;
color: #333;
text-align: right;
max-width: 66%;
}
.items {
display: flex;
flex-direction: column;
gap: 14rpx;
margin-top: 8rpx;
}
.item-card {
background: #fafbff;
border: 1rpx solid #eef2ff;
border-radius: 12rpx;
padding: 18rpx;
}
.item-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12rpx;
margin-bottom: 14rpx;
}
.item-name {
font-size: 28rpx;
font-weight: 600;
color: #2b2b2b;
flex: 1;
}
.item-tag {
font-size: 22rpx;
padding: 6rpx 12rpx;
border-radius: 999rpx;
color: #3074f7;
background: rgba(48, 116, 247, 0.1);
white-space: nowrap;
}
.item-grid {
display: flex;
gap: 10rpx;
}
.grid-cell {
flex: 1;
background: #ffffff;
border-radius: 10rpx;
padding: 14rpx 10rpx;
text-align: center;
border: 1rpx solid #f0f0f0;
}
.g-label {
display: block;
font-size: 22rpx;
color: #888;
margin-bottom: 6rpx;
}
.g-val {
display: block;
font-size: 30rpx;
font-weight: 700;
color: #222;
}
.item-remark {
margin-top: 12rpx;
display: flex;
gap: 12rpx;
align-items: flex-start;
}
.remark-label {
font-size: 24rpx;
color: #888;
white-space: nowrap;
}
.remark-value {
font-size: 24rpx;
color: #333;
flex: 1;
}
.text-block {
padding: 10rpx 0;
}
.text-label {
display: block;
font-size: 24rpx;
color: #888;
margin-bottom: 6rpx;
}
.text-value {
display: block;
font-size: 26rpx;
color: #333;
line-height: 1.6;
white-space: pre-wrap;
}
.attach-grid {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
margin-top: 10rpx;
}
.attach-item {
width: 32%;
height: 208rpx;
border-radius: 12rpx;
overflow: hidden;
background: #f6f6f6;
}
.attach-img {
width: 100%;
height: 100%;
}
.empty-hint {
padding: 18rpx 0 6rpx;
font-size: 24rpx;
color: #9a9a9a;
}
.bottom-actions {
margin-top: 26rpx;
}
.primary-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
border-radius: 14rpx;
background: #3074f7;
color: #fff;
font-size: 30rpx;
font-weight: 600;
}
.status-ribbon {
position: absolute;
top: -4px;
right: -32px;
width: 100px;
height: 47px;
transform: rotate(45deg);
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
.ribbon-returned {
background: #08a400;
}
.ribbon-notReturned {
background: #bd0000;
}
.ribbon-pendingReview {
background: #3471ff;
}
.ribbon-text {
color: #fff;
font-size: 20rpx;
font-weight: 500;
display: block;
text-align: center;
margin-top: 16rpx;
white-space: nowrap;
letter-spacing: 1rpx;
}
</style>