configSider.jsx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import React from 'react'
  2. import { connect } from 'dva'
  3. import { Form, Input, Cascader, Select, Icon } from 'antd'
  4. import ChooseChartBox from './chooseChartBox'
  5. import CusFilterBox from './cusFilterBox'
  6. import copy from 'copy-to-clipboard'
  7. import themes from '../chartDesigner/sections/style/theme/index'
  8. import './configSider.less'
  9. const FormItem = Form.Item
  10. class ConfigSider extends React.Component {
  11. constructor(props) {
  12. super(props);
  13. this.state = {
  14. description: props.dashboardDesigner.description,
  15. visibleChooseChartBox: false,
  16. visibleCusFilterBox: false,
  17. copyDisabled: false,
  18. copyText: '复制',
  19. validInfo: { description: { status: 'success', help: '' } }
  20. };
  21. }
  22. componentDidMount() {
  23. this.props.dispatch({ type: 'dashboard/remoteMenuTree' })
  24. }
  25. showChooseChartBox = (o) => {
  26. this.setState({
  27. visibleChooseChartBox: true
  28. });
  29. }
  30. hideChooseChartBox = (o) => {
  31. this.setState({
  32. visibleChooseChartBox: false
  33. });
  34. }
  35. showCusFilterBox = (o) => {
  36. this.setState({
  37. visibleCusFilterBox: true
  38. });
  39. }
  40. hideCusFilterBox = (o) => {
  41. this.setState({
  42. visibleCusFilterBox: false
  43. });
  44. }
  45. generateViewTypes = () => {
  46. const { dispatch } = this.props;
  47. const { visibleChooseChartBox } = this.state;
  48. return (<div className='view-types'>
  49. <div className='view-type-item'onClick={() => {
  50. this.showChooseChartBox("create");
  51. }}>
  52. <Icon type='area-chart'/>
  53. <span>图表选择</span>
  54. </div>
  55. <div className='view-type-item' onClick={() => {
  56. dispatch({ type: 'dashboardDesigner/addRichText' });
  57. setTimeout(() => {
  58. // 滚动到最底部
  59. let viewScrollContent = document.querySelector('.viewlayout');
  60. viewScrollContent.scrollTo && viewScrollContent.scrollTo(0, viewScrollContent.scrollHeight - viewScrollContent.clientHeight);
  61. var e = document.createEvent("Event");
  62. e.initEvent("resize", true, true);
  63. window.dispatchEvent(e);
  64. }, 500);
  65. }}>
  66. <Icon type='book'/>
  67. <span>富文本</span>
  68. </div>
  69. {visibleChooseChartBox && <ChooseChartBox visibleBox={visibleChooseChartBox} hideBox={this.hideChooseChartBox} />}
  70. </div>)
  71. }
  72. generateMenuOptions = (menuTree) => {
  73. let menuList = [];
  74. menuTree.forEach(t => {
  75. t.children = t.children instanceof Array ? t.children : [];
  76. if(t.type === 'menu') {
  77. menuList.push({
  78. key: t.code,
  79. value: t.code,
  80. label: t.name,
  81. children: this.generateMenuOptions(t.children)
  82. });
  83. }
  84. })
  85. return menuList;
  86. }
  87. getParens = (menu) => {
  88. const { menuList } = this.props.dashboard;
  89. let pmenus = [menu];
  90. let fmenu = menuList.find(l => l.code === menu.pcode);
  91. if(fmenu) {
  92. pmenus = pmenus.concat(this.getParens(fmenu));
  93. }
  94. return pmenus;
  95. }
  96. getMenuValue = () => {
  97. const { dashboard, dashboardDesigner } = this.props;
  98. const { menuCode: key } = dashboardDesigner;
  99. let menu = dashboard.menuList.find(m => m.code === key);
  100. if(menu) {
  101. let menus = this.getParens(menu);
  102. let val = menus.reverse().map(m => m.code);
  103. return val;
  104. }else {
  105. return null;
  106. }
  107. }
  108. render() {
  109. const { dashboard, dashboardDesigner, dispatch } = this.props;
  110. const { description, visibleCusFilterBox, copyDisabled, copyText, validInfo } = this.state;
  111. const { theme } = dashboardDesigner;
  112. const { menuTree } = dashboard;
  113. return <Form className='form-config' layout={'vertical'}>
  114. <div className='divider'>报表制作</div>
  115. {this.generateViewTypes()}
  116. <div className='divider'>字段过滤</div>
  117. <div className="cus-filter-button" onClick={this.showCusFilterBox}>
  118. <Icon type='bulb' theme='outlined' />自定义过滤字段
  119. </div>
  120. {visibleCusFilterBox && <CusFilterBox visibleBox={visibleCusFilterBox} hideBox={this.hideCusFilterBox} />}
  121. <div className='divider'>其他设置</div>
  122. <FormItem label='所属目录'>
  123. <Cascader
  124. value={this.getMenuValue()}
  125. allowClear={false}
  126. changeOnSelect={true}
  127. expandTrigger='hover'
  128. placeholder='无'
  129. options={this.generateMenuOptions(menuTree)}
  130. onChange={(value, items) => {
  131. let v = value[value.length - 1];
  132. dispatch({ type: 'dashboardDesigner/setField', name: 'menuCode', value: v });
  133. }}
  134. >
  135. </Cascader>
  136. </FormItem>
  137. <FormItem label='备注' validateStatus={validInfo.description.status} help={validInfo.description.help}>
  138. <Input.TextArea
  139. autosize={{ minRows: 2, maxRows: 6 }}
  140. value={description}
  141. onChange={e => {
  142. let val = e.target.value;
  143. let status = 'success', help = '';
  144. if(val.length > 150) {
  145. status = 'error';
  146. help = '备注不能超过150个字符'
  147. }
  148. this.setState({
  149. description: val,
  150. validInfo: {
  151. description: { status, help, }
  152. }
  153. });
  154. window.clearTimeout(this.descriptionKey);
  155. this.descriptionKey = window.setTimeout(() => {
  156. if(val.trim().length <= 150) {
  157. dispatch({ type: 'dashboardDesigner/setField', name: 'description', value: val });
  158. }
  159. }, 200);
  160. }}
  161. onBlur={(e) => {
  162. if(validInfo.description.status === 'success') {
  163. dispatch({ type: 'dashboardDesigner/setField', name: 'description', value: e.target.value });
  164. }else {
  165. this.setState({
  166. description: dashboardDesigner.description
  167. }, () => {
  168. window.setTimeout(() => {
  169. this.setState({
  170. validInfo: {
  171. description: { status: 'success', help: '', }
  172. }
  173. });
  174. }, 500);
  175. })
  176. }
  177. }}
  178. />
  179. </FormItem>
  180. <FormItem label='报表编号'>
  181. <Input
  182. value={dashboardDesigner.shareCode}
  183. onChange={(e) => {
  184. dispatch({ type: 'dashboardDesigner/setField', name: 'shareCode', value: e.target.value });
  185. }}
  186. addonAfter={<span style={{ cursor: (copyDisabled || !dashboardDesigner.shareCode) ? 'not-allowed' : 'pointer' }} onClick={() => {
  187. if(copyDisabled || !dashboardDesigner.shareCode) {
  188. return;
  189. }
  190. copy(dashboardDesigner.shareCode);
  191. this.setState({
  192. copyDisabled: true,
  193. copyText: '已复制'
  194. }, () => {
  195. setTimeout(() => {
  196. this.setState({
  197. copyDisabled: false,
  198. copyText: '复制'
  199. });
  200. }, 3000)
  201. });
  202. }}>{copyText}</span>}
  203. />
  204. </FormItem>
  205. <div className='divider'>看板主题</div>
  206. <FormItem>
  207. <Select
  208. defaultValue={theme || 'default'}
  209. onChange={(value, item) => {
  210. dispatch({ type: 'dashboardDesigner/setField', name: 'theme', value: value });
  211. dispatch({ type: 'dashboardDesigner/refresh' });
  212. }}
  213. >
  214. {themes.map((theme) => (
  215. <Select.Option value={theme.name} key={theme.name}>{theme.label}</Select.Option>
  216. ))}
  217. </Select>
  218. </FormItem>
  219. </Form>
  220. }
  221. }
  222. export default connect(({ dashboard, dashboardDesigner }) => ({ dashboard, dashboardDesigner }))(ConfigSider);