news.jsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. import React from 'react';
  2. import { Icon, Button, Spin, message, Table, Input, Modal, DatePicker, Upload, Select, Radio } from 'antd';
  3. import { beforeUpload, getBase64 } from '../../../tools';
  4. import Editors from '../../../richTextEditors'
  5. import moment from 'moment';
  6. import ajax from 'jquery/src/ajax/xhr.js';
  7. import $ from 'jquery/src/ajax';
  8. const Avatar = React.createClass({
  9. getInitialState() {
  10. return {
  11. imageUrl: ''
  12. }
  13. },
  14. handleChange(info) {
  15. if (info.file.status === 'done') {
  16. // Get this url from response in real world.
  17. getBase64(info.file.originFileObj, imageUrl => this.setState({ imageUrl }));
  18. this.props.urlData(info.file.response.data);
  19. }
  20. },
  21. componentWillReceiveProps(nextProps) {
  22. if (this.props.visible && !nextProps.visible) {
  23. this.state.imageUrl = null;
  24. };
  25. },
  26. render() {
  27. const imageUrl = this.state.imageUrl;
  28. return (
  29. <Upload
  30. className="avatar-uploader"
  31. name={this.props.name}
  32. showUploadList={false}
  33. action={globalConfig.context + "/api/admin/news/upload"}
  34. data={{ 'sign': 'news_title_picture' }}
  35. beforeUpload={beforeUpload}
  36. onChange={this.handleChange} >
  37. {
  38. (imageUrl || this.props.imageUrl) ?
  39. <img src={imageUrl || this.props.imageUrl} role="presentation" id={this.props.name} /> :
  40. <Icon type="plus" className="avatar-uploader-trigger" />
  41. }
  42. </Upload>
  43. );
  44. }
  45. });
  46. const News = React.createClass({
  47. loadData(pageNo, theType) {
  48. this.setState({
  49. loading: true
  50. });
  51. $.ajax({
  52. method: "get",
  53. dataType: "json",
  54. crossDomain: false,
  55. url: globalConfig.context + '/api/admin/news/list',
  56. data: {
  57. pageNo: pageNo || 1,
  58. pageSize: this.state.pagination.pageSize,
  59. type: theType || this.props.newsType || 0, //新闻类型
  60. title: this.state.searchTitle,
  61. author: this.state.searchAuthor,
  62. startCreateTime: this.state.startDate, //新闻开始时间 yyyy-MM-dd
  63. endCreateTime: this.state.endDate, //新闻结束时间 yyyy-MM-dd
  64. source: this.state.searchSource,
  65. hot: this.state.searchHot, //是否放在首页
  66. },
  67. success: function (data) {
  68. let theArr = [];
  69. if (!data.data || !data.data.list) {
  70. if (data.error && data.error.length) {
  71. message.warning(data.error[0].message);
  72. };
  73. } else {
  74. for (let i = 0; i < data.data.list.length; i++) {
  75. let thisdata = data.data.list[i];
  76. theArr.push({
  77. key: i,
  78. id: thisdata.id ? thisdata.id.toString() : null,
  79. createTime: thisdata.createTime,
  80. editTime: thisdata.editTime,
  81. title: thisdata.title,
  82. titleImg: thisdata.titleImg,
  83. author: thisdata.author,
  84. type: thisdata.type,
  85. hot: thisdata.hot,
  86. source: thisdata.source,
  87. sourceUrl: thisdata.sourceUrl,
  88. summary: thisdata.summary,
  89. content: thisdata.content,
  90. createTimeFormattedDate: thisdata.createTimeFormattedDate,
  91. });
  92. };
  93. this.state.pagination.current = data.data.pageNo;
  94. this.state.pagination.total = data.data.totalCount;
  95. };
  96. this.setState({
  97. tableData: theArr,
  98. pagination: this.state.pagination
  99. });
  100. }.bind(this),
  101. }).always(function () {
  102. this.setState({
  103. loading: false
  104. });
  105. }.bind(this));
  106. },
  107. loadDetailData() {
  108. this.setState({
  109. loading: true
  110. });
  111. $.ajax({
  112. method: "get",
  113. dataType: "json",
  114. crossDomain: false,
  115. url: globalConfig.context + '/api/admin/news/detail',
  116. data: {
  117. id: this.state.RowData.id //新闻主键ID(数字类型,非字符串)
  118. },
  119. success: function (data) {
  120. let theObj = {};
  121. if (!data.data) {
  122. if (data.error && data.error.length) {
  123. message.warning(data.error[0].message);
  124. }
  125. } else {
  126. theObj = data.data;
  127. if(theObj.provinceId==null||theObj.provinceId==''){
  128. theObj.provinceId=11
  129. }
  130. };
  131. this.setState({
  132. RowData: theObj,
  133. });
  134. }.bind(this),
  135. }).always(function () {
  136. this.setState({
  137. loading: false
  138. });
  139. }.bind(this));
  140. },
  141. getInitialState() {
  142. return {
  143. loading: false,
  144. visible: false,
  145. selectedRowKeys: [],
  146. selectedRows: [],
  147. keysObj: {},
  148. RowData: {},
  149. pagination: {
  150. defaultCurrent: 1,
  151. defaultPageSize: 10,
  152. showQuickJumper: true,
  153. pageSize: 10,
  154. onChange: function (page) {
  155. this.loadData(page);
  156. }.bind(this),
  157. showTotal: function (total) {
  158. return '共' + total + '条数据';
  159. }
  160. },
  161. columns: [
  162. {
  163. title: '标题',
  164. dataIndex: 'title',
  165. key: 'title',
  166. width: '20%'
  167. }, {
  168. title: '发布时间',
  169. dataIndex: 'createTimeFormattedDate',
  170. key: 'createTimeFormattedDate',
  171. }, {
  172. title: '作者',
  173. dataIndex: 'author',
  174. key: 'author',
  175. }, {
  176. title: '来源',
  177. dataIndex: 'source',
  178. key: 'source',
  179. }, {
  180. title: '简介',
  181. dataIndex: 'summary',
  182. key: 'summary',
  183. width: '50%'
  184. }
  185. ],
  186. list: [
  187. {"code":"11","cn":"湖南"},
  188. {"code":"1","cn":"北京"},
  189. {"code":"2","cn":"上海"},
  190. {"code":"3","cn":"天津"},
  191. {"code":"4","cn":"重庆"},
  192. {"code":"5","cn":"四川"},
  193. {"code":"6","cn":"贵州"},
  194. {"code":"7","cn":"云南"},
  195. {"code":"8","cn":"西藏"},
  196. {"code":"9","cn":"河南"},
  197. {"code":"10","cn":"湖北"},
  198. {"code":"12","cn":"广东"},
  199. {"code":"13","cn":"广西"},
  200. {"code":"14","cn":"陕西"},
  201. {"code":"15","cn":"甘肃"},
  202. {"code":"16","cn":"青海"},
  203. {"code":"17","cn":"宁夏"},
  204. {"code":"18","cn":"新疆"},
  205. {"code":"19","cn":"河北"},
  206. {"code":"20","cn":"山西"},
  207. {"code":"21","cn":"内蒙古"},
  208. {"code":"22" ,"cn":"江苏"},
  209. {"code":"23","cn":"浙江"},
  210. {"code":"24","cn":"安徽"},
  211. {"code":"25","cn":"福建"},
  212. {"code":"26","cn":"江西"},
  213. {"code":"27","cn":"山东"},
  214. {"code":"28","cn":"辽宁"},
  215. {"code":"29","cn":"吉林"},
  216. {"code":"30","cn":"黑龙江"},
  217. {"code":"31","cn":"海南"},
  218. {"code":"32","cn":"台湾"},
  219. {"code":"33","cn":"香港"},
  220. {"code":"34","cn":"澳门"},
  221. ],
  222. tableData: []
  223. };
  224. },
  225. tableRowClick(record, index) {
  226. this.state.RowData = record;
  227. this.loadDetailData();
  228. this.setState({
  229. visible: true
  230. });
  231. },
  232. componentWillMount() {
  233. this.loadData();
  234. },
  235. componentWillReceiveProps(nextProps) {
  236. if (this.props.newsType != nextProps.newsType) {
  237. this.state.searchTitle = undefined;
  238. this.state.searchAuthor = undefined;
  239. this.state.startDate = undefined;
  240. this.state.endDate = undefined;
  241. this.state.searchSource = undefined;
  242. this.state.searchHot = undefined;
  243. this.loadData(1, nextProps.newsType);
  244. };
  245. },
  246. submit() {
  247. if (!this.state.RowData.title) {
  248. message.warning('必须填写一个标题!');
  249. return;
  250. };
  251. if (!this.state.RowData.createTimeFormattedDate) {
  252. message.warning('必须选择一个发布时间!');
  253. return;
  254. };
  255. if (!this.state.RowData.author) {
  256. message.warning('必须填写一个作者!');
  257. return;
  258. };
  259. this.setState({
  260. loading: true
  261. });
  262. $.ajax({
  263. method: "post",
  264. dataType: "json",
  265. crossDomain: false,
  266. url: globalConfig.context + (this.state.RowData.id ? '/api/admin/news/update' : '/api/admin/news/add'),
  267. data: {
  268. id: this.state.RowData.id || null, //主键,如果不填主键则为新增记录,填主键则为更新
  269. title: this.state.RowData.title,
  270. titleImg: this.state.RowData.titleImg,
  271. author: this.state.RowData.author,
  272. type: this.props.newsType,
  273. hot: this.state.RowData.hot || 0,
  274. source: this.state.RowData.source,
  275. sourceUrl: this.state.RowData.sourceUrl,
  276. summary: this.state.RowData.summary,
  277. content: this.state.RowData.content,
  278. createTimeFormattedDate: this.state.RowData.createTimeFormattedDate,
  279. jmrhFlag: this.state.RowData.jmrhFlag ,
  280. provinceId: this.state.RowData.provinceId,
  281. },
  282. success: function (data) {
  283. if (data.error && data.error.length) {
  284. message.warning(data.error[0].message);
  285. } else {
  286. message.success('保存成功!');
  287. this.setState({ visible: false });
  288. this.loadData();
  289. };
  290. }.bind(this),
  291. }).always(function () {
  292. this.setState({
  293. loading: false
  294. });
  295. }.bind(this));
  296. },
  297. delectRow() {
  298. let deletedIds = [];
  299. for (let idx = 0; idx < this.state.selectedRows.length; idx++) {
  300. let rowItem = this.state.selectedRows[idx];
  301. if (rowItem.id) {
  302. deletedIds.push(rowItem.id)
  303. };
  304. };
  305. this.setState({
  306. selectedRowKeys: [],
  307. loading: deletedIds.length > 0
  308. });
  309. $.ajax({
  310. method: "POST",
  311. dataType: "json",
  312. crossDomain: false,
  313. url: globalConfig.context + "/api/admin/news/delete",
  314. data: {
  315. ids: deletedIds
  316. }
  317. }).done(function (data) {
  318. if (data.error && data.error.length) {
  319. message.warning(data.error[0].message);
  320. } else {
  321. message.success('删除成功!');
  322. };
  323. this.setState({
  324. loading: false,
  325. });
  326. this.loadData();
  327. }.bind(this));
  328. },
  329. reset() {
  330. this.state.searchTitle = undefined;
  331. this.state.searchAuthor = undefined;
  332. this.state.startDate = undefined;
  333. this.state.endDate = undefined;
  334. this.state.searchSource = undefined;
  335. this.state.searchHot = undefined;
  336. this.loadData();
  337. },
  338. cleanCache(sign) {
  339. this.setState({
  340. loading: true
  341. });
  342. $.ajax({
  343. method: "post",
  344. dataType: "json",
  345. crossDomain: false,
  346. url: globalConfig.context + '/api/admin/news/cleanCache',
  347. data: {
  348. 'cacheKey': sign
  349. },
  350. success: function (data) {
  351. if (data.error && data.error.length) {
  352. message.warning(data.error[0].message);
  353. } else {
  354. message.success('清除缓存成功!');
  355. };
  356. }.bind(this),
  357. }).always(function () {
  358. this.setState({
  359. loading: false
  360. });
  361. }.bind(this));
  362. },
  363. render() {
  364. const rowSelection = {
  365. selectedRowKeys: this.state.selectedRowKeys,
  366. onChange: (selectedRowKeys, selectedRows) => {
  367. this.setState({
  368. selectedRows: selectedRows.slice(-1),
  369. selectedRowKeys: selectedRowKeys.slice(-1)
  370. });
  371. }
  372. };
  373. const hasSelected = this.state.selectedRowKeys.length > 0;
  374. return (
  375. <div className="admin-content" >
  376. <div className="admin-content-title">
  377. {(() => {
  378. switch (this.props.newsType) {
  379. case 1: return <span>科技快讯管理</span>;
  380. case 4: return <span>国家政策管理</span>;
  381. case 5: return <span>地方政策管理</span>;
  382. case 2: return <span>政府往来管理</span>;
  383. case 3: return <span>技淘动态管理</span>;
  384. }
  385. })()}
  386. <Button type="primary" style={{ float: 'right' }}
  387. onClick={() => { this.setState({ RowData: {}, visible: true }) }}>
  388. 添加<Icon type="plus" />
  389. </Button>
  390. </div>
  391. <div className="admin-content-warp">
  392. <div className="admin-content-search">
  393. <Input placeholder="标题" style={{ width: 200 }}
  394. value={this.state.searchTitle}
  395. onChange={(e) => { this.setState({ searchTitle: e.target.value }); }} />
  396. <Input placeholder="作者" style={{ width: 100 }}
  397. value={this.state.searchAuthor}
  398. onChange={(e) => { this.setState({ searchAuthor: e.target.value }); }} />
  399. <Input placeholder="来源" style={{ width: 100 }}
  400. value={this.state.searchSource}
  401. onChange={(e) => { this.setState({ searchSource: e.target.value }); }} />
  402. {this.props.newsType == 2 || this.props.newsType == 3 ? <Select placeholder="显示在首页"
  403. style={{ width: 100 }}
  404. value={this.state.searchHot}
  405. onChange={(e) => { this.setState({ searchHot: e }) }}>
  406. <Select.Option value="0" >不显示</Select.Option>
  407. <Select.Option value="1" >显示</Select.Option>
  408. </Select> : <span></span>}
  409. <span>发布时间</span>
  410. <DatePicker style={{ width: 110 }}
  411. format="YYYY-MM-DD"
  412. placeholder="选择开始时间"
  413. value={this.state.startDate ? moment(this.state.startDate, "YYYY-MM-DD") : undefined}
  414. onChange={(t, str) => {
  415. this.setState({ startDate: str });
  416. }} />
  417. <span>到</span>
  418. <DatePicker style={{ width: 110 }}
  419. format="YYYY-MM-DD"
  420. placeholder="选择结束时间"
  421. value={this.state.endDate ? moment(this.state.endDate, "YYYY-MM-DD") : undefined}
  422. onChange={(t, str) => {
  423. this.setState({ endDate: str });
  424. }} />
  425. <Button type="primary" onClick={() => { this.loadData() }}>搜索</Button>
  426. <Button onClick={this.reset}>重置</Button>
  427. <Button type='danger' disabled={!hasSelected} onClick={this.delectRow}>
  428. 删除<Icon type="minus" />
  429. </Button>
  430. <Button type="primary" onClick={() => { this.cleanCache('news_list_cache_key'); }}>清除策源地缓存</Button>
  431. <Button type="primary" onClick={() => { this.cleanCache('news_portal_list_cache_key'); }}>清除列表页缓存</Button>
  432. {this.props.newsType == 2 || this.props.newsType == 3 ? <Button type="primary" onClick={() => { this.cleanCache('news_index_list_cache_key'); }}>清除首页缓存</Button> : <div></div>}
  433. </div>
  434. <Spin spinning={this.state.loading}>
  435. <Table className="no-all-select" columns={this.state.columns}
  436. dataSource={this.state.tableData}
  437. pagination={this.state.pagination}
  438. rowSelection={rowSelection}
  439. onRowClick={this.tableRowClick} />
  440. </Spin>
  441. </div>
  442. <Modal title="新闻详情" width={1000} className="news-modal"
  443. visible={this.state.visible}
  444. maskClosable={false}
  445. footer={null}
  446. afterClose={() => { this.state.RowData = {}; }}
  447. onCancel={() => { this.setState({ visible: false }) }} >
  448. <Spin spinning={this.state.loading}>
  449. <div className="clearfix">
  450. <div className="modal-box">
  451. <span className="modal-box-title">新闻标题</span>
  452. <div className="modal-box-detail">
  453. <Input value={this.state.RowData.title}
  454. onChange={(e) => {
  455. this.state.RowData.title = e.target.value;
  456. this.setState({ RowData: this.state.RowData });
  457. }} />
  458. </div>
  459. </div>
  460. <div className="modal-box">
  461. <span className="modal-box-title">简介</span>
  462. <div className="modal-box-detail">
  463. <Input type="textarea" rows={3} value={this.state.RowData.summary}
  464. onChange={(e) => {
  465. this.state.RowData.summary = e.target.value;
  466. this.setState({ RowData: this.state.RowData });
  467. }} />
  468. </div>
  469. </div>
  470. <div className="modal-box">
  471. <span className="modal-box-title">来源</span>
  472. <div className="modal-box-detail">
  473. <Input value={this.state.RowData.source}
  474. onChange={(e) => {
  475. this.state.RowData.source = e.target.value;
  476. this.setState({ RowData: this.state.RowData });
  477. }} />
  478. </div>
  479. </div>
  480. <div className="modal-box">
  481. <span className="modal-box-title">来源链接</span>
  482. <div className="modal-box-detail">
  483. <Input value={this.state.RowData.sourceUrl}
  484. onChange={(e) => {
  485. this.state.RowData.sourceUrl = e.target.value;
  486. this.setState({ RowData: this.state.RowData });
  487. }} />
  488. </div>
  489. </div>
  490. <div className="modal-box" style={{ position: 'absolute', right: '0', width: '480px' }}>
  491. <span className="modal-box-title">标题图片</span>
  492. <div className="modal-box-detail clearfix" style={{ width: '360px' }}>
  493. <Avatar sign={'news_title_picture'} visible={this.state.visible}
  494. imageUrl={this.state.RowData.titleImg ? (globalConfig.avatarHost + "/upload" + this.state.RowData.titleImg) : null}
  495. urlData={(url) => { this.state.RowData.titleImg = url }} />
  496. </div>
  497. </div>
  498. </div>
  499. <div className="clearfix">
  500. <div className="modal-box news-box">
  501. <span className="modal-box-title">作者</span>
  502. <div className="modal-box-detail">
  503. <Input value={this.state.RowData.author}
  504. onChange={(e) => {
  505. this.state.RowData.author = e.target.value;
  506. this.setState({ RowData: this.state.RowData });
  507. }} />
  508. </div>
  509. </div>
  510. <div className="modal-box news-box">
  511. <span className="modal-box-title">发布时间</span>
  512. <div className="modal-box-detail">
  513. <DatePicker style={{ width: '120px' }}
  514. format="YYYY-MM-DD"
  515. placeholder="选择发布时间"
  516. value={this.state.RowData.createTimeFormattedDate ? moment(this.state.RowData.createTimeFormattedDate, "YYYY-MM-DD") : undefined}
  517. onChange={(t, str) => {
  518. this.state.RowData.createTimeFormattedDate = str;
  519. this.setState({ RowData: this.state.RowData});
  520. }} />
  521. </div>
  522. </div>
  523. <div className="modal-box news-box">
  524. <span className="modal-box-title jmrhFlag">军民融合:</span>
  525. <Radio.Group value={this.state.RowData.jmrhFlag} onChange={(e) => {
  526. this.state.RowData.jmrhFlag = e.target.value;
  527. this.setState({jmrhFlag: this.state.jmrhFlag });
  528. }} >
  529. <Radio value={0}>否</Radio>
  530. <Radio value={1}>是</Radio>
  531. </Radio.Group>
  532. </div>
  533. {this.props.newsType == 2 || this.props.newsType == 3 ? <div className="modal-box news-box">
  534. <span className="modal-box-title">发布在首页</span>
  535. <div className="modal-box-detail">
  536. <Radio.Group value={this.state.RowData.hot} onChange={(e) => {
  537. this.state.RowData.hot = e.target.value;
  538. this.setState({ RowData: this.state.RowData });
  539. }} >
  540. <Radio value={0}>否</Radio>
  541. <Radio value={1}>是</Radio>
  542. </Radio.Group>
  543. </div>
  544. </div> : <div></div>}
  545. </div>
  546. <div className="modal-box">
  547. <span className="modal-box-title">新闻内容</span>
  548. <select value={this.state.RowData.provinceId} onChange={(e) => {
  549. this.state.RowData.provinceId = e.target.value;
  550. this.setState({provinceId: this.state.provinceId });
  551. }} className="provin">
  552. {
  553. this.state.list.map(function(name){
  554. return (
  555. <option value={name.code} key={name.code} >{name.cn}</option>
  556. )
  557. })
  558. }
  559. </select>
  560. </div>
  561. <Editors textContent={this.state.RowData.content}
  562. uploadUrl={'/api/admin/news/upload'}
  563. uploadSign={'news_content_picture'}
  564. handleRichText={(value) => { this.state.RowData.content = value; }}
  565. visible={this.state.visible} />
  566. <div className="modal-box">
  567. <Button type="primary" onClick={this.submit}>提交</Button>
  568. <Button type="ghost" onClick={() => { this.setState({ visible: false }) }}>取消</Button>
  569. </div>
  570. </Spin>
  571. </Modal>
  572. </div >
  573. );
  574. }
  575. });
  576. export default News;