accountReview.jsx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. import React from "react";
  2. import $ from "jquery/src/ajax";
  3. import moment from "moment";
  4. import {
  5. Button,
  6. Form,
  7. Input,
  8. Spin,
  9. Table,
  10. Select,
  11. message,
  12. Tabs,
  13. AutoComplete,
  14. DatePicker,
  15. Modal,
  16. } from "antd";
  17. import { ChooseList } from "../../order/orderNew/chooseList";
  18. import { ShowModal, getVehicleName, getTypeName, commonAdd, dealBigMoney } from "../../../tools"
  19. import ShowModalDiv from "@/showModal.jsx";
  20. import AccountDetails from "./accountDetails";
  21. import { accountType, accountStatus } from "@/dataDic";
  22. const FormItem = Form.Item;
  23. const { RangePicker } = DatePicker;
  24. const { TabPane } = Tabs;
  25. const AccountReview = React.createClass({
  26. getInitialState() {
  27. return {
  28. showDetails: false,
  29. data: {},
  30. logvisible: false,
  31. logdataSour: [],
  32. visible: "",
  33. reason: "",
  34. checkData: {},
  35. aname: "",
  36. searchValues: {
  37. examineStatus: this.props.isOperate ? "1" : undefined
  38. }, // 列表筛选条件
  39. loading: false, //加载动画
  40. changeList: undefined, // 更改后的表格显示数据
  41. dataSource: [], // 列表数据
  42. departmentArr: [],
  43. pagination: {
  44. defaultCurrent: 1,
  45. defaultPageSize: 10,
  46. showQuickJumper: true,
  47. pageSize: 10,
  48. onChange: function (page) {
  49. this.loadData(page);
  50. }.bind(this),
  51. showTotal: function (total) {
  52. return "共" + total + "条数据";
  53. },
  54. },
  55. columns: [
  56. {
  57. title: "类型",
  58. dataIndex: "type",
  59. key: "type",
  60. render: (text, record) => {
  61. return (
  62. <span>
  63. {text == 0 ? record.typeOther : accountType.find(item => item.value === text).label}
  64. </span>
  65. );
  66. },
  67. },
  68. {
  69. title: "报销金额(元)",
  70. dataIndex: "amount",
  71. key: "amount",
  72. },
  73. {
  74. title: "实报金额(元)",
  75. dataIndex: "realAmount",
  76. key: "realAmount",
  77. },
  78. {
  79. title: "报销编号",
  80. dataIndex: "checkNo",
  81. key: "checkNo",
  82. },
  83. {
  84. title: "报销至订单",
  85. dataIndex: "buyerName",
  86. key: "buyerName",
  87. render: (text, record) => {
  88. return (
  89. record.targetType == 0
  90. ? <div>固定费用</div>
  91. : <div>
  92. <div>{text || ""}</div>
  93. <div>{record.contractNo || ""}</div>
  94. </div>
  95. );
  96. },
  97. },
  98. {
  99. title: "报销至部门",
  100. dataIndex: "applyDepName",
  101. key: "applyDepName",
  102. render: (text, record) => {
  103. return (
  104. <span>{record.targetType == 0 && text}</span>
  105. );
  106. },
  107. },
  108. {
  109. title: "报销人",
  110. dataIndex: "aname",
  111. key: "aname",
  112. },
  113. {
  114. title: "财务负责人",
  115. dataIndex: "financeName",
  116. key: "financeName",
  117. },
  118. {
  119. title: "状态",
  120. dataIndex: "status",
  121. key: "status",
  122. render: (text, record) => {
  123. return (
  124. <span style={{ color: accountStatus[text].color }}>
  125. {accountStatus[text].label}
  126. </span>
  127. );
  128. },
  129. },
  130. {
  131. title: "报销公司/支付公司",
  132. dataIndex: "payDepName",
  133. key: "payDepName",
  134. render: (text, record) => {
  135. return (
  136. <div>
  137. <div>{record.applyDepName || ""}</div>
  138. <div>{text || ""}</div>
  139. </div>
  140. );
  141. },
  142. },
  143. {
  144. title: "报销时间",
  145. dataIndex: "createTimeStr",
  146. key: "createTimeStr",
  147. },
  148. {
  149. title: "操作",
  150. dataIndex: "operate",
  151. key: "operate",
  152. render: (text, record) => {
  153. return (
  154. <div>
  155. <div>
  156. {this.props.isOperate &&
  157. <Button type="primary"
  158. style={{ margin: 4 }}
  159. onClick={() => { this.download(record.attachmentUrl) }}
  160. >下载</Button>}
  161. {this.props.isOperate && record.examine == 1 &&
  162. <Button type="primary"
  163. style={{ margin: 4 }}
  164. onClick={(e) => {
  165. e.stopPropagation();
  166. this.setState({
  167. visible: "adopt",
  168. checkData: record,
  169. })
  170. }}
  171. >同意</Button>}
  172. {this.props.isOperate && record.examine == 1 &&
  173. <Button type="danger"
  174. style={{ margin: 4 }}
  175. onClick={(e) => {
  176. e.stopPropagation();
  177. this.setState({
  178. visible: "reject",
  179. checkData: record,
  180. })
  181. }}
  182. >驳回</Button>}
  183. {record.status != 0 && <Button
  184. style={{ margin: 4 }}
  185. onClick={() => {
  186. this.setState({
  187. logvisible: true
  188. })
  189. this.getLogData(record.id)
  190. }}>日志</Button>}
  191. </div>
  192. </div>
  193. )
  194. }
  195. },
  196. ],
  197. logcolumns: [
  198. {
  199. title: "审核人",
  200. dataIndex: "auditorName",
  201. key: "auditorName"
  202. },
  203. {
  204. title: "操作",
  205. dataIndex: "status",
  206. key: "status",
  207. width: 120,
  208. render: (text, record) => {
  209. return (
  210. <span style={{ color: ["#1D4FEA", "#34DE38", "#108EE9", "red", "#1D4FEA"][text] }}>
  211. {["【发起】", "【通过】", "【完成】", "【驳回】", "【重新发起】"][text]}
  212. {this.state.processStatus == record.processStatus && !record.id &&
  213. <span style={{ color: "#FFA500" }}>&nbsp;审核中...</span>}
  214. </span>
  215. );
  216. },
  217. },
  218. {
  219. title: "操作时间",
  220. dataIndex: "createTimeStr",
  221. key: "createTimeStr",
  222. width: 88,
  223. },
  224. {
  225. title: "备注",
  226. dataIndex: "remarks",
  227. key: "remarks",
  228. render: (text, record) => {
  229. return (
  230. <div style={{ minWidth: 250 }}>{text}</div>
  231. )
  232. }
  233. }
  234. ],
  235. };
  236. },
  237. componentWillMount() {
  238. this.departmentList();
  239. this.loadData();
  240. },
  241. // 列表接口
  242. loadData(pageNo) {
  243. const { searchValues, pagination } = this.state;
  244. this.setState({
  245. loading: true,
  246. });
  247. let datas = Object.assign(searchValues, {
  248. pageNo: pageNo || 1,
  249. pageSize: pagination.pageSize,
  250. expenseMain: 1,
  251. processStatus: this.props.isOperate ? 1 : 2,
  252. });
  253. $.ajax({
  254. method: "get",
  255. dataType: "json",
  256. crossDomain: false,
  257. url: globalConfig.context + "/api/admin/expenseAccount/pageList",
  258. data: datas,
  259. success: function (data) {
  260. ShowModal(this);
  261. this.setState({
  262. loading: false,
  263. });
  264. if (data.error && data.error.length === 0) {
  265. if (data.data.list) {
  266. pagination.current = data.data.pageNo;
  267. pagination.total = data.data.totalCount;
  268. if (data.data && data.data.list && !data.data.list.length) {
  269. pagination.current = 0;
  270. pagination.total = 0;
  271. }
  272. this.setState({
  273. dataSource: data.data.list,
  274. pagination: this.state.pagination,
  275. pageNo: data.data.pageNo,
  276. totalAmount: data.data.totalAmount,
  277. });
  278. } else {
  279. this.setState({
  280. dataSource: data.data,
  281. pagination: false,
  282. });
  283. }
  284. } else {
  285. message.warning(data.error[0].message);
  286. }
  287. }.bind(this),
  288. }).always(
  289. function () {
  290. this.setState({
  291. loading: false,
  292. });
  293. }.bind(this)
  294. );
  295. },
  296. // 日志
  297. getLogData(eaid) {
  298. $.ajax({
  299. method: "get",
  300. dataType: "json",
  301. crossDomain: false,
  302. url: globalConfig.context + "/api/admin/expenseAccount/log/list",
  303. data: { eaid },
  304. success: function (data) {
  305. if (data.error.length === 0) {
  306. this.setState({
  307. logdataSour: data.data || []
  308. });
  309. this.isHere(data.data || [])
  310. } else {
  311. message.warning(data.error[0].message);
  312. }
  313. }.bind(this)
  314. }).always(
  315. function () {
  316. }.bind(this)
  317. );
  318. },
  319. //
  320. isHere(list = []) {
  321. for (var i = 0; i < list.length; i++) {
  322. if (!list[i].id) {
  323. this.setState({
  324. processStatus: list[i].processStatus
  325. })
  326. return
  327. }
  328. }
  329. },
  330. download(urls) {
  331. if (!urls) {
  332. message.error("暂无可下载的附件!");
  333. } else {
  334. let list = urls.split(',') || []
  335. list.forEach(e => {
  336. var aLink = document.createElement('a');
  337. aLink.download = e;
  338. aLink.href = globalConfig.context + `/open/download?fileName=${e}&delete=false`;
  339. document.body.appendChild(aLink);
  340. aLink.click();
  341. document.body.removeChild(aLink);
  342. });
  343. }
  344. },
  345. departmentList() {
  346. $.ajax({
  347. method: "get",
  348. dataType: "json",
  349. crossDomain: false,
  350. url: globalConfig.context + "/api/admin/organization/selectSuperId",
  351. data: {},
  352. success: function (data) {
  353. let thedata = data.data;
  354. let theArr = [];
  355. if (!thedata) {
  356. if (data.error && data.error.length) {
  357. message.warning(data.error[0].message);
  358. }
  359. } else {
  360. thedata.map(function (item, index) {
  361. theArr.push({
  362. key: index,
  363. name: item.name,
  364. id: item.id
  365. });
  366. });
  367. }
  368. this.setState({
  369. departmentArr: theArr
  370. });
  371. }.bind(this)
  372. }).always(
  373. function () {
  374. }.bind(this)
  375. );
  376. },
  377. // 审核
  378. toExamine(num) {
  379. const { checkData, reason } = this.state
  380. if (!reason) {
  381. message.warning("请填写审核说明~");
  382. return;
  383. }
  384. this.setState({
  385. loading: true,
  386. });
  387. $.ajax({
  388. method: "POST",
  389. dataType: "json",
  390. crossDomain: false,
  391. url: globalConfig.context + "/api/admin/expenseAccount/examine",
  392. data: {
  393. id: checkData.id,
  394. reason,
  395. status: num,//1同意 3驳回
  396. },
  397. }).done(
  398. function (data) {
  399. if (!data.error.length) {
  400. message.success("审核成功!");
  401. this.setState({
  402. visible: "",
  403. reason: "",
  404. showDetails: false,
  405. checkData: {},
  406. });
  407. this.loadData(this.state.pageNo)
  408. } else {
  409. message.warning(data.error[0].message);
  410. }
  411. }.bind(this)
  412. );
  413. },
  414. tableRowClick(e) {
  415. this.setState({
  416. showDetails: true,
  417. id: e.id,
  418. })
  419. // this.getDetails(e.id)
  420. },
  421. // 查询负责人
  422. followUp(e) {
  423. this.setState({
  424. aname: e
  425. });
  426. $.ajax({
  427. method: "get",
  428. dataType: "json",
  429. crossDomain: false,
  430. url: globalConfig.context + "/api/admin/customer/listAdminByName",
  431. data: {
  432. adminName: e,
  433. },
  434. success: function (data) {
  435. let thedata = data.data || [];
  436. if (!thedata) {
  437. if (data.error && data.error.length) {
  438. message.warning(data.error[0].message);
  439. }
  440. thedata = {};
  441. }
  442. this.setState({
  443. fjlist: thedata,
  444. });
  445. }.bind(this),
  446. }).always(
  447. function () {
  448. this.setState({
  449. loading: false,
  450. });
  451. }.bind(this)
  452. );
  453. },
  454. // 选中负责人
  455. selectF(value) {
  456. const { searchValues, fjlist } = this.state;
  457. const newdataSources = JSON.stringify(fjlist) == "{}" ? [] : fjlist;
  458. this.setState({
  459. searchValues: Object.assign(searchValues, {
  460. aid: newdataSources.find((item) => item.name == value).id,
  461. }),
  462. });
  463. },
  464. // 搜索
  465. search() {
  466. this.loadData();
  467. },
  468. // 重置
  469. reset() {
  470. this.setState({
  471. aname: "",
  472. searchValues: JSON.parse(JSON.stringify({})),
  473. }, () => {
  474. this.loadData();
  475. })
  476. },
  477. changeList(arr) {
  478. const newArr = [];
  479. this.state.columns.forEach((item) => {
  480. arr.forEach((val) => {
  481. if (val === item.title) {
  482. newArr.push(item);
  483. }
  484. });
  485. });
  486. this.setState({
  487. changeList: newArr,
  488. });
  489. },
  490. render() {
  491. const { TextArea } = Input
  492. const { searchValues, visible, } = this.state
  493. const formItemLayout = {
  494. labelCol: { span: 5 },
  495. wrapperCol: { span: 18 },
  496. };
  497. const dataSources = this.state.fjlist || [];
  498. const options = dataSources.map((group) => (
  499. <Select.Option key={group.id} value={group.name}>
  500. {group.name}
  501. </Select.Option>
  502. ));
  503. return (
  504. <div className="user-content">
  505. <ShowModalDiv ShowModal={this.state.showModal} />
  506. <div className="content-title" style={{ marginBottom: 10 }}>
  507. <span style={{ fontWeight: 900, fontSize: 16 }}>{this.props.isOperate ? "报销审核" : "报销列表"}</span>
  508. </div>
  509. <Tabs defaultActiveKey="2" className="test">
  510. <TabPane tab="搜索" key="2">
  511. <div className="user-search" style={{ marginLeft: 10 }}>
  512. <Input
  513. placeholder="合同编号"
  514. value={searchValues["contractNo"]
  515. ? searchValues["contractNo"]
  516. : ""}
  517. onChange={(e) => {
  518. searchValues["contractNo"] = e.target.value;
  519. this.setState({
  520. searchValues: searchValues,
  521. });
  522. }}
  523. />
  524. <Input
  525. placeholder="客户名称"
  526. value={searchValues["username"]
  527. ? searchValues["username"]
  528. : ""}
  529. onChange={(e) => {
  530. searchValues["username"] = e.target.value;
  531. this.setState({
  532. searchValues: searchValues,
  533. });
  534. }}
  535. />
  536. <Select
  537. style={{ width: 140 }}
  538. placeholder="报销类型"
  539. value={searchValues["type"]
  540. ? searchValues["type"]
  541. : undefined}
  542. onChange={(e) => {
  543. searchValues["type"] = e;
  544. this.setState({
  545. searchValues: searchValues,
  546. });
  547. }}
  548. >
  549. <Option value="1">差旅费</Option>
  550. <Option value="2">非业务报销</Option>
  551. <Option value="3">第三方付款</Option>
  552. <Option value="4">申请借支</Option>
  553. <Option value="5">申请抵扣</Option>
  554. <Option value="0">其他</Option>
  555. </Select>
  556. <AutoComplete
  557. className="certain-category-search"
  558. dropdownClassName="certain-category-search-dropdown"
  559. dropdownMatchSelectWidth={false}
  560. style={{ width: 140 }}
  561. dataSource={options}
  562. placeholder="报销人"
  563. value={this.state.aname}
  564. onChange={this.followUp.bind(this)}
  565. filterOption={true}
  566. onSelect={this.selectF.bind(this)}
  567. >
  568. <Input />
  569. </AutoComplete>
  570. <Select
  571. placeholder="所属部门"
  572. style={{ width: 200, marginRight: 10 }}
  573. value={searchValues["depId"]
  574. ? searchValues["depId"]
  575. : undefined}
  576. onChange={e => {
  577. searchValues["depId"] = e;
  578. this.setState({
  579. searchValues: searchValues,
  580. });
  581. }}
  582. >
  583. {this.state.departmentArr.map(function (item) {
  584. return <Select.Option key={item.id}>{item.name}</Select.Option>;
  585. })}
  586. </Select>
  587. <Select
  588. placeholder="申请部门"
  589. style={{ width: 200, marginRight: 10 }}
  590. value={searchValues["applyDep"]
  591. ? searchValues["applyDep"]
  592. : undefined}
  593. onChange={e => {
  594. searchValues["applyDep"] = e;
  595. this.setState({
  596. searchValues: searchValues,
  597. });
  598. }}
  599. >
  600. {this.state.departmentArr.map(function (item) {
  601. return <Select.Option key={item.id}>{item.name}</Select.Option>;
  602. })}
  603. </Select>
  604. <Select
  605. placeholder="支付部门"
  606. style={{ width: 200, marginRight: 10 }}
  607. value={searchValues["payDep"]
  608. ? searchValues["payDep"]
  609. : undefined}
  610. onChange={e => {
  611. searchValues["payDep"] = e;
  612. this.setState({
  613. searchValues: searchValues,
  614. });
  615. }}
  616. >
  617. {this.state.departmentArr.map(function (item) {
  618. return <Select.Option key={item.id}>{item.name}</Select.Option>;
  619. })}
  620. </Select>
  621. <Select
  622. style={{ width: 140 }}
  623. placeholder="审核状态"
  624. value={searchValues["examineStatus"]
  625. ? searchValues["examineStatus"]
  626. : undefined}
  627. onChange={(e) => {
  628. searchValues["examineStatus"] = e;
  629. this.setState({
  630. searchValues: searchValues,
  631. });
  632. }}
  633. >
  634. <Option value="0">全部</Option>
  635. <Option value="1">待审核</Option>
  636. <Option value="2">已审核</Option>
  637. </Select>
  638. <Input
  639. placeholder="报销编号"
  640. value={searchValues["checkNo"]
  641. ? searchValues["checkNo"]
  642. : ""}
  643. onChange={(e) => {
  644. searchValues["checkNo"] = e.target.value;
  645. this.setState({
  646. searchValues: searchValues,
  647. });
  648. }}
  649. />
  650. <div style={{ marginTop: 10 }}>
  651. <span>报销时间:</span>
  652. <RangePicker
  653. style={{ width: 300 }}
  654. value={[
  655. searchValues.startTime ? moment(searchValues.startTime) : null,
  656. searchValues.endTime ? moment(searchValues.endTime) : null,
  657. ]}
  658. onChange={(data, dataString) => {
  659. this.setState({
  660. searchValues: Object.assign(searchValues, {
  661. startTime: dataString[0],
  662. endTime: dataString[1],
  663. }),
  664. });
  665. }}
  666. />
  667. <Button
  668. type="primary"
  669. onClick={this.search}
  670. style={{ margin: "0 10px" }}
  671. >
  672. 搜索
  673. </Button>
  674. <Button onClick={this.reset}>重置</Button>
  675. </div>
  676. </div>
  677. </TabPane>
  678. <TabPane tab="更改表格显示数据" key="1">
  679. <div style={{ marginLeft: 10 }}>
  680. <ChooseList
  681. columns={this.state.columns}
  682. changeFn={this.changeList}
  683. changeList={this.state.changeList}
  684. top={55}
  685. margin={11}
  686. />
  687. </div>
  688. </TabPane>
  689. </Tabs>
  690. <div className="patent-table">
  691. <Spin spinning={this.state.loading}>
  692. <Table
  693. bordered
  694. columns={
  695. this.state.changeList == undefined
  696. ? this.state.columns
  697. : this.state.changeList
  698. }
  699. dataSource={this.state.dataSource}
  700. pagination={this.state.pagination}
  701. onRowDoubleClick={this.tableRowClick.bind(this)}
  702. size="small"
  703. />
  704. </Spin>
  705. <p
  706. style={{ display: "inline-block", fontSize: "14px", color: "red" }}
  707. >
  708. {
  709. <span style={{ marginRight: 10 }}>
  710. {`金额总计(元):${this.state.totalAmount}`}
  711. </span>
  712. }
  713. </p>
  714. </div>
  715. {
  716. //审核弹窗
  717. this.state.visible != "" &&
  718. <Modal
  719. width="400px"
  720. maskClosable={false}
  721. title="审核"
  722. confirmLoading={this.state.loading}
  723. visible={this.state.visible != ""}
  724. onOk={() => { this.toExamine(visible == "adopt" ? 1 : visible == "reject" && 3) }}
  725. okText={this.state.visible == "adopt" ? "通过" : this.state.visible == "reject" && "驳回"}
  726. onCancel={() => {
  727. this.setState({
  728. visible: '',
  729. reason: "",
  730. checkData: {},
  731. })
  732. }}
  733. >
  734. <div style={{ width: "90%", margin: "0 auto" }}>
  735. <TextArea
  736. rows={4}
  737. value={this.state.reason}
  738. onChange={(e) => {
  739. this.setState({
  740. reason: e.target.value,
  741. })
  742. }}
  743. placeholder="请填写审核内容"
  744. />
  745. </div>
  746. </Modal>
  747. }
  748. {
  749. this.state.showDetails &&
  750. <AccountDetails
  751. showDetails={this.state.showDetails}
  752. id={this.state.id}
  753. isOperate={this.props.isOperate}
  754. onCancel={() => {
  755. this.setState({
  756. showDetails: false
  757. }, () => {
  758. this.loadData(this.state.pageNo)
  759. })
  760. }}
  761. />
  762. }
  763. {
  764. // 审核日志
  765. this.state.logvisible &&
  766. <Modal
  767. visible={this.state.logvisible}
  768. className="admin-desc-content"
  769. width="800px"
  770. maskClosable={false}
  771. title="审核日志"
  772. footer={null}
  773. onCancel={() => {
  774. this.setState({
  775. logvisible: false,
  776. })
  777. }}
  778. >
  779. <div className="patent-table">
  780. <Spin spinning={this.state.loading}>
  781. <Table
  782. columns={this.state.logcolumns}
  783. dataSource={this.state.logdataSour}
  784. pagination={false}
  785. bordered
  786. size="small"
  787. />
  788. </Spin>
  789. </div>
  790. </Modal>
  791. }
  792. </div>
  793. );
  794. },
  795. });
  796. export default AccountReview;