已修改5个文件
705 ■■■■■ 文件已修改
src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue 508 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/components/Modal.vue 138 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/indicatorStats/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
@@ -18,7 +18,7 @@
                        placeholder="请选择部门"
                        check-strictly
                        style="width: 100%"
                        :disabled="operationType === 'view'" />
                        :disabled="['edit', 'view'].includes(operationType)" />
      </el-form-item>
      <!-- 地点信息 -->
      <!-- <el-form-item label="地点名称"
@@ -89,6 +89,9 @@
        <el-time-picker v-model="form.endAt"
                        format="HH:mm"
                        value-format="HH:mm"
                        :picker-options="{
      minTime: form.startAt
    }"
                        placeholder="请选择下班时间"
                        :disabled="operationType === 'view'" />
      </el-form-item>
@@ -127,6 +130,7 @@
      default: () => ({}),
    },
  });
  // const pickerOptions = ref({ minTime: form.value.startAt });
  const emit = defineEmits(["update:modelValue", "close"]);
@@ -164,7 +168,28 @@
    latitude: [{ required: true, message: "请选择打卡位置", trigger: "blur" }],
    radius: [{ required: true, message: "请输入打卡范围", trigger: "blur" }],
    startAt: [{ required: true, message: "请选择上班时间", trigger: "change" }],
    endAt: [{ required: true, message: "请选择下班时间", trigger: "change" }],
    endAt: [
      { required: true, message: "请选择下班时间", trigger: "change" },
      {
        validator: (rule, value, callback) => {
          if (form.startAt && value) {
            const startParts = form.startAt.split(":");
            const endParts = value.split(":");
            const startTime =
              parseInt(startParts[0]) * 60 + parseInt(startParts[1]);
            const endTime = parseInt(endParts[0]) * 60 + parseInt(endParts[1]);
            if (endTime <= startTime) {
              callback(new Error("下班时间不能早于上班时间"));
            } else {
              callback();
            }
          } else {
            callback();
          }
        },
        trigger: "change",
      },
    ],
  };
  // 部门选项
