Browse Source

完成积分包详情页面

yuanmingze 4 months ago
parent
commit
8f160504b0

+ 352 - 0
src/pages-task/task-package/detail.vue

@@ -0,0 +1,352 @@
+<template>
+  <view class="package-detail">
+    <!-- header -->
+    <view class="package-detail__header">
+      <view class="package-detail__title">
+        {{ packageDetail?.scorePackageName || '积分包详情' }}
+      </view>
+      <view class="package-detail__sub"> 编号:{{ packageDetail?.packageSn || '-' }} </view>
+    </view>
+
+    <!-- 基础信息 -->
+    <view class="detail-card">
+      <view class="detail-card__title">基础信息</view>
+
+      <view
+        v-for="item in detailRows"
+        :key="item.label"
+        class="detail-row"
+        :class="{ 'detail-row--long': item.long }"
+      >
+        <text class="detail-row__label">{{ item.label }}</text>
+        <text class="detail-row__value">{{ item.value }}</text>
+      </view>
+    </view>
+
+    <!-- 积分规则 -->
+    <view v-if="ruleSections.length" class="rule-card">
+      <view class="rule-card__title">积分规则</view>
+
+      <view v-for="section in ruleSections" :key="section.title" class="rule-section">
+        <view class="rule-section__title">{{ section.title }}</view>
+
+        <view v-for="item in section.items" :key="item.id" class="rule-item">
+          <text class="rule-item__name">{{ item.taskTypeName }}</text>
+          <text class="rule-item__score">+{{ item.score }} 积分</text>
+        </view>
+      </view>
+    </view>
+
+    <view v-if="!loading && !packageDetail" class="empty"> 暂无详情数据 </view>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { computed, ref } from 'vue'
+
+import { onLoad } from '@dcloudio/uni-app'
+
+import {
+  getPackageCanTaskListApi,
+  getScorePackagePageByIdApi,
+} from '@/services/modules/task/package'
+
+const id = ref('')
+const loading = ref(false)
+const packageDetail = ref(null)
+const ruleSections = ref([])
+
+const EMPTY_TEXT = '无'
+
+const formatDrugList = (val) => {
+  if (!val) return EMPTY_TEXT
+
+  // 已经是数组
+  if (Array.isArray(val)) {
+    return val.join('、') || EMPTY_TEXT
+  }
+  return String(val) || EMPTY_TEXT
+}
+
+const areaName = computed(() => {
+  const area = packageDetail.value?.area
+
+  if (!Array.isArray(area) || area.length === 0) return EMPTY_TEXT
+
+  return (
+    area
+      .map((item) => `${item.province ?? ''}${item.city ?? ''}${item.area ?? ''}`)
+      .filter(Boolean)
+      .join(',') || EMPTY_TEXT
+  )
+})
+
+const quizNames = computed(() => {
+  const list = packageDetail.value?.quizRelations
+
+  if (!Array.isArray(list) || list.length === 0) return EMPTY_TEXT
+
+  return (
+    list
+      .map((item) => item.title)
+      .filter(Boolean)
+      .join(',') || EMPTY_TEXT
+  )
+})
+
+const detailRows = computed(() => {
+  const d = packageDetail.value
+
+  return [
+    { label: '截止日期', value: d?.endTimeValue || EMPTY_TEXT },
+    { label: '接单对象类型', value: d?.typeidName || EMPTY_TEXT },
+    { label: '接单对象', value: d?.usernameList?.join(',') || EMPTY_TEXT },
+    { label: '结算渠道', value: d?.subjectLocationName || EMPTY_TEXT },
+    { label: '关联服务企业', value: d?.relatedServiceName || EMPTY_TEXT },
+    { label: '关联任务积分包', value: d?.relationScoreName || EMPTY_TEXT },
+    { label: '可分配积分值', value: d?.kfpjf || EMPTY_TEXT },
+    { label: '积分包值', value: d?.score || EMPTY_TEXT },
+    {
+      label: '接单对象范围',
+      value: d?.packageUserScopeName || EMPTY_TEXT,
+    },
+
+    // ⭐ 重点优化
+    {
+      label: '推广药品',
+      value: formatDrugList(d?.drugtableName),
+      long: true,
+    },
+
+    { label: '推广区域', value: areaName.value },
+    {
+      label: '派工范围',
+      value: d?.dispatchUserScopeName?.join(',') || EMPTY_TEXT,
+    },
+    { label: '测试试卷', value: quizNames.value },
+
+    {
+      label: '描述',
+      value: d?.description || EMPTY_TEXT,
+      long: true,
+    },
+  ]
+})
+
+onLoad((query) => {
+  const packageId = String(query?.id || '')
+
+  if (!packageId) {
+    uni.showToast({ title: '缺少ID', icon: 'none' })
+    return
+  }
+
+  id.value = packageId
+  initPage()
+})
+
+const initPage = async () => {
+  loading.value = true
+  uni.showLoading({ title: '加载中' })
+
+  try {
+    await Promise.all([getScorePackagePageById(), getPackageCanTaskList()])
+  } finally {
+    loading.value = false
+    uni.hideLoading()
+  }
+}
+
+const getScorePackagePageById = async () => {
+  const res = await getScorePackagePageByIdApi(id.value)
+  packageDetail.value = res.data || null
+}
+
+const getPackageCanTaskList = async () => {
+  const res = await getPackageCanTaskListApi(id.value)
+  ruleSections.value = normalizeRuleSections(res.data)
+}
+
+const normalizeRuleSections = (raw) => {
+  if (!raw) return []
+
+  if (Array.isArray(raw)) {
+    return raw.length ? [{ title: '积分规则', items: raw }] : []
+  }
+
+  if (Object.prototype.toString.call(raw) === '[object Object]') {
+    return Object.entries(raw)
+      .filter(([, v]) => Array.isArray(v) && v.length > 0)
+      .map(([title, items]) => ({ title, items }))
+  }
+
+  return []
+}
+</script>
+
+<style lang="scss" scoped>
+.package-detail {
+  min-height: 100vh;
+  padding: 24rpx;
+  background: #f5f7fa;
+
+  .package-detail__header {
+    padding: 36rpx 32rpx;
+    margin-bottom: 24rpx;
+    color: #ffffff;
+    background: linear-gradient(135deg, #3fa3f1 0%, #2176e8 100%);
+    border-radius: 24rpx;
+  }
+
+  .package-detail__title {
+    font-size: 38rpx;
+    font-weight: 700;
+    line-height: 52rpx;
+  }
+
+  .package-detail__sub {
+    margin-top: 10rpx;
+    font-size: 26rpx;
+    line-height: 36rpx;
+    opacity: 0.8;
+  }
+
+  .detail-card,
+  .rule-card {
+    margin-bottom: 24rpx;
+    overflow: hidden;
+    background: #ffffff;
+    border-radius: 20rpx;
+    box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
+  }
+
+  .detail-card__title,
+  .rule-card__title {
+    padding: 28rpx 32rpx 18rpx;
+    color: #1f2937;
+    font-size: 32rpx;
+    font-weight: 700;
+    line-height: 44rpx;
+    border-bottom: 1rpx solid #eef0f3;
+  }
+
+  .detail-row {
+    display: flex;
+    align-items: flex-start;
+    gap: 24rpx;
+    padding: 26rpx 32rpx;
+    border-bottom: 1rpx solid #f1f2f4;
+  }
+
+  .detail-row:last-child {
+    border-bottom: none;
+  }
+
+  .detail-row__label {
+    flex-shrink: 0;
+    width: 260rpx;
+    color: #6b7280;
+    font-size: 28rpx;
+    line-height: 40rpx;
+    white-space: nowrap;
+  }
+
+  .detail-row__value {
+    flex: 1;
+    min-width: 0;
+    color: #111827;
+    font-size: 28rpx;
+    line-height: 40rpx;
+    text-align: right;
+    word-break: break-all;
+  }
+
+  .detail-row--long {
+    display: block;
+  }
+
+  .detail-row--long .detail-row__label {
+    display: block;
+    width: auto;
+    margin-bottom: 16rpx;
+    white-space: nowrap;
+  }
+
+  .detail-row--long .detail-row__value {
+    display: block;
+    padding: 20rpx 24rpx;
+    color: #374151;
+    font-size: 28rpx;
+    line-height: 44rpx;
+    text-align: left;
+    word-break: break-all;
+    background: #f8fafc;
+    border-radius: 12rpx;
+  }
+
+  .rule-section {
+    padding: 28rpx 32rpx;
+  }
+
+  .rule-section + .rule-section {
+    border-top: 1rpx dashed #e5e7eb;
+  }
+
+  .rule-section__title {
+    position: relative;
+    padding-left: 18rpx;
+    margin-bottom: 20rpx;
+    color: #111827;
+    font-size: 30rpx;
+    font-weight: 700;
+    line-height: 42rpx;
+  }
+
+  .rule-section__title::before {
+    content: '';
+    position: absolute;
+    top: 8rpx;
+    left: 0;
+    width: 6rpx;
+    height: 28rpx;
+    background: #3fa3f1;
+    border-radius: 999rpx;
+  }
+
+  .rule-item {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: 24rpx;
+    padding: 18rpx 0;
+  }
+
+  .rule-item__name {
+    flex: 1;
+    min-width: 0;
+    color: #374151;
+    font-size: 28rpx;
+    line-height: 40rpx;
+    word-break: break-all;
+  }
+
+  .rule-item__score {
+    flex-shrink: 0;
+    padding: 8rpx 18rpx;
+    color: #2f86e6;
+    font-size: 26rpx;
+    font-weight: 600;
+    line-height: 34rpx;
+    background: rgba(63, 163, 241, 0.1);
+    border-radius: 999rpx;
+  }
+
+  .empty {
+    padding: 80rpx 24rpx;
+    color: #9ca3af;
+    font-size: 28rpx;
+    line-height: 40rpx;
+    text-align: center;
+  }
+}
+</style>

+ 14 - 3
src/pages-task/task-package/list.vue

@@ -45,7 +45,12 @@
     </view>
 
     <view v-else class="task-list-content">
-      <view v-for="item in packageListArr" :key="item.id" class="task-card">
+      <view
+        v-for="item in packageListArr"
+        :key="item.id"
+        class="task-card"
+        @click="handleOpenDetail(item)"
+      >
         <view class="task-card__header">
           <view class="task-card__title">
             {{ item.scorePackageName }}{{ item.packageSn ? `(${item.packageSn})` : '' }}
@@ -121,11 +126,11 @@ import dayjs from 'dayjs'
 
 import { getDictTypeApi } from '@/services/modules/common'
 import type { DictItem } from '@/services/modules/common/type'
-import { getUserScorePackageListApi, pickupPackageApi } from '@/services/modules/task/list'
+import { getUserScorePackageListApi, pickupPackageApi } from '@/services/modules/task/package'
 import type {
   getUserScorePackageListRequest,
   TaskPackageItem,
-} from '@/services/modules/task/list/type'
+} from '@/services/modules/task/package/type'
 
 const dialog = useDialog()
 const toast = useToast()
