zhangwencui
3 天以前 0dc723247c2b9851fd0b9ff0138d63f90a2265e3
人员薪资台账接口调联
已添加3个文件
686 ■■■■■ 文件已修改
src/api/personnelManagement/monthlyStatistics.js 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/monthlyStatistics/components/formDia.vue 318 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/monthlyStatistics/index.vue 303 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/personnelManagement/monthlyStatistics.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
import request from "@/utils/request";
// äººå‘˜è–ªèµ„台账列表
export function monthlyStatisticsListPage(query) {
  return request({
    url: "/compensationPerformance/listPage",
    method: "get",
    params: query,
  });
}
// äººå‘˜è–ªèµ„台账详情
export function monthlyStatisticsGet(id) {
  return request({
    url: "/monthlyStatistics/get",
    method: "get",
    params: { id },
  });
}
// æ–°å¢žäººå‘˜è–ªèµ„台账
export function monthlyStatisticsAdd(data) {
  return request({
    url: "/compensationPerformance/add",
    method: "post",
    data,
  });
}
// ç¼–辑人员薪资台账
export function monthlyStatisticsUpdate(data) {
  return request({
    url: "/compensationPerformance/update",
    method: "post",
    data,
  });
}
// åˆ é™¤äººå‘˜è–ªèµ„台账
export function monthlyStatisticsDelete(ids) {
  return request({
    url: "/compensationPerformance/delete",
    method: "delete",
    data: ids,
  });
}
// å¯¼å‡ºäººå‘˜è–ªèµ„台账
export function monthlyStatisticsExport(query) {
  return request({
    url: "/compensationPerformance/export",
    method: "get",
    params: query,
    responseType: "blob",
  });
}
// äººå‘˜åˆ—表
export function staffOnJobList(query) {
  return request({
    url: "/staff/staffOnJob/list",
    method: "get",
    params: query,
  });
}
src/views/personnelManagement/monthlyStatistics/components/formDia.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,318 @@
<template>
  <el-dialog v-model="dialogVisible"
             :title="title"
             width="700px"
             :close-on-click-modal="false">
    <el-form ref="formRef"
             :model="form"
             :rules="rules"
             label-width="140px"
             label-position="top">
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="统计月份"
                        prop="payDate">
            <el-date-picker v-model="form.payDate"
                            type="month"
                            value-format="YYYY-MM"
                            format="YYYY-MM"
                            placeholder="请选择月份"
                            style="width: 100%"
                            :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="姓名"
                        prop="staffId">
            <el-select v-model="form.staffId"
                       placeholder="请选择员工"
                       style="width: 100%"
                       :disabled="operationType === 'view'">
              <el-option v-for="item in userList"
                         :key="item.id"
                         :label="item.staffName"
                         :value="item.id" />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="基本工资"
                        prop="basicSalary">
            <el-input v-model="form.basicSalary"
                      type="number"
                      placeholder="请输入基本工资"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="计件工资"
                        prop="pieceworkSalary">
            <el-input v-model="form.pieceworkSalary"
                      type="number"
                      placeholder="请输入计件工资"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="计时工资"
                        prop="hourlySalary">
            <el-input v-model="form.hourlySalary"
                      type="number"
                      placeholder="请输入计时工资"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="其他收入"
                        prop="otherIncome">
            <el-input v-model="form.otherIncome"
                      type="number"
                      placeholder="请输入其他收入"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="社保个人"
                        prop="socialSecurityIndividuals">
            <el-input v-model="form.socialSecurityIndividuals"
                      type="number"
                      placeholder="请输入社保个人"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="公积金个人"
                        prop="providentFundIndividuals">
            <el-input v-model="form.providentFundIndividuals"
                      type="number"
                      placeholder="请输入公积金个人"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="个人所得税"
                        prop="personalIncomeTax">
            <el-input v-model="form.personalIncomeTax"
                      type="number"
                      placeholder="请输入个人所得税"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="其他扣款"
                        prop="otherDeductions">
            <el-input v-model="form.otherDeductions"
                      type="number"
                      placeholder="请输入其他扣款"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="24">
          <el-form-item label="备注"
                        prop="remark">
            <el-input v-model="form.remark"
                      type="textarea"
                      placeholder="请输入备注"
                      :rows="3"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary"
                   @click="submitForm"
                   v-if="operationType !== 'view'">
          ç¡®å®š
        </el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script setup>
  import { ref, reactive, computed, onMounted } from "vue";
  import { ElMessage } from "element-plus";
  import {
    monthlyStatisticsAdd,
    monthlyStatisticsUpdate,
    staffOnJobList,
  } from "@/api/personnelManagement/monthlyStatistics.js";
  const props = defineProps({
    modelValue: {
      type: Boolean,
      default: false,
    },
    operationType: {
      type: String,
      default: "add",
    },
    row: {
      type: Object,
      default: () => ({}),
    },
  });
  const emit = defineEmits(["update:modelValue", "close"]);
  const dialogVisible = computed({
    get: () => props.modelValue,
    set: val => emit("update:modelValue", val),
  });
  const title = computed(() => {
    if (props.operationType === "add") return "新增薪资台账";
    if (props.operationType === "edit") return "编辑薪资台账";
    return "查看薪资台账";
  });
  const formRef = ref();
  const form = reactive({
    id: "",
    payDate: "",
    staffId: "",
    basicSalary: 0,
    pieceworkSalary: 0,
    hourlySalary: 0,
    otherIncome: 0,
    socialSecurityIndividuals: 0,
    providentFundIndividuals: 0,
    personalIncomeTax: 0,
    otherDeductions: 0,
    payableWages: 0,
    deductibleWages: 0,
    actualWages: 0,
    remark: "",
  });
  const rules = {
    payDate: [{ required: true, message: "请选择统计月份", trigger: "change" }],
    staffId: [{ required: true, message: "请选择员工", trigger: "change" }],
    basicSalary: [{ required: true, message: "请输入基本工资", trigger: "blur" }],
  };
  const userList = ref([]);
  const loadUserList = () => {
    // userListNoPage().then(res => {
    //   userList.value = res.data || [];
    // });
    staffOnJobList().then(res => {
      userList.value = res.data || [];
    });
  };
  const openDialog = (type, row) => {
    // é‡ç½®è¡¨å•
    Object.assign(form, {
      id: "",
      payDate: "",
      staffId: "",
      basicSalary: 0,
      pieceworkSalary: 0,
      hourlySalary: 0,
      otherIncome: 0,
      socialSecurityIndividuals: 0,
      providentFundIndividuals: 0,
      personalIncomeTax: 0,
      otherDeductions: 0,
      payableWages: 0,
      deductibleWages: 0,
      actualWages: 0,
      remark: "",
    });
    if (type === "add") {
      dialogVisible.value = true;
    } else if (type === "edit" || type === "view") {
      if (row && row.id) {
        Object.assign(form, row);
        dialogVisible.value = true;
      }
    }
  };
  const submitForm = () => {
    formRef.value.validate(valid => {
      if (valid) {
        form.basicSalary = Number(form.basicSalary);
        form.pieceworkSalary = Number(form.pieceworkSalary);
        form.hourlySalary = Number(form.hourlySalary);
        form.otherIncome = Number(form.otherIncome);
        form.socialSecurityIndividuals = Number(form.socialSecurityIndividuals);
        form.providentFundIndividuals = Number(form.providentFundIndividuals);
        form.personalIncomeTax = Number(form.personalIncomeTax);
        form.otherDeductions = Number(form.otherDeductions);
        // è®¡ç®—应发工资、应扣工资和实发工资
        const payableWages =
          form.basicSalary +
          form.pieceworkSalary +
          form.hourlySalary +
          form.otherIncome;
        const deductibleWages =
          form.socialSecurityIndividuals +
          form.providentFundIndividuals +
          form.personalIncomeTax +
          form.otherDeductions;
        const actualWages = payableWages - deductibleWages;
        const submitData = {
          ...form,
          payableWages,
          deductibleWages,
          actualWages,
        };
        if (props.operationType === "add") {
          monthlyStatisticsAdd(submitData).then(res => {
            if (res.code === 200) {
              ElMessage.success("新增成功");
              dialogVisible.value = false;
              emit("close");
            } else {
              ElMessage.error(res.msg || "新增失败");
            }
          });
        } else if (props.operationType === "edit") {
          monthlyStatisticsUpdate(submitData).then(res => {
            if (res.code === 200) {
              ElMessage.success("更新成功");
              dialogVisible.value = false;
              emit("close");
            } else {
              ElMessage.error(res.msg || "更新失败");
            }
          });
        }
      }
    });
  };
  onMounted(() => {
    loadUserList();
  });
  defineExpose({
    openDialog,
  });
