diff --git a/frontend/src/views/modules/MeetingPage.vue b/frontend/src/views/modules/MeetingPage.vue
index 4f45db0..9338aff 100644
--- a/frontend/src/views/modules/MeetingPage.vue
+++ b/frontend/src/views/modules/MeetingPage.vue
@@ -1,4 +1,4 @@
-锘?template>
+<template>
   <PageContainer title="浼氳绠＄悊">
     <MeetingQueryToolbar v-model:query-form="queryForm" @load="handleMeetingQueryLoad" @reset-query="resetQuery" />
     <MeetingListTable
@@ -111,6 +111,13 @@
       :handle-theme-photo-picture-change="handleThemePhotoPictureChange"
       :handle-theme-photo-picture-preview="handleThemePhotoPicturePreview"
       :handle-theme-photo-picture-remove="handleThemePhotoPictureRemove"
+      v-model:meeting-video-type="docForm.videoType"
+      v-model:meeting-video-link="docForm.videoLink"
+      :meeting-video-upload-file-list="meetingVideoUploadFileList"
+      :before-meeting-video-upload="beforeMeetingVideoUpload"
+      :handle-meeting-video-picture-change="handleMeetingVideoChange"
+      :handle-meeting-video-picture-remove="handleMeetingVideoRemove"
+      :meeting-form="resolveSelectedMeetingForm()"
       :invitation-upload-file-list="invitationUploadFileList"
       :before-invitation-upload="beforeInvitationUpload"
       :handle-invitation-picture-change="handleInvitationPictureChange"
@@ -944,6 +951,10 @@ const docForm = ref({
   themePhotoName: "",
   themePhotoOssKey: "",
   invitationLines: "",
+  videoType: "file" as "file" | "link",
+  videoName: "",
+  videoOssKey: "",
+  videoLink: "",
 });
 const expertProfileForm = ref({
   fileName: "",
@@ -968,6 +979,7 @@ const agendaFile = ref<File | null>(null);
 const signInFile = ref<File | null>(null);
 const themePhotoFile = ref<File | null>(null);
 const invitationFile = ref<File | null>(null);
+const meetingVideoFile = ref<File | null>(null);
 const photoAutoUploading = ref(false);
 const laborProtocolAutoUploading = ref(false);
 const laborInvoiceAutoUploading = ref(false);
@@ -1438,6 +1450,19 @@ const agendaUploadFileList = computed<UploadUserFile[]>(() =>
     } as UploadUserFile & { ossKey: string };
   }),
 );
