detail.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. <template>
  2. <div class="borderless" v-loading="pageLoading">
  3. <div class="customer-head">
  4. <div class="customer-back">
  5. <el-button
  6. type="danger"
  7. style="border: none;background: none;color: red"
  8. icon="el-icon-arrow-left"
  9. @click="backToList"
  10. :loading="btnLoading"
  11. >返回列表</el-button>
  12. </div>
  13. <div class="add-customer-btn">
  14. <el-button
  15. type="primary"
  16. size="small"
  17. class="el-button--small-yh"
  18. @click.stop="openEdit"
  19. v-if="disabled"
  20. >编 辑</el-button>
  21. <el-button
  22. v-if="checker && form.status != 3"
  23. type="primary"
  24. size="small"
  25. class="el-button--small-yh"
  26. @click.stop="openCheckDialog">
  27. 审批
  28. </el-button>
  29. <el-button
  30. v-if="form.status > 0"
  31. @click.native="checkScheduleDialog = true,checkId=form.id"
  32. type="primary"
  33. size="small"
  34. >审核进度</el-button>
  35. <el-button
  36. type="primary"
  37. v-if="!checkDisabled"
  38. :disabled="!form.id || disabled"
  39. size="small"
  40. @click="pleaseCheck"
  41. :loading="btnLoading"
  42. >请核</el-button>
  43. <el-button
  44. type="success"
  45. :disabled="!form.id"
  46. size="small"
  47. @click="copyDoc"
  48. :loading="btnLoading"
  49. v-if="false"
  50. >复制单据</el-button>
  51. <el-button
  52. type="primary"
  53. @click="editCustomer"
  54. size="small"
  55. :loading="btnLoading"
  56. >保存数据</el-button>
  57. </div>
  58. </div>
  59. <div class="customer-main">
  60. <containerTitle title="基础信息"/>
  61. <basic-container :showBtn="true">
  62. <avue-form
  63. ref="form"
  64. class="trading-form"
  65. v-model="form"
  66. :option="option"
  67. >
  68. <template slot="userId">
  69. <el-select
  70. v-model="form.userId"
  71. filterable
  72. clearable
  73. size="small"
  74. placeholder="请选择"
  75. @change="userHandle"
  76. @clear="form.userName == null"
  77. :disabled="disabled || checkDisabled"
  78. >
  79. <el-option
  80. v-for="(item,index) in userList"
  81. :key="index"
  82. :label="item.realName"
  83. :value="item.id"
  84. ></el-option>
  85. </el-select>
  86. </template>
  87. <template slot="deptId">
  88. <avue-input-tree
  89. leaf-only
  90. style="width: 100%;"
  91. size="small"
  92. :props="{ label: 'title' }"
  93. v-model="form.deptId"
  94. placeholder=" "
  95. type="tree"
  96. :dic="dic"
  97. :nodeClick="deptClick"
  98. :disabled="disabled || checkDisabled"
  99. ></avue-input-tree>
  100. </template>
  101. <template slot="postId">
  102. <el-select
  103. v-model="form.postId"
  104. clearable
  105. filterable
  106. placeholder="请选择 岗位"
  107. @change="postHandle"
  108. @clear="form.postId == null"
  109. :disabled="disabled || checkDisabled"
  110. >
  111. <el-option
  112. v-for="(item, index) in postDic"
  113. :label="item.postName"
  114. :value="item.id"
  115. :key="index"
  116. />
  117. </el-select>
  118. </template>
  119. </avue-form>
  120. </basic-container>
  121. <containerTitle title="报销明细"/>
  122. <basic-container>
  123. <avue-crud
  124. ref="crud"
  125. :data="dataList"
  126. :option="tableOption"
  127. :cell-style="cellStyle"
  128. @saveColumn="saveColumn"
  129. @resetColumn="resetColumn"
  130. >
  131. <template slot="menuLeft">
  132. <el-button
  133. type="primary"
  134. icon="el-icon-plus"
  135. size="small"
  136. @click.stop="newDetails"
  137. :disabled="disabled || checkDisabled"
  138. >录入明细</el-button>
  139. <el-button
  140. type="info"
  141. icon="el-icon-printer"
  142. size="small"
  143. @click="openReport"
  144. >报表打印</el-button>
  145. </template>
  146. <template slot="menu" slot-scope="{ row, index }">
  147. <el-button
  148. size="small"
  149. icon="el-icon-edit"
  150. type="text"
  151. @click="rowCell(row, index)"
  152. :disabled="disabled || checkDisabled"
  153. >{{ row.$cellEdit ? "保存" : "修改" }}</el-button>
  154. <el-button
  155. size="small"
  156. icon="el-icon-delete"
  157. type="text"
  158. @click="rowDel(row, index)"
  159. :disabled="disabled || checkDisabled"
  160. >删除</el-button>
  161. </template>
  162. <template slot="payDate" slot-scope="{ row, index }">
  163. <el-date-picker
  164. v-if="row.$cellEdit"
  165. v-model="row.payDate"
  166. type="date"
  167. placeholder="选择日期"
  168. size="small"
  169. style="width: 100%"
  170. format="yyyy-MM-dd"
  171. valueFormat="yyyy-MM-dd"
  172. ></el-date-picker>
  173. <span v-else>{{row.payDate}}</span>
  174. </template>
  175. <template slot="moldId" slot-scope="{ row }">
  176. <avue-cascader
  177. v-if="row.$cellEdit"
  178. v-model="row.moldId"
  179. size="small"
  180. style="width: 100%;"
  181. :dic="dicArea"
  182. :props="props"
  183. check-strictly
  184. :emit-path="false"
  185. :show-all-levels="false"
  186. @change="moldChange($event,row,dicArea)"
  187. @clear="row.feeList = feesOption"
  188. placeholder="请选择"
  189. ></avue-cascader>
  190. <span v-else>{{ row.mold }}</span>
  191. </template>
  192. <template slot="detailId" slot-scope="{ row }">
  193. <el-select
  194. v-if="row.$cellEdit"
  195. v-model="row.detailId"
  196. filterable
  197. clearable
  198. @change="detailChange(row)"
  199. size="small"
  200. >
  201. <el-option
  202. v-for="(item, index) in row.feeList"
  203. :key="index"
  204. :label="item.cname"
  205. :value="item.id"
  206. ></el-option>
  207. </el-select>
  208. <span v-else>{{ row.detail }}</span>
  209. </template>
  210. <template slot="explanation" slot-scope="{ row, index }">
  211. <el-input
  212. v-if="row.$cellEdit"
  213. v-model="row.explanation"
  214. size="small"
  215. placeholder="输入内容"
  216. />
  217. <span v-else>{{row.explanation}}</span>
  218. </template>
  219. <template slot="payMethod" slot-scope="{ row, index }">
  220. <el-select
  221. v-model="row.payMethod"
  222. size="small"
  223. placeholder="请选择"
  224. clearable
  225. :disabled="!row.$cellEdit"
  226. >
  227. <el-option
  228. v-for="(item, index) in paymentOption"
  229. :key="item.dictKey"
  230. :label="item.dictValue"
  231. :value="item.dictKey"
  232. ></el-option>
  233. </el-select>
  234. </template>
  235. <template slot="amount" slot-scope="{ row, index }">
  236. <el-input-number
  237. v-if="row.$cellEdit"
  238. v-model="row.amount"
  239. size="small"
  240. :controls="false"
  241. :precision="2"
  242. style="width: 100%"
  243. placeholder="金额"
  244. ></el-input-number>
  245. <span v-else>{{ row.amount }}</span>
  246. </template>
  247. </avue-crud>
  248. </basic-container>
  249. </div>
  250. <el-dialog
  251. append-to-body
  252. title="审批"
  253. class="el-dialogDeep"
  254. :visible.sync="checkDialog"
  255. width="50%"
  256. :close-on-click-modal="false"
  257. :destroy-on-close="true"
  258. :close-on-press-escape="false"
  259. v-dialog-drag
  260. >
  261. <check
  262. :checkData="checkData"
  263. :checkDetail="false"
  264. :idList="[]"
  265. @choceCheckFun="choceCheckFun"
  266. >
  267. </check>
  268. </el-dialog>
  269. <el-dialog
  270. append-to-body
  271. title="审批进度"
  272. class="el-dialogDeep"
  273. :visible.sync="checkScheduleDialog"
  274. width="40%"
  275. :close-on-click-modal="false"
  276. :destroy-on-close="true"
  277. :close-on-press-escape="false"
  278. v-dialog-drag
  279. >
  280. <check-schedule
  281. :checkId="checkId"
  282. :batchNo="batchNo"
  283. @choceScheduleFun="choceScheduleFun"
  284. >
  285. </check-schedule>
  286. </el-dialog>
  287. <!-- 报表-->
  288. <report-dialog
  289. :switchDialog="switchDialog"
  290. :reportId="form.id"
  291. reportName="事务-报销单"
  292. @onClose="onClose()"
  293. />
  294. </div>
  295. </template>
  296. <script>
  297. import tableOption from "./config/customerContact.json";
  298. import {
  299. isDiscount,
  300. isPercentage,
  301. micrometerFormat,
  302. IntegerFormat
  303. } from "@/util/validate";
  304. import { gainUser } from "@/api/basicData/customerInquiry";
  305. import {getUserInfo} from "@/api/system/user";
  306. import {getDeptTree} from "@/api/system/dept";
  307. import { getCurrentDate } from "@/util/date";
  308. import {getList as getPostList} from "@/api/system/post";
  309. import {dataDetail, typeSave, removeGoods, pleaseCheck} from "@/api/standAlone/reimbursement";
  310. import { contrastObj, contrastList } from "@/util/contrastData";
  311. import check from "@/components/check/check";
  312. import checkSchedule from "@/components/check/checkSchedule";
  313. import reportDialog from "@/components/report-dialog/main";
  314. import {getDeptTree as getFeesId, customerList as getFeesList} from "@/api/basicData/basicFeesDesc";
  315. export default {
  316. name: "detail",
  317. props: {
  318. detailData: {
  319. type: Object
  320. }
  321. },
  322. components: {
  323. check,
  324. checkSchedule,
  325. reportDialog
  326. },
  327. data() {
  328. return {
  329. disabled: false,
  330. pageLoading: false,
  331. btnLoading: false,
  332. form: {},
  333. option: {
  334. menuBtn: false,
  335. labelWidth: 100,
  336. column: [
  337. {
  338. label: "日期",
  339. prop: "claimDate",
  340. span: 8,
  341. type: "date",
  342. format: "yyyy-MM-dd",
  343. valueFormat: "yyyy-MM-dd 00:00:00",
  344. rules: [
  345. {
  346. required: true,
  347. message: " ",
  348. trigger: "blur"
  349. }
  350. ]
  351. },
  352. {
  353. label: "报销人",
  354. prop: "userId",
  355. rules: [
  356. {
  357. required: true,
  358. message: " ",
  359. trigger: "change"
  360. }
  361. ],
  362. span: 8,
  363. slot: true,
  364. },
  365. {
  366. label: "所属部门",
  367. prop: "deptId",
  368. rules: [
  369. {
  370. required: true,
  371. message: " ",
  372. trigger: "blur"
  373. }
  374. ],
  375. span: 8,
  376. slot: true,
  377. },
  378. {
  379. label: "备注",
  380. prop: "remarks",
  381. type: "textarea",
  382. minRows: 2,
  383. span: 24,
  384. },
  385. ],
  386. },
  387. dataList: [],
  388. tableOption: {},
  389. goodsoptions: [],
  390. unitOption: [],
  391. paymentOption: [],
  392. selectionList: [],
  393. search: {},
  394. treeStyle: "height:" + (window.innerHeight - 315) + "px",
  395. goodsOption: {},
  396. loading: false,
  397. switchDialog: false, // 报表弹窗控制
  398. userList: [],
  399. dic: [], // 部门
  400. postDic: [], // 岗位
  401. loginUser: '', // 登录人
  402. breakConfiguration: {
  403. multipleChoices: false,
  404. multiple: false,
  405. disabled: false,
  406. searchShow: true,
  407. collapseTags: false,
  408. clearable: true,
  409. placeholder: "请点击右边按钮选择",
  410. dicData: []
  411. },
  412. oldForm: {},
  413. oldDataList: [],
  414. checkDisabled: false, // 审核状态
  415. checker: false,
  416. checkId: '',
  417. batchNo:'',
  418. checkDialog: false,
  419. checkScheduleDialog: false,
  420. checkData: {},
  421. dicArea: [],
  422. props: {
  423. value: 'value',
  424. label: 'title',
  425. },
  426. feesOption: [],
  427. }
  428. },
  429. async created() {
  430. this.$set(this.form, 'claimDate', getCurrentDate()); // 默认当前日期
  431. this.tableOption = await this.getColumnData(
  432. this.getColumnName(107),
  433. tableOption
  434. );
  435. gainUser().then(res => {
  436. this.userList = res.data.data;
  437. });
  438. getUserInfo().then(res => {
  439. this.$set(this.form, 'userId', res.data.data.id);
  440. this.$set(this.form, 'userName', res.data.data.realName);
  441. this.$set(this.form, 'deptId', res.data.data.deptId);
  442. this.$set(this.form, 'deptName', res.data.data.deptName);
  443. this.$set(this.form, 'postId', res.data.data.postId.split(',')[0]);
  444. this.$set(this.form, 'postName', res.data.data.postName.split(',')[0]);
  445. this.loginUser = res.data.data.realName;
  446. })
  447. getDeptTree().then(res => {
  448. this.dic = res.data.data
  449. })
  450. getPostList(1, 10).then(res => {
  451. if (res.data.data.total > 0) {
  452. this.postDic = res.data.data.records;
  453. if (Math.ceil(res.data.data.total / 10) > 1) {
  454. for (let i = 2; i <= Math.ceil(res.data.data.total / 10); i++) {
  455. getPostList(i, 10).then(e => {
  456. this.postDic = this.postDic.concat(e.data.data.records);
  457. });
  458. }
  459. }
  460. }
  461. });
  462. getFeesId().then(res => {
  463. this.dicArea = res.data.data;
  464. })
  465. getFeesList({size: 10, current: 1}).then(res => {
  466. this.feesOption = res.data.data.total > 0? res.data.data.records: [];
  467. if (Math.ceil(res.data.data.total / 10) > 1) {
  468. for (let i = 2; i <= Math.ceil(res.data.data.total / 10); i++) {
  469. getFeesList({size: 10, current: 1}).then(e => {
  470. this.feesOption = this.feesOption.concat(e.data.data.records);
  471. });
  472. }
  473. }
  474. });
  475. this.getWorkDicts('unit').then(res => {
  476. this.unitOption = res.data.data;
  477. })
  478. this.getWorkDicts("payment_term").then(res => {
  479. this.paymentOption = res.data.data;
  480. })
  481. if (this.detailData.query) {
  482. this.disabled = true;
  483. this.option.column.map(e => {
  484. this.$set(e, 'disabled', true)
  485. })
  486. this.queryData(this.detailData.id);
  487. } else if (this.detailData.auditId) {
  488. this.checker = true;
  489. this.batchNo = this.detailData.check.batchNo
  490. this.queryData(this.detailData.id);
  491. }
  492. },
  493. filters: {
  494. IntegerFormat(num) {
  495. return IntegerFormat(num);
  496. },
  497. decimalFormat(num) {
  498. return num ? Number(num).toFixed(2) : "0.00";
  499. }
  500. },
  501. methods: {
  502. // 查询
  503. queryData(id) {
  504. this.pageLoading = true;
  505. dataDetail({id: id}).then(res => {
  506. this.form = res.data.data;
  507. this.dataList = this.form.itemList? this.form.itemList: [];
  508. this.dataList.forEach(item => {
  509. this.moldChange(item.moldId, item, this.dicArea, false)
  510. })
  511. this.oldForm = {...this.form};
  512. this.oldDataList = [...this.dataList];
  513. delete this.form.itemList;
  514. this.checkDisabled = this.form.status > 0? true: false;
  515. if (this.form.status > 0) {
  516. this.option.column.map(e => {
  517. this.$set(e, 'disabled', true)
  518. })
  519. }
  520. }).finally(() => {
  521. this.pageLoading = false;
  522. })
  523. },
  524. //返回列表
  525. backToList() {
  526. this.$emit("goBack");
  527. },
  528. // 编辑按钮触发
  529. openEdit() {
  530. this.disabled = false;
  531. this.option.column.map(e => {
  532. if (this.checkDisabled) {
  533. this.$set(e, 'disabled', true)
  534. } else {
  535. if (e.prop != 'serialNo') {
  536. this.$set(e, 'disabled', false)
  537. }
  538. }
  539. })
  540. },
  541. // 复制
  542. copyDoc() {
  543. this.$emit("copyOrder", this.form.id);
  544. },
  545. //修改提交触发
  546. editCustomer(status) {
  547. this.$refs["form"].validate((valid, done) => {
  548. done();
  549. if (valid) {
  550. this.$set(this.form, 'itemList', this.dataList)
  551. this.btnLoading = true;
  552. typeSave(this.form).then(res => {
  553. this.$message({type: "success", message: this.form.id ? "修改成功!" : "新增成功!"});
  554. this.queryData(res.data.data);
  555. }).finally(() => {
  556. this.btnLoading = false;
  557. })
  558. } else {
  559. return false
  560. }
  561. })
  562. },
  563. cellStyle() {
  564. return "padding:0;height:40px;";
  565. },
  566. async saveColumn() {
  567. const inSave = await this.saveColumnData(
  568. this.getColumnName(107),
  569. this.tableOption
  570. );
  571. if (inSave) {
  572. this.$message.success("保存成功");
  573. //关闭窗口
  574. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  575. this.$nextTick(() => {
  576. this.$refs.crud.doLayout()
  577. })
  578. }
  579. },
  580. async resetColumn() {
  581. this.tableOption = tableOption;
  582. const inSave = await this.delColumnData(
  583. this.getColumnName(107),
  584. tableOption
  585. );
  586. if (inSave) {
  587. this.$nextTick(() => {
  588. this.$refs.crud.doLayout()
  589. })
  590. this.$message.success("重置成功");
  591. //关闭窗口
  592. setTimeout(() => {
  593. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  594. }, 1000);
  595. }
  596. },
  597. //录入明细
  598. newDetails() {
  599. this.$refs["form"].validate((valid, done) => {
  600. done()
  601. if (valid) {
  602. this.dataList.push({
  603. $cellEdit: true,
  604. feeList: this.feesOption,
  605. })
  606. }
  607. })
  608. },
  609. rowCell(row, index) {
  610. if (row.$cellEdit == true) {
  611. this.$set(row, "$cellEdit", false);
  612. } else {
  613. this.$set(row, "$cellEdit", true);
  614. }
  615. },
  616. rowDel(row, index) {
  617. this.$confirm("确定删除数据?", {
  618. confirmButtonText: "确定",
  619. cancelButtonText: "取消",
  620. type: "warning"
  621. }).then(() => {
  622. if (row.id) {
  623. removeGoods(row.id).then(res => {
  624. this.$message({
  625. type: 'success',
  626. message: '删除成功!'
  627. })
  628. this.dataList.splice(row.$index, 1);
  629. })
  630. } else {
  631. this.$message({
  632. type: "success",
  633. message: "删除成功!"
  634. });
  635. this.dataList.splice(row.$index, 1);
  636. }
  637. });
  638. },
  639. getKHData(row) {},
  640. //选择费用
  641. selectValue(value, row) {
  642. console.log(value)
  643. this.$set(row, "expenseItem", value.cname);
  644. },
  645. userHandle() {
  646. this.form.userName = this.userList.find(item => item.id == this.form.userId).realName;
  647. },
  648. postHandle() {
  649. this.form.postName = this.postDic.find(item => item.id == this.form.postId).postName;
  650. },
  651. // 验证新旧值对比
  652. verification() {
  653. if (contrastObj(this.form, this.oldForm) ||
  654. contrastList(this.dataList, this.oldDataList)) {
  655. this.$confirm("数据发生变化未有提交记录, 是否提交?", "提示", {
  656. confirmButtonText: "确定",
  657. cancelButtonText: "取消",
  658. type: "warning"
  659. }).then(() => {
  660. this.editCustomer();
  661. }).catch(() => {
  662. return false; //取消改动数据
  663. })
  664. } else {
  665. return true;
  666. }
  667. },
  668. deptClick(data) {
  669. this.$set(this.form, 'deptName', data.title)
  670. },
  671. //打开审核
  672. openCheckDialog(){
  673. this.checkData = this.detailData.check
  674. this.checkDialog = true;
  675. },
  676. //关闭审核
  677. choceCheckFun(){
  678. this.checkDialog = false;
  679. },
  680. choceScheduleFun(){
  681. this.checkScheduleDialog = false
  682. },
  683. // 请核
  684. pleaseCheck() {
  685. if (this.verification()) {
  686. const data = {
  687. id : this.form.id,
  688. checkType: 'fybx',
  689. url: '/reimbursement/index',
  690. pageStatus:"this.$store.getters.reimbursementStatus",
  691. pageLabel:"报销",
  692. checkFlag: 1,
  693. }
  694. this.btnLoading = true;
  695. pleaseCheck(data).then(res => {
  696. this.$message.success('请核成功')
  697. this.queryData(this.form.id)
  698. }).catch(() => {
  699. this.$message.error('请核失败')
  700. }).finally(() => {
  701. this.btnLoading = false;
  702. })
  703. }
  704. },
  705. // 报表
  706. openReport() {
  707. this.switchDialog =! this.switchDialog;
  708. },
  709. // 报表关闭
  710. onClose(val) {
  711. this.switchDialog = val;
  712. },
  713. moldChange(e, row, list, remove = true) {
  714. if (remove && row.moldId != e) {
  715. this.$set(row, 'detailId', null);
  716. }
  717. list.forEach(item => {
  718. if (e == item.value) {
  719. this.$set(row, 'mold', item.title)
  720. getFeesList({size: 10, current: 1,feesTypeId: e}).then(res => {
  721. this.$set(row, 'feeList', res.data.data.total > 0? res.data.data.records: []);
  722. if (Math.ceil(res.data.data.total / 10) > 1) {
  723. for (let i = 2; i <= Math.ceil(res.data.data.total / 10); i++) {
  724. getFeesList({size: 10, current: 1,feesTypeId: e}).then(e => {
  725. row.feeList = row.feeList.concat(e.data.data.records);
  726. });
  727. }
  728. }
  729. });
  730. }
  731. if (item.hasChildren) {
  732. this.moldChange(e, row, item.children, false)
  733. }
  734. })
  735. },
  736. detailChange(row) {
  737. row.detail = row.feeList.find(item => item.id == row.detailId)? row.feeList.find(item => item.id == row.detailId).cname: null
  738. },
  739. },
  740. }
  741. </script>
  742. <style scoped>
  743. </style>