gaoluyang
2025-11-26 1c4ff7adf79cd9abc1ea644a3161780a623b9f5c
1.湟水峡-生产订单不和销售关联逻辑修改联调
已修改15个文件
563 ■■■■■ 文件已修改
src/api/productionManagement/productionOrder.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/DynamicTable/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/Pagination.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Pagination/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/fakePage/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitorManagement/videoMonitor/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/advancedPriceManagement/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementPlan/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/index.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionCosting/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/index.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue 397 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/reportManagement.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/reportManagement/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | 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,
  });
@@ -17,3 +17,28 @@
    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/components/DynamicTable/index.vue
@@ -136,9 +136,9 @@
    <!-- 分页组件 -->
    <div v-if="showPagination" class="pagination-container">
      <el-pagination
        v-model:current-page="pagination.current"
        v-model:page-size="pagination.size"
        :page-sizes="[10, 20, 50, 100]"
        v-model:currentPage="pagination.current"
        v-model:pageSize="pagination.size"
        :page-size-options="[10, 20, 50, 100]"
        :total="pagination.total"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
src/components/PIMTable/Pagination.vue
@@ -2,10 +2,10 @@
  <div :class="{ hidden }" class="pagination-container">
    <el-pagination
      :background="background"
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      v-model:currentPage="currentPage"
      v-model:pageSize="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :page-size-options="pageSizes"
      :pager-count="pagerCount"
      :total="total"
      v-bind="$attrs"
src/components/Pagination/index.vue
@@ -2,10 +2,10 @@
  <div :class="{ 'hidden': hidden }" class="pagination-container">
    <el-pagination
      :background="background"
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      v-model:currentPage="currentPage"
      v-model:pageSize="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :page-size-options="pageSizes"
      :pager-count="pagerCount"
      :total="total"
      @size-change="handleSizeChange"
