| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="工序名称:"> |
| | | <el-input v-model="searchForm.name" |
| | | placeholder="请输入" |
| | | clearable |
| | | prefix-icon="Search" |
| | | style="width: 200px;" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="工序编号:"> |
| | | <el-input v-model="searchForm.no" |
| | | placeholder="请输入" |
| | | clearable |
| | | prefix-icon="Search" |
| | | style="width: 200px;" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <div class="process-config-container"> |
| | | <!-- 左侧工序列表 --> |
| | | <div class="process-list-section"> |
| | | <div class="section-header"> |
| | | <h3 class="section-title">工序列表</h3> |
| | | <el-button type="primary" |
| | | @click="handleQuery">搜索</el-button> |
| | | size="small" |
| | | @click="handleAddProcess"> |
| | | <el-icon> |
| | | <Plus /> |
| | | </el-icon>新增工序 |
| | | </el-button> |
| | | </div> |
| | | <div class="process-card-list" |
| | | v-loading="processLoading"> |
| | | <div v-for="process in processValueList" |
| | | :key="process.id" |
| | | class="process-card" |
| | | :class="{ active: selectedProcess?.id === process.id }" |
| | | @click="selectProcess(process)"> |
| | | <div class="card-header"> |
| | | <div class="process-name">{{ process.name }} <span class="process-code">{{ process.no }}</span></div> |
| | | <div class="card-actions"> |
| | | <el-button link |
| | | type="primary" |
| | | @click.stop="handleEditProcess(process)"> |
| | | <el-icon> |
| | | <Edit /> |
| | | </el-icon> |
| | | 编辑 |
| | | </el-button> |
| | | <el-button link |
| | | type="danger" |
| | | @click.stop="handleDeleteProcess(process)"> |
| | | <el-icon> |
| | | <Delete /> |
| | | </el-icon> |
| | | 删除 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <div class="card-body"> |
| | | <!-- <div class="process-name">{{ process.name }}</div> --> |
| | | <div class="process-desc">{{ process.remark || '暂无描述' }}</div> |
| | | </div> |
| | | <div class="card-footer"> |
| | | <div class="status-tag"> <el-tag size="small" |
| | | :type="process.status ? 'success' : 'info'"> |
| | | {{ process.status ? '启用' : '停用' }} |
| | | </el-tag> |
| | | <el-tag size="small" |
| | | :type="process.isQuality ? 'warning' : 'info'" |
| | | style="margin-left: 8px"> |
| | | {{ process.isQuality ? '质检' : '非质检' }} |
| | | </el-tag> |
| | | </div> |
| | | <span class="param-count">工资定额: ¥{{ process.salaryQuota || 0 }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- 右侧参数列表 --> |
| | | <div class="param-list-section"> |
| | | <div class="section-header"> |
| | | <h3 class="section-title"> |
| | | {{ selectedProcess ? selectedProcess.name + ' - 参数配置' : '请选择工序' }} |
| | | </h3> |
| | | <el-button type="primary" |
| | | size="small" |
| | | :disabled="!selectedProcess" |
| | | @click="handleSelectParam"> |
| | | <el-icon> |
| | | <Plus /> |
| | | </el-icon>选择参数 |
| | | </el-button> |
| | | </div> |
| | | <div class="param-table-wrapper"> |
| | | <PIMTable v-if="selectedProcess" |
| | | rowKey="id" |
| | | :column="paramColumn" |
| | | :tableData="paramList" |
| | | :page="paramPage" |
| | | height="calc(100vh - 280px)" |
| | | :isSelection="false" |
| | | @pagination="handleParamPagination" /> |
| | | <div v-else |
| | | class="empty-tip"> |
| | | <el-empty description="请从左侧选择一个工序" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- 工序新增/编辑对话框 --> |
| | | <el-dialog v-model="processDialogVisible" |
| | | :title="isProcessEdit ? '编辑工序' : '新增工序'" |
| | | width="500px"> |
| | | <el-form :model="processForm" |
| | | :rules="processRules" |
| | | ref="processFormRef" |
| | | label-width="100px"> |
| | | <el-form-item label="工序编码" |
| | | prop="no"> |
| | | <el-input v-model="processForm.no" |
| | | placeholder="请输入工序编码" /> |
| | | </el-form-item> |
| | | <el-form-item label="工序名称" |
| | | prop="name"> |
| | | <el-input v-model="processForm.name" |
| | | placeholder="请输入工序名称" /> |
| | | </el-form-item> |
| | | <el-form-item label="工资定额" |
| | | prop="salaryQuota"> |
| | | <el-input v-model="processForm.salaryQuota" |
| | | type="number" |
| | | :step="0.001" /> |
| | | </el-form-item> |
| | | <el-form-item label="是否质检" |
| | | prop="isQuality"> |
| | | <el-switch v-model="processForm.isQuality" |
| | | :active-value="true" |
| | | inactive-value="false" /> |
| | | </el-form-item> |
| | | <el-form-item label="工序描述" |
| | | prop="remark"> |
| | | <el-input v-model="processForm.remark" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请输入工序描述" /> |
| | | </el-form-item> |
| | | <el-form-item label="状态" |
| | | prop="status"> |
| | | <el-radio-group v-model="processForm.status"> |
| | | <el-radio :label="true">启用</el-radio> |
| | | <el-radio :label="false">停用</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div style="text-align: right" |
| | | class="mb10"> |
| | | <el-button type="primary" |
| | | @click="showNewModal">新增工序</el-button> |
| | | <el-button type="info" |
| | | plain |
| | | @click="handleImport">导入</el-button> |
| | | <el-button type="danger" |
| | | @click="handleDelete" |
| | | :disabled="selectedRows.length === 0" |
| | | plain>删除工序</el-button> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="processDialogVisible = false">取消</el-button> |
| | | <el-button type="primary" |
| | | @click="handleProcessSubmit">确定</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 选择参数对话框 --> |
| | | <el-dialog v-model="paramDialogVisible" |
| | | title="选择参数" |
| | | width="1000px"> |
| | | <div class="param-select-container"> |
| | | <!-- 左侧参数列表 --> |
| | | <div class="param-list-area"> |
| | | <div class="area-title">可选参数</div> |
| | | <div class="search-box"> |
| | | <el-input v-model="paramSearchKeyword" |
| | | placeholder="请输入参数名称搜索" |
| | | clearable |
| | | size="small" |
| | | @input="handleSelectParam"> |
| | | <template #prefix> |
| | | <el-icon> |
| | | <Search /> |
| | | </el-icon> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | <el-table :data="filteredParamList" |
| | | height="300" |
| | | border |
| | | highlight-current-row |
| | | @current-change="handleParamSelect"> |
| | | <el-table-column prop="paramName" |
| | | label="参数名称" /> |
| | | <el-table-column prop="paramType" |
| | | label="参数类型"> |
| | | <template #default="scope"> |
| | | <el-tag size="small" |
| | | :type="getParamTypeTag(scope.row.paramType)"> |
| | | {{ getParamTypeText(scope.row.paramType) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- 分页控件 --> |
| | | <div class="pagination-container" |
| | | style="margin-top: 10px;"> |
| | | <el-pagination v-model:current-page="paramPage.current" |
| | | v-model:page-size="paramPage.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :total="paramPage.total" |
| | | @size-change="handleParamSizeChange" |
| | | @current-change="handleParamCurrentChange" |
| | | size="small" /> |
| | | </div> |
| | | </div> |
| | | <!-- 右侧参数详情 --> |
| | | <div class="param-detail-area"> |
| | | <div class="area-title">参数详情</div> |
| | | <el-form v-if="selectedParam" |
| | | :model="selectedParam" |
| | | label-width="100px" |
| | | class="param-detail-form"> |
| | | <el-form-item label="参数名称"> |
| | | <span class="detail-text">{{ selectedParam.paramName }}</span> |
| | | </el-form-item> |
| | | <el-form-item label="参数模式"> |
| | | <el-tag size="small" |
| | | :type="selectedParam.valueMode == '1' ? 'success' : 'warning'"> |
| | | {{ selectedParam.valueMode == '1' ? '单值' : '区间' }} |
| | | </el-tag> |
| | | </el-form-item> |
| | | <el-form-item label="参数类型"> |
| | | <el-tag size="small" |
| | | :type="getParamTypeTag(selectedParam.paramType)"> |
| | | {{ getParamTypeText(selectedParam.paramType) }} |
| | | </el-tag> |
| | | </el-form-item> |
| | | <el-form-item label="参数格式"> |
| | | <span class="detail-text">{{ selectedParam.paramFormat || '-' }}</span> |
| | | </el-form-item> |
| | | <el-form-item label="单位"> |
| | | <span class="detail-text">{{ selectedParam.unit || '-' }}</span> |
| | | </el-form-item> |
| | | <el-form-item label="标准值" |
| | | v-if="selectedParam.valueMode == '1'"> |
| | | <el-input v-model="selectedParam.standardValue" |
| | | type="number" |
| | | placeholder="请输入默认值" /> |
| | | </el-form-item> |
| | | <el-form-item label="最小值" |
| | | v-if="selectedParam.valueMode == '2'"> |
| | | <el-input v-model="selectedParam.minValue" |
| | | type="number" |
| | | placeholder="请输入最小值" /> |
| | | </el-form-item> |
| | | <el-form-item label="最大值" |
| | | v-if="selectedParam.valueMode == '2'"> |
| | | <el-input v-model="selectedParam.maxValue" |
| | | type="number" |
| | | placeholder="请输入最大值" /> |
| | | </el-form-item> |
| | | <el-form-item label="排序"> |
| | | <el-input v-model="selectedParam.sort" |
| | | type="number" |
| | | placeholder="请输入排序" /> |
| | | </el-form-item> |
| | | <el-form-item label="是否必填"> |
| | | <el-switch v-model="selectedParam.isRequired" |
| | | :active-value="1" |
| | | :inactive-value="0" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-empty v-else |
| | | description="请从左侧选择参数" /> |
| | | </div> |
| | | </div> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :total="page.total"></PIMTable> |
| | | </div> |
| | | <new-process v-if="isShowNewModal" |
| | | v-model:visible="isShowNewModal" |
| | | @completed="getList" /> |
| | | <edit-process v-if="isShowEditModal" |
| | | v-model:visible="isShowEditModal" |
| | | :record="record" |
| | | @completed="getList" /> |
| | | <ImportDialog ref="importDialogRef" |
| | | v-model="importDialogVisible" |
| | | title="导入工序" |
| | | :action="importAction" |
| | | :headers="importHeaders" |
| | | :auto-upload="false" |
| | | :on-success="handleImportSuccess" |
| | | :on-error="handleImportError" |
| | | @confirm="handleImportConfirm" |
| | | @download-template="handleDownloadTemplate" |
| | | @close="handleImportClose" /> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="paramDialogVisible = false">取消</el-button> |
| | | <el-button type="primary" |
| | | :disabled="!selectedParam" |
| | | @click="handleParamSubmit">确定</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 编辑参数对话框 --> |
| | | <el-dialog v-model="editParamDialogVisible" |
| | | title="编辑参数" |
| | | width="600px"> |
| | | <el-form :model="editParamForm" |
| | | :rules="editParamRules" |
| | | ref="editParamFormRef" |
| | | label-width="120px"> |
| | | <el-form-item label="参数名称"> |
| | | <span class="detail-text">{{ editParamForm.paramName }}</span> |
| | | </el-form-item> |
| | | <el-form-item label="参数模式"> |
| | | <el-tag size="small" |
| | | :type="editParamForm.valueMode == '1' ? 'success' : 'warning'"> |
| | | {{ editParamForm.valueMode == '1' ? '单值' : '区间' }} |
| | | </el-tag> |
| | | </el-form-item> |
| | | <el-form-item label="标准值" |
| | | v-if="editParamForm.valueMode == '1'" |
| | | prop="standardValue"> |
| | | <el-input v-model="editParamForm.standardValue" |
| | | type="number" |
| | | placeholder="请输入标准值" /> |
| | | </el-form-item> |
| | | <el-form-item label="最小值" |
| | | v-if="editParamForm.valueMode == '2'" |
| | | prop="minValue"> |
| | | <el-input v-model="editParamForm.minValue" |
| | | type="number" |
| | | placeholder="请输入最小值" /> |
| | | </el-form-item> |
| | | <el-form-item label="最大值" |
| | | v-if="editParamForm.valueMode == '2'" |
| | | prop="maxValue"> |
| | | <el-input v-model="editParamForm.maxValue" |
| | | type="number" |
| | | placeholder="请输入最大值" /> |
| | | </el-form-item> |
| | | <el-form-item label="排序" |
| | | prop="sort"> |
| | | <el-input v-model="editParamForm.sort" |
| | | type="number" |
| | | placeholder="请输入排序" /> |
| | | </el-form-item> |
| | | <el-form-item label="是否必填" |
| | | prop="isRequired"> |
| | | <el-switch v-model="editParamForm.isRequired" |
| | | :active-value="1" |
| | | :inactive-value="0" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="editParamDialogVisible = false">取消</el-button> |
| | | <el-button type="primary" |
| | | @click="handleEditParamSubmit">确定</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue"; |
| | | import NewProcess from "@/views/productionManagement/productionProcess/New.vue"; |
| | | import EditProcess from "@/views/productionManagement/productionProcess/Edit.vue"; |
| | | import ImportDialog from "@/components/Dialog/ImportDialog.vue"; |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Plus, Edit, Delete, Search } from "@element-plus/icons-vue"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import { listType } from "@/api/system/dict/type"; |
| | | import { |
| | | listPage, |
| | | add, |
| | | update, |
| | | del, |
| | | importData, |
| | | downloadTemplate, |
| | | list as getProcessListApi, |
| | | processList, |
| | | getProcessParamList, |
| | | addProcessParam, |
| | | editProcessParam, |
| | | deleteProcessParam, |
| | | } from "@/api/productionManagement/productionProcess.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import { getBaseParamList } from "@/api/basicData/parameterMaintenance.js"; |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | name: "", |
| | | no: "", |
| | | }, |
| | | // 工序列表数据 |
| | | const processValueList = ref([]); |
| | | const selectedProcess = ref(null); |
| | | const processLoading = ref(false); |
| | | |
| | | // 参数列表数据 |
| | | const paramList = ref([]); |
| | | const paramLoading = ref(false); |
| | | |
| | | // 数据字典 |
| | | const dictTypes = ref([]); |
| | | |
| | | // 工序对话框 |
| | | const processDialogVisible = ref(false); |
| | | const isProcessEdit = ref(false); |
| | | const processFormRef = ref(null); |
| | | const processForm = reactive({ |
| | | id: null, |
| | | no: "", |
| | | name: "", |
| | | salaryQuota: null, |
| | | isQuality: false, |
| | | remark: "", |
| | | status: true, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "工序编号", |
| | | prop: "no", |
| | | }, |
| | | { |
| | | label: "工序名称", |
| | | prop: "name", |
| | | }, |
| | | const processRules = { |
| | | no: [{ required: true, message: "请输入工序编码", trigger: "blur" }], |
| | | name: [{ required: true, message: "请输入工序名称", trigger: "blur" }], |
| | | salaryQuota: [ |
| | | { |
| | | required: false, |
| | | message: "请输入工资定额", |
| | | trigger: "blur", |
| | | validator: (rule, value, callback) => { |
| | | if (isNaN(value) || value < 0) { |
| | | callback(new Error("工资定额必须是非负数字")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | }; |
| | | |
| | | // 参数对话框 |
| | | const paramDialogVisible = ref(false); |
| | | const availableParamList = ref([]); |
| | | const filteredParamList = ref([]); |
| | | const selectedParam = ref(null); |
| | | const paramSearchKeyword = ref(""); |
| | | |
| | | // 可选参数分页 |
| | | const paramPage = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | // 编辑参数对话框 |
| | | const editParamDialogVisible = ref(false); |
| | | const editParamFormRef = ref(null); |
| | | const editParamForm = reactive({ |
| | | id: null, |
| | | processId: null, |
| | | paramId: null, |
| | | paramName: "", |
| | | valueMode: "1", |
| | | standardValue: null, |
| | | minValue: null, |
| | | maxValue: null, |
| | | sort: 1, |
| | | isRequired: 0, |
| | | tenantId: 1, |
| | | }); |
| | | const editParamRules = { |
| | | standardValue: [ |
| | | { |
| | | required: true, |
| | | message: "请输入标准值", |
| | | trigger: "blur", |
| | | validator: (rule, value, callback) => { |
| | | if (value === null || value === undefined || value === "") { |
| | | callback(new Error("请输入标准值")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | minValue: [ |
| | | { |
| | | required: true, |
| | | message: "请输入最小值", |
| | | trigger: "blur", |
| | | validator: (rule, value, callback) => { |
| | | if (value === null || value === undefined || value === "") { |
| | | callback(new Error("请输入最小值")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | maxValue: [ |
| | | { |
| | | required: true, |
| | | message: "请输入最大值", |
| | | trigger: "blur", |
| | | validator: (rule, value, callback) => { |
| | | if (value === null || value === undefined || value === "") { |
| | | callback(new Error("请输入最大值")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | sort: [ |
| | | { |
| | | required: true, |
| | | message: "请输入排序", |
| | | trigger: "blur", |
| | | validator: (rule, value, callback) => { |
| | | if (value === null || value === undefined || value === "") { |
| | | callback(new Error("请输入排序")); |
| | | } else if (isNaN(value) || value < 1) { |
| | | callback(new Error("排序必须是大于0的整数")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | }; |
| | | |
| | | // 参数表格列配置 |
| | | const paramColumn = ref([ |
| | | { |
| | | label: "工资定额", |
| | | prop: "salaryQuota", |
| | | label: "参数名称", |
| | | prop: "paramName", |
| | | }, |
| | | { |
| | | label: "备注", |
| | | prop: "remark", |
| | | label: "参数模式", |
| | | prop: "valueMode", |
| | | dataType: "tag", |
| | | formatType: row => (row.valueMode === "1" ? "success" : "warning"), |
| | | formatData: row => (row.valueMode === "1" ? "单值" : "区间"), |
| | | }, |
| | | { |
| | | label: "更新时间", |
| | | prop: "updateTime", |
| | | label: "参数类型", |
| | | prop: "paramType", |
| | | dataType: "tag", |
| | | formatType: params => { |
| | | const typeMap = { |
| | | 1: "primary", |
| | | 2: "info", |
| | | 3: "warning", |
| | | 4: "success", |
| | | }; |
| | | return typeMap[params] || "default"; |
| | | }, |
| | | formatData: val => { |
| | | const labelMap = { |
| | | 1: "数值格式", |
| | | 2: "文本格式", |
| | | 3: "下拉选项", |
| | | 4: "时间格式", |
| | | }; |
| | | return labelMap[val] || val; |
| | | }, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "取值格式", |
| | | prop: "paramFormat", |
| | | formatData: (val, row) => { |
| | | if (row.paramType == "3") { |
| | | const dict = dictTypes.value.find(item => item.dictType === val); |
| | | return dict ? "字典:" + dict.dictName : val; |
| | | } |
| | | return val; |
| | | }, |
| | | }, |
| | | { |
| | | label: "标准值", |
| | | prop: "standardValue", |
| | | formatData: (val, row) => { |
| | | return row.valueMode == "1" ? val : "-"; |
| | | }, |
| | | }, |
| | | { |
| | | label: "最小值", |
| | | prop: "minValue", |
| | | formatData: (val, row) => { |
| | | return row.valueMode == "2" ? val : "-"; |
| | | }, |
| | | }, |
| | | { |
| | | label: "最大值", |
| | | prop: "maxValue", |
| | | formatData: (val, row) => { |
| | | return row.valueMode == "2" ? val : "-"; |
| | | }, |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "排序", |
| | | prop: "sort", |
| | | }, |
| | | { |
| | | label: "是否必填", |
| | | prop: "isRequired", |
| | | dataType: "tag", |
| | | formatType: row => (row.isRequired === 1 ? "success" : "info"), |
| | | formatData: row => (row.isRequired === 1 ? "是" : "否"), |
| | | }, |
| | | { |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 280, |
| | | dataType: "action", |
| | | width: "150", |
| | | operation: [ |
| | | { |
| | | name: "编辑", |
| | | type: "text", |
| | | clickFun: row => { |
| | | showEditModal(row); |
| | | }, |
| | | clickFun: row => handleEditParam(row), |
| | | }, |
| | | { |
| | | name: "删除", |
| | | clickFun: row => handleDeleteParam(row), |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const isShowNewModal = ref(false); |
| | | const isShowEditModal = ref(false); |
| | | const record = ref({}); |
| | | const importDialogVisible = ref(false); |
| | | const importDialogRef = ref(null); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // 导入相关配置 |
| | | const importAction = |
| | | import.meta.env.VITE_APP_BASE_API + "/productProcess/importData"; |
| | | const importHeaders = { Authorization: "Bearer " + getToken() }; |
| | | |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | 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; |
| | | listPage(params) |
| | | // 获取工序列表 |
| | | const getProcessList = () => { |
| | | processLoading.value = true; |
| | | getProcessListApi() |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records.map(item => ({ |
| | | ...item, |
| | | })); |
| | | page.total = res.data.total; |
| | | processValueList.value = res.data || []; |
| | | }) |
| | | .catch(err => { |
| | | tableLoading.value = false; |
| | | .catch(() => { |
| | | ElMessage.error("获取工序列表失败"); |
| | | }) |
| | | .finally(() => { |
| | | processLoading.value = false; |
| | | }); |
| | | }; |
| | | // 表格选择数据 |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | |
| | | // 获取参数列表 |
| | | const getParamList = processId => { |
| | | paramLoading.value = true; |
| | | getProcessParamList(processId) |
| | | .then(res => { |
| | | paramList.value = res.data || []; |
| | | paramPage.total = paramList.value.length; |
| | | }) |
| | | .catch(() => { |
| | | ElMessage.error("获取参数列表失败"); |
| | | }) |
| | | .finally(() => { |
| | | paramLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // 打开新增弹框 |
| | | const showNewModal = () => { |
| | | isShowNewModal.value = true; |
| | | // 选择工序 |
| | | const selectProcess = process => { |
| | | selectedProcess.value = process; |
| | | getParamList(process.id); |
| | | }; |
| | | |
| | | const showEditModal = row => { |
| | | isShowEditModal.value = true; |
| | | record.value = row; |
| | | // 工序操作 |
| | | const handleAddProcess = () => { |
| | | isProcessEdit.value = false; |
| | | processForm.id = null; |
| | | processForm.no = ""; |
| | | processForm.name = ""; |
| | | processForm.salaryQuota = null; |
| | | processForm.isQuality = false; |
| | | processForm.remark = ""; |
| | | processForm.status = true; |
| | | processDialogVisible.value = true; |
| | | }; |
| | | |
| | | // 删除 |
| | | function handleDelete() { |
| | | const no = selectedRows.value.map(item => item.no); |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | if (no.length > 2) { |
| | | proxy.$modal |
| | | .confirm( |
| | | '是否确认删除工序编号为"' + |
| | | no[0] + |
| | | "、" + |
| | | no[1] + |
| | | '"等' + |
| | | no.length + |
| | | "条数据项?" |
| | | ) |
| | | .then(function () { |
| | | return del(ids); |
| | | }) |
| | | const handleEditProcess = process => { |
| | | isProcessEdit.value = true; |
| | | processForm.id = process.id; |
| | | processForm.no = process.no; |
| | | processForm.name = process.name; |
| | | processForm.salaryQuota = process.salaryQuota; |
| | | processForm.isQuality = process.isQuality || false; |
| | | processForm.remark = process.remark || ""; |
| | | processForm.status = process.status; |
| | | processDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleDeleteProcess = process => { |
| | | ElMessageBox.confirm("确定要删除该工序吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | del([process.id]) |
| | | .then(() => { |
| | | getList(); |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | ElMessage.success("删除成功"); |
| | | getProcessList(); |
| | | if (selectedProcess.value?.id === process.id) { |
| | | selectedProcess.value = null; |
| | | paramList.value = []; |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | } else { |
| | | proxy.$modal |
| | | .confirm('是否确认删除工序编号为"' + no + '"的数据项?') |
| | | .then(function () { |
| | | return del(ids); |
| | | }) |
| | | .then(() => { |
| | | getList(); |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | }) |
| | | .catch(() => {}); |
| | | } |
| | | } |
| | | |
| | | // 导入 |
| | | const handleImport = () => { |
| | | importDialogVisible.value = true; |
| | | .catch(() => { |
| | | ElMessage.error("删除失败"); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // 确认导入 |
| | | const handleImportConfirm = () => { |
| | | if (importDialogRef.value) { |
| | | importDialogRef.value.submit(); |
| | | } |
| | | }; |
| | | |
| | | // 导入成功 |
| | | const handleImportSuccess = response => { |
| | | if (response.code === 200) { |
| | | proxy.$modal.msgSuccess("导入成功"); |
| | | importDialogVisible.value = false; |
| | | if (importDialogRef.value) { |
| | | importDialogRef.value.clearFiles(); |
| | | const handleProcessSubmit = () => { |
| | | processFormRef.value.validate(valid => { |
| | | if (valid) { |
| | | const apiMethod = isProcessEdit.value ? update : add; |
| | | apiMethod(processForm) |
| | | .then(() => { |
| | | ElMessage.success(isProcessEdit.value ? "编辑成功" : "新增成功"); |
| | | processDialogVisible.value = false; |
| | | getProcessList(); |
| | | }) |
| | | .catch(() => { |
| | | ElMessage.error(isProcessEdit.value ? "编辑失败" : "新增失败"); |
| | | }); |
| | | } |
| | | getList(); |
| | | } else { |
| | | proxy.$modal.msgError(response.msg || "导入失败"); |
| | | }); |
| | | }; |
| | | |
| | | // 参数操作 |
| | | const handleSelectParam = () => { |
| | | if (!selectedProcess.value) { |
| | | ElMessage.warning("请先选择一个工序"); |
| | | return; |
| | | } |
| | | // 获取可选参数列表 |
| | | getBaseParamList({ |
| | | paramName: paramSearchKeyword.value, |
| | | current: paramPage.current, |
| | | size: paramPage.size, |
| | | }).then(res => { |
| | | if (res.code === 200) { |
| | | filteredParamList.value = res.data?.records || []; |
| | | paramPage.total = res.data?.total || 0; |
| | | } else { |
| | | ElMessage.error(res.msg || "查询失败"); |
| | | } |
| | | }); |
| | | console.log(filteredParamList.value, "可选参数列表"); |
| | | selectedParam.value = null; |
| | | paramDialogVisible.value = true; |
| | | }; |
| | | |
| | | // 导入失败 |
| | | const handleImportError = error => { |
| | | proxy.$modal.msgError("导入失败:" + (error.message || "未知错误")); |
| | | const handleParamSelect = row => { |
| | | selectedParam.value = row; |
| | | }; |
| | | |
| | | // 关闭导入弹窗 |
| | | const handleImportClose = () => { |
| | | if (importDialogRef.value) { |
| | | importDialogRef.value.clearFiles(); |
| | | const handleParamSearch = () => { |
| | | // 重置分页 |
| | | paramPage.current = 1; |
| | | // 重新加载数据 |
| | | handleSelectParam(); |
| | | }; |
| | | |
| | | // 处理分页大小变化 |
| | | const handleParamSizeChange = size => { |
| | | paramPage.size = size; |
| | | handleSelectParam(); |
| | | }; |
| | | |
| | | // 处理当前页码变化 |
| | | const handleParamCurrentChange = current => { |
| | | paramPage.current = current; |
| | | handleSelectParam(); |
| | | }; |
| | | const getParamTypeText = type => { |
| | | const typeMap = { |
| | | 1: "数值格式", |
| | | 2: "文本格式", |
| | | 3: "下拉选项", |
| | | 4: "时间格式", |
| | | }; |
| | | return typeMap[type] || "未知参数类型"; |
| | | }; |
| | | const getParamTypeTag = type => { |
| | | const typeMap = { |
| | | 1: "primary", |
| | | 2: "info", |
| | | 3: "warning", |
| | | 4: "success", |
| | | }; |
| | | return typeMap[type] || "default"; |
| | | }; |
| | | |
| | | const handleDeleteParam = row => { |
| | | ElMessageBox.confirm("确定要删除该参数吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteProcessParam(row.id) |
| | | .then(() => { |
| | | ElMessage.success("删除成功"); |
| | | getParamList(selectedProcess.value.id); |
| | | }) |
| | | .catch(() => { |
| | | ElMessage.error("删除失败"); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | const handleEditParam = row => { |
| | | editParamForm.id = row.id; |
| | | editParamForm.processId = row.processId; |
| | | editParamForm.paramId = row.paramId; |
| | | editParamForm.paramName = row.paramName; |
| | | editParamForm.valueMode = row.valueMode; |
| | | editParamForm.standardValue = row.standardValue; |
| | | editParamForm.minValue = row.minValue; |
| | | editParamForm.maxValue = row.maxValue; |
| | | editParamForm.sort = row.sort || 1; |
| | | editParamForm.isRequired = row.isRequired || 0; |
| | | editParamForm.tenantId = 1; |
| | | editParamDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleEditParamSubmit = () => { |
| | | editParamFormRef.value.validate(valid => { |
| | | if (valid) { |
| | | editProcessParam(editParamForm) |
| | | .then(() => { |
| | | ElMessage.success("编辑成功"); |
| | | editParamDialogVisible.value = false; |
| | | getParamList(selectedProcess.value.id); |
| | | }) |
| | | .catch(() => { |
| | | ElMessage.error("编辑失败"); |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleParamSubmit = () => { |
| | | if (!selectedParam.value) { |
| | | ElMessage.warning("请先选择一个参数"); |
| | | return; |
| | | } |
| | | }; |
| | | |
| | | // 下载模板 |
| | | const handleDownloadTemplate = async () => { |
| | | try { |
| | | const res = await downloadTemplate(); |
| | | const blob = new Blob([res], { |
| | | type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| | | addProcessParam({ |
| | | processId: selectedProcess.value.id, |
| | | paramId: selectedParam.value.id, |
| | | sort: selectedParam.value.sort || 1, |
| | | standardValue: selectedParam.value.standardValue, |
| | | minValue: selectedParam.value.minValue, |
| | | maxValue: selectedParam.value.maxValue, |
| | | isRequired: selectedParam.value.isRequired || 0, |
| | | tenantId: 1, |
| | | }) |
| | | .then(() => { |
| | | ElMessage.success("添加成功"); |
| | | paramDialogVisible.value = false; |
| | | getParamList(selectedProcess.value.id); |
| | | }) |
| | | .catch(() => { |
| | | ElMessage.error("添加失败"); |
| | | }); |
| | | const url = window.URL.createObjectURL(blob); |
| | | const link = document.createElement("a"); |
| | | link.href = url; |
| | | link.download = "工序导入模板.xlsx"; |
| | | link.click(); |
| | | window.URL.revokeObjectURL(url); |
| | | proxy.$modal.msgSuccess("模板下载成功"); |
| | | } catch (error) { |
| | | proxy.$modal.msgError("模板下载失败"); |
| | | } |
| | | }; |
| | | |
| | | // 导出 |
| | | // const handleOut = () => { |
| | | // ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { |
| | | // confirmButtonText: "确认", |
| | | // cancelButtonText: "取消", |
| | | // type: "warning", |
| | | // }) |
| | | // .then(() => { |
| | | // proxy.download("/salesLedger/scheduling/exportTwo", {}, "工序排产.xlsx"); |
| | | // }) |
| | | // .catch(() => { |
| | | // proxy.$modal.msg("已取消"); |
| | | // }); |
| | | // }; |
| | | const handleParamPagination = obj => { |
| | | paramPage.current = obj.page; |
| | | paramPage.size = obj.limit; |
| | | getParamList(selectedProcess.value.id); |
| | | }; |
| | | |
| | | // 获取数据字典 |
| | | const getDictTypes = () => { |
| | | listType({ pageNum: 1, pageSize: 1000 }).then(res => { |
| | | dictTypes.value = res.rows || []; |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | getProcessList(); |
| | | getDictTypes(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped></style> |
| | | <style scoped lang="scss"> |
| | | .app-container { |
| | | padding: 20px; |
| | | background-color: #f0f2f5; |
| | | min-height: calc(100vh - 84px); |
| | | } |
| | | |
| | | .process-config-container { |
| | | display: flex; |
| | | gap: 20px; |
| | | height: calc(100vh - 124px); |
| | | } |
| | | |
| | | // 左侧工序列表 |
| | | .process-list-section { |
| | | width: 370px; |
| | | min-width: 370px; |
| | | flex-shrink: 0; |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .section-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | |
| | | .section-title { |
| | | margin: 0; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | .process-card-list { |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | padding: 16px; |
| | | } |
| | | |
| | | .process-card { |
| | | background: #fff; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | margin-bottom: 12px; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | &.active { |
| | | border-color: #409eff; |
| | | background: #f5f7fa; |
| | | box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2); |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | |
| | | .process-code { |
| | | font-size: 12px; |
| | | // color: #909399; |
| | | color: #cb9b18; |
| | | font-family: "Courier New", monospace; |
| | | } |
| | | |
| | | .card-actions { |
| | | display: flex; |
| | | gap: 4px; |
| | | |
| | | .el-button { |
| | | padding: 4px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .card-body { |
| | | margin-bottom: 12px; |
| | | |
| | | .process-name { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .process-desc { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | |
| | | .card-footer { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .param-count { |
| | | font-size: 12px; |
| | | color: #606266; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 右侧参数列表 |
| | | .param-list-section { |
| | | flex: 1; |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .param-table-wrapper { |
| | | flex: 1; |
| | | padding: 0 20px 20px; |
| | | overflow: auto; |
| | | } |
| | | |
| | | /* 表格横向滚动 */ |
| | | :deep(.el-table) { |
| | | // min-width: 800px; |
| | | } |
| | | |
| | | .empty-tip { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | // 表格样式 |
| | | :deep(.el-table) { |
| | | border: none; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-table__header-wrapper { |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | |
| | | th { |
| | | background: transparent; |
| | | font-weight: 600; |
| | | // color: #ffffff; |
| | | border-bottom: none; |
| | | padding: 16px 0; |
| | | } |
| | | } |
| | | |
| | | .el-table__body-wrapper { |
| | | tr { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | background: linear-gradient( |
| | | 90deg, |
| | | rgba(102, 126, 234, 0.05) 0%, |
| | | rgba(118, 75, 162, 0.05) 100% |
| | | ); |
| | | } |
| | | |
| | | td { |
| | | border-bottom: 1px solid #f0f0f0; |
| | | padding: 14px 0; |
| | | color: #303133; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 编码单元格样式 |
| | | :deep(.code-cell) { |
| | | color: #e6a23c; |
| | | font-family: "Courier New", monospace; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | // 数值单元格样式 |
| | | :deep(.quantity-cell) { |
| | | font-weight: 600; |
| | | color: #409eff; |
| | | font-family: "Courier New", monospace; |
| | | } |
| | | |
| | | // 选择参数对话框样式 |
| | | .param-select-container { |
| | | display: flex; |
| | | gap: 20px; |
| | | height: 450px; |
| | | |
| | | .param-list-area { |
| | | // flex: 1; |
| | | width: 380px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .area-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 12px; |
| | | padding-bottom: 8px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .search-box { |
| | | margin-bottom: 12px; |
| | | |
| | | .el-input { |
| | | width: 100%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .param-detail-area { |
| | | // width: 380px; |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background: #f5f7fa; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | |
| | | .area-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 16px; |
| | | padding-bottom: 8px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .param-detail-form { |
| | | .el-form-item { |
| | | margin-bottom: 12px; |
| | | |
| | | .el-form-item__label { |
| | | color: #606266; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .detail-text { |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |