From 16b23681a7af6a268914fe7bdb4e16f1f0ba275a Mon Sep 17 00:00:00 2001
From: xingyu <xingyu4j@vip.qq.com>
Date: Tue, 25 Apr 2023 10:42:31 +0800
Subject: [PATCH] feat: mp message

---
 src/views/mp/message/MessageModal.vue |  43 ++++++++
 src/views/mp/message/index.vue        |  45 +++++++-
 src/views/mp/message/message.data.ts  | 142 ++++++++++++++++++++++++++
 3 files changed, 229 insertions(+), 1 deletion(-)
 create mode 100644 src/views/mp/message/MessageModal.vue
 create mode 100644 src/views/mp/message/message.data.ts

diff --git a/src/views/mp/message/MessageModal.vue b/src/views/mp/message/MessageModal.vue
new file mode 100644
index 0000000..69845b1
--- /dev/null
+++ b/src/views/mp/message/MessageModal.vue
@@ -0,0 +1,43 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" title="发送消息" @ok="handleSubmit">
+    <BasicForm @register="registerForm" />
+  </BasicModal>
+</template>
+<script lang="ts" setup name="MpMessageModal">
+import { BasicModal, useModalInner } from '@/components/Modal'
+import { BasicForm, useForm } from '@/components/Form'
+import { formSchema } from './message.data'
+import { sendMessage } from '@/api/mp/message'
+import { ref } from 'vue'
+
+const emit = defineEmits(['success', 'register'])
+
+const userId = ref(0)
+
+const [registerForm, { resetFields, validate }] = useForm({
+  labelWidth: 120,
+  baseColProps: { span: 24 },
+  schemas: formSchema,
+  showActionButtonGroup: false,
+  actionColOptions: { span: 23 }
+})
+
+const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
+  resetFields()
+  setModalProps({ confirmLoading: false })
+  userId.value = data.record.userId
+})
+
+async function handleSubmit() {
+  try {
+    const values = await validate()
+    values.userId = userId.value
+    setModalProps({ confirmLoading: true })
+    await sendMessage(values)
+    closeModal()
+    emit('success')
+  } finally {
+    setModalProps({ confirmLoading: false })
+  }
+}
+</script>
diff --git a/src/views/mp/message/index.vue b/src/views/mp/message/index.vue
index 3b64cfc..528f8d4 100644
--- a/src/views/mp/message/index.vue
+++ b/src/views/mp/message/index.vue
@@ -1,3 +1,46 @@
 <template>
-  <div>开发中</div>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[{ icon: IconEnum.VIEW, label: '消息', auth: 'mp:message:send', onClick: handleEdit.bind(null, record) }]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <AccountModal @register="registerModal" @success="reload()" />
+  </div>
 </template>
