PageThree.vue 28 KB

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