src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue
@@ -16,8 +16,8 @@ </el-form> <!-- 列表 --> <el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row row-key="id" @selection-change="handleSelectionChange" @select="handleSelect"> <el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row :row-key="getRowKey" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55" /> <el-table-column type="index" label="序号" width="60" /> <template v-for="column in visibleColumns" :key="column.prop"> @@ -79,8 +79,8 @@ }); const query = reactive({ productName: "", model: "", productCategory: "", unit: "", }); const page = reactive({ @@ -92,6 +92,7 @@ const tableData = ref([]); const total = ref(0); const multipleSelection = ref([]); const selectedRowMap = ref(new Map()); const tableRef = ref(); const columnsDialogVisible = ref(false); @@ -106,6 +107,29 @@ const visibleColumns = computed(() => { return allColumns.value.filter(c => selectedColumns.value.includes(c.prop)); }); const getRowKey = (row) => { return row?.id ?? row?.productModelId ?? `${row?.productCategory || ""}-${row?.specificationModel || row?.model || ""}-${row?.unit || ""}`; }; const syncMultipleSelection = () => { multipleSelection.value = Array.from(selectedRowMap.value.values()); }; const initSelectionFromProps = () => { const selectedIdSet = new Set((props.selectedIds || []).map((id) => String(id))); selectedRowMap.value = new Map(); if (!selectedIdSet.size) { syncMultipleSelection(); return; } (props.products || []).forEach((row) => { if (selectedIdSet.has(String(row?.id))) { selectedRowMap.value.set(getRowKey(row), row); } }); syncMultipleSelection(); }; const resetColumns = () => { selectedColumns.value = allColumns.value.filter(c => c.selected).map(c => c.prop); @@ -124,39 +148,33 @@ } const handleSelectionChange = (val) => { const currentPageKeys = new Set(tableData.value.map((item) => getRowKey(item))); currentPageKeys.forEach((key) => selectedRowMap.value.delete(key)); if (props.single && val.length > 1) { // 如果限制为单个选择,只保留最后一个选中的 const lastSelected = val[val.length - 1]; multipleSelection.value = [lastSelected]; // 清空表格选中状态,然后重新选中最后一个 selectedRowMap.value = new Map(); if (lastSelected) { selectedRowMap.value.set(getRowKey(lastSelected), lastSelected); } syncMultipleSelection(); nextTick(() => { if (tableRef.value) { tableRef.value.clearSelection(); tableRef.value.toggleRowSelection(lastSelected, true); } }); } else { multipleSelection.value = val; } } // 处理单个选择 const handleSelect = (selection, row) => { if (props.single) { // 如果限制为单个,清空其他选择,只保留当前行 if (selection.includes(row)) { // 选中当前行时,清空其他选中 multipleSelection.value = [row]; nextTick(() => { if (tableRef.value) { tableData.value.forEach((item) => { if (item.id !== row.id) { tableRef.value.toggleRowSelection(item, false); } }); } }); } else if (props.single) { selectedRowMap.value = new Map(); if (val[0]) { selectedRowMap.value.set(getRowKey(val[0]), val[0]); } syncMultipleSelection(); } else { val.forEach((row) => { selectedRowMap.value.set(getRowKey(row), row); }); syncMultipleSelection(); } } @@ -166,8 +184,8 @@ } function onReset() { query.productName = ""; query.model = ""; query.productCategory = ""; query.unit = ""; page.pageNum = 1; loadData(); } @@ -192,32 +210,29 @@ async function loadData() { loading.value = true; try { multipleSelection.value = []; // 翻页/搜索后清空选择更符合预期 let filtered = props.products || []; // 本地搜索过滤 if (query.productName) { filtered = filtered.filter(item => item.productName && item.productName.includes(query.productName)); if (query.productCategory) { filtered = filtered.filter(item => item.productCategory && item.productCategory.includes(query.productCategory)); } if (query.model) { filtered = filtered.filter(item => item.model && item.model.includes(query.model)); if (query.unit) { filtered = filtered.filter(item => item.unit && item.unit.includes(query.unit)); } total.value = filtered.length; // 前端分页 const start = (page.pageNum - 1) * page.pageSize; const end = start + page.pageSize; tableData.value = filtered.slice(start, end); // 自动回显选中状态 nextTick(() => { if (tableRef.value) { tableRef.value.clearSelection(); tableData.value.forEach(row => { if (props.selectedIds && props.selectedIds.includes(row.id)) { if (selectedRowMap.value.has(getRowKey(row))) { tableRef.value.toggleRowSelection(row, true); } }); } syncMultipleSelection(); }); } finally { loading.value = false; @@ -227,16 +242,31 @@ // 监听弹窗打开,重置选择 watch(() => props.modelValue, (visible) => { if (visible) { // 每次打开时重新初始化选中状态(multipleSelection 会通过 loadData 中的回显逻辑自动更新,但初始需置空避免重复) multipleSelection.value = []; initSelectionFromProps(); page.pageNum = 1; loadData(); } }); // 监听数据源变化 watch(() => props.products, () => { loadData(); const latestMap = new Map(); const currentKeys = new Set(selectedRowMap.value.keys()); (props.products || []).forEach((row) => { const key = getRowKey(row); if (currentKeys.has(key)) { latestMap.set(key, row); } }); selectedRowMap.value.forEach((row, key) => { if (!latestMap.has(key)) { latestMap.set(key, row); } }); selectedRowMap.value = latestMap; syncMultipleSelection(); if (props.modelValue) { loadData(); } }, { deep: true }); onMounted(() => { src/views/customerService/feedbackRegistration/components/formDia.vue
@@ -185,6 +185,31 @@ const serviceTypeOptions = computed(() => post_sale_waiting_list?.value || []); const urgencyOptions = computed(() => degree_of_urgency?.value || []); const getProductRowId = (row) => { return row?.id ?? row?.productModelId ?? row?.modelId ?? `${row?.productCategory || row?.productName || ""}-${row?.specificationModel || row?.model || ""}-${row?.unit || ""}` } const normalizeProductRow = (row) => { return { ...row, id: getProductRowId(row), productCategory: row?.productCategory ?? row?.productName ?? '', specificationModel: row?.specificationModel ?? row?.model ?? '', unit: row?.unit ?? '', approveStatus: row?.approveStatus ?? null, shippingStatus: row?.shippingStatus ?? '', expressCompany: row?.expressCompany ?? '', expressNumber: row?.expressNumber ?? '', shippingCarNumber: row?.shippingCarNumber ?? '', shippingDate: row?.shippingDate ?? '', quantity: row?.quantity ?? 0, taxRate: row?.taxRate ?? 0, taxInclusiveUnitPrice: row?.taxInclusiveUnitPrice ?? 0, taxInclusiveTotalPrice: row?.taxInclusiveTotalPrice ?? 0, taxExclusiveTotalPrice: row?.taxExclusiveTotalPrice ?? 0, } } const tableColumn = ref([ { label: "产品大类", prop: "productCategory" }, { label: "规格型号", prop: "specificationModel" }, @@ -239,7 +264,7 @@ name: "删除", type: "text", clickFun: (row) => { tableData.value = tableData.value.filter(i => i.id !== row.id) tableData.value = tableData.value.filter(i => getProductRowId(i) !== getProductRowId(row)) }, }, @@ -251,37 +276,21 @@ const isShowProductSelectDialog = ref(false) const handleSelectProducts = (rows) => { if (!Array.isArray(rows)) return const existingIds = new Set(tableData.value.map(i => i.id)) const existingIds = new Set(tableData.value.map(i => String(getProductRowId(i)))) const mapped = rows .filter(r => !existingIds.has(r.id)) .map(r => ({ id: r.id, productCategory: r.productName, specificationModel: r.model, unit: r.unit || '', approveStatus: null, shippingStatus: '', expressCompany: '', expressNumber: '', shippingCarNumber: '', shippingDate: '', quantity: 0, taxRate: 0, taxInclusiveUnitPrice: 0, taxInclusiveTotalPrice: 0, taxExclusiveTotalPrice: 0, })) .map(normalizeProductRow) .filter(r => !existingIds.has(String(getProductRowId(r)))) tableData.value = tableData.value.concat(mapped) } const currentSelectedProductIds = computed(() => { return tableData.value.map(item => item.id) return tableData.value.map(item => getProductRowId(item)).filter(item => item !== undefined && item !== null && item !== '') }) const associatedSalesOrderNumberChange = () => { const opt = associatedSalesOrderNumberOptions.value.find( (item) => item.value === form.value.salesContractNo ) tableData.value = opt?.productData || [] tableData.value = (opt?.productData || []).map(normalizeProductRow) form.value.salesLedgerId = opt?.id || null } @@ -291,7 +300,7 @@ const opt = associatedSalesOrderNumberOptions.value.find( (item) => item.value === form.value.salesContractNo ) return opt?.productData || [] return (opt?.productData || []).map(normalizeProductRow) }) const customerNameChange = (val) => { src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
@@ -56,6 +56,7 @@ <el-table :data="tableData" border v-loading="tableLoading" height="calc(100vh - 18.5em)" style="width: 100%" row-key="id"> <el-table-column type="index" @@ -312,4 +313,4 @@ .mt10 { margin-top: 10px; } </style> </style> src/views/personnelManagement/classsSheduling/index.vue
@@ -974,7 +974,7 @@ .user-stats { /* display: flex; */ /* flex-wrap: wrap; gap: 10px; */ gap: 10px; */ margin-bottom: 4px; } @@ -1224,6 +1224,7 @@ display: flex; flex-direction: column; align-items: center; height: 65px; } /* 月度出勤 */ src/views/personnelManagement/dimission/components/formDia.vue
@@ -97,6 +97,18 @@ </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="离职日期:" prop="leaveDate"> <el-date-picker v-model="form.leaveDate" type="date" placeholder="请选择离职日期" value-format="YYYY-MM-DD" format="YYYY-MM-DD" style="width: 100%" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="离职原因:" prop="reason"> <el-select v-model="form.reason" placeholder="请选择离职原因" style="width: 100%" @change="handleSelectDimissionReason"> <el-option @@ -108,6 +120,8 @@ </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="备注:" prop="remark" v-if="form.reason === 'other'"> <el-input @@ -168,11 +182,13 @@ const data = reactive({ form: { staffOnJobId: undefined, leaveDate: "", reason: "", remark: "", }, rules: { staffName: [{ required: true, message: "请选择人员" }], leaveDate: [{ required: true, message: "请选择离职日期", trigger: "change" }], reason: [{ required: true, message: "请选择离职原因"}], }, dimissionReasonOptions: [ @@ -193,6 +209,7 @@ if (operationType.value === 'edit') { currentStaffRecord.value = row form.value.staffOnJobId = row.staffOnJobId form.value.leaveDate = row.leaveDate form.value.reason = row.reason form.value.remark = row.remark personList.value = [ @@ -239,6 +256,7 @@ // 表单已注释,手动重置表单数据 form.value = { staffOnJobId: undefined, leaveDate: "", reason: "", remark: "", }; src/views/personnelManagement/dimission/index.vue
@@ -18,7 +18,7 @@ <div> <el-button type="primary" @click="openForm('add')">新增离职</el-button> <el-button @click="handleOut">导出</el-button> <el-button type="danger" plain @click="handleDelete">删除</el-button> <!-- <el-button type="danger" plain @click="handleDelete">删除</el-button> --> </div> </div> <div class="table_list"> @@ -76,6 +76,10 @@ }, }, { label: "离职日期", prop: "leaveDate", }, { label: "员工编号", prop: "staffNo", }, src/views/personnelManagement/employeeRecord/components/BasicInfoSection.vue
@@ -124,10 +124,10 @@ clearable style="width: 100%" > <el-option label="未婚" value="single" /> <el-option label="已婚" value="married" /> <el-option label="离异" value="divorced" /> <el-option label="丧偶" value="widowed" /> <el-option label="未婚" value="未婚" /> <el-option label="已婚" value="已婚" /> <el-option label="离异" value="离异" /> <el-option label="丧偶" value="丧偶" /> </el-select> </el-form-item> </el-col> src/views/personnelManagement/employeeRecord/components/EmergencyAndAttachmentSection.vue
@@ -68,41 +68,14 @@ </el-table> <div class="table-add-row" @click="addEmergencyRow">新建一行</div> </el-card> <!-- 材料附件 --> <el-card class="form-card" shadow="never"> <template #header> <div class="card-title"> <span class="card-title-line">|</span> <span>材料附件</span> <span class="upload-tip"> 图片支持jpeg、jpg、png等格式,附件文件支持pdf、rar、zip、doc、docx格式。 </span> </div> </template> <el-form-item label="附件"> <el-upload v-model:file-list="form.attachments" action="#" :auto-upload="false" multiple list-type="picture-card" > <el-icon> <Plus /> </el-icon> </el-upload> </el-form-item> </el-card> </div> </template> <script setup> import { toRefs } from "vue"; import { Plus } from "@element-plus/icons-vue"; const props = defineProps({ form: { type: Object, required: true }, form: { type: Object, required: true } }); const { form } = toRefs(props); @@ -137,12 +110,6 @@ color: #409eff; cursor: pointer; font-size: 14px; } .upload-tip { margin-left: 12px; font-size: 12px; color: #909399; } </style> src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue
@@ -130,8 +130,6 @@ staffEmergencyContactList: [createEmptyEmergency()], // 角色(单选) roleId: undefined, // 材料附件(仅前端展示) attachments: [], }); const state = reactive({ src/views/personnelManagement/employeeRecord/index.vue
@@ -21,7 +21,7 @@ <div> <el-button type="primary" @click="openFormNewOrEditFormDia('add')">新增入职</el-button> <el-button @click="handleOut">导出</el-button> <el-button type="danger" plain @click="handleDelete">删除</el-button> <!-- <el-button type="danger" plain @click="handleDelete">删除</el-button> --> </div> </div> <div class="table_list"> src/views/salesManagement/returnOrder/index.vue
@@ -95,7 +95,7 @@ cancelButtonText: "取消", type: "warning", }).then(() => { returnManagementDel({ ids: [row.id] }).then(() => { returnManagementDel([row.id]).then(() => { proxy.$modal.msgSuccess("删除成功"); getList(); });