997 lines
28 KiB
Vue
997 lines
28 KiB
Vue
<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>
|