businessForm.jsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. import React from 'react';
  2. import $ from 'jquery/src/ajax';
  3. import {
  4. Icon,
  5. Tooltip,
  6. Modal,
  7. message,
  8. Spin,
  9. Upload,
  10. Input,
  11. Select,
  12. Button,
  13. Radio,
  14. Form,
  15. Cascader,
  16. Tag,
  17. InputNumber
  18. } from 'antd';
  19. import { citySelect } from '@/NewDicProvinceListAll';
  20. import { splitUrl ,getReleaseStateList} from '@/tools.js';
  21. //tag组件
  22. const KeyWordTagGroup = React.createClass({
  23. getInitialState() {
  24. return {
  25. tags: [],
  26. inputVisible: false,
  27. inputValue: ''
  28. };
  29. },
  30. handleClose(removedTag) {
  31. const tags = this.state.tags.filter(tag => tag !== removedTag);
  32. this.props.tagsArr(tags);
  33. this.setState({ tags });
  34. },
  35. showInput() {
  36. this.setState({ inputVisible: true }, () => this.input.focus());
  37. },
  38. handleInputChange(e) {
  39. this.setState({ inputValue: e.target.value });
  40. },
  41. handleInputConfirm() {
  42. const state = this.state;
  43. const inputValue = state.inputValue;
  44. let tags = state.tags;
  45. if (inputValue && tags.indexOf(inputValue) === -1 && inputValue.replace(/(^\s*)|(\s*$)/g, "").length != 0) {
  46. tags = [...tags, inputValue.replace(/(^\s*)|(\s*$)/g, "")];
  47. }
  48. this.props.tagsArr(tags);
  49. this.setState({
  50. tags,
  51. inputVisible: false,
  52. inputValue: '',
  53. });
  54. },
  55. componentWillMount() {
  56. this.state.tags = this.props.keyWordArr;
  57. },
  58. componentWillReceiveProps(nextProps) {
  59. if (this.props.keyWordArr != nextProps.keyWordArr) {
  60. this.state.tags = nextProps.keyWordArr;
  61. };
  62. },
  63. render() {
  64. const { tags, inputVisible, inputValue } = this.state;
  65. return (
  66. <div className="keyWord-tips">
  67. {tags.map((tag, index) => {
  68. const isLongTag = tag.length > 10;
  69. const tagElem = (
  70. <Tag key={tag} closable={index !== -1} afterClose={() => this.handleClose(tag)}>
  71. {isLongTag ? `${tag.slice(0, 10)}...` : tag}
  72. </Tag>
  73. );
  74. return isLongTag ? <Tooltip title={tag}>{tagElem}</Tooltip> : tagElem;
  75. })}
  76. {inputVisible && (
  77. <Input
  78. ref={input => this.input = input}
  79. type="text"
  80. style={{ width: 78 }}
  81. value={inputValue}
  82. onChange={this.handleInputChange}
  83. onBlur={this.handleInputConfirm}
  84. onPressEnter={this.handleInputConfirm}
  85. />
  86. )}
  87. {!inputVisible && <Button className="addtips" type="dashed" disabled={tags.length > 9 ? true : false} onClick={this.showInput}>+ 新标签</Button>}
  88. </div>
  89. );
  90. }
  91. });
  92. //图片组件
  93. const PicturesWall = React.createClass({
  94. getInitialState() {
  95. return {
  96. previewVisible: false,
  97. previewImage: '',
  98. fileList: []
  99. };
  100. },
  101. handleCancel() {
  102. this.setState({ previewVisible: false });
  103. },
  104. handlePreview(file) {
  105. this.setState({
  106. previewImage: file.url || file.thumbUrl,
  107. previewVisible: true
  108. });
  109. },
  110. handleChange(info) {
  111. let fileList = info.fileList;
  112. this.setState({ fileList });
  113. this.props.fileList(fileList);
  114. },
  115. componentWillReceiveProps(nextProps) {
  116. this.state.fileList = nextProps.pictureUrl;
  117. },
  118. render() {
  119. const { previewVisible, previewImage, fileList } = this.state;
  120. const uploadButton = (
  121. <div>
  122. <Icon type="plus" />
  123. <div className="ant-upload-text">点击上传</div>
  124. </div>
  125. );
  126. return (
  127. <div style={{ display: 'inline-block' }}>
  128. <Upload
  129. action={globalConfig.context + '/api/user/jtBusiness/project/uploadPicture'}
  130. data={{ sign: 'jt_project_picture' }}
  131. listType="picture-card"
  132. fileList={fileList}
  133. onPreview={this.handlePreview}
  134. onChange={this.handleChange}
  135. >
  136. {fileList.length >= 1 ? null : uploadButton}
  137. </Upload>
  138. <Modal maskClosable={false} visible={previewVisible} footer={null} onCancel={this.handleCancel}>
  139. <img alt="example" style={{ width: '100%' }} src={previewImage} />
  140. </Modal>
  141. </div>
  142. );
  143. }
  144. });
  145. const DemandDetailForm = Form.create()(
  146. React.createClass({
  147. getInitialState() {
  148. return {
  149. visible: false,
  150. loading: false,
  151. auditStatus: 0,
  152. textFileList: [],
  153. videoFileList: [],
  154. pictureUrl: [],
  155. orgCodeUrl: [],
  156. companyLogoUrl: [],
  157. tags: []
  158. };
  159. },
  160. //左侧图片地址
  161. getOrgCodeUrl(e) {
  162. this.setState({ orgCodeUrl: e });
  163. },
  164. //右侧图片地址
  165. getCompanyLogoUrl(e) {
  166. this.setState({ companyLogoUrl: e });
  167. },
  168. //编辑部门,保存
  169. handleSubmit(e,index) {
  170. e.preventDefault();
  171. if (!this.state.name) {
  172. message.warning('请输入项目名称');
  173. return;
  174. }
  175. if ((this.state.name).length>16) {
  176. message.warning('项目名称在16个字以内');
  177. return false;
  178. };
  179. if (!this.state.categoryId||!this.state.categoryId[1]) {
  180. message.warning('请选择项目二级业务品类');
  181. return;
  182. }
  183. if (!this.state.ProvinceCity.length) {
  184. message.warning('请选择省份');
  185. return;
  186. }
  187. if (!this.state.price) {
  188. message.warning('请输入正确的市场价');
  189. return;
  190. }
  191. if(this.state.advertisement&&(this.state.advertisement).length>30){
  192. message.warning('项目营销说明字数不得超过30个字。');
  193. return;
  194. }
  195. this.setState({
  196. loading: true
  197. });
  198. let minPictureUrl = [];
  199. if (this.state.orgCodeUrl.length) {
  200. let picArr = [];
  201. this.state.orgCodeUrl.map(function(item) {
  202. if (item.response && item.response.data && item.response.data.length) {
  203. picArr.push(item.response.data);
  204. }
  205. });
  206. minPictureUrl = picArr.join(',');
  207. }
  208. let maxPictureUrl = [];
  209. if (this.state.companyLogoUrl.length) {
  210. let picArr = [];
  211. this.state.companyLogoUrl.map(function(item) {
  212. if (item.response && item.response.data && item.response.data.length) {
  213. picArr.push(item.response.data);
  214. }
  215. });
  216. maxPictureUrl = picArr.join(',');
  217. }
  218. $.ajax({
  219. method: 'post',
  220. dataType: 'json',
  221. crossDomain: false,
  222. url: globalConfig.context + '/api/user/jtBusiness/project/update',
  223. data: {
  224. auditStatus:index,
  225. id: this.state.id, //业务名称
  226. name: this.state.name, //业务名称
  227. categoryId: this.state.categoryId[1], //业务品类
  228. price: this.state.price, //市场价
  229. advertisement:this.state.advertisement,//项目营销说明
  230. activityPrice: this.state.activityPrice ? this.state.activityPrice : '0', //最低折扣
  231. memberPrice: this.state.memberPrice ? this.state.memberPrice : '0', //会员价
  232. offset: this.state.offset ? this.state.offset : '0',
  233. activityFlag: this.state.activityFlag, //活动生效标识
  234. province: this.state.ProvinceCity ? this.state.ProvinceCity[0] : '', //是否全国
  235. city: this.state.ProvinceCity ? this.state.ProvinceCity[1] : '',
  236. introduce: this.state.introduce,
  237. value: this.state.value,
  238. tag:this.state.tags?this.state.tags.join(','):'',
  239. isHot: this.state.isHot,
  240. minImgUrl: minPictureUrl.length ? minPictureUrl : '',
  241. maxImgUrl: maxPictureUrl.length ? maxPictureUrl : '',
  242. applyConditions: this.state.applyConditions
  243. }
  244. }).done(
  245. function(data) {
  246. if (!data.error.length) {
  247. message.success('保存成功!');
  248. this.setState({
  249. loading: false,
  250. editvisible: false
  251. });
  252. } else {
  253. message.warning(data.error[0].message);
  254. }
  255. this.props.handOk();
  256. }.bind(this)
  257. );
  258. },
  259. loadData(ids) {
  260. $.ajax({
  261. method: 'get',
  262. dataType: 'json',
  263. crossDomain: false,
  264. url: globalConfig.context + '/api/user/jtBusiness/project/detail',
  265. data: {
  266. id: ids
  267. },
  268. success: function(data) {
  269. if (!data.data) {
  270. if (data.error && data.error.length) {
  271. message.warning(data.error[0].message);
  272. }
  273. } else {
  274. let categoryIdArr=[];
  275. let thisdata = data.data;
  276. let ProvinceCityArr = [];
  277. ProvinceCityArr.push(thisdata.province, thisdata.city);
  278. (this.props.categoryList).map(item=>{
  279. if(item.children.length){
  280. (item.children).map(atem=>{
  281. if(atem.value==thisdata.categoryId){
  282. categoryIdArr.push(item.value,atem.value)
  283. }
  284. })
  285. }
  286. })
  287. this.setState({
  288. id: thisdata.id, //业务名称
  289. name: thisdata.name, //业务名称
  290. tags:thisdata.tag?thisdata.tag.split(','):[],
  291. categoryId: categoryIdArr, //业务品类
  292. number: thisdata.number,
  293. auditInfo:thisdata.auditInfo,
  294. price: thisdata.price, //市场价
  295. activityPrice: thisdata.activityPrice ? thisdata.activityPrice : '', //最低折扣
  296. memberPrice: thisdata.memberPrice ? thisdata.memberPrice : '', //会员价
  297. offset: thisdata.offset ? thisdata.offset : '',
  298. activityFlag: thisdata.activityFlag ? thisdata.activityFlag.toString() : '', //活动生效标识
  299. ProvinceCity: ProvinceCityArr,
  300. introduce: thisdata.introduce,
  301. createTime: thisdata.createTime ? new Date(thisdata.createTime).toLocaleString() : '',
  302. value: thisdata.value,
  303. isHot:thisdata.isHot,
  304. auditStatus:thisdata.auditStatus,
  305. applyConditions: thisdata.applyConditions,
  306. orgCodeUrl: thisdata.minImgUrl
  307. ? splitUrl(thisdata.minImgUrl, ',', globalConfig.avatarHost + '/upload')
  308. : [],
  309. companyLogoUrl: thisdata.maxImgUrl
  310. ? splitUrl(thisdata.maxImgUrl, ',', globalConfig.avatarHost + '/upload')
  311. : []
  312. });
  313. }
  314. }.bind(this)
  315. }).always(
  316. function() {
  317. this.setState({
  318. loading: false
  319. });
  320. }.bind(this)
  321. );
  322. },
  323. submission(e, index) {
  324. this.handleSubmit(e, index);
  325. $.ajax({
  326. method: 'get',
  327. dataType: 'json',
  328. crossDomain: false,
  329. async: true,
  330. url: globalConfig.context + '/api/user/jtBusiness/project/publish',
  331. data: {
  332. id: this.state.id,
  333. auditStatus:1
  334. }
  335. }).done(
  336. function(data) {
  337. if (!data.error.length) {
  338. this.setState({
  339. loading: false
  340. });
  341. } else {
  342. message.warning(data.error[0].message);
  343. }
  344. }.bind(this)
  345. );
  346. },
  347. cancelFun() {
  348. this.props.closeDesc();
  349. },
  350. componentWillMount() {
  351. if (this.props.data.id) {
  352. this.loadData(this.props.data.id);
  353. }
  354. },
  355. componentWillReceiveProps(nextProps) {
  356. if (!this.props.visible && nextProps.visible) {
  357. this.state.textFileList = [];
  358. this.state.videoFileList = [];
  359. if (nextProps.data.id) {
  360. this.loadData(nextProps.data.id);
  361. }
  362. }
  363. },
  364. render() {
  365. const FormItem = Form.Item;
  366. let categoryList = this.props.categoryList||[];
  367. return (
  368. <div className="patent-desc">
  369. <Form layout="horizontal" onSubmit={(e)=>{this.handleSubmit(e,0)}} id="demand-form">
  370. <Spin spinning={this.state.loading}>
  371. <div className="clearfix" style={{ paddingLeft: '86px' }}>
  372. <FormItem
  373. className="half-item"
  374. labelCol={{ span: 4 }}
  375. wrapperCol={{ span: 12 }}
  376. label={
  377. <span>
  378. <strong style={{ color: 'red' }}>*</strong>项目名称
  379. </span>
  380. }
  381. >
  382. <Input
  383. placeholder="项目名称"
  384. value={this.state.name}
  385. onChange={(e) => {
  386. this.setState({ name: e.target.value });
  387. }}
  388. />
  389. </FormItem>
  390. <FormItem
  391. className="half-item"
  392. labelCol={{ span: 4 }}
  393. wrapperCol={{ span: 12 }}
  394. label={
  395. <span>
  396. <strong style={{ color: 'red' }}>*</strong>业务品类
  397. </span>
  398. }
  399. >
  400. <Cascader
  401. options={categoryList}
  402. value={this.state.categoryId}
  403. placeholder="业务品类"
  404. onChange={(e, pre) => {
  405. this.setState({ categoryId: e });
  406. }}
  407. />
  408. </FormItem>
  409. </div>
  410. <div className="clearfix" style={{ paddingLeft: '86px' }}>
  411. <FormItem
  412. className="half-item"
  413. labelCol={{ span: 4 }}
  414. wrapperCol={{ span: 12 }}
  415. label={
  416. <span>
  417. <strong style={{ color: 'red' }}>*</strong>省-市
  418. </span>
  419. }
  420. >
  421. <Cascader
  422. options={citySelect()}
  423. value={this.state.ProvinceCity}
  424. placeholder="选择市"
  425. onChange={(e, pre) => {
  426. this.setState({ ProvinceCity: e });
  427. }}
  428. />
  429. </FormItem>
  430. <FormItem
  431. className="half-item"
  432. labelCol={{ span: 4 }}
  433. wrapperCol={{ span: 12 }}
  434. label={
  435. <span>
  436. <strong style={{ color: 'red' }}>*</strong>热点
  437. </span>
  438. }
  439. >
  440. <Radio.Group
  441. onChange={(e) => {
  442. this.setState({ isHot: e.target.value });
  443. }}
  444. value={this.state.isHot}
  445. >
  446. <Radio value={0}>否</Radio>
  447. <Radio value={1}>是</Radio>
  448. </Radio.Group>
  449. </FormItem>
  450. </div>
  451. <div className="clearfix" style={{ paddingLeft: '86px' }}>
  452. <FormItem
  453. className="half-item"
  454. labelCol={{ span: 4 }}
  455. wrapperCol={{ span: 12 }}
  456. label={
  457. <span>
  458. <strong style={{ color: 'red' }}>*</strong>市场价
  459. </span>
  460. }
  461. >
  462. <InputNumber
  463. placeholder="市场价"
  464. value={this.state.price}
  465. style={{ width: 120 }}
  466. onChange={(e) => {
  467. this.setState({ price: e });
  468. }}
  469. required="required"
  470. />
  471. <span style={{ marginLeft: 10 }}>万元</span>
  472. </FormItem>
  473. <FormItem
  474. className="half-item"
  475. labelCol={{ span: 4 }}
  476. wrapperCol={{ span: 12 }}
  477. label="活动价"
  478. >
  479. <InputNumber
  480. placeholder="活动价"
  481. value={this.state.activityPrice}
  482. style={{ width: 120 }}
  483. onChange={(e) => {
  484. this.setState({ activityPrice: e });
  485. }}
  486. min={0}
  487. max={999999}
  488. step={0.01}
  489. />
  490. <span style={{ marginLeft: 10 }}>万元</span>
  491. </FormItem>
  492. <FormItem
  493. className="half-item"
  494. labelCol={{ span: 4 }}
  495. wrapperCol={{ span: 12 }}
  496. label="最低折扣"
  497. >
  498. <InputNumber
  499. placeholder="最低折扣(如:0.5)"
  500. value={this.state.offset}
  501. style={{ width: '50%' }}
  502. onChange={(e) => {
  503. this.setState({ offset: e });
  504. }}
  505. min={0}
  506. max={1}
  507. step={0.01}
  508. />
  509. </FormItem>
  510. <FormItem
  511. className="half-item"
  512. labelCol={{ span: 4 }}
  513. wrapperCol={{ span: 12 }}
  514. label="会员价"
  515. >
  516. <InputNumber
  517. placeholder="会员价"
  518. value={this.state.memberPrice}
  519. style={{ width: '120px' }}
  520. onChange={(e) => {
  521. this.setState({ memberPrice: e });
  522. }}
  523. min={0}
  524. max={999999}
  525. step={0.01}
  526. />
  527. <span style={{ marginLeft: 10 }}>万元</span>
  528. </FormItem>
  529. <FormItem
  530. className="half-item"
  531. labelCol={{ span: 4 }}
  532. wrapperCol={{ span: 12 }}
  533. label="活动生效"
  534. >
  535. <Select
  536. placeholder="活动生效"
  537. value={this.state.activityFlag}
  538. style={{ width: '94%' }}
  539. onChange={(e) => {
  540. this.setState({ activityFlag: e });
  541. }}
  542. >
  543. <Select.Option key="0">无效</Select.Option>
  544. <Select.Option key="1">有效</Select.Option>
  545. </Select>
  546. </FormItem>
  547. <FormItem
  548. className="half-item"
  549. labelCol={{ span: 4 }}
  550. wrapperCol={{ span: 12 }}
  551. label="创建时间"
  552. >
  553. <span style={{ width: '94%' }}>{this.state.createTime}</span>
  554. </FormItem>
  555. </div>
  556. <div className="clearfix">
  557. <FormItem
  558. labelCol={{ span: 4 }}
  559. wrapperCol={{ span: 18 }}
  560. label={<span><span></span>标签</span>} >
  561. <KeyWordTagGroup
  562. keyWordArr={this.state.tags}
  563. tagsArr={(e)=>{this.setState({tags:e})}}
  564. />
  565. </FormItem>
  566. </div>
  567. <div>
  568. <FormItem
  569. labelCol={{ span: 4 }}
  570. wrapperCol={{ span: 12 }}
  571. label="发布状态">
  572. <span>{getReleaseStateList(this.state.auditStatus)}</span>
  573. </FormItem>
  574. </div>
  575. <div className="clearfix">
  576. {this.state.auditInfo?<FormItem
  577. labelCol={{ span: 4 }}
  578. wrapperCol={{ span: 12 }}
  579. label="拒绝原因">
  580. <span>{this.state.auditInfo}</span>
  581. </FormItem>:''}
  582. </div>
  583. <div className="clearfix">
  584. <FormItem labelCol={{ span: 4 }} wrapperCol={{ span: 12 }} label="业务项目服务内容">
  585. <Input
  586. type="textarea"
  587. rows={4}
  588. placeholder="业务项目服务内容"
  589. value={this.state.introduce}
  590. onChange={(e) => {
  591. this.setState({ introduce: e.target.value });
  592. }}
  593. />
  594. </FormItem>
  595. </div>
  596. <div className="clearfix">
  597. <FormItem labelCol={{ span: 4 }} wrapperCol={{ span: 12 }} label="项目营销说明">
  598. <Input
  599. type="textarea"
  600. rows={4}
  601. placeholder="项目营销说明"
  602. value={this.state.advertisement}
  603. onChange={(e) => {
  604. this.setState({ advertisement: e.target.value });
  605. }}
  606. />
  607. </FormItem>
  608. </div>
  609. <div className="clearfix">
  610. <FormItem labelCol={{ span: 4 }} wrapperCol={{ span: 12 }} label="业务项目价值及作用">
  611. <Input
  612. type="textarea"
  613. rows={4}
  614. placeholder="业务项目价值及作用"
  615. value={this.state.value}
  616. onChange={(e) => {
  617. this.setState({ value: e.target.value });
  618. }}
  619. />
  620. </FormItem>
  621. </div>
  622. <div className="clearfix">
  623. <FormItem labelCol={{ span: 4 }} wrapperCol={{ span: 12 }} label="业务项目客户基本条件">
  624. <Input
  625. type="textarea"
  626. rows={4}
  627. placeholder="业务项目客户基本条件"
  628. value={this.state.applyConditions}
  629. onChange={(e) => {
  630. this.setState({ applyConditions: e.target.value });
  631. }}
  632. />
  633. </FormItem>
  634. </div>
  635. <div className="clearfix pictures">
  636. <FormItem
  637. className="half-item"
  638. labelCol={{ span: 8 }}
  639. wrapperCol={{ span: 10 }}
  640. label="业务项目图标(小)"
  641. >
  642. <PicturesWall
  643. pictureSign="business_project_min_picture"
  644. fileList={this.getOrgCodeUrl}
  645. pictureUrl={this.state.orgCodeUrl}
  646. />
  647. <p>图片建议:图片要清晰。(72*72)</p>
  648. </FormItem>
  649. <FormItem
  650. className="half-item"
  651. labelCol={{ span: 8 }}
  652. wrapperCol={{ span: 12 }}
  653. label="业务项目图标(大)"
  654. >
  655. <PicturesWall
  656. pictureSign="business_project_max_picture"
  657. fileList={this.getCompanyLogoUrl}
  658. pictureUrl={this.state.companyLogoUrl}
  659. />
  660. <p>图片建议:图片要清晰。(330*230)</p>
  661. </FormItem>
  662. </div>
  663. <Button
  664. className="set-submit"
  665. type="primary"
  666. htmlType="submit"
  667. style={{ marginLeft: '160px', marginBottom: '20px', marginTop: '20px' }}
  668. >
  669. 保存
  670. </Button>
  671. <Button
  672. className="set-submit"
  673. type="ghost"
  674. onClick={(e) => {
  675. this.submission(e,1)
  676. }}
  677. >
  678. 提交审核
  679. </Button>
  680. <Button
  681. className="set-submit"
  682. type="ghost"
  683. onClick={this.cancelFun}
  684. >
  685. 取消
  686. </Button>
  687. </Spin>
  688. </Form>
  689. </div>
  690. );
  691. }
  692. })
  693. );
  694. export default DemandDetailForm;