Sfoglia il codice sorgente

积分包详情功能完成实现

yuanmingze 4 mesi fa
parent
commit
7ee9ca54f0

+ 1 - 0
components.d.ts

@@ -16,6 +16,7 @@ declare module 'vue' {
     WdDialog: typeof import('@wot-ui/ui/components/wd-dialog/wd-dialog.vue')['default']
     WdEmpty: typeof import('@wot-ui/ui/components/wd-empty/wd-empty.vue')['default']
     WdIcon: typeof import('@wot-ui/ui/components/wd-icon/wd-icon.vue')['default']
+    WdInput: typeof import('@wot-ui/ui/components/wd-input/wd-input.vue')['default']
     WdLoading: typeof import('@wot-ui/ui/components/wd-loading/wd-loading.vue')['default']
     WdNavbar: typeof import('@wot-ui/ui/components/wd-navbar/wd-navbar.vue')['default']
     WdNoticeBar: typeof import('@wot-ui/ui/components/wd-notice-bar/wd-notice-bar.vue')['default']

+ 235 - 36
src/pages-task/task-package/detail.vue

@@ -1,14 +1,12 @@
 <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 class="package-detail__sub">编号:{{ packageDetail?.packageSn || '-' }}</view>
     </view>
 
-    <!-- 基础信息 -->
     <view class="detail-card">
       <view class="detail-card__title">基础信息</view>
 
@@ -23,7 +21,6 @@
       </view>
     </view>
 
-    <!-- 积分规则 -->
     <view v-if="ruleSections.length" class="rule-card">
       <view class="rule-card__title">积分规则</view>
 
@@ -37,40 +34,109 @@
       </view>
     </view>
 
-    <view v-if="!loading && !packageDetail" class="empty"> 暂无详情数据 </view>
+    <view v-if="!loading && !packageDetail" class="empty">暂无详情数据</view>
+
+    <view v-if="showExportButton" class="bottom-action">
+      <wd-button block type="primary" @click="openExportPopup">发送报告</wd-button>
+    </view>
+
+    <wd-popup
+      v-model="exportPopupVisible"
+      position="bottom"
+      custom-style="border-radius: 32rpx 32rpx 0 0;"
+      @close="resetExportError"
+    >
+      <view class="export-popup">
+        <view class="export-popup__close" @click="exportPopupVisible = false">×</view>
+
+        <view class="export-popup__header">
+          <view class="export-popup__title">报告发送</view>
+          <view class="export-popup__desc">报告将发送至填写的邮箱,请确认邮箱地址有效。</view>
+        </view>
+
+        <view class="export-popup__body">
+          <view
+            class="export-popup__input-wrap"
+            :class="{ 'export-popup__input-wrap--error': emailError }"
+          >
+            <input
+              v-model="email"
+              class="export-popup__input"
+              placeholder="请输入邮箱"
+              placeholder-class="export-popup__placeholder"
+              type="text"
+              confirm-type="send"
+              cursor-spacing="120"
+              :focus="emailInputFocus"
+              :adjust-position="true"
+              @focus="emailError = ''"
+              @confirm="submitExportReport"
+            />
+          </view>
+
+          <view v-if="emailError" class="export-popup__error">
+            {{ emailError }}
+          </view>
+        </view>
+
+        <view class="export-popup__footer">
+          <wd-button block type="primary" :loading="exportLoading" @click="submitExportReport">
+            提交
+          </wd-button>
+        </view>
+      </view>
+    </wd-popup>
   </view>
 </template>
 
 <script setup lang="ts">
-import { computed, ref } from 'vue'
+import { computed, nextTick, ref } from 'vue'
 
 import { onLoad } from '@dcloudio/uni-app'
 
 import {
+  exportZbInfoFormWeiNewApi,
   getPackageCanTaskListApi,
   getScorePackagePageByIdApi,
-} from '@/services/modules/task/package'
+} from '@/services/modules/task/package/index'
+
+import { useUserStore } from '@/stores/modules/user'
+
+const userStore = useUserStore()
 
 const id = ref('')
 const loading = ref(false)