@@ -355,6 +380,16 @@
    }
  );
  // 监听上班时间变化,触发下班时间校验
  watch(
    () => form.startAt,
    () => {
      if (formRef.value && form.endAt) {
        formRef.value.validateField("endAt");
      }
    }
  );
  // 监听弹窗显示
  watch(
    () => dialogVisible.value,
src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue
@@ -1,148 +1,189 @@
<template>
  <div>
    <el-dialog
        v-model="dialogFormVisible"
        :title="operationType === 'add' ? '新增入职' : '编辑人员'"
        width="70%"
        @close="closeDia"
    >
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <el-dialog v-model="dialogFormVisible"
               :title="operationType === 'add' ? '新增入职' : '编辑人员'"
               width="70%"
               @close="closeDia">
      <el-form :model="form"
               label-width="140px"
               label-position="top"
               :rules="rules"
               ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="员工编号:" prop="staffNo">
              <el-input v-model="form.staffNo" placeholder="请输入" clearable :disabled="operationType !== 'add'"/>
            <el-form-item label="员工编号:"
                          prop="staffNo">
              <el-input v-model="form.staffNo"
                        placeholder="请输入"
                        clearable
                        :disabled="operationType !== 'add'" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="姓名:" prop="staffName">
              <el-input v-model="form.staffName" placeholder="请输入" clearable/>
            <el-form-item label="姓名:"
                          prop="staffName">
              <el-input v-model="form.staffName"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="性别:" prop="sex">
            <el-form-item label="性别:"
                          prop="sex">
              <el-select v-model="form.sex">
                <el-option label="男" value="男" />
                <el-option label="女" value="女" />
                <el-option label="男"
                           value="男" />
                <el-option label="女"
                           value="女" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="户籍住址:" prop="nativePlace">
              <el-input v-model="form.nativePlace" placeholder="请输入" clearable/>
            <el-form-item label="户籍住址:"
                          prop="nativePlace">
              <el-input v-model="form.nativePlace"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="岗位:" prop="sysPostId">
              <el-select v-model="form.sysPostId" placeholder="请选择岗位" clearable>
                <el-option
                    v-for="item in postOptions"
                    :key="item.postId"
                    :label="item.postName"
                    :value="item.postId"
                    :disabled="item.status === '1'"
                />
            <el-form-item label="岗位:"
                          prop="sysPostId">
              <el-select v-model="form.sysPostId"
                         placeholder="请选择岗位"
                         clearable>
                <el-option v-for="item in postOptions"
                           :key="item.postId"
                           :label="item.postName"
                           :value="item.postId"
                           :disabled="item.status === '1'" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="现住址:" prop="adress">
              <el-input v-model="form.adress" placeholder="请输入" clearable/>
            <el-form-item label="现住址:"
                          prop="adress">
              <el-input v-model="form.adress"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="部门:" prop="sysDeptId">
              <el-tree-select
                  v-model="form.sysDeptId"
                  :data="deptOptions"
                  :props="{ value: 'id', label: 'label', children: 'children' }"
                  value-key="id"
                  placeholder="请选择部门"
                  check-strictly
              />
            <el-form-item label="部门:"
                          prop="sysDeptId">
              <el-tree-select v-model="form.sysDeptId"
                              :data="deptOptions"
                              :props="{ value: 'id', label: 'label', children: 'children' }"
                              value-key="id"
                              placeholder="请选择部门"
                              check-strictly />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="年龄:" prop="age">
              <el-input-number v-model="form.age" :precision="0" :step="1" style="width: 100%"/>
            <el-form-item label="年龄:"
                          prop="age">
              <el-input-number v-model="form.age"
                               :precision="0"
                               :step="1"
                               style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="第一学历:" prop="firstStudy">
              <el-input v-model="form.firstStudy" placeholder="请输入" clearable/>
            <el-form-item label="第一学历:"
                          prop="firstStudy">
              <el-input v-model="form.firstStudy"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="专业:" prop="profession">
              <el-input v-model="form.profession" placeholder="请输入" clearable/>
            <el-form-item label="专业:"
                          prop="profession">
              <el-input v-model="form.profession"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="联系电话:" prop="phone">
              <el-input v-model="form.phone" placeholder="请输入" clearable/>
            <el-form-item label="联系电话:"
                          prop="phone">
              <el-input v-model="form.phone"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="紧急联系人:" prop="emergencyContact">
              <el-input v-model="form.emergencyContact" placeholder="请输入" clearable/>
            <el-form-item label="紧急联系人:"
                          prop="emergencyContact">
              <el-input v-model="form.emergencyContact"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="紧急联系人联系电话:" prop="emergencyContactPhone">
              <el-input v-model="form.emergencyContactPhone" placeholder="请输入" clearable/>
            <el-form-item label="紧急联系人联系电话:"
                          prop="emergencyContactPhone">
              <el-input v-model="form.emergencyContactPhone"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="合同年限:" prop="contractTerm">
              <el-input-number v-model="form.contractTerm" :precision="0" :step="1" style="width: 100%" :disabled="true"/>
            <el-form-item label="合同年限:"
                          prop="contractTerm">
              <el-input-number v-model="form.contractTerm"
                               :precision="0"
                               :step="1"
                               style="width: 100%"
                               :disabled="true" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="合同开始日期:" prop="contractStartTime">
              <el-date-picker
                  v-model="form.contractStartTime"
                  type="date"
                  placeholder="请选择日期"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  clearable
                  style="width: 100%"
                                    @change="calculateContractTerm"
              />
            <el-form-item label="合同开始日期:"
                          prop="contractStartTime">
              <el-date-picker v-model="form.contractStartTime"
                              type="date"
                              placeholder="请选择日期"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              clearable
                              style="width: 100%"
                              @change="calculateContractTerm" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="合同结束日期:" prop="contractEndTime">
              <el-date-picker
                  v-model="form.contractEndTime"
                  type="date"
                  placeholder="请选择日期"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  clearable
                  style="width: 100%"
                                    @change="calculateContractTerm"
              />
            <el-form-item label="合同结束日期:"
                          prop="contractEndTime">
              <el-date-picker v-model="form.contractEndTime"
                              type="date"
                              placeholder="请选择日期"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              clearable
                              style="width: 100%"
                              @change="calculateContractTerm" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确认</el-button>
          <el-button type="primary"
                     @click="submitForm">确认</el-button>
          <el-button @click="closeDia">取消</el-button>
        </div>
      </template>
@@ -151,175 +192,182 @@
</template>
<script setup>
import {ref, onMounted} from "vue";
import {findPostOptions} from "@/api/system/post.js";
import {listDept} from "@/api/system/dept.js";
import {staffOnJobInfo, createStaffOnJob, updateStaffOnJob} from "@/api/personnelManagement/staffOnJob.js";
import {deptTreeSelect} from "@/api/system/user.js";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
  import { ref, onMounted } from "vue";
  import { findPostOptions } from "@/api/system/post.js";
  import { listDept } from "@/api/system/dept.js";
  import {
    staffOnJobInfo,
    createStaffOnJob,
    updateStaffOnJob,
  } from "@/api/personnelManagement/staffOnJob.js";
  import { deptTreeSelect } from "@/api/system/user.js";
  const { proxy } = getCurrentInstance();
  const emit = defineEmits(["close"]);
const dialogFormVisible = ref(false);
const operationType = ref('')
const id = ref(0)
const data = reactive({
  form: {
    staffNo: "",
    staffName: "",
    sex: "",
    nativePlace: "",
    postJob: "",
    adress: "",
    firstStudy: "",
    profession: "",
    age: 0,
    phone: "",
    emergencyContact: "",
    emergencyContactPhone: "",
    contractTerm: 0,
    contractStartTime: "",
    contractEndTime: "",
    sysPostId: undefined,
    sysDeptId: undefined,
  },
  rules: {
    staffNo: [{ required: true, message: "请输入", trigger: "blur" },],
    staffName: [{ required: true, message: "请输入", trigger: "blur" }],
    sex: [{ required: true, message: "请输入", trigger: "blur" }],
    nativePlace: [{ required: true, message: "请输入", trigger: "blur" }],
    postJob: [{ required: true, message: "请输入", trigger: "blur" }],
    adress: [{ required: true, message: "请输入", trigger: "blur" }],
    firstStudy: [{ required: true, message: "请输入", trigger: "blur" }],
    profession: [{ required: true, message: "请输入", trigger: "blur" }],
    age: [{ required: true, message: "请输入", trigger: "blur" }],
    phone: [{ required: true, message: "请输入", trigger: "blur" }],
    emergencyContact: [{ required: true, message: "请输入", trigger: "blur" }],
    emergencyContactPhone: [{ required: true, message: "请输入", trigger: "blur" }],
    contractTerm: [{ required: true, message: "请输入", trigger: "blur" }],
    contractStartTime: [{ required: true, message: "请输入", trigger: "blur" }],
    contractEndTime: [{ required: true, message: "请输入", trigger: "blur" }],
  },
  postOptions: [], // 岗位选项
  deptOptions: [], // 部门选项
});
const { form, rules, postOptions, deptOptions } = toRefs(data);
  const dialogFormVisible = ref(false);
  const operationType = ref("");
  const id = ref(0);
  const data = reactive({
    form: {
      staffNo: "",
      staffName: "",
      sex: "",
      nativePlace: "",
      postJob: "",
      adress: "",
      firstStudy: "",
      profession: "",
      age: 0,
      phone: "",
      emergencyContact: "",
      emergencyContactPhone: "",
      contractTerm: 0,
      contractStartTime: "",
      contractEndTime: "",
      sysPostId: undefined,
      sysDeptId: undefined,
    },
    rules: {
      staffNo: [{ required: true, message: "请输入", trigger: "blur" }],
      staffName: [{ required: true, message: "请输入", trigger: "blur" }],
      sex: [{ required: true, message: "请输入", trigger: "blur" }],
      nativePlace: [{ required: true, message: "请输入", trigger: "blur" }],
      postJob: [{ required: true, message: "请输入", trigger: "blur" }],
      adress: [{ required: true, message: "请输入", trigger: "blur" }],
      firstStudy: [{ required: true, message: "请输入", trigger: "blur" }],
      profession: [{ required: true, message: "请输入", trigger: "blur" }],
      age: [{ required: true, message: "请输入", trigger: "blur" }],
      phone: [{ required: true, message: "请输入", trigger: "blur" }],
      emergencyContact: [{ required: true, message: "请输入", trigger: "blur" }],
      emergencyContactPhone: [
        { required: true, message: "请输入", trigger: "blur" },
      ],
      contractTerm: [{ required: true, message: "请输入", trigger: "blur" }],
      contractStartTime: [{ required: true, message: "请输入", trigger: "blur" }],
      contractEndTime: [{ required: true, message: "请输入", trigger: "blur" }],
      sysDeptId: [{ required: true, message: "请选择", trigger: "change" }],
    },
    postOptions: [], // 岗位选项
    deptOptions: [], // 部门选项
  });
  const { form, rules, postOptions, deptOptions } = toRefs(data);
// 打开弹框
const openDialog = (type, row) => {
  operationType.value = type;
  dialogFormVisible.value = true;
  if (operationType.value === 'edit') {
    id.value = row.id
    staffOnJobInfo(id.value, {}).then(res => {
      form.value = {...res.data}
      if (form.value.sysPostId === 0) {
        form.value.sysPostId = undefined
      }
      if (form.value.sysDeptId === 0) {
        form.value.sysDeptId = undefined
      }
      // 编辑时也计算一次合同年限
      calculateContractTerm();
    })
  } else {
        form.value.id = ''
    }
}
onMounted(() => {
  fetchPostOptions()
  fetchDeptOptions()
})
const fetchPostOptions = () => {
  findPostOptions().then(res => {
    postOptions.value = res.data
  })
}
// 查询部门列表
const fetchDeptOptions = () => {
  deptTreeSelect().then(response => {
    deptOptions.value = filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
  })
}
/** 过滤禁用的部门 */
function filterDisabledDept(deptList) {
  return deptList.filter(dept => {
    if (dept.disabled) {
      return false
  // 打开弹框
  const openDialog = (type, row) => {
    operationType.value = type;
    dialogFormVisible.value = true;
    if (operationType.value === "edit") {
      id.value = row.id;
      staffOnJobInfo(id.value, {}).then(res => {
        form.value = { ...res.data };
        if (form.value.sysPostId === 0) {
          form.value.sysPostId = undefined;
        }
        if (form.value.sysDeptId === 0) {
          form.value.sysDeptId = undefined;
        }
        // 编辑时也计算一次合同年限
        calculateContractTerm();
      });
    } else {
      form.value.id = "";
    }
    if (dept.children && dept.children.length) {
      dept.children = filterDisabledDept(dept.children)
    }
    return true
  })
}
  };
  onMounted(() => {
    fetchPostOptions();
    fetchDeptOptions();
  });
// 提交产品表单
const submitForm = () => {
  if (!form.value.sysPostId) {
    form.value.sysPostId = 0;
  const fetchPostOptions = () => {
    findPostOptions().then(res => {
      postOptions.value = res.data;
    });
  };
  // 查询部门列表
  const fetchDeptOptions = () => {
    deptTreeSelect().then(response => {
      deptOptions.value = filterDisabledDept(
        JSON.parse(JSON.stringify(response.data))
      );
    });
  };
  /** 过滤禁用的部门 */
  function filterDisabledDept(deptList) {
    return deptList.filter(dept => {
      if (dept.disabled) {
        return false;
      }
      if (dept.children && dept.children.length) {
        dept.children = filterDisabledDept(dept.children);
      }
      return true;
    });
  }
  if (!form.value.sysDeptId) {
    form.value.sysDeptId = 0;
  }
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      if (operationType.value === "add") {
        createStaffOnJob(form.value).then(res => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
        })
  // 提交产品表单
  const submitForm = () => {
    if (!form.value.sysPostId) {
      form.value.sysPostId = undefined;
    }
    if (!form.value.sysDeptId) {
      form.value.sysDeptId = undefined;
    }
    proxy.$refs.formRef.validate(valid => {
      if (valid) {
        if (operationType.value === "add") {
          createStaffOnJob(form.value).then(res => {
            proxy.$modal.msgSuccess("提交成功");
            closeDia();
          });
        } else {
          updateStaffOnJob(id.value, form.value).then(res => {
            proxy.$modal.msgSuccess("提交成功");
            closeDia();
          });
        }
      }
    });
  };
  // 计算合同年限
  const calculateContractTerm = () => {
    if (form.value.contractStartTime && form.value.contractEndTime) {
      const startDate = new Date(form.value.contractStartTime);
      const endDate = new Date(form.value.contractEndTime);
      if (endDate > startDate) {
        // 计算年份差
        const yearDiff = endDate.getFullYear() - startDate.getFullYear();
        const monthDiff = endDate.getMonth() - startDate.getMonth();
        const dayDiff = endDate.getDate() - startDate.getDate();
        let years = yearDiff;
        // 如果结束日期的月日小于开始日期的月日,则减去1年
        if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
          years = yearDiff - 1;
        }
        form.value.contractTerm = Math.max(0, years);
      } else {
        updateStaffOnJob(id.value, form.value).then(res => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
        })
        form.value.contractTerm = 0;
      }
    }
  })
}
// 计算合同年限
const calculateContractTerm = () => {
  if (form.value.contractStartTime && form.value.contractEndTime) {
    const startDate = new Date(form.value.contractStartTime);
    const endDate = new Date(form.value.contractEndTime);
    if (endDate > startDate) {
      // 计算年份差
      const yearDiff = endDate.getFullYear() - startDate.getFullYear();
      const monthDiff = endDate.getMonth() - startDate.getMonth();
      const dayDiff = endDate.getDate() - startDate.getDate();
      let years = yearDiff;
      // 如果结束日期的月日小于开始日期的月日,则减去1年
      if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
        years = yearDiff - 1;
      }
      form.value.contractTerm = Math.max(0, years);
    } else {
      form.value.contractTerm = 0;
    }
  } else {
    form.value.contractTerm = 0;
  }
};
  };
