PageThree.vue 30 KB

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