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>
<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="flag-title light-color">基础信息</div>
<up-form-item
@@ -124,6 +124,7 @@
:auto-upload="false"
width="200"
@afterRead="onUploadAfterRead($event, 'licencePhoto', 'licencePhotoFileList')"
@delete="onUploadDelete($event, 'licencePhoto', 'licencePhotoFileList')"
:max-count="1"
></u-upload>
@@ -161,6 +162,7 @@
:auto-upload="false"
width="200"
@afterRead="onUploadAfterRead($event, 'legalPhoto', 'legalPhotoFileList')"
@delete="onUploadDelete($event, 'legalPhoto', 'legalPhotoFileList')"
:max-count="1"
></u-upload>
<u-upload
@@ -168,6 +170,7 @@
:auto-upload="false"
width="200"
@afterRead="onUploadAfterRead($event, 'legalPhoto', 'legalPhotoBackFileList')"
@delete="onUploadDelete($event, 'legalPhoto', 'legalPhotoBackFileList')"
:max-count="1"
></u-upload>
</div>
@@ -187,8 +190,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch, getCurrentInstance } from 'vue'
import { onReady } from '@dcloudio/uni-app'
import { ref, reactive, computed, watch, getCurrentInstance, onMounted } from 'vue'
import { useStore } from '@/store'
import { applyFirst } from '@/api/entry'
import MCity from '@/components/m-city/m-city.vue'
@@ -278,8 +280,10 @@ const rules = {
legalPhoto: [
{ required: true, message: '请上传法人身份证照片' },
{
validator: (_rule: unknown, value: string | string[]) =>
Array.isArray(value) ? value.length === 2 : false,
validator: (_rule: unknown, value: string | string[]) => {
const urls = normalizePhotoUrls(value)
return urls.length === 2
},
message: '请上传法人身份证正反照片',
trigger: ['change', 'blur'],
},
@@ -297,24 +301,53 @@ watch(
(val) => {
if (val) {
Object.assign(form, val)
const judgeDeepPhoto = ['legalPhoto', 'licencePhoto'] as const
const fileListMap = {
legalPhoto: legalPhotoFileList,
licencePhoto: licencePhotoFileList,
}
judgeDeepPhoto.forEach((key) => {
if (form[key]) {
form[key].split(',').forEach((item: string) => {
fileListMap[key].value.push({ url: item })
})
}
})
restorePhotoFields(val)
}
},
{ 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)
})
@@ -334,17 +367,40 @@ function onUploadAfterRead(
}
handleUploadAfterRead(event, fileListMap[fileListKey].value, () => {
if (key === 'legalPhoto') {
form[key] = [
...getUploadedUrls(legalPhotoFileList.value),
...getUploadedUrls(legalPhotoBackFileList.value),
]
} else {
form[key] = getUploadedUrls(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') {
form[key] = [
...getUploadedUrls(legalPhotoFileList.value),
...getUploadedUrls(legalPhotoBackFileList.value),
]
return
}
if (key === 'licencePhoto') {
form[key] = getUploadedUrls(licencePhotoFileList.value)
}
}
function getPickerParentValue(e: any[]) {
form.companyAddressIdPath = []
@@ -366,26 +422,28 @@ function showPicker() {
cityPicker.value?.show()
}
function validatorStep1Form() {
uForm.value?.validate(async (valid: boolean) => {
if (valid) {
const params = { ...form }
async function validatorStep1Form() {
try {
await uForm.value?.validate()
} catch {
return
}
params.legalPhoto = params.legalPhoto.toString()
params.licencePhoto = params.licencePhoto.toString()
params.companyAddressIdPath = params.companyAddressIdPath.toString()
delete params.complexAddress
const params = { ...form }
const res = await applyFirst(params)
if (res.data.success) {
uni.showToast({
title: '提交成功!',
icon: 'none',
})
emit('callback')
}
}
})
params.legalPhoto = params.legalPhoto.toString()
params.licencePhoto = params.licencePhoto.toString()
params.companyAddressIdPath = params.companyAddressIdPath.toString()
delete params.complexAddress
const res = await applyFirst(params)
if (res.data.success) {
uni.showToast({
title: '提交成功!',
icon: 'none',
})
emit('callback')
}
}
</script>
<style lang="scss">
@@ -399,6 +457,21 @@ page {
.wrapper {
@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 {

View File

@@ -1,6 +1,6 @@
<template>
<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="flag-title light-color">基础信息</div>
<up-form-item
@@ -48,8 +48,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { onReady } from '@dcloudio/uni-app'
import { ref, reactive, computed, watch, onMounted } from 'vue'
import { useStore } from '@/store'
import { applySecond } from '@/api/entry'
import { getThemeStyle } from '@/utils/theme'
@@ -96,24 +95,25 @@ watch(
{ deep: true, immediate: true }
)
onReady(() => {
onMounted(() => {
uForm.value?.setRules(rules)
})
function validatorStep2Form() {
uForm.value?.validate(async (valid: boolean) => {
if (valid) {
const params = { ...form }
const res = await applySecond(params)
if (res.data.success) {
uni.showToast({
title: '提交成功!',
icon: 'none',
})
emit('callback')
}
}
})
async function validatorStep2Form() {
try {
await uForm.value?.validate()
} catch {
return
}
const params = { ...form }
const res = await applySecond(params)
if (res.data.success) {
uni.showToast({
title: '提交成功!',
icon: 'none',
})
emit('callback')
}
}
</script>
<style lang="scss">

View File

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