// 关闭弹框
const closeDia = () => {
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
  emit('close')
};
defineExpose({
  openDialog,
});
  // 关闭弹框
  const closeDia = () => {
    proxy.resetForm("formRef");
    dialogFormVisible.value = false;
    emit("close");
  };
  defineExpose({
    openDialog,
  });
</script>
<style scoped>
</style>
src/views/procurementManagement/invoiceEntry/components/Modal.vue
@@ -133,10 +133,15 @@
                />
                <el-table-column label="本次开票数" prop="ticketsNum" width="180">
                    <template #default="scope">
                        <el-input-number :step="0.1" :min="0" :max="scope.row.tempFutureTickets || 0" style="width: 100%"
                                                         :precision="2"
                                                         v-model="scope.row.ticketsNum"
                                                         @change="invoiceNumBlur(scope.row)"
                        <el-input-number
                            :step="0.1"
                            :min="0"
                            :max="scope.row.tempFutureTickets || 0"
                            style="width: 100%"
                            :precision="2"
                            v-model="scope.row.ticketsNum"
                            :disabled="isProductDisabled(scope.row)"
                            @change="invoiceNumBlur(scope.row)"
                        />
                    </template>
                </el-table-column>
@@ -146,10 +151,14 @@
                    width="180"
                >
                    <template #default="scope">
                        <el-input-number :step="0.01" :min="0" style="width: 100%"
                                                         :precision="2"
                                                         v-model="scope.row.ticketsAmount"
                                                         @change="invoiceAmountBlur(scope.row)"
                        <el-input-number
                            :step="0.01"
                            :min="0"
                            style="width: 100%"
                            :precision="2"
                            v-model="scope.row.ticketsAmount"
                            :disabled="isProductDisabled(scope.row)"
                            @change="invoiceAmountBlur(scope.row)"
                        />
                    </template>
                </el-table-column>