@@ -15,6 +15,7 @@
</template>
<script setup>
import { computed } from 'vue'
import { scrollTo } from '@/utils/scroll-to'
const props = defineProps({
src/views/demo/fakePage/index.vue
@@ -50,7 +50,7 @@
          background
          layout="total, sizes, prev, pager, next, jumper"
          :total="filteredList.length"
          :page-sizes="[5, 10, 20, 50]"
          :page-size-options="[5, 10, 20, 50]"
          :page-size="pager.pageSize"
          :current-page="pager.pageNum"
          @size-change="handleSizeChange"
src/views/monitorManagement/videoMonitor/index.vue
@@ -162,9 +162,9 @@
          <!-- 分页 -->
          <div class="pagination-container">
            <el-pagination
              v-model:current-page="capturePage"
              v-model:page-size="capturePageSize"
              :page-sizes="[10, 20, 50, 100]"
              v-model:currentPage="capturePage"
              v-model:pageSize="capturePageSize"
              :page-size-options="[10, 20, 50, 100]"
              :total="filteredCaptures.length"
              layout="total, sizes, prev, pager, next, jumper"
              @size-change="handleSizeChange"
src/views/procurementManagement/advancedPriceManagement/index.vue
@@ -127,9 +127,9 @@
      <!-- 分页 -->
      <div class="pagination-wrapper">
        <el-pagination
          v-model:current-page="pagination.current"
          v-model:page-size="pagination.size"
          :page-sizes="[10, 20, 50, 100]"
          v-model:currentPage="pagination.current"
          v-model:pageSize="pagination.size"
          :page-size-options="[10, 20, 50, 100]"
          :total="total"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
src/views/procurementManagement/procurementPlan/index.vue
@@ -76,9 +76,9 @@
      <!-- 分页 -->
      <div class="pagination-container">
        <el-pagination
          v-model:current-page="pagination.current"
          v-model:page-size="pagination.size"
          :page-sizes="[10, 20, 50, 100]"
          v-model:currentPage="pagination.current"
          v-model:pageSize="pagination.size"
          :page-size-options="[10, 20, 50, 100]"
          :total="total"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
src/views/productionManagement/operationScheduling/index.vue
@@ -94,41 +94,18 @@
    {
        label: "派工日期",
        prop: "schedulingDate",
        width: 120,
    },
    {
        label: "派工人",
        prop: "schedulingUserName",
    },
    {
        label: "合同号",
        prop: "salesContractNo",
        width: 200,
    },
    {
        label: "客户合同号",
        prop: "customerContractNo",
        width: 200,
    },
    {
        label: "客户名称",
        prop: "customerName",
        width: 200,
    },
    {
        label: "项目名称",
        prop: "projectName",
        width:300
    },
    {
        label: "产品大类",
        prop: "productCategory",
        width: 150,
    },
    {
        label: "规格型号",
        prop: "specificationModel",
        width: 150,
    },
    {
        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/index.vue
@@ -66,34 +66,12 @@
const { searchForm } = toRefs(data);
const tableColumn = ref([
    {
        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,
    },
    {
        label: "规格型号",
        prop: "specificationModel",
        width: 220,
    },
    {
        label: "单位",
@@ -103,7 +81,6 @@
    {
        label: "录入日期",
        prop: "entryDate",
        width: 120,
    },
    {
        label: "数量",
@@ -112,12 +89,10 @@
    {
        label: "排产数量",
        prop: "schedulingNum",
        width: 100,
    },
    {
        label: "待排数量",
        prop: "pendingQuantity",
        width: 100,
    },
]);
const tableData = ref([]);
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,116 +33,356 @@
                :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-tree-select
                    v-model="form.productCategory"
                    :data="productOptions"
                    placeholder="请选择产品大类"
                    clearable
                    check-strictly
                    :render-after-expand="false"
                    style="width: 100%"
                    @change="handleCategoryChange"
                />
            </el-form-item>
            <el-form-item label="规格型号" prop="productModelId">
                <el-select v-model="form.productModelId" placeholder="请选择规格型号" style="width: 100%" @change="handleModelChange">
                    <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id"/>
                </el-select>
            </el-form-item>
            <el-form-item label="单位" prop="unit">
                <el-input v-model="form.unit" placeholder="自动带出" disabled/>
            </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, modelList} 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: "status",
        dataType: "tag",
        formatType: (params) => {
            if (params == '未完成') {
                return "danger";
            } else if (params == '已完成') {
                return "success";
            } else {
                return null;
            }
        },
        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 modelOptions = ref([]);
const form = reactive({
    id: null,
    registerDate: dayjs().format("YYYY-MM-DD"),
    productCategory: "",
    productCategoryName: "",
    productModelId: "",
    specificationModel: "",
    unit: "",
    quantity: null,
});
const formRules = {
    registerDate: [{ required: true, message: "请选择录入日期", trigger: "change" }],
    productCategory: [{ required: true, message: "请选择产品大类", trigger: "change" }],
    productModelId: [{ required: true, message: "请选择规格型号", trigger: "change" }],
    quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
};
const data = reactive({
    searchForm: {
        customerName: "",
        projectName: "",
        entryDate: null, // 录入日期
        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.productCategoryName = row.productCategory;
        form.specificationModel = row.specificationModel;
        form.unit = row.unit;
        form.quantity = row.quantity;
        // 先加载产品选项,然后根据名称查找对应的ID
        if (productOptions.value.length === 0) {
            getProductOptions().then(() => {
                findAndSetProductCategory(row.productCategory);
            });
        } else {
            findAndSetProductCategory(row.productCategory);
        }
    }
    dialogVisible.value = true;
    if (productOptions.value.length === 0) {
        getProductOptions();
    }
};
const closeDialog = () => {
    dialogVisible.value = false;
};
const resetForm = () => {
    form.id = null;
    form.registerDate = dayjs().format("YYYY-MM-DD");
    form.productCategory = "";
    form.productCategoryName = "";
    form.productModelId = "";
    form.specificationModel = "";
    form.unit = "";
    form.quantity = null;
    modelOptions.value = [];
};
const handleCategoryChange = (value) => {
    form.productCategory = value;
    form.productCategoryName = findNodeById(productOptions.value, value) || "";
    form.productModelId = "";
    form.specificationModel = "";
    form.unit = "";
    modelOptions.value = [];
    if (value) {
        getModels(value);
    }
};
const handleModelChange = (value) => {
    form.productModelId = value;
    const selected = modelOptions.value.find(item => item.id === value);
    if (selected) {
        form.specificationModel = selected.model;
        form.unit = selected.unit || "";
    } else {
        form.specificationModel = "";
        form.unit = "";
    }
};
const submitForm = () => {
    formRef.value?.validate(async (valid) => {
        if (!valid) return;
        if (!form.unit) {
            proxy.$modal.msgWarning("请先选择规格型号以带出单位");
            return;
        }
        try {
            const payload = {
                registerDate: form.registerDate,
                productCategory: form.productCategoryName,
                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 getModels = (value) => {
    return modelList({ id: value }).then((res) => {
        modelOptions.value = 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 findNodeByLabel = (nodes, label) => {
    for (let i = 0; i < nodes.length; i++) {
        if (nodes[i].label === label) {
            return nodes[i].value;
        }
        if (nodes[i].children && nodes[i].children.length > 0) {
            const value = findNodeByLabel(nodes[i].children, label);
            if (value) return value;
        }
    }
    return null;
};
const findAndSetProductCategory = (categoryName) => {
    const categoryId = findNodeByLabel(productOptions.value, categoryName);
    if (categoryId) {
        form.productCategory = categoryId;
        // 加载对应的规格型号选项
        getModels(categoryId).then(() => {
            // 根据规格型号名称查找对应的ID
            const modelItem = modelOptions.value.find(item => item.model === form.specificationModel);
            if (modelItem) {
                form.productModelId = modelItem.id;
            }
        });
    }
};
// 查询列表
/** 搜索按钮操作 */
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) => {
@@ -164,12 +398,26 @@
const getList = () => {
    tableLoading.value = true;
    // 构造一个新的对象,不包含entryDate字段
    const params = { ...searchForm.value, ...page };
    params.entryDate = undefined
    const params = { ...searchForm.value, ...page.value };
    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) => {
        console.log('params---', res)
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
        tableData.value = res.data.data.records;
        page.value.total = res.data.data.total;
    }).catch(() => {
        tableLoading.value = false;
    })
@@ -192,6 +440,7 @@
onMounted(() => {
    getList();
    getProductOptions();
});
</script>
src/views/productionManagement/productionReporting/index.vue
@@ -197,26 +197,6 @@
        prop: "schedulingUserName",
    },
    {
        label: "合同号",
        prop: "salesContractNo",
        width: 200,
    },
    {
        label: "客户合同号",
        prop: "customerContractNo",
        width: 200,
    },
    {
        label: "客户名称",
        prop: "customerName",
        width: 200,
    },
    {
        label: "项目名称",
        prop: "projectName",
        width:300
    },
    {
        label: "产品大类",
        prop: "productCategory",
        width: 150,
src/views/reportAnalysis/reportManagement.vue
@@ -200,9 +200,9 @@
      
      <div class="pagination-container">
        <el-pagination
          v-model:current-page="pagination.currentPage"
          v-model:page-size="pagination.pageSize"
          :page-sizes="[10, 20, 50, 100]"
          v-model:currentPage="pagination.currentPage"
          v-model:pageSize="pagination.pageSize"
          :page-size-options="[10, 20, 50, 100]"
          :total="pagination.total"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
src/views/reportAnalysis/reportManagement/index.vue
@@ -194,9 +194,9 @@
            
            <div class="pagination-container">
                <el-pagination
                    v-model:current-page="pagination.currentPage"
                    v-model:page-size="pagination.pageSize"
                    :page-sizes="[10, 20, 50, 100]"
                    v-model:currentPage="pagination.currentPage"
                    v-model:pageSize="pagination.pageSize"
                    :page-size-options="[10, 20, 50, 100]"
                    :total="pagination.total"
                    layout="total, sizes, prev, pager, next, jumper"
                    @size-change="handleSizeChange"