20260929
This commit is contained in:
@@ -0,0 +1,996 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user