@@ -402,7 +411,7 @@
            
            // 设置产品数据,并初始化开票数量和金额
            allProductData.forEach(item => {
                // 保存“原始未来票数/金额”(用于校验与计算)
                // 保存"原始未来票数/金额"(用于校验与计算)
                // 优先使用后端返回的 futureTickets/futureTicketsAmount;没有则回退到 quantity/taxInclusiveTotalPrice
                item.tempFutureTickets = Number(
                    item.futureTickets !== undefined ? item.futureTickets : (item.quantity || 0)
@@ -411,15 +420,23 @@
                    item.futureTicketsAmount !== undefined ? item.futureTicketsAmount : (item.taxInclusiveTotalPrice || 0)
                );
                // 新增时:本次开票数默认 = 未来票数(且不能大于未来票数)
                item.ticketsNum = Number(item.tempFutureTickets || 0);
                // 联动计算本次开票金额、未来票数、未来票金额
                const unitPrice = Number(item.taxInclusiveUnitPrice || 0);
                item.ticketsAmount = Number((item.ticketsNum * unitPrice).toFixed(2));
                item.futureTickets = Number((item.tempFutureTickets - item.ticketsNum).toFixed(2));
                item.futureTicketsAmount = Number(
                    (item.tempFutureTicketsAmount - item.ticketsAmount).toFixed(2)
                );
                // 如果未来票金额为0,则本次开票数和金额都设置为0
                if (item.tempFutureTicketsAmount <= 0) {
                    item.ticketsNum = 0;
                    item.ticketsAmount = 0;
                    item.futureTickets = Number(item.tempFutureTickets || 0);
                    item.futureTicketsAmount = 0;
                } else {
                    // 新增时:本次开票数默认 = 未来票数(且不能大于未来票数)
                    item.ticketsNum = Number(item.tempFutureTickets || 0);
                    // 联动计算本次开票金额、未来票数、未来票金额
                    const unitPrice = Number(item.taxInclusiveUnitPrice || 0);
                    item.ticketsAmount = Number((item.ticketsNum * unitPrice).toFixed(2));
                    item.futureTickets = Number((item.tempFutureTickets - item.ticketsNum).toFixed(2));
                    item.futureTicketsAmount = Number(
                        (item.tempFutureTicketsAmount - item.ticketsAmount).toFixed(2)
                    );
                }
            });
            
            form.productData = allProductData;
