detail.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. <template>
  2. <view class="clueDetail_wrap">
  3. <view class="telPhone">
  4. <view class="left">
  5. <view class="phone"
  6. >电话:
  7. <show-real-text
  8. :real="receiptDetail.phone"
  9. :type="params.type"
  10. v-if="receiptDetail.phone"
  11. ></show-real-text>
  12. </view>
  13. <view
  14. class="copy_btn"
  15. v-if="params.type != '1'"
  16. @click="handleCopy(receiptDetail)"
  17. >复制</view
  18. >
  19. </view>
  20. <view class="right"> 发单人 : {{ receiptDetail.createNickName }} </view>
  21. </view>
  22. <view class="clueDetail_top_info">
  23. <view class="top_info_item">
  24. <view class="top">
  25. {{ defaultText(receiptDetail.clueOwnerName) }}
  26. </view>
  27. <view class="bottom"> 线索所属人 </view>
  28. </view>
  29. <view class="top_info_item">
  30. <view class="top">
  31. {{ defaultText(receiptDetail.brand) }}
  32. </view>
  33. <view class="bottom"> 品牌 </view>
  34. </view>
  35. <view class="top_info_item">
  36. <view class="top">
  37. {{ defaultText(receiptDetail.identificationName) }}
  38. </view>
  39. <view class="bottom"> 接单人 </view>
  40. </view>
  41. <view class="top_info_item">
  42. <view class="top">
  43. {{ crmFormCategoryFormat(receiptDetail.category) }}
  44. </view>
  45. <view class="bottom"> 类别 </view>
  46. </view>
  47. <view class="top_info_item">
  48. <view class="top">
  49. {{ crmFormTacticFormat(receiptDetail.tactic) }}
  50. </view>
  51. <view class="bottom"> 采用战术 </view>
  52. </view>
  53. <view class="top_info_item">
  54. <view class="top">
  55. {{ crmFollowStatusFormat(receiptDetail.status) }}
  56. </view>
  57. <view class="bottom"> 跟进状态 </view>
  58. </view>
  59. </view>
  60. <view class="clue_state_wrap">
  61. <view class="top_left">阶段:</view>
  62. <view class="steps_wrap">
  63. <ld-select
  64. v-model="receiptDetail.state"
  65. :list="crmFormStateDict"
  66. value-key="dictValue"
  67. label-key="dictLabel"
  68. placeholder="点击选择阶段"
  69. @change="handleStateConfirm"
  70. >
  71. </ld-select>
  72. </view>
  73. </view>
  74. <view class="clue_tag_wrap">
  75. <view class="clue_tag_add_btn" @click="handleAddClueTag">
  76. + 添加标签
  77. </view>
  78. <u-tag
  79. :text="tag.name"
  80. plain
  81. plainFill
  82. :closable="true"
  83. @close="hanldeTagClose(tag)"
  84. borderColor="#fff"
  85. v-for="tag in receiptDetail.tags"
  86. :key="tag.id"
  87. style="margin-left: 10px; margin-bottom: 10px"
  88. :bgColor="tag.color"
  89. color="#fff"
  90. ></u-tag>
  91. </view>
  92. <yui-tabs
  93. :tabs="tabs"
  94. v-model="activeIndex"
  95. :lineWidth="'120rpx'"
  96. :isLazyRender="false"
  97. color="#108cff"
  98. titleActiveColor="#108cff"
  99. :swipeable="true"
  100. :swiper="false"
  101. :ellipsis="false"
  102. :scroll-threshold="3"
  103. >
  104. <template #chatFile>
  105. <upload-file
  106. :clueId="clueId"
  107. :sourceId="orderId"
  108. ref="uploadFile1"
  109. type="2"
  110. orderFileType="1"
  111. isDuplicate="1"
  112. ></upload-file>
  113. </template>
  114. <template #quoteFile>
  115. <upload-file
  116. :clueId="clueId"
  117. :sourceId="orderId"
  118. ref="uploadFile2"
  119. type="2"
  120. orderFileType="2"
  121. isDuplicate="1"
  122. ></upload-file>
  123. </template>
  124. <template #hdImageFile>
  125. <upload-file
  126. :clueId="clueId"
  127. :sourceId="orderId"
  128. ref="uploadFile3"
  129. type="2"
  130. orderFileType="3"
  131. isDuplicate="1"
  132. ></upload-file>
  133. </template>
  134. <template #otherFile>
  135. <upload-file
  136. :clueId="clueId"
  137. :sourceId="orderId"
  138. ref="uploadFile4"
  139. type="2"
  140. orderFileType="4"
  141. isDuplicate="1"
  142. ></upload-file>
  143. </template>
  144. <template #frontendFile>
  145. <upload-file
  146. :clueId="clueId"
  147. ref="uploadFile5"
  148. type="6"
  149. isDuplicate="1"
  150. ></upload-file>
  151. </template>
  152. <template #frontendFollow>
  153. <clue-follow
  154. :clueId="clueId"
  155. ref="clueFollow"
  156. type="4"
  157. ></clue-follow>
  158. </template>
  159. <template #followRecord>
  160. <clue-follow
  161. :clueId="clueId"
  162. ref="follow"
  163. type="5"
  164. ></clue-follow>
  165. </template>
  166. <!-- <template #receiptInfo>
  167. <receipt-form-list
  168. :sendFormId="receiptDetail.id"
  169. :clueId="receiptDetail.clueId"
  170. :receiptDetail="receiptDetail"
  171. ref="receiptFormList"
  172. ></receipt-form-list>
  173. </template>
  174. <template #commissionInfo>
  175. <commission-form-list
  176. :sendFormId="receiptDetail.id"
  177. :clueId="receiptDetail.clueId"
  178. ref="commissionFormList"
  179. ></commission-form-list>
  180. </template> -->
  181. </yui-tabs>
  182. <u-tabbar
  183. class="clueDetail_tabber"
  184. :fixed="true"
  185. inactiveColor="#ffffff"
  186. :placeholder="true"
  187. :safeAreaInsetBottom="true"
  188. >
  189. <u-tabbar-item
  190. text="拨打电话"
  191. icon="../../static/clueDetail/icon-phone.png"
  192. @click="handleCallPhone"
  193. ></u-tabbar-item>
  194. <u-tabbar-item
  195. v-if="receiptDetail.status === '1'"
  196. text="接单"
  197. icon="../../static/orderDetail/jd.png"
  198. @click="handleOrderForm"
  199. ></u-tabbar-item>
  200. <u-tabbar-item
  201. v-if="receiptDetail.status === '2'"
  202. text="收单"
  203. icon="../../static/orderDetail/sd.png"
  204. @click="handleReceiptForm"
  205. ></u-tabbar-item>
  206. <u-tabbar-item
  207. v-if="receiptDetail.status === '2'"
  208. text="未收"
  209. icon="../../static/orderDetail/ws.png"
  210. @click="handleDenialForm"
  211. ></u-tabbar-item>
  212. <u-tabbar-item
  213. v-if="receiptDetail.status === '1'"
  214. text="撤销"
  215. icon="../../static/orderDetail/cx.png"
  216. @click="handleDelete"
  217. ></u-tabbar-item>
  218. <u-tabbar-item
  219. text="添加跟进"
  220. icon="../../static/caseDetail/icon-follow.png"
  221. @click="handleAddFollow"
  222. ></u-tabbar-item>
  223. </u-tabbar>
  224. <group-select
  225. class="clueTagsSelect"
  226. :list="clueTagGroupVoList"
  227. scrollHeight="720rpx"
  228. groupName="groupName"
  229. groupChild="clueTagDataList"
  230. label-key="name"
  231. value-key="id"
  232. placeholder="请选择线索标签"
  233. v-model="checkTags"
  234. multiple
  235. clearable
  236. ref="clueTag"
  237. @confirm="handleClueTagConfirm"
  238. ></group-select>
  239. </view>
  240. </template>
  241. <script>
  242. import { cloneDeep } from "lodash";
  243. import { selectDictLabel } from "@/utils/util";
  244. import uploadFile from "../tabs/uploadFile/index.vue";
  245. import clueFollow from "../tabs/followRecord/index.vue";
  246. // import receiptFormList from "../tabs/receiptFormList/receiptFormList.vue";
  247. // import commissionFormList from "../tabs/commissionFormList/commissionFormList.vue";
  248. export default {
  249. components: {
  250. uploadFile,
  251. clueFollow,
  252. // receiptFormList,
  253. // commissionFormList,
  254. },
  255. props: {
  256. orderId: {
  257. type: [String, Number],
  258. required: true,
  259. },
  260. clueId: {
  261. type: [String, Number],
  262. required: true,
  263. },
  264. params: {
  265. type: Object,
  266. required: true,
  267. },
  268. },
  269. data() {
  270. return {
  271. showModal: false,
  272. showStateSelect: false,
  273. receiptDetail: {},
  274. checkTags: [],
  275. clueTagGroupVoList: [],
  276. crmFormCategoryDict: [],
  277. crmFormTacticDict: [],
  278. crmFormStateDict: [],
  279. crmHandelStatusDict: [],
  280. tabs: [
  281. {
  282. label: "聊天附件",
  283. slot: "chatFile",
  284. },
  285. {
  286. label: "报价附件",
  287. slot: "quoteFile",
  288. },
  289. {
  290. label: "高清图附件",
  291. slot: "hdImageFile",
  292. },
  293. {
  294. label: "其他附件",
  295. slot: "otherFile",
  296. },
  297. {
  298. label: "前端附件",
  299. slot: "frontendFile",
  300. },
  301. {
  302. label: "前端跟进",
  303. slot: "frontendFollow",
  304. },
  305. {
  306. label: "跟进记录",
  307. slot: "followRecord",
  308. },
  309. // {
  310. // label: "收单信息",
  311. // slot: "receiptInfo",
  312. // },
  313. // {
  314. // label: "收单分成",
  315. // slot: "commissionInfo",
  316. // },
  317. ],
  318. activeIndex: 0,
  319. };
  320. },
  321. methods: {
  322. async hanldeTagClose(tag) {
  323. const { id, tags } = this.receiptDetail;
  324. const copyTags = cloneDeep(tags);
  325. if (id == null) {
  326. uni.$u.toast("修改异常");
  327. return;
  328. }
  329. const index = copyTags.findIndex((v) => v.id === tag.id);
  330. if (index !== -1) {
  331. copyTags.splice(index, 1);
  332. const allTags = copyTags.map((v) => v.id).join(",");
  333. await uni.$u.api.updateTags({
  334. id: id,
  335. allTags,
  336. });
  337. this.receiptDetail.tags = copyTags;
  338. this.checkTags = this.receiptDetail.tags.map((v) => v.id);
  339. }
  340. },
  341. async handleClueTagConfirm() {
  342. const allTags = this.checkTags.join(",");
  343. await uni.$u.api.updateTags({
  344. id: this.receiptDetail.id,
  345. allTags,
  346. });
  347. this.getDetail();
  348. },
  349. handleAddClueTag() {
  350. this.$refs.clueTag.showModal();
  351. },
  352. async handleStateConfirm(e) {
  353. const state = e.value;
  354. await uni.$u.api.updateOrderState({
  355. id: this.receiptDetail.id,
  356. state,
  357. });
  358. uni.$u.toast("操作成功");
  359. },
  360. defaultText(text) {
  361. return text ? text : "-";
  362. },
  363. crmFormCategoryFormat(v) {
  364. return selectDictLabel(this.crmFormCategoryDict, v);
  365. },
  366. crmFormTacticFormat(v) {
  367. return selectDictLabel(this.crmFormTacticDict, v);
  368. },
  369. crmFollowStatusFormat(v) {
  370. return selectDictLabel(this.crmHandelStatusDict, v);
  371. },
  372. selectDictLabel,
  373. handleCopy(item) {
  374. uni.setClipboardData({
  375. data: item.phone,
  376. success: function () {
  377. uni.$u.toast("复制成功");
  378. },
  379. });
  380. },
  381. // 添加联系人
  382. handleCallPhone() {
  383. uni.makePhoneCall({
  384. phoneNumber: this.receiptDetail.phone,
  385. success: () => {
  386. this.$store.commit("call/SET_FORM", {
  387. clueId: this.receiptDetail.clueId,
  388. type: "3",
  389. callee: this.receiptDetail.phone,
  390. });
  391. },
  392. });
  393. },
  394. // 添加跟进记录
  395. handleAddFollow() {
  396. uni.navigateTo({
  397. url: `/pages/addFollow/index?orderId=${this.orderId}`,
  398. });
  399. },
  400. handleUploadRecord() {
  401. uni.navigateTo({
  402. url: `/pages/uploadRecord/index?clueId=${this.orderId}`,
  403. });
  404. },
  405. // 接单操作
  406. async handleOrderForm() {
  407. if (this.receiptDetail.status === "2") {
  408. uni.$u.toast("当前订单已经被接单");
  409. return;
  410. }
  411. uni.showModal({
  412. title: "提示",
  413. content: "确定要接单吗?",
  414. success: async (res) => {
  415. if (res.confirm) {
  416. try {
  417. await uni.$u.api.oderForm({
  418. status: "2",
  419. id: this.receiptDetail.id,
  420. });
  421. uni.$u.toast("接单成功");
  422. this.getDetail(); // 刷新详情
  423. } catch (error) {
  424. uni.$u.toast("接单失败");
  425. }
  426. }
  427. },
  428. });
  429. },
  430. // 收单操作
  431. async handleReceiptForm() {
  432. if (
  433. this.receiptDetail.status === "3" ||
  434. this.receiptDetail.status === "4"
  435. ) {
  436. uni.$u.toast("当前订单已经被收单或未收");
  437. return;
  438. }
  439. uni.showModal({
  440. title: "提示",
  441. content: "确定要收单吗?",
  442. success: async (res) => {
  443. if (res.confirm) {
  444. try {
  445. await uni.$u.api.oderForm({
  446. status: "3",
  447. id: this.receiptDetail.id,
  448. });
  449. uni.$u.toast("收单成功");
  450. this.getDetail(); // 刷新详情
  451. } catch (error) {
  452. uni.$u.toast("收单失败");
  453. }
  454. }
  455. },
  456. });
  457. },
  458. // 未收操作
  459. async handleDenialForm() {
  460. if (
  461. this.receiptDetail.status === "3" ||
  462. this.receiptDetail.status === "4"
  463. ) {
  464. uni.$u.toast("当前订单已经被收单或未收");
  465. return;
  466. }
  467. uni.showModal({
  468. title: "提示",
  469. content: "确定要标记为未收吗?",
  470. success: async (res) => {
  471. if (res.confirm) {
  472. try {
  473. await uni.$u.api.oderForm({
  474. status: "4",
  475. id: this.receiptDetail.id,
  476. });
  477. uni.$u.toast("标记未收成功");
  478. this.getDetail(); // 刷新详情
  479. } catch (error) {
  480. uni.$u.toast("操作失败");
  481. }
  482. }
  483. },
  484. });
  485. },
  486. // 撤销操作
  487. async handleDelete() {
  488. uni.showModal({
  489. title: "提示",
  490. content: "是否确定撤销?",
  491. success: async (res) => {
  492. if (res.confirm) {
  493. try {
  494. await uni.$u.api.deleteOrder([this.receiptDetail.id]);
  495. uni.$u.toast("撤销成功");
  496. // 撤销后返回上一页
  497. setTimeout(() => {
  498. uni.navigateBack();
  499. }, 1500);
  500. } catch (error) {
  501. uni.$u.toast("撤销失败");
  502. }
  503. }
  504. },
  505. });
  506. },
  507. // 初始化详情页
  508. async handleInit() {
  509. this.getDetail();
  510. this.$getDicts("crm_form_category").then((res) => {
  511. this.crmFormCategoryDict = res;
  512. });
  513. this.$getDicts("crm_form_tactic").then((res) => {
  514. this.crmFormTacticDict = res;
  515. });
  516. this.$getDicts("crm_form_state").then((res) => {
  517. this.crmFormStateDict = res;
  518. });
  519. this.$getDicts("crm_follow_status").then((res) => {
  520. this.crmHandelStatusDict = res;
  521. });
  522. uni.$u.api
  523. .getClueTagGroupVoList({
  524. tagGroupApplication: "2",
  525. })
  526. .then(({ data }) => {
  527. this.clueTagGroupVoList = data;
  528. });
  529. },
  530. getDetail() {
  531. uni.$u.api.getClueSendFormVoByOrderId({
  532. id: this.orderId,
  533. })
  534. .then((res) => {
  535. this.receiptDetail = res.data;
  536. this.checkTags = this.receiptDetail.tags
  537. ? this.receiptDetail.tags.map((v) => v.id)
  538. : [];
  539. });
  540. },
  541. },
  542. created() {
  543. this.handleInit();
  544. },
  545. };
  546. </script>
  547. <style lang="scss" scoped>
  548. .clueTagsSelect {
  549. height: 0;
  550. overflow: hidden;
  551. }
  552. .clue_tag_wrap {
  553. display: flex;
  554. align-items: center;
  555. background-color: #fff;
  556. padding: 0 10px;
  557. margin: 20px 0;
  558. flex-wrap: wrap;
  559. min-height: 50px;
  560. .clue_tag_add_btn {
  561. font-size: 14px;
  562. color: #108cff;
  563. }
  564. }
  565. .clue_state_wrap {
  566. background-color: #fff;
  567. padding: 10px;
  568. margin-bottom: 20px;
  569. display: flex;
  570. align-items: center;
  571. .top_left {
  572. font-size: 16px;
  573. flex: 0 0 50px;
  574. }
  575. .steps_wrap {
  576. flex: 1;
  577. }
  578. }
  579. .clueDetail_tabber {
  580. ::v-deep .u-tabbar__content {
  581. background: #108cff;
  582. border-top-right-radius: 10px;
  583. border-top-left-radius: 10px;
  584. }
  585. }
  586. .clueDetail_wrap {
  587. .telPhone {
  588. display: flex;
  589. background: #fff;
  590. padding: 20px;
  591. justify-content: space-between;
  592. .left {
  593. display: flex;
  594. }
  595. .copy_btn {
  596. color: #4fa5fe;
  597. margin-left: 10px;
  598. }
  599. }
  600. .clueDetail_top_info {
  601. display: flex;
  602. flex-wrap: wrap;
  603. background-color: #ffffff;
  604. padding-top: 20px;
  605. margin: 18px 0;
  606. .top_info_item {
  607. width: 33.33%;
  608. text-align: center;
  609. margin-bottom: 20px;
  610. .top {
  611. font-size: 15px;
  612. color: #202020;
  613. margin-bottom: 5px;
  614. font-weight: bold;
  615. }
  616. .bottom {
  617. font-size: 15px;
  618. color: #c0c0c7;
  619. }
  620. }
  621. }
  622. }
  623. </style>