This commit is contained in:
2026-09-24 16:25:22 +08:00
commit 7428184f01
1198 changed files with 314515 additions and 0 deletions
+273
View File
@@ -0,0 +1,273 @@
<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>