PageThree.vue 24 KB

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