Browse Source

feat(app): 优化 coupon-card组件并添加新功能

- 在 coupon-card 组件中添加优惠券使用状态图标
- 优化优惠券卡片的样式,增加品牌名称显示
- 在 common.ts 中添加预览图片功能
- 优化 toast 函数,增加更多的图标选项
EvilDragon 4 months ago
parent
commit
a9b5146ec1

+ 1 - 1
packages/app/src/composables/permissions.ts

@@ -61,7 +61,7 @@ export const usePermissions = () => {
     /**
     /**
      * 1分钟了解筑巢荟
      * 1分钟了解筑巢荟
      */
      */
-    about: isDesigner.value,
+    about: true,
     toDesignerHomePage: isLogined.value,
     toDesignerHomePage: isLogined.value,
     checkInAtStoreTask: isDesigner.value,
     checkInAtStoreTask: isDesigner.value,
     shareMoment: isLogined.value && isDesigner.value && userInfo.value.level.level > 1,
     shareMoment: isLogined.value && isDesigner.value && userInfo.value.level.level > 1,

+ 7 - 0
packages/app/src/core/libs/models.ts

@@ -1089,6 +1089,13 @@ export interface AgentTask {
   finalTypeName: string
   finalTypeName: string
   roleTypeName: string
   roleTypeName: string
   statusName: string
   statusName: string
+  qrList?: {
+    avatar: string
+    createTime: number
+    id: number
+    name: string
+    remark: string
+  }[]
 }
 }
 export interface FollowUp {
 export interface FollowUp {
   id: number
   id: number

+ 17 - 3
packages/app/src/core/utils/common.ts

@@ -1,6 +1,17 @@
 import dayjs from 'dayjs'
 import dayjs from 'dayjs'
 export const handleCall = (phone: string) => {
 export const handleCall = (phone: string) => {
-  uni.makePhoneCall({ phoneNumber: phone })
+  uni.makePhoneCall({ phoneNumber: phone }).then()
+}
+/**
+ * 预览图片
+ */
+export const previewImage = (current: number, urls: string[]) => {
+  uni
+    .previewImage({
+      current,
+      urls,
+    })
+    .then()
 }
 }
 /**
 /**
  * 打开位置
  * 打开位置
@@ -26,8 +37,11 @@ export const isImageOrVideo = (url) => {
     return 'unknown'
     return 'unknown'
   }
   }
 }
 }
-export const toast = (msg: string, icon = 'none') => {
-  uni.showToast({ title: msg, icon })
+export const toast = (
+  msg: string,
+  icon: 'none' | 'success' | 'loading' | 'error' | 'fail' | 'exception' = 'none',
+) => {
+  uni.showToast({ title: msg, icon }).then()
 }
 }
 export const requestToast = async <T>(
 export const requestToast = async <T>(
   func: () => Promise<IResData<T>>,
   func: () => Promise<IResData<T>>,

+ 54 - 34
packages/app/src/pages/common/components/coupon-card.vue

@@ -3,6 +3,10 @@ import Card from '@/components/card.vue'
 import { Coupon } from '../../../core/libs/models'
 import { Coupon } from '../../../core/libs/models'
 import dayjs from 'dayjs'
 import dayjs from 'dayjs'
 import { useMessage } from 'wot-design-uni'
 import { useMessage } from 'wot-design-uni'
+import used from '@designer-hub/assets/src/libs/assets/used'
+import invalid from '@designer-hub/assets/src/libs/assets/invalid'
+import expired from '@designer-hub/assets/src/libs/assets/expired'
+
 const props = withDefaults(
 const props = withDefaults(
   defineProps<{ options?: Coupon; canSelect?: boolean; selected?: boolean }>(),
   defineProps<{ options?: Coupon; canSelect?: boolean; selected?: boolean }>(),
   {
   {
@@ -14,45 +18,61 @@ const emits = defineEmits<{ select: [coupon: Coupon]; clickInstruction: [coupon:
 </script>
 </script>
 <template>
 <template>
   <Card custom-class="mx-3.5">
   <Card custom-class="mx-3.5">
-    <div class="flex gap-3">
-      <div class="w-[94px] h-[94px] bg-[#f6f6f6] rounded-2.5 overflow-hidden">
-        <template v-if="options.couponType === 1">
-          <div class="bg-[#fff8f8] w-full h-full flex flex-col items-center justify-center">
-            <div class="text-[#ff7878] text-[26px] font-normal font-['PingFang_SC']">
-              {{ options.brandPoints }}
+    <div class="relative">
+      <div class="flex gap-3">
+        <div class="w-[94px] h-[94px] bg-[#f6f6f6] rounded-2.5 overflow-hidden">
+          <template v-if="options.couponType === 1">
+            <div class="bg-[#fff8f8] w-full h-full flex flex-col items-center justify-center">
+              <div class="text-[#ff7878] text-[26px] font-normal font-['PingFang_SC']">
+                {{ options.brandPoints }}
+              </div>
+              <div class="text-[#ff7878] text-base font-normal font-['PingFang_SC']">积分</div>
             </div>
             </div>
-            <div class="text-[#ff7878] text-base font-normal font-['PingFang_SC']">积分</div>
-          </div>
-        </template>
-        <template v-else>
-          <wd-img width="100%" height="100%" :src="options.couponImgUrl"></wd-img>
-        </template>
-      </div>
-      <div class="flex-1 flex flex-col justify-around">
-        <div class="text-black text-sm font-normal font-['PingFang_SC'] leading-normal">
-          <!-- GELATO咖啡兑换券 -->
-          {{ options.couponName }}
+          </template>
+          <template v-else>
+            <wd-img width="100%" height="100%" :src="options.couponImgUrl"></wd-img>
+          </template>
         </div>
         </div>
-        <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal">
-          有效期:
-          <!-- 2024/04/01-2024/05/30 -->
-          {{ dayjs(options.validityStartDate).format('YYYY/MM/DD') }}-{{
-            dayjs(options.validityEndDate).format('YYYY/MM/DD')
-          }}
+        <div class="flex-1 flex flex-col justify-around">
+          <div class="flex items-center gap-1">
+            <div
+              class="px-[3px] rounded border border-solid border-[#ff3636] justify-center items-center gap-2.5 inline-flex"
+            >
+              <div
+                class="text-[#ff3e3e] text-[10px] font-normal font-['PingFang_SC'] leading-normal"
+              >
+                {{ options.materialName }}
+              </div>
+            </div>
+            <div class="text-black text-sm font-normal font-['PingFang_SC'] leading-normal">
+              <!-- GELATO咖啡兑换券 -->
+              {{ options.couponName }}
+            </div>
+          </div>
+          <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal">
+            有效期:
+            <!-- 2024/04/01-2024/05/30 -->
+            {{ dayjs(options.validityStartDate).format('YYYY/MM/DD') }}-{{
+              dayjs(options.validityEndDate).format('YYYY/MM/DD')
+            }}
+          </div>
+          <div
+            class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal flex items-center"
+            @click="emits('clickInstruction', options)"
+          >
+            使用说明
+            <wd-icon name="arrow-right" size="14"></wd-icon>
+          </div>
         </div>
         </div>
-        <div
-          class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal flex items-center"
-          @click="emits('clickInstruction', options)"
-        >
-          使用说明
-          <wd-icon name="arrow-right" size="14"></wd-icon>
+        <div class="flex items-center" v-if="canSelect" @click="emits('select', options)">
+          <div
+            class="w-4 h-4 rounded-full border border-black/60 border-solid"
+            :class="`${selected ? 'bg-black' : ''}`"
+          ></div>
         </div>
         </div>
       </div>
       </div>
-      <div class="flex items-center" v-if="canSelect" @click="emits('select', options)">
-        <div
-          class="w-4 h-4 rounded-full border border-black/60 border-solid"
-          :class="`${selected ? 'bg-black' : ''}`"
-        ></div>
+      <div class="absolute top--4 right--4">
+        <wd-img width="58" height="58" :src="options.isUse ? used : options.isValid ? invalid : expired"></wd-img>
       </div>
       </div>
     </div>
     </div>
   </Card>
   </Card>

+ 108 - 48
packages/app/src/pages/material/detail/index.vue

@@ -8,9 +8,12 @@ import { getMaterialDetail, getByDictType, getMaterialHomePage } from '../../../
 import NavbarEvo from '@/components/navbar-evo.vue'
 import NavbarEvo from '@/components/navbar-evo.vue'
 import { DictType } from '../../../core/libs/models'
 import { DictType } from '../../../core/libs/models'
 import { phone } from '../../../core/libs/svgs'
 import { phone } from '../../../core/libs/svgs'
-import { handleCall, openLocation } from '../../../core/utils/common'
+import { handleCall, openLocation, previewImage } from '../../../core/utils/common'
 import router from '@designer-hub/assets/src/assets/svgs/router'
 import router from '@designer-hub/assets/src/assets/svgs/router'
+import { isVideoUrl } from 'wot-design-uni/components/common/util'
+import { useUserStore } from '@/store'
 
 
+const userStore = useUserStore()
 const id = ref()
 const id = ref()
 const { data, run: setData } = useRequest(() => getMaterialDetail({ id: id.value }))
 const { data, run: setData } = useRequest(() => getMaterialDetail({ id: id.value }))
 const { data: materialHomePageData, run: setMaterialHomePageData } = useRequest(
 const { data: materialHomePageData, run: setMaterialHomePageData } = useRequest(
@@ -33,6 +36,38 @@ const { data: materialsManageBrands, run: setMaterialsManageBrands } = useReques
   () => getByDictType(DictType.materialsManageBrand),
   () => getByDictType(DictType.materialsManageBrand),
   { initialData: [] },
   { initialData: [] },
 )
 )
+const handleDownload = () => {
+  // console.log('handleDownload')
+  const Authorization = userStore.userInfo?.token
+  uni.downloadFile({
+    url: `https://www.zhuchaohui.com/app-api/member/materials/download?materialsId=${id.value}`,
+    header: {
+      'trace-id': 1,
+      Authorization,
+    },
+    success: (res) => {
+      console.log('downloadFile success', res)
+      uni.saveFile({
+        tempFilePath: res.tempFilePath,
+        success: (res) => {
+          console.log('saveFile success', res)
+        },
+        fail: (err) => {
+          console.log('saveFile fail', err)
+        },
+      })
+      uni.openDocument({
+        filePath: res.tempFilePath,
+        success: (res) => {
+          console.log('openDocument success', res)
+        },
+        fail: (err) => {
+          console.log('openDocument fail', err)
+        },
+      })
+    },
+  })
+}
 onLoad(async (query: { id: number }) => {
 onLoad(async (query: { id: number }) => {
   id.value = query.id
   id.value = query.id
   await setData()
   await setData()
@@ -66,25 +101,24 @@ onLoad(async (query: { id: number }) => {
             ></wd-img>
             ></wd-img>
             <div class="flex flex-col gap-2.5">
             <div class="flex flex-col gap-2.5">
               <div class="flex gap-2 items-center">
               <div class="flex gap-2 items-center">
-                <div
-                  class="text-black/90 text-lg font-normal font-['PingFang_SC'] leading-[10.18px]"
-                >
+                <div class="text-black/90 text-lg font-normal font-['PingFang_SC']">
                   <!-- IMOLA瓷砖 -->
                   <!-- IMOLA瓷砖 -->
                   {{ data?.materialsName }}
                   {{ data?.materialsName }}
                 </div>
                 </div>
-                <div
-                  class="w-[52px] h-[17px] px-2 bg-[#ef4343] rounded-[3px] justify-center items-center gap-2.5 inline-flex"
-                >
-                  <div
-                    class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-normal"
-                  >
-                    <!-- 自营品牌 -->
-                    {{
-                      materialBrandLevels.find(({ value }) => value === String(data.materialsType))
-                        ?.label
-                    }}
-                  </div>
-                </div>
+
+                <!--                <div-->
+                <!--                  class="w-[52px] h-[17px] px-2 bg-[#ef4343] rounded-[3px] justify-center items-center gap-2.5 inline-flex"-->
+                <!--                >-->
+                <!--                  <div-->
+                <!--                    class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-normal"-->
+                <!--                  >-->
+                <!--                    &lt;!&ndash; 自营品牌 &ndash;&gt;-->
+                <!--                    {{-->
+                <!--                      materialBrandLevels.find(({ value }) => value === String(data.materialsType))-->
+                <!--                        ?.label-->
+                <!--                    }}-->
+                <!--                  </div>-->
+                <!--                </div>-->
               </div>
               </div>
               <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]">
               <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]">
                 {{
                 {{
@@ -112,26 +146,26 @@ onLoad(async (query: { id: number }) => {
                   }}
                   }}
                 </span>
                 </span>
               </div>
               </div>
-              <div class="flex gap-2.5">
-                <div
-                  class="w-[77px] h-5 px-2 py-px bg-neutral-100 rounded-[3px] justify-center items-center gap-2.5 inline-flex"
-                >
-                  <div
-                    class="text-black/60 text-[10px] font-normal font-['PingFang_SC'] leading-normal"
-                  >
-                    积分比例:{{ data?.pointsExchangeRate }}%
-                  </div>
-                </div>
-                <div
-                  class="w-[92px] h-5 px-2 py-px bg-neutral-100 rounded-[3px] justify-center items-center gap-2.5 inline-flex"
-                >
-                  <div
-                    class="text-black/60 text-[10px] font-normal font-['PingFang_SC'] leading-normal"
-                  >
-                    门店打卡:{{ data?.clockPoints }}积分
-                  </div>
-                </div>
-              </div>
+              <!--              <div class="flex gap-2.5">-->
+              <!--                <div-->
+              <!--                  class="w-[77px] h-5 px-2 py-px bg-neutral-100 rounded-[3px] justify-center items-center gap-2.5 inline-flex"-->
+              <!--                >-->
+              <!--                  <div-->
+              <!--                    class="text-black/60 text-[10px] font-normal font-['PingFang_SC'] leading-normal"-->
+              <!--                  >-->
+              <!--                    积分比例:{{ data?.pointsExchangeRate }}%-->
+              <!--                  </div>-->
+              <!--                </div>-->
+              <!--                <div-->
+              <!--                  class="w-[92px] h-5 px-2 py-px bg-neutral-100 rounded-[3px] justify-center items-center gap-2.5 inline-flex"-->
+              <!--                >-->
+              <!--                  <div-->
+              <!--                    class="text-black/60 text-[10px] font-normal font-['PingFang_SC'] leading-normal"-->
+              <!--                  >-->
+              <!--                    门店打卡:{{ data?.clockPoints }}积分-->
+              <!--                  </div>-->
+              <!--                </div>-->
+              <!--              </div>-->
             </div>
             </div>
           </div>
           </div>
           <template
           <template
@@ -197,14 +231,24 @@ onLoad(async (query: { id: number }) => {
               mode="aspectFill"
               mode="aspectFill"
               custom-class=""
               custom-class=""
             ></wd-img> -->
             ></wd-img> -->
-            <video class="w-full h-full"></video>
-          </div>
-          <div class="text-black/90 text-base font-normal font-['PingFang_SC'] leading-[10.18px]">
-            <!-- {{ materialHomePageData. }} -->
-            {{
-              materialsManageBrands.find(({ value }) => value === String(data?.manageBrand))?.label
-            }}
+            <template v-if="isVideoUrl(materialHomePageData.brandAdvantageUrl)">
+              <video class="w-full h-full"></video>
+            </template>
+            <template v-else>
+              <wd-img
+                width="100%"
+                height="100%"
+                :src="materialHomePageData.brandAdvantageUrl"
+                mode="aspectFill"
+                custom-class=""
+              ></wd-img>
+            </template>
           </div>
           </div>
+          <!--          <div class="text-black/90 text-base font-normal font-['PingFang_SC'] leading-[10.18px]">-->
+          <!--            {{-->
+          <!--              materialsManageBrands.find(({ value }) => value === String(data?.manageBrand))?.label-->
+          <!--            }}-->
+          <!--          </div>-->
           <div
           <div
             class="text-justify text-black/60 text-sm font-normal font-['PingFang_SC'] leading-[25px]"
             class="text-justify text-black/60 text-sm font-normal font-['PingFang_SC'] leading-[25px]"
           >
           >
@@ -216,18 +260,34 @@ onLoad(async (query: { id: number }) => {
         <SectionHeading title="产品展示"></SectionHeading>
         <SectionHeading title="产品展示"></SectionHeading>
       </template>
       </template>
       <template v-for="(it, index) in materialHomePageData.productDOList" :key="index">
       <template v-for="(it, index) in materialHomePageData.productDOList" :key="index">
-        <div class="aspect-[1.66/1] rounded-2xl overflow-hidden">
+        <div class="aspect-[1.66/1] rounded-2xl overflow-hidden relative">
           <swiper class="h-[55.7vw]">
           <swiper class="h-[55.7vw]">
-            <template v-for="img of it?.productImgUrl?.split(',')" :key="img">
+            <template v-for="(img, index) in it?.productImgUrl?.split(',')" :key="img">
               <swiper-item class="h-full">
               <swiper-item class="h-full">
-                <wd-img width="100%" height="100%" class="" :src="img" mode="aspectFill" />
+                <wd-img
+                  width="100%"
+                  height="100%"
+                  class=""
+                  :src="img"
+                  mode="aspectFill"
+                  @click="previewImage(index, it?.productImgUrl?.split(','))"
+                />
               </swiper-item>
               </swiper-item>
             </template>
             </template>
           </swiper>
           </swiper>
+          <div
+            class="absolute bottom-0 w-full h-[66px] bg-gradient-to-t from-black to-[#5e5e5e00] rounded-bl-2xl rounded-br-2xl flex items-center px-4.5"
+          >
+            <div class="text-white text-base font-normal font-['PingFang_SC'] leading-[10.18px]">
+              {{ it.productTitleName }}
+            </div>
+          </div>
         </div>
         </div>
       </template>
       </template>
 
 
-      <wd-button custom-class="w-full! rounded-lg!">下载所有素材包</wd-button>
+      <wd-button custom-class="w-full! rounded-lg!" @click="handleDownload">
+        下载所有素材包
+      </wd-button>
     </div>
     </div>
   </view>
   </view>
 </template>
 </template>

File diff suppressed because it is too large
+ 3 - 0
packages/assets/src/assets/expired.svg


File diff suppressed because it is too large
+ 3 - 0
packages/assets/src/assets/invalid.svg


File diff suppressed because it is too large
+ 3 - 0
packages/assets/src/assets/used.svg


+ 2 - 0
packages/assets/src/libs/assets/expired.ts

@@ -0,0 +1,2 @@
+import expired from '../../assets/expired.svg' 
+ export default expired

+ 2 - 0
packages/assets/src/libs/assets/invalid.ts

@@ -0,0 +1,2 @@
+import invalid from '../../assets/invalid.svg' 
+ export default invalid

+ 2 - 0
packages/assets/src/libs/assets/used.ts

@@ -0,0 +1,2 @@
+import used from '../../assets/used.svg' 
+ export default used

+ 1 - 1
packages/merchant/src/core/libs/requests.ts

@@ -233,7 +233,7 @@ export const createReportInfo = (data) => httpPost<any>('/app-api/member/report-
 // 获取任务列表
 // 获取任务列表
 export const getTaskList = (query) => httpGet<any>('/app-api/member/task/task-list', query)
 export const getTaskList = (query) => httpGet<any>('/app-api/member/task/task-list', query)
 // 任务详情
 // 任务详情
-export const getTaskDetail = (query) =>
+export const getTaskDetail = (query = {}) =>
   httpGet<AgentTask>('/app-api/member/task/task-detail', query)
   httpGet<AgentTask>('/app-api/member/task/task-detail', query)
 // 领取任务
 // 领取任务
 export const taskReceive = (data: any) => httpPost<any>('/app-api/member/task/task-receive', data)
 export const taskReceive = (data: any) => httpPost<any>('/app-api/member/task/task-receive', data)

+ 20 - 20
packages/merchant/src/pages/agent/tasks/detail/index.vue

@@ -90,7 +90,6 @@ const acceptingOrders = async () => {
         })
         })
         uni.hideLoading()
         uni.hideLoading()
         await initData()
         await initData()
-      } else if (res.cancel) {
       }
       }
     },
     },
   })
   })
@@ -112,7 +111,6 @@ const acceptingNoOrders = async () => {
         })
         })
         uni.hideLoading()
         uni.hideLoading()
         await initData()
         await initData()
-      } else if (res.cancel) {
       }
       }
     },
     },
   })
   })
@@ -283,24 +281,26 @@ onLoad(async (query?: Record<string | 'taskId', string>) => {
       </div>
       </div>
       <!-- 到店打卡-->
       <!-- 到店打卡-->
       <div v-if="taskDetails?.finalType == '1'" class="flex flex-col gap-4 mt-5">
       <div v-if="taskDetails?.finalType == '1'" class="flex flex-col gap-4 mt-5">
-        <!--        <template v-for="item in taskDetails?.brokerList" :key="item.id">-->
-        <!--          <div class="flex gap-2.5 p-3.5 bg-[#f7fbff] items-center rounded-[10px]">-->
-        <!--            <wd-img width="44" height="44" round :src="item.headImgUrl" />-->
-        <!--            <div class="flex-1 flex flex-col gap-2">-->
-        <!--              <div class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-normal">-->
-        <!--                {{ item.brokerName }}-->
-        <!--              </div>-->
-        <!--              <div class="text-black/30 text-sm font-normal font-['PingFang_SC'] leading-none">-->
-        <!--                {{ item.finalTypeName }}{{ item.shopNames }}-->
-        <!--              </div>-->
-        <!--            </div>-->
-        <!--            <div class="h-full flex items-start">-->
-        <!--              <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal">-->
-        <!--                {{ dayjs(item.createTime).format('YYYY/MM/DD HH:mm') }}-->
-        <!--              </div>-->
-        <!--            </div>-->
-        <!--          </div>-->
-        <!--        </template>-->
+        <template v-for="item in taskDetails?.qrList" :key="item.id">
+          <div class="flex gap-2.5 p-3.5 bg-[#f7fbff] items-center rounded-[10px]">
+            <wd-img width="44" height="44" round :src="item.avatar" />
+            <div class="flex-1 flex flex-col gap-2">
+              <div class="flex items-center justify-between">
+                <div class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-normal">
+                  {{ item.name }}
+                </div>
+                <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal">
+                  {{ dayjs(item.createTime).format('YYYY/MM/DD HH:mm') }}
+                </div>
+              </div>
+              <div class="h-full flex items-start">
+                <div class="text-black/30 text-sm font-normal font-['PingFang_SC'] leading-none">
+                  {{ item.remark }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </template>
       </div>
       </div>
       <!-- 上报-->
       <!-- 上报-->
       <div v-else>
       <div v-else>

+ 1 - 1
packages/merchant/src/pages/agent/tasks/index.vue

@@ -85,7 +85,7 @@ onMounted(async () => {
       <template #default="{ source }">
       <template #default="{ source }">
         <div class="flex-grow flex flex-col gap-4 p-4">
         <div class="flex-grow flex flex-col gap-4 p-4">
           <template v-for="item in source?.list" :key="item.id">
           <template v-for="item in source?.list" :key="item.id">
-            <TaskCard :options="item"></TaskCard>
+            <TaskCard :options="item" @change="pageHelperRef?.refresh()"></TaskCard>
           </template>
           </template>
         </div>
         </div>
       </template>
       </template>

Some files were not shown because too many files changed in this diff