refactor: 更新表单组件以增强上传功能和验证逻辑

- 在 step1.vue、step2.vue 和 step3.vue 中添加上传规则和删除功能
- 优化照片上传的处理逻辑,确保上传后能正确恢复表单状态
- 更新表单验证逻辑,使用 async/await 处理验证过程
- 修改样式以提升用户体验,确保上传组件的可用性和一致性
This commit is contained in:
田香琪
2026-08-11 10:36:47 +08:00
parent f51fcad9c2
commit ee6f66cac3
3 changed files with 167 additions and 90 deletions

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="wrapper" :style="themeStyle"> <div class="wrapper" :style="themeStyle">
<up-form label-position="top" :model="form" ref="uForm"> <up-form label-position="top" :model="form" :rules="rules" ref="uForm">
<div class="column"> <div class="column">
<div class="flag-title light-color">基础信息</div> <div class="flag-title light-color">基础信息</div>
<up-form-item <up-form-item
@@ -124,6 +124,7 @@
:auto-upload="false" :auto-upload="false"
width="200" width="200"
@afterRead="onUploadAfterRead($event, 'licencePhoto', 'licencePhotoFileList')" @afterRead="onUploadAfterRead($event, 'licencePhoto', 'licencePhotoFileList')"
@delete="onUploadDelete($event, 'licencePhoto', 'licencePhotoFileList')"
:max-count="1" :max-count="1"
></u-upload> ></u-upload>
@@ -161,6 +162,7 @@
:auto-upload="false" :auto-upload="false"
width="200" width="200"
@afterRead="onUploadAfterRead($event, 'legalPhoto', 'legalPhotoFileList')" @afterRead="onUploadAfterRead($event, 'legalPhoto', 'legalPhotoFileList')"
@delete="onUploadDelete($event, 'legalPhoto', 'legalPhotoFileList')"
:max-count="1" :max-count="1"
></u-upload> ></u-upload>
<u-upload <u-upload
@@ -168,6 +170,7 @@
:auto-upload="false" :auto-upload="false"
width="200" width="200"
@afterRead="onUploadAfterRead($event, 'legalPhoto', 'legalPhotoBackFileList')" @afterRead="onUploadAfterRead($event, 'legalPhoto', 'legalPhotoBackFileList')"
@delete="onUploadDelete($event, 'legalPhoto', 'legalPhotoBackFileList')"
:max-count="1" :max-count="1"
></u-upload> ></u-upload>
</div> </div>
@@ -187,8 +190,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, watch, getCurrentInstance } from 'vue' import { ref, reactive, computed, watch, getCurrentInstance, onMounted } from 'vue'
import { onReady } from '@dcloudio/uni-app'
import { useStore } from '@/store' import { useStore } from '@/store'
import { applyFirst } from '@/api/entry' import { applyFirst } from '@/api/entry'
import MCity from '@/components/m-city/m-city.vue' import MCity from '@/components/m-city/m-city.vue'
@@ -278,8 +280,10 @@ const rules = {
legalPhoto: [ legalPhoto: [
{ required: true, message: '请上传法人身份证照片' }, { required: true, message: '请上传法人身份证照片' },
{ {
validator: (_rule: unknown, value: string | string[]) => validator: (_rule: unknown, value: string | string[]) => {
Array.isArray(value) ? value.length === 2 : false, const urls = normalizePhotoUrls(value)
return urls.length === 2
},
message: '请上传法人身份证正反照片', message: '请上传法人身份证正反照片',
trigger: ['change', 'blur'], trigger: ['change', 'blur'],
}, },
@@ -297,24 +301,53 @@ watch(
(val) => { (val) => {
if (val) { if (val) {
Object.assign(form, val) Object.assign(form, val)
const judgeDeepPhoto = ['legalPhoto', 'licencePhoto'] as const restorePhotoFields(val)
const fileListMap = {
legalPhoto: legalPhotoFileList,
licencePhoto: licencePhotoFileList,
}
judgeDeepPhoto.forEach((key) => {
if (form[key]) {
form[key].split(',').forEach((item: string) => {
fileListMap[key].value.push({ url: item })
})
}
})
} }
}, },
{ deep: true } { deep: true }
) )
onReady(() => { function normalizePhotoUrls(value: string | string[] | undefined) {
if (Array.isArray(value)) {
return value.filter(Boolean)
}
if (typeof value === 'string' && value) {
return value.split(',').map((item) => item.trim()).filter(Boolean)
}
return []
}
function createUploadedFileItem(url: string) {
return {
url,
status: 'success',
}
}
function restorePhotoFields(data: Record<string, any>) {
licencePhotoFileList.value = []
legalPhotoFileList.value = []
legalPhotoBackFileList.value = []
const licenceUrls = normalizePhotoUrls(data.licencePhoto)
if (licenceUrls.length) {
licencePhotoFileList.value = licenceUrls.map(createUploadedFileItem)
form.licencePhoto = licenceUrls
}
const legalUrls = normalizePhotoUrls(data.legalPhoto)
if (legalUrls.length) {
legalPhotoFileList.value = legalUrls[0]
? [createUploadedFileItem(legalUrls[0])]
: []
legalPhotoBackFileList.value = legalUrls[1]
? [createUploadedFileItem(legalUrls[1])]
: []
form.legalPhoto = legalUrls
}
}
onMounted(() => {
uForm.value?.setRules(rules) uForm.value?.setRules(rules)
}) })
@@ -334,15 +367,38 @@ function onUploadAfterRead(
} }
handleUploadAfterRead(event, fileListMap[fileListKey].value, () => { handleUploadAfterRead(event, fileListMap[fileListKey].value, () => {
syncUploadFormValue(key)
})
}
function onUploadDelete(
event: { index: number },
key: string,
fileListKey: 'licencePhotoFileList' | 'legalPhotoFileList' | 'legalPhotoBackFileList'
) {
const fileListMap = {
licencePhotoFileList,
legalPhotoFileList,
legalPhotoBackFileList,
}
const list = fileListMap[fileListKey].value
if (event.index >= 0 && event.index < list.length) {
list.splice(event.index, 1)
}
syncUploadFormValue(key)
}
function syncUploadFormValue(key: string) {
if (key === 'legalPhoto') { if (key === 'legalPhoto') {
form[key] = [ form[key] = [
...getUploadedUrls(legalPhotoFileList.value), ...getUploadedUrls(legalPhotoFileList.value),
...getUploadedUrls(legalPhotoBackFileList.value), ...getUploadedUrls(legalPhotoBackFileList.value),
] ]
} else { return
form[key] = getUploadedUrls(fileListMap[fileListKey].value) }
if (key === 'licencePhoto') {
form[key] = getUploadedUrls(licencePhotoFileList.value)
} }
})
} }
function getPickerParentValue(e: any[]) { function getPickerParentValue(e: any[]) {
@@ -366,9 +422,13 @@ function showPicker() {
cityPicker.value?.show() cityPicker.value?.show()
} }
function validatorStep1Form() { async function validatorStep1Form() {
uForm.value?.validate(async (valid: boolean) => { try {
if (valid) { await uForm.value?.validate()
} catch {
return
}
const params = { ...form } const params = { ...form }
params.legalPhoto = params.legalPhoto.toString() params.legalPhoto = params.legalPhoto.toString()
@@ -384,8 +444,6 @@ function validatorStep1Form() {
}) })
emit('callback') emit('callback')
} }
}
})
} }
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -399,6 +457,21 @@ page {
.wrapper { .wrapper {
@include seller-entry-form; @include seller-entry-form;
:deep(.u-upload__deletable) {
width: 24rpx;
height: 24rpx;
border-bottom-left-radius: 24rpx;
}
:deep(.u-upload__deletable__icon) {
transform: scale(1);
}
:deep(.u-upload__deletable .u-icon__icon) {
font-size: 16rpx !important;
line-height: 16rpx !important;
}
} }
.submit { .submit {

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="wrapper" :style="themeStyle"> <div class="wrapper" :style="themeStyle">
<up-form label-position="top" :model="form" ref="uForm"> <up-form label-position="top" :model="form" :rules="rules" ref="uForm">
<div class="column"> <div class="column">
<div class="flag-title light-color">基础信息</div> <div class="flag-title light-color">基础信息</div>
<up-form-item <up-form-item
@@ -48,8 +48,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue' import { ref, reactive, computed, watch, onMounted } from 'vue'
import { onReady } from '@dcloudio/uni-app'
import { useStore } from '@/store' import { useStore } from '@/store'
import { applySecond } from '@/api/entry' import { applySecond } from '@/api/entry'
import { getThemeStyle } from '@/utils/theme' import { getThemeStyle } from '@/utils/theme'
@@ -96,13 +95,16 @@ watch(
{ deep: true, immediate: true } { deep: true, immediate: true }
) )
onReady(() => { onMounted(() => {
uForm.value?.setRules(rules) uForm.value?.setRules(rules)
}) })
function validatorStep2Form() { async function validatorStep2Form() {
uForm.value?.validate(async (valid: boolean) => { try {
if (valid) { await uForm.value?.validate()
} catch {
return
}
const params = { ...form } const params = { ...form }
const res = await applySecond(params) const res = await applySecond(params)
if (res.data.success) { if (res.data.success) {
@@ -112,8 +114,6 @@ function validatorStep2Form() {
}) })
emit('callback') emit('callback')
} }
}
})
} }
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="wrapper" :style="themeStyle"> <div class="wrapper" :style="themeStyle">
<up-form label-position="top" :model="form" ref="uForm"> <up-form label-position="top" :model="form" :rules="rules" ref="uForm">
<div class="column"> <div class="column">
<div class="flag-title light-color">基础信息</div> <div class="flag-title light-color">基础信息</div>
<up-form-item <up-form-item
@@ -109,11 +109,14 @@
> >
</m-city> </m-city>
<u-select <u-picker
v-model:show="enableCategory" v-model:show="enableCategory"
:columns="[categoryList]"
keyName="label"
valueName="value"
title="店铺经营类目"
@confirm="confirmCategory" @confirm="confirmCategory"
:list="categoryList" ></u-picker>
></u-select>
<uniMap v-if="mapFlag" @close="closeMap" @callback="callBackAddress" /> <uniMap v-if="mapFlag" @close="closeMap" @callback="callBackAddress" />
</div> </div>
@@ -121,7 +124,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, watch, onMounted } from 'vue' import { ref, reactive, computed, watch, onMounted } from 'vue'
import { onReady } from '@dcloudio/uni-app'
import { useStore } from '@/store' import { useStore } from '@/store'
import { applyThird } from '@/api/entry' import { applyThird } from '@/api/entry'
import { getCategoryList } from '@/api/goods' import { getCategoryList } from '@/api/goods'
@@ -197,11 +199,8 @@ watch(
{ deep: true, immediate: true } { deep: true, immediate: true }
) )
onReady(() => {
uForm.value?.setRules(rules)
})
onMounted(() => { onMounted(() => {
uForm.value?.setRules(rules)
fetchCategoryList() fetchCategoryList()
}) })
@@ -266,9 +265,13 @@ async function requestAndroidPermission(permisionID: string) {
} }
} }
function confirmCategory(val: any[]) { function confirmCategory(val: any) {
form.goodsManagementCategory = val[0].value const selected = val?.value?.[0] || val?.[0]
goodsManagementCategory.value = val[0].label if (!selected) {
return
}
form.goodsManagementCategory = selected.value
goodsManagementCategory.value = selected.label
} }
async function fetchCategoryList() { async function fetchCategoryList() {
@@ -324,9 +327,12 @@ function showCategory() {
enableCategory.value = true enableCategory.value = true
} }
function validatorStep3Form() { async function validatorStep3Form() {
uForm.value?.validate(async (valid: boolean) => { try {
if (valid) { await uForm.value?.validate()
} catch {
return
}
const params = { ...form } const params = { ...form }
params.storeLogo = params.storeLogo.toString() params.storeLogo = params.storeLogo.toString()
params.storeAddressIdPath = params.storeAddressIdPath.toString() params.storeAddressIdPath = params.storeAddressIdPath.toString()
@@ -338,8 +344,6 @@ function validatorStep3Form() {
}) })
emit('callback') emit('callback')
} }
}
})
} }
</script> </script>
<style lang="scss"> <style lang="scss">