pagereceivecenter.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. <script>
  2. // import orderCard from "./compounts/orderCard.vue";
  3. export default {
  4. components: {
  5. // orderCard,
  6. },
  7. data() {
  8. return {
  9. orderList: [],
  10. page: {
  11. pageSize: 10,
  12. pageNum: 1,
  13. total: 0
  14. },
  15. tagModalVisible: false,
  16. tagList: [],
  17. currentTags: [],
  18. currentOrder: {},
  19. followUpModelShow: false,
  20. followUpNotes: '',
  21. countdown: 300,
  22. countdownIntervals: null,
  23. //筛选条件
  24. filterList: [
  25. { name: '全部列表', type: 1 },
  26. { name: '我的接发单', type: 2 }
  27. ],
  28. statisticsSendStatus: [],//中间统计数据
  29. activeType: 1,//当前选择的筛选类型,顶部tab的类型
  30. activeStatus: '',//当前选择的状态,统计数据的类型
  31. currentFollowUp: [],//当前订单的跟进记录
  32. showMoreFollowUp: false
  33. }
  34. },
  35. onLoad() {
  36. //初始调用
  37. this.getOrderList();
  38. this.getStatisticsSendStatus();
  39. this.countdownInterval()
  40. // uni.navigateTo({
  41. // url: `/pages/orderDetailNew/index?orderId=5464&item=测试发单&type=undefined&clueId=1973381744953516033`,
  42. // })
  43. },
  44. onUnload() {
  45. clearInterval(this.countdownInterval);
  46. },
  47. watch: {
  48. countdown: {
  49. handler(newVal, oldVal) {
  50. if (newVal <= 0) {
  51. this.orderList.forEach(order => {
  52. if (order.status == 1) {
  53. this.handleBtnClick('isBusy', order)
  54. }
  55. })
  56. clearInterval(this.countdownInterval);
  57. }
  58. },
  59. immediate: true
  60. }
  61. },
  62. methods: {
  63. countdownInterval() {
  64. this.countdownInterval = setInterval(() => {
  65. this.countdown--
  66. }, 1000);
  67. },
  68. //获取列表数据
  69. async getOrderList() {
  70. try {
  71. const result = await uni.$u.api.selectClueOrderFormList({
  72. pageSize: this.page.pageSize,
  73. pageNum: this.page.pageNum,
  74. }, {
  75. type: this.activeType,
  76. status: this.activeStatus,
  77. });
  78. console.log('接单列表', result);
  79. // 把数组按照status的大小排序,从小到大
  80. result.rows.sort((a, b) => {
  81. return a.status - b.status;
  82. })
  83. this.orderList.push(...result.rows);
  84. this.page.total = result.total;
  85. } catch (error) {
  86. console.error('接单列表接口调用失败:', error);
  87. // 添加用户友好的错误提示
  88. uni.$u.toast('获取订单列表失败,请稍后重试');
  89. }
  90. },
  91. //获取统计数据
  92. async getStatisticsSendStatus() {
  93. const { data } = await uni.$u.api.statisticsSendStatus({ type: this.activeType });
  94. // console.log('统计数据是', data)
  95. this.statisticsSendStatus = data;
  96. },
  97. // 处理按钮点击事件
  98. async handleBtnClick(btnType, order) {
  99. if (btnType == 'acceptOrder') {
  100. //去接单
  101. console.log('去接单', order)
  102. //打开模态窗二次确认,确认后跳转接单form
  103. uni.showModal({
  104. title: '确认接单',
  105. content: `是否确认接单订单:${order.item}?`,
  106. success: async (res) => {
  107. if (res.confirm) {
  108. await uni.$u.api.oderForm({
  109. status: "2",
  110. id: order.id,
  111. });
  112. uni.navigateTo({
  113. url: `/pages/orderDetailNew/index?orderId=${order.id}&item=${order.item}&type=${this.type}&clueId=${order.clueId}`,
  114. })
  115. } else if (res.cancel) {
  116. // 用户点击了取消,不执行任何操作
  117. uni.$u.toast('已取消接单');
  118. }
  119. }
  120. })
  121. } else if (btnType == 'isBusy') {
  122. //在忙
  123. console.log('在忙', order)
  124. //当前订单移动到末尾
  125. this.orderList.push(this.orderList.splice(this.orderList.indexOf(order), 1)[0]);
  126. } else if (btnType == 'willFollow') {
  127. //待跟进
  128. console.log('待跟进', order)
  129. //打开模态窗
  130. this.followUpModelShow = true;
  131. this.currentOrder = order
  132. } else if (btnType == 'tag') {
  133. //打标签
  134. console.log('打标签', order)
  135. //打开模态窗
  136. this.tagModalVisible = true;
  137. this.getAllTags();
  138. this.currentTags = order.tags.map(tag => tag.id);
  139. this.currentOrder = order
  140. } else if (btnType == 'share') {
  141. //一键分享
  142. console.log('一键分享', order)
  143. } else if (btnType == 'oneFollow') {
  144. //待跟进
  145. console.log('待跟进', order)
  146. this.followUpModelShow = true;
  147. this.currentOrder = order
  148. }
  149. },
  150. // 跳转订单详情
  151. toOrderDetail(order) {
  152. //点卡片看详情
  153. // if (order.status == '1' || order.status == '2') {
  154. uni.navigateTo({
  155. url: `/pages/orderDetailNew/index?orderId=${order.id}&item=${order.item}&type=${this.type}&clueId=${order.clueId}`,
  156. })
  157. // } else {
  158. // uni.$u.toast('当前订单无法查看详情');
  159. // return;
  160. // }
  161. },
  162. //滑动加载
  163. scrolltolower() {
  164. // console.log('到底了');
  165. if (this.orderList.length >= this.page.total) {
  166. //到底了,没有更多
  167. } else {
  168. this.page.pageNum++;
  169. this.getOrderList();
  170. }
  171. },
  172. //获取全部标签
  173. async getAllTags() {
  174. const res = await uni.$u.api.getClueTagGroupVoList({ tagGroupApplication: '2' })
  175. console.log('全部标签', res.data[0].clueTagDataList)
  176. this.tagList = res.data[0].clueTagDataList;
  177. },
  178. cancelTag() {
  179. this.tagModalVisible = false;
  180. },
  181. async confirmTag() {
  182. console.log('确认打标签', this.currentTags)
  183. // 这里可以添加打标签的逻辑
  184. const allTags = this.currentTags.map(tag => tag).join(',');
  185. console.log('allTags', allTags)
  186. await uni.$u.api.updateTags({
  187. id: this.currentOrder.id,
  188. allTags: allTags,
  189. })
  190. this.tagModalVisible = false;
  191. uni.$u.toast('标签更新成功');
  192. //更新当前订单的标签
  193. this.currentOrder.tags = this.tagList.filter(tag => this.currentTags.includes(tag.id));
  194. },
  195. // 确认跟进细节按钮点击事件
  196. async confirmFollowUp() {
  197. console.log('确认跟进细节:', this.followUpNotes);
  198. this.followUpModelShow = false;
  199. // 可以在这里添加提交跟进细节的逻辑
  200. // 未收的时候,提交一个跟进记录 待跟进_内容
  201. const res = await uni.$u.api.addOrderFollow({
  202. orderId: this.currentOrder.id,
  203. content: `待跟进_${this.followUpNotes}`,
  204. })
  205. if (res.code == 200) {
  206. uni.$u.toast('提交待跟进记录成功');
  207. }
  208. this.followUpNotes = '';
  209. },
  210. // 切换筛选条件
  211. async changeFilter(param) {
  212. this.activeType = param.type;
  213. this.page.pageNum = 1;
  214. this.orderList = [];
  215. this.getOrderList();
  216. this.getStatisticsSendStatus()
  217. },
  218. //切换统计数据的类型
  219. changeStatus(param) {
  220. if (param == this.activeStatus) {
  221. //如果当前点击的状态和当前选中的状态相同,则取消选中
  222. this.activeStatus = '';
  223. this.page.pageNum = 1;
  224. this.orderList = [];
  225. this.getOrderList();
  226. } else {
  227. //如果当前点击的状态和当前选中的状态不同,则切换选中状态
  228. this.activeStatus = param;
  229. this.page.pageNum = 1;
  230. this.orderList = [];
  231. this.getOrderList();
  232. }
  233. },
  234. //点击查看更多的跟进
  235. async handleShowMoreFollowUp() {
  236. //当前的order是
  237. console.log()
  238. const { data } = await uni.$u.api.getDuplicateOrderFollowListByClueId({
  239. clueId: this.currentOrder.clueId
  240. });
  241. console.log('这里是跟进', data)
  242. const allData = []
  243. for (const key in data) {
  244. allData.push(...data[key])
  245. }
  246. const filterData = allData.filter(item => {
  247. console.log('过滤', item)
  248. //过滤出来tem.content不包括联系师傅、师傅拍图技巧、到达客户面对面、未收评分、待跟进_
  249. return item.content.indexOf('联系师傅') == -1 && item.content.indexOf('师傅拍图技巧') == -1 && item.content.indexOf('到达客户面对面') == -1 && item.content.indexOf('未收评分') == -1 && item.content.indexOf('待跟进_') == -1
  250. })
  251. console.log('筛选后的跟进', filterData)
  252. this.currentFollowUp = filterData || [];
  253. this.showMoreFollowUp = true
  254. }
  255. }
  256. }
  257. </script>
  258. <template>
  259. <view class="container">
  260. <u-navbar title="接单中心" :autoBack="true" :placeholder="true" v-hideNav></u-navbar>
  261. <!-- 筛选条件 -->
  262. <u-tabs :list="filterList" @click="changeFilter"></u-tabs>
  263. <!-- 统计数据 -->
  264. <scroll-view scroll-x class="statusScrollView" style="width: 100%;">
  265. <view class="statisticsContainer">
  266. <view v-for="item in statisticsSendStatus" :key="item.status" @click="changeStatus(item.status)"
  267. class="statisticsItem" :class="{ 'activeStatusClass': item.status == activeStatus }">
  268. <view>{{ item.statusName }}</view>
  269. <view>({{ item.count || 0 }})</view>
  270. </view>
  271. </view>
  272. </scroll-view>
  273. <view class="scrollViewContainer">
  274. <scroll-view class="scrollView" scroll-y @scrolltolower="scrolltolower">
  275. <transition-group name="order-move" tag="div">
  276. <!-- <orderCard v-for="item in orderList" :key="item.receiptId + item.id" :order="item"
  277. @handleBtnClick="handleBtnClick">
  278. </orderCard> -->
  279. <view class="orderCard" v-for="item in orderList" :key="item.receiptId + item.id"
  280. @click.stop="toOrderDetail(item)">
  281. <view class="bandAndPrice">
  282. <view class="bandName">{{ item.itemBrand || '暂无品牌' }}</view>
  283. <view class="price">¥{{ item.priceRange || '?' }}</view>
  284. </view>
  285. <view class="mainLind">
  286. <!-- <view class="mainLindImg">
  287. <image :src="'/static/acceptOrder/orderCardPic.jpg'" v-if="item.src" />
  288. </view> -->
  289. <view class="itemName">{{ item.item || '暂无项目' }}</view>
  290. <view class="mainLindInfo">
  291. <view class="infoItem">
  292. <view class="infoItemTitle">发单人:</view>
  293. <view>{{ item.createNickName || '未知' }}</view>
  294. </view>
  295. <view class="infoItem">
  296. <view class="infoItemTitle">机构:</view>
  297. <view>{{ item.orgName || '暂无机构' }}</view>
  298. </view>
  299. <view class="infoItem">
  300. <view class="infoItemTitle">电话:</view>
  301. <view>{{ item.phone || '暂无电话' }}</view>
  302. </view>
  303. <view class="infoItem">
  304. <view class="infoItemTitle">接单人:</view>
  305. <view>{{ item.identificationName || '暂无所属人' }}</view>
  306. </view>
  307. <view class="infoItem">
  308. <view class="infoItemTitle">运营人:</view>
  309. <view>{{ item.clueOperationName || '暂无运营人' }}</view>
  310. </view>
  311. <view class="infoItem">
  312. <view class="infoItemTitle">发单日期:</view>
  313. <view>{{ item.sendDate || '暂无时间' }}</view>
  314. </view>
  315. </view>
  316. </view>
  317. <view class="tags">
  318. <view class="tag" v-for="(tag, index) in item.tags" :key="index"
  319. :style="{ backgroundColor: tag.color, opacity: 0.8 }">
  320. {{ tag.name }}</view>
  321. </view>
  322. <view class="Btns">
  323. <view class="btnGroup" v-if="item && (item.status == '1')">
  324. <view class="card-button" @click.stop="handleBtnClick('acceptOrder', item)">立即接单</view>
  325. <view class=" card-button isBusy" @click.stop="handleBtnClick('isBusy', item)">
  326. <view>
  327. 在忙
  328. </view>
  329. <view v-if="countdown > 0">
  330. ({{ countdown }} s)
  331. </view>
  332. </view>
  333. </view>
  334. <view class="btnGroup" v-if="item && (item.status == '2')">
  335. <view class="card-button willFollow" @click.stop="handleBtnClick('willFollow', item)">
  336. 待跟进
  337. </view>
  338. <view class="card-button isBusy" @click.stop="handleBtnClick('tag', item)">打标签</view>
  339. </view>
  340. <!-- <view class="btnGroup" v-if="item && (item.status == '3')">
  341. <view class="card-button share" @click.stop="handleBtnClick('share', item)">一键分享</view>
  342. </view> -->
  343. <view class="btnGroup" v-if="item && (item.status == '4')">
  344. <view class="card-button oneFollow" @click.stop="handleBtnClick('oneFollow', item)">待跟进
  345. </view>
  346. </view>
  347. </view>
  348. </view>
  349. </transition-group>
  350. <view class="hasMore">
  351. {{ orderList.length >= page.total ? '没有更多了~' : '向下滑动加载更多~' }}
  352. </view>
  353. </scroll-view>
  354. </view>
  355. <!-- 打标签模态窗 -->
  356. <u-modal showCancelButton :show="tagModalVisible" title="选择标签" @confirm="confirmTag" @cancel="cancelTag">
  357. <view class="slot-content">
  358. <u-checkbox-group class="tagCheckboxGroup" v-model="currentTags" placement="column">
  359. <u-checkbox :customStyle="{ marginBottom: '8px' }" v-for="(item, index) in tagList" :key="item.id"
  360. :label="item.name" :name="item.id">
  361. </u-checkbox>
  362. </u-checkbox-group>
  363. </view>
  364. </u-modal>
  365. <u-modal showCancelButton :show="followUpModelShow" :title="'填写跟进细节'" @confirm="confirmFollowUp"
  366. @cancel="followUpModelShow = false">
  367. <view class="modal-content">
  368. <u--textarea v-model="followUpNotes" placeholder="请输入情况" confirm-type="done"
  369. style="width: 400rpx;margin-bottom: 10rpx; "></u--textarea>
  370. <u-button type="primary" @click="handleShowMoreFollowUp">点击查看更多跟进</u-button>
  371. </view>
  372. </u-modal>
  373. <!-- 更多跟进 -->
  374. <u-modal :show="showMoreFollowUp" title="详细跟进记录" @confirm="showMoreFollowUp = false">
  375. <!-- <view class="followUpBox"> -->
  376. <scroll-view class="followUpBox" scroll-y>
  377. <view v-for="value in currentFollowUp" :key="value.id" class="followUpItem">
  378. <view class="followUpInfo">
  379. <view class="followUpNickname">
  380. 账号:{{ value.createNickname }}
  381. </view>
  382. <view class="followUpOrgName">{{ value.orgName }}</view>
  383. </view>
  384. <view class="followUpContent">{{ value.content }}</view>
  385. </view>
  386. </scroll-view>
  387. <!-- </view> -->
  388. </u-modal>
  389. </view>
  390. </template>
  391. <style scoped lang="scss">
  392. .hasMore {
  393. text-align: center;
  394. padding: 20rpx 0;
  395. font-size: 24rpx;
  396. color: #999;
  397. }
  398. .scrollViewContainer {
  399. height: calc(100vh - 44px - 44px - 27px - 10rpx);
  400. }
  401. .followUpScroll {
  402. height: 600rpx;
  403. }
  404. .scrollView {
  405. height: 100%;
  406. }
  407. /* 订单移动动画 */
  408. .order-move-enter-active,
  409. .order-move-leave-active {
  410. transition: all 0.5s ease;
  411. }
  412. .order-move-enter-from,
  413. .order-move-leave-to {
  414. opacity: 0;
  415. transform: translateY(30px);
  416. }
  417. .order-move-move {
  418. transition: transform 0.5s ease;
  419. }
  420. /* 订单卡片主容器 */
  421. .orderCard {
  422. box-sizing: border-box;
  423. width: 95%;
  424. background-color: #fff;
  425. margin: 20rpx auto;
  426. border-radius: 20rpx;
  427. padding: 20rpx;
  428. }
  429. /* 品牌和价格区域 */
  430. .orderCard .bandAndPrice {
  431. display: flex;
  432. justify-content: space-between;
  433. align-items: center;
  434. }
  435. /* 品牌名称 */
  436. .orderCard .bandAndPrice .bandName {
  437. font-size: 20rpx;
  438. font-weight: 700;
  439. border: 2px solid #2563EB;
  440. padding: 6rpx 12rpx;
  441. border-radius: 15rpx;
  442. background-color: #EFF6FF;
  443. color: #2563EB;
  444. }
  445. /* 价格 */
  446. .orderCard .bandAndPrice .price {
  447. font-size: 30rpx;
  448. font-weight: 700;
  449. }
  450. /* 主要内容行 */
  451. .orderCard .mainLind {
  452. margin-top: 10rpx;
  453. display: flex;
  454. justify-content: space-between;
  455. align-items: center;
  456. gap: 20rpx;
  457. flex-direction: column;
  458. }
  459. /* 主要内容行图片容器 */
  460. .orderCard .mainLind .mainLindImg image {
  461. width: 150rpx;
  462. height: 150rpx;
  463. border-radius: 20rpx;
  464. }
  465. /* 主要内容行信息容器 */
  466. .orderCard .mainLind .mainLindInfo {
  467. display: grid;
  468. grid-template-columns: 1fr 1fr;
  469. flex-direction: column;
  470. gap: 10rpx;
  471. font-size: 24rpx;
  472. color: #6b7280;
  473. text-wrap: nowrap;
  474. .infoItem {
  475. display: flex;
  476. .infoItemTitle {
  477. font-weight: 700;
  478. }
  479. }
  480. }
  481. /* 商品名称 */
  482. .orderCard .mainLind .itemName {
  483. font-size: 30rpx;
  484. font-weight: 700;
  485. color: #374751;
  486. width: 100%;
  487. text-align: left;
  488. }
  489. /* 标签区域 */
  490. .orderCard .tags {
  491. display: flex;
  492. gap: 10rpx;
  493. }
  494. /* 单个标签 */
  495. .orderCard .tags .tag {
  496. font-size: 20rpx;
  497. font-weight: 700;
  498. padding: 6rpx 12rpx;
  499. border-radius: 15rpx;
  500. background-color: #EFF6FF;
  501. color: #fff;
  502. }
  503. /* 按钮区域 */
  504. .orderCard .Btns {
  505. margin-top: 10rpx;
  506. }
  507. /* 按钮组 */
  508. .orderCard .Btns .btnGroup {
  509. display: flex;
  510. justify-content: space-between;
  511. align-items: center;
  512. gap: 20rpx;
  513. }
  514. /* 卡片按钮基础样式 */
  515. .orderCard .Btns .btnGroup .card-button {
  516. font-size: 24rpx;
  517. font-weight: 700;
  518. border: 2rpx solid #2563EB;
  519. padding: 6rpx 12rpx;
  520. border-radius: 15rpx;
  521. background-color: #2563EB;
  522. color: #fff;
  523. width: 45%;
  524. text-align: center;
  525. cursor: pointer;
  526. height: 60rpx;
  527. line-height: 60rpx;
  528. }
  529. /* 忙碌状态按钮 */
  530. .orderCard .Btns .btnGroup .card-button.isBusy {
  531. background-color: #fff;
  532. color: #6B7280;
  533. border-color: #6B7280;
  534. display: flex;
  535. justify-content: center;
  536. }
  537. /* 待跟进状态按钮 */
  538. .orderCard .Btns .btnGroup .card-button.willFollow {
  539. background-color: #EFF6FF;
  540. color: #2563EB;
  541. }
  542. /* 分享按钮 */
  543. .orderCard .Btns .btnGroup .card-button.share {
  544. width: 100%;
  545. }
  546. /* 单独跟进按钮 */
  547. .orderCard .Btns .btnGroup .card-button.oneFollow {
  548. width: 100%;
  549. background-color: #EFF6FF;
  550. color: #2563EB;
  551. }
  552. .cancelBtn {
  553. margin-top: 20rpx;
  554. }
  555. .tagCheckboxGroup {
  556. display: grid;
  557. grid-template-columns: repeat(2, 1fr);
  558. }
  559. .statisticsContainer {
  560. display: flex;
  561. align-items: center;
  562. flex-wrap: nowrap;
  563. white-space: nowrap;
  564. padding: 0 0rpx;
  565. }
  566. .statisticsItem {
  567. display: flex;
  568. justify-content: center;
  569. align-items: center;
  570. background-color: #fff;
  571. padding: 10rpx 20rpx;
  572. border-radius: 15rpx;
  573. font-size: 24rpx;
  574. font-weight: 700;
  575. margin: 0 10rpx;
  576. white-space: nowrap;
  577. flex-shrink: 0;
  578. }
  579. .activeStatusClass {
  580. background-color: #2563EB;
  581. color: #fff;
  582. }
  583. ::v-deep .u-tabs__wrapper__nav__line {
  584. top: 7px;
  585. }
  586. .followUpItem {
  587. background-color: #F7FBFE;
  588. width: 540rpx;
  589. margin: 20rpx;
  590. padding: 20rpx;
  591. box-sizing: border-box;
  592. .followUpInfo {
  593. display: flex;
  594. justify-content: space-between;
  595. align-items: center;
  596. gap: 10rpx;
  597. margin-bottom: 10rpx;
  598. }
  599. .followUpNickname {
  600. font-size: 24rpx;
  601. font-weight: 700;
  602. color: #2563EB;
  603. }
  604. .followUpOrgName {
  605. font-size: 24rpx;
  606. font-weight: 700;
  607. color: #6B7280;
  608. }
  609. .followUpContent {
  610. font-size: 24rpx;
  611. font-weight: 700;
  612. color: #374751;
  613. }
  614. }
  615. .followUpBox {
  616. height: 600rpx;
  617. }
  618. </style>