Files
hospital-rescue-app-v2/pages/warehouse/goods-detail.uvue
T
2026-09-24 16:25:22 +08:00

274 lines
6.6 KiB
Plaintext
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>
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="物资详情" :xloading="true" @right-click="onMore">
<template v-slot:right>
<x-icon name="more-fill" color="#6B7280" font-size="18"></x-icon>
</template>
<view class="hr-body">
<!-- ============ 概览 ============ -->
<hr-card>
<view class="hr-row">
<view class="gd-ring">
<x-circle-progress :size="76" :line-width="8" color="#F3F4F6" active-color="#F59E0B"
:model-value="ringPercent" :show-label="false" :duration="600"></x-circle-progress>
<view class="gd-ring-label">
<text class="gd-ring-b">{{ goods.stock }}</text>
<text class="gd-ring-u">{{ goods.unit }}</text>
</view>
</view>
<view class="hr-flex1">
<text class="gd-name">{{ goods.name }}</text>
<text class="gd-code">编码 {{ goods.code }} · {{ goods.spec }}</text>
<view style="margin-top:7px">
<hr-pc :level="0" :text="goods.statusLabel"></hr-pc>
</view>
</view>
</view>
</hr-card>
<!-- ============ 库存信息 ============ -->
<hr-sec title="库存信息"></hr-sec>
<hr-card variant="list">
<hr-lrow icon="▦" title="当前库存" :sub="'预警线 ' + goods.warnLine + ' ' + goods.unit">
<template v-slot:right>
<text class="gd-v gd-v-red">{{ goods.stock }} {{ goods.unit }}</text>
</template>
</hr-lrow>
<hr-lrow icon="⇅" theme="pri" title="近 30 天出库" :sub="goods.dailyUse">
<template v-slot:right>
<text class="gd-v">{{ goods.out30 }} {{ goods.unit }}</text>
</template>
</hr-lrow>
<hr-lrow icon="▤" theme="grn" title="最近入库" :sub="goods.lastIn" :is-last="true">
<template v-slot:right>
<text class="gd-v gd-v-grn">{{ goods.lastInQty }}</text>
</template>
</hr-lrow>
</hr-card>
<!-- ============ 消耗趋势 ============ -->
<hr-sec title="30 天消耗趋势" more="查看明细 "></hr-sec>
<hr-card>
<view class="gd-chart">
<view v-for="(h, i) in barHeights" :key="i" class="gd-bar-wrap">
<view class="gd-bar" :style="barStyle(i, h)"></view>
</view>
</view>
<view class="gd-xaxis">
<text v-for="(x, i) in xLabels" :key="i" class="gd-x">{{ x }}</text>
</view>
<view class="gd-legend">
<view class="gd-lg">
<view class="gd-lg-d" style="background-color:#EFF6FF"></view>
<text class="gd-lg-t">正常区间</text>
</view>
<view class="gd-lg">
<view class="gd-lg-d" style="background-color:#F59E0B"></view>
<text class="gd-lg-t">接近预警</text>
</view>
<view class="gd-lg">
<view class="gd-lg-d" style="background-color:#DC2626"></view>
<text class="gd-lg-t">低于预警线</text>
</view>
</view>
</hr-card>
<hr-tip style="margin-top:14px" theme="warn" icon="⚠"
:text="'按当前消耗速度(' + goods.dailyUse + '),库存预计 ' + daysLeft + ' 天后耗尽,建议尽快补货。'"></hr-tip>
<view class="hr-btn hr-btn-primary hr-btn-lg" style="margin-top:12px" @click="onRestock">
<x-icon name="add-line" color="#FFFFFF" font-size="17"></x-icon>
<text class="gd-bt">发起补货申请</text>
</view>
<view style="height:14px"></view>
</view>
</hr-page>
</template>
<script lang="uts" setup>
import { ref, computed } from 'vue'
import { goodsDetail } from '@/mock/index.uts'
import { navTo } from '@/utils/nav.uts'
/**
* s25 物资详情
* 库存环 + 库存信息 + 30 天消耗趋势 + 补货入口。
*/
const goods = goodsDetail
const xLabels : string[] = ['08-24', '08-31', '09-07', '09-14', '09-21']
const ringPercent = computed(() : number => {
// 库存 / (预警线 × 2.5) —— 8 / 50 ≈ 16%,与设计稿 18% 量级一致
return Math.round(goods.stock * 100 / (goods.warnLine * 2.5))
})
const barHeights = computed(() : number[] => {
const arr : number[] = []
for (let i = 0; i < goods.trend.length; i++) {
arr.push(Math.round(176 * goods.trend[i] / 100))
}
return arr
})
const daysLeft = computed(() : number => {
const daily = goods.out30 / 30
if (daily <= 0) { return 0 }
return Math.floor(goods.stock / daily)
})
function barStyle(i : number, h : number) : string {
let color = '#EFF6FF'
if (i == goods.trend.length - 1) { color = '#DC2626' }
else if (i == goods.trend.length - 2) { color = '#F59E0B' }
return `height:${h}rpx;background-color:${color};`
}
function onMore() : void {
uni.showToast({ title: '出入库流水 / 编辑物资', icon: 'none' })
}
function onRestock() : void {
uni.showModal({
title: '发起补货申请',
content: `物资:${goods.name}\n建议补货量:40 ${goods.unit}(约 2 周用量)`,
cancelText: '取消',
confirmText: '提交申请',
success: (res) => {
if (res.confirm) {
uni.showToast({ title: '补货申请已提交', icon: 'success' })
setTimeout(() => {
navTo('/pages/message/index')
}, 700)
}
}
})
}
</script>
<style>
.gd-ring {
width: 152rpx;
height: 152rpx;
position: relative;
margin-right: 26rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.gd-ring-label {
position: absolute;
left: 0rpx;
top: 0rpx;
width: 152rpx;
height: 152rpx;
flex-direction: row;
align-items: center;
justify-content: center;
}
.gd-ring-b {
font-size: 42.6rpx;
font-weight: bold;
color: #1F2937;
}
.gd-ring-u {
font-size: 22.4rpx;
color: #9CA3AF;
margin-left: 2rpx;
}
.gd-name {
font-size: 33.6rpx;
font-weight: bold;
color: #1F2937;
}
.gd-code {
font-size: 25.8rpx;
color: #6B7280;
margin-top: 10rpx;
}
.gd-v {
font-size: 33.6rpx;
font-weight: bold;
color: #1F2937;
margin-left: 16rpx;
}
.gd-v-red {
color: #DC2626;
}
.gd-v-grn {
color: #059669;
}
/* ---------- 趋势图 ---------- */
.gd-chart {
display: flex;
flex-direction: row;
align-items: flex-end;
height: 176rpx;
}
.gd-bar-wrap {
flex: 1;
justify-content: flex-end;
margin-right: 10rpx;
}
.gd-bar {
border-radius: 8rpx 8rpx 0rpx 0rpx;
}
.gd-xaxis {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 14rpx;
}
.gd-x {
font-size: 22.4rpx;
color: #9CA3AF;
}
.gd-legend {
display: flex;
flex-direction: row;
margin-top: 20rpx;
}
.gd-lg {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 28rpx;
}
.gd-lg-d {
width: 20rpx;
height: 20rpx;
border-radius: 6rpx;
margin-right: 10rpx;
}
.gd-lg-t {
font-size: 23.6rpx;
color: #6B7280;
}
.gd-bt {
font-size: 35.8rpx;
font-weight: bold;
color: #FFFFFF;
margin-left: 12rpx;
}
</style>