Browse Source

feat(app): 优化消息页面功能和交互

- 添加消息类型枚举和分组处理
- 实现消息列表按类型筛选和刷新功能
- 增加积分消息的确认和驳回操作- 优化消息详情展示,支持 HTML 内容
- 调整消息列表请求接口和参数
- 重构 PageHelper 组件,支持手动刷新
EvilDragon 4 months ago
parent
commit
c552a8a712

+ 26 - 9
packages/app/src/components/page-helper.vue

@@ -3,11 +3,17 @@ import { NetImages } from '../core/libs/net-images'
 import useRequest from '../hooks/useRequest'
 import { ref, Ref, watch, onMounted } from 'vue'
 
-const props = defineProps<{
-  request: (query: any) => Promise<IResData<T>>
-  query: Partial<T['list'][0]>
-  customClass?: string
-}>()
+const props = withDefaults(
+  defineProps<{
+    request: (query: any) => Promise<IResData<T>>
+    query: Partial<T['list'][0]>
+    customClass?: string
+    automatic?: boolean
+  }>(),
+  {
+    automatic: true,
+  },
+)
 const slot = defineSlots<{
   default(props: { data: Ref<S>[]; source: T }): any
 }>()
@@ -20,16 +26,27 @@ watch(
     await setData()
   },
 )
+// const
 onMounted(async () => {
-  await setData()
+  if (props.automatic) {
+    await setData()
+  }
 })
+
 // onReachBottom(() => {
 //   console.log(1111)
 // })
+const refresh = async () => {
+  console.log('Page Helper Refresh')
+  await setData()
+}
 defineExpose({
-  refresh: () => {
-    setData()
-  },
+  // refresh: () => {
+  //   console.log(1111)
+
+  //   setData()
+  // },
+  refresh,
 })
 </script>
 <template>

+ 14 - 0
packages/app/src/core/libs/enums.ts

@@ -0,0 +1,14 @@
+export enum MessageType {
+  /**
+   * 系统消息
+   */
+  System = 1,
+  /**
+   * 积分消息
+   */
+  Integral = 2,
+  /**
+   * 互动消息
+   */
+  Interact = 3,
+}

+ 16 - 0
packages/app/src/core/libs/requests.ts

@@ -19,6 +19,7 @@ import {
   Message,
 } from './models'
 import dayjs from 'dayjs'
