Schema.jsx 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. import React, {Component} from 'react';
  2. import {Button, Col, Icon, Modal, Pagination, Row, Spin, Input} from 'antd';
  3. import './index.css';
  4. import {Mutation, Query} from "react-apollo";
  5. import gql from "graphql-tag";
  6. import {
  7. DELETE_SCHEMA,
  8. SHOW_SCHEMA,
  9. SHOW_TABLE,
  10. UPDATE_SCHEMA,
  11. UPDATE_SCHEMA_NAME,
  12. SEARCH_SCHEMA,
  13. ADD_SCHEMA
  14. } from '../../../../gql'
  15. import Table from "./Table";
  16. import {request} from 'graphql-request'
  17. import {getCookie} from "../../../../cookie";
  18. import {idGen} from "../../../../func";
  19. import {graphqlUrl} from "../../../../config";
  20. import {manageUsers} from "../../../../config";
  21. const confirm = Modal.confirm;
  22. const Search = Input.Search;
  23. class Schema extends Component {
  24. constructor(props) {
  25. super(props);
  26. this.state = {
  27. currentTable: props.location.state === undefined ? '' : props.location.state.create ? 'add' : '',
  28. // default schemaID and schemaName
  29. schemaID: props.location.state === undefined ? props.schemaID : props.location.state.schemaID,
  30. schemaName: props.location.state === undefined ? props.schemaName : props.location.state.schemaName,
  31. editSchemaName: '',
  32. allData: '',
  33. data: '',
  34. page: '1',
  35. pageSize: '15',
  36. once: 0
  37. };
  38. }
  39. shouldComponentUpdate(nextProps, nextState) {
  40. return true;
  41. }
  42. switchTable = (table) => {
  43. this.setState({
  44. currentTable: table
  45. })
  46. };
  47. changeEditSchemaName = (e) => {
  48. this.setState({
  49. editSchemaName: e.target.value
  50. })
  51. };
  52. clearEditSchemaName = () => {
  53. this.setState({
  54. editSchemaName: ''
  55. })
  56. };
  57. findColumns = data => this.state.currentTable === '' ? [] : data.find(table => table.name === this.state.currentTable) ? data.find(table => table.name === this.state.currentTable).cols : [];
  58. findRemark = data => this.state.currentTable === '' ? '' : data.find(table => table.name === this.state.currentTable) ? data.find(table => table.name === this.state.currentTable).remark : '';
  59. goBack = () => {
  60. this.setState({
  61. currentTable: ''
  62. })
  63. };
  64. showTablePagination = (page, pageSize, data) => {
  65. // console.log(page);
  66. // console.log(pageSize);
  67. // console.log(data);
  68. // 这个之所以这么麻烦,是因为 'apollo 不能存数据' 而 '分页又得用数据展示',
  69. // 所以展示 table 的时候分了两个,
  70. // 首先进入展示 15个 , 这前 15 个没有任何问题。
  71. // 如果数据多于 15个,在按下第二页的时候 将数据通过 antd 的分页组件的回调函数传入 state,之后 table 的展示由 this.state.data 来接管
  72. // 但是这又引起一个问题,通过 this.state.data 的展示如果进行删除,是不会通过 apollo 的,这也意味着数据库被删除了,而页面还存在
  73. // 于是,在使用 this.state.data 的页面的 deleteTableButton 组件内调用该函数,重新刷新 this.state.data
  74. this.setState({
  75. page,
  76. pageSize,
  77. allData: data,
  78. data: data.slice((page - 1) * pageSize, page * pageSize)
  79. });
  80. };
  81. fetchData = (referenceID) => {
  82. let schemaData;
  83. if (localStorage.getItem('ecommerce') && localStorage.getItem('bills') && localStorage.getItem('subscribe')) {
  84. switch (referenceID) {
  85. case 'ecommerce_schemaID':
  86. schemaData = localStorage.getItem('ecommerce');
  87. break;
  88. case 'bills_schemaID':
  89. schemaData = localStorage.getItem('bills');
  90. break;
  91. case 'subscribe_schemaID':
  92. schemaData = localStorage.getItem('subscribe');
  93. break;
  94. default:
  95. schemaData = ''
  96. }
  97. return Promise.resolve(schemaData);
  98. } else {
  99. return new Promise((resolve, reject) => {
  100. request(graphqlUrl, SEARCH_SCHEMA, {id: referenceID}).then(
  101. data => {
  102. if (data.schema_by_id !== null) {
  103. localStorage.setItem('ecommerce', data.caseSchema.find(obj => obj.schemaName === 'ecommerce').schemaData);
  104. localStorage.setItem('subscribe', data.caseSchema.find(obj => obj.schemaName === 'subscribe').schemaData);
  105. localStorage.setItem('bills', data.caseSchema.find(obj => obj.schemaName === 'bills').schemaData);
  106. resolve(data.schema_by_id.schemaData);
  107. }
  108. }
  109. )
  110. });
  111. }
  112. };
  113. receiveDataFromTable = (data) => {
  114. this.setState({
  115. data
  116. })
  117. };
  118. componentWillReceiveProps(next) {
  119. this.setState({
  120. currentTable: next.location.state === undefined ? '' : next.location.state.create ? 'add' : '',
  121. schemaID: next.schemaID,
  122. schemaName: next.schemaName,
  123. data: '',
  124. once: 0
  125. });
  126. }
  127. render() {
  128. let userID = this.props.userID;
  129. let trialcase = this.props.trialcase;
  130. return (
  131. <Query query={gql(SHOW_TABLE)} variables={{schema_id: this.state.schemaID}}>
  132. {
  133. ({loading, error, data}) => {
  134. if (loading) {
  135. return <Spin style={{marginLeft: 3}}/>
  136. }
  137. if (error) {
  138. return 'error!';
  139. }
  140. let copy;
  141. if (this.props.location.state)
  142. copy = this.props.location.state.copy;
  143. // 找到 copy 一定几率不显示的 问题原因,异步导致的未存先取
  144. if (data.schema_by_id === null && copy !== true) data = [];
  145. else {
  146. let reference = data.schema_by_id ? data.schema_by_id.reference : this.props.location.state.reference;
  147. data = data.schema_by_id ? JSON.parse(data.schema_by_id.schemaData) : [];
  148. if (data.length === 0 && reference !== '' && this.state.once === 0) {
  149. this.fetchData(reference).then((data) => {
  150. // 会执行好多好多次
  151. this.setState({
  152. data: JSON.parse(data),
  153. once: 1
  154. })
  155. });
  156. }
  157. }
  158. return (
  159. <div>
  160. {
  161. this.state.currentTable === '' ?
  162. <div>
  163. {
  164. this.state.editSchemaName ?
  165. <ModifySchemaNameInput
  166. editSchemaName={this.state.editSchemaName}
  167. changeEditSchemaName={this.changeEditSchemaName}
  168. clearEditSchemaName={this.clearEditSchemaName}
  169. schemaID={this.state.schemaID}
  170. userID={userID}
  171. schemaName={this.state.schemaName}
  172. history={this.props.history}
  173. />
  174. :
  175. <div className={'schema'}>
  176. <span className={'schema-name'}>{this.state.schemaName}</span>
  177. {
  178. userID.indexOf(manageUsers) > -1 ?
  179. <Icon style={{marginLeft: 15}}
  180. type="edit"
  181. theme="twoTone"
  182. onClick={
  183. () => {
  184. this.setState({editSchemaName: this.state.schemaName})
  185. }
  186. }
  187. />
  188. :
  189. trialcase ?
  190. ''
  191. :
  192. <Icon style={{marginLeft: 15}}
  193. type="edit"
  194. theme="twoTone"
  195. onClick={
  196. () => {
  197. this.setState({editSchemaName: this.state.schemaName})
  198. }
  199. }
  200. />
  201. }
  202. </div>
  203. }
  204. <div className={'schema-table-list-title'}>
  205. <Row>
  206. <Col span={10}><span
  207. className={'schema-table-title'}>Name</span></Col>
  208. <Col span={10}><span
  209. className={'schema-table-title'}>Remark</span></Col>
  210. <Col span={2} offset={2}>
  211. {
  212. userID.indexOf(manageUsers) > -1 ?
  213. <span
  214. className={'schema-table-title'}
  215. onClick={() => {
  216. this.setState({
  217. currentTable: 'add'
  218. })
  219. }}>
  220. <Icon type="plus"/>
  221. </span>
  222. :
  223. trialcase ?
  224. ''
  225. :
  226. <span
  227. className={'schema-table-title'}
  228. onClick={() => {
  229. this.setState({
  230. currentTable: 'add'
  231. })
  232. }}>
  233. <Icon type="plus" style={{color: '#096dd9',cursor: 'pointer'}}/>
  234. </span>
  235. }
  236. </Col>
  237. </Row>
  238. </div>
  239. <div>
  240. {
  241. this.state.data ?
  242. this.state.data.map(table => (
  243. <div key={table.name}
  244. className={'schema-table-list-content'}>
  245. <Row>
  246. <Col
  247. span={10}
  248. onClick={() => this.switchTable(table.name)}
  249. >
  250. <span
  251. className={'schema-table-content name'}>{table.name}</span>
  252. </Col>
  253. <Col span={10}>
  254. <span
  255. className={'schema-table-content'}>{table.remark}</span>
  256. </Col>
  257. <Col span={2} offset={2}>
  258. <span className={'schema-table-content'}>
  259. {
  260. userID.indexOf(manageUsers) > -1 ?
  261. <DeleteTableButton
  262. currentTable={table.name}
  263. schemaData={data}
  264. schemaID={this.state.schemaID}
  265. userID={userID}
  266. showTablePagination={this.showTablePagination}
  267. page={this.state.page}
  268. pageSize={this.state.pageSize}
  269. fetchData={this.fetchData}
  270. location={this.props.location}
  271. />
  272. :
  273. trialcase ?
  274. ''
  275. :
  276. <DeleteTableButton
  277. currentTable={table.name}
  278. schemaData={data}
  279. schemaID={this.state.schemaID}
  280. userID={userID}
  281. showTablePagination={this.showTablePagination}
  282. page={this.state.page}
  283. pageSize={this.state.pageSize}
  284. fetchData={this.fetchData}
  285. location={this.props.location}
  286. />
  287. }
  288. </span>
  289. </Col>
  290. </Row>
  291. </div>
  292. ))
  293. :
  294. data.slice(0, 15).map(table => (
  295. <div key={table.name}
  296. className={'schema-table-list-content'}>
  297. <Row>
  298. <Col
  299. span={10}
  300. onClick={() => this.switchTable(table.name)}
  301. >
  302. <span
  303. className={'schema-table-content name'}>{table.name}</span>
  304. </Col>
  305. <Col span={10}>
  306. <span
  307. className={'schema-table-content'}>{table.remark}</span>
  308. </Col>
  309. <Col span={2} offset={2}>
  310. <span className={'schema-table-content'}>
  311. {
  312. userID.indexOf(manageUsers) > -1 ?
  313. <DeleteTableButton
  314. currentTable={table.name}
  315. schemaData={data}
  316. schemaID={this.state.schemaID}
  317. showTablePagination={this.showTablePagination}
  318. page={this.state.page}
  319. pageSize={this.state.pageSize}
  320. userID={userID}
  321. fetchData={this.fetchData}
  322. location={this.props.location}
  323. />
  324. :
  325. trialcase ?
  326. ''
  327. :
  328. <DeleteTableButton
  329. currentTable={table.name}
  330. schemaData={data}
  331. schemaID={this.state.schemaID}
  332. showTablePagination={this.showTablePagination}
  333. page={this.state.page}
  334. pageSize={this.state.pageSize}
  335. userID={userID}
  336. fetchData={this.fetchData}
  337. location={this.props.location}
  338. />
  339. }
  340. </span>
  341. </Col>
  342. </Row>
  343. </div>
  344. ))
  345. }
  346. </div>
  347. <div className={'schema-bottom'}>
  348. <Row>
  349. <Col span={4}>
  350. {
  351. userID.indexOf(manageUsers) > -1 ?
  352. trialcase ?
  353. <div>
  354. <div style={{display: 'inline-block'}}
  355. className={'delete-schema'}>
  356. <CopySchemaButton
  357. userID={userID}
  358. history={this.props.history}
  359. schemaName={this.state.schemaName}
  360. />
  361. </div>
  362. <div style={{display: 'inline-block'}}
  363. className={'delete-schema'}>
  364. <DeleteSchemaButton
  365. userID={userID}
  366. schemaName={this.state.schemaName}
  367. history={this.props.history}
  368. />
  369. </div>
  370. </div>
  371. :
  372. <div className={'delete-schema'}>
  373. <DeleteSchemaButton
  374. userID={userID}
  375. schemaName={this.state.schemaName}
  376. history={this.props.history}
  377. />
  378. </div>
  379. :
  380. trialcase ?
  381. <div className={'delete-schema'}>
  382. <CopySchemaButton
  383. userID={userID}
  384. history={this.props.history}
  385. schemaName={this.state.schemaName}
  386. />
  387. </div>
  388. :
  389. <div className={'delete-schema'}>
  390. <DeleteSchemaButton
  391. userID={userID}
  392. schemaName={this.state.schemaName}
  393. history={this.props.history}
  394. />
  395. </div>
  396. }
  397. </Col>
  398. <Col span={4} offset={16}>
  399. <div className={'pagination'}>
  400. <Pagination
  401. simple
  402. defaultCurrent={1}
  403. hideOnSinglePage={true}
  404. defaultPageSize={15}
  405. total={data.length}
  406. onChange={(page, pageSize) => {
  407. this.showTablePagination(page, pageSize, data)
  408. }}
  409. />
  410. </div>
  411. </Col>
  412. </Row>
  413. </div>
  414. </div>
  415. :
  416. this.state.currentTable === 'add' ?
  417. <Table
  418. currentTable={''}
  419. schemaData={data}
  420. columns={[]}
  421. remark=''
  422. schemaID={this.state.schemaID}
  423. schemaName={this.state.schemaName}
  424. userID={userID}
  425. goBack={this.goBack}
  426. trialcase={trialcase}
  427. fetchData={this.fetchData}
  428. showTablePagination={this.showTablePagination}
  429. page={this.state.page}
  430. pageSize={this.state.pageSize}
  431. history={this.props.history}
  432. add={'add'}
  433. /> :
  434. <Table
  435. currentTable={this.state.currentTable}
  436. schemaData={data}
  437. columns={this.findColumns(data.length !== 0 ? data : this.state.data)}
  438. remark={this.findRemark(data.length !== 0 ? data : this.state.data)}
  439. schemaID={this.state.schemaID}
  440. schemaName={this.state.schemaName}
  441. userID={userID}
  442. goBack={this.goBack}
  443. trialcase={trialcase}
  444. fetchData={this.fetchData}
  445. showTablePagination={this.showTablePagination}
  446. page={this.state.page}
  447. pageSize={this.state.pageSize}
  448. history={this.props.history}
  449. add={'whatever but not add'}
  450. />
  451. }
  452. </div>
  453. );
  454. }
  455. }
  456. </Query>
  457. )
  458. }
  459. }
  460. export default Schema;
  461. class CopySchemaButton extends Component {
  462. constructor(props) {
  463. super(props);
  464. this.state = {
  465. schemaName: '',
  466. schemaID: '',
  467. };
  468. }
  469. render() {
  470. let userID = getCookie('user_id');
  471. let {history, schemaName} = this.props;
  472. let schemaID = schemaName + '_schemaID';
  473. return (
  474. <div>
  475. <Mutation
  476. mutation={gql(ADD_SCHEMA)}
  477. refetchQueries={[{query: gql(SHOW_SCHEMA), variables: {user_id: userID}}]}
  478. >
  479. {(create_schema, {loading, error}) => {
  480. if (loading)
  481. return <Spin style={{marginLeft: 30, marginTop: 10}}/>;
  482. if (error)
  483. return 'error';
  484. let varObj = {
  485. id: idGen('schema'),
  486. user_id: userID,
  487. createdAt: new Date().getTime(),
  488. updatedAt: '',
  489. schemaState: 'copy',
  490. schemaData: JSON.stringify([]),
  491. reference: schemaID,
  492. schemaName: schemaName + '_' + Math.random().toString().slice(-3) + Math.random().toString().slice(-4)
  493. };
  494. return (
  495. <Button
  496. type="primary"
  497. onClick={() => {
  498. create_schema({variables: varObj});
  499. history.push({
  500. pathname: `/graphql-service/my-create/${varObj.schemaName}`,
  501. state: {
  502. schemaName: varObj.schemaName,
  503. schemaID: varObj.id,
  504. copy: true,
  505. reference: varObj.reference
  506. }
  507. });
  508. }}
  509. >copy</Button>
  510. )
  511. }}
  512. </Mutation>
  513. </div>
  514. )
  515. }
  516. }
  517. class DeleteSchemaButton extends Component {
  518. constructor(props) {
  519. super(props);
  520. this.state = {
  521. schemaName: props.schemaName
  522. }
  523. }
  524. showConfirm = (delete_schema, schemaName, userID) => {
  525. let _this = this;
  526. confirm({
  527. title: 'Do you want to delete this schema?',
  528. content: 'It cannot be found back!',
  529. onOk() {
  530. delete_schema({variables: {schemaName, user_id: userID}});
  531. _this.props.history.push({
  532. pathname: '/graphql-service',
  533. });
  534. },
  535. onCancel() {
  536. },
  537. });
  538. };
  539. render() {
  540. let userID = this.props.userID;
  541. let schemaName = this.props.schemaName;
  542. return (
  543. <Mutation
  544. mutation={gql(DELETE_SCHEMA)}
  545. update={(cache) => {
  546. let data = cache.readQuery({query: gql(SHOW_SCHEMA), variables: {user_id: userID}});
  547. data.schema_by_props.splice(data.schema_by_props.findIndex(obj => obj.schemaName === this.state.schemaName), 1);
  548. cache.writeQuery({
  549. query: gql(SHOW_SCHEMA),
  550. variables: {user_id: userID},
  551. data
  552. });
  553. }}
  554. >
  555. {(delete_schema, {loading, error}) => {
  556. if (error)
  557. return 'error';
  558. if (loading)
  559. return <Spin style={{marginLeft: 3}}/>;
  560. return (
  561. <Button
  562. type="danger"
  563. onClick={() => {
  564. this.showConfirm(delete_schema, schemaName, userID);
  565. }}
  566. >
  567. delete
  568. </Button>
  569. )
  570. }}
  571. </Mutation>
  572. )
  573. }
  574. }
  575. class DeleteTableButton extends Component {
  576. render() {
  577. let schemaID = this.props.schemaID;
  578. let userID = this.props.userID;
  579. let varobj = {
  580. id: schemaID,
  581. updatedAt: new Date().getTime(),
  582. schemaState: 'updated-delete-table',
  583. };
  584. return (
  585. <Query query={gql(SHOW_TABLE)} variables={{schema_id: schemaID}}>
  586. {
  587. ({loading, error, data}) => {
  588. if (loading)
  589. return <Spin style={{marginLeft: 30, marginTop: 10}}/>;
  590. if (error)
  591. return 'error';
  592. let schemaData = data;
  593. let referenceID = data.schema_by_id ? data.schema_by_id.reference : this.props.location.state.reference;
  594. return (
  595. <Mutation
  596. mutation={gql(UPDATE_SCHEMA)}
  597. refetchQueries={[{query: gql(SHOW_TABLE), variables: {schema_id: schemaID}}]}
  598. >
  599. {(update_schema, {loading, error}) => {
  600. if (loading)
  601. return <Spin style={{marginLeft: 30, marginTop: 10}}/>;
  602. if (error)
  603. return 'error';
  604. // 先 query 再 mutation,然后删除
  605. let schemaCols;
  606. if (schemaData.schema_by_id === null) schemaCols = [];
  607. else schemaCols = JSON.parse(schemaData.schema_by_id.schemaData);
  608. const index = this.props.schemaData.findIndex(obj => obj.name === this.props.currentTable);
  609. if (index === -1) {
  610. // 先取数据,然后删除,然后填充
  611. this.props.fetchData(referenceID).then(value => {
  612. schemaCols = JSON.parse(value);
  613. const index = schemaCols.findIndex(obj => obj.name === this.props.currentTable);
  614. schemaCols.splice(index, 1);
  615. });
  616. } else {
  617. schemaCols.splice(index, 1);
  618. }
  619. return (
  620. <Icon type="delete"
  621. theme="twoTone"
  622. onClick={() => {
  623. update_schema({
  624. variables: {
  625. ...varobj,
  626. schemaData: JSON.stringify(schemaCols)
  627. }
  628. });
  629. this.props.showTablePagination(this.props.page, this.props.pageSize, schemaCols)
  630. }}>
  631. </Icon>
  632. )
  633. }}
  634. </Mutation>
  635. )
  636. }
  637. }
  638. </Query>
  639. )
  640. }
  641. }
  642. class ModifySchemaNameInput extends Component {
  643. constructor(props) {
  644. super(props);
  645. this.state = {}
  646. }
  647. render() {
  648. let userID = this.props.userID;
  649. let schemaName = this.props.schemaName;
  650. return (
  651. <Mutation mutation={gql(UPDATE_SCHEMA_NAME)}>
  652. {(update_schema, {loading, error}) => {
  653. if (error)
  654. return 'error';
  655. if (loading)
  656. return <Spin style={{marginLeft: 3}}/>;
  657. return (
  658. <div className={'schema'}>
  659. <Search
  660. value={this.props.editSchemaName}
  661. enterButton="Confirm"
  662. style={{width: 500}}
  663. size="large"
  664. onChange={this.props.changeEditSchemaName}
  665. onSearch={value => {
  666. update_schema({
  667. variables: {
  668. id: this.props.schemaID,
  669. schemaName: value,
  670. updateAt: new Date().getTime()
  671. }
  672. });
  673. this.props.history.push({
  674. pathname: `/graphql-service/my-create/${value}`,
  675. state: {
  676. schemaName: value,
  677. schemaID: this.props.schemaID,
  678. }
  679. });
  680. this.props.clearEditSchemaName();
  681. }}
  682. />
  683. </div>
  684. )
  685. }}
  686. </Mutation>
  687. )
  688. }
  689. }