@@ -435,15 +452,45 @@
        });
    } else if (type == "edit") {
        const id = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows;
        const data = await getPurchaseById({ id, type: 2 });
        form.purchaseLedgerNo = data.purchaseContractNumber;
        const response = await getPurchaseById({ id, type: 2 });
        // 兼容不同的返回格式:可能是 { code, data } 或直接返回数据
        const data = response.data || response;
        // 兼容不同的字段名:purchaseContractNumber 或 purchaseLedgerNo
        form.purchaseLedgerNo = data.purchaseContractNumber || data.purchaseLedgerNo || "";
        form.invoiceAmount = data.invoiceAmount;
        form.invoiceNumber = data.invoiceNumber;
        form.salesContractNo = data.salesContractNo;
        form.projectName = data.projectName;
        form.supplierName = data.supplierName;
        form.entryDate = data.entryDate;
        form.productData = data.productData;
        form.enterDate = data.enterDate || dayjs().format("YYYY-MM-DD");
        // 编辑时也需要初始化产品数据的 tempFutureTickets 和 tempFutureTicketsAmount
        // 同时为每个产品添加合同号等信息
        const contractNumber = data.purchaseContractNumber || data.purchaseLedgerNo || "";
        if (data.productData && Array.isArray(data.productData)) {
            data.productData.forEach(item => {
                // 保存"原始未来票数/金额"(用于校验与计算)
                // 优先使用后端返回的 futureTickets/futureTicketsAmount;没有则回退到 quantity/taxInclusiveTotalPrice
                item.tempFutureTickets = Number(
                    item.futureTickets !== undefined ? item.futureTickets : (item.quantity || 0)
                );
                item.tempFutureTicketsAmount = Number(
                    item.futureTicketsAmount !== undefined ? item.futureTicketsAmount : (item.taxInclusiveTotalPrice || 0)
                );
                // 确保每个产品都有合同号,用于显示在"所属合同"列
                if (!item.purchaseLedgerNo) {
                    item.purchaseLedgerNo = contractNumber;
                }
            });
        }
        form.productData = data.productData || [];
        // 编辑模式下,根据产品数据中的本次开票金额自动计算发票金额
        calculateinvoiceAmount();
    }
};
// 子表合计方法
@@ -515,22 +562,45 @@
    form.invoiceAmount = Number(invoiceAmountTotal.toFixed(2));
};
const open = async (type, selectedRows) => {
    visible.value = true;
// 判断产品是否可以继续来票操作:如果未来票数和未来票金额都为0或小于等于0,则禁用
const isProductDisabled = (row) => {
    // 优先使用 tempFutureTickets(原始未来票数),如果没有则使用 futureTickets
    const futureTickets = Number(row.tempFutureTickets !== undefined
        ? row.tempFutureTickets
        : (row.futureTickets !== undefined ? row.futureTickets : 0));
    
    // 如果是批量操作,设置标题
    if (Array.isArray(selectedRows) && selectedRows.length > 1) {
        modalOptions.value = {
            ...(modalOptions.value || {}),
            title: `批量新增 (${selectedRows.length}条)`,
        };
    } else {
        modalOptions.value = {
            ...(modalOptions.value || {}),
            title: type === "add" ? "新增" : "编辑",
        };
    // 优先使用 tempFutureTicketsAmount(原始未来票金额),如果没有则使用 futureTicketsAmount
    const futureAmount = Number(row.tempFutureTicketsAmount !== undefined
        ? row.tempFutureTicketsAmount
        : (row.futureTicketsAmount !== undefined ? row.futureTicketsAmount : 0));
    // 只有当未来票数和未来票金额都为0或小于等于0时,才禁用
    return futureTickets <= 0 && futureAmount <= 0;
};
const open = async (type, selectedRows) => {
    // 确保 modalOptions.value 是对象
    if (!modalOptions.value || typeof modalOptions.value !== 'object') {
        modalOptions.value = {};
    }
    
    // 根据操作类型和选中数据设置标题
    if (Array.isArray(selectedRows) && selectedRows.length > 1) {
        // 批量操作
        modalOptions.value.title = type === "add" ? `批量新增 (${selectedRows.length}条)` : `批量编辑 (${selectedRows.length}条)`;
    } else {
        // 单个操作 - 明确判断 type 的值
        if (type === "add" || type === "新增") {
            modalOptions.value.title = "新增";
        } else if (type === "edit" || type === "编辑") {
            modalOptions.value.title = "编辑";
        } else {
            modalOptions.value.title = "来票登记"; // 默认标题
        }
    }
    visible.value = true;
    // 如果是单个操作,获取id
    if (!Array.isArray(selectedRows) || selectedRows.length === 1) {
        const idValue = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows;
src/views/procurementManagement/invoiceEntry/index.vue
@@ -39,7 +39,7 @@
        <div></div>
        <div>
          <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
          <el-button type="primary" @click="handleAdd('add')">
          <el-button type="primary" @click="handleAdd('add')" :disabled="isInvoiceDisabled">
            来票登记
          </el-button>
<!--          <el-button type="danger" plain @click="handleDelete">删除</el-button>-->
@@ -84,7 +84,7 @@
<script setup>
import { usePaginationApi } from "@/hooks/usePaginationApi";
import {delRegistration, gePurchaseListPage} from "@/api/procurementManagement/invoiceEntry.js";
import { nextTick, onMounted, getCurrentInstance, ref } from "vue";
import { nextTick, onMounted, getCurrentInstance, ref, computed } from "vue";
import ExpandTable from "./components/ExpandTable.vue";
import Modal from "./components/Modal.vue";
import {ElMessageBox} from "element-plus";
@@ -186,6 +186,18 @@
  );
};
// 计算是否可以来票登记:如果所有选中行的待来票金额都为0,则禁用按钮
const isInvoiceDisabled = computed(() => {
  if (selectedRows.value.length === 0) {
    return true;
  }
  // 如果所有选中行的待来票金额都为0或小于等于0,则禁用
  return selectedRows.value.every(row => {
    const amount = parseFloat(row.unReceiptPaymentAmount || 0);
    return amount <= 0;
  });
});
const handleAdd = (type) => {
    if (selectedRows.value.length < 1) {
        proxy.$modal.msgWarning("请至少选中一条数据");
src/views/salesManagement/indicatorStats/index.vue
@@ -98,11 +98,11 @@
              <label class="filter-label">日期范围</label>
              <el-date-picker 
                v-model="indicatorFilter.dateRange" 
                type="daterange"
                type="monthrange"
                range-separator="至"
                start-placeholder="开始日期" 
                end-placeholder="结束日期" 
                value-format="YYYY-MM-DD"
                value-format="YYYY-MM"
                style="width: 100%" 
              />
            </div>