techDemandDesc.jsx 50 KB

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