diff --git a/mock/deviceStatus.ts b/mock/deviceStatus.ts
index 8bbfac1..11f3a50 100644
--- a/mock/deviceStatus.ts
+++ b/mock/deviceStatus.ts
@@ -2,17 +2,17 @@
  * @Author: donghao donghao@supervision.ltd
  * @Date: 2025-03-07 14:57:20
  * @LastEditors: donghao donghao@supervision.ltd
- * @LastEditTime: 2025-03-07 15:10:10
+ * @LastEditTime: 2025-03-13 14:34:44
  * @FilePath: \5G-Loading-Bay-Web\mock\deviceStatus.ts
  * @Description: 设备状态
  */
 import { MockMethod } from "vite-plugin-mock";
-import { deviceStatusListData } from "./pools/deviceStatusData";
-import { fetchCurrPageByList } from "./utils/apiMock";
+import { deviceStatusListData, deviceHistoryListData } from "./pools/deviceStatusData";
+import { fetchCurrPageByList, fetchMockSuccessFullByOther } from "./utils/apiMock";
 
 export default [
   {
-    url: "/api/getDeviceStatusList",
+    url: "/api/v1/device/device/",
     method: "post",
     response: req => {
       const { page, pageSize } = req.body;
@@ -28,5 +28,14 @@ export default [
         })
       };
     }
+  },
+  {
+    url: "/api/v1/device/device_history/",
+    method: "post",
+    response: req => {
+      const { page, pageSize } = req.body;
+      // console.log(req);
+      return  {...fetchMockSuccessFullByOther(deviceHistoryListData)}  
+    }
   }
 ] as MockMethod[];
\ No newline at end of file
diff --git a/mock/pools/deviceStatusData.ts b/mock/pools/deviceStatusData.ts
index d5b17cd..41a8366 100644
--- a/mock/pools/deviceStatusData.ts
+++ b/mock/pools/deviceStatusData.ts
@@ -2,7 +2,7 @@
  * @Author: donghao donghao@supervision.ltd
  * @Date: 2024-02-22 13:38:04
  * @LastEditors: donghao donghao@supervision.ltd
- * @LastEditTime: 2025-03-07 15:07:28
+ * @LastEditTime: 2025-03-13 14:35:20
  * @FilePath: \General-AI-Platform-Web-Client\mock\pools\deviceStatusData.ts
  * @Description: 设备状态数据
  */
