view.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. <template>
  2. <el-dialog
  3. title="工资信息"
  4. v-model="visible"
  5. :width="width"
  6. append-to-body
  7. draggable
  8. @close="close"
  9. >
  10. <!-- 功能按钮 -->
  11. <div style="padding: 8px 24px 16px 24px">
  12. <el-form size="small" label-width="100px" v-model="form">
  13. <el-row :gutter="30">
  14. <el-col :span="12">
  15. <el-form-item label="客户名称">
  16. <div>{{ form.companyName }}</div>
  17. </el-form-item>
  18. </el-col>
  19. <el-col :span="12">
  20. <el-form-item label="所属月份">
  21. <div>{{ form.year }}-{{ form.month }}</div>
  22. </el-form-item>
  23. </el-col>
  24. <el-col :span="24" class="details-container">
  25. <div class="details-head">
  26. <div class="title">
  27. <i class="fa fa-th-list" aria-hidden="true" /> 人员信息
  28. <el-button
  29. size="small"
  30. @click="printSalary"
  31. icon="printer"
  32. type="primary"
  33. >打印</el-button
  34. >
  35. <el-button
  36. size="small"
  37. @click="exportSalary"
  38. icon="download"
  39. type="info"
  40. >导出</el-button
  41. >
  42. </div>
  43. </div>
  44. <div class="details-body">
  45. <div>
  46. <el-table
  47. ref="sourceTable"
  48. :data="form.details"
  49. size="small"
  50. max-height="260px"
  51. border
  52. show-summary
  53. :summary-method="getSummaries"
  54. highlight-current-row
  55. header-row-class-name="list-header-row"
  56. row-class-name="list-row"
  57. @selection-change="handleCheckChange"
  58. @current-change="handleCurrentChange"
  59. >
  60. <el-table-column
  61. type="index"
  62. label="序号"
  63. width="50"
  64. align="center"
  65. />
  66. <el-table-column label="员工姓名" width="80" align="center">
  67. <template #default="scope">
  68. <div>
  69. {{ scope.row.employeeName }}
  70. </div>
  71. <span
  72. style="
  73. color: red;
  74. position: absolute;
  75. z-index: 10;
  76. top: 4px;
  77. right: 6px;
  78. "
  79. >*</span
  80. >
  81. </template>
  82. </el-table-column>
  83. <el-table-column label="身份证号" width="150" align="center">
  84. <template #default="scope">
  85. <div>
  86. {{ scope.row.idCode }}
  87. </div>
  88. <span
  89. style="
  90. color: red;
  91. position: absolute;
  92. z-index: 10;
  93. top: 4px;
  94. right: 6px;
  95. "
  96. >*</span
  97. >
  98. </template>
  99. </el-table-column>
  100. <el-table-column
  101. label="应发工资"
  102. width="70"
  103. header-align="center"
  104. align="right"
  105. prop="planSalary"
  106. >
  107. <template #default="scope">
  108. <div>
  109. {{ rowNum(scope.row.planSalary) }}
  110. </div>
  111. </template>
  112. </el-table-column>
  113. <el-table-column
  114. label="实发工资"
  115. width="70"
  116. header-align="center"
  117. align="right"
  118. prop="actuallySalary"
  119. >
  120. <template #default="scope">
  121. <div>
  122. {{ rowNum(scope.row.actuallySalary) }}
  123. </div>
  124. </template>
  125. </el-table-column>
  126. <el-table-column
  127. label="奖金及其他"
  128. width="95"
  129. header-align="center"
  130. align="right"
  131. prop="bonusAmount"
  132. >
  133. <template #default="scope">
  134. <div>
  135. {{ rowNum(scope.row.bonusAmount) }}
  136. </div>
  137. </template>
  138. </el-table-column>
  139. <el-table-column label="社保" align="center">
  140. <el-table-column
  141. label="养老保险"
  142. width="70"
  143. header-align="center"
  144. align="right"
  145. prop="endowmentInsurance"
  146. >
  147. <template #default="scope">
  148. <div>
  149. {{ rowNum(scope.row.endowmentInsurance) }}
  150. </div>
  151. </template>
  152. </el-table-column>
  153. <el-table-column
  154. label="医疗保险"
  155. width="70"
  156. header-align="center"
  157. align="right"
  158. prop="medicalInsurance"
  159. >
  160. <template #default="scope">
  161. <div>
  162. {{ rowNum(scope.row.medicalInsurance) }}
  163. </div>
  164. </template>
  165. </el-table-column>
  166. <el-table-column
  167. label="失业险"
  168. width="70"
  169. header-align="center"
  170. align="right"
  171. prop="unemploymentBenefit"
  172. >
  173. <template #default="scope">
  174. <div>
  175. {{ rowNum(scope.row.unemploymentBenefit) }}
  176. </div>
  177. </template>
  178. </el-table-column>
  179. <el-table-column
  180. label="大病险"
  181. width="70"
  182. header-align="center"
  183. align="right"
  184. prop="seriousIllnessInsurance"
  185. >
  186. <template #default="scope">
  187. <div>
  188. {{ rowNum(scope.row.seriousIllnessInsurance) }}
  189. </div>
  190. </template>
  191. </el-table-column>
  192. </el-table-column>
  193. <el-table-column
  194. label="公积金"
  195. width="80"
  196. header-align="center"
  197. align="right"
  198. prop="housingFund"
  199. >
  200. <template #default="scope">
  201. <div>
  202. {{ rowNum(scope.row.housingFund) }}
  203. </div>
  204. </template>
  205. </el-table-column>
  206. <el-table-column
  207. label="个税"
  208. header-align="center"
  209. align="right"
  210. :prop="
  211. form.status === 3 && form.hasIndividualIncomeTax
  212. ? 'individualIncomeTaxConfirm'
  213. : 'currentIndividualIncomeTax'
  214. "
  215. >
  216. <template #default="scope">
  217. <div>
  218. {{
  219. rowNum(
  220. form.status === 3 && form.hasIndividualIncomeTax
  221. ? scope.row.individualIncomeTaxConfirm
  222. : scope.row.currentIndividualIncomeTax
  223. )
  224. }}
  225. </div>
  226. </template></el-table-column
  227. >
  228. <el-table-column
  229. label="其他扣款"
  230. width="70"
  231. header-align="center"
  232. align="right"
  233. prop="otherCut"
  234. >
  235. <template #default="scope">
  236. <div>
  237. {{ rowNum(scope.row.otherCut) }}
  238. </div>
  239. </template>
  240. </el-table-column>
  241. <el-table-column
  242. label="备注"
  243. width="100"
  244. header-align="center"
  245. >
  246. <template #default="scope">
  247. <div>
  248. {{ scope.row.remark }}
  249. </div>
  250. </template>
  251. </el-table-column>
  252. </el-table>
  253. </div>
  254. </div>
  255. </el-col>
  256. <el-col :span="24">
  257. <el-divider />
  258. </el-col>
  259. <el-col :span="24">
  260. <el-form-item label="备注">
  261. <span>
  262. {{ form.content }}
  263. </span>
  264. </el-form-item>
  265. </el-col>
  266. <el-col :span="24">
  267. <el-form-item label="合计工资">
  268. {{ rowNum(form.amount) }}
  269. </el-form-item>
  270. </el-col>
  271. <el-col v-if="showVerify()" :span="24">
  272. <el-divider />
  273. </el-col>
  274. <el-col v-if="showVerify()" :span="24">
  275. <el-form-item label="是否有个税">
  276. <el-select
  277. v-model.trim="form.hasIndividualIncomeTax"
  278. placeholder="请选择"
  279. size="small"
  280. style="width: 100%"
  281. @change="changeIndividual"
  282. >
  283. <el-option
  284. v-for="item in confirmChoices"
  285. :key="item.value"
  286. :label="item.label"
  287. :value="item.value"
  288. />
  289. </el-select>
  290. </el-form-item>
  291. </el-col>
  292. <el-col
  293. v-if="showVerify() && form.hasIndividualIncomeTax === 1"
  294. :span="24"
  295. class="details-container"
  296. >
  297. <div class="details-head">
  298. <div class="title">
  299. <i class="fa fa-th-list" aria-hidden="true" /> 人员信息
  300. </div>
  301. </div>
  302. <div class="details-body">
  303. <div>
  304. <el-table
  305. ref="sourceTable"
  306. :data="form.details"
  307. size="small"
  308. max-height="260px"
  309. border
  310. highlight-current-row
  311. header-row-class-name="list-header-row"
  312. row-class-name="list-row"
  313. @selection-change="handleCheckChange"
  314. @current-change="handleCurrentChange"
  315. >
  316. <el-table-column
  317. type="index"
  318. label="序号"
  319. width="50"
  320. align="center"
  321. />
  322. <el-table-column label="员工姓名" width="120" align="center">
  323. <template #default="scope">
  324. <div>
  325. {{ scope.row.employeeName }}
  326. </div>
  327. <span
  328. style="
  329. color: red;
  330. position: absolute;
  331. z-index: 10;
  332. top: 4px;
  333. right: 6px;
  334. "
  335. >*</span
  336. >
  337. </template>
  338. </el-table-column>
  339. <el-table-column
  340. label="实际个税"
  341. align="center"
  342. width="120"
  343. prop="individualIncomeTaxConfirm"
  344. >
  345. <template #default="scope">
  346. <div>
  347. <el-input-number
  348. v-model="scope.row.individualIncomeTaxConfirm"
  349. size="small"
  350. placeholder="个税"
  351. :precision="2"
  352. :controls="false"
  353. style="width: 100%"
  354. @change="rowChangeSum(scope.row)"
  355. />
  356. </div>
  357. </template>
  358. </el-table-column>
  359. </el-table>
  360. <br />
  361. </div>
  362. </div>
  363. </el-col>
  364. <el-col :span="24">
  365. <el-form-item label="审核备注">
  366. <el-input
  367. v-if="form.status === 2"
  368. maxlength="200"
  369. show-word-limit
  370. v-model.trim="form.verifyContent"
  371. type="textarea"
  372. rows="2"
  373. />
  374. <span v-else>{{ form.verifyContent }}</span>
  375. </el-form-item>
  376. </el-col>
  377. </el-row>
  378. </el-form>
  379. </div>
  380. <div class="form-btns-container" style="height: 40px">
  381. <el-button
  382. v-if="showVerify()"
  383. type="danger"
  384. size="small"
  385. icon="back"
  386. style="float: right; margin-left: 12px"
  387. @click="handleVerify(4)"
  388. >
  389. 驳回</el-button
  390. >
  391. <el-button
  392. v-if="showVerify()"
  393. type="primary"
  394. size="small"
  395. style="float: right; margin-left: 12px"
  396. icon="check"
  397. @click="handleVerify(3)"
  398. >
  399. 审核通过</el-button
  400. >
  401. <el-button
  402. v-if="verifiable() && form.status === 3"
  403. type="warning"
  404. size="small"
  405. icon="back"
  406. style="float: right; margin-left: 12px"
  407. @click="returnStatus()"
  408. >
  409. 退回</el-button
  410. >
  411. </div>
  412. <feedback-dialog ref="feedbackDialogView" :verify="verify" />
  413. <!-- <print-dialog ref="printDialog" /> -->
  414. </el-dialog>
  415. </template>
  416. <script setup>
  417. import {
  418. getDetail,
  419. verifyDetail,
  420. turnBackDetail,
  421. exportSalaryEmployee,
  422. exportSalaryPdf,
  423. } from "@/api/business/production/salaryZero";
  424. import { rowNum, numberToCurrencyNo } from "@/utils/index";
  425. import feedbackDialog from "../feedbackDialog.vue";
  426. import useUserStore from "@/store/modules/user";
  427. import { ref } from "vue";
  428. const { proxy } = getCurrentInstance();
  429. const visible = ref(false);
  430. const width = ref(800);
  431. const selections = ref([]);
  432. const currentSource = ref(null);
  433. const permissions = useUserStore().permissions;
  434. const all_permission = "*:*:*";
  435. const feedbackDialogView = ref(null);
  436. const confirmChoices = ref([
  437. {
  438. label: "是",
  439. value: 1,
  440. },
  441. {
  442. label: "否",
  443. value: 0,
  444. },
  445. ]);
  446. const props = defineProps({
  447. getList: {
  448. type: Function,
  449. default: () => {},
  450. },
  451. });
  452. const { getList } = toRefs(props);
  453. const total = ref(0);
  454. const employeeEmptyData = {
  455. id: null,
  456. title: "",
  457. remark: "",
  458. employeeName: "",
  459. departmentName: "",
  460. idCode: "",
  461. salaryAmount: "",
  462. bonusAmount: "",
  463. allowanceAmount: "",
  464. subsidyAmount: "",
  465. absenceCut: "",
  466. planSalary: 0,
  467. actuallySalary: 0,
  468. endowmentInsurance: 0,
  469. medicalInsurance: 0,
  470. unemploymentBenefit: 0,
  471. seriousIllnessInsurance: 0,
  472. housingFund: 0,
  473. otherCut: 0,
  474. cumulativeIncome: 0,
  475. cumulativeSpecialCut: 0,
  476. cumulativeChildEduCut: 0,
  477. cumulativeHouseLoanInterestCut: 0,
  478. cumulativeHouseRentCut: 0,
  479. cumulativeSupportElderCut: 0,
  480. cumulativeContinuingEduCut: 0,
  481. cumulativeBabyCareCut: 0,
  482. sumSpecialCumulativeCut: 0,
  483. cumulativeOtherCut: 0,
  484. cumulativeIndividualIncomeTax: 0,
  485. cumulativeHasPaidIit: 0,
  486. currentIndividualIncomeTax: 0,
  487. idiograph: "",
  488. details: [],
  489. editStatus: true,
  490. };
  491. const form = ref({
  492. amount: null,
  493. details: [],
  494. });
  495. const emptyForm = {
  496. details: [],
  497. };
  498. function open(detail) {
  499. console.log(detail);
  500. visible.value = true;
  501. form.value = detail;
  502. loadData();
  503. }
  504. function loadData() {
  505. getDetail(form.value).then((res) => {
  506. form.value = { ...proxy.deepClone(emptyForm), ...res.data };
  507. computeTotal();
  508. });
  509. }
  510. function close() {
  511. visible.value = false;
  512. reset();
  513. }
  514. function reset() {
  515. form.value = proxy.deepClone(emptyForm);
  516. total.value = 0;
  517. }
  518. function printSalary() {
  519. exportSalaryPdf(form.value.id);
  520. }
  521. function exportSalary() {
  522. exportSalaryEmployee(form.value.id);
  523. }
  524. function showVerify() {
  525. if (
  526. form.value.id == null ||
  527. form.value.status === 0 ||
  528. form.value.status === 3 ||
  529. form.value.status === 4
  530. ) {
  531. return false;
  532. } else if (verifiable()) {
  533. return true;
  534. } else {
  535. return false;
  536. }
  537. }
  538. function verifiable() {
  539. // console.log(permissions)
  540. // console.log(permissions)
  541. return (
  542. permissions.includes(all_permission) ||
  543. permissions.includes("business:salary:verify")
  544. );
  545. }
  546. function handleCurrentChange(row) {
  547. currentSource.value = row;
  548. }
  549. function handleCheckChange(selection) {
  550. selections.value = selection.map((item) => item);
  551. }
  552. function getSummaries(param) {
  553. const { columns, data } = param;
  554. const sums = [];
  555. columns.forEach((column, index) => {
  556. if (index === 0) {
  557. sums[index] = "合计";
  558. return;
  559. } else if (index === 1) {
  560. sums[index] = "";
  561. return;
  562. }
  563. const values = data.map((item) => Number(item[column.property]));
  564. if (!values.every((value) => isNaN(value))) {
  565. sums[index] = values.reduce((prev, curr) => {
  566. const value = Number(curr);
  567. if (!isNaN(value)) {
  568. return (Number(prev) + Number(curr)).toFixed(2);
  569. } else {
  570. return Number(prev).toFixed(2);
  571. }
  572. }, 0);
  573. sums[index] = numberToCurrencyNo(sums[index]);
  574. } else {
  575. sums[index] = "";
  576. }
  577. });
  578. return sums;
  579. }
  580. function handleVerify(status) {
  581. if (status === 4) {
  582. const saveValue = proxy.deepClone(form.value);
  583. saveValue.status = status;
  584. feedbackDialogView.value.open(saveValue);
  585. } else {
  586. proxy.$modal
  587. .confirm("确认审核么?")
  588. .then((_) => {
  589. const saveValue = proxy.deepClone(form.value);
  590. saveValue.status = status;
  591. verify(saveValue);
  592. })
  593. .catch((_) => {
  594. proxy.$modal.msg("已取消审核");
  595. });
  596. }
  597. }
  598. function verify(data) {
  599. verifyDetail(data).then((res) => {
  600. reset();
  601. getList.value();
  602. close();
  603. });
  604. }
  605. function rowChangeSum(row) {
  606. let actuallySalary = 0;
  607. actuallySalary += row.planSalary == null ? 0 : row.planSalary;
  608. actuallySalary += row.bonusAmount == null ? 0 : row.bonusAmount;
  609. actuallySalary -= row.endowmentInsurance == null ? 0 : row.endowmentInsurance;
  610. actuallySalary -= row.medicalInsurance == null ? 0 : row.medicalInsurance;
  611. actuallySalary -=
  612. row.unemploymentBenefit == null ? 0 : row.unemploymentBenefit;
  613. actuallySalary -=
  614. row.seriousIllnessInsurance == null ? 0 : row.seriousIllnessInsurance;
  615. actuallySalary -= row.housingFund == null ? 0 : row.housingFund;
  616. if (form.value.hasIndividualIncomeTax === 1) {
  617. actuallySalary -=
  618. row.individualIncomeTaxConfirm == null
  619. ? 0
  620. : row.individualIncomeTaxConfirm;
  621. } else {
  622. actuallySalary -=
  623. row.currentIndividualIncomeTax == null
  624. ? 0
  625. : row.currentIndividualIncomeTax;
  626. }
  627. actuallySalary -= row.otherCut == null ? 0 : row.otherCut;
  628. row.actuallySalary = actuallySalary;
  629. computeTotal();
  630. }
  631. function computeTotal() {
  632. let totalSalay = 0;
  633. form.value.details.forEach((l) => {
  634. totalSalay += l.actuallySalary == null ? 0 : l.actuallySalary;
  635. });
  636. form.value.amount = totalSalay;
  637. }
  638. function returnStatus(status) {
  639. proxy.$modal
  640. .confirm("确认退回么?")
  641. .then((_) => {
  642. turnBackDetail(form.value).then((res) => {
  643. // if (res.data.successStatus = true) {
  644. // reset()
  645. // getList.value()
  646. // close()
  647. // } else {
  648. // proxy.$modal.msg(res.data.message)
  649. // }
  650. reset();
  651. getList.value();
  652. close();
  653. });
  654. })
  655. .catch((_) => {
  656. proxy.$modal.msg("已取消退回");
  657. });
  658. }
  659. function changeIndividual(arg) {
  660. // if (arg === 1) {
  661. form.value.details.forEach((row) => {
  662. let actuallySalary = 0;
  663. actuallySalary += row.planSalary == null ? 0 : row.planSalary;
  664. actuallySalary += row.bonusAmount == null ? 0 : row.bonusAmount;
  665. actuallySalary -=
  666. row.endowmentInsurance == null ? 0 : row.endowmentInsurance;
  667. actuallySalary -= row.medicalInsurance == null ? 0 : row.medicalInsurance;
  668. actuallySalary -=
  669. row.unemploymentBenefit == null ? 0 : row.unemploymentBenefit;
  670. actuallySalary -=
  671. row.seriousIllnessInsurance == null ? 0 : row.seriousIllnessInsurance;
  672. actuallySalary -= row.housingFund == null ? 0 : row.housingFund;
  673. if (arg === 1) {
  674. actuallySalary -=
  675. row.individualIncomeTaxConfirm == null
  676. ? 0
  677. : row.individualIncomeTaxConfirm;
  678. } else {
  679. actuallySalary -=
  680. row.currentIndividualIncomeTax == null
  681. ? 0
  682. : row.currentIndividualIncomeTax;
  683. }
  684. actuallySalary -= row.otherCut == null ? 0 : row.otherCut;
  685. row.actuallySalary = actuallySalary;
  686. });
  687. computeTotal();
  688. }
  689. // 暴露给父组件的方法
  690. defineExpose({
  691. open,
  692. });
  693. </script>