Files
yxe-mp/pages/performance/index.vue
T
2026-09-29 15:17:13 +08:00

997 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="performance-page">
<view class="perf-hero">
<AppNavbar title="业绩统计"/>
<view class="stats-card">
<view class="flex justify-between items-center w-100p">
<view class="stat-item">
<view class="stat-value">{{ stats.doneNum }}/{{ stats.taskNum }}</view>
<view class="stat-label">我的完成进度</view>
</view>
<!-- <view class="stat-item" @click="toBonus">-->
<!-- <view class="stat-value">{{ stats.income }}元</view>-->
<!-- <view class="stat-label">我的活动奖励</view>-->
<!-- </view>-->
<view class="stat-item">
<view class="stat-value">{{ stats.doneRate }}%</view>
<view class="stat-label">我的完成率</view>
</view>
</view>
<view class="flex justify-between items-center w-100p pt-20 border-top" v-if="isLoggedIn && user.canAuth === 1">
<view class="stat-item">
<view class="stat-value text-main">{{ stats.totalDoneNum }}/{{ stats.totalTaskNum }}</view>
<view class="stat-label">总完成进度</view>
</view>
<!-- <view class="stat-item" @click="toBonus">-->
<!-- <view class="stat-value text-main">{{ stats.totalIncome }}元</view>-->
<!-- <view class="stat-label">总活动奖励</view>-->
<!-- </view>-->
<view class="stat-item">
<view class="stat-value text-main">{{ stats.totalDoneRate }}%</view>
<view class="stat-label">总完成率</view>
</view>
</view>
</view>
</view>
<view class="section-head">
<view class="head-left" @tap="openAreaPicker">
<u-icon name="map" size="26" color="#27c7a4"/>
<text>{{ currentCity }}</text>
</view>
<view class="head-center">
<image class="head-icon" mode="heightFix"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/6a639dcbe30e9c503d50f391272a066a.png"
alt=""/>
<!-- <text class="head-dot">✦</text>-->
<!-- <text class="section-title">任务完成详情</text>-->
</view>
<view class="section-more"></view>
</view>
<view class="filter-chips">
<view class="filter-chip" @tap="openMerchantPicker">{{ merchantLabel }}</view>
<view class="filter-chip" @tap="openManufacturerPicker">{{ manufacturerLabel }}</view>
</view>
<view class="task-list">
<template v-if="details.length">
<view class="task-card" v-for="(item, index) in visibleDetails" :key="index" @tap="showDetails(item)">
<view class="task-top">
<text class="task-label">匹配门店:</text>
<text class="task-value">{{ item.merchant.name || '-' }}</text>
</view>
<view class="task-divider"></view>
<view class="task-row">
<text class="task-label">任务名称:</text>
<text class="task-value">{{ item.title }}</text>
</view>
<view class="task-row">
<text class="task-label">当前状态:</text>
<text :class="['task-status', taskStatusClass(item)]">{{ resolveTaskStatusLabel(item) }}</text>
</view>
<view class="task-row task-row-space">
<text class="task-time">任务时间:{{ item.date || '-' }}</text>
<view class="task-distance">
<u-icon name="map" size="24" color="#ff9f43"/>
<text>距离{{ item.distance || '100米' }}</text>
</view>
</view>
<view class="task-progress">
<view class="progress-line">
<view class="progress-fill"
:style="{ width: `${item.num ? (item.doneNum / item.num) * 100 : 0}%` }"></view>
</view>
<view class="progress-right">
<u-icon name="close-circle" color="#2fc6a7" size="30rpx"/>
<!-- <view class="progress-icon">×</view>-->
<view class="progress-count">{{ item.doneNum }}/{{ item.num }}</view>
</view>
</view>
</view>
<view v-if="showMoreTaskBtn" class="task-more-btn" @tap="expandTaskList">查看更多</view>
</template>
<u-empty v-else
icon="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/ddcc1bbd561d97128ed19407b07e299b.png"
text="暂无数据"/>
</view>
<view class="person-section">
<view class="section-banner">
<view class="banner-center">
<!-- <text class="head-dot">✦</text>-->
<!-- <text class="section-title section-title-light">按人员筛选</text>-->
<image class="head-icon" mode="aspectFit"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/10fe8406037bab94adf5045216feb74a.png"
alt=""/>
</view>
<view class="section-more section-more-light"></view>
</view>
<!-- <view class="person-search">-->
<!-- <u-icon name="search" size="26" color="#9ca3af"/>-->
<!-- <input type="text" placeholder="输入姓名搜索" v-model="personKeyword"/>-->
<!-- <view class="search-btn" @tap="searchPerson">搜索</view>-->
<!-- </view>-->
<view class="p-20">
<u-search showAction animation v-model="personKeyword" bgColor="white"
searchIcon="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/16f54dd102cacccfb5085533009b70fc.png"/>
</view>
<view class="person-list">
<template v-if="filteredPersons.length">
<view class="person-item" v-for="(person, idx) in filteredPersons" :key="idx">
<view class="person-left">
<u-icon v-if="idx === 0"
name="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/99b7a70575473d52e38c765a8635428c.png"
size="50rpx"/>
<u-icon v-else-if="idx === 1"
name="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/3a984885c03dbd31f1bd998f98c41493.png"
size="50rpx"/>
<u-icon v-else-if="idx === 2"
name="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/722383e4ed2ba2e98cd04ce3ee5c4b8f.png"
size="50rpx"/>
<text v-else class="person-index">{{ idx + 1 }}</text>
<text class="person-name">{{ person.nickname || person.name || '-' }}</text>
</view>
<!-- <view class="person-right">奖励 ¥{{ person.incomeAmount }} 完成 {{-->
<!-- person.taskCompleteNum-->
<!-- }}/{{ person.totalTaskNum }}-->
<!-- </view>-->
</view>
</template>
<u-empty v-else
icon="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/ddcc1bbd561d97128ed19407b07e299b.png"
text="暂无数据"/>
</view>
</view>
<Login ref="Login" @done="getUserData"/>
<AreaPicker
:show="showAreaPicker"
:default-province="currentProvince"
:default-city="currentCity"
@close="showAreaPicker = false"
@confirm="onAreaConfirm"
/>
<u-popup :show="showMerchantPicker" mode="bottom" round="24rpx" @close="closeMerchantPicker">
<view class="merchant-picker">
<view class="merchant-picker-head">
<view class="picker-action" @tap="closeMerchantPicker">取消</view>
<text class="picker-title">药店筛选</text>
<view class="picker-action primary" @tap="confirmMerchantPicker">确定</view>
</view>
<view class="merchant-picker-search">
<u-search
v-model="merchantSearchKeyword"
bgColor="white"
showAction
animation
actionText="搜索"
searchIcon="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/16f54dd102cacccfb5085533009b70fc.png"
/>
</view>
<view v-if="merchantLoading" class="merchant-picker-loading">
<u-loading-icon mode="circle"></u-loading-icon>
</view>
<picker-view
v-else
class="merchant-picker-view"
:value="merchantPickerValue"
:indicator-style="merchantIndicatorStyle"
@change="onMerchantPickerChange"
>
<picker-view-column>
<view
v-for="(item, idx) in merchantFilteredOptions"
:key="idx"
class="merchant-picker-item"
>{{ item.text }}
</view>
</picker-view-column>
</picker-view>
</view>
</u-popup>
<u-popup :show="showManufacturerPicker" mode="bottom" round="24rpx" @close="closeManufacturerPicker">
<view class="merchant-picker">
<view class="merchant-picker-head">
<view class="picker-action" @tap="closeManufacturerPicker">取消</view>
<text class="picker-title">厂家筛选</text>
<view class="picker-action primary" @tap="confirmManufacturerPicker">确定</view>
</view>
<view v-if="manufacturerLoading" class="merchant-picker-loading">
<u-loading-icon mode="circle"></u-loading-icon>
</view>
<picker-view
v-else
class="merchant-picker-view"
:value="manufacturerPickerValue"
:indicator-style="merchantIndicatorStyle"
@change="onManufacturerPickerChange"
>
<picker-view-column>
<view
v-for="(item, idx) in manufacturerOptions"
:key="idx"
class="merchant-picker-item"
>{{ item.text }}
</view>
</picker-view-column>
</picker-view>
</view>
</u-popup>
</view>
</template>
<script>
import {taskDataReq, taskListForDataReq, taskUserRankReq} from "@/api/task";
import AppNavbar from "@/components/AppNavbar.vue";
import {calcDistanceMeters, formatDistance, getLocationAction} from "@/util";
import AreaPicker from "@/components/AreaPicker.vue";
import Login from "@/components/Login.vue";
import {userInfoReq} from "@/api/user";
import {getUserInfo} from "@/util/user";
import {merchantListReq} from "@/api/shop";
import {productGroupReq} from "@/api/product";
export default {
components: {Login, AppNavbar, AreaPicker},
data() {
return {
customerOptions: ['全部客户', '大参林', '老百姓', '海王星辰'],
industryOptions: ['自身产品', '大参林联营', '老百姓联营'],
roleOptions: ['管理员视角', '店长视角', '本人视角'],
customerIndex: 0,
industryIndex: 0,
roleIndex: 0,
stats: {
taskNum: 0,
doneNum: 0,
income: 0,
doneRate: 0,
totalDoneNum: 0,
totalTaskNum: 0,
totalIncome: 0,
totalDoneRate: 0,
},
details: [],
taskDisplayLimit: 10,
taskListExpanded: false,
lat: null,
lng: null,
currentCity: '定位中',
currentProvince: '',
showAreaPicker: false,
isLoggedIn: false,
personKeyword: '',
persons: [],
showMerchantPicker: false,
merchantLoading: false,
merchantOptions: [
{id: '', text: '全部门店'}
],
merchantId: '',
merchantText: '药店筛选',
merchantSearchKeyword: '',
merchantPickerValue: [0],
showManufacturerPicker: false,
manufacturerLoading: false,
manufacturerOptions: [
{markAbb: '', text: '全部厂家'}
],
manufacturerMarkAbb: '',
manufacturerText: '厂家筛选',
manufacturerPickerValue: [0],
user: {
canAuth: 0
}
}
},
computed: {
filteredPersons() {
const kw = this.personKeyword.trim()
const list = Array.isArray(this.persons) ? this.persons : []
const filtered = kw ? list.filter(p => (p.nickname || '').includes(kw)) : list
return filtered.slice().sort((a, b) => {
const aAmount = Number(a.incomeAmount) || 0
const bAmount = Number(b.incomeAmount) || 0
return bAmount - aAmount
})
},
merchantLabel() {
return this.merchantText || '药店筛选'
},
manufacturerLabel() {
return this.manufacturerText || '厂家筛选'
},
merchantFilteredOptions() {
const kw = this.merchantSearchKeyword.trim()
const list = Array.isArray(this.merchantOptions) ? this.merchantOptions : []
const filtered = kw ? list.filter(item => (item.text || '').includes(kw)) : list
return filtered.length ? filtered : [{id: '', text: '无匹配门店'}]
},
merchantIndicatorStyle() {
return 'height: 44px;'
},
visibleDetails() {
const list = Array.isArray(this.details) ? this.details : []
if (this.taskListExpanded) return list
return list.slice(0, this.taskDisplayLimit)
},
showMoreTaskBtn() {
const list = Array.isArray(this.details) ? this.details : []
return !this.taskListExpanded && list.length > this.taskDisplayLimit
}
},
watch: {
merchantSearchKeyword() {
this.merchantPickerValue = [0]
}
},
async onShow() {
await this.refreshPageData()
},
async onPullDownRefresh() {
try {
await this.refreshPageData()
} finally {
uni.stopPullDownRefresh()
}
},
methods: {
async refreshPageData() {
await this.getLocation()
await this.getTaskList()
await this.getUserRank()
if (getUserInfo().token) await this.getUserData()
},
async getUserData() {
const {data} = await userInfoReq()
this.isLoggedIn = true
this.user = data
await this.getTaskData()
},
async getLocation() {
const res = await getLocationAction().catch(() => {
uni.showToast({
title: '请允许位置授权',
icon: 'none'
})
})
if (res) {
this.lat = Number(res.latitude)
this.lng = Number(res.longitude)
this.currentCity = res.city_str || this.currentCity
this.currentProvince = res.province_str || this.currentProvince
this.updateTaskDistances()
}
},
async getTaskData() {
const {data} = await taskDataReq()
this.stats = data
},
async getTaskList() {
const params = {
province: this.currentProvince,
city: this.currentCity,
}
if (this.merchantId !== '' && this.merchantId !== null && this.merchantId !== undefined) {
params.merchantId = this.merchantId
}
if (this.manufacturerMarkAbb) {
params.markAbb = this.manufacturerMarkAbb
}
const {data} = await taskListForDataReq(params)
this.details = data
this.taskListExpanded = false
this.updateTaskDistances()
},
expandTaskList() {
this.taskListExpanded = true
},
async getUserRank() {
const {data} = await taskUserRankReq()
this.persons = data
},
changeCustomer(e) {
this.customerIndex = Number(e.detail.value)
},
changeIndustry(e) {
this.industryIndex = Number(e.detail.value)
},
changeRole(e) {
this.roleIndex = Number(e.detail.value)
},
openAreaPicker() {
this.showAreaPicker = true
},
onAreaConfirm({provinceName, cityName}) {
this.currentProvince = provinceName
this.currentCity = cityName
this.showAreaPicker = false
this.getTaskList()
},
async getMerchantList() {
this.merchantLoading = true
try {
const params = {}
if (this.currentProvince) params.province = this.currentProvince
if (this.currentCity && this.currentCity !== '定位中') params.city = this.currentCity
const {data} = await merchantListReq(params)
const list = Array.isArray(data)
? data
: (Array.isArray(data && data.records) ? data.records : (Array.isArray(data && data.list) ? data.list : []))
const options = list.map(item => ({
id: item.id ?? item.merchantId ?? item.merchant_id,
text: item.name || item.merchantName || item.merchant_name || item.title || '未命名门店'
})).filter(item => item.id !== undefined && item.id !== null)
this.merchantOptions = [{id: '', text: '全部门店'}].concat(options)
} catch (error) {
uni.showToast({
title: '门店列表获取失败',
icon: 'none'
})
} finally {
this.merchantLoading = false
}
},
async openMerchantPicker() {
// if (!this.merchantOptions || this.merchantOptions.length <= 1) {
await this.getMerchantList()
// }
this.merchantSearchKeyword = ''
const idx = this.merchantOptions.findIndex(item => item.id === this.merchantId)
this.merchantPickerValue = [idx > -1 ? idx : 0]
this.showMerchantPicker = true
},
closeMerchantPicker() {
this.showMerchantPicker = false
},
onMerchantPickerChange(e) {
const value = Array.isArray(e.detail && e.detail.value) ? e.detail.value : [0]
this.merchantPickerValue = value
},
confirmMerchantPicker() {
const selected = this.merchantFilteredOptions[this.merchantPickerValue[0]] || null
if (selected) {
this.merchantId = selected.id ?? ''
this.merchantText = selected.text || '药店筛选'
} else {
this.merchantId = ''
this.merchantText = '药店筛选'
}
this.showMerchantPicker = false
this.getTaskList()
},
async getManufacturerList() {
this.manufacturerLoading = true
try {
const {data} = await productGroupReq()
console.log(data)
const options = data.map(item => ({
makerAbb: item.makerAbb,
text: item.makerAbb || ''
})).filter(item => item.text)
console.log(options)
this.manufacturerOptions = [{makerAbb: '', text: '全部厂家'}].concat(options)
} catch (error) {
uni.showToast({
title: '厂家列表获取失败',
icon: 'none'
})
} finally {
this.manufacturerLoading = false
}
},
async openManufacturerPicker() {
if (!this.manufacturerOptions || this.manufacturerOptions.length <= 1) {
await this.getManufacturerList()
}
const idx = this.manufacturerOptions.findIndex(item => item.markAbb === this.manufacturerMarkAbb)
this.manufacturerPickerValue = [idx > -1 ? idx : 0]
this.showManufacturerPicker = true
},
closeManufacturerPicker() {
this.showManufacturerPicker = false
},
onManufacturerPickerChange(e) {
const value = Array.isArray(e.detail && e.detail.value) ? e.detail.value : [0]
this.manufacturerPickerValue = value
},
confirmManufacturerPicker() {
const selected = this.manufacturerOptions[this.manufacturerPickerValue[0]] || null
if (selected) {
this.manufacturerMarkAbb = selected.markAbb ?? ''
this.manufacturerText = selected.text || '厂家筛选'
} else {
this.manufacturerMarkAbb = ''
this.manufacturerText = '厂家筛选'
}
this.showManufacturerPicker = false
this.getTaskList()
},
updateTaskDistances() {
if (!Number.isFinite(this.lat) || !Number.isFinite(this.lng)) return
this.details = this.details.map(item => {
const merchant = item.merchant || {}
const lat = Number(merchant.lat || merchant.latitude || item.lat || item.latitude)
const lng = Number(merchant.lng || merchant.longitude || item.lng || item.longitude)
if (!Number.isFinite(lat) || !Number.isFinite(lng)) return item
const meters = calcDistanceMeters(this.lat, this.lng, lat, lng)
return Object.assign({}, item, {
distance: formatDistance(meters)
})
})
},
pickFirstTaskText(values = []) {
for (let i = 0; i < values.length; i++) {
const value = values[i]
if (value === undefined || value === null) continue
const text = String(value).trim()
if (text) return text
}
return ''
},
pickFirstTaskNumber(values = []) {
for (let i = 0; i < values.length; i++) {
const raw = values[i]
if (raw === '' || raw === undefined || raw === null) continue
const num = Number(raw)
if (Number.isFinite(num)) return num
}
return null
},
resolveTaskStatusLabel(item = {}) {
const userTask = item.userTask || {}
const textLabel = this.pickFirstTaskText([
item.statusText,
item.taskStatusText,
item.stateText,
item.statusName,
item.taskStatusName,
userTask.statusText
])
if (textLabel) return textLabel
const userStatus = this.pickFirstTaskNumber([item.userTaskStatus, userTask.status, item.auditStatus])
if (userStatus !== null) {
if (userStatus === 2) return '已完成'
if (userStatus === 1) return '审核中'
if (userStatus === 3) return '审核驳回'
if (userStatus === 0) return '待提交'
}
const taskStatus = this.pickFirstTaskNumber([item.taskStatus, item.status, item.state])
if (taskStatus !== null) {
if (taskStatus === 2) return '已完成'
if (taskStatus === 1) return '进行中'
if (taskStatus === 0) return '未开始'
}
const doneNum = Number(item.doneNum) || 0
const totalNum = Number(item.num) || 0
if (totalNum > 0 && doneNum >= totalNum) return '已完成'
if (doneNum > 0) return '进行中'
return '未开始'
},
taskStatusClass(item = {}) {
const label = this.resolveTaskStatusLabel(item)
if (label.includes('驳回') || label.includes('失败')) return 'task-status-danger'
if (label.includes('完成') || label.includes('通过')) return 'task-status-success'
if (label.includes('审核中') || label.includes('进行') || label.includes('待')) return 'task-status-pending'
return 'task-status-default'
},
searchPerson() {
if (!this.personKeyword.trim()) {
uni.showToast({
title: '请输入姓名',
icon: 'none'
})
}
},
showDetails(task) {
uni.navigateTo({
url: `/pages/task/detail?title=${encodeURIComponent(task.merchant.name)}&reward=${task.reward}&target=${task.cate.title}&id=${task.id}`
})
},
toBonus() {
if (!this.isLoggedIn) {
return this.$refs.Login.open()
}
uni.navigateTo({
url: '/pages/bonus/index'
})
}
}
}
</script>
<style lang="scss" scoped>
.performance-page {
min-height: 100vh;
padding: 0 0 40rpx;
background: #e9fbf6;
}
.perf-hero {
padding: 0 0 20rpx;
background: url('https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/462bfa04cf0eff8698884c38b9d17519.png') no-repeat top center / 100% auto;
}
.perf-navbar {
padding: 0 6rpx;
}
.stats-card {
margin: 0 20rpx 0;
padding: 18rpx 18rpx;
background: #ffffff;
border-radius: 20rpx;
border: 1rpx solid #2fc6a7;
border-top: 20rpx solid #2fc6a7;
//display: grid;
//grid-template-columns: repeat(3, 1fr);
//gap: 10rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.stat-item {
text-align: center;
width: 30%;
}
.stat-value {
font-size: 30rpx;
font-weight: 700;
color: #ff3b30;
}
.stat-label {
margin-top: 6rpx;
font-size: 22rpx;
color: #6b7280;
}
.section-head {
margin: 14rpx 20rpx 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 6rpx;
}
.head-left {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 24rpx;
color: #2fc6a7;
font-weight: 700;
}
.head-center {
display: flex;
align-items: center;
gap: 6rpx;
color: #2fc6a7;
font-weight: 700;
}
.head-dot {
font-size: 20rpx;
}
.section-title {
font-size: 26rpx;
font-weight: 700;
color: #2fc6a7;
}
.section-more {
font-size: 22rpx;
color: #6b7280;
width: 50rpx;
}
.filter-chips {
margin: 12rpx 20rpx 0;
display: flex;
justify-content: flex-end;
gap: 10rpx;
}
.filter-chip {
padding: 6rpx 14rpx;
border-radius: 999rpx;
border: 1rpx solid #2fc6a7;
color: #2fc6a7;
font-size: 22rpx;
}
.task-list {
margin: 12rpx 20rpx 0;
display: flex;
flex-direction: column;
gap: 14rpx;
}
.task-more-btn {
margin: 6rpx auto 0;
padding: 10rpx 30rpx;
border-radius: 999rpx;
border: 1rpx solid #2fc6a7;
color: #2fc6a7;
font-size: 24rpx;
background: #ffffff;
}
.task-card {
background: #ffffff;
border-radius: 18rpx;
padding: 14rpx 16rpx;
border: 1rpx solid #2fc6a7;
box-shadow: 0 8rpx 16rpx rgba(39, 199, 164, 0.12);
}
.task-top {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 24rpx;
color: #374151;
}
.task-label {
color: #6b7280;
}
.task-divider {
height: 1rpx;
background: #d7f4eb;
margin: 10rpx 0;
}
.task-row {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 24rpx;
color: #374151;
margin-top: 6rpx;
}
.task-row-space {
justify-content: space-between;
}
.task-time {
color: #6b7280;
font-size: 22rpx;
}
.task-distance {
display: flex;
align-items: center;
gap: 4rpx;
font-size: 22rpx;
color: #ff8a00;
}
.task-status {
font-size: 22rpx;
font-weight: 700;
}
.task-status-default {
color: #6b7280;
}
.task-status-pending {
color: #ff9f43;
}
.task-status-success {
color: #22c55e;
}
.task-status-danger {
color: #ef4444;
}
.task-progress {
margin-top: 12rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12rpx;
}
.progress-line {
flex: 1;
height: 6rpx;
background: #e5f7f1;
border-radius: 999rpx;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: #37c977;
}
.progress-right {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 22rpx;
color: #2fc6a7;
}
.progress-icon {
width: 28rpx;
height: 28rpx;
border-radius: 50%;
border: 1rpx solid #2fc6a7;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
}
.person-section {
margin-top: 18rpx;
overflow: hidden;
background-image: url("https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/09dd8e6519b44d71410fc82a7e255540.jpg");
background-size: cover;
}
.section-banner {
padding: 12rpx 14rpx;
//background: linear-gradient(135deg, #33d0b3, #22c3a1);
display: flex;
align-items: center;
justify-content: center;
}
.banner-center {
display: flex;
align-items: center;
gap: 6rpx;
}
.section-title-light {
color: #ffffff;
}
.section-more-light {
color: #ffffff;
}
.person-search {
padding: 12rpx 14rpx;
display: flex;
align-items: center;
gap: 10rpx;
background: #ffffff;
border-bottom: 1rpx dashed #d7f4eb;
}
.person-search input {
flex: 1;
font-size: 24rpx;
color: #1f2937;
}
.search-btn {
padding: 6rpx 16rpx;
border-radius: 999rpx;
background: #2fc6a7;
color: #ffffff;
font-size: 24rpx;
font-weight: 700;
}
.person-list {
padding: 10rpx;
margin: 20rpx;
background-color: white;
border-radius: 10rpx;
min-height: 200rpx;
}
.person-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12rpx 0;
border-bottom: 1rpx dashed #d7f4eb;
font-size: 24rpx;
}
.person-item:last-child {
border-bottom: none;
}
.person-left {
display: flex;
align-items: center;
gap: 10rpx;
flex: 1;
}
.person-index {
font-size: 24rpx;
font-weight: 700;
color: #2fc6a7;
width: 36rpx;
text-align: center;
}
.person-name {
color: #1f2937;
}
.person-right {
color: #ef4444;
font-size: 22rpx;
}
.head-icon {
height: 60rpx;
}
.merchant-picker {
background: #ffffff;
border-radius: 24rpx 24rpx 0 0;
padding-bottom: 24rpx;
}
.merchant-picker-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18rpx 20rpx;
border-bottom: 1rpx solid #eef2f7;
}
.picker-title {
font-size: 28rpx;
font-weight: 700;
color: #111827;
}
.picker-action {
font-size: 24rpx;
color: #6b7280;
}
.picker-action.primary {
color: #2fc6a7;
font-weight: 700;
}
.merchant-picker-search {
padding: 12rpx 20rpx 0;
}
.merchant-picker-loading {
height: 320rpx;
display: flex;
align-items: center;
justify-content: center;
}
.merchant-picker-view {
height: 360rpx;
}
.merchant-picker-item {
height: 44px;
line-height: 44px;
text-align: center;
font-size: 26rpx;
color: #111827;
}
</style>