diff --git a/src/api/crm/message/index.ts b/src/api/crm/message/index.ts
new file mode 100644
index 00000000..fcd5fbd7
--- /dev/null
+++ b/src/api/crm/message/index.ts
@@ -0,0 +1,39 @@
+import request from '@/config/axios'
+
+export interface CustomerVO {
+  id?: number
+  name: string
+  industryId: number
+  level: number
+  source: number
+  followUpStatus?: boolean
+  lockStatus?: boolean
+  dealStatus?: boolean
+  mobile: string
+  telephone: string
+  website: string
+  qq: string
+  wechat: string
+  email: string
+  description: string
+  remark: string
+  ownerUserId?: number
+  ownerUserName?: string
+  ownerUserDept?: string
+  roUserIds?: string
+  rwUserIds?: string
+  areaId?: number
+  areaName?: string
+  detailAddress: string
+  contactLastTime?: Date
+  contactNextTime: Date
+  createTime?: Date
+  updateTime?: Date
+  creator?: string
+  creatorName?: string
+}
+
+// 查询客户列表
+export const getTodayCustomerPage = async (params) => {
+  return await request.get({ url: `/crm/message/todayCustomer`, params })
+}
diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts
index 8fa8373c..35320edb 100644
--- a/src/router/modules/remaining.ts
+++ b/src/router/modules/remaining.ts
@@ -528,6 +528,16 @@ const remainingRouter: AppRouteRecordRaw[] = [
           activeMenu: '/crm/product'
         },
         component: () => import('@/views/crm/product/detail/index.vue')
+      },
+      {
+        path: 'message',
+        name: 'CrmMessage',
+        meta: {
+          title: '待办事项',
+          noCache: true,
+          hidden: true
+        },
+        component: () => import('@/views/crm/message/index.vue')
       }
     ]
   }
