From 80adf052e0b58abd634ca9b67f8569ccc468c430 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期一, 23 三月 2026 15:11:36 +0800
Subject: [PATCH] Merge branch 'dev_银川_中盛建材' of http://114.132.189.42:9002/r/product-inventory-management into dev_银川_中盛建材
---
/dev/null | 420 -----------
src/views/productionManagement/productionReporting/index.vue | 59 +
src/views/productionManagement/productionReporting/reportingDialog.vue | 1647 +++++++++++++++++++++++++++++++++++++++++++++
src/api/productionManagement/productProcessRoute.js | 7
4 files changed, 1,690 insertions(+), 443 deletions(-)
diff --git a/src/api/productionManagement/productProcessRoute.js b/src/api/productionManagement/productProcessRoute.js
index c926a28..9c08894 100644
--- a/src/api/productionManagement/productProcessRoute.js
+++ b/src/api/productionManagement/productProcessRoute.js
@@ -83,4 +83,11 @@
url: `/productionOrderRouteItemParam/delete/${id}`,
method: "delete",
});
+}
+// 鐢熶骇鎶ュ伐-鏂板
+export function productionRecordAdd(id) {
+ return request({
+ url: "/productionRecord/add/" + id,
+ method: "get",
+ });
}
\ No newline at end of file
diff --git a/src/views/productionManagement/productionReporting/Input.vue b/src/views/productionManagement/productionReporting/Input.vue
deleted file mode 100644
index 3ba68f7..0000000
--- a/src/views/productionManagement/productionReporting/Input.vue
+++ /dev/null
@@ -1,115 +0,0 @@
-<template>
- <div>
- <el-dialog
- v-model="isShow"
- title="鎶曞叆"
- @close="closeModal"
- >
- <PIMTable
- rowKey="id"
- :column="tableColumn"
- :tableData="data"
- :page="page"
- :tableLoading="tableLoading"
- @pagination="pagination"
- ></PIMTable>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="closeModal">鍏抽棴</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
-</template>
-
-<script setup>
-import {ref, computed, onMounted} from "vue";
-import { productionProductInputListPage } from "@/api/productionManagement/productionProductInput";
-
-const props = defineProps({
- visible: {
- type: Boolean,
- required: true,
- },
- productionProductMainId: {
- type: Number,
- required: true,
- },
-});
-
-const emit = defineEmits(['update:visible', 'completed']);
-
-const page = reactive({
- current: 1,
- size: 100,
- total: 0
-});
-
-const pagination = (obj) => {
- page.current = obj.page;
- page.size = obj.limit;
- fetchData();
-};
-
-const tableLoading = ref(false);
-
-const tableColumn = [
- {
- label: '鎶ュ伐鍗曞彿',
- prop: 'productNo',
- },
- {
- label: '鎶曞叆浜у搧鍚嶇О',
- prop: 'productName',
- },
- {
- label: '鎶曞叆浜у搧鍨嬪彿',
- prop: 'model',
- },
- {
- label: '鎶曞叆鏁伴噺',
- prop: 'quantity',
- },
- {
- label: '鍗曚綅',
- prop: 'unit',
- },
-]
-
-const isShow = computed({
- get() {
- return props.visible;
- },
- set(val) {
- emit('update:visible', val);
- },
-});
-
-const data = ref([])
-
-const closeModal = () => {
- isShow.value = false;
-};
-
-const fetchData = () => {
- tableLoading.value = true;
- const params = { productMainId: props.productionProductMainId, ...page };
-
- productionProductInputListPage(params).then(res => {
- tableLoading.value = false;
- data.value = res.data.records;
- page.total = res.data.total;
- }).catch(err => {
- tableLoading.value = false;
- })
-};
-
-defineExpose({
- closeModal,
- isShow,
-});
-
-onMounted(() => {
- fetchData()
-})
-</script>
diff --git a/src/views/productionManagement/productionReporting/Output.vue b/src/views/productionManagement/productionReporting/Output.vue
deleted file mode 100644
index 4eeac43..0000000
--- a/src/views/productionManagement/productionReporting/Output.vue
+++ /dev/null
@@ -1,106 +0,0 @@
-<template>
- <div>
- <el-dialog v-model="isShow"
- title="浜у嚭"
- @close="closeModal">
- <PIMTable rowKey="id"
- :column="tableColumn"
- :tableData="data"
- :page="page"
- :tableLoading="tableLoading"
- @pagination="pagination"></PIMTable>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary"
- @click="closeModal">鍏抽棴</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
-</template>
-
-<script setup>
- import { ref, computed, onMounted } from "vue";
- import { productionProductOutputListPage } from "@/api/productionManagement/productionProductOutput.js";
-
- const props = defineProps({
- visible: {
- type: Boolean,
- required: true,
- },
- productionProductMainId: {
- type: Number,
- required: true,
- },
- });
-
- const emit = defineEmits(["update:visible", "completed"]);
-
- const page = reactive({
- current: 1,
- size: 100,
- total: 0,
- });
-
- const pagination = obj => {
- page.current = obj.page;
- page.size = obj.limit;
- fetchData();
- };
-
- const tableLoading = ref(false);
-
- const tableColumn = [
- {
- label: "鎶ュ伐鍗曞彿",
- prop: "productNo",
- },
- {
- label: "浜у搧鍨嬪彿",
- prop: "model",
- },
- {
- label: "浜у嚭鏁伴噺",
- prop: "quantity",
- },
- ];
-
- const isShow = computed({
- get() {
- return props.visible;
- },
- set(val) {
- emit("update:visible", val);
- },
- });
-
- const data = ref([]);
-
- const closeModal = () => {
- isShow.value = false;
- };
-
- const fetchData = () => {
- tableLoading.value = true;
- const params = { productMainId: props.productionProductMainId, ...page };
-
- productionProductOutputListPage(params)
- .then(res => {
- tableLoading.value = false;
- data.value = res.data.records;
- page.total = res.data.total;
- })
- .catch(err => {
- tableLoading.value = false;
- });
- };
-
- defineExpose({
- closeModal,
- isShow,
- });
-
- onMounted(() => {
- fetchData();
- });
-</script>
diff --git a/src/views/productionManagement/productionReporting/components/ReportingDialog.vue b/src/views/productionManagement/productionReporting/components/ReportingDialog.vue
deleted file mode 100644
index 8eff508..0000000
--- a/src/views/productionManagement/productionReporting/components/ReportingDialog.vue
+++ /dev/null
@@ -1,588 +0,0 @@
-<template>
- <el-dialog v-model="localVisible"
- :title="dialogTitle"
- width="800px"
- @close="handleClose">
- <!-- 姝ラ鏉� -->
- <el-steps :active="activeStep"
- finish-status="success">
- <el-step title="閫夋嫨鐢熶骇璁㈠崟" />
- <el-step title="濉啓鍩虹淇℃伅" />
- <el-step title="鏌ョ湅宸ュ簭鍙傛暟" />
- <el-step title="濉啓浜ч噺淇℃伅" />
- </el-steps>
- <!-- 绗竴姝ワ細閫夋嫨鐢熶骇璁㈠崟 -->
- <div v-if="activeStep === 0">
- <el-form :model="form"
- ref="formRef"
- label-width="120px">
- <el-form-item label="鐢熶骇璁㈠崟"
- prop="orderId"
- required>
- <el-select v-model="orderId"
- placeholder="璇烽�夋嫨鐢熶骇璁㈠崟"
- clearable
- filterable
- style="width: 100%"
- :loading="orderLoading"
- @change="handleOrderChange">
- <el-option v-for="order in orderList"
- :key="order.id"
- :label="`${order.npsNo} - ${order.productName} ${order.model}`"
- :value="order.id" />
- </el-select>
- </el-form-item>
- </el-form>
- </div>
- <!-- 绗簩姝ワ細濉啓鍩虹淇℃伅 -->
- <div v-else-if="activeStep === 1">
- <el-form :model="form"
- :rules="rules"
- ref="formRef"
- label-width="120px">
- <el-form-item label="鐢熶骇璁㈠崟鍙�"
- prop="npsNo">
- <el-input disabled
- v-model="form.npsNo" />
- </el-form-item>
- <el-form-item label="鐝粍"
- prop="teamName"
- required>
- <el-select v-model="form.teamName"
- placeholder="璇烽�夋嫨鐝粍"
- style="width: 100%">
- <el-option label="鐧界彮"
- value="鐧界彮" />
- <el-option label="澶滅彮"
- value="澶滅彮" />
- </el-select>
- </el-form-item>
- <el-form-item label="浜у搧缂栫爜"
- prop="materialCode">
- <el-input disabled
- v-model="form.materialCode" />
- </el-form-item>
- <el-form-item label="浜у搧鍚嶇О"
- prop="productName">
- <el-input disabled
- v-model="form.productName" />
- </el-form-item>
- <el-form-item label="瑙勬牸"
- prop="specification">
- <el-input disabled
- v-model="form.specification" />
- </el-form-item>
- <el-form-item label="鍒涘缓浜�"
- prop="createBy"
- required>
- <el-input v-model="form.createBy"
- placeholder="璇疯緭鍏ュ垱寤轰汉" />
- </el-form-item>
- <el-form-item label="鍒涘缓鏃堕棿"
- prop="createTime">
- <el-date-picker disabled
- v-model="form.createTime"
- type="datetime"
- placeholder="璇烽�夋嫨鍒涘缓鏃堕棿"
- style="width: 100%" />
- </el-form-item>
- </el-form>
- </div>
- <!-- 绗笁姝ワ細鏌ョ湅宸ュ簭鍙傛暟 -->
- <div v-else-if="activeStep === 2">
- <!-- 宸ュ簭Tab椤� -->
- <el-tabs v-model="activeProcessId"
- @tab-click="handleTabClick">
- <el-tab-pane v-for="process in processList"
- :key="process.id"
- :label="process.processName"
- :name="process.id + ''">
- <div>
- <!-- 鍙傛暟缁勫垪琛� -->
- <div v-for="(group, groupIndex) in form.paramGroups[process.id] || []"
- :key="groupIndex"
- class="param-group">
- <div class="group-header">
- <span>鍙傛暟缁� {{ groupIndex + 1 }}</span>
- <el-button type="danger"
- size="small"
- @click="removeParamGroup(process.id, groupIndex)"
- v-if="(form.paramGroups[process.id] || []).length > 1">
- 鍒犻櫎
- </el-button>
- </div>
- <el-form :model="form"
- ref="formRef"
- label-width="120px">
- <!-- 鍔ㄦ�佸弬鏁� -->
- <el-form-item v-for="param in params"
- :key="param.id"
- :label="param.paramName">
- <template v-if="param.paramType == '1'">
- <!-- 鏁板瓧绫诲瀷 -->
- <div style="display: flex; align-items: center; gap: 8px;">
- <el-input-number v-model="group[param.id]"
- controls-position="right"
- :precision="getPrecision(param.paramFormat)"
- style="flex: 1" />
- <span v-if="param.unit && param.unit != '/'">
- {{ param.unit }}
- </span>
- </div>
- </template>
- <template v-else-if="param.paramType == '2'">
- <!-- 鏂囨湰绫诲瀷 -->
- <div style="display: flex; align-items: center; gap: 8px;">
- <el-input v-model="group[param.id]"
- style="flex: 1" />
- <span v-if="param.unit && param.unit != '/'">
- {{ param.unit }}
- </span>
- </div>
- </template>
- <template v-else-if="param.paramType == '3'">
- <!-- 瀛楀吀绫诲瀷 -->
- <div style="display: flex; align-items: center; gap: 8px;">
- <el-select v-model="group[param.id]"
- placeholder="璇烽�夋嫨"
- style="flex: 1;width: 150px">
- <el-option v-for="option in dictOptions[param.paramFormat] || []"
- :key="option.dictValue"
- :label="option.dictLabel"
- :value="option.dictValue" />
- </el-select>
- <span v-if="param.unit && param.unit != '/'">
- {{ param.unit }}
- </span>
- </div>
- </template>
- <template v-else-if="param.paramType == '4'">
- <!-- 鏃ユ湡绫诲瀷 -->
- <div style="display: flex; align-items: center; gap: 8px;">
- <el-date-picker :value-format="param.paramFormat"
- :format="param.paramFormat"
- :type="param.paramFormat=='YYYY-MM-DD'?'daterange':'datetimerange'"
- v-model="group[param.id]"
- style="flex: 1" />
- <span v-if="param.unit && param.unit != '/'">
- {{ param.unit }}
- </span>
- </div>
- </template>
- <template v-else>
- <!-- 鍏朵粬绫诲瀷 -->
- <div style="display: flex; align-items: center; gap: 8px;">
- <el-input v-model="group[param.id]"
- style="flex: 1" />
- <span v-if="param.unit && param.unit != '/'">
- {{ param.unit }}
- </span>
- </div>
- </template>
- </el-form-item>
- </el-form>
- </div>
- <!-- 鏂板鍙傛暟缁勬寜閽� -->
- <el-button type="primary"
- size="small"
- @click="addParamGroup(process.id)">
- 鏂板鍙傛暟缁�
- </el-button>
- </div>
- </el-tab-pane>
- </el-tabs>
- </div>
- <!-- 绗洓姝ワ細濉啓浜ч噺淇℃伅 -->
- <div v-else-if="activeStep === 3">
- <el-form :model="form"
- :rules="rules"
- ref="formRef"
- label-width="120px">
- <el-form-item label="浜у嚭鏂归噺"
- prop="outputVolume"
- required>
- <el-input-number v-model="form.outputVolume"
- :min="0"
- :precision="2"
- style="width: 100%" />
- </el-form-item>
- <el-form-item label="涓嶅悎鏍兼柟閲�"
- prop="unqualifiedVolume"
- required>
- <el-input-number v-model="form.unqualifiedVolume"
- :min="0"
- :precision="2"
- style="width: 100%" />
- </el-form-item>
- <el-form-item label="瀹屾垚鏂归噺"
- prop="completedVolume"
- required>
- <el-input-number v-model="form.completedVolume"
- :min="0"
- :precision="2"
- style="width: 100%" />
- </el-form-item>
- </el-form>
- </div>
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="handleClose">鍙� 娑�</el-button>
- <el-button type="primary"
- v-if="activeStep > 0"
- @click="activeStep--">涓婁竴姝�</el-button>
- <el-button type="primary"
- v-if="activeStep < 3"
- @click="handleNextStep">涓嬩竴姝�</el-button>
- <el-button type="primary"
- v-if="activeStep === 3"
- :loading="submitLoading"
- @click="handleSubmit">纭� 璁�</el-button>
- </span>
- </template>
- </el-dialog>
-</template>
-
-<script setup>
- import { ref, reactive, computed, watch } from "vue";
- import { ElMessage } from "element-plus";
- import { getDicts } from "@/api/system/dict/data";
- import { productOrderListPage } from "@/api/productionManagement/productionOrder.js";
- import {
- findProductProcessRouteItemList,
- findProcessParamListOrder,
- } from "@/api/productionManagement/productProcessRoute.js";
-
- const props = defineProps({
- visible: {
- type: Boolean,
- default: false,
- },
- data: {
- type: Object,
- default: () => ({}),
- },
- });
-
- const emit = defineEmits(["update:visible", "completed"]);
-
- const dialogTitle = computed(() => (props.data.id ? "缂栬緫鎶ュ伐" : "鏂板鎶ュ伐"));
-
- const formRef = ref(null);
- const submitLoading = ref(false);
- const orderLoading = ref(false);
- const processLoading = ref(false);
- const localVisible = ref(props.visible);
- const activeStep = ref(0);
-
- const orderId = ref(props.data.orderId || "");
- const processId = ref(props.data.processId || "");
- const activeProcessId = ref("");
- const orderList = ref([]);
- const processList = ref([]);
- const params = ref([]);
- const dictOptions = ref({});
-
- const form = reactive({
- id: props.data.id || undefined,
- orderId: props.data.orderId || "",
- npsNo: props.data.npsNo || "",
- teamName: props.data.teamName || "",
- materialCode: props.data.materialCode || "",
- productName: props.data.productName || "",
- specification: props.data.specification || "",
- outputVolume: props.data.outputVolume || 0,
- unqualifiedVolume: props.data.unqualifiedVolume || 0,
- completedVolume: props.data.completedVolume || 0,
- createBy: props.data.createBy || "褰撳墠鐧诲綍浜�",
- createTime: props.data.createTime || new Date(),
- paramGroups: props.data.paramGroups || {}, // 瀛樺偍姣忎釜宸ュ簭鐨勫弬鏁扮粍
- });
-
- const rules = {
- teamName: [{ required: true, message: "璇烽�夋嫨鐝粍", trigger: "blur" }],
- outputVolume: [
- { required: true, message: "璇疯緭鍏ヤ骇鍑烘柟閲�", trigger: "blur" },
- ],
- unqualifiedVolume: [
- { required: true, message: "璇疯緭鍏ヤ笉鍚堟牸鏂归噺", trigger: "blur" },
- ],
- completedVolume: [
- { required: true, message: "璇疯緭鍏ュ畬鎴愭柟閲�", trigger: "blur" },
- ],
- createBy: [{ required: true, message: "璇疯緭鍏ュ垱寤轰汉", trigger: "blur" }],
- };
-
- // 鍔犺浇鐢熶骇璁㈠崟鍒楄〃
- const loadOrders = () => {
- orderLoading.value = true;
- productOrderListPage({ pageNum: 1, pageSize: 100 })
- .then(res => {
- orderList.value = res.data.records || [];
- })
- .finally(() => {
- orderLoading.value = false;
- });
- };
-
- // 澶勭悊鐢熶骇璁㈠崟閫夋嫨
- const handleOrderChange = val => {
- if (val) {
- const order = orderList.value.find(item => item.id === val);
- if (order) {
- form.orderId = val;
- form.npsNo = order.npsNo;
- form.materialCode = order.materialCode;
- form.productName = order.productName;
- form.specification = order.model;
- }
- // 鍔犺浇宸ュ簭鍒楄〃
- loadProcesses(val);
- } else {
- form.orderId = "";
- form.npsNo = "";
- form.materialCode = "";
- form.productName = "";
- form.specification = "";
- processId.value = "";
- activeProcessId.value = "";
- processList.value = [];
- params.value = [];
- form.params = {};
- }
- };
-
- // 鍔犺浇宸ュ簭鍒楄〃
- const loadProcesses = orderId => {
- processLoading.value = true;
- findProductProcessRouteItemList({ orderId })
- .then(res => {
- processList.value = res.data || [];
- // 濡傛灉鏈夊伐搴忥紝榛樿閫夋嫨绗竴涓�
- if (processList.value.length > 0) {
- const firstProcess = processList.value[0];
- activeProcessId.value = firstProcess.id + "";
- processId.value = firstProcess.id;
- form.processId = firstProcess.id;
- // 鍔犺浇绗竴涓伐搴忕殑鍙傛暟
- loadParams(firstProcess.id, orderId);
- }
- })
- .finally(() => {
- processLoading.value = false;
- });
- };
-
- // 澶勭悊tab椤电偣鍑�
- const handleTabClick = tab => {
- const selectedProcessId = parseInt(tab.paneName);
- processId.value = selectedProcessId;
- form.processId = selectedProcessId;
- // 鍔犺浇鍙傛暟鍒楄〃
- loadParams(selectedProcessId, form.orderId);
- };
-
- // 鑾峰彇瀛楀吀鏁版嵁
- const getDictOptions = async dictType => {
- if (!dictType) return [];
- if (dictOptions.value[dictType]) return dictOptions.value[dictType];
-
- try {
- const res = await getDicts(dictType);
- if (res.code === 200) {
- dictOptions.value[dictType] = res.data;
- return res.data;
- }
- return [];
- } catch (error) {
- console.error("鑾峰彇瀛楀吀鏁版嵁澶辫触:", error);
- return [];
- }
- };
-
- // 鍔犺浇鍙傛暟鍒楄〃
- const loadParams = (processId, orderId) => {
- findProcessParamListOrder({ orderId, routeItemId: processId }).then(
- async res => {
- params.value = res.data || [];
- // 鍒濆鍖栧弬鏁扮粍
- if (!form.paramGroups[processId]) {
- form.paramGroups[processId] = [];
- }
- // 濡傛灉娌℃湁鍙傛暟缁勶紝娣诲姞涓�涓粯璁ゅ弬鏁扮粍
- if (form.paramGroups[processId].length === 0) {
- const defaultGroup = {};
- for (const param of params.value) {
- defaultGroup[param.id] = param.standardValue || "";
- // 濡傛灉鏄瓧鍏哥被鍨嬪弬鏁帮紝鑾峰彇瀛楀吀鏁版嵁
- if (param.paramType == "3" && param.paramFormat) {
- await getDictOptions(param.paramFormat);
- }
- }
- form.paramGroups[processId].push(defaultGroup);
- }
- }
- );
- };
-
- // 鑾峰彇灏忔暟绮惧害
- const getPrecision = format => {
- if (!format) return 2;
- const match = format.match(/\.(\d+)/);
- return match ? parseInt(match[1].length) : 2;
- };
-
- // 澶勭悊涓嬩竴姝�
- const handleNextStep = () => {
- if (activeStep.value === 0) {
- // 绗竴姝ワ細楠岃瘉鐢熶骇璁㈠崟閫夋嫨
- if (!orderId.value) {
- ElMessage.error("璇烽�夋嫨鐢熶骇璁㈠崟");
- return;
- }
- activeStep.value = 1;
- } else if (activeStep.value === 1) {
- // 绗簩姝ワ細楠岃瘉鍩虹淇℃伅
- formRef.value.validate(valid => {
- if (valid) {
- activeStep.value = 2;
- }
- });
- } else if (activeStep.value === 2) {
- // 绗笁姝ワ細鐩存帴杩涘叆绗洓姝�
- activeStep.value = 3;
- }
- };
-
- // 澶勭悊鎻愪氦
- const handleSubmit = () => {
- formRef.value.validate(valid => {
- if (valid) {
- submitLoading.value = true;
- // 杩欓噷鍙互璋冪敤API杩涜鎻愪氦
- setTimeout(() => {
- ElMessage.success(props.data.id ? "淇敼鎴愬姛" : "鏂板鎴愬姛");
- localVisible.value = false;
- emit("completed");
- submitLoading.value = false;
- }, 1000);
- }
- });
- };
-
- // 澶勭悊鍏抽棴
- const handleClose = () => {
- // 閲嶇疆鍒板垵濮嬬姸鎬�
- activeStep.value = 0;
- orderId.value = "";
- processId.value = "";
- activeProcessId.value = "";
- processList.value = [];
- params.value = [];
- Object.assign(form, {
- id: undefined,
- orderId: "",
- npsNo: "",
- teamName: "",
- materialCode: "",
- productName: "",
- specification: "",
- outputVolume: 0,
- unqualifiedVolume: 0,
- completedVolume: 0,
- createBy: "褰撳墠鐧诲綍浜�",
- createTime: new Date(),
- params: {},
- });
- localVisible.value = false;
- };
-
- // 鏂板鍙傛暟缁�
- const addParamGroup = processId => {
- if (!form.paramGroups[processId]) {
- form.paramGroups[processId] = [];
- }
- // 鍒涘缓涓�涓柊鐨勫弬鏁扮粍锛屼娇鐢ㄩ粯璁ゅ��
- const newGroup = {};
- params.value.forEach(param => {
- newGroup[param.id] = param.standardValue || "";
- });
- form.paramGroups[processId].push(newGroup);
- };
-
- // 鍒犻櫎鍙傛暟缁�
- const removeParamGroup = (processId, index) => {
- if (form.paramGroups[processId] && form.paramGroups[processId].length > 1) {
- form.paramGroups[processId].splice(index, 1);
- }
- };
-
- // 鍒濆鍖�
- const init = () => {
- // 鏃犺鏂板杩樻槸缂栬緫锛岄兘鍔犺浇璁㈠崟鍒楄〃
- loadOrders();
-
- if (props.data.id) {
- // 缂栬緫鏃惰缃〃鍗曟暟鎹�
- Object.assign(form, props.data);
- // 璁剧疆orderId
- orderId.value = props.data.orderId || "";
- // 濡傛灉鏈夎鍗旾D锛屽姞杞藉伐搴忓拰鍙傛暟
- if (props.data.orderId) {
- // 妯℃嫙閫夋嫨璁㈠崟鐨勬搷浣滐紝瑙﹀彂鏁版嵁鍔犺浇
- setTimeout(() => {
- handleOrderChange(props.data.orderId);
- }, 100);
- }
- } else {
- // 鏂板鏃惰缃粯璁ゅ��
- form.createBy = "褰撳墠鐧诲綍浜�";
- form.createTime = new Date();
- }
- // 濮嬬粓浠庣涓�姝ュ紑濮�
- activeStep.value = 0;
- };
-
- // 鐩戝惉props.visible鍙樺寲
- watch(
- () => props.visible,
- newVal => {
- localVisible.value = newVal;
- if (newVal) {
- init();
- }
- }
- );
-
- // 鐩戝惉localVisible鍙樺寲
- watch(localVisible, newVal => {
- emit("update:visible", newVal);
- });
-</script>
-
-<style scoped>
- .dialog-footer {
- text-align: right;
- }
-
- .param-group {
- border: 1px solid #e4e7ed;
- border-radius: 4px;
- padding: 16px;
- margin-bottom: 16px;
- background-color: #f9f9f9;
- }
-
- .group-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
- padding-bottom: 8px;
- border-bottom: 1px solid #e4e7ed;
- }
-
- .group-header span {
- font-weight: bold;
- font-size: 14px;
- }
-</style>
\ No newline at end of file
diff --git a/src/views/productionManagement/productionReporting/components/formDia.vue b/src/views/productionManagement/productionReporting/components/formDia.vue
deleted file mode 100644
index 15958e6..0000000
--- a/src/views/productionManagement/productionReporting/components/formDia.vue
+++ /dev/null
@@ -1,185 +0,0 @@
-<template>
- <div>
- <el-dialog
- v-model="dialogFormVisible"
- title="鐢熶骇鎶ュ伐"
- width="70%"
- @close="closeDia"
- >
- <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鎺掍骇鏁伴噺锛�" prop="schedulingNum">
- <el-input v-model="form.schedulingNum" placeholder="璇疯緭鍏�" clearable disabled/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="寰呯敓浜ф暟閲忥細" prop="pendingNum">
- <el-input v-model="form.pendingNum" placeholder="璇疯緭鍏�" clearable disabled/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鏈鐢熶骇鏁伴噺锛�" prop="finishedNum">
- <el-input-number
- v-model="form.finishedNum"
- placeholder="璇疯緭鍏�"
- :min="0"
- :step="0.1"
- :precision="2"
- clearable
- style="width: 100%"
- @change="changeNum"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鍗曚环(鍏�)锛�" prop="unitPrice">
- <el-input v-model="form.unitPrice" placeholder="璇疯緭鍏�" clearable @input="calculateTotalPrice"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鎬讳环(鍏�)锛�" prop="totalPrice">
- <el-input v-model="form.totalPrice" placeholder="璇疯緭鍏�" clearable disabled/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鐢熶骇浜猴細" prop="schedulingUserId">
- <el-select
- v-model="form.schedulingUserId"
- placeholder="閫夋嫨浜哄憳"
- style="width: 100%;"
- filterable
- default-first-option
- :reserve-keyword="false"
- >
- <el-option
- v-for="user in userList"
- :key="user.userId"
- :label="user.nickName"
- :value="user.userId"
- />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鐢熶骇鏃ユ湡锛�" prop="schedulingDate">
- <el-date-picker
- v-model="form.schedulingDate"
- type="date"
- placeholder="璇烽�夋嫨鏃ユ湡"
- value-format="YYYY-MM-DD"
- format="YYYY-MM-DD"
- clearable
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="submitForm">纭</el-button>
- <el-button @click="closeDia">鍙栨秷</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
-</template>
-
-<script setup>
-import {ref} from "vue";
-// import {getStaffJoinInfo, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
-import {productionReport, productionReportUpdate} from "@/api/productionManagement/productionReporting.js";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits(['close'])
-
-const userList = ref([])
-const dialogFormVisible = ref(false);
-const operationType = ref('')
-const data = reactive({
- form: {
- successNum: "",
- schedulingNum: "",
- finishedNum: "",
- schedulingUserId: "",
- schedulingDate: "",
- unitPrice: "",
- totalPrice: "",
- },
- rules: {
- schedulingNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" },],
- },
-});
-const { form, rules } = toRefs(data);
-
-// 鎵撳紑寮规
-const openDialog = (type, row) => {
- operationType.value = type;
- dialogFormVisible.value = true;
- userListNoPageByTenantId().then((res) => {
- userList.value = res.data;
- });
- form.value = {...row}
-}
-
-const changeNum = (value) => {
- if (value > form.value.schedulingNum) {
- form.value.finishedNum = form.value.schedulingNum;
- proxy.$modal.msgWarning('鏈鐢熶骇鏁伴噺涓嶅彲澶т簬鎺掍骇鏁伴噺')
- }
- form.value.pendingNum = form.value.schedulingNum - form.value.finishedNum;
- calculateTotalPrice();
-}
-
-// 璁$畻鎬讳环
-const calculateTotalPrice = () => {
- const quantity = Number(form.value.finishedNum ?? 0);
- const unitPrice = Number(form.value.unitPrice ?? 0);
-
- if (quantity > 0 && unitPrice > 0) {
- form.value.totalPrice = (quantity * unitPrice).toFixed(2);
- } else {
- form.value.totalPrice = '0.00';
- }
-}
-// 鎻愪氦浜у搧琛ㄥ崟
-const submitForm = () => {
- proxy.$refs.formRef.validate(valid => {
- if (valid) {
- form.value.staffState = 1
- if (operationType.value === "add") {
- productionReport(form.value).then(res => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
- closeDia();
- })
- } else {
- productionReportUpdate(form.value).then(res => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
- closeDia();
- })
- }
- }
- })
-}
-
-// 鍏抽棴寮规
-const closeDia = () => {
- proxy.resetForm("formRef");
- dialogFormVisible.value = false;
- emit('close')
-};
-defineExpose({
- openDialog,
-});
-</script>
-
-<style scoped>
-
-</style>
\ No newline at end of file
diff --git a/src/views/productionManagement/productionReporting/index.vue b/src/views/productionManagement/productionReporting/index.vue
index 4bf8452..08fc2a6 100644
--- a/src/views/productionManagement/productionReporting/index.vue
+++ b/src/views/productionManagement/productionReporting/index.vue
@@ -11,11 +11,19 @@
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="鐝粍:">
- <el-input v-model="searchForm.teamName"
- placeholder="璇疯緭鍏�"
- clearable
- style="width: 160px;"
- @keyup.enter="handleQuery" />
+ <el-select v-model="searchForm.teamName"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery">
+ <el-option label="鐧界彮"
+ value="鐧界彮" />
+ <el-option label="澶滅彮"
+ value="澶滅彮" />
+ </el-select>
+ <!-- <el-input v-model="searchForm.teamName"
+ placeholder="璇疯緭鍏�""
+ @keyup.enter="handleQuery" /> -->
</el-form-item>
<el-form-item label="浜у搧鍚嶇О:">
<el-input v-model="searchForm.productName"
@@ -57,14 +65,12 @@
</template>
</PIMTable>
</div>
- <ReportingDialog v-model:visible="dialogVisible"
- :data="form"
- @completed="handleQuery" />
</div>
</template>
<script setup>
import { onMounted, ref, reactive, getCurrentInstance } from "vue";
+ import { useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import {
@@ -74,21 +80,23 @@
productionReportDelete,
} from "@/api/productionManagement/productionReporting.js";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
- import ReportingDialog from "./components/ReportingDialog.vue";
+ const router = useRouter();
const { proxy } = getCurrentInstance();
const tableColumn = ref([
{
label: "鐢熶骇璁㈠崟鍙�",
prop: "orderNo",
- width: "150px",
},
{
label: "鐝粍",
prop: "teamName",
width: "120px",
dataType: "tag",
+ formatType: params => {
+ return params === "鐧界彮" ? "primary" : "warning";
+ },
},
{
label: "浜у搧缂栫爜",
@@ -191,7 +199,7 @@
{
id: 1,
orderNo: "PO202401001",
- teamName: "鐢熶骇涓�缁�",
+ teamName: "鐧界彮",
materialCode: "PC001",
productName: "鏍囧噯鐮屽潡",
specification: "600脳240脳200",
@@ -204,7 +212,7 @@
{
id: 2,
orderNo: "PO202401002",
- teamName: "鐢熶骇浜岀粍",
+ teamName: "澶滅彮",
materialCode: "PC002",
productName: "鏍囧噯鐮屽潡",
specification: "600脳240脳200",
@@ -217,7 +225,7 @@
{
id: 3,
orderNo: "PO202401003",
- teamName: "鐢熶骇涓夌粍",
+ teamName: "鐧界彮",
materialCode: "PC003",
productName: "鍔犳皵鐮屽潡",
specification: "600脳240脳250",
@@ -230,7 +238,7 @@
{
id: 4,
orderNo: "PO202401004",
- teamName: "鐢熶骇涓�缁�",
+ teamName: "鐧界彮",
materialCode: "PC004",
productName: "鏍囧噯鐮屽潡",
specification: "600脳240脳200",
@@ -243,7 +251,7 @@
{
id: 5,
orderNo: "PO202401005",
- teamName: "鐢熶骇浜岀粍",
+ teamName: "澶滅彮",
materialCode: "PC005",
productName: "鍔犳皵鐮屽潡",
specification: "600脳240脳250",
@@ -256,7 +264,7 @@
{
id: 6,
orderNo: "PO202401006",
- teamName: "鐢熶骇涓夌粍",
+ teamName: "鐧界彮",
materialCode: "PC006",
productName: "鏍囧噯鐮屽潡",
specification: "600脳240脳200",
@@ -269,7 +277,7 @@
{
id: 7,
orderNo: "PO202401007",
- teamName: "鐢熶骇涓�缁�",
+ teamName: "鐧界彮",
materialCode: "PC007",
productName: "鍔犳皵鐮屽潡",
specification: "600脳240脳250",
@@ -282,7 +290,7 @@
{
id: 8,
orderNo: "PO202401008",
- teamName: "鐢熶骇浜岀粍",
+ teamName: "澶滅彮",
materialCode: "PC008",
productName: "鏍囧噯鐮屽潡",
specification: "600脳240脳200",
@@ -295,7 +303,7 @@
{
id: 9,
orderNo: "PO202401009",
- teamName: "鐢熶骇涓夌粍",
+ teamName: "鐧界彮",
materialCode: "PC009",
productName: "鍔犳皵鐮屽潡",
specification: "600脳240脳250",
@@ -308,7 +316,7 @@
{
id: 10,
orderNo: "PO202401010",
- teamName: "鐢熶骇涓�缁�",
+ teamName: "鐧界彮",
materialCode: "PC010",
productName: "鏍囧噯鐮屽潡",
specification: "600脳240脳200",
@@ -320,7 +328,6 @@
},
];
- const dialogVisible = ref(false);
const form = reactive({
id: undefined,
orderId: "",
@@ -387,7 +394,10 @@
processId: "",
params: {},
});
- dialogVisible.value = true;
+ router.push({
+ path: "/productionManagement/ReportingDialog",
+ query: { data: JSON.stringify(form) },
+ });
};
const handleEdit = row => {
@@ -407,7 +417,10 @@
processId: row.processId || "",
params: row.params || {},
});
- dialogVisible.value = true;
+ router.push({
+ path: "/productionManagement/ReportingDialog",
+ query: { data: JSON.stringify(form) },
+ });
};
const handleDetail = row => {
diff --git a/src/views/productionManagement/productionReporting/index2.vue b/src/views/productionManagement/productionReporting/index2.vue
deleted file mode 100644
index 0b42dae..0000000
--- a/src/views/productionManagement/productionReporting/index2.vue
+++ /dev/null
@@ -1,420 +0,0 @@
-<template>
- <div class="app-container">
- <div class="search_form">
- <el-form :model="searchForm"
- :inline="true">
- <el-form-item label="鎶ュ伐浜哄憳鍚嶇О:">
- <el-input v-model="searchForm.nickName"
- placeholder="璇疯緭鍏�"
- clearable
- prefix-icon="Search"
- style="width: 200px;"
- @change="handleQuery" />
- </el-form-item>
- <el-form-item label="宸ュ崟鍙�:">
- <el-input v-model="searchForm.workOrderNo"
- placeholder="璇疯緭鍏�"
- clearable
- prefix-icon="Search"
- style="width: 200px;"
- @change="handleQuery" />
- </el-form-item>
- <el-form-item>
- <el-button type="primary"
- @click="handleQuery">鎼滅储</el-button>
- </el-form-item>
- </el-form>
- </div>
- <div class="table_list">
- <div style="text-align: right"
- class="mb10">
- <!-- <el-button type="primary"
- @click="openForm('add')">鐢熶骇鎶ュ伐</el-button> -->
- <el-button @click="handleOut">瀵煎嚭</el-button>
- </div>
- <PIMTable rowKey="id"
- :column="tableColumn"
- :tableData="tableData"
- :page="page"
- :isSelection="true"
- :expandRowKeys="expandedRowKeys"
- @expand-change="expandChange"
- @selection-change="handleSelectionChange"
- :tableLoading="tableLoading"
- @pagination="pagination"
- :total="page.total">
- <template #expand="{ row }">
- <el-table :data="expandData"
- border
- show-summary
- :summary-method="summarizeMainTable"
- v-loading="childrenLoading">
- <el-table-column align="center"
- label="搴忓彿"
- type="index"
- width="60" />
- <el-table-column label="鏈鐢熶骇鏁伴噺"
- prop="finishedNum"
- align="center"
- width="400">
- <template #default="scope">
- <el-input-number :step="0.01"
- :min="0"
- style="width: 100%"
- v-model="scope.row.finishedNum"
- :disabled="!scope.row.editType"
- :precision="2"
- placeholder="璇疯緭鍏�"
- clearable
- @change="changeNum(scope.row)" />
- </template>
- </el-table-column>
- <!-- <el-table-column label="寰呯敓浜ф暟閲�" prop="pendingNum" width="240" align="center"></el-table-column>-->
- <el-table-column label="鐢熶骇浜�"
- prop="schedulingUserId"
- width="400">
- <template #default="scope">
- <el-select v-model="scope.row.schedulingUserId"
- placeholder="閫夋嫨浜哄憳"
- :disabled="!scope.row.editType"
- style="width: 100%;">
- <el-option v-for="user in userList"
- :key="user.userId"
- :label="user.nickName"
- :value="user.userId" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="鐢熶骇鏃ユ湡"
- prop="schedulingDate"
- width="400">
- <template #default="scope">
- <el-date-picker v-model="scope.row.schedulingDate"
- type="date"
- :disabled="!scope.row.editType"
- placeholder="璇烽�夋嫨鏃ユ湡"
- value-format="YYYY-MM-DD"
- format="YYYY-MM-DD"
- clearable
- style="width: 100%" />
- </template>
- </el-table-column>
- <el-table-column label="鎿嶄綔"
- >
- <template #default="scope">
- <el-button link
- type="primary"
- size="small"
- @click="changeEditType(scope.row)"
- v-if="!scope.row.editType"
- :disabled="scope.row.parentStatus === 3">缂栬緫</el-button>
- <el-button link
- type="primary"
- size="small"
- @click="saveReceiptPayment(scope.row)"
- v-if="scope.row.editType">淇濆瓨</el-button>
- </template>
- </el-table-column>
- </el-table>
- </template>
- </PIMTable>
- </div>
- <form-dia ref="formDia"
- @close="handleQuery"></form-dia>
- <input-modal v-if="isShowInput"
- v-model:visible="isShowInput"
- :production-product-main-id="isShowingId" />
- </div>
-</template>
-
-<script setup>
- import { onMounted, ref } from "vue";
- import FormDia from "@/views/productionManagement/productionReporting/components/formDia.vue";
- import { ElMessageBox } from "element-plus";
- import {
- productionReportUpdate,
- workListPageById,
- productionReportDelete,
- } from "@/api/productionManagement/productionReporting.js";
- import { productionProductMainListPage } from "@/api/productionManagement/productionProductMain.js";
- import { userListNoPageByTenantId } from "@/api/system/user.js";
- import InputModal from "@/views/productionManagement/productionReporting/Input.vue";
-
- const data = reactive({
- searchForm: {
- nickName: "",
- workOrderNo: "",
- workOrderStatus: "",
- },
- });
- const { searchForm } = toRefs(data);
- const expandedRowKeys = ref([]);
- const expandData = ref([]);
- const userList = ref([]);
- const tableColumn = ref([
- {
- label: "鎶ュ伐鍗曞彿",
- prop: "productNo",
- width: 120,
- },
- {
- label: "鎶ュ伐浜哄憳",
- prop: "nickName",
- width: 120,
- },
- {
- label: "宸ュ簭",
- prop: "process",
- width: 120,
- },
- {
- label: "宸ュ崟缂栧彿",
- prop: "workOrderNo",
- width: 120,
- },
- {
- label: "閿�鍞悎鍚屽彿",
- prop: "salesContractNo",
- width: 120,
- },
- {
- label: "浜у搧鍚嶇О",
- prop: "productName",
- width: 120,
- },
- {
- label: "浜у搧瑙勬牸鍨嬪彿",
- prop: "productModelName",
- width: 120,
- },
- {
- label: "浜у嚭鏁伴噺",
- prop: "quantity",
- width: 120,
- },
- {
- label: "鎶ュ簾鏁伴噺",
- prop: "scrapQty",
- width: 120,
- },
- {
- label: "鍗曚綅",
- prop: "unit",
- width: 120,
- },
-
- {
- label: "鍒涘缓鏃堕棿",
- prop: "createTime",
- width: 120,
- },
- {
- dataType: "action",
- label: "鎿嶄綔",
- align: "center",
- fixed: "right",
- operation: [
- {
- name: "鏌ョ湅鎶曞叆",
- type: "text",
- clickFun: row => {
- showInput(row);
- },
- },
- {
- name: "鍒犻櫎",
- type: "danger",
- clickFun: row => {
- deleteReport(row);
- },
- },
- ],
- },
- ]);
- const tableData = ref([]);
- const selectedRows = ref([]);
- const tableLoading = ref(false);
- const childrenLoading = ref(false);
- const page = reactive({
- current: 1,
- size: 100,
- total: 0,
- });
- const formDia = ref();
- const { proxy } = getCurrentInstance();
-
- // 鏌ヨ鍒楄〃
- /** 鎼滅储鎸夐挳鎿嶄綔 */
- const handleQuery = () => {
- page.current = 1;
- getList();
- };
- const changeDaterange = value => {
- if (value) {
- searchForm.value.entryDateStart = value[0];
- searchForm.value.entryDateEnd = value[1];
- } else {
- searchForm.value.entryDateStart = undefined;
- searchForm.value.entryDateEnd = undefined;
- }
- handleQuery();
- };
- const deleteReport = row => {
- ElMessageBox.confirm("纭畾鍒犻櫎璇ユ姤宸ュ悧锛�", "鎻愮ず", {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- }).then(() => {
- productionReportDelete({ id: row.id }).then(res => {
- if (res.code === 200) {
- proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
- getList();
- } else {
- ElMessageBox.alert(res.msg || "鍒犻櫎澶辫触", "鎻愮ず", {
- confirmButtonText: "纭畾",
- });
- }
- });
- });
- };
- const pagination = obj => {
- page.current = obj.page;
- page.size = obj.limit;
- getList();
- };
- const getList = () => {
- tableLoading.value = true;
- const params = { ...searchForm.value, ...page };
- params.entryDate = undefined;
- expandedRowKeys.value = [];
- productionProductMainListPage(params)
- .then(res => {
- tableLoading.value = false;
- tableData.value = res.data.records.map(item => ({
- ...item,
- pendingFinishNum:
- (Number(item.schedulingNum) || 0) - (Number(item.finishedNum) || 0),
- }));
- page.total = res.data.total;
- })
- .catch(err => {
- tableLoading.value = false;
- });
- };
- // 灞曞紑琛�
- const expandChange = (row, expandedRows) => {
- userListNoPageByTenantId().then(res => {
- userList.value = res.data;
- });
- if (expandedRows.length > 0) {
- nextTick(() => {
- expandedRowKeys.value = [];
- try {
- childrenLoading.value = true;
- workListPageById({ id: row.id }).then(res => {
- childrenLoading.value = false;
- const index = tableData.value.findIndex(item => item.id === row.id);
- if (index > -1) {
- expandData.value = res.data.map(item => ({
- ...item,
- pendingNum:
- (Number(item.schedulingNum) || 0) -
- (Number(item.finishedNum) || 0),
- parentStatus: row.status, // 鏂板鐖惰〃鐘舵��
- }));
- }
- expandedRowKeys.value.push(row.id);
- });
- } catch (error) {
- childrenLoading.value = false;
- console.log(error);
- }
- });
- } else {
- expandedRowKeys.value = [];
- }
- };
- const changeNum = row => {
- // 鎵惧埌鐖惰〃鏍兼暟鎹�
- const parentRow = tableData.value.find(
- item => item.id === expandedRowKeys.value[0]
- );
- // 璁$畻鎵�鏈夊瓙琛ㄦ牸 finishedNum 鐨勬�诲拰
- const totalFinishedNum = expandData.value.reduce(
- (sum, item) => sum + (Number(item.finishedNum) || 0),
- 0
- );
- // 鐖惰〃鏍肩殑鎺掍骇鏁伴噺
- const schedulingNum = parentRow ? Number(parentRow.schedulingNum) : 0;
-
- if (totalFinishedNum > schedulingNum) {
- // 鍥為��鏈杈撳叆
- row.finishedNum =
- schedulingNum - (totalFinishedNum - Number(row.finishedNum));
- proxy.$modal.msgWarning("鎵�鏈夋湰娆$敓浜ф暟閲忎箣鍜屼笉鍙ぇ浜庢帓浜ф暟閲�");
- }
- row.pendingNum = row.schedulingNum - row.finishedNum;
- };
- // 缂栬緫淇敼鐘舵��
- const changeEditType = row => {
- row.editType = !row.editType;
- };
- // 淇濆瓨璁板綍
- const saveReceiptPayment = row => {
- productionReportUpdate(row).then(res => {
- row.editType = !row.editType;
- getList();
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
- });
- };
- // 琛ㄦ牸閫夋嫨鏁版嵁
- const handleSelectionChange = selection => {
- selectedRows.value = selection;
- };
- const summarizeMainTable = param => {
- return proxy.summarizeTable(param, ["finishedNum"]);
- };
- // 鎵撳紑寮规
- const openForm = (type, row) => {
- if (selectedRows.value.length !== 1) {
- proxy.$message.error("璇烽�夋嫨涓�鏉℃暟鎹�");
- return;
- }
- if (selectedRows.value[0].pendingFinishNum == 0) {
- proxy.$message.warning("鏃犻渶鍐嶆姤宸�");
- return;
- }
- nextTick(() => {
- const rowInfo = type === "add" ? selectedRows.value[0] : row;
- formDia.value?.openDialog(type, rowInfo);
- });
- };
-
- // 鎵撳紑鎶曞叆妯℃�佹
- const isShowInput = ref(false);
- const isShowingId = ref(0);
- const showInput = row => {
- isShowInput.value = true;
- isShowingId.value = row.id;
- };
-
- // 瀵煎嚭
- const handleOut = () => {
- ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
- confirmButtonText: "纭",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- })
- .then(() => {
- proxy.download("/productionProductMain/export", {}, "鐢熶骇鎶ュ伐.xlsx");
- })
- .catch(() => {
- proxy.$modal.msg("宸插彇娑�");
- });
- };
- onMounted(() => {
- getList();
- });
-</script>
-
-<style scoped></style>
diff --git a/src/views/productionManagement/productionReporting/reportingDialog.vue b/src/views/productionManagement/productionReporting/reportingDialog.vue
new file mode 100644
index 0000000..1c8ad3f
--- /dev/null
+++ b/src/views/productionManagement/productionReporting/reportingDialog.vue
@@ -0,0 +1,1647 @@
+<template>
+ <div class="reporting-page">
+ <!-- 椤甸潰澶撮儴 -->
+ <PageHeader content="鐢熶骇宸ュ崟鎶ュ伐">
+ </PageHeader>
+ <!-- 姝ラ鎸囩ず鍣� -->
+ <div class="step-indicator">
+ <div v-for="(step, index) in steps"
+ :key="index"
+ class="step-item"
+ :class="{
+ 'active': index === activeStep,
+ 'completed': index < activeStep
+ }">
+ <div class="step-circle">
+ <span v-if="index < activeStep"
+ class="step-check">
+ <el-icon>
+ <Check />
+ </el-icon>
+ </span>
+ <span v-else
+ class="step-number">{{ index + 1 }}</span>
+ </div>
+ <div class="step-content">
+ <div class="step-title">{{ step.title }}</div>
+ <div class="step-description">{{ step.description }}</div>
+ </div>
+ <div class="step-line"
+ v-if="index < steps.length - 1"></div>
+ </div>
+ </div>
+ <!-- 椤甸潰鍐呭 -->
+ <div class="page-content">
+ <!-- 绗竴姝ワ細閫夋嫨鐢熶骇璁㈠崟 -->
+ <div v-if="activeStep === 0"
+ class="step-panel">
+ <div class="panel-header">
+ <div>
+ <h3 class="panel-title">閫夋嫨鐢熶骇璁㈠崟</h3>
+ <p class="panel-subtitle">璇蜂粠浠ヤ笅鍒楄〃涓�夋嫨闇�瑕佹姤宸ョ殑鐢熶骇璁㈠崟</p>
+ </div>
+ <div class="header-actions">
+ <el-button @click="activeStep--"
+ v-if="activeStep > 0"
+ :disabled="isSubmitting">
+ <el-icon>
+ <ArrowLeft />
+ </el-icon> 涓婁竴姝�
+ </el-button>
+ <el-button type="primary"
+ @click="handleNextStep"
+ v-if="activeStep < 3"
+ :disabled="isSubmitting">
+ 涓嬩竴姝� <el-icon>
+ <ArrowRight />
+ </el-icon>
+ </el-button>
+ </div>
+ </div>
+ <el-form :model="form"
+ ref="formRef"
+ class="form-container">
+ <el-form-item label="鐢熶骇璁㈠崟"
+ prop="orderId"
+ required>
+ <el-select v-model="orderId"
+ placeholder="璇烽�夋嫨鐢熶骇璁㈠崟"
+ clearable
+ filterable
+ class="form-select"
+ :loading="orderLoading"
+ @change="handleOrderChange">
+ <el-option v-for="order in orderList"
+ :key="order.id"
+ :label="`${order.npsNo} - ${order.productName} ${order.model}`"
+ :value="order.id" />
+ </el-select>
+ </el-form-item>
+ </el-form>
+ </div>
+ <!-- 绗簩姝ワ細濉啓鍩虹淇℃伅 -->
+ <div v-else-if="activeStep === 1"
+ class="step-panel">
+ <div class="panel-header">
+ <div>
+ <h3 class="panel-title">濉啓鍩虹淇℃伅</h3>
+ <p class="panel-subtitle">璇峰~鍐欐姤宸ョ殑鍩烘湰淇℃伅</p>
+ </div>
+ <div class="header-actions">
+ <el-button @click="activeStep--"
+ v-if="activeStep > 0"
+ :disabled="isSubmitting">
+ <el-icon>
+ <ArrowLeft />
+ </el-icon> 涓婁竴姝�
+ </el-button>
+ <el-button type="primary"
+ @click="handleNextStep"
+ v-if="activeStep < 3"
+ :disabled="isSubmitting">
+ 涓嬩竴姝� <el-icon>
+ <ArrowRight />
+ </el-icon>
+ </el-button>
+ </div>
+ </div>
+ <el-form :model="form"
+ :rules="rules"
+ ref="formRef"
+ class="form-container">
+ <div class="form-grid">
+ <el-form-item label="鐢熶骇璁㈠崟鍙�"
+ prop="npsNo"
+ class="form-item">
+ <el-input disabled
+ v-model="form.npsNo"
+ class="form-input" />
+ </el-form-item>
+ <el-form-item label="浜у搧缂栫爜"
+ prop="materialCode"
+ class="form-item">
+ <el-input disabled
+ v-model="form.materialCode"
+ class="form-input" />
+ </el-form-item>
+ <el-form-item label="浜у搧鍚嶇О"
+ prop="productName"
+ class="form-item">
+ <el-input disabled
+ v-model="form.productName"
+ class="form-input" />
+ </el-form-item>
+ <el-form-item label="瑙勬牸"
+ prop="specification"
+ class="form-item">
+ <el-input disabled
+ v-model="form.specification"
+ class="form-input" />
+ </el-form-item>
+ <el-form-item label="鍒涘缓鏃堕棿"
+ prop="createTime"
+ class="form-item">
+ <el-date-picker disabled
+ v-model="form.createTime"
+ type="datetime"
+ placeholder="璇烽�夋嫨鍒涘缓鏃堕棿"
+ class="form-input" />
+ </el-form-item>
+ <el-form-item label="鐝粍"
+ prop="teamName"
+ required
+ class="form-item">
+ <el-select v-model="form.teamName"
+ placeholder="璇烽�夋嫨鐝粍"
+ class="form-select">
+ <el-option label="鐧界彮"
+ value="鐧界彮" />
+ <el-option label="澶滅彮"
+ value="澶滅彮" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍒涘缓浜�"
+ prop="createBy"
+ required
+ class="form-item">
+ <el-select v-model="form.createBy"
+ placeholder="璇烽�夋嫨鍒涘缓浜�"
+ class="form-select"
+ :loading="userLoading">
+ <el-option v-for="user in userList"
+ :key="user.id"
+ :label="user.nickName || user.userName"
+ :value="user.nickName || user.userName" />
+ </el-select>
+ </el-form-item>
+ </div>
+ </el-form>
+ </div>
+ <!-- 绗笁姝ワ細鏌ョ湅宸ュ簭鍙傛暟 -->
+ <div v-else-if="activeStep === 2"
+ class="step-panel process-panel">
+ <div class="panel-header">
+ <div>
+ <h3 class="panel-title">宸ュ簭鍙傛暟绠$悊</h3>
+ <p class="panel-subtitle">璇锋煡鐪嬪苟濉啓鍚勫伐搴忕殑鍙傛暟淇℃伅</p>
+ </div>
+ <div class="header-actions">
+ <el-button @click="activeStep--"
+ v-if="activeStep > 0"
+ :disabled="isSubmitting">
+ <el-icon>
+ <ArrowLeft />
+ </el-icon> 涓婁竴姝�
+ </el-button>
+ <el-button type="primary"
+ @click="handleNextStep"
+ v-if="activeStep < 3"
+ :disabled="isSubmitting">
+ 涓嬩竴姝� <el-icon>
+ <ArrowRight />
+ </el-icon>
+ </el-button>
+ </div>
+ </div>
+ <div class="process-container">
+ <!-- 宸︿晶宸ュ簭瀵艰埅 -->
+ <div class="process-nav">
+ <div v-for="process in processList"
+ :key="process.processId"
+ class="process-nav-item"
+ :class="{ 'active': activeProcessId === process.processId + '' }"
+ @click="handleProcessClick(process.processId)">
+ <span class="process-name">{{ process.processName }}</span>
+ <span class="process-badge"
+ v-if="getProcessInfo(parseInt(process.processId)).postPersonnel">
+ {{ getProcessInfo(parseInt(process.processId)).postPersonnel }}
+ </span>
+ </div>
+ </div>
+ <!-- 鍙充晶宸ュ簭鍐呭 -->
+ <div class="process-content">
+ <div v-if="activeProcessId"
+ class="process-details">
+ <!-- 鍥哄畾鍙傛暟 -->
+ <div class="param-section">
+ <div class="section-header">
+ <h4 class="section-title">宸ュ簭鍩烘湰淇℃伅</h4>
+ </div>
+ <div class="param-form">
+ <el-form :label-position="'top'">
+ <div class="form-grid">
+ <el-form-item label="宀椾綅浜哄憳"
+ class="form-item">
+ <el-select v-model="getProcessInfo(parseInt(activeProcessId)).postPersonnel"
+ placeholder="璇烽�夋嫨宀椾綅浜哄憳"
+ class="form-select"
+ :loading="userLoading">
+ <el-option v-for="user in userList"
+ :key="user.id"
+ :label="user.nickName || user.userName"
+ :value="user.nickName || user.userName" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="璁惧寮傚父鎯呭喌"
+ class="form-item">
+ <el-input v-model="getProcessInfo(parseInt(activeProcessId)).equipmentAbnormality"
+ placeholder="璇疯緭鍏ヨ澶囧紓甯告儏鍐�"
+ type="textarea"
+ :rows="2"
+ class="form-textarea" />
+ </el-form-item>
+ <el-form-item label="褰撶彮璁惧澶勭疆"
+ class="form-item">
+ <el-input v-model="getProcessInfo(parseInt(activeProcessId)).equipmentHandling"
+ placeholder="璇疯緭鍏ュ綋鐝澶囧缃�"
+ type="textarea"
+ :rows="2"
+ class="form-textarea" />
+ </el-form-item>
+ <el-form-item label="宸ヨ壓浜哄憳浜ゅ緟"
+ class="form-item">
+ <el-input v-model="getProcessInfo(parseInt(activeProcessId)).processInstructions"
+ placeholder="璇疯緭鍏ュ伐鑹轰汉鍛樹氦寰�"
+ type="textarea"
+ :rows="2"
+ class="form-textarea" />
+ </el-form-item>
+ <el-form-item label="涓婁紶鏂囦欢"
+ class="form-item"
+ :span="24">
+ <el-upload class="upload-demo upload-block"
+ action="#"
+ :on-preview="handlePreview"
+ :on-remove="handleRemove"
+ :file-list="getProcessInfo(parseInt(activeProcessId)).files || []"
+ :auto-upload="false"
+ :accept="'.jpg,.png'"
+ :max-size="500000"
+ :on-change="handleFileChange">
+ <el-button type="primary"
+ :icon="Upload">鐐瑰嚮涓婁紶</el-button>
+ <template #tip>
+ <div class="el-upload__tip">
+ 鍙兘涓婁紶jpg/png鏂囦欢锛屼笖涓嶈秴杩�500kb
+ </div>
+ </template>
+ </el-upload>
+ </el-form-item>
+ </div>
+ </el-form>
+ </div>
+ </div>
+ <!-- BOM淇℃伅 -->
+ <div class="param-section"
+ v-if="getProcessStructures(parseInt(activeProcessId)).length > 0">
+ <div class="section-header">
+ <h4 class="section-title">BOM淇℃伅</h4>
+ </div>
+ <div class="param-form">
+ <el-form :label-position="'top'">
+ <div class="form-grid">
+ <el-form-item v-for="item in getProcessStructures(parseInt(activeProcessId))"
+ :key="item.id"
+ :label="`${item.productName} ${item.model}`"
+ class="form-item">
+ <div class="consumable-input-group">
+ <el-input-number v-model="getProcessInfo(parseInt(activeProcessId)).consumables[item.id]"
+ :min="0"
+ :model-value="getConsumableValue(parseInt(activeProcessId), item.id)"
+ @change="val => getProcessInfo(parseInt(activeProcessId)).consumables[item.id] = val"
+ class="consumable-input" />
+ <span class="consumable-unit">{{ item.unit }}</span>
+ </div>
+ </el-form-item>
+ </div>
+ </el-form>
+ </div>
+ </div>
+ <!-- 鍙傛暟缁勫垪琛� -->
+ <div class="param-section">
+ <div class="section-header">
+ <h4 class="section-title">鍙傛暟缁勭鐞�</h4>
+ <div class="section-actions">
+ <el-switch v-model="useTableView"
+ active-text="琛ㄦ牸瑙嗗浘"
+ inactive-text="鍗$墖瑙嗗浘"
+ inline-prompt />
+ <el-button type="primary"
+ @click="addParamGroup(parseInt(activeProcessId))"
+ :icon="Plus">
+ 鏂板鍙傛暟缁�
+ </el-button>
+ </div>
+ </div>
+ <!-- 鍗$墖瑙嗗浘 -->
+ <div v-if="!useTableView"
+ class="param-cards">
+ <div v-for="(group, index) in form.paramGroups[activeProcessId] || []"
+ :key="index"
+ class="param-card">
+ <div class="card-header">
+ <span class="card-title">鍙傛暟缁� {{ index + 1 }}</span>
+ <el-button type="danger"
+ size="small"
+ @click="removeParamGroup(parseInt(activeProcessId), index)"
+ v-if="(form.paramGroups[activeProcessId] || []).length > 1"
+ circle>
+ <el-icon>
+ <Delete />
+ </el-icon>
+ </el-button>
+ </div>
+ <div class="card-body">
+ <div class="param-grid">
+ <el-form-item v-for="param in params"
+ :key="param.id"
+ :label="param.paramName"
+ :label-width="120"
+ :required="param.isRequired"
+ :prop="`paramGroups.${activeProcessId}.${index}.${param.id}`"
+ :rules="param.isRequired ? [{ required: true, message: `璇疯緭鍏�${param.paramName}`, trigger: 'blur' }] : []"
+ class="param-item">
+ <template v-if="param.paramType == '1'">
+ <!-- 鏁板瓧绫诲瀷 -->
+ <div class="param-input-group">
+ <el-input-number v-model="form.paramGroups[activeProcessId][index][param.id]"
+ controls-position="right"
+ :precision="getPrecision(param.paramFormat)"
+ class="param-input" />
+ <span v-if="param.unit && param.unit != '/'"
+ class="param-unit">
+ {{ param.unit }}
+ </span>
+ </div>
+ </template>
+ <template v-else-if="param.paramType == '2'">
+ <!-- 鏂囨湰绫诲瀷 -->
+ <div class="param-input-group">
+ <el-input v-model="form.paramGroups[activeProcessId][index][param.id]"
+ class="param-input" />
+ <span v-if="param.unit && param.unit != '/'"
+ class="param-unit">
+ {{ param.unit }}
+ </span>
+ </div>
+ </template>
+ <template v-else-if="param.paramType == '3'">
+ <!-- 瀛楀吀绫诲瀷 -->
+ <div class="param-input-group">
+ <el-select v-model="form.paramGroups[activeProcessId][index][param.id]"
+ placeholder="璇烽�夋嫨"
+ class="param-select"
+ style="width: 100%">
+ <el-option v-for="option in dictOptions[param.paramFormat] || []"
+ :key="option.dictValue"
+ :label="option.dictLabel"
+ :value="option.dictValue" />
+ </el-select>
+ <span v-if="param.unit && param.unit != '/'"
+ class="param-unit">
+ {{ param.unit }}
+ </span>
+ </div>
+ </template>
+ <template v-else-if="param.paramType == '4'">
+ <!-- 鏃ユ湡绫诲瀷 -->
+ <div class="param-input-group">
+ <el-date-picker :value-format="param.paramFormat"
+ :format="param.paramFormat"
+ :type="param.paramFormat=='YYYY-MM-DD'?'date':'datetime'"
+ v-model="form.paramGroups[activeProcessId][index][param.id]"
+ class="param-input" />
+ <span v-if="param.unit && param.unit != '/'"
+ class="param-unit">
+ {{ param.unit }}
+ </span>
+ </div>
+ </template>
+ <template v-else>
+ <!-- 鍏朵粬绫诲瀷 -->
+ <div class="param-input-group">
+ <el-input v-model="form.paramGroups[activeProcessId][index][param.id]"
+ class="param-input" />
+ <span v-if="param.unit && param.unit != '/'"
+ class="param-unit">
+ {{ param.unit }}
+ </span>
+ </div>
+ </template>
+ </el-form-item>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- 琛ㄦ牸瑙嗗浘 -->
+ <div v-else
+ class="param-table">
+ <el-table :data="form.paramGroups[activeProcessId] || []"
+ style="width: 100%"
+ class="table-view">
+ <!-- 鎿嶄綔鍒� -->
+ <el-table-column label="鎿嶄綔"
+ width="100"
+ fixed>
+ <template #default="{ $index }">
+ <el-button type="danger"
+ size="small"
+ @click="removeParamGroup(parseInt(activeProcessId), $index)"
+ circle>
+ <el-icon>
+ <Delete />
+ </el-icon>
+ </el-button>
+ </template>
+ </el-table-column>
+ <!-- 鍙傛暟鍒� -->
+ <el-table-column v-for="param in params"
+ :key="param.id"
+ :min-width="200">
+ <template #header>
+ <span :class="{ 'required-label': param.isRequired }">{{ param.paramName }}</span>
+ </template>
+ <template #default="{ row }">
+ <template v-if="param.paramType == '1'">
+ <!-- 鏁板瓧绫诲瀷 -->
+ <el-input-number v-model="row[param.id]"
+ controls-position="right"
+ :precision="getPrecision(param.paramFormat)"
+ class="table-input" />
+ </template>
+ <template v-else-if="param.paramType == '2'">
+ <!-- 鏂囨湰绫诲瀷 -->
+ <el-input v-model="row[param.id]"
+ class="table-input" />
+ </template>
+ <template v-else-if="param.paramType == '3'">
+ <!-- 瀛楀吀绫诲瀷 -->
+ <el-select v-model="row[param.id]"
+ placeholder="璇烽�夋嫨"
+ class="table-select">
+ <el-option v-for="option in dictOptions[param.paramFormat] || []"
+ :key="option.dictValue"
+ :label="option.dictLabel"
+ :value="option.dictValue" />
+ </el-select>
+ </template>
+ <template v-else-if="param.paramType == '4'">
+ <!-- 鏃ユ湡绫诲瀷 -->
+ <el-date-picker :value-format="param.paramFormat"
+ :format="param.paramFormat"
+ width="100%"
+ :type="param.paramFormat=='YYYY-MM-DD'?'date':'datetime'"
+ v-model="row[param.id]"
+ class="table-input table-select" />
+ </template>
+ <template v-else>
+ <!-- 鍏朵粬绫诲瀷 -->
+ <el-input v-model="row[param.id]"
+ class="table-input" />
+ </template>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ <!-- 鏂板鍙傛暟缁勬寜閽� -->
+ <!-- <div class="param-actions">
+ <el-button type="primary"
+ @click="addParamGroup(parseInt(activeProcessId))"
+ :icon="Plus">
+ 鏂板鍙傛暟缁�
+ </el-button>
+ </div> -->
+ </div>
+ </div>
+ <div v-else
+ class="empty-process">
+ <el-empty description="璇烽�夋嫨涓�涓伐搴�"
+ :image-size="120" />
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- 绗洓姝ワ細濉啓浜ч噺淇℃伅 -->
+ <div v-else-if="activeStep === 3"
+ class="step-panel">
+ <div class="panel-header">
+ <div>
+ <h3 class="panel-title">濉啓浜ч噺淇℃伅</h3>
+ <p class="panel-subtitle">璇峰~鍐欐湰娆℃姤宸ョ殑浜ч噺鏁版嵁</p>
+ </div>
+ <div class="header-actions">
+ <el-button @click="activeStep--"
+ v-if="activeStep > 0"
+ :disabled="isSubmitting">
+ <el-icon>
+ <ArrowLeft />
+ </el-icon> 涓婁竴姝�
+ </el-button>
+ <el-button type="primary"
+ @click="handleSubmit"
+ v-if="activeStep === 3"
+ :loading="isSubmitting">
+ <el-icon v-if="!isSubmitting">
+ <Check />
+ </el-icon>
+ <el-icon v-else>
+ <Loading />
+ </el-icon>
+ {{ isSubmitting ? '鎻愪氦涓�...' : '纭鎻愪氦' }}
+ </el-button>
+ </div>
+ </div>
+ <el-form :model="form"
+ :rules="rules"
+ ref="formRef"
+ :label-position="'top'"
+ class="form-container">
+ <div class="form-grid1">
+ <el-form-item label="浜у嚭鏂归噺"
+ prop="outputVolume"
+ required
+ class="form-item">
+ <div class="volume-input-group">
+ <el-input-number v-model="form.outputVolume"
+ :min="0"
+ :precision="2"
+ @change="handleVolumeChange"
+ class="volume-input" />
+ <span class="volume-unit">鏂�</span>
+ </div>
+ </el-form-item>
+ <el-form-item label="涓嶅悎鏍兼柟閲�"
+ prop="unqualifiedVolume"
+ required
+ class="form-item">
+ <div class="volume-input-group">
+ <el-input-number v-model="form.unqualifiedVolume"
+ :min="0"
+ :precision="2"
+ @change="handleVolumeChange"
+ class="volume-input" />
+ <span class="volume-unit">鏂�</span>
+ </div>
+ </el-form-item>
+ <el-form-item label="瀹屾垚鏂归噺"
+ prop="completedVolume"
+ required
+ class="form-item">
+ <div class="volume-input-group">
+ <el-input-number v-model="form.completedVolume"
+ :min="0"
+ :precision="2"
+ class="volume-input" />
+ <span class="volume-unit">鏂�</span>
+ </div>
+ </el-form-item>
+ </div>
+ </el-form>
+ </div>
+ </div>
+ <!-- 搴曢儴鎸夐挳 -->
+ </div>
+</template>
+
+<script setup>
+ import { ref, reactive, computed, watch, onMounted } from "vue";
+ import { ElMessage, ElEmpty } from "element-plus";
+ import { useRouter, useRoute } from "vue-router";
+ import { getDicts } from "@/api/system/dict/data";
+ import { productOrderListPage } from "@/api/productionManagement/productionOrder.js";
+ import { productionRecordAdd } from "@/api/productionManagement/productProcessRoute.js";
+ import { userListNoPage } from "@/api/system/user.js";
+ import { getInfo } from "@/api/login.js";
+ import {
+ Check,
+ Close,
+ Delete,
+ Plus,
+ ArrowLeft,
+ ArrowRight,
+ Loading,
+ Upload,
+ } from "@element-plus/icons-vue";
+
+ const router = useRouter();
+
+ // 浠庤矾鐢卞弬鏁拌幏鍙栨暟鎹�
+ const route = useRoute();
+ const data = route.query.data ? JSON.parse(route.query.data) : {};
+
+ const dialogTitle = computed(() => (data.id ? "缂栬緫鎶ュ伐" : "鏂板鎶ュ伐"));
+
+ const formRef = ref(null);
+ const isSubmitting = ref(false);
+ const orderLoading = ref(false);
+ const processLoading = ref(false);
+ const activeStep = ref(0);
+
+ const steps = [
+ { title: "閫夋嫨鐢熶骇璁㈠崟", description: "閫夋嫨闇�瑕佹姤宸ョ殑鐢熶骇璁㈠崟" },
+ { title: "濉啓鍩虹淇℃伅", description: "濉啓鎶ュ伐鐨勫熀鏈俊鎭�" },
+ { title: "鏌ョ湅宸ュ簭鍙傛暟", description: "濉啓鍚勫伐搴忕殑鍙傛暟淇℃伅" },
+ { title: "濉啓浜ч噺淇℃伅", description: "濉啓鏈鎶ュ伐鐨勪骇閲忔暟鎹�" },
+ ];
+
+ // 璁$畻褰撳墠宸ュ簭鐨勫弬鏁扮粍鏁伴噺
+ const paramGroupCount = computed(() => {
+ if (!activeProcessId.value) return 0;
+ return (form.paramGroups[activeProcessId.value] || []).length;
+ });
+
+ const orderId = ref(data.orderId || "");
+ const processId = ref(data.processId || "");
+ const activeProcessId = ref("");
+ const orderList = ref([]);
+ const processList = ref([]);
+ const params = ref([]);
+ const dictOptions = ref({});
+ const userList = ref([]);
+ const userLoading = ref(false);
+ const useTableView = ref(false); // 鎺у埗鏄惁浣跨敤琛ㄦ牸瑙嗗浘
+
+ const form = reactive({
+ id: data.id || undefined,
+ orderId: data.orderId || "",
+ npsNo: data.npsNo || "",
+ teamName: data.teamName || "鐧界彮",
+ materialCode: data.materialCode || "",
+ productName: data.productName || "",
+ specification: data.specification || "",
+ outputVolume: data.outputVolume || 0,
+ unqualifiedVolume: data.unqualifiedVolume || 0,
+ completedVolume: data.completedVolume || 0,
+ createBy: data.createBy || "褰撳墠鐧诲綍浜�",
+ createTime: data.createTime || new Date(),
+ paramGroups: data.paramGroups || {}, // 瀛樺偍姣忎釜宸ュ簭鐨勫弬鏁扮粍
+ processInfo: data.processInfo || {}, // 瀛樺偍姣忎釜宸ュ簭鐨勫熀鏈俊鎭�
+ });
+
+ const rules = {
+ teamName: [{ required: true, message: "璇烽�夋嫨鐝粍", trigger: "blur" }],
+ outputVolume: [
+ { required: true, message: "璇疯緭鍏ヤ骇鍑烘柟閲�", trigger: "blur" },
+ ],
+ unqualifiedVolume: [
+ { required: true, message: "璇疯緭鍏ヤ笉鍚堟牸鏂归噺", trigger: "blur" },
+ ],
+ completedVolume: [
+ { required: true, message: "璇疯緭鍏ュ畬鎴愭柟閲�", trigger: "blur" },
+ ],
+ createBy: [{ required: true, message: "璇疯緭鍏ュ垱寤轰汉", trigger: "blur" }],
+ };
+
+ // 鍔犺浇鐢熶骇璁㈠崟鍒楄〃
+ const loadOrders = () => {
+ orderLoading.value = true;
+ productOrderListPage({ pageNum: 1, pageSize: 100 })
+ .then(res => {
+ orderList.value = res.data.records || [];
+ })
+ .finally(() => {
+ orderLoading.value = false;
+ });
+ };
+ const handleVolumeChange = () => {
+ form.completedVolume = form.outputVolume - form.unqualifiedVolume;
+ };
+
+ // 澶勭悊鐢熶骇璁㈠崟閫夋嫨
+ const handleOrderChange = val => {
+ if (val) {
+ const order = orderList.value.find(item => item.id === val);
+ if (order) {
+ form.orderId = val;
+ form.npsNo = order.npsNo;
+ form.materialCode = order.materialCode;
+ form.productName = order.productName;
+ form.specification = order.model;
+ }
+ // 鍔犺浇宸ュ簭鍒楄〃
+ loadProcesses(val);
+ } else {
+ form.orderId = "";
+ form.npsNo = "";
+ form.materialCode = "";
+ form.productName = "";
+ form.specification = "";
+ processId.value = "";
+ activeProcessId.value = "";
+ processList.value = [];
+ params.value = [];
+ form.params = {};
+ }
+ };
+
+ // 鍔犺浇宸ュ簭鍒楄〃
+ const loadProcesses = orderId => {
+ processLoading.value = true;
+ // 璋冪敤鏂扮殑鎺ュ彛
+ productionRecordAdd(orderId)
+ .then(res => {
+ if (res.code === 200) {
+ const data = res.data;
+ // 鎻愬彇宸ュ簭鍒楄〃
+ processList.value = data.productionOrderRouteItemVos || [];
+ // 瀛樺偍宸ュ簭缁撴瀯鏁版嵁
+ form.processStructures = {};
+ processList.value.forEach(process => {
+ form.processStructures[process.processId] =
+ process.orderStructureVos || [];
+ });
+ // 濡傛灉鏈夊伐搴忥紝榛樿閫夋嫨绗竴涓�
+ if (processList.value.length > 0) {
+ const firstProcess = processList.value[0];
+ activeProcessId.value = firstProcess.processId + "";
+ processId.value = firstProcess.processId;
+ form.processId = firstProcess.processId;
+ // 鍔犺浇绗竴涓伐搴忕殑鍙傛暟
+ loadParams(firstProcess.processId, orderId);
+ }
+ }
+ })
+ .finally(() => {
+ processLoading.value = false;
+ });
+ };
+
+ // 澶勭悊宸ュ簭瀵艰埅鐐瑰嚮
+ const handleProcessClick = selectedProcessId => {
+ activeProcessId.value = selectedProcessId + "";
+ processId.value = selectedProcessId;
+ form.processId = selectedProcessId;
+ // 鍔犺浇鍙傛暟鍒楄〃
+ loadParams(selectedProcessId, form.orderId);
+ };
+
+ // 鑾峰彇宸ュ簭鍩烘湰淇℃伅锛屼笉瀛樺湪鍒欏垵濮嬪寲
+ const getProcessInfo = processId => {
+ if (!form.processInfo) {
+ form.processInfo = {};
+ }
+ if (!form.processInfo[processId]) {
+ form.processInfo[processId] = {
+ postPersonnel: "",
+ equipmentAbnormality: "",
+ equipmentHandling: "",
+ processInstructions: "",
+ files: [],
+ consumables: {},
+ };
+ }
+ return form.processInfo[processId];
+ };
+
+ // 鑾峰彇宸ュ簭缁撴瀯鏁版嵁锛圔OM鍒楄〃锛�
+ const getProcessStructures = processId => {
+ return form.processStructures && form.processStructures[processId]
+ ? form.processStructures[processId]
+ : [];
+ };
+
+ // 鑾峰彇娑堣�楀搧鏁伴噺锛岄粯璁や负0
+ const getConsumableValue = (processId, itemId) => {
+ const processInfo = getProcessInfo(processId);
+ if (!processInfo.consumables[itemId]) {
+ processInfo.consumables[itemId] = 0;
+ }
+ return processInfo.consumables[itemId];
+ };
+
+ // 澶勭悊鏂囦欢棰勮
+ const handlePreview = file => {
+ // 妫�鏌ユ槸鍚︽槸鍥剧墖鏂囦欢
+ if (file.raw && file.raw.type.startsWith("image/")) {
+ // 鍒涘缓鍥剧墖棰勮
+ const imageUrl = URL.createObjectURL(file.raw);
+ const image = new Image();
+ image.src = imageUrl;
+
+ // 鍒涘缓棰勮瀹瑰櫒
+ const previewContainer = document.createElement("div");
+ previewContainer.style.position = "fixed";
+ previewContainer.style.top = "0";
+ previewContainer.style.left = "0";
+ previewContainer.style.width = "100%";
+ previewContainer.style.height = "100%";
+ previewContainer.style.backgroundColor = "rgba(0, 0, 0, 0.8)";
+ previewContainer.style.display = "flex";
+ previewContainer.style.alignItems = "center";
+ previewContainer.style.justifyContent = "center";
+ previewContainer.style.zIndex = "9999";
+ previewContainer.style.cursor = "pointer";
+
+ // 娣诲姞鍥剧墖
+ previewContainer.appendChild(image);
+ image.style.maxWidth = "90%";
+ image.style.maxHeight = "90%";
+
+ // 娣诲姞鍏抽棴鍔熻兘
+ previewContainer.addEventListener("click", () => {
+ URL.revokeObjectURL(imageUrl);
+ document.body.removeChild(previewContainer);
+ });
+
+ // 娣诲姞鍒版枃妗�
+ document.body.appendChild(previewContainer);
+ }
+ };
+
+ // 澶勭悊鏂囦欢鍒犻櫎
+ const handleRemove = (file, fileList) => {
+ const processId = parseInt(activeProcessId.value);
+ if (processId) {
+ const processInfo = getProcessInfo(processId);
+ processInfo.files = fileList;
+ }
+ };
+
+ // 澶勭悊鏂囦欢鍙樻洿
+ const handleFileChange = (file, fileList) => {
+ const processId = parseInt(activeProcessId.value);
+ if (processId) {
+ const processInfo = getProcessInfo(processId);
+ processInfo.files = fileList;
+ }
+ };
+
+ // 鑾峰彇瀛楀吀鏁版嵁
+ const getDictOptions = async dictType => {
+ if (!dictType) return [];
+ if (dictOptions.value[dictType]) return dictOptions.value[dictType];
+
+ try {
+ const res = await getDicts(dictType);
+ if (res.code === 200) {
+ dictOptions.value[dictType] = res.data;
+ return res.data;
+ }
+ return [];
+ } catch (error) {
+ console.error("鑾峰彇瀛楀吀鏁版嵁澶辫触:", error);
+ return [];
+ }
+ };
+
+ // 鍔犺浇鍙傛暟鍒楄〃
+ const loadParams = (processId, orderId) => {
+ // 浠庡凡鍔犺浇鐨勫伐搴忔暟鎹腑鑾峰彇鍙傛暟鍒楄〃
+ const process = processList.value.find(
+ p => p.processId === parseInt(processId)
+ );
+ if (process) {
+ params.value = process.orderRouteItemParaVos || [];
+
+ // 鍒濆鍖栧弬鏁扮粍
+ if (!form.paramGroups[processId]) {
+ form.paramGroups[processId] = [];
+ }
+ // 濡傛灉娌℃湁鍙傛暟缁勶紝娣诲姞涓�涓粯璁ゅ弬鏁扮粍
+ if (form.paramGroups[processId].length === 0) {
+ const defaultGroup = {};
+ for (const param of params.value) {
+ defaultGroup[param.id] = param.standardValue || "";
+ // 濡傛灉鏄瓧鍏哥被鍨嬪弬鏁帮紝鑾峰彇瀛楀吀鏁版嵁
+ if (param.paramType == "3" && param.paramFormat) {
+ getDictOptions(param.paramFormat);
+ }
+ }
+ form.paramGroups[processId].push(defaultGroup);
+ }
+ }
+ };
+
+ // 鑾峰彇灏忔暟绮惧害
+ const getPrecision = format => {
+ if (!format) return 2;
+ const match = format.match(/\.(\d+)/);
+ return match ? parseInt(match[1].length) : 2;
+ };
+
+ // 澶勭悊涓嬩竴姝�
+ const handleNextStep = () => {
+ if (activeStep.value === 0) {
+ // 绗竴姝ワ細楠岃瘉鐢熶骇璁㈠崟閫夋嫨
+ if (!orderId.value) {
+ ElMessage.error("璇烽�夋嫨鐢熶骇璁㈠崟");
+ return;
+ }
+ activeStep.value = 1;
+ } else if (activeStep.value === 1) {
+ // 绗簩姝ワ細楠岃瘉鍩虹淇℃伅
+ formRef.value.validate(valid => {
+ if (valid) {
+ activeStep.value = 2;
+ }
+ });
+ } else if (activeStep.value === 2) {
+ // 绗笁姝ワ細楠岃瘉鍙傛暟蹇呭~椤�
+ let isValid = true;
+ let errorMessage = "";
+
+ // 閬嶅巻鎵�鏈夊伐搴�
+ for (const process of processList.value) {
+ const processId = process.processId;
+ const paramGroups = form.paramGroups[processId] || [];
+ const processParams = process.orderRouteItemParaVos || [];
+
+ // 鑾峰彇蹇呭~鍙傛暟
+ const requiredParams = processParams.filter(p => p.isRequired);
+
+ if (requiredParams.length > 0) {
+ // 妫�鏌ユ瘡涓弬鏁扮粍涓殑蹇呭~鍙傛暟
+ for (
+ let groupIndex = 0;
+ groupIndex < paramGroups.length;
+ groupIndex++
+ ) {
+ const group = paramGroups[groupIndex];
+ for (const param of requiredParams) {
+ const value = group[param.id];
+ if (value === undefined || value === null || value === "") {
+ isValid = false;
+ errorMessage = `宸ュ簭銆�${process.processName}銆戝弬鏁扮粍${
+ groupIndex + 1
+ }鐨勩��${param.paramName}銆戜负蹇呭~椤筦;
+ break;
+ }
+ }
+ if (!isValid) break;
+ }
+ }
+ if (!isValid) break;
+ }
+
+ if (!isValid) {
+ ElMessage.error(errorMessage);
+ return;
+ }
+
+ activeStep.value = 3;
+ }
+ };
+
+ // 澶勭悊鎻愪氦
+ const handleSubmit = () => {
+ formRef.value.validate(valid => {
+ if (valid) {
+ isSubmitting.value = true;
+ // 杩欓噷鍙互璋冪敤API杩涜鎻愪氦
+ setTimeout(() => {
+ ElMessage.success(data.id ? "淇敼鎴愬姛" : "鏂板鎴愬姛");
+ router.back();
+ isSubmitting.value = false;
+ }, 1000);
+ }
+ });
+ };
+
+ // 澶勭悊鍙栨秷
+ const handleCancel = () => {
+ router.back();
+ };
+
+ // 鏂板鍙傛暟缁�
+ const addParamGroup = processId => {
+ if (!form.paramGroups[processId]) {
+ form.paramGroups[processId] = [];
+ }
+ // 鍒涘缓涓�涓柊鐨勫弬鏁扮粍锛屼娇鐢ㄩ粯璁ゅ��
+ const newGroup = {};
+ params.value.forEach(param => {
+ newGroup[param.id] = param.standardValue || "";
+ });
+ form.paramGroups[processId].push(newGroup);
+ };
+
+ // 鍒犻櫎鍙傛暟缁�
+ const removeParamGroup = (processId, index) => {
+ if (form.paramGroups[processId] && form.paramGroups[processId].length > 1) {
+ form.paramGroups[processId].splice(index, 1);
+ }
+ };
+
+ // 鍔犺浇鐢ㄦ埛鍒楄〃
+ const loadUsers = () => {
+ userLoading.value = true;
+ userListNoPage()
+ .then(res => {
+ userList.value = res.data || [];
+ })
+ .finally(() => {
+ userLoading.value = false;
+ });
+ };
+
+ // 鑾峰彇褰撳墠鐧诲綍浜轰俊鎭�
+ const getCurrentUser = async () => {
+ try {
+ const res = await getInfo();
+ if (res && res.user) {
+ form.createBy = res.user.nickName || res.user.userName;
+ }
+ } catch (error) {
+ console.error("鑾峰彇褰撳墠鐧诲綍浜轰俊鎭け璐�:", error);
+ }
+ };
+
+ // 鍒濆鍖�
+ const init = () => {
+ // 鏃犺鏂板杩樻槸缂栬緫锛岄兘鍔犺浇璁㈠崟鍒楄〃鍜岀敤鎴峰垪琛�
+ loadOrders();
+ loadUsers();
+ getCurrentUser();
+
+ if (data.id) {
+ // 缂栬緫鏃惰缃〃鍗曟暟鎹�
+ Object.assign(form, data);
+ // 璁剧疆orderId
+ orderId.value = data.orderId || "";
+ // 濡傛灉鏈夎鍗旾D锛屽姞杞藉伐搴忓拰鍙傛暟
+ if (data.orderId) {
+ // 妯℃嫙閫夋嫨璁㈠崟鐨勬搷浣滐紝瑙﹀彂鏁版嵁鍔犺浇
+ setTimeout(() => {
+ handleOrderChange(data.orderId);
+ }, 100);
+ }
+ } else {
+ // 鏂板鏃惰缃粯璁ゅ��
+ form.createTime = new Date();
+ }
+ // 濮嬬粓浠庣涓�姝ュ紑濮�
+ activeStep.value = 0;
+ };
+
+ // 椤甸潰鍔犺浇鏃跺垵濮嬪寲
+ onMounted(() => {
+ init();
+ });
+</script>
+
+<style scoped>
+ /* 椤甸潰瀹瑰櫒 */
+ .reporting-page {
+ min-height: 100vh;
+ padding: 24px;
+ background-color: #f0f2f5;
+ }
+
+ /* 椤甸潰澶撮儴 */
+ .page-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 32px;
+ padding-bottom: 16px;
+ border-bottom: 1px solid #e8e8e8;
+ }
+
+ .page-title {
+ margin: 0;
+ font-size: 24px;
+ font-weight: 600;
+ color: #1f2329;
+ }
+
+ .header-actions {
+ display: flex;
+ gap: 12px;
+ }
+
+ /* 姝ラ鎸囩ず鍣� */
+ .step-indicator {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 32px;
+ padding: 0 16px;
+ padding-top: 16px;
+ }
+
+ .step-item {
+ display: flex;
+ align-items: center;
+ flex: 1;
+ position: relative;
+ }
+
+ .step-circle {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ background-color: #f0f0f0;
+ color: #999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ font-weight: 600;
+ z-index: 2;
+ transition: all 0.3s ease;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+
+ .step-item.active .step-circle {
+ background-color: #1890ff;
+ color: white;
+ box-shadow: 0 0 0 8px rgba(24, 144, 255, 0.1);
+ }
+
+ .step-item.completed .step-circle {
+ background-color: #52c41a;
+ color: white;
+ box-shadow: 0 0 0 8px rgba(82, 196, 26, 0.1);
+ }
+
+ .step-check {
+ font-size: 20px;
+ }
+
+ .step-content {
+ margin-left: 16px;
+ flex: 1;
+ }
+
+ .step-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #666;
+ margin-bottom: 4px;
+ transition: color 0.3s ease;
+ }
+
+ .step-item.active .step-title {
+ color: #1890ff;
+ }
+
+ .step-item.completed .step-title {
+ color: #52c41a;
+ }
+
+ .step-description {
+ font-size: 12px;
+ color: #999;
+ }
+
+ .step-line {
+ position: absolute;
+ top: 20px;
+ left: 50%;
+ right: -50%;
+ height: 2px;
+ background-color: #e8e8e8;
+ z-index: 1;
+ transition: all 0.3s ease;
+ }
+
+ .step-item.completed .step-line {
+ background-color: #52c41a;
+ }
+
+ /* 椤甸潰鍐呭 */
+ .page-content {
+ background-color: white;
+ border-radius: 12px;
+ padding: 0;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ margin-bottom: 32px;
+ overflow: hidden;
+ }
+
+ /* 姝ラ闈㈡澘 */
+ .step-panel {
+ padding: 32px;
+ }
+
+ .panel-header {
+ margin-bottom: 24px;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ }
+
+ .panel-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #1f2329;
+ margin: 0 0 8px 0;
+ }
+
+ .panel-subtitle {
+ font-size: 14px;
+ color: #666;
+ margin: 0;
+ }
+
+ .header-actions {
+ display: flex;
+ gap: 12px;
+ align-items: center;
+ }
+
+ /* 琛ㄥ崟瀹瑰櫒 */
+ .form-container {
+ width: 100%;
+ }
+
+ /* 涓婁紶缁勪欢鏍峰紡 */
+ .upload-block {
+ display: block;
+ }
+
+ .upload-block .el-upload__tip {
+ margin-top: 8px;
+ }
+
+ /* BOM杈撳叆缁勬牱寮� */
+ .consumable-input-group {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .consumable-input {
+ flex: 1;
+ }
+
+ .consumable-unit {
+ font-size: 14px;
+ color: #666;
+ white-space: nowrap;
+ }
+
+ /* 蹇呭~鏍囪瘑鏍峰紡 */
+ .required-label::before {
+ content: "*";
+ color: #f56c6c;
+ margin-right: 4px;
+ }
+
+ .form-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ gap: 20px;
+ }
+ .form-grid1 {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
+ gap: 20px;
+ }
+
+ .form-item {
+ margin-bottom: 0;
+ }
+
+ .form-select,
+ .form-input {
+ width: 100%;
+ }
+
+ .form-textarea {
+ width: 100%;
+ resize: vertical;
+ }
+
+ /* 浜ч噺杈撳叆缁� */
+ .volume-input-group {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .volume-input {
+ flex: 1;
+ width: 100%;
+ }
+
+ .volume-unit {
+ font-size: 14px;
+ color: #666;
+ white-space: nowrap;
+ }
+
+ /* 宸ュ簭瀹瑰櫒 */
+ .process-container {
+ display: flex;
+ gap: 24px;
+ min-height: 500px;
+ }
+
+ /* 宸ュ簭瀵艰埅 */
+ .process-nav {
+ width: 200px;
+ background-color: #fafafa;
+ border-radius: 8px;
+ padding: 16px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+ overflow-y: auto;
+ }
+
+ .process-nav-item {
+ padding: 12px 16px;
+ margin-bottom: 8px;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-size: 14px;
+ font-weight: 500;
+ color: #666;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .process-nav-item:hover {
+ background-color: #e6f7ff;
+ color: #1890ff;
+ }
+
+ .process-nav-item.active {
+ background-color: #1890ff;
+ color: white;
+ box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3);
+ }
+
+ .process-badge {
+ font-size: 12px;
+ background-color: rgba(255, 255, 255, 0.2);
+ padding: 2px 8px;
+ border-radius: 10px;
+ }
+
+ /* 宸ュ簭鍐呭 */
+ .process-content {
+ flex: 1;
+ overflow-y: auto;
+ }
+
+ .empty-process {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 400px;
+ }
+
+ /* 鍙傛暟閮ㄥ垎 */
+ .param-section {
+ margin-bottom: 32px;
+ padding: 24px;
+ background-color: #fafafa;
+ border-radius: 8px;
+ }
+
+ .section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ }
+
+ .section-title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #1f2329;
+ margin: 0;
+ }
+
+ .section-actions {
+ display: flex;
+ gap: 8px;
+ }
+
+ /* 鍙傛暟琛ㄥ崟 */
+ .param-form {
+ background-color: white;
+ padding: 20px;
+ border-radius: 8px;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+ }
+
+ /* 鍙傛暟鍗$墖 */
+ .param-cards {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ }
+
+ .param-card {
+ background-color: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ overflow: hidden;
+ transition: all 0.3s ease;
+ }
+
+ .param-card:hover {
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+ transform: translateY(-2px);
+ }
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 16px 20px;
+ background-color: #fafafa;
+ border-bottom: 1px solid #e8e8e8;
+ }
+
+ .card-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #1f2329;
+ }
+
+ .card-body {
+ padding: 20px;
+ }
+
+ /* 鍙傛暟缃戞牸 */
+ .param-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
+ gap: 16px;
+ }
+
+ .param-item {
+ margin-bottom: 0;
+ }
+
+ .param-input-group {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ width: 100%;
+ }
+
+ .param-input,
+ .param-select {
+ flex: 1;
+ }
+
+ .param-unit {
+ font-size: 14px;
+ color: #666;
+ white-space: nowrap;
+ }
+
+ /* 琛ㄦ牸瑙嗗浘 */
+ .param-table {
+ margin: 16px 0;
+ }
+
+ .table-view {
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ .table-view th {
+ background-color: #fafafa;
+ font-weight: 600;
+ }
+
+ .table-input,
+ .table-select {
+ width: 100%;
+ }
+
+ /* 鍙傛暟鎿嶄綔 */
+ .param-actions {
+ margin-top: 16px;
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ /* 椤甸潰搴曢儴 */
+ .page-footer {
+ display: flex;
+ justify-content: center;
+ padding: 24px;
+ background-color: white;
+ border-top: 1px solid #e8e8e8;
+ border-radius: 0 0 12px 12px;
+ }
+
+ .footer-actions {
+ display: flex;
+ gap: 12px;
+ }
+
+ /* 鍝嶅簲寮忚璁� */
+ @media (max-width: 1024px) {
+ .form-grid {
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ }
+
+ .param-grid {
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ }
+ }
+
+ @media (max-width: 768px) {
+ .reporting-page {
+ padding: 16px;
+ }
+
+ .step-indicator {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 16px;
+ padding: 0;
+ }
+
+ .step-item {
+ flex-direction: row;
+ width: 100%;
+ }
+
+ .step-line {
+ display: none;
+ }
+
+ .step-panel {
+ padding: 20px;
+ }
+
+ .form-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .process-container {
+ flex-direction: column;
+ }
+
+ .process-nav {
+ width: 100%;
+ margin-bottom: 16px;
+ }
+
+ .param-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .footer-actions {
+ flex-direction: column;
+ width: 100%;
+ }
+
+ .footer-actions button {
+ width: 100%;
+ }
+ }
+
+ /* 婊氬姩鏉℃牱寮� */
+ .process-nav::-webkit-scrollbar,
+ .process-content::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+ }
+
+ .process-nav::-webkit-scrollbar-track,
+ .process-content::-webkit-scrollbar-track {
+ background: #f1f1f1;
+ border-radius: 3px;
+ }
+
+ .process-nav::-webkit-scrollbar-thumb,
+ .process-content::-webkit-scrollbar-thumb {
+ background: #c1c1c1;
+ border-radius: 3px;
+ }
+
+ .process-nav::-webkit-scrollbar-thumb:hover,
+ .process-content::-webkit-scrollbar-thumb:hover {
+ background: #a8a8a8;
+ }
+
+ /* 鍔ㄧ敾鏁堟灉 */
+ @keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ .step-panel {
+ animation: fadeIn 0.3s ease;
+ }
+
+ /* 鍔犺浇鐘舵�� */
+ .loading-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(255, 255, 255, 0.8);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 9999;
+ }
+</style>
\ No newline at end of file
--
Gitblit v1.9.3