+const exportLoading = ref(false)
+const exportPopupVisible = ref(false)
+const emailInputFocus = ref(false)
+const emailError = ref('')
+const email = ref('')
 const packageDetail = ref(null)
 const ruleSections = ref([])
 
 const EMPTY_TEXT = '无'
 
+const roles = computed(() => userStore.currentUserInfo?.roles || [])
+
+const showExportButton = computed(() => {
+  return roles.value.includes(6) && packageDetail.value?.exportFlag === '1'
+})
+
 const formatDrugList = (val) => {
   if (!val) return EMPTY_TEXT
-
-  // 已经是数组
-  if (Array.isArray(val)) {
-    return val.join('、') || EMPTY_TEXT
-  }
-  return String(val) || EMPTY_TEXT
+  if (Array.isArray(val)) return val.join('、') || EMPTY_TEXT
+  return (
+    String(val)
+      .replace(/^\[|\]$/g, '')
+      .replace(/"/g, '')
+      .split(',')
+      .filter(Boolean)
+      .join('、') || EMPTY_TEXT
+  )
 }
 
 const areaName = computed(() => {
   const area = packageDetail.value?.area
-
   if (!Array.isArray(area) || area.length === 0) return EMPTY_TEXT
 
   return (
@@ -83,7 +149,6 @@ const areaName = computed(() => {
 
 const quizNames = computed(() => {
   const list = packageDetail.value?.quizRelations
-
   if (!Array.isArray(list) || list.length === 0) return EMPTY_TEXT
 
   return (
@@ -100,36 +165,28 @@ const detailRows = computed(() => {
   return [
     { label: '截止日期', value: d?.endTimeValue || EMPTY_TEXT },
     { label: '接单对象类型', value: d?.typeidName || EMPTY_TEXT },
-    { label: '接单对象', value: d?.usernameList?.join(',') || EMPTY_TEXT },
+    {
+      label: '接单对象',
+      value: Array.isArray(d?.usernameList)
+        ? d.usernameList.join(',')
+        : d?.usernameList || 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: d?.packageUserScopeName || EMPTY_TEXT },
+    { label: '推广药品', value: formatDrugList(d?.drugtableName), long: true },
     { label: '推广区域', value: areaName.value },
     {
       label: '派工范围',
-      value: d?.dispatchUserScopeName?.join(',') || EMPTY_TEXT,
+      value: Array.isArray(d?.dispatchUserScopeName)
+        ? d.dispatchUserScopeName.join(',')
+        : d?.dispatchUserScopeName || EMPTY_TEXT,
     },
     { label: '测试试卷', value: quizNames.value },
-
-    {
-      label: '描述',
-      value: d?.description || EMPTY_TEXT,
-      long: true,
-    },
+    { label: '描述', value: d?.description || EMPTY_TEXT, long: true },
   ]
 })
 
@@ -160,6 +217,7 @@ const initPage = async () => {
 const getScorePackagePageById = async () => {
   const res = await getScorePackagePageByIdApi(id.value)
   packageDetail.value = res.data || null
+  email.value = res.data?.email || ''
 }
 
 const getPackageCanTaskList = async () => {
@@ -167,6 +225,54 @@ const getPackageCanTaskList = async () => {
   ruleSections.value = normalizeRuleSections(res.data)
 }
 
+const openExportPopup = async () => {
+  resetExportError()
+  exportPopupVisible.value = true
+
+  await nextTick()
+
+  setTimeout(() => {
+    emailInputFocus.value = true
+  }, 300)
+}
+
+const resetExportError = () => {
+  emailError.value = ''
+  emailInputFocus.value = false
+}
+
+const submitExportReport = async () => {
+  const value = email.value.trim()
+
+  if (!validateEmail(value)) {
+    emailError.value = '请输入正确的邮箱地址'
+    emailInputFocus.value = true
+    return
+  }
+
+  exportLoading.value = true
+
+  try {
+    await exportZbInfoFormWeiNewApi({
+      id: id.value,
+      email: value,
+    })
+
+    exportPopupVisible.value = false
+
+    uni.showToast({
+      title: '报告已发送',
+      icon: 'none',
+    })
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+const validateEmail = (value) => {
+  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
+}
+
 const normalizeRuleSections = (raw) => {
   if (!raw) return []
 
@@ -187,7 +293,7 @@ const normalizeRuleSections = (raw) => {
 <style lang="scss" scoped>
 .package-detail {
   min-height: 100vh;
-  padding: 24rpx;
+  padding: 24rpx 24rpx 164rpx;
   background: #f5f7fa;
 
   .package-detail__header {
@@ -196,6 +302,7 @@ const normalizeRuleSections = (raw) => {
     color: #ffffff;
     background: linear-gradient(135deg, #3fa3f1 0%, #2176e8 100%);
     border-radius: 24rpx;
+    box-shadow: 0 12rpx 28rpx rgba(47, 134, 230, 0.24);
   }
 
   .package-detail__title {
@@ -341,6 +448,98 @@ const normalizeRuleSections = (raw) => {
     border-radius: 999rpx;
   }
 
+  .bottom-action {
+    position: fixed;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 0;
+    padding: 20rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
+    background: #ffffff;
+    box-shadow: 0 -8rpx 24rpx rgba(15, 23, 42, 0.08);
+  }
+
+  .export-popup {
+    position: relative;
+    padding: 40rpx 32rpx 24rpx;
+    background: #ffffff;
+  }
+
+  .export-popup__close {
+    position: absolute;
+    top: 28rpx;
+    right: 32rpx;
+    width: 48rpx;
+    height: 48rpx;
+    color: #9ca3af;
+    font-size: 44rpx;
+    line-height: 44rpx;
+    text-align: center;
+  }
+
+  .export-popup__header {
+    padding-right: 64rpx;
+    margin-bottom: 34rpx;
+  }
+
+  .export-popup__title {
+    color: #111827;
+    font-size: 38rpx;
+    font-weight: 700;
+    line-height: 52rpx;
+  }
+
+  .export-popup__desc {
+    margin-top: 10rpx;
+    color: #6b7280;
+    font-size: 26rpx;
+    line-height: 38rpx;
+  }
+
+  .export-popup__body {
+    margin-bottom: 40rpx;
+  }
+
+  .export-popup__input-wrap {
+    display: flex;
+    align-items: center;
+    height: 88rpx;
+    padding: 0 24rpx;
+    background: #ffffff;
+    border: 2rpx solid #e5e7eb;
+    border-radius: 16rpx;
+    box-sizing: border-box;
+  }
+
+  .export-popup__input-wrap--error {
+    border-color: #ef4444;
+    background: #fff7f7;
+  }
+
+  .export-popup__input {
+    width: 100%;
+    height: 88rpx;
+    color: #111827;
+    font-size: 30rpx;
+    line-height: 88rpx;
+  }
+
+  .export-popup__placeholder {
+    color: #9ca3af;
+    font-size: 30rpx;
+  }
+
+  .export-popup__error {
+    margin-top: 12rpx;
+    color: #ef4444;
+    font-size: 24rpx;
+    line-height: 34rpx;
+  }
+
+  .export-popup__footer {
+    padding-bottom: max(20rpx, env(safe-area-inset-bottom));
+  }
+
   .empty {
     padding: 80rpx 24rpx;
     color: #9ca3af;

+ 4 - 0
src/services/modules/task/package/index.ts

@@ -25,3 +25,7 @@ export const getScorePackagePageByIdApi = (id: string) => {
 export const getPackageCanTaskListApi = (packageId: string) => {
   return http.get(`/admin/api/getPackageCanTaskList?packageId=${packageId}`)
 }
+
+export const exportZbInfoFormWeiNewApi = (params: { id: string; email: string }) => {
+  return http.get(`/admin/reportExport/exportZbInfoFormWeiNew`, params)
+}