diff --git a/src/views/crm/message/index.vue b/src/views/crm/message/index.vue
new file mode 100644
index 00000000..1f809524
--- /dev/null
+++ b/src/views/crm/message/index.vue
@@ -0,0 +1,134 @@
+<template>
+  <el-row :gutter="20">
+    <el-col :span="4" class="min-w-[200px]">
+      <div class="side-item-list">
+        <div
+          v-for="(item, index) in leftSides"
+          :key="index"
+          :class="leftType == item.infoType ? 'side-item-select' : 'side-item-default'"
+          class="side-item"
+          @click="sideClick(item)"
+        >
+          {{ item.name }}
+          <el-badge v-if="item.msgCount > 0" :max="99" :value="item.msgCount" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :span="20" :xs="24">
+      <TodayCustomer v-if="leftType === 'todayCustomer'" />
+      <FollowLeads v-if="leftType === 'followLeads'" />
+    </el-col>
+  </el-row>
+</template>
+
+<script lang="ts" setup>
+import TodayCustomer from './tables/TodayCustomer.vue'
+import FollowLeads from './tables/FollowLeads.vue'
+
+const leftType = ref('todayCustomer')
+const leftSides = ref([
+  {
+    name: '今日需联系客户',
+    infoType: 'todayCustomer',
+    msgCount: 1,
+    tips: '下次跟进时间为今日的客户'
+  },
+  {
+    name: '分配给我的线索',
+    infoType: 'followLeads',
+    msgCount: 0,
+    tips: '转移之后未跟进的线索'
+  },
+  {
+    name: '分配给我的客户',
+    infoType: 'followCustomer',
+    msgCount: 0,
+    tips: '转移、领取、分配之后未跟进的客户,默认显示自己负责的客户'
+  },
+  {
+    name: '待进入公海的客户',
+    infoType: 'putInPoolRemind',
+    msgCount: 0,
+    tips: ''
+  },
+  {
+    name: '待审核合同',
+    infoType: 'checkContract',
+    msgCount: 0,
+    tips: ''
+  },
+  {
+    name: '待审核回款',
+    crmType: 'receivables',
+    infoType: 'checkReceivables',
+    msgCount: 0,
+    tips: ''
+  },
+  {
+    name: '待回款提醒',
+    infoType: 'remindReceivablesPlan',
+    msgCount: 4,
+    tips: ''
+  },
+  {
+    name: '即将到期的合同',
+    infoType: 'endContract',
+    msgCount: 20,
+    tips: '根据“合同到期时间”及设置的“提前提醒天数”提醒'
+  }
+])
+
+/**
+ * 侧边点击
+ */
+const sideClick = (item) => {
+  leftType.value = item.infoType
+}
+</script>
+
+<style lang="scss" scoped>
+.side-item-list {
+  top: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1;
+  font-size: 14px;
+  background-color: white;
+  border: 1px solid #e6e6e6;
+  border-radius: 5px;
+
+  .side-item {
+    position: relative;
+    height: 50px;
+    padding: 0 20px;
+    line-height: 50px;
+    cursor: pointer;
+
+    i {
+      color: #999;
+    }
+  }
+}
+
+.side-item-default {
+  color: #333;
+  border-right: 2px solid transparent;
+}
+
+.side-item-select {
+  color: #409eff;
+  background-color: #ecf5ff;
+  border-right: 2px solid var(--el-color-primary);
+}
+
+.el-badge :deep(.el-badge__content) {
+  top: 0;
+  border: none;
+}
+
+.el-badge {
+  position: absolute;
+  top: 0;
+  right: 15px;
+}
+</style>
diff --git a/src/views/crm/message/tables/FollowLeads.vue b/src/views/crm/message/tables/FollowLeads.vue
new file mode 100644
index 00000000..c94199fb
--- /dev/null
+++ b/src/views/crm/message/tables/FollowLeads.vue
@@ -0,0 +1,14 @@
+<!-- 分配给我的线索 -->
+<template>
+  <div>
+    TODO: 分配给我的线索
+  </div>
+</template>
+
+<script setup lang="ts" name="FollowLeads">
+
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/crm/message/tables/TodayCustomer.vue b/src/views/crm/message/tables/TodayCustomer.vue
new file mode 100644
index 00000000..df70e599
--- /dev/null
+++ b/src/views/crm/message/tables/TodayCustomer.vue
@@ -0,0 +1,201 @@
+<template>
+  <ContentWrap>
+    <div class="pb-5 text-xl">
+      {{ title }}
+    </div>
+    <!-- 搜索工作栏 -->
+    <el-form
+      ref="queryFormRef"
+      :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
+      label-width="68px"
+    >
+      <el-form-item label="状态" prop="contactStatus">
+        <el-select v-model="queryParams.contactStatus" class="!w-240px" placeholder="状态">
+          <el-option
+            v-for="(option, index) in CONTACT_STATUS"
+            :label="option.label"
+            :value="option.value"
+            :key="index"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="归属" prop="sceneType">
+        <el-select v-model="queryParams.sceneType" class="!w-240px" placeholder="归属">
+          <el-option
+            v-for="(option, index) in SCENE_TYPES"
+            :label="option.label"
+            :value="option.value"
+            :key="index"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery(undefined)">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
+      <el-table-column align="center" label="编号" prop="id" />
+      <el-table-column align="center" label="客户名称" prop="name" width="160">
+        <template #default="scope">
+          <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
+            {{ scope.row.name }}
+          </el-link>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="手机" prop="mobile" width="120" />
+      <el-table-column align="center" label="电话" prop="telephone" width="120" />
+      <el-table-column align="center" label="客户来源" prop="source" width="100">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="所属行业" prop="industryId" width="120">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="客户等级" prop="level" width="120">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" />
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="网址" prop="website" width="200" />
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="下次联系时间"
+        prop="contactNextTime"
+        width="180px"
+      />
+      <el-table-column align="center" label="备注" prop="remark" width="200" />
+      <el-table-column align="center" label="成交状态" prop="dealStatus">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
+        </template>
+      </el-table-column>
+      <!-- TODO @puhui999:距进入公海天数 -->
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="最后跟进时间"
+        prop="contactLastTime"
+        width="180px"
+      />
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="创建时间"
+        prop="updateTime"
+        width="180px"
+      />
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="创建时间"
+        prop="createTime"
+        width="180px"
+      />
+      <el-table-column align="center" label="负责人" prop="ownerUserName" width="100px" />
+      <el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
+      <el-table-column align="center" label="创建人" prop="creatorName" width="100px" />
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
+      @pagination="getList"
+    />
+  </ContentWrap>
+</template>
+
+<script lang="ts" setup name="TodayCustomer">
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+import * as MessageApi from '@/api/crm/message'
+
+const title = ref('今日需联系客户')
+const loading = ref(true) // 列表的加载中
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+const queryParams = ref<{
+  pageNo: number
+  pageSize: number
+  contactStatus: number | undefined
+  sceneType: number | undefined
+}>({
+  pageNo: 1,
+  pageSize: 10,
+  contactStatus: 1,
+  sceneType: 1
+})
+const queryFormRef = ref() // 搜索的表单
+
+const CONTACT_STATUS = [
+  { label: '今日需联系', value: 1 },
+  { label: '已逾期', value: 2 },
+  { label: '已联系', value: 3 }
+]
+
+const SCENE_TYPES = [
+  { label: '我负责的', value: 1 },
+  { label: '我跟进的', value: 2 },
+  { label: '我参与的', value: 3 },
+  { label: '下属负责的', value: 4 }
+]
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await MessageApi.getTodayCustomerPage(queryParams.value)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = (func: Function | undefined = undefined) => {
+  queryFormRef.value.resetFields()
+  queryParams.value = {
+    pageNo: 1,
+    pageSize: 10,
+    contactStatus: 1,
+    sceneType: 1
+  }
+  func && func()
+  handleQuery()
+}
+
+/** 打开客户详情 */
+const { push } = useRouter()
+const openDetail = (id: number) => {
+  push({ name: 'CrmCustomerDetail', params: { id } })
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style lang="scss"></style>