go-flow.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <template>
  2. <!-- 第一步:个人实名 -->
  3. <div v-if="currentStep === 1" class="form-container">
  4. <el-button class="back-btn" @click="handleBack"> 返回 </el-button>
  5. <!-- 进度条 -->
  6. <div class="progress-container">
  7. <el-steps align-center>
  8. <el-step>
  9. <template #title>
  10. <div class="step-title-wrapper">
  11. <span class="step-title">个人实名</span>
  12. <span class="step-time">约3分钟</span>
  13. </div>
  14. </template>
  15. </el-step>
  16. <el-step>
  17. <template #title>
  18. <div class="step-title-wrapper">
  19. <span class="step-title">填写信息</span>
  20. <span class="step-time">约30分钟</span>
  21. </div>
  22. </template>
  23. </el-step>
  24. <el-step>
  25. <template #title>
  26. <div class="step-title-wrapper">
  27. <span class="step-title">等待审核</span>
  28. <span class="step-time">约1-3个工作日</span>
  29. </div>
  30. </template>
  31. </el-step>
  32. <el-step>
  33. <template #title>
  34. <div class="step-title-wrapper">
  35. <span class="step-title">入驻成功</span>
  36. </div>
  37. </template>
  38. </el-step>
  39. </el-steps>
  40. </div>
  41. <!-- 表单 -->
  42. <div class="form-content">
  43. <el-form :model="step1Form" :rules="step1Rules" ref="step1FormRef" label-width="120px">
  44. <el-form-item label="姓名" prop="name">
  45. <el-input v-model="step1Form.name" placeholder="请输入姓名" style="width: 400px" />
  46. </el-form-item>
  47. <el-form-item label="身份证号码" prop="idNumber">
  48. <el-input v-model="step1Form.idNumber" placeholder="请输入身份证号码" style="width: 400px" />
  49. </el-form-item>
  50. </el-form>
  51. </div>
  52. <!-- 按钮 -->
  53. <div class="form-actions">
  54. <el-button type="primary" size="large" @click="handleNextStep"> 下一步 </el-button>
  55. </div>
  56. </div>
  57. <!-- 第二步:填写信息 -->
  58. <div v-if="currentStep === 2" class="form-container">
  59. <el-button class="back-btn" @click="handleBack"> 返回 </el-button>
  60. <!-- 进度条 -->
  61. <div class="progress-container">
  62. <el-steps :active="currentStep - 1" align-center>
  63. <el-step>
  64. <template #title>
  65. <div class="step-title-wrapper">
  66. <span class="step-title">个人实名</span>
  67. <span class="step-time">约3分钟</span>
  68. </div>
  69. </template>
  70. </el-step>
  71. <el-step>
  72. <template #title>
  73. <div class="step-title-wrapper">
  74. <span class="step-title">填写信息</span>
  75. <span class="step-time">约30分钟</span>
  76. </div>
  77. </template>
  78. </el-step>
  79. <el-step>
  80. <template #title>
  81. <div class="step-title-wrapper">
  82. <span class="step-title">等待审核</span>
  83. <span class="step-time">约1-3个工作日</span>
  84. </div>
  85. </template>
  86. </el-step>
  87. <el-step>
  88. <template #title>
  89. <div class="step-title-wrapper">
  90. <span class="step-title">入驻成功</span>
  91. </div>
  92. </template>
  93. </el-step>
  94. </el-steps>
  95. </div>
  96. <!-- 表单内容 -->
  97. <div class="form-content step2-form">
  98. <el-form :model="step2Form" :rules="step2Rules" ref="step2FormRef" label-width="125px">
  99. <div class="form-row">
  100. <!-- 左列 -->
  101. <div class="form-col">
  102. <el-form-item label="店铺名称" prop="storeName">
  103. <el-input v-model="step2Form.storeName" placeholder="请输入店铺名称" />
  104. </el-form-item>
  105. <el-form-item label="容纳人数" prop="capacity">
  106. <el-input-number v-model="step2Form.capacity" :min="1" :max="9999" />
  107. </el-form-item>
  108. <el-form-item label="门店电话" prop="storePhone">
  109. <el-input v-model="step2Form.storePhone" placeholder="请输入门店电话" />
  110. </el-form-item>
  111. <el-form-item label="门店面积" prop="storeArea">
  112. <el-radio-group v-model="step2Form.storeArea">
  113. <el-radio label="小于20平米"> 小于20平米 </el-radio>
  114. <el-radio label="20-50平米"> 20-50平米 </el-radio>
  115. <el-radio label="50-100平米"> 50-100平米 </el-radio>
  116. <el-radio label="100-300平米"> 100-300平米 </el-radio>
  117. <el-radio label="300-500平米"> 300-500平米 </el-radio>
  118. <el-radio label="500-1000平米"> 500-1000平米 </el-radio>
  119. <el-radio label="大于1000平米"> 大于1000平米 </el-radio>
  120. </el-radio-group>
  121. </el-form-item>
  122. <el-form-item label="所在地区" prop="location">
  123. <el-select v-model="step2Form.province" placeholder="请选择" style="width: 150px; margin-right: 10px">
  124. <el-option label="省份" value="province" />
  125. </el-select>
  126. <el-select v-model="step2Form.city" placeholder="请选择" style="width: 150px; margin-right: 10px">
  127. <el-option label="城市" value="city" />
  128. </el-select>
  129. <el-select v-model="step2Form.district" placeholder="请选择" style="width: 150px">
  130. <el-option label="区县" value="district" />
  131. </el-select>
  132. </el-form-item>
  133. <el-form-item label="详细地址" prop="detailedAddress">
  134. <el-input v-model="step2Form.detailedAddress" type="textarea" :rows="3" placeholder="请输入" />
  135. </el-form-item>
  136. <el-form-item label="门店简介" prop="storeIntro">
  137. <el-input v-model="step2Form.storeIntro" type="textarea" :rows="3" placeholder="请输入" />
  138. </el-form-item>
  139. <el-form-item label="经营板块" prop="businessSector">
  140. <el-radio-group v-model="step2Form.businessSector">
  141. <el-radio label="美食"> 美食 </el-radio>
  142. <el-radio label="酒店/民宿"> 酒店/民宿 </el-radio>
  143. <el-radio label="KTV"> KTV </el-radio>
  144. <el-radio label="洗浴汗蒸"> 洗浴汗蒸 </el-radio>
  145. <el-radio label="按摩足疗"> 按摩足疗 </el-radio>
  146. <el-radio label="丽人美发"> 丽人美发 </el-radio>
  147. <el-radio label="运动健身"> 运动健身 </el-radio>
  148. <el-radio label="医美医疗"> 医美医疗 </el-radio>
  149. </el-radio-group>
  150. </el-form-item>
  151. <el-form-item label="经营种类" prop="businessType">
  152. <el-checkbox-group v-model="step2Form.businessType">
  153. <el-checkbox label="小吃快餐"> 小吃快餐 </el-checkbox>
  154. <el-checkbox label="鱼鲜海鲜"> 鱼鲜海鲜 </el-checkbox>
  155. <el-checkbox label="烧烤烤串"> 烧烤烤串 </el-checkbox>
  156. <el-checkbox label="自助餐"> 自助餐 </el-checkbox>
  157. <el-checkbox label="面包蛋糕甜品"> 面包蛋糕甜品 </el-checkbox>
  158. <el-checkbox label="火锅"> 火锅 </el-checkbox>
  159. <el-checkbox label="水果生鲜"> 水果生鲜 </el-checkbox>
  160. <el-checkbox label="特色菜"> 特色菜 </el-checkbox>
  161. <el-checkbox label="中餐"> 中餐 </el-checkbox>
  162. <el-checkbox label="西餐"> 西餐 </el-checkbox>
  163. <el-checkbox label="烤肉"> 烤肉 </el-checkbox>
  164. <el-checkbox label="韩式料理"> 韩式料理 </el-checkbox>
  165. <el-checkbox label="地方菜系"> 地方菜系 </el-checkbox>
  166. <el-checkbox label="日式料理"> 日式料理 </el-checkbox>
  167. <el-checkbox label="轻食"> 轻食 </el-checkbox>
  168. </el-checkbox-group>
  169. </el-form-item>
  170. </div>
  171. <!-- 右列 -->
  172. <div class="form-col">
  173. <el-form-item label="门店营业状态" prop="businessStatus">
  174. <el-radio-group v-model="step2Form.businessStatus">
  175. <el-radio label="正常营业"> 正常营业 </el-radio>
  176. <el-radio label="暂停营业"> 暂停营业 </el-radio>
  177. <el-radio label="筹建中"> 筹建中 </el-radio>
  178. </el-radio-group>
  179. </el-form-item>
  180. <el-form-item label="经纬度查询" prop="coordinates">
  181. <el-input v-model="step2Form.coordinates" placeholder="请输入经纬度" />
  182. </el-form-item>
  183. <el-form-item label="营业执照" prop="businessLicense">
  184. <el-upload
  185. v-model:file-list="step2Form.businessLicenseFiles"
  186. action="#"
  187. list-type="picture-card"
  188. :limit="1"
  189. :on-exceed="handleExceed"
  190. >
  191. <el-icon><Plus /></el-icon>
  192. <template #tip>
  193. <div class="el-upload__tip">(0/1)</div>
  194. </template>
  195. </el-upload>
  196. </el-form-item>
  197. <el-form-item label="合同图片" prop="contractImages">
  198. <el-upload
  199. v-model:file-list="step2Form.contractImageFiles"
  200. action="#"
  201. list-type="picture-card"
  202. :limit="20"
  203. :on-exceed="handleExceed"
  204. >
  205. <el-icon><Plus /></el-icon>
  206. <template #tip>
  207. <div class="el-upload__tip">(0/20)</div>
  208. </template>
  209. </el-upload>
  210. </el-form-item>
  211. <el-form-item label="食品经营许可证" prop="foodLicense">
  212. <el-upload
  213. v-model:file-list="step2Form.foodLicenseFiles"
  214. action="#"
  215. list-type="picture-card"
  216. :limit="1"
  217. :on-exceed="handleExceed"
  218. >
  219. <el-icon><Plus /></el-icon>
  220. <template #tip>
  221. <div class="el-upload__tip">(0/1)</div>
  222. </template>
  223. </el-upload>
  224. </el-form-item>
  225. </div>
  226. </div>
  227. </el-form>
  228. </div>
  229. <!-- 按钮 -->
  230. <div class="form-actions">
  231. <el-button size="large" @click="handlePrevStep"> 上一步 </el-button>
  232. <el-button type="primary" size="large" @click="handleSubmit"> 提交 </el-button>
  233. </div>
  234. </div>
  235. </template>
  236. <script setup lang="ts">
  237. import { ref, reactive, watch } from "vue";
  238. import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
  239. import { Plus } from "@element-plus/icons-vue";
  240. const props = defineProps({
  241. currentStep: {
  242. type: Number,
  243. value: 0
  244. }
  245. });
  246. const emit = defineEmits(["update:currentStep"]);
  247. // 内部步骤状态,和父组件同步
  248. const currentStep = ref<number>(props.currentStep || 0);
  249. watch(
  250. () => props.currentStep,
  251. val => {
  252. if (typeof val === "number") currentStep.value = val;
  253. }
  254. );
  255. const setStep = (val: number) => {
  256. currentStep.value = val;
  257. emit("update:currentStep", val);
  258. };
  259. // 第一步表单
  260. const step1FormRef = ref<FormInstance>();
  261. const step1Form = reactive({
  262. name: "朱丽",
  263. idNumber: "231084199304282927"
  264. });
  265. const step1Rules: FormRules = {
  266. name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
  267. idNumber: [
  268. { required: true, message: "请输入身份证号码", trigger: "blur" },
  269. {
  270. pattern: /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/,
  271. message: "请输入正确的身份证号码",
  272. trigger: "blur"
  273. }
  274. ]
  275. };
  276. // 第二步表单
  277. const step2FormRef = ref<FormInstance>();
  278. const step2Form = reactive({
  279. storeName: "",
  280. capacity: 1,
  281. storePhone: "",
  282. storeArea: "小于20平米",
  283. province: "",
  284. city: "",
  285. district: "",
  286. detailedAddress: "",
  287. storeIntro: "",
  288. businessSector: "美食",
  289. businessType: ["小吃快餐", "火锅"],
  290. businessStatus: "正常营业",
  291. coordinates: "",
  292. businessLicenseFiles: [],
  293. contractImageFiles: [],
  294. foodLicenseFiles: []
  295. });
  296. const step2Rules: FormRules = {
  297. storeName: [{ required: true, message: "请输入店铺名称", trigger: "blur" }],
  298. storePhone: [{ required: true, message: "请输入门店电话", trigger: "blur" }],
  299. storeArea: [{ required: true, message: "请选择门店面积", trigger: "change" }],
  300. storeIntro: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
  301. businessSector: [{ required: true, message: "请选择经营板块", trigger: "change" }],
  302. businessType: [{ required: true, message: "请选择经营种类", trigger: "change" }],
  303. coordinates: [{ required: true, message: "请输入经纬度", trigger: "blur" }],
  304. businessLicense: [{ required: true, message: "请上传营业执照", trigger: "change" }],
  305. contractImages: [{ required: true, message: "请上传合同图片", trigger: "change" }],
  306. foodLicense: [{ required: true, message: "请上传食品经营许可证", trigger: "change" }]
  307. };
  308. // 返回按钮
  309. const handleBack = () => {
  310. if (currentStep.value === 1) {
  311. setStep(0);
  312. } else if (currentStep.value === 2) {
  313. setStep(1);
  314. }
  315. };
  316. // 下一步
  317. const handleNextStep = async () => {
  318. if (!step1FormRef.value) return;
  319. await step1FormRef.value.validate(valid => {
  320. if (valid) {
  321. setStep(2);
  322. } else {
  323. ElMessage.error("请完善表单信息");
  324. }
  325. });
  326. };
  327. // 上一步
  328. const handlePrevStep = () => {
  329. setStep(1);
  330. };
  331. // 提交
  332. const handleSubmit = async () => {
  333. if (!step2FormRef.value) return;
  334. await step2FormRef.value.validate(valid => {
  335. if (valid) {
  336. ElMessageBox.confirm("确认提交入驻申请吗?", "提示", {
  337. confirmButtonText: "确定",
  338. cancelButtonText: "取消",
  339. type: "warning"
  340. })
  341. .then(() => {
  342. // 这里可以调用API提交数据
  343. ElMessage.success("提交成功,等待审核");
  344. setStep(3); // 跳转到等待审核步骤
  345. })
  346. .catch(() => {
  347. // 取消提交
  348. });
  349. } else {
  350. ElMessage.error("请完善表单信息");
  351. }
  352. });
  353. };
  354. // 文件上传超出限制
  355. const handleExceed = () => {
  356. ElMessage.warning("文件数量超出限制");
  357. };
  358. </script>
  359. <style scoped lang="scss">
  360. // 表单页面样式
  361. .form-container {
  362. min-height: calc(100vh - 100px);
  363. padding: 30px;
  364. background: #ffffff;
  365. border-radius: 8px;
  366. .back-btn {
  367. margin-bottom: 30px;
  368. color: #606266;
  369. border-color: #dcdfe6;
  370. }
  371. .progress-container {
  372. padding: 0 100px;
  373. margin-bottom: 40px;
  374. :deep(.el-steps) {
  375. .el-step__head {
  376. .el-step__icon {
  377. width: 30px;
  378. height: 30px;
  379. font-size: 16px;
  380. font-weight: 600;
  381. }
  382. }
  383. .el-step__title {
  384. .step-title-wrapper {
  385. display: flex;
  386. flex-direction: column;
  387. gap: 8px;
  388. align-items: center;
  389. .step-title {
  390. font-size: 16px;
  391. font-weight: 600;
  392. color: #303133;
  393. }
  394. .step-time {
  395. display: inline-block;
  396. padding: 4px 12px;
  397. font-size: 12px;
  398. color: #909399;
  399. white-space: nowrap;
  400. background: #f5f7fa;
  401. border-radius: 12px;
  402. }
  403. }
  404. }
  405. }
  406. }
  407. .form-content {
  408. max-width: 800px;
  409. margin: 0 auto;
  410. &.step2-form {
  411. max-width: 1400px;
  412. .form-row {
  413. display: flex;
  414. gap: 40px;
  415. .form-col {
  416. flex: 1;
  417. }
  418. }
  419. }
  420. }
  421. .form-actions {
  422. display: flex;
  423. gap: 20px;
  424. justify-content: center;
  425. padding-top: 30px;
  426. margin-top: 40px;
  427. border-top: 1px solid #e4e7ed;
  428. .el-button {
  429. width: 150px;
  430. height: 44px;
  431. font-size: 16px;
  432. }
  433. }
  434. }
  435. </style>