已修改11个文件
252 ■■■■■ 文件已修改
src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/feedbackRegistration/components/formDia.vue 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/classsSheduling/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/dimission/components/formDia.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/dimission/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/components/BasicInfoSection.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/components/EmergencyAndAttachmentSection.vue 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/returnOrder/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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();
    });