pageThree.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. <template>
  2. <view class="page-container">
  3. <!-- 支付信息录入卡片 -->
  4. <view class="info-card">
  5. <view class="info-card-title">支付信息</view>
  6. <!-- 开户人和银行名称同一行 -->
  7. <u-row class="info-row" justify="space-between">
  8. <u-col span="5.8">
  9. <view class="info-label">开户人</view>
  10. <u-input v-model="paymentInfo.accountHolder" placeholder="请输入开户人姓名" class="info-input" />
  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. </u-col>
  16. </u-row>
  17. <!-- 银行账号单独一行 -->
  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" />
  22. </u-col>
  23. </u-row>
  24. <!-- 身份证号单独一行 -->
  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. </u-col>
  30. </u-row>
  31. </view>
  32. <view class="card_wrap">
  33. <view class="detail-image-section">
  34. <view class="detail-image-header">
  35. <div class="detail-image-title">高清实物图(拖拽排序)</div>
  36. </view>
  37. <view class="detail-image-content">
  38. <view class="detail-image-list">
  39. <!-- 替换drag事件为touch事件 -->
  40. <view class="detail-image-item" v-for="(item, index) in localDetailImages"
  41. :key="'detail-' + index" :style="{ opacity: draggingIndex === index ? 0.5 : 1 }"
  42. @touchstart="onTouchStart($event, index)" @touchmove="onTouchMove($event, index)"
  43. @touchend="onTouchEnd">
  44. <pic-comp :src="item"></pic-comp>
  45. <view class="image-type-tag">{{ getImageType(index) }}</view>
  46. <view class="detail-delete-btn" @click="deleteImage(index)">×</view>
  47. </view>
  48. <view class="detail-upload-btn" @click="uploadDetailImage">
  49. <u-icon name="plus" size="40rpx" color="#999"></u-icon>
  50. </view>
  51. </view>
  52. </view>
  53. </view>
  54. </view>
  55. <!-- 支付总额卡片 -->
  56. <view class="card_wrap payment-card">
  57. <view class="payment-section">
  58. <view class="payment-total-container">
  59. <text class="payment-label">支付总额</text>
  60. <text class="payment-amount">¥0.00</text>
  61. </view>
  62. <view class="payment-buttons-row">
  63. <view class="payment-button" @click="handleUnpaidClick">
  64. <u-icon name="star" size="40rpx" color="#ff9500"></u-icon>
  65. <text class="button-text">未收</text>
  66. </view>
  67. <view class="payment-button" @click="handleFollowUpClick">
  68. <u-icon name="chat" size="40rpx" color="#108cff"></u-icon>
  69. <text class="button-text">待跟进</text>
  70. </view>
  71. </view>
  72. <view class="pay-now-button" @click="handlePayNowClick">
  73. <text class="button-text">立即支付</text>
  74. </view>
  75. </view>
  76. </view>
  77. <u-button @click="handleNextClick" type="primary" size="middle" style="border-radius: 20rpx;">下一步</u-button>
  78. <u-modal :show="unpaidModelShow" :title="'未收评级'" :showConfirmButton="false">
  79. <view class="modal-content">
  80. <u-rate v-model="unpaidRating" :count="5" :size="50" active-color="#ff9500"></u-rate>
  81. <u-button type="primary" size="large" @click="confirmUnpaid" style="margin-top: 40rpx;">确认未收</u-button>
  82. </view>
  83. </u-modal>
  84. <u-modal :show="followUpModelShow" :title="'填写跟进细节'" :showConfirmButton="false">
  85. <view class="modal-content">
  86. <u--textarea v-model="followUpNotes" placeholder="请输入情况" confirm-type="done"
  87. style="width: 100%; margin-bottom: 30rpx;"></u--textarea>
  88. <u-button type="primary" size="large" @click="confirmFollowUp">确认</u-button>
  89. </view>
  90. </u-modal>
  91. <u-modal :show="payNowModelShow" :title="'确认支付信息'" :showConfirmButton="false">
  92. <view class="modal-content">
  93. <!-- 支付金额显示 -->
  94. <view class="payment-amount-display">¥0.00</view>
  95. <!-- 支付信息区域 -->
  96. <view class="payment-info-section">
  97. <view class="info-item">
  98. <text class="info-label">收款姓名:</text>
  99. <text class="info-value">{{ paymentInfo.accountHolder || '未填写' }}</text>
  100. </view>
  101. <view class="info-item">
  102. <text class="info-label">开户银行:</text>
  103. <text class="info-value">{{ paymentInfo.bankName || '未填写' }}</text>
  104. </view>
  105. <view class="info-item">
  106. <text class="info-label">银行卡号:</text>
  107. <text class="info-value">{{ paymentInfo.bankAccount || '未填写' }}</text>
  108. </view>
  109. </view>
  110. <!-- 确认转账按钮 -->
  111. <u-button type="primary" size="large" @click="confirmTransfer"
  112. style="margin-top: 40rpx;">确认转账</u-button>
  113. </view>
  114. </u-modal>
  115. </view>
  116. </template>
  117. <script>
  118. import picComp from './picComp.vue'
  119. export default {
  120. props: {
  121. orderDetail: {
  122. type: Object,
  123. default: () => { },
  124. },
  125. detailImages: {
  126. type: Array,
  127. default: () => []
  128. }
  129. },
  130. watch: {
  131. orderDetail: {
  132. handler(newVal) {
  133. if (newVal) {
  134. this.paymentInfo.accountHolder = newVal.accountHolder || ''
  135. this.paymentInfo.bankName = newVal.bankName || ''
  136. this.paymentInfo.bankAccount = newVal.bankCardNumber || ''
  137. this.paymentInfo.idNumber = newVal.idCard || ''
  138. }
  139. },
  140. deep: true,
  141. },
  142. detailImages: {
  143. handler(newVal) {
  144. this.localDetailImages = [...newVal];
  145. },
  146. deep: true
  147. }
  148. },
  149. components: {
  150. picComp
  151. },
  152. data() {
  153. return {
  154. unpaidModelShow: false,
  155. followUpModelShow: false,
  156. payNowModelShow: false,
  157. unpaidRating: 0, // 未收评级
  158. followUpNotes: '', // 跟进细节
  159. // 支付信息
  160. paymentInfo: {
  161. accountHolder: '', // 开户人
  162. bankName: '', // 银行名称
  163. bankAccount: '', // 银行账号
  164. idNumber: '' // 身份证号
  165. },
  166. // Local copy of detailImages prop to avoid direct mutation
  167. localDetailImages: [...this.detailImages],
  168. // 拖拽相关状态
  169. draggingIndex: -1, // 当前正在拖拽的元素索引
  170. startX: 0, // 触摸起始X坐标
  171. startY: 0 // 触摸起始Y坐标
  172. };
  173. },
  174. methods: {
  175. // 上传高清细节图
  176. uploadDetailImage() {
  177. uni.chooseImage({
  178. count: 9 - this.localDetailImages.length, // 最多选择9张
  179. sizeType: ['compressed'], // 压缩图片
  180. sourceType: ['album', 'camera'], // 从相册选择或拍照
  181. success: (res) => {
  182. const tempFilePaths = res.tempFilePaths;
  183. // 将图片路径添加到数组中
  184. this.localDetailImages = [...this.localDetailImages, ...tempFilePaths];
  185. },
  186. fail: (err) => {
  187. console.error('选择图片失败:', err);
  188. uni.showToast({
  189. title: '选择图片失败',
  190. icon: 'none'
  191. });
  192. }
  193. });
  194. },
  195. // 删除图片
  196. deleteImage(index) {
  197. uni.showModal({
  198. title: '提示',
  199. content: '确定要删除这张图片吗?',
  200. success: (res) => {
  201. if (res.confirm) {
  202. this.localDetailImages.splice(index, 1);
  203. }
  204. }
  205. });
  206. },
  207. // 获取图片类型
  208. getImageType(index) {
  209. const types = ['正面', '反面', '侧面', '扣子', '编号'];
  210. return types[index] || `细节${index - 4}`;
  211. },
  212. // 触摸开始(替代dragstart)
  213. onTouchStart(event, index) {
  214. this.draggingIndex = index;
  215. // 记录触摸起始坐标
  216. this.startX = event.touches[0].clientX;
  217. this.startY = event.touches[0].clientY;
  218. console.log('开始拖拽:', index);
  219. },
  220. // 触摸移动(替代dragover/drop)
  221. onTouchMove(event, currentIndex) {
  222. if (this.draggingIndex === -1) return; // 没有正在拖拽的元素则返回
  223. const moveX = event.touches[0].clientX;
  224. const moveY = event.touches[0].clientY;
  225. const diffX = moveX - this.startX;
  226. const diffY = moveY - this.startY;
  227. // 简单的拖拽距离判断(避免轻微滑动就触发交换)
  228. if (Math.abs(diffX) > 20 || Math.abs(diffY) > 20) {
  229. // 获取当前触摸位置对应的元素索引
  230. const targetIndex = this.getTargetIndexByPosition(moveX, moveY);
  231. if (targetIndex !== -1 && targetIndex !== this.draggingIndex) {
  232. // 交换数组元素(核心排序逻辑)
  233. [this.localDetailImages[this.draggingIndex], this.localDetailImages[targetIndex]] =
  234. [this.localDetailImages[targetIndex], this.localDetailImages[this.draggingIndex]];
  235. // 更新拖拽索引为目标索引(实现连续拖拽)
  236. this.draggingIndex = targetIndex;
  237. // 重置起始坐标
  238. this.startX = moveX;
  239. this.startY = moveY;
  240. }
  241. }
  242. },
  243. // 触摸结束(替代dragend)
  244. onTouchEnd() {
  245. console.log('拖拽结束');
  246. this.draggingIndex = -1; // 重置拖拽状态
  247. },
  248. // 根据触摸坐标获取目标元素索引(核心辅助方法)
  249. getTargetIndexByPosition(x, y) {
  250. // 获取所有图片元素的位置信息
  251. const query = uni.createSelectorQuery().in(this);
  252. return new Promise((resolve) => {
  253. query.selectAll('.detail-image-item').boundingClientRect(rects => {
  254. for (let i = 0; i < rects.length; i++) {
  255. const rect = rects[i];
  256. // 判断坐标是否在元素范围内
  257. if (
  258. x >= rect.left &&
  259. x <= rect.right &&
  260. y >= rect.top &&
  261. y <= rect.bottom
  262. ) {
  263. resolve(i);
  264. return;
  265. }
  266. }
  267. resolve(-1);
  268. }).exec();
  269. });
  270. },
  271. // 下一步按钮点击事件
  272. handleNextClick() {
  273. console.log('page3点击了下一步按钮');
  274. this.$emit('handleNextClick', {
  275. nowPage: 'formThree',
  276. form: {
  277. // detailImages: this.localDetailImages,
  278. // paymentInfo: this.paymentInfo
  279. }
  280. });
  281. },
  282. // 未收按钮点击事件
  283. handleUnpaidClick() {
  284. console.log('点击了未收按钮');
  285. this.unpaidModelShow = true;
  286. },
  287. // 待跟进按钮点击事件
  288. handleFollowUpClick() {
  289. console.log('点击了待跟进按钮');
  290. this.followUpModelShow = true;
  291. },
  292. // 立即支付按钮点击事件
  293. handlePayNowClick() {
  294. console.log('点击了立即支付按钮');
  295. this.payNowModelShow = true;
  296. },
  297. // 确认未收按钮点击事件
  298. confirmUnpaid() {
  299. console.log('确认未收,评分:', this.unpaidRating);
  300. this.unpaidModelShow = false;
  301. // 可以在这里添加提交评分的逻辑
  302. },
  303. // 确认跟进细节按钮点击事件
  304. confirmFollowUp() {
  305. console.log('确认跟进细节:', this.followUpNotes);
  306. this.followUpModelShow = false;
  307. // 可以在这里添加提交跟进细节的逻辑
  308. },
  309. // 确认转账按钮点击事件
  310. confirmTransfer() {
  311. console.log('确认转账');
  312. this.payNowModelShow = false;
  313. // 可以在这里添加转账确认的逻辑
  314. }
  315. }
  316. }
  317. </script>
  318. <style lang="scss" scoped>
  319. // 导入公共样式
  320. @import './common.scss';
  321. // 主样式
  322. .page-container {
  323. box-sizing: border-box;
  324. padding: 0;
  325. background-color: map-get($colors, bg);
  326. font-family: map-get($font, family);
  327. -webkit-font-smoothing: map-get($font, smoothing);
  328. font-smoothing: map-get($font, smoothing);
  329. }
  330. .card_wrap {
  331. @include card;
  332. margin-bottom: 20rpx;
  333. &:hover {
  334. @include shadow(2);
  335. }
  336. }
  337. .detail-image-section {
  338. padding: map-get($sizes, padding-sm) map-get($sizes, padding);
  339. }
  340. .detail-image-content {
  341. margin-top: 20rpx;
  342. .detail-image-list {
  343. display: flex;
  344. flex-wrap: wrap;
  345. gap: 20rpx;
  346. }
  347. .detail-image-item {
  348. position: relative;
  349. width: 200rpx;
  350. height: 200rpx;
  351. box-sizing: border-box;
  352. touch-action: none; // 禁止浏览器默认触摸行为
  353. transition: opacity 0.2s; // 拖拽时的透明度过渡
  354. &:active {
  355. opacity: 0.7;
  356. }
  357. }
  358. .image-type-tag {
  359. position: absolute;
  360. top: 10rpx;
  361. left: 10rpx;
  362. background-color: rgba(0, 0, 0, 0.6);
  363. color: white;
  364. padding: 5rpx 10rpx;
  365. border-radius: 12rpx;
  366. font-size: 22rpx;
  367. z-index: 1;
  368. }
  369. .detail-delete-btn {
  370. position: absolute;
  371. top: -10rpx;
  372. right: -10rpx;
  373. width: 40rpx;
  374. height: 40rpx;
  375. background-color: #ff4d4f;
  376. color: #fff;
  377. border-radius: 50%;
  378. display: flex;
  379. align-items: center;
  380. justify-content: center;
  381. @include font-styles($size: small, $weight: bold);
  382. z-index: 10;
  383. }
  384. .detail-upload-btn {
  385. width: 200rpx;
  386. height: 200rpx;
  387. border: 8rpx dashed #ddd;
  388. border-radius: 30rpx;
  389. display: flex;
  390. align-items: center;
  391. justify-content: center;
  392. background-color: #f9f9f9;
  393. box-sizing: border-box;
  394. cursor: pointer;
  395. &:hover {
  396. border-color: #108cff;
  397. background-color: rgba(16, 140, 255, 0.05);
  398. }
  399. }
  400. .no-images {
  401. @include font-styles($size: content, $weight: regular, $color: tertiary);
  402. text-align: center;
  403. padding: 80rpx 0;
  404. background-color: #f9f9f9;
  405. border-radius: 12rpx;
  406. margin-top: 20rpx;
  407. }
  408. }
  409. .detail-image-header {
  410. display: flex;
  411. justify-content: space-between;
  412. align-items: center;
  413. margin-bottom: map-get($sizes, margin-sm);
  414. padding-bottom: map-get($sizes, margin-sm);
  415. border-bottom: 1rpx solid map-get($colors, border);
  416. }
  417. .detail-image-title {
  418. @include font-styles($size: content, $weight: bold, $color: primary);
  419. }
  420. /* 支付信息卡片样式 */
  421. .info-card {
  422. @include card;
  423. margin-top: 20rpx;
  424. margin-bottom: 20rpx;
  425. padding: map-get($sizes, padding-sm) map-get($sizes, padding);
  426. box-sizing: border-box;
  427. &:hover {
  428. @include shadow(2);
  429. }
  430. .u-col {
  431. padding: 0;
  432. box-sizing: border-box;
  433. }
  434. .u-col:first-child {
  435. padding-right: 15rpx;
  436. }
  437. .u-col:last-child {
  438. padding-left: 15rpx;
  439. }
  440. }
  441. .info-card-title {
  442. @include font-styles($size: title, $weight: bold, $color: primary);
  443. margin-bottom: 25rpx;
  444. padding-bottom: 15rpx;
  445. border-bottom: 1rpx solid map-get($colors, border);
  446. }
  447. .info-row {
  448. margin-bottom: 20rpx;
  449. box-sizing: border-box;
  450. padding: 0;
  451. }
  452. .info-label {
  453. @include font-styles($size: tiny, $weight: regular, $color: tertiary);
  454. margin-bottom: 8rpx;
  455. display: block;
  456. }
  457. .info-input {
  458. border-radius: 8rpx;
  459. border: 1rpx solid #e5e7eb;
  460. padding: 12rpx 16rpx;
  461. width: 100%;
  462. box-sizing: border-box;
  463. @include font-styles($size: small, $weight: regular, $color: secondary);
  464. }
  465. /* 支付总额卡片样式 */
  466. .payment-card {
  467. @include card;
  468. margin-top: 20rpx;
  469. margin-bottom: 20rpx;
  470. }
  471. .payment-section {
  472. padding: map-get($sizes, padding-sm) map-get($sizes, padding);
  473. }
  474. .payment-total-container {
  475. background-color: #f5f7fa;
  476. border: 2rpx solid #e5e7eb;
  477. border-radius: 12rpx;
  478. padding: 24rpx 30rpx;
  479. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
  480. display: flex;
  481. align-items: center;
  482. justify-content: space-between;
  483. margin-bottom: 24rpx;
  484. }
  485. .payment-label {
  486. font-size: 36rpx;
  487. color: map-get($colors, text-primary);
  488. font-weight: 700;
  489. min-width: 140rpx;
  490. }
  491. .payment-amount {
  492. font-size: 48rpx;
  493. font-weight: 600;
  494. color: #f53f3f;
  495. font-family: Consolas, 'Courier New', monospace, -apple-system, BlinkMacSystemFont;
  496. }
  497. /* 支付按钮行样式 */
  498. .payment-buttons-row {
  499. display: flex;
  500. gap: 20rpx;
  501. margin-bottom: 24rpx;
  502. }
  503. .payment-button {
  504. flex: 1;
  505. border-radius: 12rpx;
  506. padding: 24rpx 0;
  507. display: flex;
  508. flex-direction: column;
  509. align-items: center;
  510. justify-content: center;
  511. background-color: #f5f7fa;
  512. border: 2rpx solid #e5e7eb;
  513. cursor: pointer;
  514. transition: all 0.3s ease;
  515. gap: 12rpx;
  516. }
  517. .payment-button:hover {
  518. background-color: #e6f7ed;
  519. border-color: #00b42a;
  520. transform: translateY(-2rpx);
  521. box-shadow: 0 4rpx 12rpx rgba(0, 180, 42, 0.15);
  522. }
  523. /* 立即支付按钮样式 */
  524. .pay-now-button {
  525. width: 100%;
  526. border-radius: 12rpx;
  527. padding: 32rpx 0;
  528. display: flex;
  529. flex-direction: column;
  530. align-items: center;
  531. justify-content: center;
  532. background-color: #108cff;
  533. color: #fff;
  534. cursor: pointer;
  535. transition: all 0.3s ease;
  536. gap: 12rpx;
  537. box-shadow: 0 4rpx 12rpx rgba(16, 140, 255, 0.2);
  538. }
  539. .pay-now-button:hover {
  540. background-color: #007aff;
  541. transform: translateY(-2rpx);
  542. box-shadow: 0 6rpx 16rpx rgba(16, 140, 255, 0.25);
  543. }
  544. .button-text {
  545. font-size: 28rpx;
  546. font-weight: 500;
  547. color: inherit;
  548. }
  549. /* 模态框内容样式 */
  550. .modal-content {
  551. width: 100%;
  552. padding: 40rpx 20rpx;
  553. display: flex;
  554. flex-direction: column;
  555. align-items: center;
  556. }
  557. /* 支付金额显示样式 */
  558. .payment-amount-display {
  559. font-size: 64rpx;
  560. font-weight: bold;
  561. color: #108cff;
  562. text-align: center;
  563. margin-bottom: 40rpx;
  564. width: 100%;
  565. }
  566. /* 支付信息区域样式 */
  567. .payment-info-section {
  568. width: 100%;
  569. background-color: #f5f7fa;
  570. border: 2rpx solid #e5e7eb;
  571. border-radius: 12rpx;
  572. padding: 30rpx 20rpx;
  573. margin-bottom: 40rpx;
  574. }
  575. /* 信息项样式 */
  576. .info-item {
  577. display: flex;
  578. margin-bottom: 20rpx;
  579. align-items: center;
  580. justify-content: space-between;
  581. }
  582. .info-item:last-child {
  583. margin-bottom: 0;
  584. }
  585. .info-label {
  586. font-size: 28rpx;
  587. color: #666;
  588. width: 200rpx;
  589. }
  590. .info-value {
  591. font-size: 28rpx;
  592. color: #333;
  593. }
  594. </style>