first commit

This commit is contained in:
2026-02-26 09:32:03 +08:00
commit 36a8e4c51b
845 changed files with 116474 additions and 0 deletions
+166
View File
@@ -0,0 +1,166 @@
<script setup lang="ts">
import ChooseImage from "@/components/choose-image/choose-image.vue";
import {appFeedbackAddPost} from "@/service";
import { z } from 'zod';
const {t} = useI18n()
const form = ref({
content: '',
contactPhone: '',
images: '',
})
// 创建zod校验schema
const createValidationSchema = () => {
return z.object({
content: z.string()
.min(1, t('pages-user.complaints.validation.content-required'))
.min(10, t('pages-user.complaints.validation.content-min-length'))
.max(500, t('pages-user.complaints.validation.content-max-length')),
contactPhone: z.string()
.min(1, t('pages-user.complaints.validation.contact-phone-required'))
.regex(/^[\d\s\-\+\(\)]+$/, t('pages-user.complaints.validation.contact-phone-invalid'))
})
}
const chooseImageRef = ref()
// 校验单个字段
const validateField = (field: keyof typeof form.value) => {
try {
const schema = createValidationSchema()
const fieldSchema = schema.shape[field]
fieldSchema.parse(form.value[field])
return true
} catch (error) {
if (error instanceof z.ZodError) {
uni.showToast({
title: error.errors[0].message,
icon: 'none'
})
}
return false
}
}
// 校验整个表单
const validateForm = () => {
try {
const schema = createValidationSchema()
schema.parse(form.value)
return true
} catch (error) {
if (error instanceof z.ZodError) {
uni.showToast({
title: error.errors[0].message,
icon: 'none'
})
}
return false
}
}
const handleSubmit = () => {
if (!validateForm()) {
return
}
appFeedbackAddPost({
body: {
...form.value
}
}).then(res=> {
uni.showToast({
title: t('toast.submitSuccess'),
icon: 'none'
})
form.value = {
content: '',
contactPhone: '',
images: '',
}
})
}
const handleChooseImage = () => {
chooseImageRef.value.init()
}
function onImageChange(files: string[]) {
form.value.images = files[0]
}
</script>
<template>
<navbar :title="t('pages-user.complaints.title')" />
<view class="px-18rpx">
<view class="mb-27rpx mt-32rpx text-28rpx text-#333">
{{ t('pages-user.complaints.description') }}
</view>
<view class="bg-white rounded-14rpx px-18rpx pt-30rpx pb-24rpx">
<view class="text-28rpx text-#333 mb-28rpx">{{ t('pages-user.complaints.feedback-content') }}</view>
<view
class="min-h-234rpx box-border bg-#F6F6F6 rounded-14rpx overflow-hidden px-18rpx py-10rpx"
>
<wd-textarea
v-model="form.content"
:maxlength="500"
custom-class="!bg-#F6F6F6"
custom-textarea-container-class="!bg-#F6F6F6"
no-border
auto-height
:placeholder="t('pages-user.complaints.feedback-content-placeholder')"
@blur="validateField('content')"
/>
</view>
<view>
<view class="text-28rpx text-#333 mt-32rpx mb-24rpx">{{ t('pages-user.complaints.image') }}:</view>
<view @click="handleChooseImage" class="relative w-210rpx h-210rpx">
<image
v-if="form.images"
src="@img/chef/113.png"
class="absolute top--10rpx right--10rpx z-10 w-36rpx h-36rpx"
></image>
<image
v-if="!form.images"
src="@img/chef/112.png"
class="w-210rpx h-210rpx"
></image>
<image
v-else
:src="form.images"
class="w-210rpx h-210rpx rounded-16rpx"
mode="aspectFill"
></image>
</view>
</view>
</view>
<view class="mt-14rpx flex-center-sb bg-white h-86rpx rounded-14rpx px-18rpx">
<view class="text-28rpx text-#333 ">{{ t('pages-user.complaints.contact-information') }}:</view>
<wd-input
no-border
custom-class="!p-[12rpx+20rpx] rounded-10rpx"
v-model.trim="form.contactPhone"
placeholderStyle="font-size: 28rpx;line-height: 40rpx;color: #B1B1B1; text-align: right;"
:placeholder="t('common.enter')"
:maxlength="50"
custom-input-class="text-right"
@blur="validateField('contactPhone')"
/>
</view>
<view class="mt-38rpx text-28rpx text-#999">
{{ t('pages-user.complaints.contact-information-tip') }}
</view>
<fixed-bottom-large-btn
class="z-100"
fixed
:text="`${t('common.submit')}`"
@click="handleSubmit"
/>
<ChooseImage ref="chooseImageRef" @change="onImageChange" />
</view>
</template>
<style lang="scss" scoped>
</style>