detail.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  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 status-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. <!-- 跟进状态 -->
  75. <view class="order_action_wrap">
  76. <view class="action_title">状态:</view>
  77. <view
  78. class="action_buttons"
  79. v-if="['1', '2'].includes(receiptDetail.status)"
  80. >
  81. <u-button
  82. v-if="receiptDetail.status === '1'"
  83. type="success"
  84. size="small"
  85. text="接单"
  86. @click="handleOrderForm"
  87. customStyle="margin-right: 20rpx;"
  88. ></u-button>
  89. <u-button
  90. v-if="receiptDetail.status === '2'"
  91. type="primary"
  92. size="small"
  93. text="收单"
  94. @click="handleReceiptForm"
  95. customStyle="margin-right: 20rpx;"
  96. ></u-button>
  97. <u-button
  98. v-if="receiptDetail.status === '2'"
  99. type="warning"
  100. size="small"
  101. text="未收"
  102. @click="handleDenialForm"
  103. customStyle="margin-right: 20rpx;"
  104. ></u-button>
  105. <u-button
  106. v-if="receiptDetail.status === '1'"
  107. type="error"
  108. size="small"
  109. text="撤销"
  110. @click="handleDelete"
  111. customStyle="margin-right: 20rpx;"
  112. ></u-button>
  113. </view>
  114. <view v-else class="last_status">
  115. 该订单{{ crmFollowStatusFormat(receiptDetail.status) }}不可再操作
  116. </view>
  117. </view>
  118. <view class="clue_tag_wrap">
  119. <view class="clue_tag_add_btn" @click="handleAddClueTag">
  120. + 添加标签
  121. </view>
  122. <u-tag
  123. :text="tag.name"
  124. plain
  125. plainFill
  126. :closable="true"
  127. @close="hanldeTagClose(tag)"
  128. borderColor="#fff"
  129. v-for="tag in receiptDetail.tags"
  130. :key="tag.id"
  131. style="margin-left: 10px; margin-bottom: 10px"
  132. :bgColor="tag.color"
  133. color="#fff"
  134. ></u-tag>
  135. </view>
  136. <yui-tabs
  137. :tabs="tabs"
  138. v-model="activeIndex"
  139. :lineWidth="'120rpx'"
  140. :isLazyRender="false"
  141. color="#108cff"
  142. titleActiveColor="#108cff"
  143. :swipeable="true"
  144. :swiper="false"
  145. :ellipsis="false"
  146. :scroll-threshold="3"
  147. >
  148. <template #chatFile>
  149. <upload-file
  150. :clueId="clueId"
  151. :sourceId="orderId"
  152. ref="uploadFile1"
  153. type="2"
  154. orderFileType="1"
  155. isDuplicate="1"
  156. ></upload-file>
  157. </template>
  158. <template #quoteFile>
  159. <upload-file
  160. :clueId="clueId"
  161. :sourceId="orderId"
  162. ref="uploadFile2"
  163. type="2"
  164. orderFileType="2"
  165. isDuplicate="1"
  166. ></upload-file>
  167. </template>
  168. <template #hdImageFile>
  169. <upload-file
  170. :clueId="clueId"
  171. :sourceId="orderId"
  172. ref="uploadFile3"
  173. type="2"
  174. orderFileType="3"
  175. isDuplicate="1"
  176. ></upload-file>
  177. </template>
  178. <template #otherFile>
  179. <upload-file
  180. :clueId="clueId"
  181. :sourceId="orderId"
  182. ref="uploadFile4"
  183. type="2"
  184. orderFileType="4"
  185. isDuplicate="1"
  186. ></upload-file>
  187. </template>
  188. <template #frontendFile>
  189. <upload-file
  190. :clueId="clueId"
  191. ref="uploadFile5"
  192. type="6"
  193. isDuplicate="1"
  194. ></upload-file>
  195. </template>
  196. <template #frontendFollow>
  197. <clue-follow :clueId="clueId" ref="clueFollow" type="4"></clue-follow>
  198. </template>
  199. <template #followRecord>
  200. <clue-follow :clueId="clueId" ref="follow" type="5"></clue-follow>
  201. </template>
  202. <template #receiptInfo>
  203. <receipt-form-list
  204. :sendFormId="orderId"
  205. :clueId="clueId"
  206. :receiptDetail="receiptDetail"
  207. ref="receiptFormList"
  208. ></receipt-form-list>
  209. </template>
  210. <template #commissionInfo>
  211. <commission-form-list
  212. :sendFormId="orderId"
  213. :clueId="clueId"
  214. ref="commissionFormList"
  215. ></commission-form-list>
  216. </template>
  217. </yui-tabs>
  218. <u-tabbar
  219. class="clueDetail_tabber"
  220. :fixed="true"
  221. inactiveColor="#ffffff"
  222. :placeholder="true"
  223. :safeAreaInsetBottom="true"
  224. >
  225. <u-tabbar-item
  226. text="拨打电话"
  227. icon="../../static/clueDetail/icon-phone.png"
  228. @click="handleCallPhone"
  229. ></u-tabbar-item>
  230. <u-tabbar-item
  231. text="添加收单"
  232. icon="../../static/orderDetail/sd.png"
  233. @click="handleAddReceiptForm"
  234. ></u-tabbar-item>
  235. <u-tabbar-item
  236. text="新增分成"
  237. icon="../../static/orderDetail/add_commission.png"
  238. @click="handleAddCommission"
  239. ></u-tabbar-item>
  240. <u-tabbar-item
  241. text="添加跟进"
  242. icon="../../static/caseDetail/icon-follow.png"
  243. @click="handleAddFollow"
  244. ></u-tabbar-item>
  245. </u-tabbar>
  246. <group-select
  247. class="clueTagsSelect"
  248. :list="clueTagGroupVoList"
  249. scrollHeight="720rpx"
  250. groupName="groupName"
  251. groupChild="clueTagDataList"
  252. label-key="name"
  253. value-key="id"
  254. placeholder="请选择线索标签"
  255. v-model="checkTags"
  256. multiple
  257. clearable
  258. ref="clueTag"
  259. @confirm="handleClueTagConfirm"
  260. ></group-select>
  261. </view>
  262. </template>
  263. <script>
  264. import { cloneDeep } from "lodash";
  265. import { selectDictLabel } from "@/utils/util";
  266. import uploadFile from "../tabs/uploadFile/index.vue";
  267. import clueFollow from "../tabs/followRecord/index.vue";
  268. import receiptFormList from "../tabs/receiptFormList/receiptFormList.vue";
  269. import commissionFormList from "../tabs/commissionFormList/commissionFormList.vue";
  270. export default {
  271. components: {
  272. uploadFile,
  273. clueFollow,
  274. receiptFormList,
  275. commissionFormList,
  276. },
  277. props: {
  278. orderId: {
  279. type: [String, Number],
  280. required: true,
  281. },
  282. clueId: {
  283. type: [String, Number],
  284. required: true,
  285. },
  286. params: {
  287. type: Object,
  288. required: true,
  289. },
  290. },
  291. data() {
  292. return {
  293. showModal: false,
  294. showStateSelect: false,
  295. receiptDetail: {},
  296. checkTags: [],
  297. clueTagGroupVoList: [],
  298. crmFormCategoryDict: [],
  299. crmFormTacticDict: [],
  300. crmFormStateDict: [],
  301. crmHandelStatusDict: [],
  302. tabs: [
  303. {
  304. label: "聊天附件",
  305. slot: "chatFile",
  306. },
  307. {
  308. label: "报价附件",
  309. slot: "quoteFile",
  310. },
  311. {
  312. label: "高清图附件",
  313. slot: "hdImageFile",
  314. },
  315. {
  316. label: "其他附件",
  317. slot: "otherFile",
  318. },
  319. {
  320. label: "前端附件",
  321. slot: "frontendFile",
  322. },
  323. {
  324. label: "前端跟进",
  325. slot: "frontendFollow",
  326. },
  327. {
  328. label: "跟进记录",
  329. slot: "followRecord",
  330. },
  331. {
  332. label: "收单信息",
  333. slot: "receiptInfo",
  334. },
  335. {
  336. label: "收单分成",
  337. slot: "commissionInfo",
  338. },
  339. ],
  340. activeIndex: 0,
  341. };
  342. },
  343. methods: {
  344. async hanldeTagClose(tag) {
  345. const { id, tags } = this.receiptDetail;
  346. const copyTags = cloneDeep(tags);
  347. if (id == null) {
  348. uni.$u.toast("修改异常");
  349. return;
  350. }
  351. const index = copyTags.findIndex((v) => v.id === tag.id);
  352. if (index !== -1) {
  353. copyTags.splice(index, 1);
  354. const allTags = copyTags.map((v) => v.id).join(",");
  355. await uni.$u.api.updateTags({
  356. id: id,
  357. allTags,
  358. });
  359. this.receiptDetail.tags = copyTags;
  360. this.checkTags = this.receiptDetail.tags.map((v) => v.id);
  361. }
  362. },
  363. async handleClueTagConfirm() {
  364. const allTags = this.checkTags.join(",");
  365. await uni.$u.api.updateTags({
  366. id: this.receiptDetail.id,
  367. allTags,
  368. });
  369. this.getDetail();
  370. },
  371. handleAddClueTag() {
  372. this.$refs.clueTag.showModal();
  373. },
  374. async handleStateConfirm(e) {
  375. const state = e.value;
  376. await uni.$u.api.updateOrderState({
  377. id: this.receiptDetail.id,
  378. state,
  379. });
  380. uni.$u.toast("操作成功");
  381. },
  382. defaultText(text) {
  383. return text ? text : "-";
  384. },
  385. crmFormCategoryFormat(v) {
  386. return v ? selectDictLabel(this.crmFormCategoryDict, v) : "-";
  387. },
  388. crmFormTacticFormat(v) {
  389. return v ? selectDictLabel(this.crmFormTacticDict, v) : "-";
  390. },
  391. crmFollowStatusFormat(v) {
  392. return selectDictLabel(this.crmHandelStatusDict, v);
  393. },
  394. selectDictLabel,
  395. handleCopy(item) {
  396. uni.setClipboardData({
  397. data: item.phone,
  398. success: function () {
  399. uni.$u.toast("复制成功");
  400. },
  401. });
  402. },
  403. // 添加联系人
  404. handleCallPhone() {
  405. uni.makePhoneCall({
  406. phoneNumber: this.receiptDetail.phone,
  407. success: () => {
  408. this.$store.commit("call/SET_FORM", {
  409. clueId: this.receiptDetail.clueId,
  410. type: "3",
  411. callee: this.receiptDetail.phone,
  412. });
  413. },
  414. });
  415. },
  416. // 添加跟进记录
  417. handleAddFollow() {
  418. uni.navigateTo({
  419. url: `/pages/addFollow/index?orderId=${this.orderId}`,
  420. });
  421. },
  422. // 跳转到收单表单页面
  423. handleAddReceiptForm() {
  424. uni.navigateTo({
  425. url: `/pages/receiptForm/index?orderId=${this.orderId}&clueId=${this.clueId}`,
  426. });
  427. },
  428. // 跳转到新增分成页面
  429. handleAddCommission() {
  430. uni.navigateTo({
  431. url: `/pages/commissionForm/index?sendFormId=${this.orderId}&clueId=${this.clueId}`,
  432. });
  433. },
  434. handleUploadRecord() {
  435. uni.navigateTo({
  436. url: `/pages/uploadRecord/index?clueId=${this.orderId}`,
  437. });
  438. },
  439. // 接单操作
  440. async handleOrderForm() {
  441. if (this.receiptDetail.status === "2") {
  442. uni.$u.toast("当前订单已经被接单");
  443. return;
  444. }
  445. uni.showModal({
  446. title: "提示",
  447. content: "确定要接单吗?",
  448. success: async (res) => {
  449. if (res.confirm) {
  450. try {
  451. await uni.$u.api.oderForm({
  452. status: "2",
  453. id: this.receiptDetail.id,
  454. });
  455. uni.$u.toast("接单成功");
  456. this.getDetail(); // 刷新详情
  457. } catch (error) {
  458. uni.$u.toast("接单失败");
  459. }
  460. }
  461. },
  462. });
  463. },
  464. // 收单操作
  465. async handleReceiptForm() {
  466. if (
  467. this.receiptDetail.status === "3" ||
  468. this.receiptDetail.status === "4"
  469. ) {
  470. uni.$u.toast("当前订单已经被收单或未收");
  471. return;
  472. }
  473. uni.showModal({
  474. title: "提示",
  475. content: "确定要收单吗?",
  476. success: async (res) => {
  477. if (res.confirm) {
  478. try {
  479. await uni.$u.api.oderForm({
  480. status: "3",
  481. id: this.receiptDetail.id,
  482. });
  483. uni.$u.toast("收单成功");
  484. this.getDetail(); // 刷新详情
  485. } catch (error) {
  486. uni.$u.toast("收单失败");
  487. }
  488. }
  489. },
  490. });
  491. },
  492. // 未收操作
  493. async handleDenialForm() {
  494. if (
  495. this.receiptDetail.status === "3" ||
  496. this.receiptDetail.status === "4"
  497. ) {
  498. uni.$u.toast("当前订单已经被收单或未收");
  499. return;
  500. }
  501. uni.showModal({
  502. title: "提示",
  503. content: "确定要标记为未收吗?",
  504. success: async (res) => {
  505. if (res.confirm) {
  506. try {
  507. await uni.$u.api.oderForm({
  508. status: "4",
  509. id: this.receiptDetail.id,
  510. });
  511. uni.$u.toast("标记未收成功");
  512. this.getDetail(); // 刷新详情
  513. } catch (error) {
  514. uni.$u.toast("操作失败");
  515. }
  516. }
  517. },
  518. });
  519. },
  520. // 撤销操作
  521. async handleDelete() {
  522. uni.showModal({
  523. title: "提示",
  524. content: "是否确定撤销?",
  525. success: async (res) => {
  526. if (res.confirm) {
  527. try {
  528. await uni.$u.api.deleteOrder([this.receiptDetail.id]);
  529. uni.$u.toast("撤销成功");
  530. // 撤销后返回上一页
  531. setTimeout(() => {
  532. uni.navigateBack();
  533. }, 1500);
  534. } catch (error) {
  535. uni.$u.toast("撤销失败");
  536. }
  537. }
  538. },
  539. });
  540. },
  541. // 初始化详情页
  542. async handleInit() {
  543. this.getDetail();
  544. this.$getDicts("crm_form_category").then((res) => {
  545. this.crmFormCategoryDict = res;
  546. });
  547. this.$getDicts("crm_form_tactic").then((res) => {
  548. this.crmFormTacticDict = res;
  549. });
  550. this.$getDicts("crm_form_state").then((res) => {
  551. this.crmFormStateDict = res;
  552. });
  553. this.$getDicts("crm_form_status").then((res) => {
  554. this.crmHandelStatusDict = res;
  555. });
  556. uni.$u.api
  557. .getClueTagGroupVoList({
  558. tagGroupApplication: "2",
  559. })
  560. .then(({ data }) => {
  561. this.clueTagGroupVoList = data;
  562. });
  563. },
  564. getDetail() {
  565. uni.$u.api
  566. .getClueSendFormVoByOrderId({
  567. id: this.orderId,
  568. })
  569. .then((res) => {
  570. this.receiptDetail = res.data;
  571. this.checkTags = this.receiptDetail.tags
  572. ? this.receiptDetail.tags.map((v) => v.id)
  573. : [];
  574. });
  575. },
  576. },
  577. created() {
  578. this.handleInit();
  579. },
  580. };
  581. </script>
  582. <style lang="scss" scoped>
  583. .clueTagsSelect {
  584. height: 0;
  585. overflow: hidden;
  586. }
  587. .clue_tag_wrap {
  588. display: flex;
  589. align-items: center;
  590. background-color: #fff;
  591. padding: 0 10px;
  592. margin: 20px 0;
  593. flex-wrap: wrap;
  594. min-height: 50px;
  595. .clue_tag_add_btn {
  596. font-size: 14px;
  597. color: #108cff;
  598. }
  599. }
  600. .clue_state_wrap {
  601. background-color: #fff;
  602. padding: 10px;
  603. margin-bottom: 20px;
  604. display: flex;
  605. align-items: center;
  606. .top_left {
  607. font-size: 16px;
  608. flex: 0 0 50px;
  609. }
  610. .steps_wrap {
  611. flex: 1;
  612. }
  613. }
  614. .order_action_wrap {
  615. padding: 10px;
  616. margin: 15px 0;
  617. background: #fff;
  618. display: flex;
  619. align-items: center;
  620. .action_title {
  621. font-size: 16px;
  622. flex: 0 0 50px;
  623. }
  624. .last_status {
  625. color: #c0c0c7;
  626. font-size: 14px;
  627. }
  628. .action_buttons {
  629. display: grid;
  630. grid-template-columns: repeat(2, 1fr);
  631. gap: 10px;
  632. ::v-deep .u-button {
  633. height: 30px !important;
  634. font-size: 12px !important;
  635. border-radius: 8px !important;
  636. border: 1px solid #e2e8f0 !important;
  637. background: #ffffff !important;
  638. color: #2d3748 !important;
  639. font-weight: 500 !important;
  640. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
  641. transition: all 0.3s ease !important;
  642. &.u-button--success {
  643. background: #ffd025 !important;
  644. color: white !important;
  645. border-color: #ffd025 !important;
  646. }
  647. // 特别样式化不同按钮类型
  648. &.u-button--primary {
  649. background: #35dbd9 !important;
  650. color: white !important;
  651. border-color: #35dbd9 !important;
  652. }
  653. &.u-button--warning {
  654. background: #ba9fb0 !important;
  655. color: white !important;
  656. border-color: #ba9fb0 !important;
  657. }
  658. &.u-button--error {
  659. background: #e53e3e !important;
  660. color: white !important;
  661. border-color: #e53e3e !important;
  662. }
  663. }
  664. }
  665. }
  666. .clueDetail_tabber {
  667. ::v-deep .u-tabbar__content {
  668. background: #108cff;
  669. border-top-right-radius: 10px;
  670. border-top-left-radius: 10px;
  671. }
  672. }
  673. .clueDetail_wrap {
  674. .telPhone {
  675. display: flex;
  676. background: #fff;
  677. padding: 20px;
  678. justify-content: space-between;
  679. .left {
  680. display: flex;
  681. }
  682. .copy_btn {
  683. color: #4fa5fe;
  684. margin-left: 10px;
  685. }
  686. }
  687. .clueDetail_top_info {
  688. display: flex;
  689. flex-wrap: wrap;
  690. background-color: #ffffff;
  691. padding-top: 20px;
  692. margin: 18px 0;
  693. .top_info_item {
  694. width: 33.33%;
  695. text-align: center;
  696. margin-bottom: 20px;
  697. .top {
  698. font-size: 15px;
  699. color: #202020;
  700. margin-bottom: 5px;
  701. font-weight: bold;
  702. }
  703. .bottom {
  704. font-size: 15px;
  705. color: #c0c0c7;
  706. }
  707. }
  708. }
  709. }
  710. </style>