PageThree.vue 24 KB

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