@@ -386,6 +391,12 @@ const getPackageStatusText = (status: string | null) => {
 
 const formatDate = (value: string | null) => value?.slice(0, 10) || '-'
 
+const handleOpenDetail = (item: TaskPackageItem) => {
+  uni.navigateTo({
+    url: `/pages-task/task-package/detail?id=${item.id}`,
+  })
+}
+
 onReachBottom(loadMoreTaskPackageList)
 onBeforeMount(() => {
   fetchTaskPackageList()

+ 7 - 0
src/pages.json

@@ -69,6 +69,13 @@
             "navigationBarTitleText": "领取任务包",
             "navigationStyle": "default"
           }
+        },
+        {
+          "path": "task-package/detail",
+          "style": {
+            "navigationBarTitleText": "积分包详情",
+            "navigationStyle": "default"
+          }
         }
       ]
     }

+ 6 - 9
src/services/modules/task/list/index.ts → src/services/modules/task/package/index.ts

@@ -19,12 +19,9 @@ export const pickupPackageApi = (data: pickupPackageRequest) => {
   })
 }
 
-
-
-  // getPackageStatusNewApi() {
-  //   return getHttp(`/admin/dict/type/package_new_status`);
-  // },
-
-// receivePackageWithQuiz: data => {
-//   return postHttp('/admin/api/pkg/pickup', data);
-// },
+export const getScorePackagePageByIdApi = (id: string) => {
+  return http.get(`/admin/wmscorepackage/getScorePackagePageById?id=${id}`)
+}
+export const getPackageCanTaskListApi = (packageId: string) => {
+  return http.get(`/admin/api/getPackageCanTaskList?packageId=${packageId}`)
+}

+ 0 - 0
src/services/modules/task/list/type.d.ts → src/services/modules/task/package/type.d.ts