PageThree.vue 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  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) {
  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. //我这里询价要用receiptid来询价
  668. this.pricingClueId = this.currentReceipt.id
  669. // brand 是品牌的 id(dictValue),itemBrand 是品牌的 label(dictLabel)
  670. const brandDictLabel = this.currentReceipt.brand
  671. const brandDictValue = brandList.find(item => item.dictLabel === this.currentReceipt.brand).dictValue;
  672. // 将图片转换为 imgsUrl 格式
  673. const imgsUrl = this.displayImages.map(item => item.fileUrl).filter(url => url)
  674. // 检查是否已有核价记录
  675. try {
  676. const data = {
  677. clueId: this.currentReceipt.clueId,
  678. type: 2
  679. }
  680. const res = await uni.$u.api.inquiryDetail(data)
  681. if (res.code === 200 && res.data) {
  682. // 编辑模式:保留原有数据,但更新品牌和图片
  683. this.pricingEditOrAdd = 'editForm'
  684. this.pricingEditInfo = {
  685. ...res.data,
  686. dictLabel: brandDictLabel || res.data.dictLabel,
  687. dictValue: brandDictValue || res.data.dictValue,
  688. imgsUrl: imgsUrl.length > 0 ? imgsUrl : (res.data.imgsUrl || [])
  689. }
  690. this.$nextTick(() => {
  691. this.$refs.pricingDialog.showDialog()
  692. })
  693. } else {
  694. // 新增模式:设置品牌和图片
  695. this.pricingEditOrAdd = 'editForm'
  696. this.pricingEditInfo = {
  697. dictLabel: brandDictLabel,
  698. dictValue: brandDictValue,
  699. imgsUrl: imgsUrl,
  700. model: this.currentReceipt.model,
  701. code: '',
  702. price: ''
  703. }
  704. this.$nextTick(() => {
  705. this.$refs.pricingDialog.showDialog()
  706. })
  707. }
  708. } catch (error) {
  709. // 如果没有记录,则新增
  710. this.pricingEditOrAdd = 'receptFormAdd'
  711. this.pricingEditInfo = {
  712. dictLabel: brandDictLabel,
  713. dictValue: brandDictValue,
  714. imgsUrl: imgsUrl,
  715. model: this.currentReceipt.model,
  716. code: '',
  717. price: ''
  718. }
  719. this.$nextTick(() => {
  720. this.$refs.pricingDialog.showDialog()
  721. })
  722. }
  723. },
  724. }
  725. }
  726. </script>
  727. <style scoped lang="scss">
  728. @import '../styles/common.scss';
  729. .page-three-container {
  730. @extend .page-container;
  731. padding-bottom: 100rpx;
  732. }
  733. .info-card {
  734. @extend .card-wrap;
  735. padding: 20rpx;
  736. margin-top: 20rpx;
  737. box-sizing: border-box;
  738. width: 100%;
  739. max-width: 100%;
  740. }
  741. .info-card-title {
  742. @include font-styles($size: title, $weight: bold, $color: primary);
  743. margin-bottom: 25rpx;
  744. padding-bottom: 15rpx;
  745. border-bottom: 1rpx solid map-get($colors, border);
  746. }
  747. .info-row {
  748. margin-bottom: 20rpx;
  749. }
  750. .info-label {
  751. @include font-styles($size: tiny, $weight: regular, $color: tertiary);
  752. margin-bottom: 8rpx;
  753. display: block;
  754. }
  755. .info-input {
  756. border-radius: 8rpx;
  757. border: 1rpx solid #e5e7eb;
  758. padding: 12rpx 16rpx;
  759. width: 100%;
  760. box-sizing: border-box;
  761. }
  762. .detail-image-section {
  763. padding: 20rpx;
  764. }
  765. .detail-image-header {
  766. display: grid;
  767. grid-template-columns: 1fr auto;
  768. margin-bottom: 20rpx;
  769. padding-bottom: 20rpx;
  770. border-bottom: 1rpx solid map-get($colors, border);
  771. }
  772. .detail-image-title {
  773. @include font-styles($size: content, $weight: bold, $color: primary);
  774. }
  775. .detail-image-list {
  776. display: flex;
  777. flex-wrap: wrap;
  778. gap: 20rpx;
  779. position: relative;
  780. }
  781. .detail-image-item {
  782. position: relative;
  783. width: 200rpx;
  784. height: 200rpx;
  785. touch-action: none;
  786. transition: transform 0.2s ease, opacity 0.2s ease;
  787. z-index: 1;
  788. box-sizing: border-box;
  789. &.dragging {
  790. opacity: 0.6;
  791. transform: scale(1.05);
  792. z-index: 999;
  793. box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.2);
  794. }
  795. &.can-drop {
  796. outline: 2rpx dashed #108cff;
  797. outline-offset: -2rpx;
  798. background-color: rgba(16, 140, 255, 0.1);
  799. border-radius: 8rpx;
  800. }
  801. }
  802. .image-type-tag {
  803. position: absolute;
  804. top: 10rpx;
  805. left: 10rpx;
  806. background-color: rgba(0, 0, 0, 0.6);
  807. color: white;
  808. padding: 5rpx 10rpx;
  809. border-radius: 12rpx;
  810. font-size: 22rpx;
  811. z-index: 1;
  812. }
  813. .detail-delete-btn {
  814. position: absolute;
  815. top: -10rpx;
  816. right: -10rpx;
  817. width: 40rpx;
  818. height: 40rpx;
  819. background-color: #ff4d4f;
  820. color: #fff;
  821. border-radius: 50%;
  822. display: flex;
  823. align-items: center;
  824. justify-content: center;
  825. font-weight: bold;
  826. z-index: 10;
  827. cursor: pointer;
  828. }
  829. .detail-upload-btn {
  830. width: 200rpx;
  831. height: 200rpx;
  832. border: 8rpx dashed #ddd;
  833. border-radius: 30rpx;
  834. display: flex;
  835. align-items: center;
  836. justify-content: center;
  837. background-color: #f9f9f9;
  838. cursor: pointer;
  839. }
  840. .pricing-button {
  841. margin-top: 0;
  842. }
  843. .payment-card {
  844. margin-top: 20rpx;
  845. }
  846. .payment-section {
  847. padding: 20rpx;
  848. }
  849. .payment-total-container {
  850. background-color: #f5f7fa;
  851. border: 2rpx solid #e5e7eb;
  852. border-radius: 12rpx;
  853. padding: 0rpx 30rpx;
  854. display: flex;
  855. align-items: center;
  856. justify-content: space-between;
  857. margin-bottom: 24rpx;
  858. }
  859. .payment-label {
  860. font-size: 36rpx;
  861. font-weight: 700;
  862. min-width: 140rpx;
  863. }
  864. .payment-amount {
  865. font-size: 48rpx;
  866. font-weight: 600;
  867. color: #f53f3f;
  868. width: auto;
  869. min-width: 150rpx;
  870. border: none;
  871. text-align: right !important;
  872. }
  873. .payment-buttons-row {
  874. display: flex;
  875. gap: 20rpx;
  876. margin-bottom: 24rpx;
  877. }
  878. .payment-button {
  879. flex: 1;
  880. border-radius: 12rpx;
  881. padding: 5rpx 0;
  882. display: flex;
  883. flex-direction: column;
  884. align-items: center;
  885. justify-content: center;
  886. background-color: #f5f7fa;
  887. border: 2rpx solid #e5e7eb;
  888. cursor: pointer;
  889. gap: 12rpx;
  890. }
  891. .pay-now-button {
  892. width: 100%;
  893. border-radius: 12rpx;
  894. padding: 32rpx 0;
  895. display: flex;
  896. flex-direction: column;
  897. align-items: center;
  898. justify-content: center;
  899. background-color: #108cff;
  900. color: #fff;
  901. cursor: pointer;
  902. box-shadow: 0 4rpx 12rpx rgba(16, 140, 255, 0.2);
  903. }
  904. .button-text {
  905. font-size: 28rpx;
  906. font-weight: 500;
  907. color: inherit;
  908. }
  909. .modal-content {
  910. width: 100%;
  911. padding: 40rpx 20rpx;
  912. display: flex;
  913. flex-direction: column;
  914. align-items: center;
  915. }
  916. .payment-amount-display {
  917. font-size: 64rpx;
  918. font-weight: bold;
  919. color: #108cff;
  920. text-align: center;
  921. margin-bottom: 40rpx;
  922. width: 100%;
  923. }
  924. .payment-info-section {
  925. width: 100%;
  926. background-color: #f5f7fa;
  927. border: 2rpx solid #e5e7eb;
  928. border-radius: 12rpx;
  929. padding: 30rpx 20rpx;
  930. margin-bottom: 40rpx;
  931. }
  932. .info-item {
  933. display: flex;
  934. margin-bottom: 20rpx;
  935. align-items: center;
  936. justify-content: space-between;
  937. &:last-child {
  938. margin-bottom: 0;
  939. }
  940. }
  941. .next-btn {
  942. position: fixed;
  943. bottom: 10rpx;
  944. left: 2.5%;
  945. width: 95%;
  946. height: 80rpx;
  947. line-height: 80rpx;
  948. text-align: center;
  949. border-radius: 20rpx;
  950. z-index: 1000;
  951. }
  952. </style>