gaoluyang
2 天以前 c6b67b0f3103729c5a14cc4777009f7ad729c7aa
浪潮
1.生产管控添加新增功能以及bug修改
已修改8个文件
503 ■■■■■ 文件已修改
src/api/productionManagement/productionOrder.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/components/formDia.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/index.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionCosting/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/components/formDia.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/index.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue 320 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/index.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionOrder.js
@@ -4,7 +4,7 @@
// 分页查询
export function schedulingListPage(query) {
  return request({
    url: "/salesLedger/scheduling/listPage",
    url: "/productionOrder/listPage",
    method: "get",
    params: query,
  });
@@ -16,4 +16,29 @@
    method: "post",
    data: query,
  });
}
// 新增生产订单
export function addProductionOrder(query) {
  return request({
    url: "/productionOrder/addProductionOrder",
    method: "post",
    data: query,
  });
}
// 修改生产订单
export function updateProductionOrder(query) {
  return request({
    url: "/productionOrder/updateProductionOrder",
    method: "post",
    data: query,
  });
}
// 删除生产订单
export function deleteProductionOrder(query) {
  return request({
    url: "/productionOrder/deleteProductionOrder",
    method: "delete",
    data: query,
  });
}
src/views/productionManagement/operationScheduling/components/formDia.vue
@@ -16,14 +16,11 @@
        </el-table-column>
        <el-table-column label="工序" prop="process">
          <template #default="scope">
                        <el-select v-model="scope.row.process" placeholder="请选择" clearable style="width: 100%">
                            <el-option
                                v-for="dict in work_step"
                                :key="dict.value"
                                :label="dict.label"
                                :value="dict.value"
                            />
                        </el-select>
            <el-input
              v-model="scope.row.process"
              placeholder="请输入工序"
              clearable
            />
          </template>
        </el-table-column>
        <el-table-column label="单位" prop="unit">
@@ -99,7 +96,6 @@
import {userListNoPageByTenantId} from "@/api/system/user.js";
import {processScheduling} from "@/api/productionManagement/operationScheduling.js";
const { proxy } = getCurrentInstance()
const { work_step } = proxy.useDict("work_step")
const emit = defineEmits(['close'])
const dialogFormVisible = ref(false);
src/views/productionManagement/operationScheduling/index.vue
@@ -2,16 +2,6 @@
    <div class="app-container">
        <div class="search_form">
            <el-form :model="searchForm" :inline="true">
                <el-form-item label="客户名称:">
                    <el-input v-model="searchForm.customerName" placeholder="请输入" clearable prefix-icon="Search"
                                        style="width: 200px;"
                                        @change="handleQuery" />
                </el-form-item>
                <el-form-item label="项目名称:">
                    <el-input v-model="searchForm.projectName" placeholder="请输入" clearable prefix-icon="Search"
                                        style="width: 200px;"
                                        @change="handleQuery" />
                </el-form-item>
                <el-form-item label="派工日期:">
                    <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                                                    placeholder="请选择" clearable @change="changeDaterange" />
