otherUser.jsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. import React, { Component } from "react";
  2. import { View, Button, Text, Picker, RadioGroup, Label, Radio } from "@tarojs/components";
  3. import Taro, { getCurrentInstance } from "@tarojs/taro";
  4. import { getProvince } from '../../utils/tools/index'
  5. import {
  6. AtSearchBar,
  7. AtTextarea,
  8. AtModal,
  9. AtModalHeader,
  10. AtModalContent,
  11. AtModalAction,
  12. AtInput,
  13. AtIcon,
  14. AtButton,
  15. AtInputNumber
  16. } from "taro-ui";
  17. import Skeleton from "taro-skeleton";
  18. import {
  19. queryByUidAll,
  20. getInterviewByPrdid,
  21. updateUser,
  22. getInterviewListByPage,
  23. addOneContact,
  24. findCustomerContacts,
  25. updateMainContact,
  26. limitUser,
  27. getBusinessProjectByName,
  28. addProject,
  29. queryProjectList,
  30. delProject
  31. } from "../../utils/servers/servers";
  32. import "./index.less";
  33. import "taro-ui/dist/style/components/icon.scss";
  34. import "taro-ui/dist/style/components/textarea.scss";
  35. import "taro-ui/dist/style/components/modal.scss";
  36. import "taro-ui/dist/style/components/timeline.scss";
  37. import "taro-ui/dist/style/components/calendar.scss";
  38. import "taro-ui/dist/style/components/input.scss";
  39. import "taro-ui/dist/style/components/search-bar.scss";
  40. import MessageNoticebar from "../../components/common/messageNoticebar";
  41. import { industry, channelTypeList, yearList, addressList } from '../../utils/tools/config';
  42. import { getChannel } from "../../utils/tools";
  43. import Superior from "../../components/common/superior";
  44. import CheckboxPicker from "../../components/common/CheckboxPicker";
  45. import AddressPicker from "../../components/common/addressPicker"
  46. import CustomerProjectSelect from '../../components/common/CustomerProjectSelect';
  47. import InterviewHisList from "../../components/common/InterviewHisList";
  48. class CustomerOtherProfile extends Component {
  49. $instance = getCurrentInstance();
  50. constructor(props) {
  51. super(props);
  52. this.state = {
  53. dtails: {
  54. interviewList: []
  55. },
  56. interactShow: false,
  57. interactShowType: '',
  58. interactTitle: '',
  59. interactList: [],
  60. };
  61. // this.update = this.update.bind(this);
  62. }
  63. componentDidMount() {
  64. this.queryByUidAll();
  65. }
  66. componentDidUpdate(prevProps) {
  67. const { interviewIdx, customerList } = this.props;
  68. if ((interviewIdx != prevProps.interviewIdx && interviewIdx >= 0 && interviewIdx < customerList.length)) {
  69. this.queryByUidAll();
  70. } else if (this.props.refreshInterview) {
  71. this.queryByUidAll();
  72. }
  73. }
  74. handlePrevClick() {
  75. this.props.onPrevClick();
  76. }
  77. handleNextClick() {
  78. this.onSaveAllData((resData) => {
  79. this.props.onNextClick(resData);
  80. })
  81. }
  82. // 获取面谈思路表
  83. getInterviewData() {
  84. const uid = this.props.customerList[this.props.interviewIdx].id
  85. getInterviewListByPage({ uid, pageNo: 1, pageSize: 9999 }).then(res => {
  86. // 是否在面谈中,表示本次面谈未结束
  87. let isInterviewIng = this.props.uaiIdList.some(item => item.uid == uid);
  88. const { list } = res.data;
  89. let earlyCommunication = '',
  90. customerDemand = '',
  91. interviewIdeas = '',
  92. interviewPurpose = '',
  93. interviewRecommend = '',
  94. interviewFeedback = '',
  95. followUpPlan = '';
  96. if (list.length) {
  97. if (!list[list.length - 1].prdid || isInterviewIng) {
  98. earlyCommunication = list[list.length - 1].earlyCommunication;
  99. customerDemand = list[list.length - 1].customerDemand;
  100. interviewIdeas = list[list.length - 1].interviewIdeas;
  101. interviewPurpose = list[list.length - 1].interviewPurpose;
  102. interviewRecommend = list[list.length - 1].interviewRecommend;
  103. interviewFeedback = list[list.length - 1].interviewFeedback;
  104. followUpPlan = list[list.length - 1].followUpPlan;
  105. }
  106. }
  107. let defaultDetailData = this.state.dtails || {};
  108. this.setState({
  109. dtails: {
  110. ...defaultDetailData,
  111. earlyCommunication,
  112. customerDemand,
  113. interviewIdeas,
  114. interviewPurpose,
  115. interviewRecommend,
  116. interviewFeedback,
  117. followUpPlan,
  118. interviewList: list.filter(item => !!item.prdid),
  119. }
  120. });
  121. })
  122. }
  123. // 客户档案详情
  124. queryByUidAll() {
  125. const id = this.props.customerList[this.props.interviewIdx].id;
  126. queryByUidAll(
  127. true,
  128. { id }
  129. )
  130. .then((v) => {
  131. if (v.error.length === 0) {
  132. let dtailsData = {
  133. ...v.data,
  134. }
  135. this.setState({
  136. dtails: { ...dtailsData }
  137. }, () => {
  138. this.getInterviewData();
  139. });
  140. } else {
  141. setTimeout(() => {
  142. Taro.navigateBack({
  143. delta: 1
  144. })
  145. }, 1800);
  146. Taro.showToast({
  147. title: v.error[0].message,
  148. icon: "none",
  149. duration: 1800,
  150. });
  151. }
  152. })
  153. .catch((err) => {
  154. Taro.showToast({ title: "系统错误,请稍后再试", icon: "none" });
  155. });
  156. }
  157. validParams(params) {
  158. const { dtails } = this.state;
  159. let flag = true;
  160. let message = '';
  161. if (dtails.newChannel === 0 && !params.earlyCommunication || (params.earlyCommunication && params.earlyCommunication.length < 20)) {
  162. message = '请输入客户的难处,并且在20字以上';
  163. flag = false;
  164. } else if (dtails.newChannel === 0 && !params.customerDemand || (params.customerDemand && params.customerDemand.length < 20)) {
  165. message = '请输入客户的需求,并且在20字以上';
  166. flag = false;
  167. } else if (!params.interviewIdeas || (params.interviewIdeas && params.interviewIdeas.length < 20)) {
  168. message = '请输入面谈思路,并且在20字以上';
  169. flag = false;
  170. } else if (!params.interviewPurpose || (params.interviewPurpose && params.interviewPurpose.length < 20)) {
  171. message = '请输入面谈达成的目的,并且在20字以上';
  172. flag = false;
  173. } else if (dtails.newChannel === 0 && !params.interviewRecommend || (params.interviewRecommend && params.interviewRecommend.length < 20)) {
  174. message = '请输入经理/上级面谈建议,并且在20字以上';
  175. flag = false;
  176. } else {
  177. if (this.state.dtails.interviewList.length) {
  178. if (!params.interviewFeedback || (params.interviewFeedback && params.interviewFeedback.length < 20)) {
  179. message = '请输入面谈后的反馈,并且在20字以上';
  180. flag = false;
  181. } else if (!params.followUpPlan || (params.followUpPlan && params.followUpPlan.length < 20)) {
  182. message = '请输入后续跟进计划,并且在20字以上';
  183. flag = false;
  184. }
  185. }
  186. }
  187. return { flag, message };
  188. }
  189. onSaveAllData(callback) {
  190. const { dtails } = this.state;
  191. let params = {
  192. id: dtails.id,
  193. uid: dtails.uid,
  194. locationProvince: dtails.locationProvince,
  195. locationProvinceName: dtails.locationProvinceName,
  196. locationCity: dtails.locationCity,
  197. locationCityName: dtails.locationCityName,
  198. locationArea: dtails.locationArea,
  199. locationAreaName: dtails.locationAreaName,
  200. type: 2, // 1、更新档案和面谈,0、只更新档案,2、只更新面谈
  201. };
  202. // 是否在面谈中,表示本次面谈未结束
  203. let curruaiIdList = this.props.uaiIdList.filter(item => item.uid == dtails.uid);
  204. if (curruaiIdList.length) {
  205. // 面谈编号
  206. params.uaiId = curruaiIdList[0].uaiId;
  207. }
  208. if (dtails.newChannel == 1) {
  209. // 渠道客户
  210. params = {
  211. ...params,
  212. channelType: dtails.channelType,
  213. enterpriseCount: dtails.enterpriseCount,
  214. channelIndicators: dtails.channelIndicators,
  215. interviewIdeas: dtails.interviewIdeas,
  216. interviewPurpose: dtails.interviewPurpose,
  217. interviewFeedback: dtails.interviewFeedback,
  218. followUpPlan: dtails.followUpPlan,
  219. };
  220. } else {
  221. params = {
  222. ...params,
  223. industry: dtails.industry,
  224. industryName: dtails.industryName,
  225. earlyCommunication: dtails.earlyCommunication,
  226. customerDemand: dtails.customerDemand,
  227. interviewIdeas: dtails.interviewIdeas,
  228. interviewPurpose: dtails.interviewPurpose,
  229. interviewRecommend: dtails.interviewRecommend,
  230. interviewFeedback: dtails.interviewFeedback,
  231. followUpPlan: dtails.followUpPlan,
  232. patentCount: dtails.patentCount,
  233. inventionPatentCount: dtails.inventionPatentCount,
  234. utilityModelCount: dtails.utilityModelCount,
  235. appearancePatentCount: dtails.appearancePatentCount,
  236. softwareWorksCount: dtails.softwareWorksCount,
  237. otherCount: dtails.otherCount,
  238. financialData: dtails.financialData,
  239. companyCount: dtails.companyCount,
  240. socialSecurityCount: dtails.socialSecurityCount,
  241. externalInvestCount: dtails.externalInvestCount,
  242. externalInvestIndustry: dtails.externalInvestIndustry,
  243. externalInvestIndustryName: dtails.externalInvestIndustryName,
  244. externalInvestId: dtails.externalInvestId,
  245. externalInvestName: dtails.externalInvestName,
  246. financialRevenue: dtails.financialRevenue,
  247. financialTax: dtails.financialTax,
  248. financialProperty: dtails.financialProperty,
  249. financialRd: dtails.financialRd,
  250. standard: dtails.standard,
  251. businessScope: dtails.businessScope,
  252. };
  253. }
  254. for (let key in params) {
  255. if (params[key] === undefined || params[key] === 'undefined' || params[key] === null || params[key] === 'null') {
  256. delete params[key];
  257. }
  258. }
  259. const { flag, message } = this.validParams(params);
  260. if (!flag) {
  261. Taro.showToast({
  262. title: message,
  263. icon: "none",
  264. });
  265. return;
  266. }
  267. updateUser(params).then((v) => {
  268. if (v.error.length === 0) {
  269. Taro.showToast({
  270. title: "修改成功",
  271. });
  272. callback && callback(v.data);
  273. } else {
  274. Taro.showToast({
  275. title: v.error[0].message,
  276. icon: "none",
  277. });
  278. }
  279. })
  280. }
  281. openInteractHis(type) {
  282. let interactTitle;
  283. let interactList = this.state.dtails.interviewList;
  284. switch (type) {
  285. case 'earlyCommunication':
  286. interactTitle = '客户的难处历史记录';
  287. break;
  288. case 'customerDemand':
  289. interactTitle = '客户的需求历史记录';
  290. break;
  291. case 'interviewIdeas':
  292. interactTitle = '面谈思路历史记录';
  293. break;
  294. case 'interviewPurpose':
  295. interactTitle = '面谈达成的目的历史记录';
  296. break;
  297. case 'interviewRecommend':
  298. interactTitle = '经理/上级面谈建议历史记录';
  299. break;
  300. case 'interviewFeedback':
  301. interactTitle = '面谈后反馈历史记录';
  302. interactList = interactList.slice(1, interactList.length);
  303. break;
  304. case 'followUpPlan':
  305. interactTitle = '后续跟进计划历史记录';
  306. interactList = interactList.slice(1, interactList.length);
  307. break;
  308. default:
  309. break;
  310. }
  311. this.setState({
  312. interactShow: true,
  313. interactShowType: type,
  314. interactTitle,
  315. interactList
  316. });
  317. }
  318. render() {
  319. const { dtails } = this.state;
  320. return (
  321. <View className="customerProfile">
  322. <MessageNoticebar />
  323. <View
  324. className="titleContent"
  325. >
  326. <View className="content">
  327. <View className="valueContent">
  328. <View className="title" style={{ margin: "14rpx 0 18rpx;" }}>企业面谈思路表</View>
  329. <View className="othersTips">
  330. <View>您正在面谈他人企业!</View>
  331. <View>企业名称:{dtails.nickname}</View>
  332. </View>
  333. {dtails.newChannel === 0 && (
  334. <>
  335. <View className="item">
  336. <View className="item-title">
  337. <View>
  338. 客户的难处:
  339. <Text className="titleTips">(20字以上)</Text>
  340. </View>
  341. <View>
  342. {dtails.interviewList && dtails.interviewList.length ? (
  343. <AtIcon value='clock' size='20' color='#1E90FF' onClick={() => this.openInteractHis('earlyCommunication')}></AtIcon>
  344. ) : null}
  345. </View>
  346. </View>
  347. <View className="item-value">
  348. <AtTextarea
  349. value={dtails.earlyCommunication || ''}
  350. placeholder='请编写本次面谈客户难处~'
  351. count={false}
  352. maxLength={1000}
  353. onChange={value => {
  354. dtails.earlyCommunication = value;
  355. this.setState({ dtails });
  356. }}
  357. />
  358. </View>
  359. </View>
  360. <View className="item">
  361. <View className="item-title">
  362. <View>
  363. 客户的需求:
  364. <Text className="titleTips">(20字以上)</Text>
  365. </View>
  366. <View>
  367. {dtails.interviewList && dtails.interviewList.length ? (
  368. <AtIcon value='clock' size='20' color='#1E90FF' onClick={() => this.openInteractHis('customerDemand')}></AtIcon>
  369. ) : null}
  370. </View>
  371. </View>
  372. <View className="item-value">
  373. <AtTextarea
  374. value={dtails.customerDemand || ''}
  375. placeholder='请编写本次面谈客户需求~'
  376. count={false}
  377. maxLength={1000}
  378. onChange={value => {
  379. dtails.customerDemand = value;
  380. this.setState({ dtails });
  381. }}
  382. />
  383. </View>
  384. </View>
  385. </>
  386. )}
  387. <View className="item">
  388. <View className="item-title">
  389. <View>
  390. 面谈思路:
  391. <Text className="titleTips">(20字以上)</Text>
  392. </View>
  393. <View>
  394. {dtails.interviewList && dtails.interviewList.length ? (
  395. <AtIcon value='clock' size='20' color='#1E90FF' onClick={() => this.openInteractHis('interviewIdeas')}></AtIcon>
  396. ) : null}
  397. </View>
  398. </View>
  399. <View className="item-value">
  400. <AtTextarea
  401. value={dtails.interviewIdeas || ''}
  402. placeholder='请编写本次面谈客户思路~'
  403. count={false}
  404. maxLength={1000}
  405. onChange={value => {
  406. dtails.interviewIdeas = value;
  407. this.setState({ dtails });
  408. }}
  409. />
  410. </View>
  411. </View>
  412. <View className="item">
  413. <View className="item-title">
  414. <View>
  415. 面谈达成的目的:
  416. <Text className="titleTips">(20字以上)</Text>
  417. </View>
  418. <View>
  419. {dtails.interviewList && dtails.interviewList.length ? (
  420. <AtIcon value='clock' size='20' color='#1E90FF' onClick={() => this.openInteractHis('interviewPurpose')}></AtIcon>
  421. ) : null}
  422. </View>
  423. </View>
  424. <View className="item-value">
  425. <AtTextarea
  426. value={dtails.interviewPurpose || ''}
  427. placeholder='请编写本次面谈达成的目的~'
  428. count={false}
  429. maxLength={1000}
  430. onChange={value => {
  431. dtails.interviewPurpose = value;
  432. this.setState({ dtails });
  433. }}
  434. />
  435. </View>
  436. </View>
  437. {dtails.newChannel === 0 && (
  438. <View className="item">
  439. <View className="item-title">
  440. <View>
  441. 经理/上级面谈建议:
  442. <Text className="titleTips">(由经理/上级口述,本人整理,20字以上)</Text>
  443. </View>
  444. <View>
  445. {dtails.interviewList && dtails.interviewList.length ? (
  446. <AtIcon value='clock' size='20' color='#1E90FF' onClick={() => this.openInteractHis('interviewRecommend')}></AtIcon>
  447. ) : null}
  448. </View>
  449. </View>
  450. <View className="item-value">
  451. <AtTextarea
  452. value={dtails.interviewRecommend || ''}
  453. placeholder='请编写本次面谈建议~'
  454. count={false}
  455. maxLength={1000}
  456. onChange={value => {
  457. dtails.interviewRecommend = value;
  458. this.setState({ dtails });
  459. }}
  460. />
  461. </View>
  462. </View>
  463. )}
  464. {dtails.interviewList && dtails.interviewList.length ? (
  465. <>
  466. <View className="item">
  467. <View className="item-title">
  468. <View>
  469. 面谈后的反馈:
  470. <Text className="titleTips">(20字以上)</Text>
  471. </View>
  472. <View>
  473. {dtails.interviewList && dtails.interviewList.length > 1 ? (
  474. <AtIcon value='clock' size='20' color='#1E90FF' onClick={() => this.openInteractHis('interviewFeedback')}></AtIcon>
  475. ) : null}
  476. </View>
  477. </View>
  478. <View className="item-value">
  479. <AtTextarea
  480. value={dtails.interviewFeedback || ''}
  481. placeholder='请编写本次面谈后的反馈~'
  482. count={false}
  483. maxLength={1000}
  484. onChange={value => {
  485. dtails.interviewFeedback = value;
  486. this.setState({ dtails });
  487. }}
  488. />
  489. </View>
  490. </View>
  491. <View className="item">
  492. <View className="item-title">
  493. <View>
  494. 后续跟进计划:
  495. <Text className="titleTips">(20字以上)</Text>
  496. </View>
  497. <View>
  498. {dtails.interviewList && dtails.interviewList.length > 1 ? (
  499. <AtIcon value='clock' size='20' color='#1E90FF' onClick={() => this.openInteractHis('followUpPlan')}></AtIcon>
  500. ) : null}
  501. </View>
  502. </View>
  503. <View className="item-value">
  504. <AtTextarea
  505. value={dtails.followUpPlan || ''}
  506. placeholder='请编写后续跟进计划~'
  507. count={false}
  508. maxLength={1000}
  509. onChange={value => {
  510. dtails.followUpPlan = value;
  511. this.setState({ dtails });
  512. }}
  513. />
  514. </View>
  515. </View>
  516. </>
  517. ) : null}
  518. <View style={{ display: 'flex', marginTop: '24rpx' }}>
  519. <AtButton type="secondary" circle onClick={this.handlePrevClick.bind(this)}>上一页</AtButton>
  520. <AtButton type="primary" circle onClick={this.handleNextClick.bind(this)}>下一页</AtButton>
  521. </View>
  522. </View>
  523. </View>
  524. </View>
  525. {/* 沟通情况历史记录 */}
  526. <InterviewHisList
  527. isOpened={this.state.interactShow}
  528. list={this.state.interactList}
  529. type={this.state.interactShowType}
  530. title={this.state.interactTitle}
  531. onClose={() => {
  532. this.setState({ interactShow: false })
  533. }}
  534. />
  535. </View>
  536. );
  537. }
  538. }
  539. export default CustomerOtherProfile;