From 2291b7406cdc184abfa1b1986baeb55499771343 Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期一, 16 三月 2026 17:07:15 +0800
Subject: [PATCH] fix(设备管理): 修正添加维护接口的URL路径
---
src/pages/consumablesLogistics/stockReport/index.vue | 242 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 242 insertions(+), 0 deletions(-)
diff --git a/src/pages/consumablesLogistics/stockReport/index.vue b/src/pages/consumablesLogistics/stockReport/index.vue
new file mode 100644
index 0000000..a46a065
--- /dev/null
+++ b/src/pages/consumablesLogistics/stockReport/index.vue
@@ -0,0 +1,242 @@
+<template>
+ <view class="report-page">
+ <PageHeader title="搴撳瓨鎶ヨ〃" @back="goBack" />
+ <view class="tabs-wrap">
+ <view
+ v-for="t in reportTypes"
+ :key="t.value"
+ class="tab-item"
+ :class="{ active: searchForm.reportType === t.value }"
+ @click="searchForm.reportType = t.value"
+ >
+ <text>{{ t.label }}</text>
+ </view>
+ </view>
+ <view class="list-section">
+ <view class="section-header">
+ <text class="table-title">{{ tableTitle }}</text>
+ </view>
+ <view v-if="tableData.length > 0">
+ <view v-for="(item, index) in tableData" :key="index" class="card-item">
+ <view class="card-header">
+ <view class="header-main">
+ <text class="product-name">{{ item.productName }}</text>
+ <text class="sub-title">{{ item.model }}</text>
+ </view>
+ </view>
+ <up-divider />
+ <view class="card-body">
+ <view class="row"><text class="l">鍗曚綅</text><text class="r">{{ item.unit }}</text></view>
+ <view class="row" v-if="searchForm.reportType !== 'inout'"><text class="l">鍏ュ簱鏃堕棿</text><text class="r">{{ item.createTime }}</text></view>
+ <view class="row" v-if="searchForm.reportType !== 'inout'"><text class="l">鍏ュ簱鎵规</text><text class="r">{{ item.inboundBatches }}</text></view>
+ <view class="row"><text class="l">鍏ュ簱鏁伴噺</text><text class="r">{{ item.totalStockIn ?? item.stockInNum }}</text></view>
+ <view class="row" v-if="searchForm.reportType === 'inout'"><text class="l">鍑哄簱鏁伴噺</text><text class="r">{{ item.totalStockOut }}</text></view>
+ <view class="row"><text class="l">鐜板湪搴撳瓨</text><text class="r highlight">{{ item.currentStock }}</text></view>
+ <view class="row" v-if="item.createBy"><text class="l">鍏ュ簱浜�</text><text class="r">{{ item.createBy }}</text></view>
+ </view>
+ </view>
+ <view class="load-more-wrap">
+ <u-loadmore :status="loadStatus" @loadmore="loadMore" />
+ </view>
+ </view>
+ <view v-else class="no-data">鏆傛棤鏁版嵁</view>
+ </view>
+ <up-popup :show="showDatePicker" mode="bottom" @close="showDatePicker = false">
+ <up-datetime-picker
+ v-model="dateValue"
+ :mode="datePickerMode"
+ @confirm="onDateConfirm"
+ @cancel="showDatePicker = false"
+ />
+ </up-popup>
+ </view>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs, computed, watch } from "vue";
+import dayjs from "dayjs";
+import PageHeader from "@/components/PageHeader.vue";
+import { formatDateToYMD } from "@/utils/ruoyi";
+import { onShow, onReachBottom } from "@dcloudio/uni-app";
+import { getConsumablesInReportList, getConsumablesInInAndOutReportList } from "@/api/consumablesLogistics/consumablesIn.js";
+
+const reportTypes = [
+ { label: "鏃ユ姤", value: "daily" },
+ { label: "鏈堟姤", value: "monthly" },
+ { label: "杩涘嚭瀛樻姤琛�", value: "inout" },
+];
+const tableData = ref([]);
+const showDatePicker = ref(false);
+const dateValue = ref(Date.now());
+const datePickerTarget = ref("");
+const loadStatus = ref("loadmore");
+const page = reactive({ current: 1, size: 20 });
+const data = reactive({
+ searchForm: {
+ reportType: "daily",
+ singleDate: "",
+ startMonth: "",
+ endMonth: "",
+ startDate: "",
+ endDate: "",
+ },
+});
+const { searchForm } = toRefs(data);
+
+const datePickerMode = computed(() => {
+ if (datePickerTarget.value === "startMonth" || datePickerTarget.value === "endMonth") return "month";
+ return "date";
+});
+
+const tableTitle = computed(() => {
+ const m = { daily: "鏃ユ姤璇︾粏鏁版嵁", monthly: "鏈堟姤璇︾粏鏁版嵁", inout: "杩涘嚭瀛樻姤琛ㄨ缁嗘暟鎹�" };
+ return m[searchForm.value.reportType] || "鎶ヨ〃鏁版嵁";
+});
+
+const getQueryParams = () => {
+ const p = {
+ reportType: searchForm.value.reportType,
+ current: page.current,
+ size: page.size,
+ };
+ if (searchForm.value.reportType === "daily") {
+ p.reportDate = searchForm.value.singleDate;
+ } else if (searchForm.value.reportType === "monthly") {
+ p.startMonth = searchForm.value.startMonth;
+ p.endMonth = searchForm.value.endMonth;
+ } else if (searchForm.value.reportType === "monthly") {
+ p.startMonth = searchForm.value.startMonth;
+ p.endMonth = searchForm.value.endMonth;
+ } else {
+ p.startDate = searchForm.value.startDate;
+ p.endDate = searchForm.value.endDate;
+ }
+ return p;
+};
+
+const getList = () => {
+ const isFirstPage = page.current === 1;
+ if (isFirstPage) {
+ uni.showLoading({ title: "鏌ヨ涓�...", mask: true });
+ }
+ const params = getQueryParams();
+ const isInout = searchForm.value.reportType === "inout";
+ const api = isInout ? getConsumablesInInAndOutReportList : getConsumablesInReportList;
+ api(params)
+ .then((res) => {
+ uni.hideLoading();
+ const records = res.data?.records || [];
+ const total = res.data?.total || records.length;
+ if (isFirstPage) {
+ tableData.value = records;
+ } else {
+ tableData.value = [...tableData.value, ...records];
+ }
+ if (tableData.value.length >= total || total === 0) {
+ loadStatus.value = "nomore";
+ } else {
+ loadStatus.value = "loadmore";
+ }
+ })
+ .catch(() => {
+ uni.hideLoading();
+ loadStatus.value = "error";
+ if (isFirstPage) {
+ uni.showToast({ title: "鏌ヨ澶辫触", icon: "none" });
+ }
+ });
+};
+
+const handleQuery = () => {
+ page.current = 1;
+ loadStatus.value = "loadmore";
+ getList();
+};
+
+const loadMore = () => {
+ if (loadStatus.value === "nomore" || loadStatus.value === "loading") return;
+ loadStatus.value = "loading";
+ page.current++;
+ getList();
+};
+
+const openDatePicker = (target) => {
+ datePickerTarget.value = target;
+ let val = "";
+ if (target === "single") val = searchForm.value.singleDate;
+ else if (target === "startMonth") val = searchForm.value.startMonth;
+ else if (target === "endMonth") val = searchForm.value.endMonth;
+ dateValue.value = val ? new Date(val).getTime() : Date.now();
+ showDatePicker.value = true;
+};
+
+const onDateConfirm = (e) => {
+ const isMonth = datePickerTarget.value === "startMonth" || datePickerTarget.value === "endMonth";
+ const str = isMonth ? dayjs(e.value).format("YYYY-MM") : formatDateToYMD(e.value);
+ if (datePickerTarget.value === "single") searchForm.value.singleDate = str;
+ else if (datePickerTarget.value === "startMonth") searchForm.value.startMonth = str;
+ else if (datePickerTarget.value === "endMonth") searchForm.value.endMonth = str;
+ showDatePicker.value = false;
+ handleQuery();
+};
+
+const initDefaultDates = () => {
+ const today = dayjs();
+ if (!searchForm.value.singleDate) {
+ searchForm.value.singleDate = today.format("YYYY-MM-DD");
+ }
+ if (!searchForm.value.startMonth || !searchForm.value.endMonth) {
+ const startOfMonth = today.startOf("month").format("YYYY-MM-DD");
+ const endOfMonth = today.endOf("month").format("YYYY-MM-DD");
+ searchForm.value.startMonth = startOfMonth;
+ searchForm.value.endMonth = endOfMonth;
+ }
+ if (!searchForm.value.startDate || !searchForm.value.endDate) {
+ searchForm.value.endDate = today.format("YYYY-MM-DD");
+ searchForm.value.startDate = today.subtract(6, "day").format("YYYY-MM-DD");
+ }
+};
+
+watch(
+ () => searchForm.value.reportType,
+ () => {
+ handleQuery();
+ }
+);
+
+onShow(() => {
+ initDefaultDates();
+ handleQuery();
+});
+
+onReachBottom(() => loadMore());
+
+const goBack = () => uni.navigateBack();
+</script>
+
+<style lang="scss" scoped>
+.report-page { min-height: 100vh; background: #f5f5f5; padding-bottom: 40rpx; }
+.tabs-wrap { display: flex; background: #fff; padding: 24rpx; gap: 24rpx; }
+.tab-item { flex: 1; text-align: center; padding: 20rpx; border-radius: 12rpx; background: #f0f0f0; font-size: 28rpx; color: #666; }
+.tab-item.active { background: #2979ff; color: #fff; }
+.search-section { background: #fff; margin: 24rpx; padding: 24rpx; border-radius: 16rpx; }
+.search-row { display: flex; align-items: center; margin-bottom: 0; flex-wrap: wrap; }
+.search-row .label { width: 140rpx; font-size: 26rpx; color: #666; }
+.search-row .label.end { margin-left: 24rpx; }
+.date-picker { flex: 1; min-width: 200rpx; padding: 20rpx; background: #f5f5f5; border-radius: 12rpx; font-size: 28rpx; }
+.btn-row { display: flex; gap: 24rpx; margin-top: 24rpx; }
+.btn-query { flex: 1; text-align: center; padding: 24rpx; background: #2979ff; color: #fff; border-radius: 12rpx; }
+.btn-reset { flex: 1; text-align: center; padding: 24rpx; background: #e0e0e0; border-radius: 12rpx; }
+.list-section { margin: 24rpx; }
+.section-header { margin-bottom: 16rpx; padding: 16rpx 20rpx; }
+.table-title { font-size: 30rpx; font-weight: 500; color: #333; }
+.card-item { background: #fff; border-radius: 16rpx; padding: 20rpx 24rpx; margin-bottom: 20rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
+.card-header { padding: 4rpx 0 12rpx; }
+.header-main { display: flex; flex-direction: column; gap: 6rpx; }
+.product-name { font-size: 30rpx; font-weight: 500; color: #333; }
+.sub-title { font-size: 24rpx; color: #999; }
+.card-body .row { display: flex; justify-content: space-between; padding: 6rpx 0; font-size: 26rpx; }
+.card-body .l { color: #666; } .card-body .r { color: #333; } .card-body .r.highlight { color: #2979ff; font-weight: 500; }
+.no-data { text-align: center; padding: 60rpx 0; color: #999; font-size: 28rpx; }
+.load-more-wrap { padding: 24rpx 0 8rpx; }
+</style>
--
Gitblit v1.9.3