|
|
@@ -1,7 +1,465 @@
|
|
|
<template>
|
|
|
- <view>积分规则</view>
|
|
|
+ <page-meta :page-style="descVisible ? 'overflow:hidden;' : 'overflow:visible;'" />
|
|
|
+
|
|
|
+ <view class="rules-box">
|
|
|
+ <image class="rules-top-img" :src="topImgBg" mode="aspectFill" />
|
|
|
+
|
|
|
+ <view class="enterprise-switch" @click="showEnterprisePicker">
|
|
|
+ <view class="enterprise-switch__icon">
|
|
|
+ <wd-icon name="loop" size="34rpx" />
|
|
|
+ </view>
|
|
|
+ <text>切换企业</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <wd-picker
|
|
|
+ v-model:visible="pickerShow"
|
|
|
+ v-model="selectedRuleId"
|
|
|
+ title="切换企业"
|
|
|
+ :columns="enterpriseList"
|
|
|
+ label-key="label"
|
|
|
+ value-key="value"
|
|
|
+ root-portal
|
|
|
+ @confirm="handleEnterpriseConfirm"
|
|
|
+ />
|
|
|
+
|
|
|
+ <view class="table-box">
|
|
|
+ <view class="table-header">
|
|
|
+ <view class="table-tab table-tab--left">获取途径</view>
|
|
|
+ <view class="table-tab">获得积分</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="table-con">
|
|
|
+ <view class="table-bg">
|
|
|
+ <view v-if="loading" class="loading">
|
|
|
+ <view class="loading__item" />
|
|
|
+ <view class="loading__item" />
|
|
|
+ <view class="loading__item" />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <template v-else-if="sections.length">
|
|
|
+ <view v-for="section in sections" :key="section.title" class="section">
|
|
|
+ <view class="section-title">{{ section.title }}</view>
|
|
|
+
|
|
|
+ <view v-for="item in section.items" :key="item.id" class="table-item">
|
|
|
+ <view class="item-left">
|
|
|
+ <text class="task-name">{{ item.taskTypeName }}</text>
|
|
|
+
|
|
|
+ <image
|
|
|
+ class="tips"
|
|
|
+ :src="tipsIcon"
|
|
|
+ mode="aspectFit"
|
|
|
+ @click.stop="openDesc(item)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <text class="score-text">+{{ formatScore(item.score) }}积分</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <view v-else class="empty">暂无数据</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <wd-popup
|
|
|
+ v-model="descVisible"
|
|
|
+ position="bottom"
|
|
|
+ root-portal
|
|
|
+ lock-scroll
|
|
|
+ :safe-area-inset-bottom="true"
|
|
|
+ custom-style="border-radius: 40rpx 40rpx 0 0;"
|
|
|
+ >
|
|
|
+ <view class="info">
|
|
|
+ <view class="title">
|
|
|
+ <text>{{ activeTask?.taskTypeName || '任务说明' }}</text>
|
|
|
+ <wd-icon name="close" size="34rpx" @click="descVisible = false" />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="list">
|
|
|
+ <view class="tit">定义:</view>
|
|
|
+ <view class="cont">{{ activeDesc }}</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-if="activeTask?.taskRemark" class="list">
|
|
|
+ <view class="tit">任务要求:</view>
|
|
|
+ <view class="cont">{{ activeTask.taskRemark }}</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="btn" @click="descVisible = false">知道了</view>
|
|
|
+ </view>
|
|
|
+ </wd-popup>
|
|
|
+ </view>
|
|
|
</template>
|
|
|
|
|
|
-<script setup lang="ts"></script>
|
|
|
+<script setup lang="ts">
|
|
|
+import { computed, onMounted, ref } from 'vue'
|
|
|
+
|
|
|
+import config from '@/config'
|
|
|
+
|
|
|
+import { getDictTypeApi } from '@/services/modules/common'
|
|
|
+import type { DictItem } from '@/services/modules/common/type'
|
|
|
+import {
|
|
|
+ getTaskTypeDeptListApi,
|
|
|
+ getTaskTypeListByRuleIdApi,
|
|
|
+} from '@/services/modules/mine/points-rule'
|
|
|
+import type {
|
|
|
+ TaskTypeDeptListResponse,
|
|
|
+ TaskTypeListByRuleIdResponse,
|
|
|
+} from '@/services/modules/mine/points-rule/type'
|
|
|
+
|
|
|
+type TaskRuleItem = TaskTypeListByRuleIdResponse[string][number]
|
|
|
+
|
|
|
+const topImgBg = `${config.imgHost}home-top-bg2.png`
|
|
|
+const tipsIcon = 'https://yy-cloud-oss.oss-cn-beijing.aliyuncs.com/img/tips.png'
|
|
|
+
|
|
|
+const selectedRuleId = ref('')
|
|
|
+const pickerShow = ref(false)
|
|
|
+const loading = ref(false)
|
|
|
+const descVisible = ref(false)
|
|
|
+
|
|
|
+const enterpriseList = ref<TaskTypeDeptListResponse>([])
|
|
|
+const dictList = ref<DictItem[]>([])
|
|
|
+const sections = ref<Array<{ title: string; items: TaskRuleItem[] }>>([])
|
|
|
+const activeTask = ref<TaskRuleItem>()
|
|
|
+
|
|
|
+const activeDesc = computed(() => {
|
|
|
+ const taskName = activeTask.value?.taskTypeName?.trim()
|
|
|
+
|
|
|
+ if (!taskName) return '暂无定义'
|
|
|
+
|
|
|
+ const dict = dictList.value.find((item) => {
|
|
|
+ return [item.label, item.value, item.externalValue].includes(taskName)
|
|
|
+ })
|
|
|
+
|
|
|
+ return dict?.description || dict?.remarks || '暂无定义'
|
|
|
+})
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ initPage()
|
|
|
+})
|
|
|
+
|
|
|
+const initPage = async () => {
|
|
|
+ await Promise.all([loadEnterpriseList(), loadDictList()])
|
|
|
+
|
|
|
+ const firstRuleId = enterpriseList.value[0]?.value
|
|
|
+
|
|
|
+ if (!firstRuleId) return
|
|
|
+
|
|
|
+ selectedRuleId.value = firstRuleId
|
|
|
+ await loadRules(firstRuleId)
|
|
|
+}
|
|
|
+
|
|
|
+const loadEnterpriseList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getTaskTypeDeptListApi()
|
|
|
+
|
|
|
+ if (res.code === 0) {
|
|
|
+ enterpriseList.value = res.data
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ enterpriseList.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const loadDictList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getDictTypeApi('task_type_desc')
|
|
|
+
|
|
|
+ if (res.code === 0) {
|
|
|
+ dictList.value = res.data
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ dictList.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const loadRules = async (ruleId: string) => {
|
|
|
+ if (!ruleId) {
|
|
|
+ sections.value = []
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ loading.value = true
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await getTaskTypeListByRuleIdApi(ruleId)
|
|
|
+
|
|
|
+ if (res.code === 0) {
|
|
|
+ sections.value = Object.entries(res.data)
|
|
|
+ .map(([title, items]) => ({ title, items }))
|
|
|
+ .filter((section) => section.items.length > 0)
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ sections.value = []
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const showEnterprisePicker = () => {
|
|
|
+ if (!enterpriseList.value.length) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '暂无可切换企业',
|
|
|
+ icon: 'none',
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ pickerShow.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const handleEnterpriseConfirm = async (event: { value: string | string[] }) => {
|
|
|
+ const ruleId = Array.isArray(event.value) ? event.value[0] : event.value
|
|
|
+
|
|
|
+ if (!ruleId) return
|
|
|
+
|
|
|
+ selectedRuleId.value = ruleId
|
|
|
+ activeTask.value = undefined
|
|
|
+ descVisible.value = false
|
|
|
+
|
|
|
+ await loadRules(ruleId)
|
|
|
+}
|
|
|
+
|
|
|
+const openDesc = (task: TaskRuleItem) => {
|
|
|
+ activeTask.value = task
|
|
|
+ descVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const formatScore = (score: TaskRuleItem['score']) => {
|
|
|
+ const value = Number(score)
|
|
|
+
|
|
|
+ return Number.isFinite(value) ? value : score || 0
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.rules-box {
|
|
|
+ position: relative;
|
|
|
+ min-height: 100vh;
|
|
|
+ overflow-x: hidden;
|
|
|
+ background: #019cd0;
|
|
|
+}
|
|
|
+
|
|
|
+.rules-top-img {
|
|
|
+ display: block;
|
|
|
+ width: 750rpx;
|
|
|
+ height: 526rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.enterprise-switch {
|
|
|
+ position: fixed;
|
|
|
+ z-index: 99;
|
|
|
+ right: 0;
|
|
|
+ top: 360rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 76rpx;
|
|
|
+ padding: 0 22rpx 0 18rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border-radius: 999rpx 0 0 999rpx;
|
|
|
+ color: #ffffff;
|
|
|
+ background: linear-gradient(135deg, #2f8cff 0%, #13c2c2 100%);
|
|
|
+ box-shadow:
|
|
|
+ 0 12rpx 28rpx rgba(19, 129, 210, 0.32),
|
|
|
+ inset 0 1rpx 0 rgba(255, 255, 255, 0.32);
|
|
|
+
|
|
|
+ text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ line-height: 76rpx;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.enterprise-switch__icon {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 46rpx;
|
|
|
+ height: 46rpx;
|
|
|
+ margin-right: 10rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ color: #2f8cff;
|
|
|
+ background: rgba(255, 255, 255, 0.96);
|
|
|
+}
|
|
|
+
|
|
|
+.table-box {
|
|
|
+ min-height: calc(100vh - 526rpx);
|
|
|
+ background: #019cd0;
|
|
|
+}
|
|
|
+
|
|
|
+.table-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 120rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.table-tab {
|
|
|
+ width: 50%;
|
|
|
+ color: #ffffff;
|
|
|
+ font-size: 38rpx;
|
|
|
+ font-weight: 800;
|
|
|
+ line-height: 120rpx;
|
|
|
+ text-align: center;
|
|
|
+ letter-spacing: 1rpx;
|
|
|
+ text-shadow: 0 4rpx 12rpx rgba(0, 72, 120, 0.2);
|
|
|
+}
|
|
|
+
|
|
|
+.table-tab--left {
|
|
|
+ border-right: 1rpx solid rgba(255, 255, 255, 0.78);
|
|
|
+}
|
|
|
+
|
|
|
+.table-con {
|
|
|
+ padding: 0 26rpx 50rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.table-bg {
|
|
|
+ min-height: 420rpx;
|
|
|
+ padding: 46rpx;
|
|
|
+ border-radius: 18rpx;
|
|
|
+ background: linear-gradient(180deg, rgba(241, 253, 255, 0.96) 0%, #ffffff 38%), #ffffff;
|
|
|
+ box-shadow:
|
|
|
+ inset 0 8rpx 54rpx rgba(110, 219, 255, 0.42),
|
|
|
+ 0 18rpx 36rpx rgba(0, 96, 140, 0.12);
|
|
|
+}
|
|
|
+
|
|
|
+.section + .section {
|
|
|
+ margin-top: 56rpx;
|
|
|
+ padding-top: 42rpx;
|
|
|
+ border-top: 1rpx solid rgba(104, 193, 228, 0.28);
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ position: relative;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ color: #4f3a9f;
|
|
|
+ font-size: 34rpx;
|
|
|
+ font-weight: 800;
|
|
|
+ line-height: 46rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title::before {
|
|
|
+ content: '';
|
|
|
+ width: 10rpx;
|
|
|
+ height: 30rpx;
|
|
|
+ margin-right: 14rpx;
|
|
|
+ border-radius: 999rpx;
|
|
|
+ background: linear-gradient(180deg, #24c6dc 0%, #514a9d 100%);
|
|
|
+}
|
|
|
+
|
|
|
+.table-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-top: 32rpx;
|
|
|
+ margin-left: 32rpx;
|
|
|
+ color: #5f4b8b;
|
|
|
+ font-size: 32rpx;
|
|
|
+ line-height: 44rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.item-left {
|
|
|
+ min-width: 0;
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.task-name {
|
|
|
+ min-width: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ color: #5b4b8a;
|
|
|
+ font-weight: 500;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.tips {
|
|
|
+ flex: none;
|
|
|
+ width: 36rpx;
|
|
|
+ height: 36rpx;
|
|
|
+ margin-left: 10rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.score-text {
|
|
|
+ flex: none;
|
|
|
+ min-width: 172rpx;
|
|
|
+ margin-left: 24rpx;
|
|
|
+ color: #0b8fc8;
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 800;
|
|
|
+ line-height: 44rpx;
|
|
|
+ text-align: right;
|
|
|
+ text-shadow: 0 4rpx 12rpx rgba(11, 143, 200, 0.12);
|
|
|
+}
|
|
|
+
|
|
|
+.loading {
|
|
|
+ padding: 20rpx 0;
|
|
|
+}
|
|
|
+
|
|
|
+.loading__item {
|
|
|
+ height: 72rpx;
|
|
|
+ margin-top: 24rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ background: linear-gradient(90deg, #eff9fd 0%, #e0f5fb 50%, #f7fdff 100%);
|
|
|
+}
|
|
|
+
|
|
|
+.empty {
|
|
|
+ padding: 80rpx 0;
|
|
|
+ color: #999999;
|
|
|
+ font-size: 28rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.info {
|
|
|
+ position: relative;
|
|
|
+ padding: 30rpx;
|
|
|
+ background: #ffffff;
|
|
|
+}
|
|
|
+
|
|
|
+.title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 60rpx;
|
|
|
+
|
|
|
+ text {
|
|
|
+ color: #000000;
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.list {
|
|
|
+ margin: 10rpx 0;
|
|
|
+}
|
|
|
+
|
|
|
+.tit {
|
|
|
+ margin-bottom: 10rpx;
|
|
|
+ color: #333333;
|
|
|
+ font-size: 32rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.cont {
|
|
|
+ min-height: 5vh;
|
|
|
+ margin-bottom: 60rpx;
|
|
|
+ color: #666666;
|
|
|
+ font-size: 24rpx;
|
|
|
+ line-height: 42rpx;
|
|
|
+}
|
|
|
|
|
|
-<style lang="scss" scoped></style>
|
|
|
+.btn {
|
|
|
+ height: 80rpx;
|
|
|
+ margin-top: 40rpx;
|
|
|
+ color: #333333;
|
|
|
+ font-size: 30rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ text-align: center;
|
|
|
+ background: #f1f1f1;
|
|
|
+}
|
|
|
+</style>
|