dtl.jsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. import Taro, { Component } from '@tarojs/taro'
  2. import { View, Image, Input, Swiper, SwiperItem, ScrollView } from '@tarojs/components'
  3. import ListMore from '@/c/pageDataList/listMore'
  4. import LoginPopup from '@/c/login/Popup'
  5. import './dtl.scss'
  6. import { strTrim } from '@utils'
  7. class Index extends Component {
  8. onShareAppMessage() {
  9. const { id } = this.$router.params
  10. return {
  11. title: `来谈谈你的见解?`,
  12. path: `/pagesQa/dtl?id=${id}`,
  13. }
  14. }
  15. onShareTimeline () {
  16. const { id } = this.$router.params
  17. const { curObj } = this.state
  18. return {
  19. title: `${curObj.question_cont}`,
  20. path: `/pagesQa/dtl?id=${id}`,
  21. }
  22. }
  23. constructor (props) {
  24. super(props)
  25. this.state = {
  26. page_size: 10,
  27. page: 1,
  28. isListEnd: false,
  29. isListLoading: false,
  30. isListEmpty: false,
  31. dataList: [],
  32. curObj: {},
  33. commentVal: '',
  34. tempObj: {},
  35. userInfo: '',
  36. token: '',
  37. isLoginPopupShow: false,
  38. isAnswerHide: false,
  39. adBannerList: {}
  40. }
  41. }
  42. config = {
  43. navigationBarTitleText: '问答详情',
  44. }
  45. componentWillMount () {
  46. Taro.$AHU(this)
  47. const { name } = this.$router.params
  48. Taro.setNavigationBarTitle({
  49. title: name || '问答详情'
  50. })
  51. this.getDataList()
  52. this.getDtl()
  53. this.getBannerAd()
  54. }
  55. getDtl () {
  56. const userInfo = Taro.getStorageSync('APP_userInfo') || ''
  57. if (userInfo) {
  58. this.setState({
  59. userInfo
  60. })
  61. }
  62. this.setState({
  63. token: Taro.getStorageSync('APP_token') || ''
  64. })
  65. }
  66. componentDidShow () { }
  67. componentDidHide () { }
  68. renderTop () {
  69. const { curObj } = this.state
  70. const HideMan = require('@img/icon_hide_man.png')
  71. const btnBack = require('./img/bg_bc_list.png')
  72. let imgArr = []
  73. if (curObj.question_img) imgArr = curObj.question_img.split(',')
  74. const imgItems = imgArr.map((src, srcIndex) => {
  75. return (
  76. <View className="op" key={srcIndex} onClick={this.previewImageHandle.bind(this, src, imgArr)}>
  77. <Image className="img" src={src + '_xs'} mode="aspectFill" />
  78. </View>
  79. )
  80. })
  81. const voteOps = curObj.vote && curObj.vote.vote_cont ? curObj.vote.vote_cont : []
  82. return (
  83. <View className="l-comment-box">
  84. <View className="lcb-top">
  85. <View className="lt-content" onClick={this.sendChangeHandle.bind(this, curObj)}>
  86. <View className="lb-img">
  87. <Image className="img" src={curObj.is_anon === '1' ? HideMan : curObj.avatar} />
  88. </View>
  89. <View className="lb-info">
  90. <View className="lb-p1 t2">
  91. {curObj.nickname || '洪楼Plus'}
  92. <Image onClick={this.linkDtl.bind(this)} className="b" src={btnBack}></Image>
  93. </View>
  94. <View className="lb-time">{curObj.create_at}</View>
  95. </View>
  96. </View>
  97. <View className="lt-content-more" onClick={this.sendChangeHandle.bind(this, curObj)}>
  98. <View className="lb-p2">{curObj.question_cont}</View>
  99. {
  100. imgArr.length > 0
  101. &&
  102. <View className="scoped-img">
  103. {imgItems}
  104. </View>
  105. }
  106. </View>
  107. {voteOps.length === 2 && this.renderVs(curObj)}
  108. {voteOps.length > 2 && this.renderVote(curObj)}
  109. </View>
  110. </View>
  111. )
  112. }
  113. previewImageHandle (current, urls) {
  114. Taro.previewImage({
  115. current,
  116. urls
  117. })
  118. }
  119. linkDtl () {
  120. Taro.redirectTo({url: '/pagesQa/index'})
  121. }
  122. zanHandle (answer_id, flag) {
  123. let apiStr = flag ? 'apianswerunzan' : 'apianswerzan'
  124. Taro.api.news[apiStr]({
  125. answer_id
  126. }).then(res => {
  127. this.getDataList()
  128. })
  129. }
  130. renderVs (item) {
  131. const bg = require('./img/index/vsbg.png')
  132. const edIcon = require('./img/index/rightblue.png')
  133. const edIcon2 = require('./img/index/rightred.png')
  134. const vsbg2 = require('./img/index/vsbg2.png')
  135. const vsbg3 = require('./img/index/vsbg3.png')
  136. const voteOps = item.vote.vote_cont || []
  137. const voteUser = item.vote.vote_user || {}
  138. const totalNum = item.vote.vote_count_sum || 0
  139. const curItems = voteOps.map((op, i) => {
  140. return (
  141. <View className="op" key={i} onClick={this.voteHandle.bind(this, op)}>{op.vote_cont}</View>
  142. )
  143. })
  144. const edBgItems = voteOps.map((op, i) => {
  145. const per = parseInt(op.vote_count / totalNum * 100)
  146. return (
  147. <View className={op.id === voteUser.vote_id ? 'op cur' : 'op'} style={`width:${per + 10}%`} key={i}>
  148. <View className="bg"></View>
  149. <View className="v">{op.vote_count}</View>
  150. { op.id === voteUser.vote_id && i === 0 && <Image className="i" src={vsbg2}></Image> }
  151. { op.id === voteUser.vote_id && i === 1 && <Image className="i" src={vsbg3}></Image> }
  152. </View>
  153. )
  154. })
  155. const edItems = voteOps.map((op, i) => {
  156. return (
  157. <View className='op' key={i}>
  158. <View className={op.id === voteUser.vote_id && i === 0 ? 'cur t' : 't'}>{op.vote_cont}
  159. { op.id === voteUser.vote_id && i === 0 && <Image className="i" src={edIcon2}></Image> }
  160. { op.id === voteUser.vote_id && i === 1 && <Image className="i" src={edIcon}></Image> }
  161. </View>
  162. </View>
  163. )
  164. })
  165. return (
  166. <View className="ql-vs">
  167. {
  168. voteUser.is_vote
  169. ?
  170. <View className="qv-ed">
  171. <View className="qve-bg">
  172. {edBgItems}
  173. </View>
  174. <View className="qve-content">
  175. {edItems}
  176. </View>
  177. </View>
  178. :
  179. <View className="qv-un">
  180. <Image className="bg" src={bg}></Image>
  181. <View className="content">
  182. {curItems}
  183. </View>
  184. </View>
  185. }
  186. </View>
  187. )
  188. }
  189. renderVote (item) {
  190. const edIcon = require('./img/index/rightblue.png')
  191. const voteOps = item.vote.vote_cont || []
  192. const voteUser = item.vote.vote_user || {}
  193. const totalNum = item.vote.vote_count_sum || 0
  194. const curItems = voteOps.map((op, i) => {
  195. return (
  196. <View className="op" key={i} onClick={this.voteHandle.bind(this, op)}>{op.vote_cont}</View>
  197. )
  198. })
  199. const edItems = voteOps.map((op, i) => {
  200. const per = parseInt(op.vote_count / totalNum * 100)
  201. return (
  202. <View className={op.id === voteUser.vote_id ? 'op cur' : 'op'} key={i}>
  203. <View className="bg" style={`width:${per}%`}></View>
  204. <View className="t">{op.vote_cont}
  205. {
  206. op.id === voteUser.vote_id
  207. &&
  208. <Image className="i" src={edIcon}></Image>
  209. }
  210. </View>
  211. <View className="v">{op.vote_count}</View>
  212. </View>
  213. )
  214. })
  215. return (
  216. <View className="ql-vote">
  217. {
  218. voteUser.is_vote
  219. ?
  220. <View className="qv-ed">
  221. {edItems}
  222. </View>
  223. :
  224. <View className="qv-un">
  225. {curItems}
  226. </View>
  227. }
  228. </View>
  229. )
  230. }
  231. voteHandle (op) {
  232. Taro.api.news.apiuservoteadd({
  233. question_id: op.question_id,
  234. vote_id: op.id
  235. }).then(() => {
  236. Taro.$msg('投票成功')
  237. this.getDataList()
  238. })
  239. }
  240. getDataList () {
  241. const HideMan = require('@img/icon_hide_man.png')
  242. let { page_size, page, dataList, isListEmpty } = this.state
  243. const { id: question_id } = this.$router.params
  244. Taro.api.news.apianswerlist2({
  245. page,
  246. page_size,
  247. question_id,
  248. }).then(res => {
  249. let curObj = res.question || {}
  250. if (curObj.is_anon === '1') curObj.nickname = '洪楼粉丝'
  251. let curData = res.answer_list.list || []
  252. let isListEnd = false
  253. if (curData.length > 0) {
  254. if (page === 1) {
  255. dataList = curData
  256. } else {
  257. dataList = dataList.concat(curData)
  258. }
  259. if (curData.length === page_size && res.answer_list.total !== curData.length) {
  260. isListEnd = false
  261. } else {
  262. isListEnd = true
  263. }
  264. }
  265. if (curData.length === 0 && page === 1) {
  266. isListEmpty = true
  267. dataList = []
  268. isListEnd = true
  269. } else {
  270. isListEmpty = false
  271. }
  272. dataList.map(item => {
  273. if (item.is_anon === '1') {
  274. item.nickname = '洪楼粉丝'
  275. item.avatar = HideMan
  276. }
  277. if (item.child && item.child.length > 0) {
  278. let child = item.child
  279. child.map(sub => {
  280. if (sub.is_anon === '1') {
  281. sub.nickname = '洪楼粉丝'
  282. sub.avatar = HideMan
  283. }
  284. })
  285. }
  286. })
  287. this.setState({
  288. curObj,
  289. tempObj: curObj,
  290. dataList,
  291. isListEnd,
  292. isListEmpty,
  293. isListLoading: false
  294. })
  295. })
  296. }
  297. onScrollToLower (e) {
  298. let { isListEnd, isListLoading, page } = this.state
  299. if (!isListEnd && !isListLoading) {
  300. page++
  301. this.setState({
  302. page,
  303. isListLoading: true
  304. }, () => {
  305. this.getDataList()
  306. })
  307. }
  308. }
  309. renderList () {
  310. const { dataList, isListEnd, isListLoading, isListEmpty } = this.state
  311. const zan1Icon = require('@img/i_g_zan.png')
  312. const zan2Icon = require('@img/i_g_zan2.png')
  313. let newArr = []
  314. const userCurInfo = Taro.getStorageSync('APP_userInfo')
  315. dataList.forEach(item => {
  316. if (item.hide_status === "2") {
  317. if (userCurInfo.user_id === item.user_id) {
  318. newArr.push(item)
  319. }
  320. } else {
  321. newArr.push(item)
  322. }
  323. })
  324. const curItems = newArr.map((item, index) => {
  325. const lvIcon = Taro.$getLvIcon(item.integral)
  326. const oldList = JSON.parse(JSON.stringify(item.child))
  327. let subList = item.isMoreAllShow ? [...oldList] : oldList.splice(0, 2)
  328. return (
  329. <View className="lcb-item" key={index}>
  330. <View className="lb-img" onClick={this.sendChangeHandle.bind(this, item)} >
  331. <Image className="img" src={item.avatar} />
  332. </View>
  333. <View className="lb-info">
  334. <View>
  335. <Navigator url="/pagesOther/index" className="lb-p1">{item.nickname}
  336. <Image className="i" src={lvIcon}></Image>
  337. </Navigator>
  338. <View onClick={this.dtlLink.bind(this, item)} className="lb-time">{item.create_at}</View>
  339. <View onClick={this.dtlLink.bind(this, item)} className="lb-p2">{item.answer_cont}</View>
  340. </View>
  341. <View className="lb-zan" onClick={this.zanHandle.bind(this, item.answer_id, item.is_zan)}>
  342. {
  343. item.is_zan
  344. ?
  345. <Image className="i" src={zan2Icon}/>
  346. :
  347. <Image className="i" src={zan1Icon}/>
  348. }
  349. <View className={item.is_zan ? 'n cur' : 'n'}>{item.zan_count}</View>
  350. </View>
  351. <View className="lb-sub">
  352. <View>
  353. {
  354. subList.map((sub, subIndex) => {
  355. const lvSubIcon = Taro.$getLvIcon(sub.integral)
  356. return (
  357. <View className="lcb-item" key={subIndex}>
  358. <View className="lb-img" onClick={this.sendChangeHandle.bind(this, sub)}>
  359. <Image className="img" src={sub.avatar} />
  360. </View>
  361. <View className="lb-info">
  362. <Navigator url="/pagesOther/index" className="lb-p1">{sub.nickname}
  363. <Image className="i" src={lvSubIcon}></Image>
  364. </Navigator>
  365. <View className="lb-time">{sub.create_at}</View>
  366. {
  367. sub.parent_id === item.answer_id
  368. ?
  369. <View onClick={this.dtlLink.bind(this, item)} className="lb-p2">{sub.answer_cont}</View>
  370. :
  371. <View onClick={this.dtlLink.bind(this, item)} className="lb-p2">回复:<View className="link">{sub.parent_user_name}</View>{sub.answer_cont}</View>
  372. }
  373. </View>
  374. </View>
  375. )
  376. })
  377. }
  378. </View>
  379. {
  380. item.child.length > 2
  381. ?
  382. item.isMoreAllShow
  383. ?
  384. <View className="lb-more t2" onClick={this.commentMoreHandle.bind(this, index)}>收起
  385. <View className="sign"></View>
  386. </View>
  387. :
  388. <View className="lb-more" onClick={this.commentMoreHandle.bind(this, index)}>-展开回复({item.child.length - 2}条)
  389. <View className="sign"></View>
  390. </View>
  391. : ''
  392. }
  393. </View>
  394. </View>
  395. </View>
  396. )
  397. })
  398. return (
  399. <View>
  400. <View className="l-comment-box pb200">
  401. {curItems}
  402. </View>
  403. <ListMore isListEnd={isListEnd} isListLoading={isListLoading} isListEmpty={isListEmpty} />
  404. </View>
  405. )
  406. }
  407. dtlLink (item) {
  408. Taro.navigateTo({
  409. url: `/pagesQa/dtlSub?id=${item.answer_id}`
  410. })
  411. }
  412. commentMoreHandle (index) {
  413. const { dataList } = this.state
  414. let mList = dataList || []
  415. mList.map((item, i) => {
  416. if (index === i) item.isMoreAllShow = !item.isMoreAllShow
  417. })
  418. this.setState({
  419. dataList: [...mList]
  420. })
  421. }
  422. sendChangeHandle (tempObj) {
  423. this.setState({
  424. commentVal: '',
  425. tempObj
  426. })
  427. }
  428. sendHandle () {
  429. const { commentVal, tempObj, isAnswerHide } = this.state
  430. const { id } = this.$router.params
  431. if (commentVal) {
  432. let params = {
  433. question_id: Number(id),
  434. answer_cont: commentVal,
  435. }
  436. if (tempObj.user_id) {
  437. params = {
  438. question_id: Number(id),
  439. answer_cont: commentVal,
  440. parent_id: tempObj.id || tempObj.answer_id || '',
  441. parent_user_id: tempObj.user_id || '',
  442. parent_user_name: tempObj.nickname || '',
  443. }
  444. }
  445. if (isAnswerHide) {
  446. params.is_anon = '1'
  447. }
  448. Taro.api.news.apiansweradd(params).then(res => {
  449. Taro.$msg('回答成功~')
  450. this.setState({
  451. commentVal: ''
  452. })
  453. this.getDataList()
  454. })
  455. } else {
  456. Taro.$msg('请输入你的回答')
  457. }
  458. }
  459. changeInput (e) {
  460. const val = strTrim(e.target.value)
  461. this.setState({
  462. commentVal: val
  463. })
  464. }
  465. renderQaAdd () {
  466. const iconGif = require('@img/icon_g_qa.gif')
  467. return (
  468. <Navigator url={'/pagesQa/add'} className="scoped-fix-q2 t2">
  469. <Image className="img" src={iconGif} />
  470. </Navigator>
  471. )
  472. }
  473. renderShare () {
  474. const iconShare = require('@img/images/icon_g_share6.png')
  475. return (
  476. <Button className="g-icon-share btn-to-div" openType="share">
  477. <Image className="img" src={iconShare} />
  478. </Button>
  479. )
  480. }
  481. getUserProfile (e) {
  482. wx.getUserProfile({
  483. desc: '用于完善头像和昵称资料',
  484. success: (res) => {
  485. const dtlObj = res || {}
  486. this.setState({
  487. userInfo: dtlObj.userInfo
  488. })
  489. Taro.setStorageSync('APP_userInfo', dtlObj.userInfo)
  490. }
  491. })
  492. }
  493. openLoginPopup (obj) {
  494. this.setState({
  495. isLoginPopupShow: true
  496. })
  497. }
  498. closeLoginPopup (str) {
  499. this.setState({
  500. isLoginPopupShow: false
  501. })
  502. if (str && str === 'success') {
  503. this.getDtl()
  504. }
  505. }
  506. answerHideChange () {
  507. let { isAnswerHide } = this.state
  508. isAnswerHide = !isAnswerHide
  509. this.setState({
  510. isAnswerHide
  511. })
  512. }
  513. renderBanner () {
  514. const { adBannerList } = this.state
  515. const adItems = adBannerList.map((item, index) => {
  516. return (
  517. <SwiperItem key={index}>
  518. <View className='ad-img' onClick={this.bannerHandle.bind(this, item)} >
  519. <Image src={item.images} className="img" />
  520. </View>
  521. </SwiperItem>
  522. )
  523. })
  524. return (
  525. <View className="index-banner">
  526. <Swiper
  527. className='test-h'
  528. indicatorColor='#999'
  529. indicatorActiveColor='#fff'
  530. circular
  531. indicatorDots
  532. autoplay>
  533. {adItems}
  534. </Swiper>
  535. </View>
  536. )
  537. }
  538. bannerHandle (item) {
  539. if (item.ad_link_type) {
  540. if (item.ad_link_type === 'estate') {
  541. Taro.navigateTo({
  542. url: `/pagesHouse/indexDtl?id=${item.link_type_value}`
  543. })
  544. }
  545. if (item.ad_link_type === 'news') {
  546. Taro.navigateTo({
  547. url: `/pagesMore/news/indexDtl?id=${item.link_type_value}`
  548. })
  549. }
  550. if (item.ad_link_type === 'page') {
  551. Taro.navigateTo({
  552. url: `${item.link_type_value}`
  553. })
  554. }
  555. }
  556. }
  557. getBannerAd () {
  558. const testImg1 = 'http://icon.honglounews.com/ex_banner.jpg'
  559. Taro.api.house.apiadvertslist({ad_position: 'qa_dtl_banner'}).then(res => {
  560. const adList = res.qa_dtl_banner || []
  561. // if (adList.length === 0) {
  562. // adList.push({images: testImg1})
  563. // }
  564. this.setState({
  565. adBannerList: adList
  566. })
  567. })
  568. }
  569. loginJudge () {
  570. const { userInfo, token } = this.state
  571. const uInfo = userInfo || Taro.getStorageSync('APP_userInfo')
  572. const { isLoginPopupShow } = this.state
  573. return (
  574. <View style={uInfo && uInfo.avatarUrl && token ? '' : 'position: absolute;height: 100%;width: 100%;'}>
  575. <LoginPopup show={isLoginPopupShow} close={this.closeLoginPopup.bind(this)} />
  576. {
  577. uInfo && uInfo.avatarUrl
  578. ? token || isLoginPopupShow
  579. ? ''
  580. : <Button className="g-u-btn t2" onClick={this.openLoginPopup.bind(this)}></Button>
  581. : <Button className="g-u-btn t2" onClick={this.getUserProfile.bind(this)}></Button>
  582. }
  583. </View>
  584. )
  585. }
  586. renderScrollBody () {
  587. const { tempObj, commentVal, curObj, isAnswerHide, adBannerList } = this.state
  588. const hideN = require('@img/icon_hide2.png')
  589. const hideY = require('@img/icon_hide3.png')
  590. return (
  591. <ScrollView
  592. className='l-scroll-view'
  593. scrollY
  594. scrollWithAnimation
  595. scrollTop="0"
  596. lowerThreshold="100"
  597. onScrollToLower={this.onScrollToLower.bind(this)}
  598. >
  599. <View style="position:relative;">
  600. {this.loginJudge()}
  601. {this.renderTop()}
  602. {adBannerList.length > 0 && this.renderBanner()}
  603. <View className="scoped-main">
  604. <View className="sm-title">
  605. 全部回答
  606. <View className="t">({curObj.answer_count}条)</View>
  607. </View>
  608. {this.renderList()}
  609. </View>
  610. <View className="l-floor-footer">
  611. <View className="scoped-footer">
  612. <View className="sf-input">
  613. {/* focus */}
  614. {/* <Input className="input" placeholder={`我来回答`} value={commentVal} onInput={this.changeInput.bind(this)} /> */}
  615. <Input className="input" placeholder={`回复:${tempObj.nickname}(点头像切换)`} value={commentVal} onInput={this.changeInput.bind(this)} />
  616. <View className="more" onClick={this.answerHideChange.bind(this)}>
  617. {
  618. isAnswerHide
  619. ?
  620. <Image className="i" src={hideY} />
  621. :
  622. <Image className="i" src={hideN} />
  623. }
  624. </View>
  625. <View className="btn" onClick={this.sendHandle.bind(this)}>发送</View>
  626. </View>
  627. </View>
  628. </View>
  629. </View>
  630. </ScrollView>
  631. )
  632. }
  633. render () {
  634. return (
  635. <View className="l-box has-footer">
  636. {this.renderQaAdd()}
  637. {this.renderShare()}
  638. {this.renderScrollBody()}
  639. </View>
  640. )
  641. }
  642. }
  643. export default Index