accountDetaillist.jsx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  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, getAccountName, getSecondaryAccountName } from "../../../tools"
  19. import ShowModalDiv from "@/showModal.jsx";
  20. import AccountDetails from "./accountDetails";
  21. import { accountType, typeLists, accountStatus } from "@/dataDic";
  22. const FormItem = Form.Item;
  23. const { RangePicker } = DatePicker;
  24. const { TabPane } = Tabs;
  25. const AccountDetaillist = 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. loading: false, //加载动画
  38. changeList: undefined, // 更改后的表格显示数据
  39. dataSource: [], // 列表数据
  40. departmentArr: [],
  41. pagination: {
  42. defaultCurrent: 1,
  43. defaultPageSize: 10,
  44. showQuickJumper: true,
  45. pageSize: 10,
  46. onChange: function (page) {
  47. this.loadData(page);
  48. }.bind(this),
  49. showTotal: function (total) {
  50. return "共" + total + "条数据";
  51. },
  52. },
  53. columns: [
  54. {
  55. title: "类型",
  56. dataIndex: "type",
  57. key: "type",
  58. render: (text, record) => {
  59. return (
  60. <span>
  61. {(text == 0 && !record.typeOther)
  62. ? getAccountName(record.sonType, record.sonTypeOther)
  63. : getSecondaryAccountName(text, record.typeOther)}
  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.mainId)
  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", "#808080", "#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/detailsList",
  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()
  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 }}>报销明细列表</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="6">预借支</Option>
  555. <Option value="7">油费</Option>
  556. <Option value="8">招待费</Option>
  557. <Option value="9">办公费</Option>
  558. <Option value="10">福利费</Option>
  559. <Option value="11">物业水电费</Option>
  560. <Option value="12">打印费</Option>
  561. <Option value="0">其他</Option>
  562. </Select>
  563. <AutoComplete
  564. className="certain-category-search"
  565. dropdownClassName="certain-category-search-dropdown"
  566. dropdownMatchSelectWidth={false}
  567. style={{ width: 140 }}
  568. dataSource={options}
  569. placeholder="报销人"
  570. value={this.state.aname}
  571. onChange={this.followUp.bind(this)}
  572. filterOption={true}
  573. onSelect={this.selectF.bind(this)}
  574. >
  575. <Input />
  576. </AutoComplete>
  577. <Select
  578. placeholder="所属部门"
  579. style={{ width: 200, marginRight: 10 }}
  580. value={searchValues["depId"]
  581. ? searchValues["depId"]
  582. : undefined}
  583. onChange={e => {
  584. searchValues["depId"] = e;
  585. this.setState({
  586. searchValues: searchValues,
  587. });
  588. }}
  589. >
  590. {this.state.departmentArr.map(function (item) {
  591. return <Select.Option key={item.id}>{item.name}</Select.Option>;
  592. })}
  593. </Select>
  594. <Select
  595. placeholder="申请部门"
  596. style={{ width: 200, marginRight: 10 }}
  597. value={searchValues["applyDep"]
  598. ? searchValues["applyDep"]
  599. : undefined}
  600. onChange={e => {
  601. searchValues["applyDep"] = e;
  602. this.setState({
  603. searchValues: searchValues,
  604. });
  605. }}
  606. >
  607. {this.state.departmentArr.map(function (item) {
  608. return <Select.Option key={item.id}>{item.name}</Select.Option>;
  609. })}
  610. </Select>
  611. <Select
  612. placeholder="支付部门"
  613. style={{ width: 200, marginRight: 10 }}
  614. value={searchValues["payDep"]
  615. ? searchValues["payDep"]
  616. : undefined}
  617. onChange={e => {
  618. searchValues["payDep"] = e;
  619. this.setState({
  620. searchValues: searchValues,
  621. });
  622. }}
  623. >
  624. {this.state.departmentArr.map(function (item) {
  625. return <Select.Option key={item.id}>{item.name}</Select.Option>;
  626. })}
  627. </Select>
  628. {/* <Select
  629. style={{ width: 140 }}
  630. placeholder="审核状态"
  631. value={searchValues["status"]
  632. ? searchValues["status"]
  633. : undefined}
  634. onChange={(e) => {
  635. searchValues["status"] = e;
  636. this.setState({
  637. searchValues: searchValues,
  638. });
  639. }}
  640. >
  641. <Option value="0">未提交</Option>
  642. <Option value="1">审核中</Option>
  643. <Option value="2">完成</Option>
  644. <Option value="3">驳回</Option>
  645. <Option value="4">撤销</Option>
  646. </Select> */}
  647. <Input
  648. placeholder="报销编号"
  649. value={searchValues["checkNo"]
  650. ? searchValues["checkNo"]
  651. : ""}
  652. onChange={(e) => {
  653. searchValues["checkNo"] = e.target.value;
  654. this.setState({
  655. searchValues: searchValues,
  656. });
  657. }}
  658. />
  659. <div style={{ marginTop: 10 }}>
  660. <span>报销时间:</span>
  661. <RangePicker
  662. style={{ width: 300 }}
  663. value={[
  664. searchValues.startTime ? moment(searchValues.startTime) : null,
  665. searchValues.endTime ? moment(searchValues.endTime) : null,
  666. ]}
  667. onChange={(data, dataString) => {
  668. this.setState({
  669. searchValues: Object.assign(searchValues, {
  670. startTime: dataString[0],
  671. endTime: dataString[1],
  672. }),
  673. });
  674. }}
  675. />
  676. <Button
  677. type="primary"
  678. onClick={this.search}
  679. style={{ margin: "0 10px" }}
  680. >
  681. 搜索
  682. </Button>
  683. <Button onClick={this.reset}>重置</Button>
  684. </div>
  685. </div>
  686. </TabPane>
  687. <TabPane tab="更改表格显示数据" key="1">
  688. <div style={{ marginLeft: 10 }}>
  689. <ChooseList
  690. columns={this.state.columns}
  691. changeFn={this.changeList}
  692. changeList={this.state.changeList}
  693. top={55}
  694. margin={11}
  695. />
  696. </div>
  697. </TabPane>
  698. </Tabs>
  699. <div className="patent-table">
  700. <Spin spinning={this.state.loading}>
  701. <Table
  702. bordered
  703. columns={
  704. this.state.changeList == undefined
  705. ? this.state.columns
  706. : this.state.changeList
  707. }
  708. dataSource={this.state.dataSource}
  709. pagination={this.state.pagination}
  710. // onRowDoubleClick={this.tableRowClick.bind(this)}
  711. size="small"
  712. />
  713. </Spin>
  714. <p
  715. style={{ display: "inline-block", fontSize: "14px", color: "red" }}
  716. >
  717. {
  718. <span style={{ marginRight: 10 }}>
  719. {`金额总计(元):${this.state.totalAmount}`}
  720. </span>
  721. }
  722. </p>
  723. </div>
  724. {
  725. //审核弹窗
  726. this.state.visible != "" &&
  727. <Modal
  728. width="400px"
  729. maskClosable={false}
  730. title="审核"
  731. confirmLoading={this.state.loading}
  732. visible={this.state.visible != ""}
  733. onOk={() => { this.toExamine(visible == "adopt" ? 1 : visible == "reject" && 3) }}
  734. okText={this.state.visible == "adopt" ? "通过" : this.state.visible == "reject" && "驳回"}
  735. onCancel={() => {
  736. this.setState({
  737. visible: '',
  738. reason: "",
  739. checkData: {},
  740. })
  741. }}
  742. >
  743. <div style={{ width: "90%", margin: "0 auto" }}>
  744. <TextArea
  745. rows={4}
  746. value={this.state.reason}
  747. onChange={(e) => {
  748. this.setState({
  749. reason: e.target.value,
  750. })
  751. }}
  752. placeholder="请填写审核内容"
  753. />
  754. </div>
  755. </Modal>
  756. }
  757. {
  758. this.state.showDetails &&
  759. <AccountDetails
  760. showDetails={this.state.showDetails}
  761. id={this.state.id}
  762. isOperate={this.props.isOperate}
  763. onCancel={() => { this.setState({ showDetails: false }) }}
  764. />
  765. }
  766. {
  767. // 审核日志
  768. this.state.logvisible &&
  769. <Modal
  770. visible={this.state.logvisible}
  771. className="admin-desc-content"
  772. width="800px"
  773. maskClosable={false}
  774. title="审核日志"
  775. footer={null}
  776. onCancel={() => {
  777. this.setState({
  778. logvisible: false,
  779. })
  780. }}
  781. >
  782. <div className="patent-table">
  783. <Spin spinning={this.state.loading}>
  784. <Table
  785. columns={this.state.logcolumns}
  786. dataSource={this.state.logdataSour}
  787. pagination={false}
  788. bordered
  789. size="small"
  790. />
  791. </Spin>
  792. </div>
  793. </Modal>
  794. }
  795. </div>
  796. );
  797. },
  798. });
  799. export default AccountDetaillist;