feat: 报告中增过程中媒体区块,单按钮上传照片/视频;基础信息折叠优化
This commit is contained in:
parent
d6b4419225
commit
1e10ebc759
@ -341,13 +341,6 @@ const loadReport = async () => {
|
||||
else notFound.value = true
|
||||
}
|
||||
|
||||
const playVideo = (url) => {
|
||||
if (!url) return
|
||||
uni.navigateTo({
|
||||
url: `/pages/video-player/videoPlayer?url=${encodeURIComponent(url)}`
|
||||
})
|
||||
}
|
||||
|
||||
const goHome = () => uni.reLaunch({ url: '/pages/home/Home' })
|
||||
|
||||
const callStore = () => {
|
||||
@ -383,6 +376,13 @@ const previewPhotos = (group, index = 0) => {
|
||||
})
|
||||
}
|
||||
|
||||
const playVideo = (url) => {
|
||||
if (!url) return
|
||||
uni.navigateTo({
|
||||
url: `/pages/video-player/videoPlayer?url=${encodeURIComponent(url)}`
|
||||
})
|
||||
}
|
||||
|
||||
onShareAppMessage(() => {
|
||||
const q = routeToken.value ? `token=${encodeURIComponent(routeToken.value)}` : ''
|
||||
return {
|
||||
|
||||
@ -9,41 +9,44 @@
|
||||
<view class="report-body">
|
||||
<!-- 基础信息 -->
|
||||
<view class="section">
|
||||
<view class="section-head">
|
||||
<view class="section-head section-head--clickable" @click="basicInfoCollapsed = !basicInfoCollapsed">
|
||||
<text class="section-label">基础信息</text>
|
||||
<text class="section-toggle">{{ basicInfoCollapsed ? '展开' : '收起' }}</text>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">宠物名字</text>
|
||||
<input v-model="report.petName" class="form-input" placeholder="请输入宠物名字" />
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">服务类型</text>
|
||||
<picker mode="selector" :range="serviceColumns" range-key="label" @change="onServiceConfirm">
|
||||
<view class="form-input form-picker">
|
||||
<text :class="{ placeholder: !report.serviceType }">{{ report.serviceType || '请选择' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
<view v-show="!basicInfoCollapsed">
|
||||
<view class="form-row">
|
||||
<text class="form-label">宠物名字</text>
|
||||
<input v-model="report.petName" class="form-input" placeholder="请输入宠物名字" />
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">服务类型</text>
|
||||
<picker mode="selector" :range="serviceColumns" range-key="label" @change="onServiceConfirm">
|
||||
<view class="form-input form-picker">
|
||||
<text :class="{ placeholder: !report.serviceType }">{{ report.serviceType || '请选择' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">服务时间</text>
|
||||
<view class="time-row">
|
||||
<picker mode="date" :value="serviceDate" @change="onServiceDateChange" class="time-picker">
|
||||
<view class="form-input form-picker">
|
||||
<text :class="{ placeholder: !serviceDate }">{{ serviceDate || '日期' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
:range="HALF_HOUR_TIME_SLOTS"
|
||||
:value="halfHourServiceTimeIndex"
|
||||
@change="onServiceTimeChange"
|
||||
class="time-picker"
|
||||
>
|
||||
<view class="form-input form-picker">
|
||||
<text :class="{ placeholder: !serviceTimePart }">{{ serviceTimePart || '时间' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">服务时间</text>
|
||||
<view class="time-row">
|
||||
<picker mode="date" :value="serviceDate" @change="onServiceDateChange" class="time-picker">
|
||||
<view class="form-input form-picker">
|
||||
<text :class="{ placeholder: !serviceDate }">{{ serviceDate || '日期' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
:range="HALF_HOUR_TIME_SLOTS"
|
||||
:value="halfHourServiceTimeIndex"
|
||||
@change="onServiceTimeChange"
|
||||
class="time-picker"
|
||||
>
|
||||
<view class="form-input form-picker">
|
||||
<text :class="{ placeholder: !serviceTimePart }">{{ serviceTimePart || '时间' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -66,7 +69,7 @@
|
||||
<image :src="item.url" class="thumb-img" mode="aspectFill" />
|
||||
<view class="thumb-del" @click="removeMedia('beforeMedia', idx)">✕</view>
|
||||
</view>
|
||||
<view v-if="report.beforeMedia.length < 4" class="photo-add" @click="uploadMedia('beforeMedia', 'photo')">
|
||||
<view v-if="report.beforeMedia.length < 4" class="photo-add" @click="uploadPhoto('beforeMedia')">
|
||||
<AppIcon name="camera" :size="20" color="#bbbbb5" />
|
||||
</view>
|
||||
</view>
|
||||
@ -84,7 +87,7 @@
|
||||
<image :src="item.url" class="thumb-img" mode="aspectFill" />
|
||||
<view class="thumb-del" @click="removeMedia('afterMedia', idx)">✕</view>
|
||||
</view>
|
||||
<view v-if="report.afterMedia.length < 4" class="photo-add" @click="uploadMedia('afterMedia', 'photo')">
|
||||
<view v-if="report.afterMedia.length < 4" class="photo-add" @click="uploadPhoto('afterMedia')">
|
||||
<AppIcon name="camera" :size="20" color="#bbbbb5" />
|
||||
</view>
|
||||
</view>
|
||||
@ -99,14 +102,10 @@
|
||||
<text class="section-hint">照片或视频,记录服务细节</text>
|
||||
</view>
|
||||
|
||||
<view class="during-actions">
|
||||
<view class="during-action-btn" @click="uploadMedia('duringMedia', 'photo')">
|
||||
<AppIcon name="camera" :size="18" color="#666660" />
|
||||
<text>上传照片</text>
|
||||
</view>
|
||||
<view class="during-action-btn during-action-btn--video" @click="uploadMedia('duringMedia', 'video')">
|
||||
<AppIcon name="video" :size="18" color="#666660" />
|
||||
<text>拍摄视频</text>
|
||||
<view class="during-add-row">
|
||||
<view class="during-add-btn" @click="uploadDuring()">
|
||||
<AppIcon name="camera" :size="18" color="#bbbbb5" />
|
||||
<text>添加照片或视频</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -121,17 +120,12 @@
|
||||
:show-play-btn="false"
|
||||
objectFit="cover"
|
||||
/>
|
||||
<!-- 视频角标 -->
|
||||
<view v-if="item.mediaType === 'video'" class="video-badge">
|
||||
<text>视频</text>
|
||||
</view>
|
||||
<view class="thumb-del" @click="removeMedia('duringMedia', idx)">✕</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="report.duringMedia.length === 0" class="during-empty">
|
||||
<text>暂无过程中记录</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 备注 -->
|
||||
@ -139,10 +133,23 @@
|
||||
<view class="section-head">
|
||||
<text class="section-label">备注</text>
|
||||
</view>
|
||||
<textarea v-model="report.remark" class="form-textarea" placeholder="服务细节、注意事项(可选)" />
|
||||
<textarea
|
||||
v-model="report.remark"
|
||||
class="form-textarea"
|
||||
placeholder="服务细节、注意事项(可选)"
|
||||
@focus="onRemarkFocus"
|
||||
@blur="onRemarkBlur"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<button class="submit-btn" :disabled="submitting" @click="submitReport">
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="submit-fixed"
|
||||
:class="{ 'submit-fixed--scrolled': hasScrolled }"
|
||||
:style="submitFixedStyle"
|
||||
>
|
||||
<button class="submit-btn submit-btn--fixed" :disabled="submitting" @click="submitReport">
|
||||
{{ submitting ? '提交中…' : '生成报告' }}
|
||||
</button>
|
||||
</view>
|
||||
@ -154,14 +161,13 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<TabBar current-page="report" @change="goPage" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { onPageScroll } from '@dcloudio/uni-app'
|
||||
import { createReport, getServiceTypeList, imgUrl, BASE_URL } from '../../api/index.js'
|
||||
import TabBar from '../../components/TabBar.vue'
|
||||
import AppIcon from '../../components/AppIcon.vue'
|
||||
import { getUserSession, getStoreSession } from '../../utils/session.js'
|
||||
import { useNavigator } from '../../composables/useNavigator.js'
|
||||
@ -175,7 +181,7 @@ import {
|
||||
|
||||
const userInfo = getUserSession()
|
||||
const storeInfo = getStoreSession()
|
||||
const { goPage, navigateTo } = useNavigator()
|
||||
const { navigateTo } = useNavigator()
|
||||
const navSafeStyle = (() => {
|
||||
const statusBarHeight = uni.getSystemInfoSync?.().statusBarHeight || 20
|
||||
let navHeight = statusBarHeight + 44
|
||||
@ -201,6 +207,17 @@ const report = ref({
|
||||
const serviceTypes = ref([])
|
||||
const currentAppointmentId = ref(null)
|
||||
const submitting = ref(false)
|
||||
const basicInfoCollapsed = ref(false)
|
||||
const hasScrolled = ref(false)
|
||||
const keyboardHeight = ref(0)
|
||||
const remarkFocused = ref(false)
|
||||
const autoCollapsedByKeyboard = ref(false)
|
||||
let keyboardChangeHandler = null
|
||||
|
||||
const submitFixedStyle = computed(() => {
|
||||
const bottom = keyboardHeight.value > 0 ? `${keyboardHeight.value}px` : '0px'
|
||||
return `bottom:${bottom};`
|
||||
})
|
||||
|
||||
const serviceColumns = computed(() =>
|
||||
serviceTypes.value.map(s => ({ label: s.name, value: s.name }))
|
||||
@ -213,99 +230,115 @@ const loadServiceTypes = async () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传媒体文件
|
||||
* @param {string} field - beforeMedia | afterMedia | duringMedia
|
||||
* @param {string} mediaType - photo | video
|
||||
* 上传照片(用于服务前/后)
|
||||
*/
|
||||
const uploadMedia = (field, mediaType) => {
|
||||
const maxTotal = 12 // 全局最多12条
|
||||
const uploadPhoto = (field) => {
|
||||
const fieldMax = 4
|
||||
const maxTotal = 12
|
||||
if (report.value[field].length >= maxTotal) {
|
||||
return uni.showToast({ title: `最多上传${maxTotal}个`, icon: 'none' })
|
||||
}
|
||||
const remain = maxTotal - report.value[field].length
|
||||
|
||||
if (mediaType === 'video') {
|
||||
// 拍摄/选择视频
|
||||
uni.chooseMedia({
|
||||
count: Math.min(remain, 4),
|
||||
mediaType: ['video'],
|
||||
success: (res) => {
|
||||
const tempFiles = res.tempFiles
|
||||
uni.showLoading({ title: '上传中...' })
|
||||
let failCount = 0
|
||||
const tasks = tempFiles.map(f => {
|
||||
return new Promise((resolve) => {
|
||||
const sizeMB = (f.size || 0) / 1024 / 1024
|
||||
if (sizeMB > 100) {
|
||||
failCount++
|
||||
uni.showToast({ title: '视频不能超过100MB', icon: 'none' })
|
||||
const count = Math.min(fieldMax - report.value[field].length, maxTotal - report.value[field].length, 4)
|
||||
uni.chooseImage({
|
||||
count,
|
||||
success: (res) => {
|
||||
const tempPaths = res.tempFilePaths
|
||||
uni.showLoading({ title: '上传中...' })
|
||||
let failCount = 0
|
||||
const tasks = tempPaths.map(tempPath => {
|
||||
return new Promise((resolve) => {
|
||||
uni.uploadFile({
|
||||
url: `${BASE_URL}/upload/image`,
|
||||
filePath: tempPath,
|
||||
name: 'file',
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data)
|
||||
if (data.code === 200) {
|
||||
report.value[field].push({ url: imgUrl(data.data.url), mediaType: 'photo' })
|
||||
} else { failCount++ }
|
||||
} catch (e) { failCount++ }
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
uni.uploadFile({
|
||||
url: `${BASE_URL}/upload/image`,
|
||||
filePath: f.tempFilePath,
|
||||
name: 'file',
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data)
|
||||
if (data.code === 200) {
|
||||
report.value[field].push({ url: imgUrl(data.data.url), mediaType: 'video' })
|
||||
} else {
|
||||
failCount++
|
||||
}
|
||||
} catch (e) { failCount++ }
|
||||
resolve()
|
||||
},
|
||||
fail: () => { failCount++; resolve() }
|
||||
})
|
||||
},
|
||||
fail: () => { failCount++; resolve() }
|
||||
})
|
||||
})
|
||||
Promise.all(tasks).then(() => {
|
||||
uni.hideLoading()
|
||||
if (failCount > 0) uni.showToast({ title: `${failCount}个上传失败`, icon: 'none' })
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 上传照片
|
||||
const fieldMax = 4
|
||||
if (report.value[field].length >= fieldMax) {
|
||||
return uni.showToast({ title: '最多上传4张', icon: 'none' })
|
||||
})
|
||||
Promise.all(tasks).then(() => {
|
||||
uni.hideLoading()
|
||||
if (failCount > 0) uni.showToast({ title: `${failCount}张上传失败`, icon: 'none' })
|
||||
})
|
||||
}
|
||||
const count = Math.min(fieldMax - report.value[field].length, remain, 4)
|
||||
uni.chooseImage({
|
||||
count,
|
||||
success: (res) => {
|
||||
const tempPaths = res.tempFilePaths
|
||||
uni.showLoading({ title: '上传中...' })
|
||||
let failCount = 0
|
||||
const tasks = tempPaths.map(tempPath => {
|
||||
return new Promise((resolve) => {
|
||||
uni.uploadFile({
|
||||
url: `${BASE_URL}/upload/image`,
|
||||
filePath: tempPath,
|
||||
name: 'file',
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data)
|
||||
if (data.code === 200) {
|
||||
report.value[field].push({ url: imgUrl(data.data.url), mediaType: 'photo' })
|
||||
} else { failCount++ }
|
||||
} catch (e) { failCount++ }
|
||||
resolve()
|
||||
},
|
||||
fail: () => { failCount++; resolve() }
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传视频(用于过程中)
|
||||
*/
|
||||
const uploadVideo = (field) => {
|
||||
const maxTotal = 12
|
||||
if (report.value[field].length >= maxTotal) {
|
||||
return uni.showToast({ title: `最多上传${maxTotal}个`, icon: 'none' })
|
||||
}
|
||||
uni.chooseMedia({
|
||||
count: 1,
|
||||
mediaType: ['video'],
|
||||
success: (res) => {
|
||||
const tempFiles = res.tempFiles
|
||||
uni.showLoading({ title: '上传中...' })
|
||||
let failCount = 0
|
||||
const tasks = tempFiles.map(f => {
|
||||
return new Promise((resolve) => {
|
||||
const sizeMB = (f.size || 0) / 1024 / 1024
|
||||
if (sizeMB > 100) {
|
||||
failCount++
|
||||
uni.showToast({ title: '视频不能超过100MB', icon: 'none' })
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
uni.uploadFile({
|
||||
url: `${BASE_URL}/upload/image`,
|
||||
filePath: f.tempFilePath,
|
||||
name: 'file',
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data)
|
||||
if (data.code === 200) {
|
||||
report.value[field].push({ url: imgUrl(data.data.url), mediaType: 'video' })
|
||||
} else { failCount++ }
|
||||
} catch (e) { failCount++ }
|
||||
resolve()
|
||||
},
|
||||
fail: () => { failCount++; resolve() }
|
||||
})
|
||||
})
|
||||
Promise.all(tasks).then(() => {
|
||||
uni.hideLoading()
|
||||
if (failCount > 0) uni.showToast({ title: `${failCount}张上传失败`, icon: 'none' })
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
Promise.all(tasks).then(() => {
|
||||
uni.hideLoading()
|
||||
if (failCount > 0) uni.showToast({ title: `${failCount}个上传失败`, icon: 'none' })
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传过程中媒体(照片或视频,弹窗选择)
|
||||
*/
|
||||
const uploadDuring = () => {
|
||||
const maxTotal = 12
|
||||
if (report.value.duringMedia.length >= maxTotal) {
|
||||
return uni.showToast({ title: `最多上传${maxTotal}个`, icon: 'none' })
|
||||
}
|
||||
uni.showActionSheet({
|
||||
itemList: ['照片', '视频'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
uploadPhoto('duringMedia')
|
||||
} else {
|
||||
uploadVideo('duringMedia')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const removeMedia = (field, idx) => { report.value[field].splice(idx, 1) }
|
||||
@ -381,6 +414,7 @@ const submitReport = async () => {
|
||||
setTimeout(() => {
|
||||
report.value = { petName: '', serviceType: '', appointmentTime: '', beforeMedia: [], afterMedia: [], duringMedia: [], remark: '' }
|
||||
currentAppointmentId.value = null
|
||||
basicInfoCollapsed.value = false
|
||||
uni.navigateTo({ url: `/pages/report-view/reportView?token=${token}` })
|
||||
}, 800)
|
||||
} else {
|
||||
@ -398,6 +432,25 @@ const goBack = () => {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (typeof uni.onKeyboardHeightChange === 'function') {
|
||||
keyboardChangeHandler = (res) => {
|
||||
const h = Math.max(0, Number(res?.height || 0))
|
||||
keyboardHeight.value = h
|
||||
|
||||
// 仅在备注输入态自动折叠基础信息,减少输入时视觉干扰。
|
||||
if (h > 0 && remarkFocused.value && !basicInfoCollapsed.value) {
|
||||
basicInfoCollapsed.value = true
|
||||
autoCollapsedByKeyboard.value = true
|
||||
}
|
||||
// 仅恢复由本逻辑触发的折叠,避免覆盖用户手动操作。
|
||||
if (h === 0 && autoCollapsedByKeyboard.value) {
|
||||
basicInfoCollapsed.value = false
|
||||
autoCollapsedByKeyboard.value = false
|
||||
}
|
||||
}
|
||||
uni.onKeyboardHeightChange(keyboardChangeHandler)
|
||||
}
|
||||
|
||||
await loadServiceTypes()
|
||||
const prefill = JSON.parse(uni.getStorageSync('petstore_report_prefill') || 'null')
|
||||
if (prefill) {
|
||||
@ -412,14 +465,34 @@ onMounted(async () => {
|
||||
report.value.appointmentTime = `${d}T${normalizeToHalfHour(hm)}`
|
||||
}
|
||||
}
|
||||
// 预约数据带入,默认折叠基础信息
|
||||
basicInfoCollapsed.value = true
|
||||
uni.removeStorageSync('petstore_report_prefill')
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (typeof uni.offKeyboardHeightChange === 'function' && keyboardChangeHandler) {
|
||||
uni.offKeyboardHeightChange(keyboardChangeHandler)
|
||||
}
|
||||
})
|
||||
|
||||
onPageScroll((e) => {
|
||||
hasScrolled.value = (e?.scrollTop || 0) > 8
|
||||
})
|
||||
|
||||
const onRemarkFocus = () => {
|
||||
remarkFocused.value = true
|
||||
}
|
||||
|
||||
const onRemarkBlur = () => {
|
||||
remarkFocused.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.report-page {
|
||||
padding-bottom: calc(76px + env(safe-area-inset-bottom));
|
||||
padding-bottom: calc(96px + env(safe-area-inset-bottom));
|
||||
background: #fafaf8;
|
||||
}
|
||||
.report-nav {
|
||||
@ -433,7 +506,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.report-body {
|
||||
padding: 12px 16px 32px;
|
||||
padding: 12px 16px 20px;
|
||||
}
|
||||
|
||||
/* 区块 */
|
||||
@ -446,6 +519,16 @@ onMounted(async () => {
|
||||
.section-head {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.section-head--clickable {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.section-toggle {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #2db96d;
|
||||
}
|
||||
.section-label {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
@ -573,35 +656,24 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
/* 过程中区块 */
|
||||
.during-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
.during-add-row {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.during-action-btn {
|
||||
flex: 1;
|
||||
height: 42px;
|
||||
.during-add-btn {
|
||||
height: 44px;
|
||||
border-radius: 12px;
|
||||
border: 1.5px solid #ebebea;
|
||||
border: 1.5px dashed #ddddd8;
|
||||
background: #fafaf8;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #666660;
|
||||
color: #999993;
|
||||
}
|
||||
.during-action-btn:active {
|
||||
.during-add-btn:active {
|
||||
background: #f0f0ee;
|
||||
}
|
||||
.during-action-btn--video {
|
||||
border-color: #e0d8f5;
|
||||
background: #f8f5ff;
|
||||
}
|
||||
.during-action-btn--video:active {
|
||||
background: #f0ecff;
|
||||
}
|
||||
|
||||
.during-grid {
|
||||
display: flex;
|
||||
@ -628,13 +700,6 @@ onMounted(async () => {
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
.during-empty {
|
||||
padding: 16px 0 4px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
color: #bbbbb5;
|
||||
}
|
||||
|
||||
/* 备注 */
|
||||
.form-textarea {
|
||||
background: #f5f5f2;
|
||||
@ -663,10 +728,28 @@ onMounted(async () => {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
border: none;
|
||||
margin-top: 8px;
|
||||
margin-top: 0;
|
||||
letter-spacing: 0.5px;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
.submit-fixed {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
|
||||
background: rgba(250, 250, 248, 0.96);
|
||||
border-top: 1px solid #efefeb;
|
||||
backdrop-filter: blur(2px);
|
||||
z-index: 50;
|
||||
transition: box-shadow 0.2s ease, background 0.2s ease, bottom 0.2s ease;
|
||||
}
|
||||
.submit-fixed--scrolled {
|
||||
box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.08);
|
||||
background: rgba(250, 250, 248, 0.985);
|
||||
}
|
||||
.submit-btn--fixed {
|
||||
box-shadow: 0 5px 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.submit-btn:active { opacity: 0.85; }
|
||||
.submit-btn[disabled] { background: #ddddd8; color: #999993; }
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user