@@ -101,26 +91,6 @@
    {
        label: "派工人",
        prop: "schedulingUserName",
    },
    {
        label: "合同号",
        prop: "salesContractNo",
        width: 200,
    },
    {
        label: "客户合同号",
        prop: "customerContractNo",
        width: 200,
    },
    {
        label: "客户名称",
        prop: "customerName",
        width: 200,
    },
    {
        label: "项目名称",
        prop: "projectName",
        width:300
    },
    {
        label: "产品大类",
src/views/productionManagement/productionCosting/index.vue
@@ -57,26 +57,6 @@
        width: 90,
    },
    {
        label: "合同号",
        prop: "salesContractNo",
        width: 220,
    },
    {
        label: "客户合同号",
        prop: "customerContractNo",
        width: 250,
    },
    {
        label: "客户名称",
        prop: "customerName",
        width: 250,
    },
    {
        label: "项目名称",
        prop: "projectName",
        width:300
    },
    {
        label: "产品大类",
        prop: "productCategory",
        width: 160,
src/views/productionManagement/productionDispatching/components/formDia.vue
@@ -9,29 +9,23 @@
      <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="projectName">
              <el-input v-model="form.projectName" placeholder="请输入" clearable disabled/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="产品大类:" prop="productCategory">
              <el-input v-model="form.productCategory" placeholder="请输入" clearable disabled/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="总数量:" prop="quantity">
              <el-input v-model="form.quantity" placeholder="请输入" clearable disabled/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
                        <el-form-item label="待排产数量:" prop="pendingQuantity">
                            <el-input v-model="form.pendingQuantity" placeholder="请输入" clearable disabled/>
                        </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
                        <el-form-item label="本次排产数量:" prop="schedulingNum">
                            <el-input-number
@@ -103,13 +97,13 @@
const operationType = ref('')
const data = reactive({
  form: {
        projectName: "",
        productCategory: "",
        quantity: "",
        schedulingNum: "",
        schedulingUserId: "",
        schedulingDate: "",
        pendingQuantity: "",
        salesLedgerProductId: "",
  },
  rules: {
        schedulingNum: [{ required: true, message: "请输入", trigger: "blur" },],
@@ -129,6 +123,10 @@
        userList.value = res.data;
    });
    form.value = {...row}
    // 绑定外层传入的产品ID到后端需要的 salesLedgerProductId 字段
    form.value.salesLedgerProductId = row.id;
    // 确保不会把原始 id 当作排产记录主键传给后端
    delete form.value.id;
    form.value.schedulingNum = 0
    form.value.schedulingUserId = userStore.id
    form.value.schedulingDate = dayjs().format("YYYY-MM-DD");
src/views/productionManagement/productionDispatching/index.vue
@@ -2,25 +2,7 @@
    <div class="app-container">
        <div class="search_form">
            <div>
                <span class="search_title">客户名称:</span>
                <el-input
                    v-model="searchForm.customerName"
                    style="width: 240px"
                    placeholder="请输入"
                    @change="handleQuery"
                    clearable
                    prefix-icon="Search"
                />
                <span class="search_title ml10">项目名称:</span>
                <el-input
                    v-model="searchForm.projectName"
                    style="width: 240px"
                    placeholder="请输入"
                    @change="handleQuery"
                    clearable
                    prefix-icon="Search"
                />
                <span class="search_title ml10">录入日期:</span>
                <span class="search_title">录入日期:</span>
                <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                                                placeholder="请选择" clearable @change="changeDaterange" />
                <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
@@ -54,8 +36,6 @@
const data = reactive({
    searchForm: {
        customerName: "",
        projectName: "",
        entryDate: [
            dayjs().format("YYYY-MM-DD"),
            dayjs().add(1, "day").format("YYYY-MM-DD"),
@@ -68,28 +48,8 @@
const tableColumn = ref([
    {
        label: "录入日期",
        prop: "entryDate",
        prop: "registerDate",
        width: 120,
    },
    {
        label: "合同号",
        prop: "salesContractNo",
        width: 220,
    },
    {
        label: "客户合同号",
        prop: "customerContractNo",
        width: 250,
    },
    {
        label: "客户名称",
        prop: "customerName",
        width: 250,
    },
    {
        label: "项目名称",
        prop: "projectName",
        width:300
    },
    {
        label: "产品大类",
src/views/productionManagement/productionOrder/index.vue
@@ -2,32 +2,26 @@
    <div class="app-container">
        <div class="search_form">
            <div>
                <span class="search_title">客户名称:</span>
                <el-input
                    v-model="searchForm.customerName"
                    style="width: 240px"
                    placeholder="请输入"
                    @change="handleQuery"
                <span class="search_title">产品大类:</span>
                <el-tree-select
                    v-model="searchForm.productCategory"
                    :data="productOptions"
                    placeholder="请选择"
                    clearable
                    prefix-icon="Search"
                />
                <span class="search_title ml10">项目名称:</span>
                <el-input
                    v-model="searchForm.projectName"
                    check-strictly
                    :render-after-expand="false"
                    style="width: 240px"
                    placeholder="请输入"
                    @change="handleQuery"
                    clearable
                    prefix-icon="Search"
                />
                <span class="search_title ml10">录入日期:</span>
                <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                <el-date-picker v-model="searchForm.registerDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                                                placeholder="请选择" clearable @change="changeDaterange" />
                <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
                >搜索</el-button
                >
            </div>
            <div>
                <el-button type="primary" @click="openDialog('create')">新增订单</el-button>
                <el-button @click="handleOut">导出</el-button>
            </div>
        </div>
@@ -39,102 +33,279 @@
                :page="page"
                :tableLoading="tableLoading"
                @pagination="pagination"
            ></PIMTable>
            >
                <template #action="{ row }">
                    <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
                    <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
                </template>
            </PIMTable>
        </div>
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="40%" @close="closeDialog">
        <el-form ref="formRef" :model="form" :rules="formRules" label-width="100px">
            <el-form-item label="录入日期" prop="registerDate">
                <el-date-picker v-model="form.registerDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="请选择录入日期" style="width: 100%"/>
            </el-form-item>
            <el-form-item label="产品大类" prop="productCategory">
                <el-input
                    v-model="form.productCategory"
                    placeholder="请输入产品大类"
                    clearable
                />
            </el-form-item>
            <el-form-item label="规格型号" prop="specificationModel">
                <el-input
                    v-model="form.specificationModel"
                    placeholder="请输入规格型号"
                    clearable
                />
            </el-form-item>
            <el-form-item label="单位" prop="unit">
                <el-input
                    v-model="form.unit"
                    placeholder="请输入单位"
                    clearable
                />
            </el-form-item>
            <el-form-item label="数量" prop="quantity">
                <el-input-number v-model="form.quantity" :min="0" :step="0.1" style="width: 100%"/>
            </el-form-item>
        </el-form>
        <template #footer>
            <div class="dialog-footer">
                <el-button type="primary" @click="submitForm">确认</el-button>
                <el-button @click="closeDialog">取消</el-button>
            </div>
        </template>
    </el-dialog>
    </div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import {onMounted, ref, reactive, toRefs, getCurrentInstance} from "vue";
import { ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import {schedulingListPage} from "@/api/productionManagement/productionOrder.js";
import {schedulingListPage, addProductionOrder, updateProductionOrder, deleteProductionOrder} from "@/api/productionManagement/productionOrder.js";
import {productTreeList} from "@/api/basicData/product.js";
const { proxy } = getCurrentInstance();
const tableColumn = ref([
    {
        label: "录入日期",
        prop: "entryDate",
        prop: "registerDate",
        width: 120,
    },
    {
        label: "合同号",
        prop: "salesContractNo",
        width: 220,
    },
    {
        label: "客户合同号",
        prop: "customerContractNo",
        width: 250,
    },
    {
        label: "客户名称",
        prop: "customerName",
        width: 250,
    },
    {
        label: "项目名称",
        prop: "projectName",
        width:300
        label: "生产订单号",
        prop: "orderNo",
    },
    {
        label: "产品大类",
        prop: "productCategory",
        width: 160,
    },
    {
        label: "规格型号",
        prop: "specificationModel",
        width: 220,
    },
    {
        label: "单位",
        prop: "unit",
        width:90
    },
    {
        label: "数量",
        prop: "quantity",
    },
    // {
    //     label: "排产数量",
    //     prop: "schedulingNum",
    //     width: 100,
    // },
    // {
    //     label: "完工数量",
    //     prop: "successNum",
    //     width: 100,
    // },
    {
        label: "排产数量",
        prop: "schedulingNum",
        width: 100,
    },
    {
        label: "完工数量",
        prop: "successNum",
        width: 100,
    },
        label: "操作",
        prop: "action",
        width: 120,
        fixed: "right",
        dataType: "slot",
        align: "center",
        slot: "action"
    }
]);
const tableData = ref([]);
const tableLoading = ref(false);
const page = reactive({
const page = ref({
    current: 1,
    size: 100,
    total: 0,
});
const dialogVisible = ref(false);
const dialogTitle = ref("");
const dialogMode = ref(""); // 'create' 或 'edit'
const formRef = ref();
const productOptions = ref([]);
const form = reactive({
    id: null,
    registerDate: dayjs().format("YYYY-MM-DD"),
    productCategory: "",
    specificationModel: "",
    unit: "",
    quantity: null,
});
const formRules = {
    registerDate: [{ required: true, message: "请选择录入日期", trigger: "change" }],
    productCategory: [{ required: true, message: "请输入产品大类", trigger: "blur" }],
    specificationModel: [{ required: true, message: "请输入规格型号", trigger: "blur" }],
    unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
};
const data = reactive({
    searchForm: {
        customerName: "",
        projectName: "",
        entryDate: [], // 录入日期
        entryDateStart: '',
        entryDateEnd: '',
        productCategory: "",
        registerDate: null, // 录入日期
        entryDateStart: undefined,
        entryDateEnd: undefined,
    },
});
const { searchForm } = toRefs(data);
const openDialog = (mode, row = null) => {
    dialogMode.value = mode;
    if (mode === 'create') {
        dialogTitle.value = "新增生产订单";
        resetForm();
    } else if (mode === 'edit') {
        dialogTitle.value = "编辑生产订单";
        resetForm();
        console.log('编辑数据:', row);
        // 填充编辑数据
        form.id = row.id;
        form.registerDate = row.registerDate;
        form.productCategory = row.productCategory;
        form.specificationModel = row.specificationModel;
        form.unit = row.unit;
        form.quantity = row.quantity;
    }
    dialogVisible.value = true;
};
const closeDialog = () => {
    dialogVisible.value = false;
};
const resetForm = () => {
    form.id = null;
    form.registerDate = dayjs().format("YYYY-MM-DD");
    form.productCategory = "";
    form.specificationModel = "";
    form.unit = "";
    form.quantity = null;
};
const submitForm = () => {
    formRef.value?.validate(async (valid) => {
        if (!valid) return;
        try {
            const payload = {
                registerDate: form.registerDate,
                productCategory: form.productCategory,
                specificationModel: form.specificationModel,
                unit: form.unit,
                quantity: form.quantity,
            };
            if (dialogMode.value === 'create') {
                await addProductionOrder(payload);
                proxy.$modal.msgSuccess("新增成功");
            } else if (dialogMode.value === 'edit') {
                payload.id = form.id;
                await updateProductionOrder(payload);
                proxy.$modal.msgSuccess("编辑成功");
            }
            closeDialog();
            getList();
        } catch (err) {
            console.error(`${dialogMode.value === 'create' ? '新增' : '编辑'}失败`, err);
            proxy.$modal.msgError(`${dialogMode.value === 'create' ? '新增' : '编辑'}失败,请重试`);
        }
    });
};
// 编辑方法
const handleEdit = (row) => {
    openDialog('edit', row);
};
// 删除方法
const handleDelete = (row) => {
    proxy.$modal.confirm(`确定要删除生产订单"${row.orderNo}"吗?`, "删除确认", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
    }).then(async () => {
        try {
            await deleteProductionOrder([row.id]);
            proxy.$modal.msgSuccess("删除成功");
            getList(); // 刷新列表
        } catch (err) {
            console.error("删除失败", err);
            proxy.$modal.msgError("删除失败,请重试");
        }
    }).catch(() => {
        proxy.$modal.msg("已取消删除");
    });
};
const getProductOptions = () => {
    return productTreeList().then((res) => {
        productOptions.value = convertIdToValue(res || []);
    });
};
const convertIdToValue = (data) => {
    return data.map((item) => {
        const { id, children, ...rest } = item;
        const newItem = {
            ...rest,
            value: id,
        };
        if (children && children.length > 0) {
            newItem.children = convertIdToValue(children);
        }
        return newItem;
    });
};
const findNodeById = (nodes, value) => {
    for (let i = 0; i < nodes.length; i++) {
        if (nodes[i].value === value) {
            return nodes[i].label;
        }
        if (nodes[i].children && nodes[i].children.length > 0) {
            const label = findNodeById(nodes[i].children, value);
            if (label) return label;
        }
    }
    return null;
};
// 查询列表
/** 搜索按钮操作 */
const handleQuery = () => {
    page.current = 1;
    page.value.current = 1;
    getList();
};
const pagination = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    page.value.current = obj.page;
    page.value.size = obj.limit;
    getList();
};
const changeDaterange = (value) => {
@@ -149,13 +320,27 @@
};
const getList = () => {
    tableLoading.value = true;
    // 构造一个新的对象,不包含entryDate字段
    const params = { ...searchForm.value, ...page };
    params.entryDate = undefined
    // 构造一个新的对象,不包含entryDate字段和 total 字段
    const { total, ...pageParams } = page.value;
    const params = { ...searchForm.value, ...pageParams };
    params.registerDate = undefined;
    if (params.productCategory) {
        // 如果是对象类型,获取其label(名称)而不是value(ID)
        if (typeof params.productCategory === "object") {
            params.productCategory = findNodeById(productOptions.value, params.productCategory) || params.productCategory;
        }
        // 如果是ID,转换为名称
        else if (typeof params.productCategory === "string" || typeof params.productCategory === "number") {
            const categoryName = findNodeById(productOptions.value, params.productCategory);
            if (categoryName) {
                params.productCategory = categoryName;
            }
        }
    }
    schedulingListPage(params).then((res) => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
        page.value.total = res.data.total;
    }).catch(() => {
        tableLoading.value = false;
    })
@@ -177,12 +362,11 @@
};
onMounted(() => {
    searchForm.value.entryDate = [
        dayjs().format("YYYY-MM-DD"),
        dayjs().add(1, "day").format("YYYY-MM-DD"),
    ]
    searchForm.value.entryDateStart = dayjs().format("YYYY-MM-DD")
    searchForm.value.entryDateEnd = dayjs().add(1, "day").format("YYYY-MM-DD")
    getProductOptions();
    // 不设置默认日期,全部条件为空加载
    searchForm.value.registerDate = null;
    searchForm.value.entryDateStart = undefined;
    searchForm.value.entryDateEnd = undefined;
    getList();
});
</script>
src/views/productionManagement/productionReporting/index.vue
@@ -2,16 +2,6 @@
    <div class="app-container">
        <div class="search_form">
            <el-form :model="searchForm" :inline="true">
                <el-form-item label="客户名称:">
                    <el-input v-model="searchForm.customerName" placeholder="请输入" clearable prefix-icon="Search"
                                        style="width: 200px;"
                                        @change="handleQuery" />
                </el-form-item>
                <el-form-item label="项目名称:">
                    <el-input v-model="searchForm.projectName" placeholder="请输入" clearable prefix-icon="Search"
                                        style="width: 200px;"
                                        @change="handleQuery" />
                </el-form-item>
                <el-form-item label="排产日期:">
                    <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                                                    placeholder="请选择" clearable @change="changeDaterange" />
@@ -198,26 +188,6 @@
    {
        label: "排产人",
        prop: "schedulingUserName",
    },
    {
        label: "合同号",
        prop: "salesContractNo",
        width: 200,
    },
    {
        label: "客户合同号",
        prop: "customerContractNo",
        width: 200,
    },
    {
        label: "客户名称",
        prop: "customerName",
        width: 200,
    },
    {
        label: "项目名称",
        prop: "projectName",
        width:300
    },
    {
        label: "产品大类",