From f2770f03e7251b32eb576113c522bfbe96e5e385 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 16 六月 2026 13:46:16 +0800
Subject: [PATCH] 君歌app 1.依照web端功能修改
---
src/pages/productionDesign/processManagement/index.vue | 68 +
src/api/productionManagement/workOrder.js | 9
src/api/personnelManagement/staffOnJob.js | 63 ++
src/pages/works.vue | 103 ---
src/pages/productionManagement/productionReport/index.vue | 13
src/api/productionManagement/productionProcess.js | 104 ++++
src/pages/productionManagement/productionReport/components/filesDia.vue | 262 ++++++++++
src/config.js | 4
src/pages/productionManagement/workOrder/index.vue | 186 ++++---
src/pages/productionManagement/productionReport/components/MaterialDialog.vue | 437 +++++++++++++++++
src/pages/productionDesign/processManagement/edit.vue | 231 +++++---
11 files changed, 1,191 insertions(+), 289 deletions(-)
diff --git a/src/api/personnelManagement/staffOnJob.js b/src/api/personnelManagement/staffOnJob.js
new file mode 100644
index 0000000..7a14391
--- /dev/null
+++ b/src/api/personnelManagement/staffOnJob.js
@@ -0,0 +1,63 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鍦ㄨ亴鍛樺伐鍙拌处
+export function staffOnJobListPage(query) {
+ return request({
+ url: '/staff/staffOnJob/listPage',
+ method: 'get',
+ params: query,
+ })
+}
+// 鏌ヨ鍛樺伐鍏ヨ亴淇℃伅
+export function staffOnJobInfo(id, query) {
+ return request({
+ url: '/staff/staffOnJob/' + id,
+ method: 'get',
+ params: query,
+ })
+}
+
+// 鏌ヨ鍛樺伐鍏ヨ亴淇℃伅
+export function getStaffOnJobInfoByUserName(query) {
+ return request({
+ url: '/staff/staffOnJob/byUserName',
+ method: 'get',
+ params: query,
+ })
+}
+
+// 鏂板鍛樺伐
+export function createStaffOnJob(params) {
+ return request({
+ url: "/staff/staffOnJob",
+ method: "post",
+ data: params,
+ });
+}
+
+// 淇敼鍛樺伐
+export function updateStaffOnJob(id, params) {
+ return request({
+ url: "/staff/staffOnJob/" + id,
+ method: "put",
+ data: params,
+ });
+}
+
+// 鍒犻櫎鍛樺伐
+export function batchDeleteStaffOnJobs(query) {
+ return request({
+ url: "/staff/staffOnJob/del",
+ method: "delete",
+ data: query,
+ });
+}
+
+// 缁鍚堝悓
+export function renewContract(id, params) {
+ return request({
+ url: "/staff/staffOnJob/renewContract/" + id,
+ method: "post",
+ data: params,
+ });
+}
diff --git a/src/api/productionManagement/productionProcess.js b/src/api/productionManagement/productionProcess.js
new file mode 100644
index 0000000..783f584
--- /dev/null
+++ b/src/api/productionManagement/productionProcess.js
@@ -0,0 +1,104 @@
+// 宸ュ簭椤甸潰鎺ュ彛
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ
+export function listPage(query) {
+ return request({
+ url: "/technologyOperation/listPage",
+ method: "get",
+ params: query,
+ });
+}
+
+export function processList(query) {
+ return request({
+ url: "/technologyOperation/listPage",
+ method: "get",
+ params: query,
+ });
+}
+
+// 宸ュ簭鏌ヨ
+export function list(query) {
+ return request({
+ url: "/technologyOperation/listPage",
+ method: "get",
+ params: query,
+ });
+}
+export function add(data) {
+ return request({
+ url: "/technologyOperation/add",
+ method: "post",
+ data: data,
+ });
+}
+
+export function del(data) {
+ return request({
+ url: "/technologyOperation/batchDelete",
+ method: "delete",
+ data: data,
+ });
+}
+
+export function update(data) {
+ return request({
+ url: "/technologyOperation/update",
+ method: "put",
+ data: data,
+ });
+}
+
+// 瀵煎叆鏁版嵁
+export function importData(data) {
+ return request({
+ url: "/technologyOperation/importData",
+ method: "post",
+ data: data,
+ });
+}
+
+// 涓嬭浇妯℃澘
+export function downloadTemplate() {
+ return request({
+ url: "/technologyOperation/downloadTemplate",
+ method: "post",
+ responseType: "blob",
+ });
+}
+
+// 鑾峰彇宸ュ簭鍙傛暟鍒楄〃
+export function getProcessParamList(params) {
+ return request({
+ url: `/technologyOperationParam/list`,
+ method: "get",
+ params,
+ });
+}
+
+// 娣诲姞宸ュ簭鍙傛暟
+export function addProcessParam(data) {
+ return request({
+ url: "/technologyOperationParam/",
+ method: "post",
+ data: data,
+ });
+}
+
+// 缂栬緫宸ュ簭鍙傛暟
+export function editProcessParam(data) {
+ return request({
+ url: "/technologyOperationParam/",
+ method: "post",
+ data: data,
+ });
+}
+
+// 鍒犻櫎宸ュ簭鍙傛暟
+export function deleteProcessParam(id) {
+ return request({
+ url: `/technologyOperationParam/batchDelete/${id}`,
+ method: "delete",
+ });
+}
diff --git a/src/api/productionManagement/workOrder.js b/src/api/productionManagement/workOrder.js
index d3e0033..33ab462 100644
--- a/src/api/productionManagement/workOrder.js
+++ b/src/api/productionManagement/workOrder.js
@@ -42,6 +42,15 @@
});
}
+// 寮�濮嬫姤宸�
+export function startWork(data) {
+ return request({
+ url: "/productionProductMain/startWork",
+ method: "post",
+ data: data,
+ });
+}
+
// 鑾峰彇宸ュ簭缁熻鏁版嵁
export function getOperationStatistics(query) {
return request({
diff --git a/src/config.js b/src/config.js
index 27244b3..e2f8ff4 100644
--- a/src/config.js
+++ b/src/config.js
@@ -1,7 +1,7 @@
// 搴旂敤鍏ㄥ眬閰嶇疆
const config = {
- baseUrl: "http://1.15.17.182:9048",
- fileUrl: "http://1.15.17.182:9049",
+ baseUrl: "http://1.15.17.182:9098",
+ fileUrl: "http://1.15.17.182:9097",
// 搴旂敤淇℃伅
appInfo: {
// 搴旂敤鍚嶇О
diff --git a/src/pages/productionDesign/processManagement/edit.vue b/src/pages/productionDesign/processManagement/edit.vue
index 425be43..c3eaac4 100644
--- a/src/pages/productionDesign/processManagement/edit.vue
+++ b/src/pages/productionDesign/processManagement/edit.vue
@@ -6,36 +6,59 @@
:model="form"
:rules="rules"
:errorType="['none']"
- label-width="110">
- <up-form-item label="宸ュ簭缂栫爜"
- prop="no">
- <up-input v-model="form.no"
- placeholder="璇疯緭鍏ュ伐搴忕紪鐮�"
- clearable />
- </up-form-item>
- <up-form-item label="宸ュ簭鍚嶇О"
+ label-width="130">
+ <up-form-item label="閮ㄤ欢"
prop="name"
required>
<up-input v-model="form.name"
- placeholder="璇疯緭鍏ュ伐搴忓悕绉�"
+ placeholder="璇疯緭鍏ラ儴浠�"
clearable />
</up-form-item>
- <up-form-item label="宸ヨ祫瀹氶"
+ <up-form-item label="宸ュ簭缂栧彿"
+ prop="no">
+ <up-input v-model="form.no"
+ placeholder="璇疯緭鍏ュ伐搴忕紪鍙�"
+ clearable />
+ </up-form-item>
+ <up-form-item label="宸ュ簭绫诲瀷"
+ prop="processType"
+ required>
+ <up-input v-model="processTypeText"
+ placeholder="璇烽�夋嫨宸ュ簭绫诲瀷"
+ readonly
+ @click="showProcessTypeSheet = true" />
+ <template #right>
+ <up-icon name="arrow-right"
+ @click="showProcessTypeSheet = true"></up-icon>
+ </template>
+ </up-form-item>
+ <up-form-item label="璁″垝宸ユ椂(灏忔椂)"
prop="salaryQuota">
<up-input v-model="form.salaryQuota"
type="number"
- placeholder="璇疯緭鍏ュ伐璧勫畾棰�"
+ placeholder="璇疯緭鍏ヨ鍒掑伐鏃�"
clearable />
</up-form-item>
- <up-form-item label="璁¤垂绫诲瀷"
- prop="type">
- <up-input v-model="typeText"
- placeholder="璇烽�夋嫨璁¤垂绫诲瀷"
+ <up-form-item label="璁″垝浜哄憳"
+ prop="planPerson">
+ <up-input v-model="planPersonText"
+ placeholder="璇烽�夋嫨璁″垝浜哄憳"
readonly
- @click="showTypeSheet = true" />
+ @click="showPlanPersonSheet = true" />
<template #right>
<up-icon name="arrow-right"
- @click="showTypeSheet = true"></up-icon>
+ @click="showPlanPersonSheet = true"></up-icon>
+ </template>
+ </up-form-item>
+ <up-form-item label="璁″垝鎵ц浜哄憳"
+ prop="executor">
+ <up-input v-model="executorText"
+ placeholder="璇烽�夋嫨璁″垝鎵ц浜哄憳"
+ readonly
+ @click="showExecutorSheet = true" />
+ <template #right>
+ <up-icon name="arrow-right"
+ @click="showExecutorSheet = true"></up-icon>
</template>
</up-form-item>
<up-form-item label="鏄惁璐ㄦ"
@@ -44,27 +67,22 @@
<up-switch v-model="form.isQuality" />
</view>
</up-form-item>
- <up-form-item label="鏄惁鐢熶骇"
- prop="isProduction">
+ <up-form-item label="鏄惁鍏ュ簱"
+ prop="inbound">
<view style="display: flex; justify-content: flex-end; width: 100%;">
- <up-switch v-model="form.isProduction" />
+ <up-switch v-model="form.inbound" />
</view>
</up-form-item>
- <up-form-item label="鍏宠仈璁惧"
- prop="deviceLedgerId">
- <up-input v-model="deviceText"
- placeholder="璇烽�夋嫨鍏宠仈璁惧"
- readonly
- @click="showDeviceSheet = true" />
- <template #right>
- <up-icon name="arrow-right"
- @click="showDeviceSheet = true"></up-icon>
- </template>
+ <up-form-item label="鏄惁鎶ュ伐"
+ prop="reportWork">
+ <view style="display: flex; justify-content: flex-end; width: 100%;">
+ <up-switch v-model="form.reportWork" />
+ </view>
</up-form-item>
- <up-form-item label="宸ュ簭鎻忚堪"
+ <up-form-item label="澶囨敞"
prop="remark">
<up-textarea v-model="form.remark"
- placeholder="璇疯緭鍏ュ伐搴忔弿杩�"
+ placeholder="璇疯緭鍏ュ娉�"
autoHeight />
</up-form-item>
</up-form>
@@ -72,18 +90,24 @@
:confirmText="processId ? '淇濆瓨' : '鏂板'"
@cancel="goBack"
@confirm="handleSubmit" />
- <!-- 璁¤垂绫诲瀷閫夋嫨 -->
- <up-action-sheet :show="showTypeSheet"
- title="閫夋嫨璁¤垂绫诲瀷"
- :actions="typeActions"
- @select="onSelectType"
- @close="showTypeSheet = false" />
- <!-- 璁惧閫夋嫨 -->
- <up-action-sheet :show="showDeviceSheet"
- title="閫夋嫨鍏宠仈璁惧"
- :actions="deviceActions"
- @select="onSelectDevice"
- @close="showDeviceSheet = false" />
+ <!-- 宸ュ簭绫诲瀷閫夋嫨 -->
+ <up-action-sheet :show="showProcessTypeSheet"
+ title="閫夋嫨宸ュ簭绫诲瀷"
+ :actions="processTypeActions"
+ @select="onSelectProcessType"
+ @close="showProcessTypeSheet = false" />
+ <!-- 璁″垝浜哄憳閫夋嫨 -->
+ <up-action-sheet :show="showPlanPersonSheet"
+ title="閫夋嫨璁″垝浜哄憳"
+ :actions="employeeActions"
+ @select="onSelectPlanPerson"
+ @close="showPlanPersonSheet = false" />
+ <!-- 璁″垝鎵ц浜哄憳閫夋嫨 -->
+ <up-action-sheet :show="showExecutorSheet"
+ title="閫夋嫨璁″垝鎵ц浜哄憳"
+ :actions="employeeActions"
+ @select="onSelectExecutor"
+ @close="showExecutorSheet = false" />
</view>
</template>
@@ -91,35 +115,49 @@
import { reactive, ref, computed, onMounted } from "vue";
import { onLoad, onReady } from "@dcloudio/uni-app";
import FooterButtons from "@/components/FooterButtons.vue";
- import {
- add,
- update,
- getDeviceLedger,
- } from "@/api/productionManagement/processManagement";
+ import { add, update } from "@/api/productionManagement/processManagement";
+ import { staffOnJobListPage } from "@/api/personnelManagement/onboarding";
const formRef = ref(null);
const loading = ref(false);
const processId = ref(null);
const pageTitle = computed(() => (processId.value ? "缂栬緫宸ュ簭" : "鏂板宸ュ簭"));
+ const processTypeOptions = [
+ "鏈哄姞宸�",
+ "鍒澘鍐疯姱鍒朵綔",
+ "绠¤矾缁勫",
+ "缃愪綋杩炴帴鍙婅皟璇�",
+ "娴嬭瘯鎵撳帇",
+ "鍏朵粬",
+ ];
+
+ const employeeList = ref([]);
+
const form = ref({
no: "",
name: "",
+ processType: "",
salaryQuota: "",
+ planPerson: null,
+ executor: null,
isQuality: false,
- isProduction: false,
+ inbound: false,
+ reportWork: false,
remark: "",
- deviceLedgerId: null,
- type: 0,
});
const rules = {
- name: [{ required: true, message: "璇疯緭鍏ュ伐搴忓悕绉�" }],
+ name: [
+ { required: true, message: "璇疯緭鍏ラ儴浠�" },
+ { max: 100, message: "鏈�澶�100涓瓧绗�" },
+ ],
+ processType: [{ required: true, message: "璇烽�夋嫨宸ュ簭绫诲瀷" }],
salaryQuota: [
{
validator: (rule, value, callback) => {
if (value !== "" && value !== null && (isNaN(value) || value < 0)) {
- callback(new Error("宸ヨ祫瀹氶蹇呴』鏄潪璐熸暟瀛�"));
+ callback(new Error("璁″垝宸ユ椂蹇呴』鏄潪璐熸暟瀛�"));
} else {
callback();
}
@@ -128,46 +166,60 @@
],
};
- const showTypeSheet = ref(false);
- const typeActions = [
- { name: "璁℃椂", value: 0 },
- { name: "璁′欢", value: 1 },
- ];
- const typeText = computed(() => {
- const action = typeActions.find(a => a.value === form.value.type);
- return action ? action.name : "";
- });
+ const showProcessTypeSheet = ref(false);
+ const processTypeActions = processTypeOptions.map(item => ({ name: item, value: item }));
+ const processTypeText = ref("");
- const showDeviceSheet = ref(false);
- const deviceActions = ref([]);
- const deviceText = ref("");
+ const showPlanPersonSheet = ref(false);
+ const showExecutorSheet = ref(false);
+ const planPersonText = ref("");
+ const executorText = ref("");
- const onSelectType = e => {
- form.value.type = e.value;
- showTypeSheet.value = false;
+ const employeeActions = computed(() =>
+ employeeList.value.map(item => ({
+ name: item.staffName,
+ id: item.id,
+ }))
+ );
+
+ const onSelectProcessType = e => {
+ form.value.processType = e.value;
+ processTypeText.value = e.name;
+ showProcessTypeSheet.value = false;
};
- const onSelectDevice = e => {
- form.value.deviceLedgerId = e.id;
- deviceText.value = e.name;
- showDeviceSheet.value = false;
+ const onSelectPlanPerson = e => {
+ form.value.planPerson = e.id;
+ planPersonText.value = e.name;
+ showPlanPersonSheet.value = false;
};
- const loadDevices = async () => {
+ const onSelectExecutor = e => {
+ form.value.executor = e.id;
+ executorText.value = e.name;
+ showExecutorSheet.value = false;
+ };
+
+ const loadEmployees = async () => {
try {
- const { data } = await getDeviceLedger();
- deviceActions.value = (data || []).map(item => ({
- name: item.deviceName,
- id: item.id,
- }));
- if (form.value.deviceLedgerId) {
- const device = deviceActions.value.find(
- d => d.id === Number(form.value.deviceLedgerId)
- );
- if (device) deviceText.value = device.name;
- }
+ const res = await staffOnJobListPage({ current: -1, size: -1, staffState: 1 });
+ employeeList.value = res.data?.records || [];
} catch (error) {
- console.error("鍔犺浇璁惧澶辫触", error);
+ console.error("鍔犺浇鍛樺伐鍒楄〃澶辫触", error);
+ }
+ };
+
+ const resolveDisplayTexts = () => {
+ if (form.value.processType) {
+ processTypeText.value = form.value.processType;
+ }
+ if (form.value.planPerson) {
+ const emp = employeeList.value.find(e => e.id === form.value.planPerson);
+ if (emp) planPersonText.value = emp.staffName;
+ }
+ if (form.value.executor) {
+ const emp = employeeList.value.find(e => e.id === form.value.executor);
+ if (emp) executorText.value = emp.staffName;
}
};
@@ -210,10 +262,9 @@
const item = JSON.parse(decodeURIComponent(option.item));
processId.value = item.id;
Object.assign(form.value, item);
- // 澶勭悊绫诲瀷杞崲锛岀‘淇濇槸鏁板瓧
- form.value.type = Number(form.value.type);
form.value.isQuality = !!form.value.isQuality;
- form.value.isProduction = !!form.value.isProduction;
+ form.value.inbound = !!form.value.inbound;
+ form.value.reportWork = !!form.value.reportWork;
}
});
@@ -222,7 +273,7 @@
});
onMounted(() => {
- loadDevices();
+ loadEmployees().then(() => resolveDisplayTexts());
});
</script>
diff --git a/src/pages/productionDesign/processManagement/index.vue b/src/pages/productionDesign/processManagement/index.vue
index 6ca2f76..9fd6d5d 100644
--- a/src/pages/productionDesign/processManagement/index.vue
+++ b/src/pages/productionDesign/processManagement/index.vue
@@ -7,7 +7,7 @@
<view class="search-input">
<up-input class="search-text"
v-model="queryParams.name"
- placeholder="璇疯緭鍏ュ伐搴忓悕绉�"
+ placeholder="璇疯緭鍏ラ儴浠跺悕绉�"
clearable
@change="handleSearch" />
</view>
@@ -38,35 +38,38 @@
<up-divider></up-divider>
<view class="item-details">
<view class="detail-row">
+ <text class="detail-label">閮ㄤ欢绫诲瀷</text>
+ <text class="detail-value">{{ item.processType || "-" }}</text>
+ </view>
+ <view class="detail-row">
<text class="detail-label">鍏宠仈璁惧</text>
<text class="detail-value">{{ getDeviceName(item.deviceLedgerId) }}</text>
</view>
<view class="detail-row">
- <text class="detail-label">宸ヨ祫瀹氶</text>
- <text class="detail-value highlight">楼{{ item.salaryQuota || 0 }}</text>
+ <text class="detail-label">璁″垝宸ユ椂</text>
+ <text class="detail-value highlight">{{ item.salaryQuota || 0 }}灏忔椂</text>
</view>
<view class="detail-row">
- <text class="detail-label">宸ュ簭鐘舵��</text>
- <view class="detail-value">
- <up-tag :text="item.isQuality ? '璐ㄦ' : '闈炶川妫�'"
- :type="item.isQuality ? 'warning' : 'info'"
- size="mini"
- style="margin-left: 8rpx" />
- <up-tag :text="item.isProduction ? '鐢熶骇' : '涓嶇敓浜�'"
- :type="item.isProduction ? 'warning' : 'info'"
- size="mini"
- style="margin-left: 8rpx" />
- <up-tag v-if="item.type !== null && item.type !== undefined"
- :text="item.type == 0 ? '璁℃椂' : '璁′欢'"
- :type="item.type == 1 ? 'primary' : 'success'"
- size="mini"
- style="margin-left: 8rpx" />
- </view>
+ <text class="detail-label">璁″垝浜哄憳</text>
+ <text class="detail-value">{{ getEmployeeName(item.planPerson) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">璁″垝鎵ц浜哄憳</text>
+ <text class="detail-value">{{ getEmployeeName(item.executor) }}</text>
</view>
<view class="detail-row">
<text class="detail-label">澶囨敞</text>
<text class="detail-value">{{ item.remark || "-" }}</text>
</view>
+ </view>
+ <view class="status-tags">
+ <up-tag :text="item.isQuality ? '璐ㄦ' : '闈炶川妫�'"
+ :type="item.isQuality ? 'warning' : 'info'"
+ size="mini" />
+ <up-tag :text="item.isProduction ? '鐢熶骇' : '涓嶇敓浜�'"
+ :type="item.isProduction ? 'warning' : 'info'"
+ size="mini"
+ style="margin-left: 8rpx" />
</view>
<view class="action-buttons">
<up-button class="action-btn"
@@ -87,7 +90,7 @@
</view>
<view v-else
class="no-data">
- <text>鏆傛棤宸ュ簭鏁版嵁</text>
+ <text>鏆傛棤閮ㄤ欢鏁版嵁</text>
</view>
<view class="fab-button"
@click="goAdd">
@@ -106,12 +109,14 @@
del,
getDeviceLedger,
} from "@/api/productionManagement/processManagement";
+ import { staffOnJobListPage } from "@/api/personnelManagement/onboarding";
const queryParams = reactive({
name: "",
});
const list = ref([]);
const deviceOptions = ref([]);
+ const employeeOptions = ref([]);
const pageStatus = ref("loadmore");
const page = reactive({
@@ -130,12 +135,27 @@
return device?.deviceName || "鏈叧鑱�";
};
+ const getEmployeeName = employeeId => {
+ if (!employeeId) return "鏈寚瀹�";
+ const emp = employeeOptions.value.find(item => item.id === Number(employeeId));
+ return emp?.staffName || "鏈寚瀹�";
+ };
+
const loadDevices = async () => {
try {
const { data } = await getDeviceLedger();
deviceOptions.value = data || [];
} catch (error) {
console.error("鍔犺浇璁惧鍒楄〃澶辫触", error);
+ }
+ };
+
+ const loadEmployees = async () => {
+ try {
+ const res = await staffOnJobListPage({ current: -1, size: -1, staffState: 1 });
+ employeeOptions.value = res.data?.records || [];
+ } catch (error) {
+ console.error("鍔犺浇鍛樺伐鍒楄〃澶辫触", error);
}
};
@@ -217,7 +237,7 @@
});
onShow(async () => {
- await loadDevices();
+ await Promise.all([loadDevices(), loadEmployees()]);
handleSearch();
});
</script>
@@ -232,6 +252,12 @@
font-size: 28rpx;
}
+ .status-tags {
+ display: flex;
+ align-items: center;
+ padding-bottom: 16rpx;
+ }
+
.action-buttons {
display: flex;
justify-content: flex-end;
diff --git a/src/pages/productionManagement/productionReport/components/MaterialDialog.vue b/src/pages/productionManagement/productionReport/components/MaterialDialog.vue
new file mode 100644
index 0000000..e9eddc9
--- /dev/null
+++ b/src/pages/productionManagement/productionReport/components/MaterialDialog.vue
@@ -0,0 +1,437 @@
+<template>
+ <view>
+ <!-- 涓荤墿鏂欏脊绐� -->
+ <view v-if="dialogVisible" class="material-overlay">
+ <view class="material-container">
+ <view class="material-header">
+ <text class="material-title">鐗╂枡</text>
+ <view class="close-btn" @click="dialogVisible = false">
+ <up-icon name="close" size="20" color="#666" />
+ </view>
+ </view>
+ <scroll-view class="material-body" scroll-y>
+ <view v-if="materialTableData.length === 0" class="empty-tip">
+ <text>鏆傛棤鐗╂枡鏁版嵁</text>
+ </view>
+ <view v-for="item in materialTableData" :key="item.id" class="material-card">
+ <view class="material-row">
+ <text class="mc-label">宸ュ簭鍚嶇О</text>
+ <text class="mc-value">{{ item.processName || '-' }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">鍘熸枡鍚嶇О</text>
+ <text class="mc-value">{{ item.materialName || '-' }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">鍘熸枡鍨嬪彿</text>
+ <text class="mc-value">{{ item.materialModel || '-' }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">璁¢噺鍗曚綅</text>
+ <text class="mc-value">{{ item.unit || '-' }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">绾胯竟浠撴暟閲�</text>
+ <text class="mc-value">{{ item.pickQty || 0 }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">琛ユ枡鏁伴噺</text>
+ <text class="mc-value">{{ item.supplementQty || 0 }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">瀹為檯鏁伴噺</text>
+ <view class="mc-value">
+ <up-input v-model="item.actualQty"
+ type="number"
+ placeholder="璇疯緭鍏ュ疄闄呮暟閲�"
+ clearable
+ style="width: 200rpx" />
+ </view>
+ </view>
+ <view class="material-actions">
+ <up-button size="small" type="primary" @click="openSupplementDialog(item)">琛ユ枡</up-button>
+ <up-button size="small" type="info" @click="openSupplementRecordDialog(item)">琛ユ枡璁板綍</up-button>
+ </view>
+ </view>
+ </scroll-view>
+ <view class="material-footer">
+ <up-button type="primary" :loading="pickSubmitting" @click="handleSubmitPick">棰嗙敤</up-button>
+ <up-button @click="dialogVisible = false">鍙栨秷</up-button>
+ </view>
+ </view>
+ </view>
+
+ <!-- 琛ユ枡寮圭獥 -->
+ <view v-if="supplementDialogVisible" class="material-overlay">
+ <view class="material-container supplement-container">
+ <view class="material-header">
+ <text class="material-title">琛ユ枡</text>
+ <view class="close-btn" @click="supplementDialogVisible = false">
+ <up-icon name="close" size="20" color="#666" />
+ </view>
+ </view>
+ <view class="material-body">
+ <up-form :model="supplementForm" ref="supplementFormRef" label-width="140">
+ <up-form-item label="琛ユ枡鏁伴噺" prop="supplementQty" required>
+ <up-input v-model="supplementForm.supplementQty"
+ type="number"
+ placeholder="璇疯緭鍏ヨˉ鏂欐暟閲�"
+ clearable />
+ </up-form-item>
+ <up-form-item label="琛ユ枡鍘熷洜" prop="supplementReason" required>
+ <up-textarea v-model="supplementForm.supplementReason"
+ placeholder="璇疯緭鍏ヨˉ鏂欏師鍥�"
+ :maxlength="200"
+ autoHeight />
+ </up-form-item>
+ </up-form>
+ </view>
+ <view class="material-footer">
+ <up-button type="primary" :loading="supplementSubmitting" @click="handleSubmitSupplement">纭畾</up-button>
+ <up-button @click="supplementDialogVisible = false">鍙栨秷</up-button>
+ </view>
+ </view>
+ </view>
+
+ <!-- 琛ユ枡璁板綍寮圭獥 -->
+ <view v-if="supplementRecordDialogVisible" class="material-overlay">
+ <view class="material-container supplement-record-container">
+ <view class="material-header">
+ <text class="material-title">琛ユ枡璁板綍</text>
+ <view class="close-btn" @click="supplementRecordDialogVisible = false">
+ <up-icon name="close" size="20" color="#666" />
+ </view>
+ </view>
+ <scroll-view class="material-body" scroll-y>
+ <view v-if="supplementRecordTableData.length === 0" class="empty-tip">
+ <text>鏆傛棤琛ユ枡璁板綍</text>
+ </view>
+ <view v-for="item in supplementRecordTableData" :key="item.id" class="record-card">
+ <view class="material-row">
+ <text class="mc-label">琛ユ枡鏁伴噺</text>
+ <text class="mc-value">{{ item.supplementQty }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">琛ユ枡鍘熷洜</text>
+ <text class="mc-value">{{ item.supplementReason }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">琛ユ枡浜�</text>
+ <text class="mc-value">{{ item.supplementUserName }}</text>
+ </view>
+ <view class="material-row">
+ <text class="mc-label">琛ユ枡鏃ユ湡</text>
+ <text class="mc-value">{{ item.supplementTime }}</text>
+ </view>
+ </view>
+ </scroll-view>
+ <view class="material-footer">
+ <up-button @click="supplementRecordDialogVisible = false">鍏抽棴</up-button>
+ </view>
+ </view>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { computed, nextTick, reactive, ref, watch } from "vue";
+ import {
+ listWorkOrderMaterialLedger,
+ addWorkOrderMaterialSupplement,
+ listWorkOrderMaterialSupplementRecord,
+ pickWorkOrderMaterial,
+ } from "@/api/productionManagement/workOrder.js";
+
+ const props = defineProps({
+ modelValue: {
+ type: Boolean,
+ default: false,
+ },
+ rowData: {
+ type: Object,
+ default: () => null,
+ },
+ });
+
+ const emit = defineEmits(["update:modelValue", "refresh"]);
+
+ const dialogVisible = computed({
+ get: () => props.modelValue,
+ set: val => emit("update:modelValue", val),
+ });
+
+ const materialTableLoading = ref(false);
+ const materialTableData = ref([]);
+ const currentMaterialRow = ref(null);
+ const currentMaterialOrderRow = ref(null);
+ const pickSubmitting = ref(false);
+
+ const supplementDialogVisible = ref(false);
+ const supplementSubmitting = ref(false);
+ const supplementFormRef = ref(null);
+ const supplementForm = reactive({
+ supplementQty: null,
+ supplementReason: "",
+ });
+
+ const supplementRecordDialogVisible = ref(false);
+ const supplementRecordLoading = ref(false);
+ const supplementRecordTableData = ref([]);
+
+ const loadMaterialTable = async row => {
+ if (!row?.id) return;
+ currentMaterialOrderRow.value = row;
+ materialTableLoading.value = true;
+ materialTableData.value = [];
+ try {
+ const res = await listWorkOrderMaterialLedger({
+ workOrderId: row.id,
+ processId: row.processId,
+ productProcessRouteItemId: row.productProcessRouteItemId,
+ });
+ materialTableData.value = res.data || [];
+ } catch (e) {
+ console.error("鑾峰彇鐗╂枡鍙拌处澶辫触", e);
+ uni.showToast({ title: "鑾峰彇鐗╂枡鍙拌处澶辫触", icon: "error" });
+ } finally {
+ materialTableLoading.value = false;
+ }
+ };
+
+ watch(
+ () => props.modelValue,
+ visible => {
+ if (visible && props.rowData) {
+ loadMaterialTable(props.rowData);
+ }
+ }
+ );
+
+ const resetSupplementForm = () => {
+ supplementForm.supplementQty = null;
+ supplementForm.supplementReason = "";
+ };
+
+ const openSupplementDialog = row => {
+ currentMaterialRow.value = row;
+ resetSupplementForm();
+ supplementDialogVisible.value = true;
+ };
+
+ const handleSubmitSupplement = () => {
+ if (!supplementForm.supplementQty) {
+ uni.showToast({ title: "璇疯緭鍏ヨˉ鏂欐暟閲�", icon: "none" });
+ return;
+ }
+ if (!supplementForm.supplementReason) {
+ uni.showToast({ title: "璇疯緭鍏ヨˉ鏂欏師鍥�", icon: "none" });
+ return;
+ }
+ if (!currentMaterialRow.value?.id) {
+ uni.showToast({ title: "缂哄皯鐗╂枡鏄庣粏ID", icon: "none" });
+ return;
+ }
+ supplementSubmitting.value = true;
+ addWorkOrderMaterialSupplement({
+ materialLedgerId: currentMaterialRow.value.id,
+ supplementQty: Number(supplementForm.supplementQty),
+ supplementReason: supplementForm.supplementReason,
+ workOrderId: currentMaterialOrderRow.value?.id,
+ })
+ .then(async () => {
+ supplementDialogVisible.value = false;
+ await loadMaterialTable(currentMaterialOrderRow.value);
+ uni.showToast({ title: "琛ユ枡鎴愬姛" });
+ emit("refresh");
+ })
+ .catch(e => {
+ console.error("琛ユ枡澶辫触", e);
+ uni.showToast({ title: "琛ユ枡澶辫触", icon: "error" });
+ })
+ .finally(() => {
+ supplementSubmitting.value = false;
+ });
+ };
+
+ const openSupplementRecordDialog = async row => {
+ supplementRecordDialogVisible.value = true;
+ supplementRecordLoading.value = true;
+ supplementRecordTableData.value = [];
+ try {
+ const res = await listWorkOrderMaterialSupplementRecord({
+ materialLedgerId: row.id,
+ });
+ supplementRecordTableData.value = res.data || [];
+ } catch (e) {
+ console.error("鑾峰彇琛ユ枡璁板綍澶辫触", e);
+ uni.showToast({ title: "鑾峰彇琛ユ枡璁板綍澶辫触", icon: "error" });
+ } finally {
+ supplementRecordLoading.value = false;
+ }
+ };
+
+ const validatePickRows = () => {
+ if (materialTableData.value.length === 0) {
+ return { valid: false, message: "鏆傛棤鍙鐢ㄧ墿鏂�" };
+ }
+ const invalidRow = materialTableData.value.find(
+ item =>
+ item.actualQty === null ||
+ item.actualQty === undefined ||
+ item.actualQty === ""
+ );
+ if (invalidRow) {
+ return { valid: false, message: "璇峰~鍐欏疄闄呮暟閲忓悗鍐嶉鐢�" };
+ }
+ const exceedRow = materialTableData.value.find(item => {
+ const maxQty = Number(item.pickQty || 0) + Number(item.supplementQty || 0);
+ return Number(item.actualQty || 0) > maxQty;
+ });
+ if (exceedRow) {
+ return { valid: false, message: "瀹為檯鏁伴噺涓嶈兘澶т簬棰嗙敤鏁伴噺+琛ユ枡鏁伴噺" };
+ }
+ return { valid: true, message: "" };
+ };
+
+ const handleSubmitPick = async () => {
+ if (!currentMaterialOrderRow.value?.id) return;
+ const validateResult = validatePickRows();
+ if (!validateResult.valid) {
+ uni.showToast({ title: validateResult.message, icon: "none" });
+ return;
+ }
+ pickSubmitting.value = true;
+ try {
+ await pickWorkOrderMaterial({
+ workOrderId: currentMaterialOrderRow.value.id,
+ items: materialTableData.value.map(item => ({
+ materialLedgerId: item.id,
+ actualQty: Number(item.actualQty || 0),
+ })),
+ });
+ uni.showToast({ title: "棰嗙敤鎴愬姛" });
+ await loadMaterialTable(currentMaterialOrderRow.value);
+ emit("refresh");
+ } catch (e) {
+ console.error("棰嗙敤澶辫触", e);
+ uni.showToast({ title: "棰嗙敤澶辫触", icon: "error" });
+ } finally {
+ pickSubmitting.value = false;
+ }
+ };
+</script>
+
+<style scoped lang="scss">
+ .material-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ z-index: 999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .material-container {
+ width: 92%;
+ max-height: 85vh;
+ background: #fff;
+ border-radius: 16rpx;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .supplement-container {
+ max-height: 60vh;
+ }
+
+ .supplement-record-container {
+ max-height: 75vh;
+ }
+
+ .material-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx 32rpx;
+ border-bottom: 1px solid #f0f0f0;
+ flex-shrink: 0;
+ }
+
+ .material-title {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .close-btn {
+ padding: 8rpx;
+ }
+
+ .material-body {
+ flex: 1;
+ padding: 16rpx 24rpx;
+ overflow-y: auto;
+ }
+
+ .empty-tip {
+ text-align: center;
+ padding: 60rpx 0;
+ color: #999;
+ font-size: 28rpx;
+ }
+
+ .material-card {
+ background: #f9fafb;
+ border-radius: 12rpx;
+ padding: 20rpx;
+ margin-bottom: 16rpx;
+ }
+
+ .material-row {
+ display: flex;
+ align-items: center;
+ padding: 10rpx 0;
+ }
+
+ .mc-label {
+ width: 160rpx;
+ font-size: 26rpx;
+ color: #909399;
+ flex-shrink: 0;
+ }
+
+ .mc-value {
+ flex: 1;
+ font-size: 26rpx;
+ color: #303133;
+ }
+
+ .material-actions {
+ display: flex;
+ gap: 16rpx;
+ margin-top: 16rpx;
+ padding-top: 16rpx;
+ border-top: 1px solid #ebeef5;
+ }
+
+ .record-card {
+ background: #f9fafb;
+ border-radius: 12rpx;
+ padding: 20rpx;
+ margin-bottom: 16rpx;
+ }
+
+ .material-footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 16rpx;
+ padding: 20rpx 32rpx;
+ border-top: 1px solid #f0f0f0;
+ flex-shrink: 0;
+ }
+</style>
diff --git a/src/pages/productionManagement/productionReport/components/filesDia.vue b/src/pages/productionManagement/productionReport/components/filesDia.vue
new file mode 100644
index 0000000..66b7725
--- /dev/null
+++ b/src/pages/productionManagement/productionReport/components/filesDia.vue
@@ -0,0 +1,262 @@
+<template>
+ <view v-if="visible" class="files-overlay">
+ <view class="files-container">
+ <view class="files-header">
+ <text class="files-title">宸ュ崟闄勪欢</text>
+ <view class="close-btn" @click="closeDia">
+ <up-icon name="close" size="20" color="#666" />
+ </view>
+ </view>
+ <view class="files-toolbar">
+ <up-button type="primary" size="small" @click="handleUpload">涓婁紶鍥剧墖</up-button>
+ <up-button type="error" size="small" plain @click="handleDelete">鍒犻櫎</up-button>
+ </view>
+ <scroll-view class="files-list" scroll-y>
+ <view v-if="tableData.length === 0" class="empty-tip">
+ <text>鏆傛棤闄勪欢</text>
+ </view>
+ <view v-for="item in tableData" :key="item.id" class="file-item">
+ <view class="file-left" @click="toggleSelect(item)">
+ <up-icon :name="selectedIds.includes(item.id) ? 'checkbox-mark' : 'checkbox'"
+ size="20"
+ :color="selectedIds.includes(item.id) ? '#2979ff' : '#c0c4cc'" />
+ </view>
+ <view class="file-info" @click="handlePreview(item)">
+ <text class="file-name">{{ item.name }}</text>
+ </view>
+ <view class="file-actions">
+ <text class="action-link" @click="handleDownload(item)">涓嬭浇</text>
+ <text class="action-link" @click="handlePreview(item)">棰勮</text>
+ </view>
+ </view>
+ </scroll-view>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { ref, getCurrentInstance } from "vue";
+ import { getToken } from "@/utils/auth.js";
+ import {
+ productWorkOrderFileAdd,
+ productWorkOrderFileDel,
+ productWorkOrderFileListPage,
+ } from "@/api/productionManagement/productWorkOrderFile.js";
+
+ const { proxy } = getCurrentInstance();
+
+ const visible = ref(false);
+ const currentWorkOrderId = ref("");
+ const selectedIds = ref([]);
+ const tableData = ref([]);
+ const tableLoading = ref(false);
+
+ const uploadUrl = import.meta.env.VITE_APP_BASE_API + "/file/upload";
+
+ const openDialog = row => {
+ visible.value = true;
+ currentWorkOrderId.value = row.id;
+ selectedIds.value = [];
+ getList();
+ };
+
+ const closeDia = () => {
+ visible.value = false;
+ };
+
+ const getList = () => {
+ tableLoading.value = true;
+ productWorkOrderFileListPage({
+ workOrderId: currentWorkOrderId.value,
+ current: 1,
+ size: 100,
+ })
+ .then(res => {
+ tableData.value = res.data.records || [];
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ };
+
+ const toggleSelect = item => {
+ const idx = selectedIds.value.indexOf(item.id);
+ if (idx > -1) {
+ selectedIds.value.splice(idx, 1);
+ } else {
+ selectedIds.value.push(item.id);
+ }
+ };
+
+ const handleUpload = () => {
+ uni.chooseImage({
+ count: 1,
+ sizeType: ["compressed"],
+ sourceType: ["album", "camera"],
+ success: res => {
+ const tempFilePath = res.tempFilePaths[0];
+ uni.showLoading({ title: "涓婁紶涓�..." });
+ uni.uploadFile({
+ url: uploadUrl,
+ filePath: tempFilePath,
+ name: "file",
+ header: {
+ Authorization: "Bearer " + getToken(),
+ },
+ success: uploadRes => {
+ const data = JSON.parse(uploadRes.data);
+ if (data.code === 200) {
+ const fileRow = {
+ name: data.data.originalName,
+ url: data.data.tempPath,
+ workOrderId: currentWorkOrderId.value,
+ };
+ productWorkOrderFileAdd(fileRow).then(() => {
+ uni.showToast({ title: "涓婁紶鎴愬姛" });
+ getList();
+ });
+ } else {
+ uni.showToast({ title: "涓婁紶澶辫触", icon: "error" });
+ }
+ },
+ fail: () => {
+ uni.showToast({ title: "涓婁紶澶辫触", icon: "error" });
+ },
+ complete: () => {
+ uni.hideLoading();
+ },
+ });
+ },
+ });
+ };
+
+ const handleDelete = () => {
+ if (selectedIds.value.length === 0) {
+ uni.showToast({ title: "璇烽�夋嫨鏁版嵁", icon: "none" });
+ return;
+ }
+ uni.showModal({
+ title: "鍒犻櫎",
+ content: "閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�",
+ success: res => {
+ if (res.confirm) {
+ productWorkOrderFileDel(selectedIds.value).then(() => {
+ uni.showToast({ title: "鍒犻櫎鎴愬姛" });
+ selectedIds.value = [];
+ getList();
+ });
+ }
+ },
+ });
+ };
+
+ const handleDownload = row => {
+ proxy.$download.byUrl(row.url, row.originalFilename);
+ };
+
+ const handlePreview = row => {
+ uni.previewImage({
+ urls: [row.url],
+ current: row.url,
+ });
+ };
+
+ defineExpose({
+ openDialog,
+ });
+</script>
+
+<style scoped lang="scss">
+ .files-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ z-index: 999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .files-container {
+ width: 90%;
+ max-height: 80vh;
+ background: #fff;
+ border-radius: 16rpx;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .files-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx 32rpx;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .files-title {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .close-btn {
+ padding: 8rpx;
+ }
+
+ .files-toolbar {
+ display: flex;
+ justify-content: flex-end;
+ gap: 16rpx;
+ padding: 16rpx 32rpx;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .files-list {
+ flex: 1;
+ padding: 16rpx 32rpx;
+ overflow-y: auto;
+ }
+
+ .empty-tip {
+ text-align: center;
+ padding: 60rpx 0;
+ color: #999;
+ font-size: 28rpx;
+ }
+
+ .file-item {
+ display: flex;
+ align-items: center;
+ padding: 20rpx 0;
+ border-bottom: 1px solid #f5f5f5;
+ }
+
+ .file-left {
+ margin-right: 16rpx;
+ }
+
+ .file-info {
+ flex: 1;
+ }
+
+ .file-name {
+ font-size: 28rpx;
+ color: #303133;
+ }
+
+ .file-actions {
+ display: flex;
+ gap: 24rpx;
+ flex-shrink: 0;
+ }
+
+ .action-link {
+ font-size: 26rpx;
+ color: #2979ff;
+ }
+</style>
diff --git a/src/pages/productionManagement/productionReport/index.vue b/src/pages/productionManagement/productionReport/index.vue
index ac92038..9adbd6d 100644
--- a/src/pages/productionManagement/productionReport/index.vue
+++ b/src/pages/productionManagement/productionReport/index.vue
@@ -164,6 +164,8 @@
reportWork: "",
productionOrderRoutingOperationId: "",
productionOrderId: "",
+ productMainId: null,
+ productProcessRouteItemId: "",
workHour: 0,
type: null,
paramGroups: {},
@@ -352,11 +354,13 @@
const submitData = {
quantity: quantity,
- scrapQty: scrapQty,
+ scrapQty: isNaN(scrapQty) ? 0 : scrapQty,
userId: form.value.userId,
userName: form.value.userName,
productionOperationTaskId: form.value.workOrderId,
+ productProcessRouteItemId: form.value.productProcessRouteItemId,
reportWork: form.value.reportWork,
+ productMainId: form.value.productMainId,
productionOrderRoutingOperationId:
form.value.productionOrderRoutingOperationId,
productionOrderId: form.value.productionOrderId,
@@ -429,7 +433,14 @@
Math.max(0, planQuantity - completeQuantity)
);
form.value.workOrderId = orderRow.id || "";
+ form.value.productProcessRouteItemId =
+ orderRow.productProcessRouteItemId || "";
form.value.reportWork = orderRow.reportWork || "";
+ form.value.productMainId = orderRow.productMainId || null;
+ form.value.scrapQty =
+ orderRow.scrapQty !== undefined && orderRow.scrapQty !== null
+ ? orderRow.scrapQty
+ : "";
form.value.productionOrderRoutingOperationId =
orderRow.productionOrderRoutingOperationId || "";
form.value.productionOrderId = orderRow.productionOrderId || "";
diff --git a/src/pages/productionManagement/workOrder/index.vue b/src/pages/productionManagement/workOrder/index.vue
index 5360a11..c1c7aa9 100644
--- a/src/pages/productionManagement/workOrder/index.vue
+++ b/src/pages/productionManagement/workOrder/index.vue
@@ -1,27 +1,34 @@
<template>
<view class="work-order">
- <!-- 閫氱敤椤甸潰澶撮儴 -->
<PageHeader title="鐢熶骇宸ュ崟" @back="goBack" />
-
+
<!-- 鎼滅储鍖哄煙 -->
<view class="search-section">
<view class="search-bar">
<view class="search-input">
- <up-input
- class="search-text"
- placeholder="璇疯緭鍏ュ伐鍗曠紪鍙锋悳绱�"
- v-model="searchForm.workOrderNo"
- @confirm="handleQuery"
- clearable
- />
+ <up-input class="search-text"
+ v-model="data.searchForm.workOrderNo"
+ placeholder="宸ュ崟缂栧彿"
+ @confirm="handleQuery"
+ clearable />
</view>
-
+ <view class="search-input">
+ <up-input class="search-text"
+ v-model="data.searchForm.npsNo"
+ placeholder="鐢熶骇璁㈠崟鍙�"
+ @confirm="handleQuery"
+ clearable />
+ </view>
<view class="filter-button" @click="handleQuery">
<up-icon name="search" size="24" color="#999"></up-icon>
</view>
</view>
+ <view class="switch-row">
+ <text class="switch-label">浠呯湅鎴戠殑</text>
+ <up-switch v-model="filterMine" @change="handleQuery" size="18" />
+ </view>
</view>
-
+
<!-- 宸ュ崟鍒楄〃 -->
<scroll-view scroll-y class="ledger-list" v-if="tableData.length > 0" @scrolltolower="loadMore">
<view v-for="(item, index) in tableData" :key="item.id || index" class="ledger-item">
@@ -36,10 +43,14 @@
<text class="item-tag tag-type">{{ item.workOrderType }}</text>
</view>
</view>
-
+
<up-divider></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>
@@ -50,24 +61,24 @@
</view>
<view class="detail-row">
<text class="detail-label">宸ュ簭鍚嶇О</text>
- <text class="detail-value">{{ item.processName }}</text>
+ <text class="detail-value">{{ item.operationName }}</text>
</view>
<view class="detail-row">
<text class="detail-label">闇�姹�/瀹屾垚鏁伴噺</text>
<text class="detail-value">{{ item.planQuantity }} / {{ item.completeQuantity }} {{ item.unit }}</text>
</view>
-
+
<view class="progress-section">
<text class="detail-label">瀹屾垚杩涘害</text>
<view class="progress-bar">
- <up-line-progress
- :percentage="toProgressPercentage(item.completionStatus)"
+ <up-line-progress
+ :percentage="toProgressPercentage(item.completionStatus)"
activeColor="#2979ff"
:showText="true"
></up-line-progress>
</view>
</view>
-
+
<view class="detail-row">
<text class="detail-label">璁″垝寮�濮�</text>
<text class="detail-value">{{ item.planStartTime }}</text>
@@ -76,51 +87,52 @@
<text class="detail-label">璁″垝缁撴潫</text>
<text class="detail-value">{{ item.planEndTime }}</text>
</view>
+ <view class="detail-row">
+ <text class="detail-label">瀹為檯寮�濮�</text>
+ <text class="detail-value">{{ item.actualStartTime || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">瀹為檯缁撴潫</text>
+ <text class="detail-value">{{ item.actualEndTime || '-' }}</text>
+ </view>
+ </view>
+
+ <view class="item-actions">
+ <up-button v-if="showStartReport(item)"
+ class="action-btn"
+ size="small"
+ type="primary"
+ @click="handleStartWork(item)">寮�濮嬫姤宸�</up-button>
+ <up-button v-if="showEndReport(item)"
+ class="action-btn"
+ size="small"
+ type="success"
+ @click="goReport(item)">缁撴潫鎶ュ伐</up-button>
</view>
</view>
<up-loadmore :status="loadStatus" />
</scroll-view>
-
+
<view v-else-if="!loading" class="no-data">
<up-empty mode="data" text="鏆傛棤宸ュ崟鏁版嵁"></up-empty>
</view>
- <!-- 娴佽浆鍗″脊绐� -->
- <up-popup :show="transferCardVisible" mode="center" @close="transferCardVisible = false" round="10">
- <view class="qr-popup">
- <text class="qr-title">宸ュ崟娴佽浆鍗′簩缁寸爜</text>
- <view class="qr-box">
- <geek-qrcode
- v-if="transferCardRowData"
- :val="String(transferCardRowData.id)"
- :size="200"
- />
- </view>
- <text class="qr-info" v-if="transferCardRowData">{{ transferCardRowData.workOrderNo }}</text>
- <up-button text="鍏抽棴" @click="transferCardVisible = false" style="margin-top: 20px;"></up-button>
- </view>
- </up-popup>
-
- <!-- 闄勪欢缁勪欢 -->
- <FilesDia ref="workOrderFilesRef" />
</view>
</template>
<script setup>
-import { ref, reactive, toRefs, getCurrentInstance } from "vue";
+import { ref, reactive } from "vue";
import { onShow } from '@dcloudio/uni-app';
-import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js";
+import { productWorkOrderPage, startWork } from "@/api/productionManagement/workOrder.js";
import PageHeader from "@/components/PageHeader.vue";
-import FilesDia from "./components/filesDia.vue";
+import useUserStore from "@/store/modules/user";
-const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
const loading = ref(false);
const tableData = ref([]);
const loadStatus = ref('loadmore');
-const transferCardVisible = ref(false);
-const transferCardRowData = ref(null);
-const workOrderFilesRef = ref(null);
+const filterMine = ref(false);
const page = reactive({
current: 1,
@@ -131,9 +143,20 @@
const data = reactive({
searchForm: {
workOrderNo: "",
+ npsNo: "",
},
});
-const { searchForm } = toRefs(data);
+
+const isCompleted = row => {
+ const status = Number(row?.completionStatus);
+ return Number.isFinite(status) && status >= 100;
+};
+
+const canOperate = row => !row.endOrder && !isCompleted(row);
+
+const showStartReport = row => canOperate(row) && !row.actualStartTime;
+
+const showEndReport = row => canOperate(row) && !!row.actualStartTime;
const goBack = () => {
uni.navigateBack();
@@ -148,15 +171,18 @@
const getList = () => {
if (loading.value) return;
loading.value = true;
-
- const params = { ...searchForm.value, ...page };
-
+
+ const params = { ...data.searchForm, ...page };
+ if (filterMine.value) {
+ params.filterMine = true;
+ }
+
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;
-
+
if (tableData.value.length >= page.total) {
loadStatus.value = 'nomore';
} else {
@@ -182,13 +208,34 @@
return Math.round(n);
};
-const showTransferCard = (row) => {
- transferCardRowData.value = row;
- transferCardVisible.value = true;
+const handleStartWork = (row) => {
+ uni.showModal({
+ title: "鎻愮ず",
+ content: "纭寮�濮嬫姤宸ワ紵",
+ success: res => {
+ if (res.confirm) {
+ startWork({
+ productionOperationTaskId: row.id,
+ userId: userStore.id,
+ })
+ .then(() => {
+ uni.showToast({ title: "寮�濮嬫姤宸ユ垚鍔�" });
+ handleQuery();
+ })
+ .catch(() => {
+ uni.showToast({ title: "寮�濮嬫姤宸ュけ璐�", icon: "error" });
+ });
+ }
+ },
+ });
};
-const openWorkOrderFiles = (row) => {
- workOrderFilesRef.value?.openDialog(row);
+const goReport = (row) => {
+ uni.navigateTo({
+ url: `/pages/productionManagement/productionReport/index?orderRow=${encodeURIComponent(
+ JSON.stringify(row)
+ )}`,
+ });
};
onShow(() => {
@@ -228,37 +275,10 @@
gap: 10px;
padding: 12px 0;
border-top: 1px solid #f5f5f5;
-
- :deep(.up-button) {
+
+ .action-btn {
margin: 0;
width: auto;
- }
-}
-
-.qr-popup {
- padding: 30px;
- background-color: #fff;
- display: flex;
- flex-direction: column;
- align-items: center;
-
- .qr-title {
- font-size: 18px;
- font-weight: bold;
- margin-bottom: 20px;
- }
-
- .qr-box {
- padding: 20px;
- background-color: #fff;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
- border-radius: 8px;
- margin-bottom: 15px;
- }
-
- .qr-info {
- font-size: 14px;
- color: #666;
}
}
diff --git a/src/pages/works.vue b/src/pages/works.vue
index 9e89ddf..1b77038 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -306,7 +306,6 @@
<script setup>
import { ref, onMounted, nextTick, reactive, computed } from "vue";
import { userLoginFacotryList } from "@/api/login";
- import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting";
import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
import modal from "@/plugins/modal";
import useUserStore from "@/store/modules/user";
@@ -343,10 +342,10 @@
icon: "/static/images/icon/gongxuguanli.svg",
label: "宸ュ簭绠$悊",
},
- {
- icon: "/static/images/icon/bom.svg",
- label: "BOM",
- },
+ // {
+ // icon: "/static/images/icon/bom.svg",
+ // label: "BOM",
+ // },
{
icon: "/static/images/icon/gongyiluxian.svg",
label: "宸ヨ壓璺嚎",
@@ -359,10 +358,10 @@
icon: "/static/images/icon/kehudangan.svg",
label: "瀹㈡埛妗f",
},
- {
- icon: "/static/images/icon/xiaoshoubaojia.svg",
- label: "閿�鍞姤浠�",
- },
+ // {
+ // icon: "/static/images/icon/xiaoshoubaojia.svg",
+ // label: "閿�鍞姤浠�",
+ // },
{
icon: "/static/images/icon/xiaoshoutaizhang.svg",
label: "閿�鍞彴璐�",
@@ -912,7 +911,9 @@
});
break;
case "鐢熶骇鎶ュ伐":
- getcode();
+ uni.navigateTo({
+ url: "/pages/productionManagement/workOrder/index",
+ });
break;
case "鎶ュ伐鍙拌处":
uni.navigateTo({
@@ -1120,88 +1121,6 @@
factoryList.value = [];
});
}
- const getcode = async () => {
- uni.scanCode({
- success: async res => {
- // 瑙f瀽浜岀淮鐮佸唴瀹�
- const scanResult = res.result;
- let orderRow = "";
-
- // 鍒ゆ柇鎵弿缁撴灉鏄惁涓虹函鏁板瓧锛坕d锛�
- const isNumericId = /^\d+$/.test(scanResult.trim());
-
- if (isNumericId) {
- // 濡傛灉鏄函鏁板瓧锛屾牴鎹� id 鑾峰彇宸ュ崟鏁版嵁
- const workOrderId = scanResult.trim();
- modal.loading("姝e湪鑾峰彇宸ュ崟淇℃伅...");
- try {
- const workRes = await getProductWorkOrderById({ id: workOrderId });
- modal.closeLoading();
-
- console.log("宸ュ崟鏌ヨ缁撴灉:", workRes);
-
- if (workRes.code === 200 && workRes.data) {
- // 鏂版帴鍙h繑鍥炵殑鏄崟涓璞★紝涓嶆槸鏁扮粍
- const workData = workRes.data;
- console.log("宸ュ崟鏁版嵁:", workData);
-
- if (workData.endOrder === true) {
- modal.msgError("璇ヨ鍗曞凡缁撴潫锛屾棤娉曟姤宸�");
- return;
- }
-
- orderRow = JSON.stringify(workData);
-
- console.log("鏋勯�犵殑orderRow:", orderRow);
- } else {
- modal.msgError("鏈壘鍒板搴旂殑宸ュ崟淇℃伅");
- return;
- }
- } catch (error) {
- modal.closeLoading();
- console.error("鑾峰彇宸ュ崟淇℃伅澶辫触:", error);
- modal.msgError("鑾峰彇宸ュ崟淇℃伅澶辫触: " + (error.message || "鏈煡閿欒"));
- return;
- }
- } else {
- // 濡傛灉涓嶆槸绾暟瀛楋紝灏濊瘯浠庢壂鐮佺粨鏋滀腑鎻愬彇orderRow鍙傛暟
- try {
- // 澶勭悊娣峰悎鏍煎紡: http://...?orderRow={...}
- const orderRowStart = scanResult.indexOf("orderRow={");
- if (orderRowStart !== -1) {
- // 鎻愬彇浠巓rderRow={寮�濮嬬殑JSON鍐呭
- const jsonPart = scanResult.substring(orderRowStart + 9); // 9鏄�"orderRow=".length
- orderRow = jsonPart;
- } else {
- // 濡傛灉鐩存帴鏄疛SON瀛楃涓诧紝灏濊瘯瑙f瀽
- orderRow = scanResult;
- }
- } catch (e) {
- console.error(e, "瑙f瀽澶辫触====????=====");
- orderRow = "";
- }
-
- // 楠岃瘉鏄惁涓烘湁鏁堢殑JSON
- try {
- JSON.parse(orderRow);
- } catch (error) {
- modal.msgError("璁㈠崟瑙f瀽澶辫触锛岃妫�鏌ヤ簩缁寸爜鏍煎紡");
- return;
- }
- }
- // 鎵爜鎴愬姛鍚庤烦杞埌鐢熶骇鎶ュ伐椤甸潰锛屽苟浼犻�抩rderRow鍙傛暟
- uni.navigateTo({
- url: `/pages/productionManagement/productionReport/index?orderRow=${orderRow}`,
- });
- },
- fail: err => {
- uni.showToast({
- title: "鎵爜澶辫触",
- icon: "none",
- });
- },
- });
- };
const changeFactory = async arr => {
show.value = false;
const factoryId = factoryListTem.value[arr.indexs[0]].deptId;
--
Gitblit v1.9.3