用户中心样式调整
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import ChooseImage from "@/components/choose-image/choose-image.vue";
|
||||
import {appFeedbackAddPost} from "@/service";
|
||||
import { appFeedbackAddPost } from "@/service";
|
||||
import { z } from 'zod';
|
||||
const {t} = useI18n()
|
||||
const { t } = useI18n()
|
||||
|
||||
const form = ref({
|
||||
content: '',
|
||||
@@ -24,9 +24,37 @@ const createValidationSchema = () => {
|
||||
}
|
||||
|
||||
const chooseImageRef = ref()
|
||||
const showNoticePopup = ref(true)
|
||||
const confirmCountdown = ref(5)
|
||||
let countdownTimer: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
// 校验单个字段
|
||||
const validateField = (field: keyof typeof form.value) => {
|
||||
function startNoticeCountdown() {
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer)
|
||||
}
|
||||
confirmCountdown.value = 5
|
||||
countdownTimer = setInterval(() => {
|
||||
if (confirmCountdown.value <= 1) {
|
||||
confirmCountdown.value = 0
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = null
|
||||
}
|
||||
return
|
||||
}
|
||||
confirmCountdown.value -= 1
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function handleCloseNoticePopup() {
|
||||
if (confirmCountdown.value > 0) {
|
||||
return
|
||||
}
|
||||
showNoticePopup.value = false
|
||||
}
|
||||
|
||||
// 校验单个字段(只校验 schema 中存在的字段)
|
||||
const validateField = (field: 'content' | 'contactPhone') => {
|
||||
try {
|
||||
const schema = createValidationSchema()
|
||||
const fieldSchema = schema.shape[field]
|
||||
@@ -64,12 +92,12 @@ const handleSubmit = () => {
|
||||
if (!validateForm()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
appFeedbackAddPost({
|
||||
body: {
|
||||
...form.value
|
||||
}
|
||||
}).then(res=> {
|
||||
}).then(res => {
|
||||
uni.showToast({
|
||||
title: t('toast.submitSuccess'),
|
||||
icon: 'none'
|
||||
@@ -88,79 +116,217 @@ const handleChooseImage = () => {
|
||||
function onImageChange(files: string[]) {
|
||||
form.value.images = files[0]
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
startNoticeCountdown()
|
||||
})
|
||||
|
||||
onUnload(() => {
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = null
|
||||
}
|
||||
})
|
||||
</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 class="complaints-root">
|
||||
<navbar :title="t('pages-user.complaints.title')" />
|
||||
<view class="complaints-page">
|
||||
|
||||
|
||||
<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 class="form-card">
|
||||
<view class="field">
|
||||
<view class="field__label">{{ t('pages-user.complaints.feedback-content') }}</view>
|
||||
<view class="field__box field__box--textarea">
|
||||
<wd-textarea v-model="form.content" :maxlength="500" custom-class="!bg-transparent"
|
||||
custom-textarea-container-class="!bg-transparent" no-border auto-height
|
||||
:placeholder="t('pages-user.complaints.feedback-content-placeholder')" @blur="validateField('content')" />
|
||||
</view>
|
||||
</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 class="field field--mt">
|
||||
<view class="field__label">{{ t('pages-user.complaints.image') }}</view>
|
||||
<view class="upload" @click="handleChooseImage">
|
||||
<image v-if="form.images" src="@img/chef/113.png" class="upload__remove"></image>
|
||||
<image v-if="!form.images" src="@img/chef/112.png" class="upload__placeholder"></image>
|
||||
<image v-else :src="form.images" class="upload__image" mode="aspectFill"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="field field--mt">
|
||||
<view class="field__label">{{ t('pages-user.complaints.contact-information') }}</view>
|
||||
<view class="field__box field__box--input">
|
||||
<wd-input v-model.trim="form.contactPhone" no-border custom-class="!p-0 !bg-transparent"
|
||||
custom-input-class="complaints-input" :placeholder="t('pages-user.complaints.contact-information-placeholder')" :maxlength="50"
|
||||
@blur="validateField('contactPhone')" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<view class="complaints-page__desc">
|
||||
{{ t('pages-user.complaints.description') }}
|
||||
</view>
|
||||
|
||||
<!-- 底部固定提交按钮 -->
|
||||
<view class="bottom-actions">
|
||||
<wd-button custom-class="submit-btn" block @click="handleSubmit">
|
||||
{{ t('common.submit') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<ChooseImage ref="chooseImageRef" @change="onImageChange" />
|
||||
|
||||
<wd-popup v-model="showNoticePopup" :close-on-click-modal="false" custom-class="!bg-transparent">
|
||||
<view class="notice-dialog">
|
||||
<view class="notice-dialog__title">{{ t('pages-user.complaints.title') }}</view>
|
||||
<view class="notice-dialog__content">
|
||||
{{ t('pages-user.complaints.contact-information-tip') }}
|
||||
</view>
|
||||
<wd-button
|
||||
custom-class="notice-dialog__btn"
|
||||
block
|
||||
:disabled="confirmCountdown > 0"
|
||||
@click="handleCloseNoticePopup"
|
||||
>
|
||||
{{ confirmCountdown > 0 ? `${t('common.gotIt')} (${confirmCountdown}s)` : t('common.gotIt') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
</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>
|
||||
.complaints-page {
|
||||
padding: 32rpx 30rpx calc(160rpx + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.complaints-page__desc {
|
||||
font-size: 22rpx;
|
||||
line-height: 36rpx;
|
||||
color: #333;
|
||||
margin-bottom: 18rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 26rpx 24rpx 18rpx;
|
||||
}
|
||||
|
||||
.field__label {
|
||||
font-size: 26rpx;
|
||||
line-height: 36rpx;
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.field--mt {
|
||||
margin-top: 26rpx;
|
||||
}
|
||||
|
||||
.field__box {
|
||||
border: 1rpx solid #ececec;
|
||||
border-radius: 18rpx;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.field__box--textarea {
|
||||
padding: 14rpx 16rpx;
|
||||
min-height: 240rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.field__box--input {
|
||||
padding: 18rpx 16rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:deep(.complaints-input) {
|
||||
text-align: left;
|
||||
font-size: 26rpx;
|
||||
line-height: 36rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.upload {
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
border: 1rpx solid #ececec;
|
||||
border-radius: 18rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.upload__placeholder,
|
||||
.upload__image {
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
}
|
||||
|
||||
.upload__remove {
|
||||
position: absolute;
|
||||
top: -10rpx;
|
||||
right: -10rpx;
|
||||
z-index: 2;
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
bottom: calc(36rpx + env(safe-area-inset-bottom));
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
:deep(.submit-btn) {
|
||||
height: 108rpx !important;
|
||||
border-radius: 999rpx !important;
|
||||
background: #111 !important;
|
||||
color: #fff !important;
|
||||
font-size: 32rpx !important;
|
||||
font-weight: 800 !important;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.notice-dialog {
|
||||
width: 620rpx;
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 36rpx 28rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.notice-dialog__title {
|
||||
text-align: center;
|
||||
font-size: 30rpx;
|
||||
line-height: 40rpx;
|
||||
color: #222;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.notice-dialog__content {
|
||||
margin-top: 18rpx;
|
||||
margin-bottom: 28rpx;
|
||||
font-size: 26rpx;
|
||||
line-height: 38rpx;
|
||||
color: #666;
|
||||
// text-align: center;
|
||||
}
|
||||
|
||||
:deep(.notice-dialog__btn) {
|
||||
height: 84rpx !important;
|
||||
border-radius: 999rpx !important;
|
||||
font-size: 28rpx !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user