+import { pointsCancel } from '../../../../merchant/node_modules/@designer-hub/app/src/core/libs/requests'
 
 export const getUserInfo = () =>
   httpGetMock<any>({
@@ -552,6 +553,21 @@ export const getBanners = (query: { mode: BannerMode }) =>
 export const getMessages = (query) =>
   httpGet<ResPageData<Message>>('/app-api/member/message-manage/page', query)
 /**
+ * 删除消息
+ */
+export const deleteMessage = (id: string) =>
+  httpPost('/app-api/member/message-manage/delete', {}, { id })
+/**
+ * 积分订单取消
+ */
+export const orderPointsCancel = (query: { id: string; cancelReason: string }) =>
+  httpGet('/app-api/member/message-manage/points-cancel', query)
+/**
+ * 积分订单确认
+ */
+export const orderPointsSubmit = (query: { id: string }) =>
+  httpGet('/app-api/member/message-manage/order-points-confirm', query)
+/**
  * 获取Banner
  */
 export const getBanner = (id) => httpGet<Banner>('/app-api/member/banner/get-by-id', { id })

+ 67 - 12
packages/app/src/pages/messages/index.vue

@@ -11,16 +11,27 @@
 <script setup lang="ts">
 import Card from '@/components/card.vue'
 import PageHelper from '@/components/page-helper.vue'
-import { getMessages } from '../../core/libs/requests'
+import {
+  deleteMessage,
+  getMessages,
+  orderPointsCancel,
+  orderPointsSubmit,
+} from '../../core/libs/requests'
 import { integral, interact, system } from '../../core/libs/svgs'
 import { beforeNow } from '../../utils/date-util'
 import dayjs from 'dayjs'
+import { MessageType } from '../../core/libs/enums'
+import { group } from 'radash'
+import { ComponentExposed } from 'vue-component-type-helpers'
+import { Message } from '@/core/libs/models'
+import { requestToast } from '@/core/utils/common'
 
-const tab = ref('integral')
+const pageHelperRef = ref<ComponentExposed<typeof PageHelper>>()
+const tab = ref(0)
 const tabs = ref([
-  { label: '积分消息', value: 'integral' },
-  { label: '系统消息', value: 'system' },
-  { label: '互动消息', value: 'interact' },
+  { label: '积分消息', value: MessageType.Integral },
+  { label: '系统消息', value: MessageType.System },
+  { label: '互动消息', value: MessageType.Interact },
 ])
 const msgs = ref({
   integral: [
@@ -50,18 +61,41 @@ const msgs = ref({
   ],
 })
 const messageTypes = ref([{}])
+onShow(async () => {
+  nextTick(() => {
+    pageHelperRef.value?.refresh()
+  })
+})
+const handleCancel = async (message: Message) => {
+  await requestToast(
+    () => orderPointsCancel({ id: message.businessId.toString(), cancelReason: '用户取消' }),
+    { success: true, successTitle: '积分确认已驳回' },
+  )
+  await deleteMessage(message.id.toString())
+  await pageHelperRef.value?.refresh()
+}
+const handleSubmit = async (message: Message) => {
+  await requestToast(() => orderPointsSubmit({ id: message.businessId.toString() }), {
+    success: true,
+    successTitle: '积分已确认',
+  })
+  // await deleteMessage(message.id.toString())
+  await pageHelperRef.value?.refresh()
+}
 </script>
 
 <template>
   <view class="flex-grow flex flex-col">
     <wd-tabs v-model="tab">
-      <block v-for="({ label, value }, i) in tabs" :key="i">
-        <wd-tab :title="`${label}`" :name="value"></wd-tab>
+      <block v-for="({ label }, i) in tabs" :key="i">
+        <wd-tab :title="`${label}`"></wd-tab>
       </block>
     </wd-tabs>
     <PageHelper
+      ref="pageHelperRef"
+      :automatic="false"
       :request="getMessages"
-      :query="{ messageType: '1' }"
+      :query="{ messageType: tabs[tab]?.value.toString() }"
       class="flex-grow flex flex-col"
     >
       <template #default="{ source }">
@@ -76,7 +110,7 @@ const messageTypes = ref([{}])
                     <wd-img
                       width="18"
                       height="18"
-                      :src="{ integral: integral, system: system, interact: interact }[tab]"
+                      :src="[integral, system, interact][tab]"
                     ></wd-img>
                   </div>
                 </div>
@@ -91,14 +125,18 @@ const messageTypes = ref([{}])
                   <div
                     class="text-black/30 text-sm font-normal font-['PingFang_SC'] leading-[10.18px]"
                   >
-                    {{ beforeNow(dayjs(it.createdAt).toDate()) }}
+                    {{ beforeNow(dayjs(it.createTime).toDate()) }}
                   </div>
                 </div>
                 <div class="row-start-2 col-start-2 col-end-4">
                   <div
                     class="my-3 text-black/40 text-sm font-normal font-['PingFang_SC'] leading-[25px]"
                   >
-                    {{ it.content }}
+                    <div
+                      v-if="it.messageType === MessageType.Integral.toString()"
+                      v-html="it.detailBody"
+                    ></div>
+                    <!-- {{ it.detailBody }} -->
                   </div>
                 </div>
                 <div v-if="it.img" class="row-start-3 col-start-2 col-end-4">
@@ -111,7 +149,24 @@ const messageTypes = ref([{}])
                   <div
                     class="text-black/90 text-xs font-normal font-['PingFang_SC'] leading-[25px]"
                   >
-                    查看详情
+                    <template v-if="[MessageType.Integral].includes(Number(it.messageType))">
+                      <span class="text-black/40">
+                        确认积分后,即刻到账,如有问题请驳回,联系材料商修改积分后再次确认
+                      </span>
+                    </template>
+                    <template v-else>查看详情</template>
+                  </div>
+                </div>
+                <div class="row-start-6 col-start-1 col-end-4">
+                  <div class="flex gap-4">
+                    <div class="flex-1">
+                      <wd-button block :round="false" plain @click="handleCancel(it)">
+                        驳回
+                      </wd-button>
+                    </div>
+                    <div class="flex-1">
+                      <wd-button block :round="false" @click="handleSubmit(it)">确认</wd-button>
+                    </div>
                   </div>
                 </div>
               </div>

+ 10 - 1
packages/app/src/pages/mine/index.vue

@@ -16,7 +16,6 @@ import TasksCard from './components/tasks-card.vue'
 import { useRouter } from '../../core/utils/router'
 import { NetImages } from '../../core/libs/net-images'
 import { qrCodeString2Object, toQrCodeString } from '../../core/utils/common'
-import { QrCodeBusinessType } from '@/core/libs/models'
 
 const router = useRouter()
 const userStore = useUserStore()
@@ -53,6 +52,11 @@ const levels = ref({
     bgImg:
       'https://image.zhuchaohui.com/zhucaohui/60811dfd5c5a4fa7502cfc2ff3db188849d4f9363849420ba72e32c03f20eca5.png',
   },
+  4: {
+    color: '#65341d',
+    bgImg:
+      'https://image.zhuchaohui.com/zhucaohui/236227e8094b50dafb21039c259b6fef9c9960a3347ae4286beddee23871e662.png',
+  },
 })
 const pieces = ref([
   {
@@ -132,6 +136,10 @@ const handleClickScan = async () => {
   console.log(qrCodeString2Object(toQrCodeString('到店', { a: 1, orderId: 2222 })))
   router.push(`/pages/mine/scan/result/index?result=${result}`)
 }
+const handle2Video = () => {
+  // wx.openChannelsUserProfile({ finderUserName: 'sphtEhk7olIepB0' })
+  uni.openChannelsUserProfile({ finderUserName: 'sphtEhk7olIepB0' })
+}
 onMounted(async () => {})
 const navBarProps = ref({ customClass: 'bg-transparent!' })
 onPageScroll(({ scrollTop }: { scrollTop: number }) => {
@@ -327,6 +335,7 @@ onPageScroll(({ scrollTop }: { scrollTop: number }) => {
       <TasksCard custom-class="my-6" :items="taskData.list"></TasksCard>
       <SectionHeading custom-class="my-6" title="和筑巢荟一起共同成长"></SectionHeading>
       <CardMenu :items="pieces" custom-class="grid-cols-2" />
+      <wd-button @click="handle2Video">视频号</wd-button>
     </view>
   </view>
 </template>