@@ -46,13 +46,130 @@ function fetchList(): Record<string, any>[] {
 // 告警代码MSRF-0 RL0F HTFIF-02 TLOC-1 E1AIS-05
 // 设备组:核心检测组001 无尘总装组005 送料监测线02
 
+const mockHistroyData = [
+  {
+      id: 10,
+      key: "10",
+      video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
+      created_at: "2025-03-12 14:53:36",
+      device: 1
+  },
+  {
+      id: 11,
+      key: "11",
+      video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
+      created_at: "2025-03-12 15:20:15",
+      device: 1
+  },
+  {
+      id: 12,
+      key: "12",
+      video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
+      created_at: "2025-03-13 09:45:22",
+      device: 1
+  },
+  {
+      id: 20,
+      key: "10",
+      video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
+      created_at: "2025-03-12 14:53:36",
+      device: 1
+  },
+  {
+      id: 21,
+      key: "11",
+      video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
+      created_at: "2025-03-12 15:20:15",
+      device: 1
+  },
+  {
+      id: 22,
+      key: "12",
+      video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
+      created_at: "2025-03-13 09:45:22",
+      device: 1
+  },
+  // {
+  //     id: 10,
+  //     key: "10",
+  //     video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
+  //     created_at: "2025-03-12 14:53:36",
+  //     device: 1
+  // },
+  // {
+  //     id: 11,
+  //     key: "11",
+  //     video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
+  //     created_at: "2025-03-12 15:20:15",
+  //     device: 1
+  // },
+  // {
+  //     id: 12,
+  //     key: "12",
+  //     video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
+  //     created_at: "2025-03-13 09:45:22",
+  //     device: 1
+  // },
+  // {
+  //     id: 10,
+  //     key: "10",
+  //     video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
+  //     created_at: "2025-03-12 14:53:36",
+  //     device: 1
+  // },
+  // {
+  //     id: 11,
+  //     key: "11",
+  //     video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
+  //     created_at: "2025-03-12 15:20:15",
+  //     device: 1
+  // },
+  // {
+  //     id: 12,
+  //     key: "12",
+  //     video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
+  //     created_at: "2025-03-13 09:45:22",
+  //     device: 1
+  // },
+  // {
+  //     id: 10,
+  //     key: "10",
+  //     video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
+  //     created_at: "2025-03-12 14:53:36",
+  //     device: 1
+  // },
+  // {
+  //     id: 11,
+  //     key: "11",
+  //     video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
+  //     created_at: "2025-03-12 15:20:15",
+  //     device: 1
+  // },
+  // {
+  //     id: 12,
+  //     key: "12",
+  //     video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
+  //     created_at: "2025-03-13 09:45:22",
+  //     device: 1
+  // }
+];
+
+
 const currentData = fetchList();
+const currentHistroyData = mockHistroyData;
 
+// 
 export const deviceStatusListData = {
   data: {
-    list: currentData,
+    data: currentData,
     total: currentData.length,
-    page: 1,
+    current: 1,
     pageSize: 10
   }
 };
+
+export const deviceHistoryListData = {
+  data: currentHistroyData
+}
+
+
diff --git a/mock/utils/apiMock.ts b/mock/utils/apiMock.ts
index 8445850..9e4d0ea 100644
--- a/mock/utils/apiMock.ts
+++ b/mock/utils/apiMock.ts
@@ -1,39 +1,47 @@
+/*
+ * @Author: donghao donghao@supervision.ltd
+ * @Date: 2025-03-07 14:58:39
+ * @LastEditors: donghao donghao@supervision.ltd
+ * @LastEditTime: 2025-03-13 14:29:26
+ * @FilePath: \5G-Loading-Bay-Web\mock\utils\apiMock.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
 import { failMockApiProps, successMockApiProps } from "../typing";
 export function fetchMockSuccessFullByOther({
   data,
-  msg
+  msg,
 }): successMockApiProps {
   // return {
-  //   code: 0, // 0 成功
+  //   code: 200, // 200 成功
   //   success: true, // true 成功
   //   data: data || null, // mock业务层数据
   //   msg: msg | "ok", // 成功提示
   //   isMock: true // true 标识当前是模拟数据
   // } as successMockApiProps;
   const result: successMockApiProps = {
-    code: 0, // 0 成功
+    code: 200, // 200 成功
     success: true, // true 成功
     data: data || null, // mock业务层数据
     msg: msg as string | "ok", // 成功提示
-    isMock: true // true 标识当前是模拟数据
+    isMock: true, // true 标识当前是模拟数据
   };
   return result;
 }
 
 export function fetchMockFailFullByOther({ data, msg }): failMockApiProps {
   // return {
-  //   code: 599, // 0 成功
+  //   code: 599, // 200 成功
   //   success: true, // true 成功
   //   data: data || null, // mock业务层数据
   //   msg: msg | "fail", // 成功提示
   //   isMock: true // true 标识当前是模拟数据
   // } as failMockApiProps;
   const result: failMockApiProps = {
-    code: 599, // 0 成功
+    code: 599, // 200 成功
     success: false, // true 成功
     data: data || null, // mock业务层数据
     msg: msg as string | "fail", // 成功提示
-    isMock: true // true 标识当前是模拟数据
+    isMock: true, // true 标识当前是模拟数据
   };
   return result;
 }
@@ -41,11 +49,11 @@ export function fetchMockFailFullByOther({ data, msg }): failMockApiProps {
 // 分页展示
 export function fetchCurrPageByList({ data }): successMockApiProps {
   // console.log("fetchCurrPageByList_data", data);
-  const { page, pageSize } = data;
-  const prevPage = page - 1;
+  const { current, pageSize } = data;
+  const prevPage = current - 1;
   const currPageData = {
     ...data,
-    list: data.list.slice(prevPage * pageSize, page * pageSize)
+    data: data.data.slice(prevPage * pageSize, current * pageSize),
   };
   return fetchMockSuccessFullByOther({ data: currPageData });
 }
diff --git a/package.json b/package.json
index d4223f4..d0cdd6b 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
   "dependencies": {
     "axios": "^1.8.3",
     "echarts": "^5.6.0",
+    "moment": "^2.30.1",
     "postcss-scss": "^4.0.9",
     "sass": "^1.85.1",
     "swiper": "^11.2.5",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 44631d0..7cfe04c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,6 +14,9 @@ importers:
       echarts:
         specifier: ^5.6.0
         version: 5.6.0
+      moment:
+        specifier: ^2.30.1
+        version: 2.30.1
       postcss-scss:
         specifier: ^4.0.9
         version: 4.0.9(postcss@8.5.3)
@@ -1455,6 +1458,9 @@ packages:
     resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==}
     hasBin: true
 
+  moment@2.30.1:
+    resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
+
   mpd-parser@1.3.1:
     resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==}
     hasBin: true
@@ -3224,6 +3230,8 @@ snapshots:
     dependencies:
       commander: 13.1.0
 
+  moment@2.30.1: {}
+
   mpd-parser@1.3.1:
     dependencies:
       '@babel/runtime': 7.26.10
diff --git a/src/assets/common/pause_icon.png b/src/assets/common/pause_icon.png
new file mode 100644
index 0000000..f7acae2
Binary files /dev/null and b/src/assets/common/pause_icon.png differ
diff --git a/src/components/videoPlayer/Player.vue b/src/components/videoPlayer/Player.vue
index b6433c6..821d18a 100644
--- a/src/components/videoPlayer/Player.vue
+++ b/src/components/videoPlayer/Player.vue
@@ -2,10 +2,178 @@
  * @Author: donghao donghao@supervision.ltd
  * @Date: 2025-03-12 13:48:31
  * @LastEditors: donghao donghao@supervision.ltd
- * @LastEditTime: 2025-03-12 13:56:15
+ * @LastEditTime: 2025-03-13 15:01:16
  * @FilePath: \5G-Loading-Bay-Web\src\components\videoPlayer\player.vue
  * @Description: 视频播放器
 -->
 <template>
     <!-- 视频播放器 -->
-</template>
\ No newline at end of file
+    <div class="video-player-box">
+        <video ref="videoRef" class="video-element" controls @timeupdate="handleTimeUpdate"
+            @loadedmetadata="handleLoadedMetadata" @play="handlePlay" @pause="handlePause" @waiting="handleWaiting"
+            @canplay="handleCanPlay" style="object-fit: fill;">
+            <source :src="src" type="video/mp4">
+            您的浏览器不支持视频播放
+        </video>
+        <!-- 加载状态提示 -->
+        <div v-if="loading" class="loading-overlay">
+            <el-icon class="is-loading">
+                <Loading />
+            </el-icon>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch, onMounted, onUnmounted } from 'vue'
+import { ElIcon } from 'element-plus'
+import { Loading } from '@element-plus/icons-vue'
+
+type ProgressData = {
+    currentTime: number
+    duration: number
+    progress: number
+}
+
+const props = defineProps({
+    src: {
+        type: String,
+        required: true
+    },
+    isPlaying: {
+        type: Boolean,
+        default: false
+    }
+})
+
+const emit = defineEmits<{
+    (e: 'update:progress', data: ProgressData): void
+    (e: 'update:duration', duration: number): void
+    (e: 'play'): void
+    (e: 'pause'): void
+}>()
+
+const videoRef = ref<HTMLVideoElement | null>(null)
+const loading = ref(false)
+let currentDuration = 0
+
+// 监听播放状态变化
+watch(() => props.isPlaying, (newVal) => {
+    if (!videoRef.value) return
+    newVal ? videoRef.value.play() : videoRef.value.pause()
+})
+
+// 监听视频源变化
+watch(() => props.src, (newVal) => {
+    if (!videoRef.value) return
+    videoRef.value.pause()
+    videoRef.value.src = newVal
+    videoRef.value.load()
+    if (props.isPlaying) {
+        videoRef.value.play()
+    }
+})
+
+// 进度更新处理
+const handleTimeUpdate = () => {
+    if (!videoRef.value) return
+
+    const currentTime = videoRef.value.currentTime
+    const progress = currentDuration > 0
+        ? (currentTime / currentDuration) * 100
+        : 0
+
+    emit('update:progress', {
+        currentTime,
+        duration: currentDuration,
+        progress
+    })
+}
+
+// 元数据加载完成
+const handleLoadedMetadata = () => {
+    if (!videoRef.value) return
+    currentDuration = videoRef.value.duration
+    emit('update:duration', currentDuration)
+}
+
+// 播放状态处理
+const handlePlay = () => emit('play')
+const handlePause = () => emit('pause')
+
+// 加载状态处理
+const handleWaiting = () => loading.value = true
+const handleCanPlay = () => loading.value = false
+
+
+onMounted(() => {
+    if (videoRef.value) {
+        videoRef.value.src = props.src
+    }
+})
+
+onUnmounted(() => {
+    if (videoRef.value) {
+        videoRef.value.pause()
+        videoRef.value.removeAttribute('src')
+        videoRef.value.load()
+    }
+})
+
+// 暴露控制方法
+defineExpose({
+    play: () => videoRef.value?.play(),
+    pause: () => videoRef.value?.pause(),
+    seek: (time: number) => {
+        if (videoRef.value) {
+            videoRef.value.currentTime = time
+        }
+    }
+})
+
+
+</script>
+
+
+
+<style lang="scss">
+.video-player-box {
+    position: relative;
+    width: 100%;
+    margin: 0 auto;
+
+    .video-element {
+        width: 100%;
+        height: auto;
+        border-radius: 8px;
+    }
+
+    .loading-overlay {
+        position: absolute;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        background: rgba(0, 0, 0, 0.5);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        color: white;
+    }
+
+    .el-icon.is-loading {
+        font-size: 32px;
+        animation: rotating 2s linear infinite;
+    }
+
+    @keyframes rotating {
+        from {
+            transform: rotate(0deg);
+        }
+
+        to {
+            transform: rotate(360deg);
+        }
+    }
+}
+</style>
diff --git a/src/utils/array.ts b/src/utils/array.ts
new file mode 100644
index 0000000..34014af
--- /dev/null
+++ b/src/utils/array.ts
@@ -0,0 +1,32 @@
+/*
+ * @Author: donghao donghao@supervision.ltd
+ * @Date: 2025-03-13 16:12:49
+ * @LastEditors: donghao donghao@supervision.ltd
+ * @LastEditTime: 2025-03-13 16:25:52
+ * @FilePath: \5G-Loading-Bay-Web\src\utils\array.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import moment from 'moment';
+
+export function extractUniqueDatesWithMoment(data: { created_at: string }[]): string[] {
+    const dateSet = new Set<string>();
+    data.forEach(item => {
+        // 使用 moment 解析 created_at 字段并格式化为 YYYY-MM-DD
+        const formattedDate = moment(item.created_at).format('YYYY-MM-DD');
+        dateSet.add(formattedDate);
+    });
+    return Array.from(dateSet);
+}
+
+
+export function filterDataByDate(data: { created_at: string }[], targetDate: string): { created_at: string }[] {
+    // 补全开始时间为目标日期的 0 点
+    const startTime = moment(targetDate).startOf('day').format('YYYY-MM-DD HH:mm:ss');
+    // 补全结束时间为目标日期的 23:59:59
+    const endTime = moment(targetDate).endOf('day').format('YYYY-MM-DD HH:mm:ss');
+
+    return data.filter(item => {
+        const createdAt = moment(item.created_at);
+        return createdAt.isBetween(startTime, endTime, null, '[]');
+    });
+}
\ No newline at end of file
diff --git a/src/utils/request/instance.ts b/src/utils/request/instance.ts
index 4de71a8..3732b0a 100644
--- a/src/utils/request/instance.ts
+++ b/src/utils/request/instance.ts
@@ -1,3 +1,11 @@
+/*
+ * @Author: donghao donghao@supervision.ltd
+ * @Date: 2025-03-12 15:12:58
+ * @LastEditors: donghao donghao@supervision.ltd
+ * @LastEditTime: 2025-03-13 13:42:24
+ * @FilePath: \5G-Loading-Bay-Web\src\utils\request\instance.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
 import Request from './index'
 import { config } from '@/config'
 import { ElLoading } from "element-plus";
@@ -20,7 +28,7 @@ const request = new Request({
       }
 
       // 全局 loading 配置
-      if (config.showLoading !== false) {
+      if (config.showLoading) {
         const loading = ElLoading.service({
           lock: true,
           text: '加载中...',
diff --git a/src/views/dashboard/DeviceStatus.vue b/src/views/dashboard/DeviceStatus.vue
index 20bfa5b..481d302 100644
--- a/src/views/dashboard/DeviceStatus.vue
+++ b/src/views/dashboard/DeviceStatus.vue
@@ -44,7 +44,8 @@
             </div>
         </div>
         <RealVideoModal v-model:value="isRealOpen" :info="currentRow" @close="isRealOpen = false" />
-        <HistoryVideoModal />
+        <HistoryVideoModal ref="historyModalRef" v-model:value="isHistoryOpen" :info="currentRow"
+            :historyVideos="historyVideos" @close="isHistoryOpen = false" />
     </div>
 </template>
 
@@ -59,6 +60,7 @@ import outLineIcon from '@/assets/common/outline_icon.png';
 import errorIcon from '@/assets/common/error_icon.png';
 import { getDeviceStatusApi } from '@/api/dashboard';
 import { isSuccessApi } from "@/utils/forApi";
+import { nextTick } from "vue";
 defineOptions({
     name: "DeviceStatusIndex"
 });
@@ -99,6 +101,8 @@ const alarmLevelStatusEnum = {
 const currentRow = ref<Record<string, any>>({});
 const isRealOpen = ref<Boolean>(false); // 实时视频弹窗
 const isHistoryOpen = ref<Boolean>(false); // 历史视频弹窗
+const historyVideos = ref<Record<string, any>[]>([]); //历史视频数据
+const historyModalRef = ref(null);
 
 const columns = [
     {
@@ -120,8 +124,6 @@ const columns = [
             console.log(val);
             const currentLevelObj =
                 alarmLevelStatusEnum[val?.device_status] || alarmLevelStatusEnum.notFound;
-
-
             return h(
                 "div",
                 {
@@ -153,7 +155,6 @@ const columns = [
             );
         }
     },
-    // TODO 需要封装操作按钮
     {
         type: "action",
         label: "操作"
@@ -197,12 +198,33 @@ function openCurrent(row) {
 
 }
 /**打开历史视频 */
+// TODO mock 获取视频列表数据
+const fetchHistoryList = async () => {
+    try {
+        const resAll = await fetch('/api/v1/device/device_history/', {
+            method: 'POST'
+        })
+        const res = await resAll.json()
+        if (isSuccessApi(res)) {
+            historyVideos.value = res.data;
+            isHistoryOpen.value = true;
+            nextTick(() => {
+                historyModalRef.value.loadData()
+            })
+            console.log(res, 'fetchHistoryList_data')
+
+        }
+    } catch (error) {
+        console.error('获取数据失败:', error)
+    }
+}
+
 function openHistory(row) {
     console.log(row, "openHistory");
     currentRow.value = row;
-    // TODO 历史视频模块
-    isHistoryOpen.value = true;
+    fetchHistoryList();
 }
+
 onMounted(() => {
     getList();
 });
diff --git a/src/views/dashboard/components/HistoryVideoModal.vue b/src/views/dashboard/components/HistoryVideoModal.vue
index 4936ee6..13b380d 100644
--- a/src/views/dashboard/components/HistoryVideoModal.vue
+++ b/src/views/dashboard/components/HistoryVideoModal.vue
@@ -1,12 +1,260 @@
 <template>
-    <div class="historyVideoModal-wrap">
-       
-    </div>
-
+    <el-dialog class="historyVideoModal-wrap" v-model="show" @close="handleClose">
+        <!-- 自定义标题栏 -->
+        <template #header="{ close, titleId, titleClass }">
+            <div class="flex items-center justify-between video-dialog-header">
+                <div class="flex items-center justify-center header-left">
+                    <div class="header-icon mr-[12px]"></div>
+                    <p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">{{
+                        info.device_name }}</p>
+                </div>
+            </div>
+        </template>
+        <div class="flex main-content">
+            <!-- 播放器 -->
+            <Player :src="currentVideo.video_url" :is-playing="isPlaying" @update:progress="handleProgress"
+                @update:duration="handleDuration" @play="isPlaying = true" @pause="isPlaying = false" />
+            <div class="flex video-record-list">
+                <!-- 日期筛选 -->
+                <div class="flex pl-[16px] pr-[24px] items-center">
+                    <span>时间:</span>
+                    <el-select v-model="selectedDate" placeholder="请选择" class="custom-select record_date_select"
+                        clearable @change="handleDateChange" @clear="handleClear">
+                        <el-option v-for="(item, index) in dateList" :key="item" :label="item"
+                            :value="item"></el-option>
+                    </el-select>
+                    <!-- <el-date-picker v-model="selectedDate" type="date" placeholder="选择日期"
+                        @change="handleDateChange"></el-date-picker> -->
+                </div>
+                <!-- 记录列表 -->
+                <el-scrollbar style="height: calc(100% - 80px)">
+                    <ul class="record-list-box">
+                        <li v-for="(item, index) in recordList" :key="item.id"
+                            :class="{ active: currentVideo?.id === item.id }" @click="handleItemClick(item)"
+                            class="flex items-center justify-between">
+                            <span class="time">{{ item.created_at }}</span>
+                            <div :class="{ 'play-btn': true, 'playing': isPlaying && currentVideo?.id === item.id }">
+                            </div>
+                        </li>
+                    </ul>
+                </el-scrollbar>
+            </div>
+        </div>
+    </el-dialog>
 </template>
 