</script>
<style scoped>
  .dialog-footer {
    text-align: right;
  }
</style>
src/views/personnelManagement/monthlyStatistics/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,303 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">姓名:</span>
        <el-input v-model="searchForm.staffName"
                  style="width: 240px"
                  placeholder="请输入姓名搜索"
                  @change="handleQuery"
                  clearable
                  :prefix-icon="Search" />
        <span class="search_title ml10">月份:</span>
        <el-date-picker v-model="searchForm.payDateStr"
                        type="month"
                        @change="handleQuery"
                        value-format="YYYY-MM"
                        format="YYYY-MM"
                        placeholder="请选择月份"
                        style="width: 240px"
                        clearable />
        <el-button type="primary"
                   @click="handleQuery"
                   style="margin-left: 10px">
          æœç´¢
        </el-button>
      </div>
      <div>
        <el-button @click="handleExport"
                   style="margin-right: 10px">导出</el-button>
        <el-button type="primary"
                   @click="openForm('add')">新增台账</el-button>
        <el-button type="danger"
                   plain
                   @click="handleDelete">删除</el-button>
      </div>
    </div>
    <div class="table_list">
      <PIMTable rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :isSelection="true"
                @selection-change="handleSelectionChange"
                :tableLoading="tableLoading"
                @pagination="pagination"
                :total="page.total"></PIMTable>
    </div>
    <form-dia v-model="dialogVisible"
              :operation-type="operationType"
              :row="currentRow"
              ref="formDia"
              @close="handleQuery"></form-dia>
  </div>
