OrderComponent.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <div class="step-container">
  3. <!-- 横向滚动步骤条 -->
  4. <div class="steps-wrapper" ref="stepsContainer">
  5. <el-steps :active="currentStep" finish-status="success" class="dynamic-steps" simple>
  6. <el-step
  7. v-for="(step, index) in totalSteps"
  8. :key="index"
  9. :title="`步骤 ${index + 1}`"
  10. :ref="setStepRef"
  11. />
  12. </el-steps>
  13. </div>
  14. <!-- 通用表单 -->
  15. <div class="form-wrapper">
  16. <el-form :model="formData[currentStep]" :rules="formRules" ref="formRef" label-width="120px">
  17. <el-form-item label="姓名" prop="name">
  18. <el-input v-model="formData[currentStep].name" />
  19. </el-form-item>
  20. <el-form-item label="邮箱" prop="email">
  21. <el-input v-model="formData[currentStep].email" />
  22. </el-form-item>
  23. <el-form-item label="验证码" prop="code">
  24. <el-input v-model="formData[currentStep].code" />
  25. </el-form-item>
  26. </el-form>
  27. </div>
  28. <!-- 导航按钮 -->
  29. <div class="action-buttons">
  30. <el-button @click="prevStep" :disabled="currentStep === 0"> 上一步 </el-button>
  31. <span class="step-indicator"> 当前步骤:{{ currentStep + 1 }}/{{ totalSteps }} </span>
  32. <el-button type="primary" @click="nextStep" :disabled="currentStep === totalSteps - 1">
  33. {{ isLastStep ? '完成' : '下一步' }}
  34. </el-button>
  35. </div>
  36. </div>
  37. </template>
  38. <script setup lang="ts">
  39. import { computed, onMounted, ref } from 'vue'
  40. import { ElMessage } from 'element-plus'
  41. import {any} from "vue-types";
  42. const totalSteps = 30 // 总步骤数
  43. const currentStep = ref(0) // 当前步骤索引
  44. const stepsContainer = ref(null) // 步骤容器引用
  45. const stepElements = [] // 步骤元素集合
  46. const formRef = ref(null) // 表单引用
  47. defineOptions({ name: 'OrderComponent' })
  48. const props = defineProps<{ data: any }>(); // 搜索参数
  49. // 初始化表单数据
  50. const formData = ref(
  51. Array.from({ length: totalSteps }, () => ({
  52. name: '',
  53. email: '',
  54. code: ''
  55. }))
  56. )
  57. // 表单验证规则
  58. const formRules = {
  59. name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
  60. email: [
  61. { required: true, message: '请输入邮箱', trigger: 'blur' },
  62. { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
  63. ],
  64. code: [
  65. { required: true, message: '请输入验证码', trigger: 'blur' },
  66. { pattern: /^\d{6}$/, message: '请输入6位数字验证码' }
  67. ]
  68. }
  69. // 步骤元素引用收集
  70. const setStepRef = (el) => {
  71. if (el) stepElements.push(el)
  72. }
  73. // 自动滚动到当前步骤
  74. const scrollToCurrentStep = () => {
  75. if (!stepsContainer.value) return
  76. const container = stepsContainer.value
  77. const currentEl = stepElements[currentStep.value]?.$el
  78. if (currentEl) {
  79. const containerWidth = container.offsetWidth
  80. const stepLeft = currentEl.offsetLeft
  81. const stepWidth = currentEl.offsetWidth
  82. container.scrollTo({
  83. left: stepLeft - containerWidth / 2 + stepWidth / 2,
  84. behavior: 'smooth'
  85. })
  86. }
  87. }
  88. // 导航逻辑
  89. const prevStep = () => {
  90. if (currentStep.value > 0) currentStep.value--
  91. }
  92. const nextStep = async () => {
  93. try {
  94. // 验证当前表单
  95. await formRef.value.validate()
  96. if (currentStep.value < totalSteps - 1) {
  97. currentStep.value++
  98. } else {
  99. ElMessage.success('所有步骤已完成!')
  100. console.log('最终提交数据:', formData.value)
  101. }
  102. } catch (error) {
  103. ElMessage.error('请正确填写当前步骤表单')
  104. }
  105. }
  106. // 计算属性
  107. const isLastStep = computed(() => currentStep.value === totalSteps - 1)
  108. // 生命周期钩子
  109. onMounted(() => {
  110. // 初始化时滚动到第一个步骤
  111. scrollToCurrentStep()
  112. debugger
  113. })
  114. </script>
  115. <style scoped>
  116. .step-container {
  117. max-width: 100%;
  118. //margin: 20px auto;
  119. //padding: 20px;
  120. }
  121. .steps-wrapper {
  122. overflow-x: auto;
  123. margin-bottom: 30px;
  124. padding: 10px 0;
  125. }
  126. .dynamic-steps {
  127. width: max-content;
  128. min-width: 100%;
  129. }
  130. .el-step {
  131. flex-shrink: 0;
  132. min-width: 120px;
  133. }
  134. .form-wrapper {
  135. border: 1px solid #ebeef5;
  136. border-radius: 4px;
  137. padding: 20px;
  138. margin: 20px 0;
  139. }
  140. .action-buttons {
  141. display: flex;
  142. justify-content: space-between;
  143. align-items: center;
  144. }
  145. .step-indicator {
  146. color: #666;
  147. font-size: 14px;
  148. }
  149. </style>