+<script lang="ts" setup>
+import Player from '@/components/videoPlayer/Player.vue'
+import { ElMessage } from 'element-plus';
+import { extractUniqueDatesWithMoment, filterDataByDate } from '@/utils/array';
+interface Props {
+    /** 弹窗显隐 */
+    value: boolean;
+    info: Record<string, any>;
+    historyVideos: Record<string, any>[];
+}
+interface Emits {
+    (e: "update:value", val: boolean): void;
+}
+const props = withDefaults(defineProps<Props>(), {
+    value: false,
+    info: {},
+    historyVideos: []
+});
+
+const emit = defineEmits<Emits>();
+
+// 组件状态
+const dateList = ref<string[]>([]);
+const selectedDate = ref(); // 默认今天
+const recordList = ref([]);
+const currentVideo = ref<Record<string, any>>({})
+const isPlaying = ref(false);
+
+const togglePlay = () => {
+    isPlaying.value = !isPlaying.value;
+};
+
+// TODO 监听进度更新 暂未使用
+const handleProgress = (data: { currentTime: number, duration: number }) => {
+    console.log((data.currentTime / data.duration) * 100, "handleProgress")
+    const progressVal = (data.currentTime / data.duration) * 100
+}
+
+// TODO 处理时长更新 暂未使用
+const handleDuration = (newDuration: number) => {
+    //   duration.value = newDuration
+}
+// 加载数据
+const loadData = () => {
+    recordList.value = props.historyVideos
+    dateList.value = extractUniqueDatesWithMoment(recordList.value);
+    currentVideo.value = props.historyVideos[0]; // 切换日期时重置选中
+};
+
+// 日期选择变化
+const handleDateChange = (date) => {
+    console.log(date, "handleDateChange_date");
+    if (date) {
+        selectedDate.value = date;
+        recordList.value = filterDataByDate(toRaw(props.historyVideos), date);
+        currentVideo.value = recordList.value[0]; // 切换日期时重置选中
+    } else {
+        loadData()
+    }
+};
+// 点击列表项
+const handleItemClick = (item) => {
+    if (currentVideo.value?.id === item.id) {
+        togglePlay()  // 播放 暂停
+    } else {
+        currentVideo.value = item;
+    }
+
+};
+
+// 视频播放结束
+const handleVideoEnd = () => {
+    // currentIndex.value = -1;
+};
+
+// 时间格式化
+const formatTime = (timeStr) => {
+    return timeStr.split(' ')[1].substring(0, 5); // 只显示时分
+};
+
+
+// 处理对话框关闭事件
+const handleClose = () => {
+    emits('close');
+};
+
+const show = computed({
+    get() {
+        return props.value;
+    },
+    set(val: boolean) {
+        emit("update:value", val);
+    }
+});
+// TODO 后续再做自动播放
+defineExpose({ loadData })
+</script>
+
+<style lang="scss">
+.historyVideoModal-wrap.el-dialog {
+    border: none;
+    overflow: hidden;
+    box-shadow: none;
+    background-color: transparent;
+    background-image: url("@/assets/common/bg_player_dialog.png");
+    background-size: contain;
+    background-position: center;
+    background-repeat: no-repeat;
+    width: 1100px;
+    height: 612px;
+    padding: 0;
+    margin-top: calc(50vh - 316px);
+
+    .el-dialog__header.show-close {
+        padding: 0;
+    }
+
+    .el-dialog__close {
+        width: 56px;
+        height: 56px;
+        color: white;
+        font-size: 18px;
+        padding-top: 4px;
+        padding-right: 20px;
+    }
+
+    .video-dialog-header {
+        color: white;
+        padding: 0;
+        padding-top: 4px;
+
+        .header-left {
+            padding: 0 18px;
+            font-weight: bold;
+            font-size: 18px;
+
+            .header-icon {
+                margin-top: 8px;
+                width: 48px;
+                height: 48px;
+                background-image: url("@/assets/common/dialog_title_icon.png");
+                background-size: contain;
+                background-position: center;
+                background-repeat: no-repeat;
+            }
+        }
+    }
+
+    .main-content {
+        padding-left: 24px;
+        padding-top: 24px;
+
+        // background: red;
+        .video-player-box {
+            border-radius: 0px 0px 4px 4px;
+            overflow: hidden;
+            width: 752px;
+            height: 502px;
+        }
+
+        .video-record-list {
+            flex-direction: column;
+            flex: 1;
+            color: white;
+
+            .record_date_select {
+                width: 100%;
+                display: flex;
+                flex: 1;
+
+                .el-select__wrapper {
+                    width: 100%;
+                }
+            }
+            .record-list-box {
+                margin-top: 5px;
+
+                li {
+                    color: white;
+                    height: 32px;
+                    cursor: pointer;
+                    padding-left: 16px;
+                    padding-right: 24px;
+
+                    &.active,
+                    &:hover {
+                        background: linear-gradient(90deg, rgba(30, 54, 88, 0) 0%, #0C4FAD 53%, rgba(65, 117, 190, 0) 100%);
+                        color: #37DBFF;
+                    }
+
+                    .time {
+                        flex: 1;
+                        font-size: 14px;
+                    }
+
+                    .play-btn {
+                        width: 18px;
+                        height: 18px;
+                        background: url("@/assets/common/player_icon.png") no-repeat center center;
+                        background-size: contain;
+                    }
+
+                    .playing {
+                        background: url("@/assets/common/pause_icon.png") no-repeat center center;
+                        background-size: contain;
+                    }
+                }
+            }
+        }
 
 
-<style lang="scss" scoped>
 
+    }
+}
 </style>
\ No newline at end of file
diff --git a/src/views/dashboard/components/RealVideoModal.vue b/src/views/dashboard/components/RealVideoModal.vue
index 765b062..bb7ac70 100644
--- a/src/views/dashboard/components/RealVideoModal.vue
+++ b/src/views/dashboard/components/RealVideoModal.vue
@@ -1,11 +1,12 @@
 <template>
-    <el-dialog v-model="show" @close="handleClose">
+    <el-dialog class="realVideoModal-wrap" v-model="show" @close="handleClose">
         <!-- 自定义标题栏 -->
         <template #header="{ close, titleId, titleClass }">
             <div class="flex items-center justify-between video-dialog-header">
                 <div class="flex items-center justify-center header-left">
                     <div class="header-icon mr-[12px]"></div>
-                    <span>{{ info.name }}</span>
+                    <p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">{{
+                        info.device_name }}</p>
                 </div>
             </div>
         </template>
