PageThree.vue 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  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="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, oldVal) {
  257. if (newVal) {
  258. this.paymentAmount = newVal.tableFee || '0.00'
  259. // 只有当 receipt id 变化时才重新加载图片,避免 fileIds 更新时重新加载
  260. if (!oldVal || oldVal.id !== newVal.id) {
  261. this.loadDetailImages()
  262. }
  263. }
  264. },
  265. deep: true,
  266. immediate: true
  267. }
  268. },
  269. methods: {
  270. /**
  271. * 刷新图片列表(供父组件调用)
  272. */
  273. async refreshImageList() {
  274. await this.loadDetailImages()
  275. },
  276. /**
  277. * 加载细节图
  278. */
  279. async loadDetailImages() {
  280. if (!this.currentReceipt.id || !this.orderDetail.itemBrand) return
  281. try {
  282. const list = await imageUpload.getFileList(
  283. '2',
  284. '3',
  285. this.currentReceipt.id,
  286. this.orderDetail.itemBrand,
  287. this.currentReceipt.clueId
  288. )
  289. // 按照 fileIds 排序
  290. if (this.currentReceipt.fileIds && list && list.length > 0) {
  291. const sortedIds = this.currentReceipt.fileIds.split(',')
  292. list.sort((a, b) => {
  293. const indexA = sortedIds.indexOf(a.id)
  294. const indexB = sortedIds.indexOf(b.id)
  295. // 如果都不在列表中,保持原顺序
  296. if (indexA === -1 && indexB === -1) return 0
  297. // 如果 a 不在列表中,放到后面
  298. if (indexA === -1) return 1
  299. // 如果 b 不在列表中,放到后面
  300. if (indexB === -1) return -1
  301. // 都在列表中,按 index 排序
  302. return indexA - indexB
  303. })
  304. }
  305. this.detailImages = list || []
  306. } catch (error) {
  307. console.error('加载细节图失败:', error)
  308. }
  309. },
  310. /**
  311. * 初始化支付方式
  312. */
  313. initPaymentMethod(value) {
  314. if (value === '小葫芦线上支付') {
  315. this.paymentMethod = '小葫芦线上支付'
  316. this.paymentMethodRadio = 'online'
  317. } else if (value === '小葫芦线上支付宝') {
  318. this.paymentMethod = '小葫芦线上支付宝'
  319. this.paymentMethodRadio = 'online_alipay'
  320. this.paymentInfo.bankName = '支付宝'
  321. } else {
  322. this.paymentMethod = value || ''
  323. this.paymentMethodRadio = 'offline'
  324. }
  325. },
  326. /**
  327. * 支付方式选择改变
  328. */
  329. handlePaymentMethodRadioChange(value) {
  330. if (value === 'online') {
  331. this.paymentMethod = '小葫芦线上支付'
  332. // 恢复银行名称输入框
  333. if (this.paymentInfo.bankName === '支付宝') {
  334. this.paymentInfo.bankName = ''
  335. }
  336. } else if (value === 'online_alipay') {
  337. this.paymentMethod = '小葫芦线上支付宝'
  338. // 自动设置银行名称为支付宝
  339. this.paymentInfo.bankName = '支付宝'
  340. } else {
  341. this.paymentMethod = ''
  342. // 恢复银行名称输入框
  343. if (this.paymentInfo.bankName === '支付宝') {
  344. this.paymentInfo.bankName = ''
  345. }
  346. }
  347. },
  348. /**
  349. * 开户人输入处理 - 只允许中文
  350. */
  351. handleCustomNameInput(value) {
  352. // 只保留中文字符(包括中文标点)
  353. const chineseReg = /[^\u4e00-\u9fa5]/g
  354. this.paymentInfo.customName = String(value || '').replace(chineseReg, '')
  355. },
  356. /**
  357. * 银行名称输入处理 - 只允许中文
  358. */
  359. handleBankNameInput(value) {
  360. // 只保留中文字符(包括中文标点)
  361. const chineseReg = /[^\u4e00-\u9fa5]/g
  362. this.paymentInfo.bankName = String(value || '').replace(chineseReg, '')
  363. },
  364. /**
  365. * 银行账号输入处理 - 只允许数字
  366. */
  367. handleBankAccountInput(value) {
  368. // 只保留数字
  369. const numberReg = /[^\d]/g
  370. this.paymentInfo.bankAccount = String(value || '').replace(numberReg, '')
  371. },
  372. /**
  373. * 身份证号输入处理 - 允许数字和X
  374. */
  375. handleIdNumberInput(value) {
  376. // 只保留数字和X
  377. const reg = /[^\dxX]/g
  378. this.paymentInfo.idNumber = String(value || '').replace(reg, '')
  379. },
  380. /**
  381. * 获取图片类型
  382. */
  383. getImageType(index) {
  384. const types = ['正面', '反面', '侧面', '扣子', '编号']
  385. return types[index] || `细节${index - 4}`
  386. },
  387. /**
  388. * 触摸开始
  389. */
  390. onTouchStart(event, index) {
  391. if (this.draggingIndex !== -1) return
  392. this.draggingIndex = index
  393. const touch = event.touches[0]
  394. this.startX = touch.clientX
  395. this.startY = touch.clientY
  396. this.currentX = touch.clientX
  397. this.currentY = touch.clientY
  398. },
  399. /**
  400. * 触摸移动
  401. */
  402. onTouchMove(event, index) {
  403. if (this.draggingIndex === -1 || this.draggingIndex !== index) return
  404. const touch = event.touches[0]
  405. this.currentX = touch.clientX
  406. this.currentY = touch.clientY
  407. this.findTargetIndex(touch.clientX, touch.clientY)
  408. },
  409. /**
  410. * 触摸结束
  411. */
  412. async onTouchEnd() {
  413. if (this.draggingIndex === -1) return
  414. if (this.canDropIndex !== -1 && this.canDropIndex !== this.draggingIndex) {
  415. // 交换位置
  416. const images = [...this.detailImages]
  417. const temp = images[this.draggingIndex]
  418. images[this.draggingIndex] = images[this.canDropIndex]
  419. images[this.canDropIndex] = temp
  420. this.detailImages = images
  421. }
  422. this.resetDragState()
  423. //每次拖拽结束后把新的顺序传送给接口
  424. const fileIds = this.detailImages.map(item => item.id).join(',')
  425. await uni.$u.api.updateReceiptForm({
  426. id: this.currentReceipt.id,
  427. fileIds: fileIds
  428. })
  429. this.$emit('update-file-ids', fileIds)
  430. },
  431. /**
  432. * 查找目标索引
  433. */
  434. findTargetIndex(x, y) {
  435. const query = uni.createSelectorQuery().in(this)
  436. query.selectAll('.detail-image-item').boundingClientRect((rects) => {
  437. if (!rects || rects.length === 0) return
  438. let targetIndex = -1
  439. for (let i = 0; i < rects.length; i++) {
  440. if (i === this.draggingIndex) continue
  441. const rect = rects[i]
  442. if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
  443. targetIndex = i
  444. break
  445. }
  446. }
  447. this.canDropIndex = targetIndex
  448. }).exec()
  449. },
  450. /**
  451. * 重置拖拽状态
  452. */
  453. resetDragState() {
  454. this.draggingIndex = -1
  455. this.canDropIndex = -1
  456. this.startX = 0
  457. this.startY = 0
  458. this.currentX = 0
  459. this.currentY = 0
  460. },
  461. /**
  462. * 上传图片
  463. */
  464. async handleUploadImage() {
  465. try {
  466. const filePaths = await imageUpload.chooseImage(9)
  467. const uploadResults = await imageUpload.uploadFiles(filePaths)
  468. await imageUpload.bindOrderFile(
  469. this.currentReceipt.clueId,
  470. this.currentReceipt.id,
  471. '3',
  472. uploadResults
  473. )
  474. await this.loadDetailImages()
  475. //上传新图片完成之后也要把新数据给接口
  476. const fileIds = this.detailImages.map(item => item.id).join(',')
  477. await uni.$u.api.updateReceiptForm({
  478. id: this.currentReceipt.id,
  479. fileIds: fileIds
  480. })
  481. this.$emit('update-file-ids', fileIds)
  482. } catch (error) {
  483. console.error('上传失败:', error)
  484. }
  485. },
  486. /**
  487. * 隐藏图片
  488. */
  489. async handleHideImage(item, index) {
  490. const itemIndex = this.detailImages.findIndex(img => img.id === item.id || img.fileUrl === item.fileUrl)
  491. if (itemIndex !== -1) {
  492. this.detailImages.splice(itemIndex, 1)
  493. // 更新 fileIds
  494. const fileIds = this.detailImages.map(item => item.id).join(',')
  495. try {
  496. await uni.$u.api.updateReceiptForm({
  497. id: this.currentReceipt.id,
  498. fileIds: fileIds
  499. })
  500. this.$emit('update-file-ids', fileIds)
  501. uni.$u.toast('图片已隐藏')
  502. } catch (error) {
  503. console.error('更新失败:', error)
  504. }
  505. }
  506. },
  507. /**
  508. * 预览图片
  509. */
  510. previewImageDetail(src) {
  511. const urlList = this.detailImages.map(item => item.fileUrl)
  512. uni.previewImage({
  513. urls: urlList,
  514. current: src
  515. })
  516. },
  517. /**
  518. * 未收点击
  519. */
  520. handleUnpaidClick() {
  521. this.unpaidModalVisible = true
  522. },
  523. /**
  524. * 待跟进点击
  525. */
  526. handleFollowUpClick() {
  527. this.followUpModalVisible = true
  528. },
  529. /**
  530. * 立即支付点击
  531. */
  532. async handlePayNowClick() {
  533. // 保存支付信息
  534. await uni.$u.api.updateReceiptForm({
  535. id: this.currentReceipt.id,
  536. tableFee: this.paymentAmount,
  537. fileIds: this.detailImages.map(item => item.id).join(',')
  538. })
  539. await uni.$u.api.updateClueOrderForm({
  540. id: this.orderDetail.id,
  541. customName: this.paymentInfo.customName || '',
  542. bankName: this.paymentInfo.bankName || '',
  543. bankCardNumber: this.paymentInfo.bankAccount || '',
  544. idCard: this.paymentInfo.idNumber || '',
  545. // paymentMethod: this.paymentMethod || ''
  546. })
  547. if (!this.paymentInfo.customName || !this.paymentInfo.bankName ||
  548. !this.paymentInfo.bankAccount || !this.paymentInfo.idNumber || !this.paymentMethod) {
  549. uni.$u.toast('请填写完整的支付信息')
  550. return
  551. }
  552. if (this.paymentAmount <= 0) {
  553. uni.$u.toast('请填写正确的支付总额')
  554. return
  555. }
  556. //判断当前账号是否敏感地区
  557. if (String(this.paymentInfo.idNumber).startsWith('430481')) {
  558. this.riskWarningModalVisible = true
  559. return
  560. }
  561. this.payNowModalVisible = true
  562. },
  563. /**
  564. * 确认风险警示
  565. */
  566. confirmRiskWarning() {
  567. this.riskWarningModalVisible = false
  568. this.payNowModalVisible = true
  569. },
  570. /**
  571. * 确认转账
  572. */
  573. async confirmTransfer() {
  574. this.payNowModalVisible = false
  575. await uni.$u.api.updateClueOrderForm({
  576. id: this.orderDetail.id,
  577. paymentMethod: this.paymentMethod || ''
  578. })
  579. //如果是小葫芦线上支付或者小葫芦线上支付宝就调用接口,如果不是小葫芦线上支付就不要调用接口,直接点击下一步
  580. if (this.paymentMethod === '小葫芦线上支付' || this.paymentMethod === '小葫芦线上支付宝') {
  581. this.$emit('confirm-pay')
  582. } else {
  583. this.handleNext()
  584. }
  585. },
  586. /**
  587. * 确认未收
  588. */
  589. async confirmUnpaid() {
  590. try {
  591. await uni.$u.api.addOrderFollow({
  592. orderId: this.orderId,
  593. content: `未收评分_${this.unpaidRating}`
  594. })
  595. await uni.$u.api.oderForm({
  596. status: '4',
  597. id: this.orderId
  598. })
  599. uni.$u.toast('提交未收评级成功')
  600. this.unpaidModalVisible = false
  601. } catch (error) {
  602. console.error('提交失败:', error)
  603. uni.$u.toast('提交失败')
  604. }
  605. },
  606. /**
  607. * 确认跟进
  608. */
  609. async confirmFollowUp() {
  610. try {
  611. await uni.$u.api.addOrderFollow({
  612. orderId: this.orderId,
  613. content: `待跟进_${this.followUpNotes}`
  614. })
  615. uni.$u.toast('提交待跟进记录成功')
  616. this.followUpModalVisible = false
  617. this.followUpNotes = ''
  618. } catch (error) {
  619. console.error('提交失败:', error)
  620. uni.$u.toast('提交失败')
  621. }
  622. },
  623. /**
  624. * 下一步
  625. */
  626. async handleNext() {
  627. await uni.$u.api.updateReceiptForm({
  628. id: this.currentReceipt.id,
  629. tableFee: this.paymentAmount,
  630. fileIds: this.detailImages.map(item => item.id).join(',')
  631. })
  632. await uni.$u.api.updateClueOrderForm({
  633. id: this.orderDetail.id,
  634. customName: this.paymentInfo.customName || '',
  635. bankName: this.paymentInfo.bankName || '',
  636. bankCardNumber: this.paymentInfo.bankAccount || '',
  637. idCard: this.paymentInfo.idNumber || ''
  638. })
  639. this.$emit('save', {
  640. nowPage: 'formThree',
  641. form: {
  642. ...this.paymentInfo
  643. },
  644. fileIds: this.detailImages.map(item => item.id).join(',')
  645. })
  646. this.$emit('next', {
  647. nowPage: 'formThree',
  648. form: {
  649. ...this.paymentInfo
  650. }
  651. })
  652. },
  653. /**
  654. * 核价
  655. */
  656. async handlePricing() {
  657. const brandList = await this.$getDicts("crm_form_brand");
  658. if (!this.currentReceipt || !this.currentReceipt.clueId) {
  659. uni.$u.toast('缺少线索ID')
  660. return
  661. }
  662. if (!this.currentReceipt.brand) {
  663. uni.$u.toast('缺少品牌信息')
  664. return
  665. }
  666. if (!this.displayImages || this.displayImages.length === 0) {
  667. uni.$u.toast('请先上传图片')
  668. return
  669. }
  670. //我这里询价要用receiptid来询价
  671. this.pricingClueId = this.currentReceipt.id
  672. // brand 是品牌的 id(dictValue),itemBrand 是品牌的 label(dictLabel)
  673. const brandDictLabel = this.currentReceipt.brand
  674. const brandDictValue = brandList.find(item => item.dictLabel === this.currentReceipt.brand).dictValue;
  675. // 将图片转换为 imgsUrl 格式
  676. const imgsUrl = this.displayImages.map(item => item.fileUrl).filter(url => url)
  677. // 检查是否已有核价记录
  678. try {
  679. const data = {
  680. clueId: this.currentReceipt.clueId,
  681. type: 2
  682. }
  683. const res = await uni.$u.api.inquiryDetail(data)
  684. if (res.code === 200 && res.data) {
  685. // 编辑模式:保留原有数据,但更新品牌和图片
  686. this.pricingEditOrAdd = 'editForm'
  687. this.pricingEditInfo = {
  688. ...res.data,
  689. dictLabel: brandDictLabel || res.data.dictLabel,
  690. dictValue: brandDictValue || res.data.dictValue,
  691. imgsUrl: imgsUrl.length > 0 ? imgsUrl : (res.data.imgsUrl || [])
  692. }
  693. this.$nextTick(() => {
  694. this.$refs.pricingDialog.showDialog()
  695. })
  696. } else {
  697. // 新增模式:设置品牌和图片
  698. this.pricingEditOrAdd = 'editForm'
  699. this.pricingEditInfo = {
  700. dictLabel: brandDictLabel,
  701. dictValue: brandDictValue,
  702. imgsUrl: imgsUrl,
  703. model: this.currentReceipt.model,
  704. code: '',
  705. price: ''
  706. }
  707. this.$nextTick(() => {
  708. this.$refs.pricingDialog.showDialog()
  709. })
  710. }
  711. } catch (error) {
  712. // 如果没有记录,则新增
  713. this.pricingEditOrAdd = 'receptFormAdd'
  714. this.pricingEditInfo = {
  715. dictLabel: brandDictLabel,
  716. dictValue: brandDictValue,
  717. imgsUrl: imgsUrl,
  718. model: this.currentReceipt.model,
  719. code: '',
  720. price: ''
  721. }
  722. this.$nextTick(() => {
  723. this.$refs.pricingDialog.showDialog()
  724. })
  725. }
  726. },
  727. }
  728. }
  729. </script>
  730. <style scoped lang="scss">
  731. @import '../styles/common.scss';
  732. .page-three-container {
  733. @extend .page-container;
  734. padding-bottom: 100rpx;
  735. }
  736. .info-card {
  737. @extend .card-wrap;
  738. padding: 20rpx;
  739. margin-top: 20rpx;
  740. box-sizing: border-box;
  741. width: 100%;
  742. max-width: 100%;
  743. }
  744. .info-card-title {
  745. @include font-styles($size: title, $weight: bold, $color: primary);
  746. margin-bottom: 25rpx;
  747. padding-bottom: 15rpx;
  748. border-bottom: 1rpx solid map-get($colors, border);
  749. }
  750. .info-row {
  751. margin-bottom: 20rpx;
  752. }
  753. .info-label {
  754. @include font-styles($size: tiny, $weight: regular, $color: tertiary);
  755. margin-bottom: 8rpx;
  756. display: block;
  757. }
  758. .info-input {
  759. border-radius: 8rpx;
  760. border: 1rpx solid #e5e7eb;
  761. padding: 12rpx 16rpx;
  762. width: 100%;
  763. box-sizing: border-box;
  764. }
  765. .detail-image-section {
  766. padding: 20rpx;
  767. }
  768. .detail-image-header {
  769. display: grid;
  770. grid-template-columns: 1fr auto;
  771. margin-bottom: 20rpx;
  772. padding-bottom: 20rpx;
  773. border-bottom: 1rpx solid map-get($colors, border);
  774. }
  775. .detail-image-title {
  776. @include font-styles($size: content, $weight: bold, $color: primary);
  777. }
  778. .detail-image-list {
  779. display: flex;
  780. flex-wrap: wrap;
  781. gap: 20rpx;
  782. position: relative;
  783. }
  784. .detail-image-item {
  785. position: relative;
  786. width: 200rpx;
  787. height: 200rpx;
  788. touch-action: none;
  789. transition: transform 0.2s ease, opacity 0.2s ease;
  790. z-index: 1;
  791. box-sizing: border-box;
  792. &.dragging {
  793. opacity: 0.6;
  794. transform: scale(1.05);
  795. z-index: 999;
  796. box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.2);
  797. }
  798. &.can-drop {
  799. outline: 2rpx dashed #108cff;
  800. outline-offset: -2rpx;
  801. background-color: rgba(16, 140, 255, 0.1);
  802. border-radius: 8rpx;
  803. }
  804. }
  805. .image-type-tag {
  806. position: absolute;
  807. top: 10rpx;
  808. left: 10rpx;
  809. background-color: rgba(0, 0, 0, 0.6);
  810. color: white;
  811. padding: 5rpx 10rpx;
  812. border-radius: 12rpx;
  813. font-size: 22rpx;
  814. z-index: 1;
  815. }
  816. .detail-delete-btn {
  817. position: absolute;
  818. top: -10rpx;
  819. right: -10rpx;
  820. width: 40rpx;
  821. height: 40rpx;
  822. background-color: #ff4d4f;
  823. color: #fff;
  824. border-radius: 50%;
  825. display: flex;
  826. align-items: center;
  827. justify-content: center;
  828. font-weight: bold;
  829. z-index: 10;
  830. cursor: pointer;
  831. }
  832. .detail-upload-btn {
  833. width: 200rpx;
  834. height: 200rpx;
  835. border: 8rpx dashed #ddd;
  836. border-radius: 30rpx;
  837. display: flex;
  838. align-items: center;
  839. justify-content: center;
  840. background-color: #f9f9f9;
  841. cursor: pointer;
  842. }
  843. .pricing-button {
  844. margin-top: 0;
  845. }
  846. .payment-card {
  847. margin-top: 20rpx;
  848. }
  849. .payment-section {
  850. padding: 20rpx;
  851. }
  852. .payment-total-container {
  853. background-color: #f5f7fa;
  854. border: 2rpx solid #e5e7eb;
  855. border-radius: 12rpx;
  856. padding: 0rpx 30rpx;
  857. display: flex;
  858. align-items: center;
  859. justify-content: space-between;
  860. margin-bottom: 24rpx;
  861. }
  862. .payment-label {
  863. font-size: 36rpx;
  864. font-weight: 700;
  865. min-width: 140rpx;
  866. }
  867. .payment-amount {
  868. font-size: 48rpx;
  869. font-weight: 600;
  870. color: #f53f3f;
  871. width: auto;
  872. min-width: 150rpx;
  873. border: none;
  874. text-align: right !important;
  875. }
  876. .payment-buttons-row {
  877. display: flex;
  878. gap: 20rpx;
  879. margin-bottom: 24rpx;
  880. }
  881. .payment-button {
  882. flex: 1;
  883. border-radius: 12rpx;
  884. padding: 5rpx 0;
  885. display: flex;
  886. flex-direction: column;
  887. align-items: center;
  888. justify-content: center;
  889. background-color: #f5f7fa;
  890. border: 2rpx solid #e5e7eb;
  891. cursor: pointer;
  892. gap: 12rpx;
  893. }
  894. .pay-now-button {
  895. width: 100%;
  896. border-radius: 12rpx;
  897. padding: 32rpx 0;
  898. display: flex;
  899. flex-direction: column;
  900. align-items: center;
  901. justify-content: center;
  902. background-color: #108cff;
  903. color: #fff;
  904. cursor: pointer;
  905. box-shadow: 0 4rpx 12rpx rgba(16, 140, 255, 0.2);
  906. }
  907. .button-text {
  908. font-size: 28rpx;
  909. font-weight: 500;
  910. color: inherit;
  911. }
  912. .modal-content {
  913. width: 100%;
  914. padding: 40rpx 20rpx;
  915. display: flex;
  916. flex-direction: column;
  917. align-items: center;
  918. }
  919. .payment-amount-display {
  920. font-size: 64rpx;
  921. font-weight: bold;
  922. color: #108cff;
  923. text-align: center;
  924. margin-bottom: 40rpx;
  925. width: 100%;
  926. }
  927. .payment-info-section {
  928. width: 100%;
  929. background-color: #f5f7fa;
  930. border: 2rpx solid #e5e7eb;
  931. border-radius: 12rpx;
  932. padding: 30rpx 20rpx;
  933. margin-bottom: 40rpx;
  934. }
  935. .info-item {
  936. display: flex;
  937. margin-bottom: 20rpx;
  938. align-items: center;
  939. justify-content: space-between;
  940. &:last-child {
  941. margin-bottom: 0;
  942. }
  943. }
  944. .next-btn {
  945. position: fixed;
  946. bottom: 10rpx;
  947. left: 2.5%;
  948. width: 95%;
  949. height: 80rpx;
  950. line-height: 80rpx;
  951. text-align: center;
  952. border-radius: 20rpx;
  953. z-index: 1000;
  954. }
  955. </style>