</template>
<script setup>
  import { Search } from "@element-plus/icons-vue";
  import {
    onMounted,
    ref,
    reactive,
    toRefs,
    getCurrentInstance,
    nextTick,
  } from "vue";
  import { ElMessageBox } from "element-plus";
  import dayjs from "dayjs";
  import FormDia from "./components/formDia.vue";
  import {
    monthlyStatisticsListPage,
    monthlyStatisticsDelete,
  } from "@/api/personnelManagement/monthlyStatistics.js";
  const data = reactive({
    searchForm: {
      staffName: "",
      payDateStr: "",
    },
  });
  const { searchForm } = toRefs(data);
  const tableColumn = ref([
    {
      label: "员工姓名",
      prop: "staffName",
    },
    {
      label: "部门",
      prop: "deptName",
      width: 140,
    },
    {
      label: "月份",
      prop: "payDate",
    },
    {
      label: "基本工资",
      prop: "basicSalary",
    },
    {
      label: "计件工资",
      prop: "pieceworkSalary",
    },
    {
      label: "计时工资",
      prop: "hourlySalary",
    },
    {
      label: "其他收入",
      prop: "otherIncome",
    },
    {
      label: "社保个人",
      prop: "socialSecurityIndividuals",
    },
    {
      label: "公积金个人",
      prop: "providentFundIndividuals",
      width: 140,
    },
    {
      label: "工资个税",
      prop: "personalIncomeTax",
    },
    {
      label: "其他支出",
      prop: "otherDeductions",
    },
    {
      label: "应发工资",
      prop: "payableWages",
    },
    {
      label: "应扣工资",
      prop: "deductibleWages",
    },
    {
      label: "实发工资",
      prop: "actualWages",
    },
    {
      label: "备注",
      prop: "remark",
      width: 150,
    },
    {
      dataType: "action",
      label: "操作",
      align: "center",
      fixed: "right",
      width: 220,
      operation: [
        {
          name: "编辑",
          type: "text",
          clickFun: row => {
            openForm("edit", row);
          },
        },
        // {
        //   name: "查看",
        //   type: "text",
        //   clickFun: row => {
        //     openForm("view", row);
        //   },
        // },
      ],
    },
  ]);
  const tableData = ref([]);
  const selectedRows = ref([]);
  const tableLoading = ref(false);
  const page = reactive({
    current: 1,
    size: 100,
    total: 0,
  });
  const formDia = ref();
  const dialogVisible = ref(false);
  const operationType = ref("add");
  const currentRow = ref({});
  const { proxy } = getCurrentInstance();
  // æŸ¥è¯¢åˆ—表
  /** æœç´¢æŒ‰é’®æ“ä½œ */
  const handleQuery = () => {
    page.current = 1;
    getList();
  };
  const pagination = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
  const getList = () => {
    tableLoading.value = true;
    monthlyStatisticsListPage({ ...page, ...searchForm.value })
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
      })
      .catch(err => {
        tableLoading.value = false;
      });
  };
  // è¡¨æ ¼é€‰æ‹©æ•°æ®
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  // æ‰“开弹框
  const openForm = (type, row) => {
    operationType.value = type;
    currentRow.value = row || {};
    dialogVisible.value = true;
    nextTick(() => {
      formDia.value?.openDialog(type, row);
    });
  };
  // åˆ é™¤
  const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      ids = selectedRows.value.map(item => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        monthlyStatisticsDelete(ids).then(res => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  // å¯¼å‡º
  const handleExport = () => {
    ElMessageBox.confirm("是否确认导出人员薪资台账?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        proxy.download(
          "/compensationPerformance/export",
          { ...searchForm.value, ...page },
          "人员薪资台账.xlsx"
        );
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  onMounted(() => {
    getList();
  });
</script>
<style scoped>
  .search_form {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    flex-wrap: wrap;
    gap: 10px;
  }
  .search_title {
    font-weight: 500;
    margin-right: 5px;
  }
  .ml10 {
    margin-left: 10px;
  }
  .table_list {
    margin-top: 20px;
  }
  .dialog-footer {
    text-align: right;
  }
</style>