feat(visit): 客户拜访页按新原型重构为多卡片表单
参照设计稿将 pages/visit/index 拆分为 4 张表单卡片 + 历史记录卡片: - 我的信息:姓名,进页面自动带出账号 realName,可编辑 - 拜访对象:类型(门店/门店经理/其他 胶囊 tab)、姓名/门店、连锁 - 拜访信息:定位信息(点击重新定位 + 经纬度副行)、拜访日期(默认当天) - 其他信息:沟通内容(500 字 + 实时计数)、拍照上传、活动小结 一并修复: - 必填星号原用 ::before 伪元素,小程序对 <text> 伪元素支持不稳,改为 显式 <text class="field-star"> - 必填标签原复用全局类名 .required,而 common.scss 中的 .required 经 @extend .pos-a 带上 position:absolute / left:-9px / top:15px,导致标签 脱离文档流堆叠到卡片左上角。改用 .is-required 并在样式处加注释说明。 配色沿用项目主题变量,未照搬设计稿颜色。历史记录展开详情增加拜访 类型与拜访日期两行。
This commit is contained in:
+391
-150
@@ -3,88 +3,195 @@
|
||||
<view class="page-hero">
|
||||
<AppNavbar title="客户拜访" show-back/>
|
||||
<view class="intro-card">
|
||||
<view class="card-title">
|
||||
<view class="title-bar"></view>
|
||||
<text>培训拜访</text>
|
||||
<view class="tip-icon">
|
||||
<u-icon name="info-circle-fill" size="40rpx" :color="brandColor"/>
|
||||
</view>
|
||||
<view class="tip-body">
|
||||
<text class="tip-title">温馨提示</text>
|
||||
<text class="tip-text">请如实填写本次拜访信息,系统将自动记录您的姓名,拜访对象请填写实际到访人员或门店/经理。</text>
|
||||
</view>
|
||||
<text class="intro-text">记录培训拜访现场定位、沟通内容和照片,提交后可回看历史记录。</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的信息 -->
|
||||
<view class="card block">
|
||||
<view class="section-title">新增拜访</view>
|
||||
<view class="form">
|
||||
<view class="form-row location-row">
|
||||
<text>定位信息</text>
|
||||
<view class="location-box">
|
||||
<view class="picker-value location-text" :class="{placeholder: !visitForm.location}">
|
||||
{{ visitForm.location || '定位中,或点击右侧重新定位' }}
|
||||
</view>
|
||||
<view class="location-meta">
|
||||
<text>{{ formatCoordinate('纬度', visitForm.lat) }}</text>
|
||||
<text>{{ formatCoordinate('经度', visitForm.lng) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="refresh-btn" @tap="fetchLocation(false, true)">重新定位</view>
|
||||
<view class="form-card-head">
|
||||
<view class="head-icon">
|
||||
<u-icon name="account-fill" size="32rpx" :color="brandColor"/>
|
||||
</view>
|
||||
<text class="head-title">我的信息</text>
|
||||
</view>
|
||||
<view class="field-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>姓名</text>
|
||||
<view class="field-box">
|
||||
<u-icon name="account" size="32rpx" color="#9aa7b8"/>
|
||||
<input
|
||||
v-model="visitForm.submitterName"
|
||||
class="field-input"
|
||||
type="text"
|
||||
maxlength="30"
|
||||
placeholder="请输入您的姓名"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-row">
|
||||
<text>连锁</text>
|
||||
<view class="selector-picker" @tap="openChainPicker">
|
||||
<view class="picker-value" :class="{placeholder: !visitForm.chain}">
|
||||
{{ visitForm.chain || (chainLoading ? '连锁加载中...' : '请选择连锁') }}
|
||||
</view>
|
||||
<!-- 拜访对象 -->
|
||||
<view class="card block">
|
||||
<view class="form-card-head">
|
||||
<view class="head-icon">
|
||||
<u-icon name="account" size="32rpx" :color="brandColor"/>
|
||||
</view>
|
||||
<text class="head-title">拜访对象</text>
|
||||
</view>
|
||||
|
||||
<view class="field-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>类型</text>
|
||||
<view class="type-tabs">
|
||||
<view
|
||||
v-for="tab in visitTypeTabs"
|
||||
:key="tab.value"
|
||||
:class="['type-tab', visitForm.visitType === tab.value ? 'active' : '']"
|
||||
@tap="visitForm.visitType = tab.value"
|
||||
>
|
||||
<u-icon :name="tab.icon" size="28rpx" :color="visitForm.visitType === tab.value ? brandColor : '#9aa7b8'"/>
|
||||
<text>{{ tab.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-row">
|
||||
<text>拜访人员</text>
|
||||
<input v-model="visitForm.name" maxlength="30" placeholder="请输入拜访人员"/>
|
||||
<view class="field-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>姓名/门店</text>
|
||||
<view class="field-box">
|
||||
<input
|
||||
v-model="visitForm.name"
|
||||
class="field-input"
|
||||
type="text"
|
||||
maxlength="30"
|
||||
:placeholder="targetPlaceholder"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
<u-icon name="arrow-right" size="26rpx" color="#b6c2d1"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-row textarea-row">
|
||||
<text>沟通内容</text>
|
||||
<view class="field-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>连锁</text>
|
||||
<view class="field-box" @tap="openChainPicker">
|
||||
<text class="field-text" :class="{placeholder: !visitForm.chain}">
|
||||
{{ visitForm.chain || (chainLoading ? '连锁加载中...' : '请选择连锁') }}
|
||||
</text>
|
||||
<u-icon name="arrow-right" size="26rpx" color="#b6c2d1"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拜访信息 -->
|
||||
<view class="card block">
|
||||
<view class="form-card-head">
|
||||
<view class="head-icon">
|
||||
<u-icon name="map-fill" size="32rpx" :color="brandColor"/>
|
||||
</view>
|
||||
<text class="head-title">拜访信息</text>
|
||||
</view>
|
||||
|
||||
<view class="field-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>定位信息</text>
|
||||
<view class="field-box" @tap="fetchLocation(false, true)">
|
||||
<u-icon name="map" size="32rpx" color="#9aa7b8"/>
|
||||
<text class="field-text" :class="{placeholder: !visitForm.location}">
|
||||
{{ visitForm.location || '请点击获取当前位置' }}
|
||||
</text>
|
||||
<u-icon name="reload" size="30rpx" color="#b6c2d1"/>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="visitForm.lat || visitForm.lng" class="field-meta">
|
||||
<text>{{ formatCoordinate('纬度', visitForm.lat) }}</text>
|
||||
<text>{{ formatCoordinate('经度', visitForm.lng) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="field-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>拜访日期</text>
|
||||
<view class="field-box" @tap="showVisitDatePicker = true">
|
||||
<u-icon name="calendar" size="32rpx" color="#9aa7b8"/>
|
||||
<text class="field-text" :class="{placeholder: !visitForm.visitDate}">
|
||||
{{ visitForm.visitDate || '请选择拜访日期' }}
|
||||
</text>
|
||||
<u-icon name="arrow-right" size="26rpx" color="#b6c2d1"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 其他信息 -->
|
||||
<view class="card block">
|
||||
<view class="form-card-head">
|
||||
<view class="head-icon">
|
||||
<u-icon name="edit-pen-fill" size="32rpx" :color="brandColor"/>
|
||||
</view>
|
||||
<text class="head-title">其他信息</text>
|
||||
</view>
|
||||
|
||||
<view class="field-row textarea-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>沟通内容</text>
|
||||
<view class="field-box textarea-box">
|
||||
<textarea
|
||||
v-model="visitForm.content"
|
||||
class="textarea-input"
|
||||
maxlength="500"
|
||||
auto-height
|
||||
placeholder="请输入沟通内容"
|
||||
class="field-textarea"
|
||||
:maxlength="contentMaxLength"
|
||||
placeholder="请输入沟通内容..."
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
<text class="counter">{{ (visitForm.content || '').length }}/{{ contentMaxLength }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="upload" @tap="uploadPhotos">
|
||||
<view>
|
||||
<view class="upload-title">拍照上传</view>
|
||||
<view class="upload-meta">{{ photos.length ? `已上传 ${photos.length} 张,点击继续拍照` : '点击拍照上传,最多 9 张' }}</view>
|
||||
</view>
|
||||
<view class="chip">必填</view>
|
||||
<view class="field-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>拍照上传</text>
|
||||
<view class="field-box" @tap="uploadPhotos">
|
||||
<u-icon name="camera-fill" size="32rpx" color="#9aa7b8"/>
|
||||
<text class="field-text" :class="{placeholder: !photos.length}">
|
||||
{{ photos.length ? `已上传 ${photos.length} 张,点击继续拍照` : '点击拍照上传,最多 9 张' }}
|
||||
</text>
|
||||
<u-icon name="arrow-right" size="26rpx" color="#b6c2d1"/>
|
||||
</view>
|
||||
|
||||
<view v-if="photos.length" class="photo-list">
|
||||
<view class="photo-item" v-for="(photo, index) in photos" :key="`${photo}-${index}`">
|
||||
<image class="photo-image" :src="photo" mode="aspectFill" @tap="previewPhoto(index)"/>
|
||||
<view class="photo-remove" @tap.stop="removePhoto(index)">x</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="photos.length" class="photo-list">
|
||||
<view class="photo-item" v-for="(photo, index) in photos" :key="`${photo}-${index}`">
|
||||
<image class="photo-image" :src="photo" mode="aspectFill" @tap="previewPhoto(index)"/>
|
||||
<view class="photo-remove" @tap.stop="removePhoto(index)">x</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-row textarea-row">
|
||||
<text>活动小结</text>
|
||||
<view class="field-row textarea-row">
|
||||
<text class="field-label is-required"><text class="field-star">*</text>活动小结</text>
|
||||
<view class="field-box textarea-box">
|
||||
<textarea
|
||||
v-model="visitForm.summary"
|
||||
class="textarea-input"
|
||||
class="field-textarea"
|
||||
maxlength="300"
|
||||
auto-height
|
||||
placeholder="请输入活动小结"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
<text class="counter">{{ (visitForm.summary || '').length }}/300</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="primary-btn submit" @tap="submitVisit">提交拜访</view>
|
||||
<view class="submit-wrap">
|
||||
<view class="primary-btn submit" @tap="submitVisit">
|
||||
<text>提交拜访</text>
|
||||
<u-icon name="arrow-right" size="30rpx" color="#ffffff"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card block">
|
||||
<view class="section-title">历史记录</view>
|
||||
<view class="form-card-head">
|
||||
<view class="head-icon">
|
||||
<u-icon name="list-dot" size="32rpx" :color="brandColor"/>
|
||||
</view>
|
||||
<text class="head-title">历史记录</text>
|
||||
</view>
|
||||
<view v-if="loading" class="empty">加载中...</view>
|
||||
<view v-else-if="visitHistory.length === 0" class="empty">暂无记录</view>
|
||||
<view v-else>
|
||||
@@ -100,6 +207,8 @@
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="item.expanded" class="history-detail">
|
||||
<view class="history-line">拜访类型:{{ item.visitType || '-' }}</view>
|
||||
<view class="history-line">拜访日期:{{ item.visitDate || '-' }}</view>
|
||||
<view class="history-line">定位:{{ item.location || '-' }}</view>
|
||||
<view class="history-line">纬度:{{ item.lat || '-' }}</view>
|
||||
<view class="history-line">经度:{{ item.lng || '-' }}</view>
|
||||
@@ -133,25 +242,43 @@
|
||||
@cancel="closeChainPicker"
|
||||
@close="closeChainPicker"
|
||||
/>
|
||||
<u-datetime-picker
|
||||
:show="showVisitDatePicker"
|
||||
:value="visitDatePickerValue"
|
||||
mode="date"
|
||||
@confirm="onVisitDateConfirm"
|
||||
@cancel="showVisitDatePicker = false"
|
||||
@close="showVisitDatePicker = false"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from "dayjs";
|
||||
import AppNavbar from "@/components/AppNavbar.vue";
|
||||
import {chooseImg, getLocationOnly} from "@/util";
|
||||
import {visitAddReq, visitListReq} from "@/api/visit";
|
||||
import {merchantGroupByChainReq} from "@/api/shop";
|
||||
import {userInfoReq} from "@/api/user";
|
||||
|
||||
export default {
|
||||
components: {AppNavbar},
|
||||
data() {
|
||||
return {
|
||||
brandColor: '#2fc6a7',
|
||||
contentMaxLength: 500,
|
||||
visitTypeTabs: [
|
||||
{label: '门店', value: '门店', icon: 'home'},
|
||||
{label: '门店经理', value: '门店经理', icon: 'account'},
|
||||
{label: '其他', value: '其他', icon: 'more-dot-fill'}
|
||||
],
|
||||
visitForm: this.buildForm(),
|
||||
photos: [],
|
||||
visitHistory: [],
|
||||
chainOptions: [],
|
||||
chainLoading: false,
|
||||
showChainPicker: false,
|
||||
showVisitDatePicker: false,
|
||||
loading: false,
|
||||
locating: false,
|
||||
}
|
||||
@@ -161,13 +288,22 @@ export default {
|
||||
if (!this.chainOptions.length) return [0]
|
||||
const idx = this.chainOptions.findIndex(item => String(item.id) === String(this.visitForm.chainId))
|
||||
return [idx < 0 ? 0 : idx]
|
||||
},
|
||||
visitDatePickerValue() {
|
||||
return this.visitForm.visitDate ? dayjs(this.visitForm.visitDate).valueOf() : Date.now()
|
||||
},
|
||||
targetPlaceholder() {
|
||||
if (this.visitForm.visitType === '门店经理') return '请输入门店经理姓名'
|
||||
if (this.visitForm.visitType === '其他') return '请输入拜访人员姓名'
|
||||
return '请输入拜访人员姓名 / 门店名称 / 经理姓名'
|
||||
}
|
||||
},
|
||||
async onShow() {
|
||||
await Promise.all([
|
||||
this.fetchLocation(true),
|
||||
this.fetchHistory(),
|
||||
this.fetchChainOptions()
|
||||
this.fetchChainOptions(),
|
||||
this.fetchSubmitterName()
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
@@ -179,10 +315,25 @@ export default {
|
||||
chainId: '',
|
||||
chain: '',
|
||||
name: '',
|
||||
visitType: '门店',
|
||||
visitDate: dayjs().format('YYYY-MM-DD'),
|
||||
submitterName: '',
|
||||
content: '',
|
||||
summary: ''
|
||||
}
|
||||
},
|
||||
async fetchSubmitterName() {
|
||||
if (this.visitForm.submitterName) return
|
||||
try {
|
||||
const {data} = await userInfoReq()
|
||||
const info = data || {}
|
||||
const name = info.realName || info.real_name || info.nickname || info.name || ''
|
||||
if (name && !this.visitForm.submitterName) {
|
||||
this.visitForm.submitterName = name
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
},
|
||||
async fetchChainOptions() {
|
||||
this.chainLoading = true
|
||||
try {
|
||||
@@ -212,6 +363,11 @@ export default {
|
||||
this.visitForm.chain = selected ? selected.text : ''
|
||||
this.showChainPicker = false
|
||||
},
|
||||
onVisitDateConfirm(event) {
|
||||
const raw = event && event.value !== undefined ? event.value : Date.now()
|
||||
this.visitForm.visitDate = dayjs(raw).format('YYYY-MM-DD')
|
||||
this.showVisitDatePicker = false
|
||||
},
|
||||
formatCoordinate(label, value) {
|
||||
if (value === '' || value === null || value === undefined) return `${label}:-`
|
||||
return `${label}:${value}`
|
||||
@@ -268,9 +424,23 @@ export default {
|
||||
})
|
||||
},
|
||||
async submitVisit() {
|
||||
if (!this.visitForm.lat || !this.visitForm.lng || !this.visitForm.location) {
|
||||
if (!String(this.visitForm.submitterName || '').trim()) {
|
||||
uni.showToast({
|
||||
title: '请先获取定位',
|
||||
title: '请填写您的姓名',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.visitForm.visitType) {
|
||||
uni.showToast({
|
||||
title: '请选择拜访对象类型',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!String(this.visitForm.name || '').trim()) {
|
||||
uni.showToast({
|
||||
title: '请填写拜访对象姓名/门店',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -282,7 +452,21 @@ export default {
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.visitForm.name || !this.visitForm.content || !this.photos.length || !this.visitForm.summary) {
|
||||
if (!this.visitForm.lat || !this.visitForm.lng || !this.visitForm.location) {
|
||||
uni.showToast({
|
||||
title: '请先获取定位',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.visitForm.visitDate) {
|
||||
uni.showToast({
|
||||
title: '请选择拜访日期',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.visitForm.content || !this.photos.length || !this.visitForm.summary) {
|
||||
uni.showToast({
|
||||
title: '请填写完整信息',
|
||||
icon: 'none'
|
||||
@@ -297,6 +481,9 @@ export default {
|
||||
chainId: this.visitForm.chainId,
|
||||
chain: this.visitForm.chain,
|
||||
name: this.visitForm.name,
|
||||
visitType: this.visitForm.visitType,
|
||||
visitDate: this.visitForm.visitDate,
|
||||
submitterName: this.visitForm.submitterName,
|
||||
content: this.visitForm.content,
|
||||
photos: JSON.stringify(this.photos),
|
||||
summary: this.visitForm.summary
|
||||
@@ -305,16 +492,17 @@ export default {
|
||||
title: '提交成功',
|
||||
icon: 'success'
|
||||
})
|
||||
const locationSnapshot = {
|
||||
const snapshot = {
|
||||
lat: this.visitForm.lat,
|
||||
lng: this.visitForm.lng,
|
||||
location: this.visitForm.location,
|
||||
chainId: this.visitForm.chainId,
|
||||
chain: this.visitForm.chain
|
||||
chain: this.visitForm.chain,
|
||||
submitterName: this.visitForm.submitterName
|
||||
}
|
||||
this.visitForm = {
|
||||
...this.buildForm(),
|
||||
...locationSnapshot
|
||||
...snapshot
|
||||
}
|
||||
this.photos = []
|
||||
await this.fetchHistory()
|
||||
@@ -362,6 +550,8 @@ export default {
|
||||
name: item.name || item.visitName || '',
|
||||
content: item.content || item.remark || '',
|
||||
summary: item.summary || item.result || '',
|
||||
visitType: item.visitType || item.visit_type || '',
|
||||
visitDate: item.visitDate || item.visit_date || '',
|
||||
location: item.location || item.address || '',
|
||||
lat: item.lat || item.latitude || '',
|
||||
lng: item.lng || item.longitude || '',
|
||||
@@ -449,6 +639,7 @@ export default {
|
||||
.visit-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.page-hero {
|
||||
@@ -457,31 +648,35 @@ export default {
|
||||
|
||||
.intro-card {
|
||||
margin: 18rpx 20rpx 0;
|
||||
padding: 20rpx 18rpx;
|
||||
padding: 22rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
.tip-icon {
|
||||
flex-shrink: 0;
|
||||
margin-top: 2rpx;
|
||||
}
|
||||
|
||||
.tip-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.tip-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #2f78ff;
|
||||
}
|
||||
|
||||
.intro-text {
|
||||
margin-top: 12rpx;
|
||||
font-size: 26rpx;
|
||||
.tip-text {
|
||||
font-size: 25rpx;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@@ -490,124 +685,165 @@ export default {
|
||||
margin: 18rpx 20rpx 0;
|
||||
}
|
||||
|
||||
.form {
|
||||
.form-card-head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 12rpx 0;
|
||||
border-bottom: 1rpx solid #edf1f7;
|
||||
gap: 14rpx;
|
||||
padding-bottom: 20rpx;
|
||||
margin-bottom: 6rpx;
|
||||
border-bottom: 1rpx solid #eef2f7;
|
||||
}
|
||||
|
||||
.form-row input {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
.head-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(47, 198, 167, 0.12);
|
||||
}
|
||||
|
||||
.head-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.selector-picker {
|
||||
flex: 1;
|
||||
.field-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 14rpx 0;
|
||||
}
|
||||
|
||||
.selector-picker .picker-value {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.location-row {
|
||||
.field-row.textarea-row {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.location-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
.field-label {
|
||||
flex-shrink: 0;
|
||||
width: 158rpx;
|
||||
font-size: 28rpx;
|
||||
color: var(--text-main);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.picker-value.placeholder {
|
||||
color: var(--text-sub);
|
||||
/* 注意:不要用 .required 作类名 —— 全局 common.scss 里的 .required
|
||||
(经 uni.scss 全局引入)@extend 了 .pos-a,会带上 position:absolute /
|
||||
left:-9px / top:15px,导致标签脱离文档流堆到卡片左上角。 */
|
||||
.field-label.is-required {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.location-text {
|
||||
.field-star {
|
||||
color: #ff3b30;
|
||||
margin-right: 6rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.field-box {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
min-height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.textarea-box {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 16rpx 20rpx;
|
||||
}
|
||||
|
||||
.field-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.field-textarea {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
min-height: 180rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.6;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.field-text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 28rpx;
|
||||
color: var(--text-main);
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.location-meta {
|
||||
.field-text.placeholder,
|
||||
.field-placeholder {
|
||||
color: #9aa7b8;
|
||||
}
|
||||
|
||||
.counter {
|
||||
align-self: flex-end;
|
||||
margin-top: 6rpx;
|
||||
font-size: 24rpx;
|
||||
color: #9aa7b8;
|
||||
}
|
||||
|
||||
.field-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 4rpx;
|
||||
margin: -6rpx 0 6rpx 178rpx;
|
||||
font-size: 22rpx;
|
||||
color: var(--text-sub);
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
flex-shrink: 0;
|
||||
margin-top: 2rpx;
|
||||
padding: 8rpx 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #eef4ff;
|
||||
color: #2f78ff;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.textarea-row {
|
||||
align-items: flex-start;
|
||||
padding-top: 16rpx;
|
||||
}
|
||||
|
||||
.textarea-input {
|
||||
.type-tabs {
|
||||
flex: 1;
|
||||
min-height: 120rpx;
|
||||
text-align: right;
|
||||
font-size: 26rpx;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.upload {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.type-tab {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12rpx 0;
|
||||
border-bottom: 1rpx solid #edf1f7;
|
||||
}
|
||||
|
||||
.upload-title {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.upload-meta {
|
||||
justify-content: center;
|
||||
gap: 6rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f5f7fa;
|
||||
color: var(--text-sub);
|
||||
font-size: 24rpx;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
|
||||
.type-tab.active {
|
||||
background: rgba(47, 198, 167, 0.14);
|
||||
color: var(--brand-primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.photo-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
margin-top: 10rpx;
|
||||
margin: 6rpx 0 6rpx 178rpx;
|
||||
}
|
||||
|
||||
.photo-item {
|
||||
position: relative;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
background: #f8fafc;
|
||||
@@ -635,10 +871,15 @@ export default {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.submit-wrap {
|
||||
margin: 24rpx 20rpx 0;
|
||||
}
|
||||
|
||||
.submit {
|
||||
margin-top: 12rpx;
|
||||
padding: 14rpx;
|
||||
text-align: center;
|
||||
gap: 10rpx;
|
||||
padding: 24rpx 32rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.history {
|
||||
|
||||
Reference in New Issue
Block a user