+<script lang="ts" setup name="MpMessage">
+import { useI18n } from '@/hooks/web/useI18n'
+import { useModal } from '@/components/Modal'
+import AccountModal from './MessageModal.vue'
+import { IconEnum } from '@/enums/appEnum'
+import { BasicTable, useTable, TableAction } from '@/components/Table'
+import { getMessagePage } from '@/api/mp/message'
+import { columns, searchFormSchema } from './message.data'
+
+const { t } = useI18n()
+const [registerModal, { openModal }] = useModal()
+
+const [registerTable, { reload }] = useTable({
+  title: '公众号消息列表',
+  api: getMessagePage,
+  columns,
+  formConfig: { labelWidth: 120, schemas: searchFormSchema },
+  useSearchForm: true,
+  showTableSetting: true,
+  actionColumn: {
+    width: 140,
+    title: t('common.action'),
+    dataIndex: 'action',
+    fixed: 'right'
+  }
+})
+
+/** 修改按钮操作 */
+function handleEdit(record: Recordable) {
+  openModal(true, { record })
+}
+</script>
diff --git a/src/views/mp/message/message.data.ts b/src/views/mp/message/message.data.ts
new file mode 100644
index 0000000..a6031b9
--- /dev/null
+++ b/src/views/mp/message/message.data.ts
@@ -0,0 +1,142 @@
+import { getStrDictOptions } from '@/utils/dict'
+import { BasicColumn, FormSchema, useRender } from '@/components/Table'
+import { DICT_TYPE } from '@/utils/dict'
+import { getSimpleAccounts } from '@/api/mp/account'
+
+export enum MsgType {
+  Event = 'event',
+  Text = 'text',
+  Voice = 'voice',
+  Image = 'image',
+  Video = 'video',
+  Link = 'link',
+  Location = 'location',
+  Music = 'music',
+  News = 'news'
+}
+
+export const columns: BasicColumn[] = [
+  {
+    title: '发送时间',
+    dataIndex: 'createTime',
+    width: 180,
+    customRender: ({ text }) => {
+      return useRender.renderDate(text)
+    }
+  },
+  {
+    title: '消息类型',
+    dataIndex: 'type',
+    width: 80,
+    customRender: ({ text }) => {
+      return useRender.renderDict(text, DICT_TYPE.MP_MESSAGE_TYPE, 'string')
+    }
+  },
+  {
+    title: '发送方',
+    dataIndex: 'sendFrom',
+    width: 180,
+    customRender: ({ text }) => {
+      if (text === 1) {
+        return useRender.renderTag('粉丝', 'success')
+      } else {
+        return useRender.renderTag('公众号', 'default')
+      }
+    }
+  },
+  {
+    title: '用户标识',
+    dataIndex: 'openid',
+    width: 300
+  },
+  {
+    title: '内容',
+    dataIndex: 'content',
+    width: 300,
+    customRender: ({ text, record }) => {
+      if (record.type === MsgType.Event && record.event === 'subscribe') {
+        return useRender.renderTag('关注', 'success')
+      } else if (record.type === MsgType.Event && record.event === 'unsubscribe') {
+        return useRender.renderTag('取消关注', 'warn')
+      } else if (record.type === MsgType.Event && record.event === 'CLICK') {
+        return useRender.renderTag('点击菜单' + record.eventKey)
+      } else if (record.type === MsgType.Event && record.event === 'VIEW') {
+        return useRender.renderTag('点击菜单链接' + record.eventKey)
+      } else if (record.type === MsgType.Event && record.event === 'scancode_waitmsg') {
+        return useRender.renderTag('扫码结果' + record.eventKey)
+      } else if (record.type === MsgType.Event && record.event === 'scancode_push') {
+        return useRender.renderTag('扫码结果' + record.eventKey)
+      } else if (record.type === MsgType.Event && record.event === 'pic_sysphoto') {
+        return useRender.renderTag('系统拍照发图')
+      } else if (record.type === MsgType.Event && record.event === 'pic_photo_or_album') {
+        return useRender.renderTag('拍照或者相册')
+      } else if (record.type === MsgType.Event && record.event === 'pic_weixin') {
+        return useRender.renderTag('微信相册')
+      } else if (record.type === MsgType.Event && record.event === 'location_select') {
+        return useRender.renderTag('选择地理位置')
+      } else if (record.type === MsgType.Event) {
+        return useRender.renderTag('未知事件类型')
+      } else if (record.type === MsgType.Text) {
+        return text
+      } else if (record.type === MsgType.Voice) {
+        // TODO voice
+        return record.mediaUrl
+      } else if (record.type === MsgType.Image) {
+        return useRender.renderImg(record.mediaUrl)
+      } else if (record.type === MsgType.Video || record.type === 'shortvideo') {
+        // TODO
+        return record.mediaUrl
+      } else if (record.type === MsgType.Link) {
+        return useRender.renderLink(record.url, record.title)
+      } else if (record.type === MsgType.Location) {
+        // TODO
+        return record.label
+      } else if (record.type === MsgType.Music) {
+        // TODO
+        return record.title
+      } else if (record.type === MsgType.News) {
+        // TODO
+        return record.articles
+      } else {
+        return useRender.renderTag('未知消息类型', 'warn')
+      }
+    }
+  }
+]
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '公众号',
+    field: 'accountId',
+    component: 'ApiSelect',
+    componentProps: {
+      api: () => getSimpleAccounts(),
+      labelField: 'name',
+      valueField: 'id'
+    },
+    colProps: { span: 8 }
+  },
+  {
+    label: '消息类型',
+    field: 'type',
+    component: 'Select',
+    componentProps: {
+      options: getStrDictOptions(DICT_TYPE.MP_MESSAGE_TYPE)
+    },
+    colProps: { span: 8 }
+  },
+  {
+    label: '用户标识',
+    field: 'openid',
+    component: 'Select',
+    colProps: { span: 8 }
+  },
+  {
+    label: '创建时间',
+    field: 'createTime',
+    component: 'RangePicker',
+    colProps: { span: 8 }
+  }
+]
+
+export const formSchema: FormSchema[] = []