PageThree.vue 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. <template>
  2. <view class="page-three-container">
  3. <!-- 支付信息卡片 -->
  4. <view class="info-card">
  5. <view class="info-card-title">支付信息</view>
  6. <u-row class="info-row" justify="space-between">
  7. <u-col span="5.8">
  8. <view class="info-label">开户人</view>
  9. <u-input v-model="paymentInfo.customName" placeholder="请输入开户人姓名" class="info-input"
  10. @blur="handleCustomNameInput" />
  11. </u-col>
  12. <u-col span="5.8">
  13. <view class="info-label">银行名称</view>
  14. <u-input v-model="paymentInfo.bankName" placeholder="请输入银行名称" class="info-input"
  15. :disabled="isAlipayPayment" @blur="handleBankNameInput" />
  16. </u-col>
  17. </u-row>
  18. <u-row class="info-row">
  19. <u-col span="12">
  20. <view class="info-label">{{ bankAccountLabel }}</view>
  21. <u-input v-model="paymentInfo.bankAccount" :placeholder="bankAccountPlaceholder" class="info-input"
  22. :type="isAlipayPayment ? 'text' : 'number'" @input="handleBankAccountInput" />
  23. </u-col>
  24. </u-row>
  25. <u-row class="info-row">
  26. <u-col span="12">
  27. <view class="info-label">身份证号</view>
  28. <u-input v-model="paymentInfo.idNumber" placeholder="请输入身份证号" class="info-input"
  29. @blur="handleIdNumberInput" />
  30. </u-col>
  31. </u-row>
  32. <u-row class="info-row">
  33. <u-col span="12">
  34. <view class="info-label">支付方式选择</view>
  35. <u-radio-group iconPlacement="left" v-model="paymentMethodRadio" placement="row"
  36. @change="handlePaymentMethodRadioChange">
  37. <u-radio shape="circle" label="小葫芦线上支付" name="online" />
  38. <u-radio shape="circle" label="小葫芦线上支付宝" name="online_alipay" />
  39. <u-radio shape="circle" label="线下支付" name="offline" />
  40. </u-radio-group>
  41. </u-col>
  42. </u-row>
  43. <u-row class="info-row">
  44. <u-col span="12">
  45. <view class="info-label">支付方式</view>
  46. <u-input :disabled="paymentMethodRadio === 'online'||paymentMethodRadio === 'online_alipay'" v-model="paymentMethod" placeholder="请输入支付方式"
  47. class="info-input" />
  48. </u-col>
  49. </u-row>
  50. </view>
  51. <!-- 高清实物图卡片 -->
  52. <view class="card-wrap">
  53. <view class="detail-image-section">
  54. <view class="detail-image-header">
  55. <text class="detail-image-title">高清实物图(拖拽排序)</text>
  56. <u-button type="primary" v-if="displayImages.length > 0" shape="circle" plain text="核价" size="small" @click.stop="handlePricing"></u-button>
  57. </view>
  58. <view class="detail-image-content">
  59. <view class="detail-image-list">
  60. <view v-for="(item, index) in displayImages" :key="item.id || `detail-${index}`" class="detail-image-item"
  61. :class="{
  62. 'dragging': draggingIndex === index,
  63. 'can-drop': canDropIndex === index && draggingIndex !== index
  64. }" :style="draggingIndex === index ? draggingStyle : ''" @touchstart.stop="onTouchStart($event, index)"
  65. @touchmove.stop="onTouchMove($event, index)" @touchend.stop="onTouchEnd">
  66. <PicComp :src="item.fileUrl" @needPreviewPic="previewImageDetail" />
  67. <view class="image-type-tag">{{ getImageType(index) }}</view>
  68. <view class="detail-delete-btn" @click.stop="handleHideImage(item, index)">
  69. ×
  70. </view>
  71. </view>
  72. <view class="detail-upload-btn" @click="handleUploadImage">
  73. <u-icon name="plus" size="40rpx" color="#999" />
  74. </view>
  75. </view>
  76. </view>
  77. </view>
  78. </view>
  79. <!-- 支付总额卡片 -->
  80. <view class="card-wrap payment-card">
  81. <view class="payment-section">
  82. <view class="payment-total-container">
  83. <text class="payment-label">支付总额</text>
  84. <u-input v-model="paymentAmount" class="payment-amount" type="number" decimal="2" prefix="¥" />
  85. </view>
  86. <view class="payment-buttons-row">
  87. <view class="payment-button" @click="handleUnpaidClick">
  88. <u-icon name="star" size="40rpx" color="#ff9500" />
  89. <text class="button-text">未收</text>
  90. </view>
  91. <view class="payment-button" @click="handleFollowUpClick">
  92. <u-icon name="chat" size="40rpx" color="#108cff" />
  93. <text class="button-text">待跟进</text>
  94. </view>
  95. </view>
  96. <view class="pay-now-button" @click="handlePayNowClick">
  97. <text class="button-text">立即支付</text>
  98. </view>
  99. </view>
  100. </view>
  101. <!-- 下一步按钮 -->
  102. <u-button class="next-btn" @click="handleNext" type="primary" size="middle">
  103. 下一步
  104. </u-button>
  105. <!-- 未收评级模态窗 -->
  106. <u-modal showCancelButton showConfirmButton @confirm="confirmUnpaid" @cancel="unpaidModalVisible = false"
  107. :show="unpaidModalVisible" title="未收评级">
  108. <view class="modal-content">
  109. <u-rate v-model="unpaidRating" :count="5" :size="50" active-color="#ff9500" />
  110. </view>
  111. </u-modal>
  112. <!-- 待跟进模态窗 -->
  113. <u-modal showCancelButton showConfirmButton @confirm="confirmFollowUp" @cancel="followUpModalVisible = false"
  114. :show="followUpModalVisible" title="填写跟进细节">
  115. <view class="modal-content">
  116. <u--textarea v-model="followUpNotes" placeholder="请输入情况" confirm-type="done"
  117. style="width: 100%; margin-bottom: 30rpx;" />
  118. </view>
  119. </u-modal>
  120. <!-- 确认支付模态窗 -->
  121. <u-modal showCancelButton showConfirmButton @confirm="confirmRiskWarning" @cancel="riskWarningModalVisible = false"
  122. confirmText="确认并继续付款" :show="riskWarningModalVisible" title="付款警示" :content="'湖南耒阳地区身份证号请确认!'">
  123. </u-modal>
  124. <!-- 核价对话框 -->
  125. <add-inquiry-dialog ref="pricingDialog" :clueId="pricingClueId" :editOrAdd="pricingEditOrAdd"
  126. :editInfo="pricingEditInfo" :type="2" />
  127. <u-modal :show="payNowModalVisible" title="确认支付信息" :showConfirmButton="false">
  128. <view class="modal-content">
  129. <view class="payment-amount-display">¥{{ paymentAmount }}</view>
  130. <view class="payment-info-section">
  131. <view class="info-item">
  132. <text class="info-label">收款姓名:</text>
  133. <text class="info-value">{{ paymentInfo.customName || '未填写' }}</text>
  134. </view>
  135. <view class="info-item">
  136. <text class="info-label">开户银行:</text>
  137. <text class="info-value">{{ paymentInfo.bankName || '未填写' }}</text>
  138. </view>
  139. <view class="info-item">
  140. <text class="info-label">银行卡号:</text>
  141. <text class="info-value">{{ paymentInfo.bankAccount || '未填写' }}</text>
  142. </view>
  143. <view class="info-item">
  144. <text class="info-label">支付方式:</text>
  145. <text class="info-value">{{ paymentMethod || '未填写' }}</text>
  146. </view>
  147. </view>
  148. <u-button type="primary" size="large" @click="confirmTransfer" style="margin-top: 40rpx;">
  149. 确认转账
  150. </u-button>
  151. <u-button type="primary" :plain="true" @click="payNowModalVisible = false" size="large"
  152. style="margin-top: 20rpx;">
  153. 取消
  154. </u-button>
  155. </view>
  156. </u-modal>
  157. </view>
  158. </template>
  159. <script>
  160. import PicComp from './PicComp.vue'
  161. import imageUpload from '../utils/imageUpload.js'
  162. import addInquiryDialog from '@/components/add-inquiry-dialog/index.vue'
  163. export default {
  164. name: 'PageThree',
  165. components: {
  166. PicComp,
  167. addInquiryDialog
  168. },
  169. props: {
  170. orderDetail: {
  171. type: Object,
  172. default: () => ({})
  173. },
  174. orderId: {
  175. type: String,
  176. default: ''
  177. },
  178. currentReceipt: {
  179. type: Object,
  180. default: () => ({})
  181. }
  182. },
  183. data() {
  184. return {
  185. paymentInfo: {
  186. customName: '',
  187. bankName: '',
  188. bankAccount: '',
  189. idNumber: ''
  190. },
  191. paymentMethodRadio: 'offline',
  192. paymentMethod: '',
  193. paymentAmount: '0.00',
  194. detailImages: [],
  195. // 拖拽相关
  196. draggingIndex: -1,
  197. canDropIndex: -1,
  198. startX: 0,
  199. startY: 0,
  200. currentX: 0,
  201. currentY: 0,
  202. // 模态窗
  203. unpaidModalVisible: false,
  204. followUpModalVisible: false,
  205. payNowModalVisible: false,
  206. riskWarningModalVisible: false,
  207. unpaidRating: 0,
  208. followUpNotes: '',
  209. // 核价相关
  210. pricingClueId: '',
  211. pricingEditOrAdd: 'receptFormAdd',
  212. pricingEditInfo: {}
  213. }
  214. },
  215. computed: {
  216. // 显示前6个图片用于拖拽
  217. displayImages() {
  218. return this.detailImages.slice(0, 6)
  219. },
  220. // 拖拽时的样式
  221. draggingStyle() {
  222. if (this.draggingIndex === -1) return ''
  223. return {
  224. transform: `translate(${this.currentX - this.startX}px, ${this.currentY - this.startY}px)`,
  225. zIndex: 1000
  226. }
  227. },
  228. // 是否为支付宝支付
  229. isAlipayPayment() {
  230. return this.paymentMethodRadio === 'online_alipay'
  231. },
  232. // 银行账号标签
  233. bankAccountLabel() {
  234. return this.isAlipayPayment ? '支付宝账号' : '银行账号'
  235. },
  236. // 银行账号占位符
  237. bankAccountPlaceholder() {
  238. return this.isAlipayPayment ? '请输入支付宝账号' : '请输入银行账号'
  239. }
  240. },
  241. watch: {
  242. orderDetail: {
  243. handler(newVal) {
  244. if (newVal) {
  245. this.paymentInfo.customName = newVal.customName || ''
  246. this.paymentInfo.bankName = newVal.bankName || ''
  247. this.paymentInfo.bankAccount = newVal.bankCardNumber || ''
  248. this.paymentInfo.idNumber = newVal.idCard || ''
  249. this.initPaymentMethod(newVal.paymentMethod)
  250. }
  251. },
  252. deep: true,
  253. immediate: true
  254. },
  255. currentReceipt: {
  256. handler(newVal) {
  257. if (newVal) {
  258. this.paymentAmount = newVal.tableFee || '0.00'
  259. this.loadDetailImages()
  260. }
  261. },
  262. deep: true,
  263. immediate: true
  264. }
  265. },
  266. methods: {
  267. /**
  268. * 刷新图片列表(供父组件调用)
  269. */
  270. async refreshImageList() {
  271. await this.loadDetailImages()
  272. },
  273. /**
  274. * 加载细节图
  275. */
  276. async loadDetailImages() {
  277. if (!this.currentReceipt.id || !this.orderDetail.itemBrand) return
  278. try {
  279. const list = await imageUpload.getFileList(
  280. '2',
  281. '3',
  282. this.currentReceipt.id,
  283. this.orderDetail.itemBrand,
  284. this.currentReceipt.clueId
  285. )
  286. // 按照 fileIds 排序
  287. if (this.currentReceipt.fileIds && list && list.length > 0) {
  288. const sortedIds = this.currentReceipt.fileIds.split(',')
  289. list.sort((a, b) => {
  290. const indexA = sortedIds.indexOf(a.id)
  291. const indexB = sortedIds.indexOf(b.id)
  292. // 如果都不在列表中,保持原顺序
  293. if (indexA === -1 && indexB === -1) return 0
  294. // 如果 a 不在列表中,放到后面
  295. if (indexA === -1) return 1
  296. // 如果 b 不在列表中,放到后面
  297. if (indexB === -1) return -1
  298. // 都在列表中,按 index 排序
  299. return indexA - indexB
  300. })
  301. }
  302. this.detailImages = list || []
  303. } catch (error) {
  304. console.error('加载细节图失败:', error)
  305. }
  306. },
  307. /**
  308. * 初始化支付方式
  309. */
  310. initPaymentMethod(value) {
  311. if (value === '小葫芦线上支付') {
  312. this.paymentMethod = '小葫芦线上支付'
  313. this.paymentMethodRadio = 'online'
  314. } else if (value === '小葫芦线上支付宝') {
  315. this.paymentMethod = '小葫芦线上支付宝'
  316. this.paymentMethodRadio = 'online_alipay'
  317. this.paymentInfo.bankName = '支付宝'
  318. } else {
  319. this.paymentMethod = value || ''
  320. this.paymentMethodRadio = 'offline'
  321. }
  322. },
  323. /**
  324. * 支付方式选择改变
  325. */
  326. handlePaymentMethodRadioChange(value) {
  327. if (value === 'online') {
  328. this.paymentMethod = '小葫芦线上支付'
  329. // 恢复银行名称输入框
  330. if (this.paymentInfo.bankName === '支付宝') {
  331. this.paymentInfo.bankName = ''
  332. }
  333. } else if (value === 'online_alipay') {
  334. this.paymentMethod = '小葫芦线上支付宝'
  335. // 自动设置银行名称为支付宝
  336. this.paymentInfo.bankName = '支付宝'
  337. } else {
  338. this.paymentMethod = ''
  339. // 恢复银行名称输入框
  340. if (this.paymentInfo.bankName === '支付宝') {
  341. this.paymentInfo.bankName = ''
  342. }
  343. }
  344. },
  345. /**
  346. * 开户人输入处理 - 只允许中文
  347. */
  348. handleCustomNameInput(value) {
  349. // 只保留中文字符(包括中文标点)
  350. const chineseReg = /[^\u4e00-\u9fa5]/g
  351. this.paymentInfo.customName = String(value || '').replace(chineseReg, '')
  352. },
  353. /**
  354. * 银行名称输入处理 - 只允许中文
  355. */
  356. handleBankNameInput(value) {
  357. // 只保留中文字符(包括中文标点)
  358. const chineseReg = /[^\u4e00-\u9fa5]/g
  359. this.paymentInfo.bankName = String(value || '').replace(chineseReg, '')
  360. },
  361. /**
  362. * 银行账号输入处理 - 只允许数字
  363. */
  364. handleBankAccountInput(value) {
  365. // 只保留数字
  366. const numberReg = /[^\d]/g
  367. this.paymentInfo.bankAccount = String(value || '').replace(numberReg, '')
  368. },
  369. /**
  370. * 身份证号输入处理 - 允许数字和X
  371. */
  372. handleIdNumberInput(value) {
  373. // 只保留数字和X
  374. const reg = /[^\dxX]/g
  375. this.paymentInfo.idNumber = String(value || '').replace(reg, '')
  376. },
  377. /**
  378. * 获取图片类型
  379. */
  380. getImageType(index) {
  381. const types = ['正面', '反面', '侧面', '扣子', '编号']
  382. return types[index] || `细节${index - 4}`
  383. },
  384. /**
  385. * 触摸开始
  386. */
  387. onTouchStart(event, index) {
  388. if (this.draggingIndex !== -1) return
  389. this.draggingIndex = index
  390. const touch = event.touches[0]
  391. this.startX = touch.clientX
  392. this.startY = touch.clientY
  393. this.currentX = touch.clientX
  394. this.currentY = touch.clientY
  395. },
  396. /**
  397. * 触摸移动
  398. */
  399. onTouchMove(event, index) {
  400. if (this.draggingIndex === -1 || this.draggingIndex !== index) return
  401. const touch = event.touches[0]
  402. this.currentX = touch.clientX
  403. this.currentY = touch.clientY
  404. this.findTargetIndex(touch.clientX, touch.clientY)
  405. },
  406. /**
  407. * 触摸结束
  408. */
  409. async onTouchEnd() {
  410. if (this.draggingIndex === -1) return
  411. if (this.canDropIndex !== -1 && this.canDropIndex !== this.draggingIndex) {
  412. // 交换位置
  413. const images = [...this.detailImages]
  414. const temp = images[this.draggingIndex]
  415. images[this.draggingIndex] = images[this.canDropIndex]
  416. images[this.canDropIndex] = temp
  417. this.detailImages = images
  418. }
  419. this.resetDragState()
  420. //每次拖拽结束后把新的顺序传送给接口
  421. const fileIds = this.detailImages.map(item => item.id).join(',')
  422. await uni.$u.api.updateReceiptForm({
  423. id: this.currentReceipt.id,
  424. fileIds: fileIds
  425. })
  426. this.$emit('update-file-ids', fileIds)
  427. },
  428. /**
  429. * 查找目标索引
  430. */
  431. findTargetIndex(x, y) {
  432. const query = uni.createSelectorQuery().in(this)
  433. query.selectAll('.detail-image-item').boundingClientRect((rects) => {
  434. if (!rects || rects.length === 0) return
  435. let targetIndex = -1
  436. for (let i = 0; i < rects.length; i++) {
  437. if (i === this.draggingIndex) continue
  438. const rect = rects[i]
  439. if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
  440. targetIndex = i
  441. break
  442. }
  443. }
  444. this.canDropIndex = targetIndex
  445. }).exec()
  446. },
  447. /**
  448. * 重置拖拽状态
  449. */
  450. resetDragState() {
  451. this.draggingIndex = -1
  452. this.canDropIndex = -1
  453. this.startX = 0
  454. this.startY = 0
  455. this.currentX = 0
  456. this.currentY = 0
  457. },
  458. /**
  459. * 上传图片
  460. */
  461. async handleUploadImage() {
  462. try {
  463. const filePaths = await imageUpload.chooseImage(9)
  464. const uploadResults = await imageUpload.uploadFiles(filePaths)
  465. await imageUpload.bindOrderFile(
  466. this.currentReceipt.clueId,
  467. this.currentReceipt.id,
  468. '3',
  469. uploadResults
  470. )
  471. await this.loadDetailImages()
  472. //上传新图片完成之后也要把新数据给接口
  473. const fileIds = this.detailImages.map(item => item.id).join(',')
  474. await uni.$u.api.updateReceiptForm({
  475. id: this.currentReceipt.id,
  476. fileIds: fileIds
  477. })
  478. this.$emit('update-file-ids', fileIds)
  479. } catch (error) {
  480. console.error('上传失败:', error)
  481. }
  482. },
  483. /**
  484. * 隐藏图片
  485. */
  486. async handleHideImage(item, index) {
  487. const itemIndex = this.detailImages.findIndex(img => img.id === item.id || img.fileUrl === item.fileUrl)
  488. if (itemIndex !== -1) {
  489. this.detailImages.splice(itemIndex, 1)
  490. // 更新 fileIds
  491. const fileIds = this.detailImages.map(item => item.id).join(',')
  492. try {
  493. await uni.$u.api.updateReceiptForm({
  494. id: this.currentReceipt.id,
  495. fileIds: fileIds
  496. })
  497. this.$emit('update-file-ids', fileIds)
  498. uni.$u.toast('图片已隐藏')
  499. } catch (error) {
  500. console.error('更新失败:', error)
  501. }
  502. }
  503. },
  504. /**
  505. * 预览图片
  506. */
  507. previewImageDetail(src) {
  508. const urlList = this.detailImages.map(item => item.fileUrl)
  509. uni.previewImage({
  510. urls: urlList,
  511. current: src
  512. })
  513. },
  514. /**
  515. * 未收点击
  516. */
  517. handleUnpaidClick() {
  518. this.unpaidModalVisible = true
  519. },
  520. /**
  521. * 待跟进点击
  522. */
  523. handleFollowUpClick() {
  524. this.followUpModalVisible = true
  525. },
  526. /**
  527. * 立即支付点击
  528. */
  529. async handlePayNowClick() {
  530. // 保存支付信息
  531. await uni.$u.api.updateReceiptForm({
  532. id: this.currentReceipt.id,
  533. tableFee: this.paymentAmount,
  534. fileIds: this.detailImages.map(item => item.id).join(',')
  535. })
  536. await uni.$u.api.updateClueOrderForm({
  537. id: this.orderDetail.id,
  538. customName: this.paymentInfo.customName || '',
  539. bankName: this.paymentInfo.bankName || '',
  540. bankCardNumber: this.paymentInfo.bankAccount || '',
  541. idCard: this.paymentInfo.idNumber || '',
  542. // paymentMethod: this.paymentMethod || ''
  543. })
  544. if (!this.paymentInfo.customName || !this.paymentInfo.bankName ||
  545. !this.paymentInfo.bankAccount || !this.paymentInfo.idNumber || !this.paymentMethod) {
  546. uni.$u.toast('请填写完整的支付信息')
  547. return
  548. }
  549. if (this.paymentAmount <= 0) {
  550. uni.$u.toast('请填写正确的支付总额')
  551. return
  552. }
  553. //判断当前账号是否敏感地区
  554. if (String(this.paymentInfo.idNumber).startsWith('430481')) {
  555. this.riskWarningModalVisible = true
  556. return
  557. }
  558. this.payNowModalVisible = true
  559. },
  560. /**
  561. * 确认风险警示
  562. */
  563. confirmRiskWarning() {
  564. this.riskWarningModalVisible = false
  565. this.payNowModalVisible = true
  566. },
  567. /**
  568. * 确认转账
  569. */
  570. async confirmTransfer() {
  571. this.payNowModalVisible = false
  572. await uni.$u.api.updateClueOrderForm({
  573. id: this.orderDetail.id,
  574. paymentMethod: this.paymentMethod || ''
  575. })
  576. //如果是小葫芦线上支付或者小葫芦线上支付宝就调用接口,如果不是小葫芦线上支付就不要调用接口,直接点击下一步
  577. if (this.paymentMethod === '小葫芦线上支付' || this.paymentMethod === '小葫芦线上支付宝') {
  578. this.$emit('confirm-pay')
  579. } else {
  580. this.handleNext()
  581. }
  582. },
  583. /**
  584. * 确认未收
  585. */
  586. async confirmUnpaid() {
  587. try {
  588. await uni.$u.api.addOrderFollow({
  589. orderId: this.orderId,
  590. content: `未收评分_${this.unpaidRating}`
  591. })
  592. await uni.$u.api.oderForm({
  593. status: '4',
  594. id: this.orderId
  595. })
  596. uni.$u.toast('提交未收评级成功')
  597. this.unpaidModalVisible = false
  598. } catch (error) {
  599. console.error('提交失败:', error)
  600. uni.$u.toast('提交失败')
  601. }
  602. },
  603. /**
  604. * 确认跟进
  605. */
  606. async confirmFollowUp() {
  607. try {
  608. await uni.$u.api.addOrderFollow({
  609. orderId: this.orderId,
  610. content: `待跟进_${this.followUpNotes}`
  611. })
  612. uni.$u.toast('提交待跟进记录成功')
  613. this.followUpModalVisible = false
  614. this.followUpNotes = ''
  615. } catch (error) {
  616. console.error('提交失败:', error)
  617. uni.$u.toast('提交失败')
  618. }
  619. },
  620. /**
  621. * 下一步
  622. */
  623. async handleNext() {
  624. await uni.$u.api.updateReceiptForm({
  625. id: this.currentReceipt.id,
  626. tableFee: this.paymentAmount,
  627. fileIds: this.detailImages.map(item => item.id).join(',')
  628. })
  629. await uni.$u.api.updateClueOrderForm({
  630. id: this.orderDetail.id,
  631. customName: this.paymentInfo.customName || '',
  632. bankName: this.paymentInfo.bankName || '',
  633. bankCardNumber: this.paymentInfo.bankAccount || '',
  634. idCard: this.paymentInfo.idNumber || ''
  635. })
  636. this.$emit('save', {
  637. nowPage: 'formThree',
  638. form: {
  639. ...this.paymentInfo
  640. },
  641. fileIds: this.detailImages.map(item => item.id).join(',')
  642. })
  643. this.$emit('next', {
  644. nowPage: 'formThree',
  645. form: {
  646. ...this.paymentInfo
  647. }
  648. })
  649. },
  650. /**
  651. * 核价
  652. */
  653. async handlePricing() {
  654. const brandList = await this.$getDicts("crm_form_brand");
  655. if (!this.currentReceipt || !this.currentReceipt.clueId) {
  656. uni.$u.toast('缺少线索ID')
  657. return
  658. }
  659. if (!this.currentReceipt.brand) {
  660. uni.$u.toast('缺少品牌信息')
  661. return
  662. }
  663. if (!this.displayImages || this.displayImages.length === 0) {
  664. uni.$u.toast('请先上传图片')
  665. return
  666. }
  667. this.pricingClueId = this.currentReceipt.clueId
  668. // brand 是品牌的 id(dictValue),itemBrand 是品牌的 label(dictLabel)
  669. const brandDictLabel = this.currentReceipt.brand
  670. const brandDictValue = brandList.find(item => item.dictLabel === this.currentReceipt.brand).dictValue;
  671. // 将图片转换为 imgsUrl 格式
  672. const imgsUrl = this.displayImages.map(item => item.fileUrl).filter(url => url)
  673. // 检查是否已有核价记录
  674. try {
  675. const data = {
  676. clueId: this.currentReceipt.clueId,
  677. type: 2
  678. }
  679. const res = await uni.$u.api.inquiryDetail(data)
  680. if (res.code === 200 && res.data) {
  681. // 编辑模式:保留原有数据,但更新品牌和图片
  682. this.pricingEditOrAdd = 'editForm'
  683. this.pricingEditInfo = {
  684. ...res.data,
  685. dictLabel: brandDictLabel || res.data.dictLabel,
  686. dictValue: brandDictValue || res.data.dictValue,
  687. imgsUrl: imgsUrl.length > 0 ? imgsUrl : (res.data.imgsUrl || [])
  688. }
  689. this.$nextTick(() => {
  690. this.$refs.pricingDialog.showDialog()
  691. })
  692. } else {
  693. // 新增模式:设置品牌和图片
  694. this.pricingEditOrAdd = 'editForm'
  695. this.pricingEditInfo = {
  696. dictLabel: brandDictLabel,
  697. dictValue: brandDictValue,
  698. imgsUrl: imgsUrl,
  699. model: '',
  700. code: '',
  701. price: ''
  702. }
  703. this.$nextTick(() => {
  704. this.$refs.pricingDialog.showDialog()
  705. })
  706. }
  707. } catch (error) {
  708. // 如果没有记录,则新增
  709. this.pricingEditOrAdd = 'receptFormAdd'
  710. this.pricingEditInfo = {
  711. dictLabel: brandDictLabel,
  712. dictValue: brandDictValue,
  713. imgsUrl: imgsUrl,
  714. model: '',
  715. code: '',
  716. price: ''
  717. }
  718. this.$nextTick(() => {
  719. this.$refs.pricingDialog.showDialog()
  720. })
  721. }
  722. },
  723. }
  724. }
  725. </script>
  726. <style scoped lang="scss">
  727. @import '../styles/common.scss';
  728. .page-three-container {
  729. @extend .page-container;
  730. padding-bottom: 100rpx;
  731. }
  732. .info-card {
  733. @extend .card-wrap;
  734. padding: 20rpx;
  735. margin-top: 20rpx;
  736. box-sizing: border-box;
  737. width: 100%;
  738. max-width: 100%;
  739. }
  740. .info-card-title {
  741. @include font-styles($size: title, $weight: bold, $color: primary);
  742. margin-bottom: 25rpx;
  743. padding-bottom: 15rpx;
  744. border-bottom: 1rpx solid map-get($colors, border);
  745. }
  746. .info-row {
  747. margin-bottom: 20rpx;
  748. }
  749. .info-label {
  750. @include font-styles($size: tiny, $weight: regular, $color: tertiary);
  751. margin-bottom: 8rpx;
  752. display: block;
  753. }
  754. .info-input {
  755. border-radius: 8rpx;
  756. border: 1rpx solid #e5e7eb;
  757. padding: 12rpx 16rpx;
  758. width: 100%;
  759. box-sizing: border-box;
  760. }
  761. .detail-image-section {
  762. padding: 20rpx;
  763. }
  764. .detail-image-header {
  765. display: grid;
  766. grid-template-columns: 1fr auto;
  767. margin-bottom: 20rpx;
  768. padding-bottom: 20rpx;
  769. border-bottom: 1rpx solid map-get($colors, border);
  770. }
  771. .detail-image-title {
  772. @include font-styles($size: content, $weight: bold, $color: primary);
  773. }
  774. .detail-image-list {
  775. display: flex;
  776. flex-wrap: wrap;
  777. gap: 20rpx;
  778. position: relative;
  779. }
  780. .detail-image-item {
  781. position: relative;
  782. width: 200rpx;
  783. height: 200rpx;
  784. touch-action: none;
  785. transition: transform 0.2s ease, opacity 0.2s ease;
  786. z-index: 1;
  787. box-sizing: border-box;
  788. &.dragging {
  789. opacity: 0.6;
  790. transform: scale(1.05);
  791. z-index: 999;
  792. box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.2);
  793. }
  794. &.can-drop {
  795. outline: 2rpx dashed #108cff;
  796. outline-offset: -2rpx;
  797. background-color: rgba(16, 140, 255, 0.1);
  798. border-radius: 8rpx;
  799. }
  800. }
  801. .image-type-tag {
  802. position: absolute;
  803. top: 10rpx;
  804. left: 10rpx;
  805. background-color: rgba(0, 0, 0, 0.6);
  806. color: white;
  807. padding: 5rpx 10rpx;
  808. border-radius: 12rpx;
  809. font-size: 22rpx;
  810. z-index: 1;
  811. }
  812. .detail-delete-btn {
  813. position: absolute;
  814. top: -10rpx;
  815. right: -10rpx;
  816. width: 40rpx;
  817. height: 40rpx;
  818. background-color: #ff4d4f;
  819. color: #fff;
  820. border-radius: 50%;
  821. display: flex;
  822. align-items: center;
  823. justify-content: center;
  824. font-weight: bold;
  825. z-index: 10;
  826. cursor: pointer;
  827. }
  828. .detail-upload-btn {
  829. width: 200rpx;
  830. height: 200rpx;
  831. border: 8rpx dashed #ddd;
  832. border-radius: 30rpx;
  833. display: flex;
  834. align-items: center;
  835. justify-content: center;
  836. background-color: #f9f9f9;
  837. cursor: pointer;
  838. }
  839. .pricing-button {
  840. margin-top: 0;
  841. }
  842. .payment-card {
  843. margin-top: 20rpx;
  844. }
  845. .payment-section {
  846. padding: 20rpx;
  847. }
  848. .payment-total-container {
  849. background-color: #f5f7fa;
  850. border: 2rpx solid #e5e7eb;
  851. border-radius: 12rpx;
  852. padding: 0rpx 30rpx;
  853. display: flex;
  854. align-items: center;
  855. justify-content: space-between;
  856. margin-bottom: 24rpx;
  857. }
  858. .payment-label {
  859. font-size: 36rpx;
  860. font-weight: 700;
  861. min-width: 140rpx;
  862. }
  863. .payment-amount {
  864. font-size: 48rpx;
  865. font-weight: 600;
  866. color: #f53f3f;
  867. width: auto;
  868. min-width: 150rpx;
  869. border: none;
  870. text-align: right !important;
  871. }
  872. .payment-buttons-row {
  873. display: flex;
  874. gap: 20rpx;
  875. margin-bottom: 24rpx;
  876. }
  877. .payment-button {
  878. flex: 1;
  879. border-radius: 12rpx;
  880. padding: 5rpx 0;
  881. display: flex;
  882. flex-direction: column;
  883. align-items: center;
  884. justify-content: center;
  885. background-color: #f5f7fa;
  886. border: 2rpx solid #e5e7eb;
  887. cursor: pointer;
  888. gap: 12rpx;
  889. }
  890. .pay-now-button {
  891. width: 100%;
  892. border-radius: 12rpx;
  893. padding: 32rpx 0;
  894. display: flex;
  895. flex-direction: column;
  896. align-items: center;
  897. justify-content: center;
  898. background-color: #108cff;
  899. color: #fff;
  900. cursor: pointer;
  901. box-shadow: 0 4rpx 12rpx rgba(16, 140, 255, 0.2);
  902. }
  903. .button-text {
  904. font-size: 28rpx;
  905. font-weight: 500;
  906. color: inherit;
  907. }
  908. .modal-content {
  909. width: 100%;
  910. padding: 40rpx 20rpx;
  911. display: flex;
  912. flex-direction: column;
  913. align-items: center;
  914. }
  915. .payment-amount-display {
  916. font-size: 64rpx;
  917. font-weight: bold;
  918. color: #108cff;
  919. text-align: center;
  920. margin-bottom: 40rpx;
  921. width: 100%;
  922. }
  923. .payment-info-section {
  924. width: 100%;
  925. background-color: #f5f7fa;
  926. border: 2rpx solid #e5e7eb;
  927. border-radius: 12rpx;
  928. padding: 30rpx 20rpx;
  929. margin-bottom: 40rpx;
  930. }
  931. .info-item {
  932. display: flex;
  933. margin-bottom: 20rpx;
  934. align-items: center;
  935. justify-content: space-between;
  936. &:last-child {
  937. margin-bottom: 0;
  938. }
  939. }
  940. .next-btn {
  941. position: fixed;
  942. bottom: 10rpx;
  943. left: 2.5%;
  944. width: 95%;
  945. height: 80rpx;
  946. line-height: 80rpx;
  947. text-align: center;
  948. border-radius: 20rpx;
  949. z-index: 1000;
  950. }
  951. </style>