<template>
|
<view class="report-entry-page">
|
<PageHeader title="生产报工"
|
@back="goBack" />
|
|
<view class="scan-section">
|
<view class="scan-card"
|
@click="startScan">
|
<up-icon name="scan"
|
size="28"
|
color="#2979ff" />
|
<view class="scan-text-wrap">
|
<text class="scan-title">扫码报工</text>
|
</view>
|
<up-icon name="arrow-right"
|
size="18"
|
color="#c0c4cc" />
|
</view>
|
</view>
|
|
<scroll-view v-if="tableData.length > 0"
|
scroll-y
|
class="list-body"
|
@scrolltolower="loadMore">
|
<view v-for="(item, index) in tableData"
|
:key="item.id || index"
|
class="ledger-item"
|
@click="onCardClick(item)">
|
<view class="item-header">
|
<view class="item-left">
|
<view class="document-icon">
|
<up-icon name="file-text"
|
size="16"
|
color="#ffffff" />
|
</view>
|
<text class="item-id">{{ item.workOrderNo || "-" }}</text>
|
</view>
|
<view class="item-right operation-header-right">
|
<view class="operation-pill">
|
<text class="operation-pill-text">{{ operationNameOf(item) }}</text>
|
</view>
|
<view v-if="item.endOrder"
|
class="end-pill">
|
<text class="end-pill-text">已结束</text>
|
</view>
|
</view>
|
</view>
|
<up-divider />
|
<view class="item-details">
|
<view class="detail-row">
|
<text class="detail-label">生产订单号</text>
|
<text class="detail-value">{{ item.npsNo || "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">产品名称</text>
|
<text class="detail-value">{{ item.productName || "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">规格</text>
|
<text class="detail-value">{{ item.model || "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">单位</text>
|
<text class="detail-value">{{ item.unit || "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">需求数量</text>
|
<text class="detail-value">{{ item.planQuantity ?? "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">完成数量</text>
|
<text class="detail-value">{{ item.completeQuantity ?? "-" }}</text>
|
</view>
|
</view>
|
</view>
|
<up-loadmore :status="loadStatus" />
|
</scroll-view>
|
|
<view v-else-if="!loading"
|
class="no-data">
|
<up-empty mode="data"
|
text="暂无工单数据" />
|
</view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, reactive } from "vue";
|
import { onShow } from "@dcloudio/uni-app";
|
import PageHeader from "@/components/PageHeader.vue";
|
import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js";
|
import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting";
|
import modal from "@/plugins/modal";
|
import useUserStore from "@/store/modules/user";
|
|
const userStore = useUserStore();
|
|
const loading = ref(false);
|
const tableData = ref([]);
|
const loadStatus = ref("loadmore");
|
|
const page = reactive({
|
current: 1,
|
size: 10,
|
total: 0,
|
});
|
|
const goBack = () => {
|
uni.navigateBack();
|
};
|
|
const operationNameOf = item =>
|
item?.operationName || item?.processName || "-";
|
|
const reportPermissionMessage = row => {
|
if (row.endOrder) return "该订单已结束,无法报工";
|
const pq = Number(row.planQuantity);
|
if (Number.isFinite(pq) && pq <= 0) return "待生产数量为0,无法报工";
|
// if (row.userIds) {
|
// try {
|
// const userIds =
|
// typeof row.userIds === "string" ? JSON.parse(row.userIds) : row.userIds;
|
// if (
|
// Array.isArray(userIds) &&
|
// userIds.length > 0 &&
|
// !userIds.some(id => String(id) === String(userStore.id))
|
// ) {
|
// return "您不在该工单的指定报工人范围内";
|
// }
|
// } catch {
|
// return "工单报工权限校验失败";
|
// }
|
// }
|
return "";
|
};
|
|
const navigateToReport = orderRowStr => {
|
uni.navigateTo({
|
url: `/pages/productionManagement/productionReport/index?orderRow=${encodeURIComponent(orderRowStr)}`,
|
});
|
};
|
|
const onCardClick = row => {
|
const msg = reportPermissionMessage(row);
|
if (msg) {
|
uni.showToast({ title: msg, icon: "none" });
|
return;
|
}
|
navigateToReport(JSON.stringify(row));
|
};
|
|
const handleQuery = () => {
|
page.current = 1;
|
tableData.value = [];
|
getList();
|
};
|
|
const getList = () => {
|
if (loading.value) return;
|
loading.value = true;
|
const params = { ...page };
|
productWorkOrderPage(params)
|
.then(res => {
|
loading.value = false;
|
const records = res.data?.records || [];
|
tableData.value =
|
page.current === 1 ? records : [...tableData.value, ...records];
|
page.total = res.data?.total ?? 0;
|
loadStatus.value =
|
tableData.value.length >= page.total ? "nomore" : "loadmore";
|
})
|
.catch(() => {
|
loading.value = false;
|
uni.showToast({ title: "加载失败", icon: "none" });
|
});
|
};
|
|
const loadMore = () => {
|
if (loadStatus.value === "nomore" || loading.value) return;
|
page.current++;
|
getList();
|
};
|
|
const startScan = () => {
|
uni.scanCode({
|
success: async res => {
|
const scanResult = res.result;
|
let orderRow = "";
|
|
const isNumericId = /^\d+$/.test(String(scanResult).trim());
|
|
if (isNumericId) {
|
const workOrderId = String(scanResult).trim();
|
modal.loading("正在获取工单信息...");
|
try {
|
const workRes = await getProductWorkOrderById({ id: workOrderId });
|
modal.closeLoading();
|
if (workRes.code === 200 && workRes.data) {
|
const workData = workRes.data;
|
if (workData.endOrder === true) {
|
modal.msgError("该订单已结束,无法报工");
|
return;
|
}
|
orderRow = JSON.stringify(workData);
|
} else {
|
modal.msgError("未找到对应的工单信息");
|
return;
|
}
|
} catch (error) {
|
modal.closeLoading();
|
modal.msgError(
|
"获取工单信息失败: " + (error?.message || "未知错误")
|
);
|
return;
|
}
|
} else {
|
try {
|
const orderRowStart = scanResult.indexOf("orderRow={");
|
if (orderRowStart !== -1) {
|
orderRow = scanResult.substring(orderRowStart + 9);
|
} else {
|
orderRow = scanResult;
|
}
|
JSON.parse(orderRow);
|
} catch {
|
try {
|
const parsed = JSON.parse(scanResult);
|
orderRow = JSON.stringify(parsed);
|
} catch {
|
modal.msgError("订单解析失败,请检查二维码格式");
|
return;
|
}
|
}
|
}
|
|
navigateToReport(orderRow);
|
},
|
fail: () => {
|
uni.showToast({ title: "扫码失败", icon: "none" });
|
},
|
});
|
};
|
|
onShow(() => {
|
handleQuery();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
@import "@/styles/sales-common.scss";
|
|
.report-entry-page {
|
min-height: 100vh;
|
background: #f8f9fa;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.scan-section {
|
padding: 12px 16px 8px;
|
}
|
|
.scan-card {
|
display: flex;
|
align-items: center;
|
gap: 12px;
|
background: #fff;
|
border-radius: 12px;
|
padding: 16px;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
}
|
|
.scan-text-wrap {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
gap: 4px;
|
}
|
|
.scan-title {
|
font-size: 16px;
|
font-weight: 600;
|
color: #303133;
|
}
|
|
.scan-desc {
|
font-size: 12px;
|
color: #909399;
|
}
|
|
.list-body {
|
flex: 1;
|
height: 0;
|
padding: 12px 16px 20px;
|
box-sizing: border-box;
|
}
|
|
.operation-header-right {
|
flex: 1;
|
min-width: 0;
|
justify-content: flex-end;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 8px;
|
}
|
|
.operation-pill {
|
max-width: 58%;
|
min-width: 0;
|
padding: 5px 12px;
|
border-radius: 20px;
|
background: #e8f1ff;
|
flex-shrink: 0;
|
}
|
|
.operation-pill-text {
|
font-size: 12px;
|
line-height: 1.35;
|
color: #2979ff;
|
font-weight: 500;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
display: block;
|
}
|
|
.end-pill {
|
padding: 5px 10px;
|
border-radius: 20px;
|
background: #fef0f0;
|
flex-shrink: 0;
|
}
|
|
.end-pill-text {
|
font-size: 12px;
|
line-height: 1.35;
|
color: #f56c6c;
|
font-weight: 500;
|
}
|
|
.no-data {
|
flex: 1;
|
padding-top: 80px;
|
}
|
</style>
|