@@ -28,14 +29,6 @@ interface Props {
 interface Emits {
     (e: "update:value", val: boolean): void;
 }
-
-// const props = withDefaults(defineProps<{
-//     isOpen: boolean;
-//     info: Record<string, any>;
-// }>(), {
-//     isOpen: false,
-//     info: {}
-// });
 const props = withDefaults(defineProps<Props>(), {
     value: false,
     info: {}
@@ -66,7 +59,7 @@ const show = computed({
 </script>
 
 <style lang="scss">
-.el-dialog {
+.realVideoModal-wrap.el-dialog {
     border: none;
     overflow: hidden;
     box-shadow: none;
@@ -78,6 +71,7 @@ const show = computed({
     width: 805px;
     height: 612px;
     padding: 0;
+    margin-top: calc(50vh - 316px);
 
     .el-dialog__header.show-close {
         padding: 0;
@@ -98,7 +92,7 @@ const show = computed({
         padding-top: 4px;
 
         .header-left {
-            padding: 0 20px;
+            padding: 0 18px;
             font-weight: bold;
             font-size: 18px;
 
diff --git a/src/views/login/Login.vue b/src/views/login/Login.vue
index 23ac45d..81d2a7d 100644
--- a/src/views/login/Login.vue
+++ b/src/views/login/Login.vue
@@ -2,7 +2,7 @@
  * @Author: donghao donghao@supervision.ltd
  * @Date: 2025-03-06 17:57:05
  * @LastEditors: donghao donghao@supervision.ltd
- * @LastEditTime: 2025-03-13 10:50:03
+ * @LastEditTime: 2025-03-13 16:55:26
  * @FilePath: \5G-Loading-Bay-Web\src\views\login\Login.vue
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE?
 -->
@@ -58,8 +58,8 @@ const router = useRouter()
 const userStore = useUserStore()
 
 const form = reactive({
-    username: 'admin',
-    password: 'admin',
+    username: '',
+    password: '',
     remember: false
 })
 const handleLogin = async () => {