techDemandDesc.jsx 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. import React from 'react';
  2. import { Icon, Tooltip, Modal, Popover, message, Spin, Upload, Input, InputNumber, Select, DatePicker, Button, Radio, Form, Cascader, Tag } from 'antd';
  3. import moment from 'moment';
  4. import './techDemand.less';
  5. import ajax from 'jquery/src/ajax/xhr.js';
  6. import $ from 'jquery/src/ajax';
  7. import { IndustryObject, getIndustryCategory } from '../../DicIndustryList.js';
  8. import { beforeUploadFile, splitUrl, companySearch, getTechField, getDemandType } from '../../tools.js';
  9. const KeyWordTagGroup = React.createClass({
  10. getInitialState() {
  11. return {
  12. tags: [],
  13. inputVisible: false,
  14. inputValue: ''
  15. };
  16. },
  17. handleClose(removedTag) {
  18. const tags = this.state.tags.filter(tag => tag !== removedTag);
  19. this.props.tagsArr(tags);
  20. this.setState({ tags });
  21. },
  22. showInput() {
  23. this.setState({ inputVisible: true }, () => this.input.focus());
  24. },
  25. handleInputChange(e) {
  26. this.setState({ inputValue: e.target.value });
  27. },
  28. handleInputConfirm() {
  29. const state = this.state;
  30. const inputValue = state.inputValue;
  31. let tags = state.tags;
  32. if (inputValue && tags.indexOf(inputValue) === -1 && inputValue.replace(/(^\s*)|(\s*$)/g, "").length != 0) {
  33. tags = [...tags, inputValue.replace(/(^\s*)|(\s*$)/g, "")];
  34. }
  35. this.props.tagsArr(tags);
  36. this.setState({
  37. tags,
  38. inputVisible: false,
  39. inputValue: '',
  40. });
  41. },
  42. componentWillMount() {
  43. this.state.tags = this.props.keyWordArr;
  44. },
  45. componentWillReceiveProps(nextProps) {
  46. if (this.props.keyWordArr != nextProps.keyWordArr) {
  47. this.state.tags = nextProps.keyWordArr;
  48. };
  49. },
  50. render() {
  51. const { tags, inputVisible, inputValue } = this.state;
  52. return (
  53. <div className="keyWord-tips">
  54. {tags.map((tag, index) => {
  55. const isLongTag = tag.length > 10;
  56. const tagElem = (
  57. <Tag key={tag} closable={index !== -1} afterClose={() => this.handleClose(tag)}>
  58. {isLongTag ? `${tag.slice(0, 10)}...` : tag}
  59. </Tag>
  60. );
  61. return isLongTag ? <Tooltip title={tag}>{tagElem}</Tooltip> : tagElem;
  62. })}
  63. {inputVisible && (
  64. <Input
  65. ref={input => this.input = input}
  66. type="text"
  67. style={{ width: 78 }}
  68. value={inputValue}
  69. onChange={this.handleInputChange}
  70. onBlur={this.handleInputConfirm}
  71. onPressEnter={this.handleInputConfirm}
  72. />
  73. )}
  74. {!inputVisible && <Button className="addtips" type="dashed" disabled={tags.length > 9 ? true : false} onClick={this.showInput}>+ 新关键词</Button>}
  75. </div>
  76. );
  77. }
  78. });
  79. const PicturesWall = React.createClass({
  80. getInitialState() {
  81. return {
  82. previewVisible: false,
  83. previewImage: '',
  84. fileList: [],
  85. }
  86. },
  87. handleCancel() {
  88. this.setState({ previewVisible: false })
  89. },
  90. handlePreview(file) {
  91. this.setState({
  92. previewImage: file.url || file.thumbUrl,
  93. previewVisible: true,
  94. });
  95. },
  96. handleChange(info) {
  97. let fileList = info.fileList;
  98. this.setState({ fileList });
  99. this.props.fileList(fileList);
  100. },
  101. componentWillReceiveProps(nextProps) {
  102. this.state.fileList = nextProps.pictureUrl;
  103. },
  104. render() {
  105. const { previewVisible, previewImage, fileList } = this.state;
  106. const uploadButton = (
  107. <div>
  108. <Icon type="plus" />
  109. <div className="ant-upload-text">点击上传</div>
  110. </div>
  111. );
  112. return (
  113. <div className="clearfix">
  114. <Upload
  115. action={globalConfig.context + "/api/user/demand/uploadPicture"}
  116. data={{ 'sign': 'demand_picture', 'uid': this.props.uid }}
  117. listType="picture-card"
  118. fileList={fileList}
  119. onPreview={this.handlePreview}
  120. onChange={this.handleChange} >
  121. {fileList.length >= 5 ? null : uploadButton}
  122. </Upload>
  123. <Modal maskClosable={false} visible={previewVisible} footer={null} onCancel={this.handleCancel}>
  124. <img alt="example" style={{ width: '100%' }} src={previewImage} />
  125. </Modal>
  126. </div>
  127. );
  128. }
  129. });
  130. const DemandDetailShow = Form.create()(React.createClass({
  131. getInitialState() {
  132. return {
  133. visible: false,
  134. loading: false,
  135. contactsObj: {},
  136. salesmanObj: {},
  137. pictureUrl: [],
  138. tags: []
  139. };
  140. },
  141. loadData(id) {
  142. this.setState({
  143. loading: true
  144. });
  145. $.ajax({
  146. method: "get",
  147. dataType: "json",
  148. crossDomain: false,
  149. url: globalConfig.context + (window.userData.type == '1' ? '/api/user/demand/orgDemandDetail' : '/api/user/demand/userDemandDetail'),
  150. data: {
  151. id: id
  152. },
  153. success: function (data) {
  154. let thisData = data.data;
  155. if (!thisData) {
  156. if (data.error && data.error.length) {
  157. message.warning(data.error[0].message);
  158. };
  159. thisData = {};
  160. };
  161. this.setState({
  162. data: thisData,
  163. tags: thisData.keyword ? thisData.keyword.split(",") : [],
  164. pictureUrl: thisData.pictureUrl ? splitUrl(thisData.pictureUrl, ',', globalConfig.avatarHost + '/upload') : []
  165. });
  166. }.bind(this),
  167. }).always(function () {
  168. this.setState({
  169. loading: false
  170. });
  171. }.bind(this));
  172. },
  173. offShelf() {
  174. this.setState({
  175. loading: true
  176. });
  177. $.ajax({
  178. method: "post",
  179. dataType: "json",
  180. crossDomain: false,
  181. url: globalConfig.context + "/api/user/demand/offShelf",
  182. data: { "id": this.props.data.id }
  183. }).done(function (data) {
  184. if (!data.error.length) {
  185. message.success('撤销成功!');
  186. this.setState({
  187. visible: false,
  188. releaseSubmitVisible: false
  189. });
  190. this.props.handleOk();
  191. } else {
  192. message.warning(data.error[0].message);
  193. }
  194. }.bind(this));
  195. },
  196. componentWillMount() {
  197. if (this.props.data.id) {
  198. this.loadData(this.props.data.id);
  199. } else {
  200. this.state.data = {};
  201. };
  202. },
  203. componentWillReceiveProps(nextProps) {
  204. if (!this.props.visible && nextProps.visible) {
  205. if (nextProps.data.id) {
  206. this.loadData(nextProps.data.id);
  207. } else {
  208. this.state.data = {};
  209. };
  210. this.props.form.resetFields();
  211. };
  212. },
  213. render() {
  214. const theData = this.state.data || {};
  215. const { getFieldDecorator } = this.props.form;
  216. const FormItem = Form.Item
  217. const formItemLayout = {
  218. labelCol: { span: 6 },
  219. wrapperCol: { span: 12 },
  220. };
  221. return (
  222. <Form horizontal onSubmit={this.handleSubmit} id="demand-form">
  223. <Spin spinning={this.state.loading}>
  224. <div className="clearfix">
  225. <FormItem className="half-item"
  226. {...formItemLayout}
  227. label="编号" >
  228. <span>{theData.serialNumber}</span>
  229. </FormItem>
  230. <FormItem className="half-item"
  231. {...formItemLayout}
  232. label="需求名称" >
  233. <span>{theData.name}</span>
  234. </FormItem>
  235. <FormItem className="half-item"
  236. {...formItemLayout}
  237. label="雇主名称" >
  238. <span>{theData.username}</span>
  239. </FormItem>
  240. {window.userData.type == '1' ? <FormItem className="half-item"
  241. {...formItemLayout}
  242. label="联系人" >
  243. <span>{this.props.contactsObj[theData.contacts]}</span>
  244. </FormItem> : <div></div>}
  245. {window.userData.type == '0' ? <FormItem className="half-item"
  246. {...formItemLayout}
  247. label="联系方式" >
  248. <span>{theData.mobile}</span>
  249. </FormItem> : <div></div>}
  250. </div>
  251. <div className="clearfix">
  252. <FormItem className="half-item"
  253. {...formItemLayout}
  254. label="是否发布" >
  255. {(() => {
  256. switch (theData.releaseStatus) {
  257. case "0":
  258. return <span>未发布</span>;
  259. case "1":
  260. return <div>
  261. <span>已发布</span>
  262. <Button style={{ marginLeft: '10px' }} onClick={() => { this.setState({ releaseSubmitVisible: true }); }}>撤消发布</Button>
  263. <Modal maskClosable={false} title="确认"
  264. visible={this.state.releaseSubmitVisible}
  265. width='300px'
  266. footer={null}
  267. onCancel={() => { this.setState({ releaseSubmitVisible: false }) }} >
  268. <span>确认要撤销发布吗?</span>
  269. <Button className="modal-submit" type="primary" onClick={this.offShelf} >确认</Button>
  270. <Button className="modal-submit" type="ghost" onClick={() => { this.setState({ releaseSubmitVisible: false }) }}>取消</Button>
  271. </Modal>
  272. </div>;
  273. }
  274. })()}
  275. </FormItem>
  276. <FormItem className="half-item"
  277. {...formItemLayout}
  278. label="发布时间" >
  279. <span>{theData.releaseDateFormattedDate}</span>
  280. </FormItem>
  281. </div>
  282. <div className="clearfix">
  283. <FormItem className="half-item"
  284. {...formItemLayout}
  285. label="需求状态" >
  286. {(() => {
  287. switch (theData.status) {
  288. case "0":
  289. return <span>未解决</span>;
  290. case "1":
  291. return <span>已解决</span>;
  292. }
  293. })()}
  294. </FormItem>
  295. <FormItem className="half-item"
  296. {...formItemLayout}
  297. label="审核状态" >
  298. {(() => {
  299. switch (theData.auditStatus) {
  300. case "0":
  301. return <span>未提交审核(草稿)</span>;
  302. case "1":
  303. return <span>提交审核</span>;
  304. case "2":
  305. return <span>审核中</span>;
  306. case "3":
  307. return <span>审核通过</span>;
  308. case "4":
  309. return <span>审核未通过</span>;
  310. }
  311. })()}
  312. </FormItem>
  313. </div>
  314. <div className="clearfix">
  315. <FormItem className="half-item"
  316. {...formItemLayout}
  317. label="信息来源" >
  318. {(() => {
  319. switch (theData.infoSources) {
  320. case "0":
  321. return <span>平台采集</span>;
  322. case "1":
  323. return <span>客户发布</span>;
  324. }
  325. })()}
  326. </FormItem>
  327. </div>
  328. <FormItem
  329. labelCol={{ span: 3 }}
  330. wrapperCol={{ span: 20 }}
  331. label="关键词" >
  332. {this.state.tags.map((tag) => {
  333. return <Tooltip key={tag} title={tag}>
  334. <Tag key={tag}>{tag}</Tag>
  335. </Tooltip>;
  336. })}
  337. </FormItem>
  338. <FormItem
  339. labelCol={{ span: 3 }}
  340. wrapperCol={{ span: 18 }}
  341. label="行业类别" >
  342. <span>{getIndustryCategory(theData.industryCategoryA, theData.industryCategoryB)}</span>
  343. </FormItem>
  344. <div className="clearfix">
  345. <FormItem className="half-item"
  346. {...formItemLayout}
  347. label="需求类型" >
  348. <span>{getDemandType(theData.demandType)}</span>
  349. </FormItem>
  350. </div>
  351. <FormItem
  352. labelCol={{ span: 3 }}
  353. wrapperCol={{ span: 18 }}
  354. label="问题说明" >
  355. <span>{theData.problemDes}</span>
  356. </FormItem>
  357. <FormItem
  358. labelCol={{ span: 3 }}
  359. wrapperCol={{ span: 18 }}
  360. label="技术指标要求" >
  361. <span>{theData.technicalRequirements}</span>
  362. </FormItem>
  363. <FormItem
  364. labelCol={{ span: 3 }}
  365. wrapperCol={{ span: 18 }}
  366. label="需求文件(图片)" >
  367. <div className="clearfix">
  368. <Upload className="demandDetailShow-upload"
  369. listType="picture-card"
  370. fileList={this.state.pictureUrl}
  371. onPreview={(file) => {
  372. this.setState({
  373. previewImage: file.url || file.thumbUrl,
  374. previewVisible: true,
  375. });
  376. }} >
  377. </Upload>
  378. <Modal maskClosable={false} footer={null}
  379. visible={this.state.previewVisible}
  380. onCancel={() => { this.setState({ previewVisible: false }) }}>
  381. <img alt="" style={{ width: '100%' }} src={this.state.previewImage || ''} />
  382. </Modal>
  383. </div>
  384. </FormItem>
  385. <FormItem
  386. labelCol={{ span: 3 }}
  387. wrapperCol={{ span: 6 }}
  388. label="需求文件(文本)" >
  389. <div>{theData.textFileUrl ?
  390. <span className="download-file">
  391. <a onClick={() => { window.open(globalConfig.context + '/api/admin/demand/download?id=' + this.props.data.id) }}>需求文件(文本文件)</a>
  392. </span>
  393. : <span><Icon type="exclamation-circle" style={{ color: '#ffbf00', marginRight: '6px' }} />未上传!</span>}</div>
  394. </FormItem>
  395. <FormItem
  396. labelCol={{ span: 3 }}
  397. wrapperCol={{ span: 18 }}
  398. label="需求文件(视频地址)" >
  399. <span>{theData.videoUrl}</span>
  400. </FormItem>
  401. <div className="clearfix">
  402. <FormItem className="half-item"
  403. {...formItemLayout}
  404. label="固定周期" >
  405. <span>{theData.fixedCycle}</span>
  406. </FormItem>
  407. <FormItem className="half-item"
  408. {...formItemLayout}
  409. label="固定人数" >
  410. <span>{theData.peopleNumber} 人</span>
  411. </FormItem>
  412. </div>
  413. <FormItem
  414. labelCol={{ span: 3 }}
  415. wrapperCol={{ span: 18 }}
  416. label="固定方案" >
  417. <span>{theData.fixedScheme}</span>
  418. </FormItem>
  419. <div className="clearfix">
  420. <FormItem className="half-item"
  421. {...formItemLayout}
  422. label="预算费用" >
  423. <span>{theData.budgetCost} 万元</span>
  424. </FormItem>
  425. <FormItem className="half-item"
  426. {...formItemLayout}
  427. label="费用托管" >
  428. {(() => {
  429. switch (theData.costEscrow) {
  430. case 0:
  431. return <span>否</span>;
  432. case 1:
  433. return <span>是</span>;
  434. }
  435. })()}
  436. </FormItem>
  437. <FormItem className="half-item"
  438. {...formItemLayout}
  439. label="有效期限" >
  440. <span>{theData.validityPeriodFormattedDate}</span>
  441. </FormItem>
  442. </div>
  443. <FormItem wrapperCol={{ span: 12, offset: 3 }}>
  444. <Button className="set-submit" type="primary" onClick={this.props.closeDesc}>取消</Button>
  445. </FormItem>
  446. </Spin>
  447. </Form >
  448. )
  449. }
  450. }));
  451. const DemandDetailForm = Form.create()(React.createClass({
  452. getInitialState() {
  453. return {
  454. visible: false,
  455. loading: false,
  456. auditStatus: 0,
  457. textFileList: [],
  458. videoFileList: [],
  459. pictureUrl: [],
  460. tags: []
  461. };
  462. },
  463. loadData(id) {
  464. this.setState({
  465. loading: true
  466. });
  467. $.ajax({
  468. method: "get",
  469. dataType: "json",
  470. crossDomain: false,
  471. url: globalConfig.context + (window.userData.type == '1' ? '/api/user/demand/orgDemandDetail' : '/api/user/demand/userDemandDetail'),
  472. data: {
  473. id: id
  474. },
  475. success: function (data) {
  476. let thisData = data.data;
  477. if (!thisData) {
  478. if (data.error && data.error.length) {
  479. message.warning(data.error[0].message);
  480. };
  481. thisData = {};
  482. };
  483. this.setState({
  484. data: thisData,
  485. tags: thisData.keyword ? thisData.keyword.split(",") : [],
  486. pictureUrl: thisData.pictureUrl ? splitUrl(thisData.pictureUrl, ',', globalConfig.avatarHost + '/upload') : []
  487. });
  488. }.bind(this),
  489. }).always(function () {
  490. this.setState({
  491. loading: false
  492. });
  493. }.bind(this));
  494. },
  495. getTagsArr(e) {
  496. this.setState({ tags: e });
  497. },
  498. getPictureUrl(e) {
  499. this.setState({ pictureUrl: e });
  500. },
  501. handleSubmit(e) {
  502. e.preventDefault();
  503. this.props.form.validateFields((err, values) => {
  504. //keyword长度判断
  505. if (this.state.tags.length < 3) {
  506. message.warning('关键词数量不能小于3个!');
  507. return;
  508. };
  509. //url转化
  510. let thePictureUrl = [];
  511. if (this.state.pictureUrl.length) {
  512. let picArr = [];
  513. this.state.pictureUrl.map(function (item) {
  514. picArr.push(item.response.data);
  515. });
  516. thePictureUrl = picArr.join(",");
  517. };
  518. if (!err) {
  519. this.setState({
  520. loading: true
  521. });
  522. $.ajax({
  523. method: "POST",
  524. dataType: "json",
  525. crossDomain: false,
  526. url: this.props.data.id ? globalConfig.context + '/api/user/demand/update' : globalConfig.context + '/api/user/demand/apply',
  527. data: {
  528. id: this.props.data.id,
  529. dataCategory: Number(window.userData.type),
  530. serialNumber: this.props.data.serialNumber,
  531. name: values.name,
  532. keyword: this.state.tags ? this.state.tags.join(",") : [],
  533. keywords: this.state.tags,
  534. infoSources: values.infoSources,
  535. industryCategoryA: values.industryCategory ? values.industryCategory[0] : undefined,
  536. industryCategoryB: values.industryCategory ? values.industryCategory[1] : undefined,
  537. demandType: values.demandType,
  538. problemDes: values.problemDes,
  539. technicalRequirements: values.technicalRequirements,
  540. pictureUrl: thePictureUrl,
  541. textFileUrl: this.state.textFileUrl,
  542. videoUrl: values.videoUrl,
  543. fixedBudget: values.fixedBudget,
  544. fixedCycle: values.fixedCycle,
  545. peopleNumber: values.peopleNumber,
  546. fixedScheme: values.fixedScheme,
  547. costEscrow: values.costEscrow,
  548. budgetCost: values.budgetCost,
  549. employerId: values.employerId || this.state.data.employerId,
  550. releaseStatus: values.releaseStatus,
  551. principalId: values.principalId,
  552. validityPeriodFormattedDate: values.validityPeriod ? values.validityPeriod.format('YYYY-MM-DD') : undefined,
  553. //
  554. contacts: values.contacts,
  555. status: this.state.status,
  556. auditStatus: this.state.auditStatus
  557. }
  558. }).done(function (data) {
  559. this.state.auditStatus = 0;
  560. if (!data.error.length) {
  561. message.success('保存成功!');
  562. this.setState({
  563. visible: false
  564. });
  565. this.props.handleOk();
  566. } else {
  567. message.warning(data.error[0].message);
  568. }
  569. }.bind(this));
  570. }
  571. });
  572. },
  573. componentWillMount() {
  574. if (this.props.data.id) {
  575. this.loadData(this.props.data.id);
  576. } else {
  577. this.state.data = {};
  578. };
  579. },
  580. componentWillReceiveProps(nextProps) {
  581. if (!this.props.visible && nextProps.visible) {
  582. this.state.textFileList = [];
  583. this.state.videoFileList = [];
  584. if (nextProps.data.id) {
  585. this.loadData(nextProps.data.id);
  586. } else {
  587. this.state.data = {};
  588. this.state.tags = [];
  589. this.state.pictureUrl = [];
  590. };
  591. this.props.form.resetFields();
  592. };
  593. },
  594. render() {
  595. const theData = this.state.data || {};
  596. const { getFieldDecorator } = this.props.form;
  597. const FormItem = Form.Item
  598. const formItemLayout = {
  599. labelCol: { span: 6 },
  600. wrapperCol: { span: 12 },
  601. };
  602. return (
  603. <Form horizontal onSubmit={this.handleSubmit} id="demand-form">
  604. <Spin spinning={this.state.loading}>
  605. <div className="clearfix">
  606. <FormItem className="half-item"
  607. {...formItemLayout}
  608. label="编号" >
  609. <span>{theData.serialNumber}</span>
  610. </FormItem>
  611. <FormItem className="half-item"
  612. {...formItemLayout}
  613. label="需求名称" >
  614. {getFieldDecorator('name', {
  615. rules: [{ required: true, message: '此项为必填项!' }],
  616. initialValue: theData.name
  617. })(
  618. <Input />
  619. )}
  620. </FormItem>
  621. {theData.username ? <FormItem className="half-item"
  622. {...formItemLayout}
  623. label="雇主名称" >
  624. <span>{theData.username}</span>
  625. </FormItem> : <div></div>}
  626. {window.userData.type == "1" ? <FormItem className="half-item"
  627. {...formItemLayout}
  628. label="联系人" >
  629. {getFieldDecorator('contacts', {
  630. initialValue: theData.contacts
  631. })(
  632. <Select style={{ width: 260 }}
  633. placeholder="请选择联系人"
  634. notFoundContent="未获取到联系人列表"
  635. showSearch
  636. filterOption={companySearch}>
  637. {this.props.contactsOption}
  638. </Select>
  639. )}
  640. </FormItem> : <div></div>}
  641. {window.userData.type == "0" ? <FormItem className="half-item"
  642. {...formItemLayout}
  643. label="联系方式" >
  644. <span>{theData.mobile}</span>
  645. </FormItem> : <div></div>}
  646. </div>
  647. {theData.releaseStatus ? <div className="clearfix">
  648. <FormItem className="half-item"
  649. {...formItemLayout}
  650. label="是否发布" >
  651. {(() => {
  652. switch (theData.releaseStatus) {
  653. case "0":
  654. return <span>未发布</span>;
  655. case "1":
  656. return <span>已发布</span>;
  657. }
  658. })()}
  659. </FormItem>
  660. <FormItem className="half-item"
  661. {...formItemLayout}
  662. label="发布时间" >
  663. <span>{theData.releaseDateFormattedDate}</span>
  664. </FormItem>
  665. </div> : <div></div>}
  666. <div className="clearfix">
  667. {theData.releaseStatus == "1" ? <FormItem className="half-item"
  668. {...formItemLayout}
  669. label="需求状态" >
  670. {getFieldDecorator('status', {
  671. initialValue: theData.status
  672. })(
  673. <Radio.Group>
  674. <Radio value="0">未解决</Radio>
  675. <Radio value="1">已解决</Radio>
  676. </Radio.Group>
  677. )}
  678. </FormItem> : <div></div>}
  679. <FormItem className="half-item"
  680. {...formItemLayout}
  681. label="审核状态" >
  682. {(() => {
  683. switch (theData.auditStatus) {
  684. case "0":
  685. return <span>未提交审核(草稿)</span>;
  686. case "1":
  687. return <span>提交审核</span>;
  688. case "2":
  689. return <span>审核中</span>;
  690. case "3":
  691. return <span>审核通过</span>;
  692. case "4":
  693. return <span>审核未通过</span>;
  694. }
  695. })()}
  696. </FormItem>
  697. </div>
  698. <div className="clearfix">
  699. <FormItem className="half-item"
  700. {...formItemLayout}
  701. label="信息来源" >
  702. {getFieldDecorator('infoSources', {
  703. rules: [{ required: true, message: '此项为必填项!' }],
  704. initialValue: theData.infoSources
  705. })(
  706. <Radio.Group>
  707. <Radio value="0">平台采集</Radio>
  708. <Radio value="1">客户发布</Radio>
  709. </Radio.Group>
  710. )}
  711. </FormItem>
  712. </div>
  713. <FormItem
  714. labelCol={{ span: 3 }}
  715. wrapperCol={{ span: 20 }}
  716. label="关键词" >
  717. <KeyWordTagGroup
  718. keyWordArr={this.state.tags}
  719. tagsArr={this.getTagsArr}
  720. visible={this.props.visible} />
  721. </FormItem>
  722. <FormItem
  723. labelCol={{ span: 3 }}
  724. wrapperCol={{ span: 18 }}
  725. label="行业类别" >
  726. {getFieldDecorator('industryCategory', {
  727. rules: [{ type: 'array', required: true, message: '此项为必填项!' }],
  728. initialValue: [theData.industryCategoryA, theData.industryCategoryB]
  729. })(
  730. <Cascader style={{ width: 300 }} options={IndustryObject} placeholder="请选择一个行业" />
  731. )}
  732. </FormItem>
  733. <div className="clearfix">
  734. <FormItem className="half-item"
  735. {...formItemLayout}
  736. label="需求类型" >
  737. {getFieldDecorator('demandType', {
  738. rules: [{ required: true, message: '此项为必填项!' }],
  739. initialValue: theData.demandType
  740. })(
  741. <Select style={{ width: 160 }} placeholder="请选择需求类型">
  742. {this.props.demandTypeOption}
  743. </Select>
  744. )}
  745. </FormItem>
  746. </div>
  747. <FormItem
  748. labelCol={{ span: 3 }}
  749. wrapperCol={{ span: 18 }}
  750. label="问题说明" >
  751. {getFieldDecorator('problemDes', {
  752. rules: [{ required: true, message: '此项为必填项!' }],
  753. initialValue: theData.problemDes
  754. })(
  755. <Input type="textarea" rows={4} />
  756. )}
  757. </FormItem>
  758. <FormItem
  759. labelCol={{ span: 3 }}
  760. wrapperCol={{ span: 18 }}
  761. label="技术指标要求" >
  762. {getFieldDecorator('technicalRequirements', {
  763. initialValue: theData.technicalRequirements
  764. })(
  765. <Input type="textarea" rows={2} />
  766. )}
  767. </FormItem>
  768. <FormItem
  769. labelCol={{ span: 3 }}
  770. wrapperCol={{ span: 18 }}
  771. label="需求文件(图片)" >
  772. <PicturesWall
  773. uid={theData.employerId}
  774. fileList={this.getPictureUrl}
  775. pictureUrl={this.state.pictureUrl}
  776. visible={this.props.visible} />
  777. </FormItem>
  778. <FormItem
  779. labelCol={{ span: 3 }}
  780. wrapperCol={{ span: 6 }}
  781. label="需求文件(文本)" >
  782. <Upload
  783. name="ratepay"
  784. action={globalConfig.context + "/api/admin/demand/uploadTextFile"}
  785. data={{ 'sign': 'demand_text_file', 'uid': theData.employerId }}
  786. beforeUpload={beforeUploadFile}
  787. fileList={this.state.textFileList}
  788. onChange={(info) => {
  789. if (info.file.status !== 'uploading') {
  790. console.log(info.file, info.fileList);
  791. }
  792. if (info.file.status === 'done') {
  793. if (!info.file.response.error.length) {
  794. message.success(`${info.file.name} 文件上传成功!`);
  795. } else {
  796. message.warning(info.file.response.error[0].message);
  797. return;
  798. };
  799. this.state.textFileUrl = info.file.response.data;
  800. } else if (info.file.status === 'error') {
  801. message.error(`${info.file.name} 文件上传失败。`);
  802. };
  803. this.setState({ textFileList: info.fileList.slice(-1) });
  804. }} >
  805. <Button><Icon type="upload" /> 上传需求文本文件 </Button>
  806. </Upload>
  807. <p style={{ marginTop: '10px' }}>{theData.textFileUrl ?
  808. <span className="download-file">
  809. <a onClick={() => { window.open(globalConfig.context + '/api/admin/demand/download?id=' + this.props.data.id) }}>需求文件(文本文件)</a>
  810. </span>
  811. : <span><Icon type="exclamation-circle" style={{ color: '#ffbf00', marginRight: '6px' }} />未上传!</span>}</p>
  812. </FormItem>
  813. <FormItem
  814. labelCol={{ span: 3 }}
  815. wrapperCol={{ span: 18 }}
  816. label="需求文件(视频地址)" >
  817. {getFieldDecorator('videoUrl', {
  818. initialValue: theData.videoUrl
  819. })(
  820. <Input />
  821. )}
  822. </FormItem>
  823. <div className="clearfix">
  824. <FormItem className="half-item"
  825. {...formItemLayout}
  826. label="固定周期" >
  827. {getFieldDecorator('fixedCycle', {
  828. initialValue: theData.fixedCycle
  829. })(
  830. <Input />
  831. )}
  832. </FormItem>
  833. <FormItem className="half-item"
  834. {...formItemLayout}
  835. label="固定人数" >
  836. {getFieldDecorator('peopleNumber', {
  837. initialValue: theData.peopleNumber
  838. })(
  839. <InputNumber />
  840. )}
  841. <span style={{ marginLeft: '20px' }}>人</span>
  842. </FormItem>
  843. </div>
  844. <FormItem
  845. labelCol={{ span: 3 }}
  846. wrapperCol={{ span: 18 }}
  847. label="固定方案" >
  848. {getFieldDecorator('fixedScheme', {
  849. initialValue: theData.fixedScheme
  850. })(
  851. <Input type="textarea" rows={2} />
  852. )}
  853. </FormItem>
  854. <div className="clearfix">
  855. <FormItem className="half-item"
  856. {...formItemLayout}
  857. label="预算费用" >
  858. {getFieldDecorator('budgetCost', {
  859. initialValue: theData.budgetCost
  860. })(
  861. <InputNumber />
  862. )}
  863. <span style={{ marginLeft: '20px' }}>万元</span>
  864. </FormItem>
  865. <FormItem className="half-item"
  866. {...formItemLayout}
  867. label="费用托管" >
  868. {getFieldDecorator('costEscrow', {
  869. initialValue: theData.costEscrow
  870. })(
  871. <Radio.Group>
  872. <Radio value={0}>否</Radio>
  873. <Radio value={1}>是</Radio>
  874. </Radio.Group>
  875. )}
  876. </FormItem>
  877. <FormItem className="half-item"
  878. {...formItemLayout}
  879. label="有效期限" >
  880. {getFieldDecorator('validityPeriod', {
  881. initialValue: theData.validityPeriod ? moment(theData.validityPeriod) : null
  882. })(
  883. <DatePicker />
  884. )}
  885. </FormItem>
  886. </div>
  887. <div className="clearfix" style={{ display: 'none' }}>
  888. <FormItem className="half-item"
  889. {...formItemLayout}
  890. label="雇主地址" >
  891. <span>{theData.employerAddress}</span>
  892. </FormItem>
  893. <FormItem className="half-item"
  894. {...formItemLayout}
  895. label="雇主联系人名称" >
  896. <span>{theData.employerContacts}</span>
  897. </FormItem>
  898. <FormItem className="half-item"
  899. {...formItemLayout}
  900. label="雇主联系人电话" >
  901. <span>{theData.employerContactsMobile}</span>
  902. </FormItem>
  903. <FormItem className="half-item"
  904. {...formItemLayout}
  905. label="雇主联系人邮箱" >
  906. <span>{theData.employerContactsMailbox}</span>
  907. </FormItem>
  908. </div>
  909. <FormItem wrapperCol={{ span: 12, offset: 3 }}>
  910. <Button className="set-submit" type="primary" htmlType="submit">保存</Button>
  911. <Button className="set-submit" type="ghost" onClick={(e) => { this.state.auditStatus = 1; }} htmlType="submit">发布</Button>
  912. <Button className="set-submit" type="ghost" onClick={this.props.closeDesc}>取消</Button>
  913. </FormItem>
  914. </Spin>
  915. </Form >
  916. )
  917. }
  918. }));
  919. const DemandDetail = React.createClass({
  920. getInitialState() {
  921. return {
  922. visible: false,
  923. contactsObj: {}
  924. };
  925. },
  926. getContactsList() {
  927. $.ajax({
  928. method: "get",
  929. dataType: "json",
  930. crossDomain: false,
  931. url: globalConfig.context + "/api/user/cognizance/getContacts",
  932. success: function (data) {
  933. let theOption = [];
  934. if (!data.data) {
  935. if (data.error && data.error.length) {
  936. message.warning(data.error[0].message);
  937. };
  938. } else {
  939. for (let item in data.data) {
  940. let theData = data.data[item];
  941. theOption.push(
  942. <Select.Option value={item} key={theData}>{theData}</Select.Option>
  943. );
  944. };
  945. };
  946. this.setState({
  947. contactsOption: theOption,
  948. contactsObj: data.data || {}
  949. });
  950. }.bind(this),
  951. });
  952. },
  953. showModal() {
  954. this.setState({
  955. visible: true,
  956. });
  957. },
  958. handleCancel(e) {
  959. this.setState({
  960. visible: false,
  961. });
  962. this.props.closeDesc(false);
  963. },
  964. handleOk(e) {
  965. this.setState({
  966. visible: false,
  967. });
  968. this.props.closeDesc(false, true);
  969. },
  970. componentWillMount() {
  971. this.getContactsList();
  972. },
  973. componentWillReceiveProps(nextProps) {
  974. this.state.visible = nextProps.showDesc;
  975. },
  976. render() {
  977. if (this.props.data) {
  978. return (
  979. <div className="patent-desc">
  980. <Modal maskClosable={false} title="用户需求详情" visible={this.state.visible}
  981. onOk={this.checkPatentProcess} onCancel={this.handleCancel}
  982. width='1000px'
  983. footer=''
  984. className="admin-desc-content">
  985. {(() => {
  986. if (this.props.data.auditStatus && this.props.data.auditStatus != "0" && this.props.data.auditStatus != "4") {
  987. return <DemandDetailShow
  988. data={this.props.data}
  989. demandTypeOption={this.props.demandTypeOption}
  990. contactsObj={this.state.contactsObj}
  991. closeDesc={this.handleCancel}
  992. visible={this.state.visible}
  993. handleOk={this.handleOk} />
  994. } else {
  995. return <DemandDetailForm
  996. data={this.props.data}
  997. contactsOption={this.state.contactsOption}
  998. demandTypeOption={this.props.demandTypeOption}
  999. closeDesc={this.handleCancel}
  1000. visible={this.state.visible}
  1001. handleOk={this.handleOk} />
  1002. }
  1003. })()}
  1004. </Modal>
  1005. </div>
  1006. );
  1007. } else {
  1008. return <div></div>
  1009. }
  1010. },
  1011. });
  1012. export default DemandDetail;