+const meetingVideoUploadFileList = computed<UploadUserFile[]>(() => {
+  if (!docForm.value.videoOssKey) {
+    return [];
+  }
+  const name = displayDocName(docForm.value.videoName, docForm.value.videoOssKey, "浼氳瑙嗛");
+  return [{
+    name,
+    url: "",
+    status: "success",
+    uid: 2,
+    ossKey: docForm.value.videoOssKey,
+  } as UploadUserFile & { ossKey: string }];
+});
 const signInUploadFileList = computed<UploadUserFile[]>(() => {
   if (!docForm.value.signInOssKey) {
     return [];
@@ -4275,9 +4300,7 @@ const showPendingIssueSubmitBlockDialog = async (meetingId: number, pendingIssue
     }, "褰撳墠浼氳浠嶆湁椹冲洖椤规湭澶勭悊瀹屾垚锛屾殏涓嶈兘鎻愪氦瀹℃牳銆?),
     h("div", {
       style: "margin-top:8px;font-size:13px;line-height:1.7;color:#606266;",
-    }, firstOpenIssue
-      ? "璇峰厛鎸夐┏鍥炲師鍥犲畬鎴愪慨鏀癸紱鐘舵€佷负鈥滃凡淇敼锛屽緟瀹℃牳纭鈥濈殑闂锛岄渶瑕佺瓑寰呭鏍镐汉鍛樼‘璁ゅ悗鎵嶈兘鍐嶆鎻愪氦銆?
-      : "浠ヤ笅椹冲洖椤瑰凡淇敼浣嗕粛寰呭鏍镐汉鍛樼‘璁わ紝纭瀹屾垚鍓嶆殏涓嶈兘鍐嶆鎻愪氦銆?),
+    }, "璇峰厛鎸夐┏鍥炲師鍥犲畬鎴愪笅鏂瑰垪鍑虹殑闂淇敼鍚庯紝鍐嶅皾璇曟彁浜ゅ鏍搞€?),
     h("div", {
       style: "margin-top:16px;max-height:360px;overflow:auto;padding-right:6px;",
     }, groups.map((group) => h("div", {
@@ -4468,7 +4491,7 @@ const openDocPicturePreview = async (ossKey: string, fileNameHint = "") => {
 };
 const handleDocPicturePreview = async (
   uploadFile: Parameters<NonNullable<UploadProps["onPreview"]>>[0],
-  target: "agenda" | "signIn" | "themePhoto" | "invitation",
+  target: "agenda" | "signIn" | "themePhoto" | "invitation" | "meetingVideo",
 ) => {
   const row = uploadFile as UploadUserFile & { ossKey?: string };
   const fallbackOssKey = target === "agenda"
@@ -4666,6 +4689,50 @@ const validateExpertProfileFile = (file: File | null, maxSizeMb = MATERIAL_MAX_F
   }
   return true;
 };
+
+const validateVideoFile = (file: File | null, label: string, maxSizeMb = 500) => {
+  if (!file) {
+    return false;
+  }
+  const ext = extractExt(file.name || "");
+  const mime = String(file.type || "").toLowerCase();
+  const allowedExts = new Set([".mp4", ".mov", ".avi", ".mkv"]);
+  if (!allowedExts.has(ext) && !mime.startsWith("video/")) {
+    ElMessage.warning(`${label}浠呮敮鎸佽棰戞枃浠?mp4/mov/avi/mkv)`);
+    return false;
+  }
+  if (Number(file.size || 0) > maxSizeMb * 1024 * 1024) {
+    ElMessage.warning(`${label}澶у皬涓嶈兘瓒呰繃${maxSizeMb}MB`);
+    return false;
+  }
+  return true;
+};
+
+const beforeMeetingVideoUpload = (rawFile: any, maxSizeMb = 500) =>
+  validateVideoFile((rawFile as File) || null, "浼氳瑙嗛", maxSizeMb);
+
+const handleMeetingVideoChange = async (uploadFile: any, uploadFiles: any, maxSizeMb = 500) => {
+  if (isReviewApproved("meetingVideo")) {
+    warnReviewedMaterialLocked();
+    return;
+  }
+  const file = (uploadFile?.raw as File) || null;
+  meetingVideoFile.value = validateVideoFile(file, "浼氳瑙嗛", maxSizeMb) ? file : null;
+  if (!meetingVideoFile.value) {
+    return;
+  }
+  await uploadDocFile("meetingVideo");
+};
+
+const handleMeetingVideoRemove = () => {
+  if (isReviewApproved("meetingVideo")) {
+    warnReviewedMaterialLocked();
+    return false;
+  }
+  docForm.value.videoName = "";
+  docForm.value.videoOssKey = "";
+};
+
 const beforeAgendaUpload = (rawFile: any, maxSizeMb?: number) => {
   if (!validateMaterialFile((rawFile as File) || null, "浼氳鏃ョ▼", maxSizeMb)) {
     return false;
@@ -4891,7 +4958,7 @@ const handleLaborInvoiceFileRemove: UploadProps["onRemove"] = async (uploadFile)
   laborInvoiceUploadFiles.value = [];
 };
 
-const uploadDocFile = async (target: "agenda" | "signIn" | "themePhoto" | "invitation") => {
+const uploadDocFile = async (target: "agenda" | "signIn" | "themePhoto" | "invitation" | "meetingVideo") => {
   if (!selectedMeetingId.value) {
     return;
   }
@@ -4901,7 +4968,9 @@ const uploadDocFile = async (target: "agenda" | "signIn" | "themePhoto" | "invit
       ? signInFile.value
       : target === "themePhoto"
         ? themePhotoFile.value
-        : invitationFile.value;
+        : target === "meetingVideo"
+          ? meetingVideoFile.value
+          : invitationFile.value;
   if (!file) {
     ElMessage.warning("璇峰厛閫夋嫨鏂囦欢");
     return;
@@ -4930,6 +4999,10 @@ const uploadDocFile = async (target: "agenda" | "signIn" | "themePhoto" | "invit
     docForm.value.themePhotoName = file.name;
     docForm.value.themePhotoOssKey = objectKey;
     themePhotoFile.value = null;
+  } else if (target === "meetingVideo") {
+    docForm.value.videoName = file.name;
+    docForm.value.videoOssKey = objectKey;
+    meetingVideoFile.value = null;
   } else {
     const line = `${file.name}|${objectKey}`;
     docForm.value.invitationLines = docForm.value.invitationLines ? `${docForm.value.invitationLines}\n${line}` : line;
@@ -5463,7 +5536,7 @@ const resetMaterialForms = () => {
     improvementSuggestion: "",
     meetingEffect: "",
   };
-  docForm.value = { agendaLines: "", signInName: "", signInOssKey: "", themePhotoName: "", themePhotoOssKey: "", invitationLines: "" };
+  docForm.value = { agendaLines: "", signInName: "", signInOssKey: "", themePhotoName: "", themePhotoOssKey: "", invitationLines: "", videoType: "file", videoName: "", videoOssKey: "", videoLink: "" };
   expertProfileForm.value = { fileName: "", ossKey: "" };
   photoForm.value = { photoLines: "", summary: "" };
   photoSummaryByExpert.value = {};
@@ -5900,6 +5973,10 @@ const loadMaterialModule = async (
         docForm.value.signInOssKey = parsed.signInSheet?.ossKey || "";
         docForm.value.themePhotoName = resolveStoredDocFileName(parsed.themePhoto);
         docForm.value.themePhotoOssKey = parsed.themePhoto?.ossKey || "";
+        docForm.value.videoType = parsed.meetingVideo?.type || "file";
+        docForm.value.videoName = resolveStoredDocFileName(parsed.meetingVideo) || String(parsed.meetingVideo?.name || "");
+        docForm.value.videoOssKey = parsed.meetingVideo?.ossKey || "";
+        docForm.value.videoLink = parsed.meetingVideo?.link || "";
         expertProfileForm.value.fileName = resolveStoredDocFileName(parsed?.profileFile) || String(parsed?.fileName || "").trim();
         expertProfileForm.value.ossKey = String(parsed?.profileFile?.ossKey || parsed?.ossKey || "").trim();
         const invitationList = Array.isArray(parsed.invitation) ? parsed.invitation : [];
@@ -5913,6 +5990,10 @@ const loadMaterialModule = async (
         docForm.value.signInOssKey = parsed.signInSheet?.ossKey || "";
         docForm.value.themePhotoName = resolveStoredDocFileName(parsed.themePhoto);
         docForm.value.themePhotoOssKey = parsed.themePhoto?.ossKey || "";
+        docForm.value.videoType = parsed.meetingVideo?.type || "file";
+        docForm.value.videoName = resolveStoredDocFileName(parsed.meetingVideo) || String(parsed.meetingVideo?.name || "");
+        docForm.value.videoOssKey = parsed.meetingVideo?.ossKey || "";
+        docForm.value.videoLink = parsed.meetingVideo?.link || "";
         const invitationList = Array.isArray(parsed.invitation) ? parsed.invitation : [];
         docForm.value.invitationLines = invitationList
           .map((x: any) => `${resolveStoredDocFileName(x)}|${x?.ossKey || ""}`.trim())
@@ -6801,6 +6882,13 @@ const buildContentJson = () => {
         fileName: String(docForm.value.themePhotoName || "").trim(),
         ossKey: String(docForm.value.themePhotoOssKey || "").trim(),
       },
+      meetingVideo: {
+        type: docForm.value.videoType,
+        name: String(docForm.value.videoName || "").trim(),
+        fileName: String(docForm.value.videoName || "").trim(),
+        ossKey: String(docForm.value.videoOssKey || "").trim(),
+        link: String(docForm.value.videoLink || "").trim(),
+      },
       invitation: (docForm.value.invitationLines || "")
         .split("\n")
         .map((line) => line.trim())
@@ -6848,6 +6936,13 @@ const buildContentJson = () => {
         fileName: String(docForm.value.themePhotoName || "").trim(),
         ossKey: String(docForm.value.themePhotoOssKey || "").trim(),
       },
+      meetingVideo: {
+        type: docForm.value.videoType,
+        name: String(docForm.value.videoName || "").trim(),
+        fileName: String(docForm.value.videoName || "").trim(),
+        ossKey: String(docForm.value.videoOssKey || "").trim(),
+        link: String(docForm.value.videoLink || "").trim(),
+      },
       invitation: invitations,
       profileFile: {
         name: String(expertProfileForm.value.fileName || "").trim(),
