You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

418 lines
8.4 KiB

  1. <template>
  2. <view class="order-modify-container">
  3. <view class="header">
  4. <text class="title">修改订单</text>
  5. </view>
  6. <view class="content">
  7. <!-- 加载状态 -->
  8. <view class="loading-container" v-if="loading">
  9. <view class="loading-circle"></view>
  10. <text class="loading-text">加载中...</text>
  11. </view>
  12. <view v-else>
  13. <view class="info-section">
  14. <view class="section-title">修改说明</view>
  15. <view class="info-content">
  16. <view class="desc-text">修改订单不会额外收取任何费用如需修改服务内容请点击"修改服务"按钮</view>
  17. </view>
  18. </view>
  19. <view class="info-section">
  20. <view class="section-title">修改信息</view>
  21. <view class="info-content">
  22. <view class="info-item">
  23. <text class="info-label">联系人</text>
  24. <input class="info-value" type="text" v-model="modifyInfo.contactName" placeholder="请输入联系人姓名" />
  25. </view>
  26. <view class="info-item">
  27. <text class="info-label">联系方式</text>
  28. <input class="info-value" type="text" v-model="modifyInfo.contactPhone" placeholder="请输入联系电话" />
  29. </view>
  30. <view class="info-item payment-method">
  31. <text class="info-label">销售支持方式</text>
  32. <view class="info-value payment-value">
  33. <input type="text" v-model="modifyInfo.paymentMethod" placeholder="请输入支付方式" />
  34. <text class="arrow-right">></text>
  35. </view>
  36. </view>
  37. </view>
  38. </view>
  39. <view class="info-section">
  40. <view class="section-title">修改原因</view>
  41. <view class="info-content">
  42. <textarea class="reason-input" v-model="modifyReason" placeholder="请输入修改原因(选填)"></textarea>
  43. </view>
  44. </view>
  45. </view>
  46. </view>
  47. <!-- 底部按钮区域 -->
  48. <view class="order-modify-footer">
  49. <view class="footer-btn cancel-service-btn" @click="modifyOrder">
  50. <text>修改服务</text>
  51. </view>
  52. <view class="footer-btn confirm-modify-btn" @click="confirmModify">
  53. <text>确认修改</text>
  54. </view>
  55. </view>
  56. <!-- 取消订单弹窗 -->
  57. <cancel-order-popup
  58. ref="cancelPopup"
  59. @cancel="handleCancelOrder"
  60. ></cancel-order-popup>
  61. <!-- 客服组件 -->
  62. <Kefu></Kefu>
  63. </view>
  64. </template>
  65. <script>
  66. import { getOrderDetail, updateOrder } from '@/api/order/order.js';
  67. export default {
  68. components: {
  69. },
  70. data() {
  71. return {
  72. loading: false,
  73. orderId: null,
  74. modifyInfo: {
  75. contactName: '',
  76. contactPhone: '',
  77. paymentMethod: '',
  78. },
  79. modifyReason: '',
  80. showCancelOrderPopup: false,
  81. originalOrderData: null
  82. }
  83. },
  84. onLoad(options) {
  85. if (options.orderId) {
  86. this.orderId = options.orderId;
  87. this.loadOrderData();
  88. } else {
  89. uni.showToast({
  90. title: '订单ID不存在',
  91. icon: 'none'
  92. });
  93. setTimeout(() => {
  94. uni.navigateBack();
  95. }, 1500);
  96. }
  97. },
  98. methods: {
  99. // 加载订单数据
  100. async loadOrderData() {
  101. if (!this.orderId) return;
  102. this.loading = true;
  103. try {
  104. const res = await getOrderDetail({ id: this.orderId });
  105. if (res && res.code === 200) {
  106. const orderData = res.data;
  107. this.originalOrderData = JSON.parse(JSON.stringify(orderData));
  108. // 初始化修改信息
  109. this.modifyInfo.contactName = orderData.contactName || '';
  110. this.modifyInfo.contactPhone = orderData.contactPhone || '';
  111. this.modifyInfo.paymentMethod = orderData.paymentMethod || '';
  112. } else {
  113. uni.showToast({
  114. title: res.msg || '获取订单信息失败',
  115. icon: 'none'
  116. });
  117. }
  118. } catch (error) {
  119. console.error('获取订单数据失败', error);
  120. uni.showToast({
  121. title: '网络异常,请稍后重试',
  122. icon: 'none'
  123. });
  124. } finally {
  125. this.loading = false;
  126. }
  127. },
  128. // 确认修改
  129. async confirmModify() {
  130. // 表单验证
  131. if (!this.modifyInfo.contactName.trim()) {
  132. return uni.showToast({
  133. title: '请输入联系人姓名',
  134. icon: 'none'
  135. });
  136. }
  137. if (!this.modifyInfo.contactPhone.trim()) {
  138. return uni.showToast({
  139. title: '请输入联系方式',
  140. icon: 'none'
  141. });
  142. }
  143. // 验证手机号
  144. const phoneReg = /^1[3-9]\d{9}$/;
  145. if (!phoneReg.test(this.modifyInfo.contactPhone)) {
  146. return uni.showToast({
  147. title: '请输入正确的手机号码',
  148. icon: 'none'
  149. });
  150. }
  151. // 检查是否有修改
  152. const hasChanged =
  153. this.modifyInfo.contactName !== this.originalOrderData.contactName ||
  154. this.modifyInfo.contactPhone !== this.originalOrderData.contactPhone ||
  155. this.modifyInfo.paymentMethod !== this.originalOrderData.paymentMethod;
  156. if (!hasChanged) {
  157. return uni.showToast({
  158. title: '未检测到任何修改',
  159. icon: 'none'
  160. });
  161. }
  162. this.loading = true;
  163. try {
  164. const updateData = {
  165. id: this.orderId,
  166. contactName: this.modifyInfo.contactName,
  167. contactPhone: this.modifyInfo.contactPhone,
  168. paymentMethod: this.modifyInfo.paymentMethod,
  169. modifyReason: this.modifyReason || '客户修改订单信息'
  170. };
  171. const res = await updateOrder(updateData);
  172. if (res && res.code === 200) {
  173. uni.showToast({
  174. title: '订单修改成功',
  175. icon: 'success'
  176. });
  177. setTimeout(() => {
  178. uni.navigateBack();
  179. }, 1500);
  180. } else {
  181. uni.showToast({
  182. title: res.msg || '订单修改失败',
  183. icon: 'none'
  184. });
  185. }
  186. } catch (error) {
  187. console.error('订单修改失败', error);
  188. uni.showToast({
  189. title: '网络异常,请稍后重试',
  190. icon: 'none'
  191. });
  192. } finally {
  193. this.loading = false;
  194. }
  195. },
  196. // 修改服务(跳转到下单流程)
  197. modifyOrder() {
  198. uni.navigateTo({
  199. url: `/pages/newOrder/serviceNew?orderId=${this.orderId}&isModify=true`
  200. });
  201. },
  202. }
  203. }
  204. </script>
  205. <style lang="scss" scoped>
  206. .order-modify-container {
  207. background-color: #f5f5f5;
  208. min-height: 100vh;
  209. display: flex;
  210. flex-direction: column;
  211. }
  212. .header {
  213. background-color: #FFAA48;
  214. padding: 20rpx 30rpx;
  215. color: #FFFFFF;
  216. .title {
  217. font-size: 36rpx;
  218. font-weight: bold;
  219. }
  220. }
  221. .content {
  222. flex: 1;
  223. padding: 20rpx;
  224. }
  225. .loading-container {
  226. display: flex;
  227. flex-direction: column;
  228. align-items: center;
  229. justify-content: center;
  230. height: 300rpx;
  231. margin-top: 100rpx;
  232. }
  233. .loading-circle {
  234. width: 80rpx;
  235. height: 80rpx;
  236. border: 4rpx solid #FFAA48;
  237. border-top-color: transparent;
  238. border-radius: 50%;
  239. animation: spin 1s linear infinite;
  240. margin-bottom: 20rpx;
  241. }
  242. @keyframes spin {
  243. 0% {
  244. transform: rotate(0deg);
  245. }
  246. 100% {
  247. transform: rotate(360deg);
  248. }
  249. }
  250. .loading-text {
  251. font-size: 28rpx;
  252. color: #666;
  253. }
  254. .info-section {
  255. background-color: #FFFFFF;
  256. border-radius: 20rpx;
  257. margin-bottom: 20rpx;
  258. overflow: hidden;
  259. }
  260. .section-title {
  261. font-size: 32rpx;
  262. font-weight: bold;
  263. padding: 20rpx;
  264. border-bottom: 1px solid #EEEEEE;
  265. }
  266. .info-content {
  267. padding: 20rpx;
  268. }
  269. .desc-text {
  270. font-size: 28rpx;
  271. color: #666;
  272. line-height: 1.5;
  273. }
  274. .info-item {
  275. display: flex;
  276. align-items: center;
  277. margin-bottom: 20rpx;
  278. &:last-child {
  279. margin-bottom: 0;
  280. }
  281. .info-label {
  282. width: 180rpx;
  283. font-size: 28rpx;
  284. color: #666;
  285. }
  286. .info-value {
  287. flex: 1;
  288. font-size: 28rpx;
  289. color: #333;
  290. padding: 10rpx;
  291. border: 1px solid #EEEEEE;
  292. border-radius: 8rpx;
  293. }
  294. }
  295. .payment-method {
  296. .payment-value {
  297. display: flex;
  298. align-items: center;
  299. input {
  300. flex: 1;
  301. border: none;
  302. padding: 0;
  303. }
  304. .arrow-right {
  305. font-size: 24rpx;
  306. color: #999;
  307. margin-left: 10rpx;
  308. }
  309. }
  310. }
  311. .reason-input {
  312. width: 100%;
  313. height: 200rpx;
  314. font-size: 28rpx;
  315. padding: 20rpx;
  316. box-sizing: border-box;
  317. border: 1px solid #EEEEEE;
  318. border-radius: 8rpx;
  319. }
  320. .footer {
  321. padding: 30rpx 20rpx;
  322. background-color: #FFFFFF;
  323. border-top: 1px solid #EEEEEE;
  324. .btn-container {
  325. display: flex;
  326. justify-content: space-between;
  327. align-items: center;
  328. width: 100%;
  329. .btn {
  330. flex: 1;
  331. padding: 16rpx 30rpx;
  332. border-radius: 30rpx;
  333. text-align: center;
  334. font-size: 30rpx;
  335. margin: 0 10rpx;
  336. &:first-child {
  337. margin-left: 0;
  338. }
  339. &:last-child {
  340. margin-right: 0;
  341. }
  342. &:disabled {
  343. opacity: 0.6;
  344. }
  345. }
  346. .modify-service {
  347. background-color: #F5F5F5;
  348. color: #666;
  349. border: 1px solid #DDDDDD;
  350. }
  351. .confirm-modify {
  352. background-color: #FFAA48;
  353. color: #FFFFFF;
  354. }
  355. .cancel-order {
  356. background-color: #F5F5F5;
  357. color: #666;
  358. border: 1px solid #DDDDDD;
  359. width: 100%;
  360. }
  361. }
  362. .mt-20 {
  363. margin-top: 20rpx;
  364. }
  365. }
  366. </style>