From 91c0cd2e0220472f9866479b218be72924b2aefa Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期一, 19 一月 2026 17:48:20 +0800
Subject: [PATCH] 会议审批,会议发布,会议总结模块

---
 src/pages/index.vue                                  |   27 
 src/pages.json                                       |   42 
 src/pages/managementMeetings/meetPublish/index.vue   |  348 ++++++
 src/pages/managementMeetings/meetSummary/approve.vue |  554 +++++++++++
 src/api/managementMeetings/meetExamine.js            |   47 
 package.json                                         |    5 
 src/pages/managementMeetings/meetExamine/approve.vue |  470 +++++++++
 src/pages/managementMeetings/meetSummary/index.vue   |  352 +++++++
 src/pages/managementMeetings/meetExamine/index.vue   |  352 +++++++
 src/pages/managementMeetings/meetPublish/approve.vue |  497 +++++++++
 src/components/Editor/index.vue                      |  261 +++++
 11 files changed, 2,953 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index ea878de..bf8f26d 100644
--- a/package.json
+++ b/package.json
@@ -79,7 +79,8 @@
     "tslib": "^2.7.0",
     "uview-plus": "^3.4.62",
     "vue": "3.4.21",
-    "vue-i18n": "^9.14.2"
+    "vue-i18n": "^9.14.2",
+    "@vueup/vue-quill": "^1.2.0"
   },
   "devDependencies": {
     "@dcloudio/types": "^3.4.14",
@@ -96,4 +97,4 @@
     "vite": "5.4.10",
     "vue-tsc": "2.1.6"
   }
-}
+}
\ No newline at end of file
diff --git a/src/api/managementMeetings/meetExamine.js b/src/api/managementMeetings/meetExamine.js
new file mode 100644
index 0000000..c40a905
--- /dev/null
+++ b/src/api/managementMeetings/meetExamine.js
@@ -0,0 +1,47 @@
+import request from '@/utils/request';
+
+export function getExamineList(data) {
+    return request({
+        url: "/meeting/applicationList",
+        method: "post",
+        data: data,
+    });
+}
+
+export function getRoomEnum() {
+    return request({
+        url: "/meeting/roomEnum",
+        method: "get",
+    });
+}
+
+export function saveMeetingApplication(data){
+    return request({
+        url: "/meeting/saveMeetingApplication",
+        method: "post",
+        data: data,
+    });
+}
+
+export function getMeetingPublish(data){
+    return request({
+        url: "/meeting/meetingPublishList",
+        method: "post",
+        data: data
+    });
+}
+
+export function getMeetingMinutesByMeetingId(id){
+    return request({
+        url: "/meeting/getMeetingMinutesByMeetingId/"+id,
+        method: "get",
+    });
+}
+
+export function saveMeetingMinutes(data){
+    return request({
+        url: "/meeting/saveMeetingMinutes",
+        method: "post",
+        data: data,
+    });
+}
diff --git a/src/components/Editor/index.vue b/src/components/Editor/index.vue
new file mode 100644
index 0000000..8b95790
--- /dev/null
+++ b/src/components/Editor/index.vue
@@ -0,0 +1,261 @@
+<template>
+  <view class="editor-container">
+    <div class="editor">
+      <QuillEditor v-model:content="content"
+                   contentType="html"
+                   @textChange="(e) => emit('update:modelValue', content)"
+                   :options="options"
+                   :style="styles" />
+    </div>
+  </view>
+</template>
+
+<script setup>
+  import { ref, computed, watch } from "vue";
+  import { QuillEditor } from "@vueup/vue-quill";
+  import "@vueup/vue-quill/dist/vue-quill.snow.css";
+  import { getToken } from "@/utils/auth";
+
+  const props = defineProps({
+    /* 缂栬緫鍣ㄧ殑鍐呭 */
+    modelValue: {
+      type: String,
+    },
+    /* 楂樺害 */
+    height: {
+      type: Number,
+      default: null,
+    },
+    /* 鏈�灏忛珮搴� */
+    minHeight: {
+      type: Number,
+      default: null,
+    },
+    /* 鍙 */
+    readOnly: {
+      type: Boolean,
+      default: false,
+    },
+    /* 涓婁紶鏂囦欢澶у皬闄愬埗(MB) */
+    fileSize: {
+      type: Number,
+      default: 5,
+    },
+    /* 绫诲瀷锛坆ase64鏍煎紡銆乽rl鏍煎紡锛� */
+    type: {
+      type: String,
+      default: "url",
+    },
+  });
+
+  const emit = defineEmits(["update:modelValue"]);
+
+  const styles = computed(() => {
+    let style = {};
+    if (props.minHeight) {
+      style.minHeight = `${props.minHeight}px`;
+    }
+    if (props.height) {
+      style.height = `${props.height}px`;
+    }
+    return style;
+  });
+
+  const content = ref("");
+
+  watch(
+    () => props.modelValue,
+    v => {
+      if (v !== content.value) {
+        content.value = v == undefined ? "<p></p>" : v;
+      }
+    },
+    { immediate: true }
+  );
+
+  const options = {
+    theme: "snow",
+    bounds: document.body,
+    debug: "warn",
+    modules: {
+      // 宸ュ叿鏍忛厤缃�
+      toolbar: [
+        [{ align: [] }], // 瀵归綈鏂瑰紡
+        ["bold", "italic", "underline", "strike"], // 鍔犵矖 鏂滀綋 涓嬪垝绾� 鍒犻櫎绾�
+        ["blockquote", "code-block"], // 寮曠敤  浠g爜鍧�
+        [{ list: "ordered" }, { list: "bullet" }], // 鏈夊簭銆佹棤搴忓垪琛�
+        [{ indent: "-1" }, { indent: "+1" }], // 缂╄繘
+        [{ size: ["small", false, "large", "huge"] }], // 瀛椾綋澶у皬
+        [{ header: [1, 2, 3, 4, 5, 6, false] }], // 鏍囬
+        [{ color: [] }, { background: [] }], // 瀛椾綋棰滆壊銆佸瓧浣撹儗鏅鑹�
+        ["clean"], // 娓呴櫎鏂囨湰鏍煎紡
+        ["link", "image", "video"], // 閾炬帴銆佸浘鐗囥�佽棰�
+      ],
+    },
+    placeholder: "璇疯緭鍏ュ唴瀹�",
+    readOnly: props.readOnly,
+  };
+</script>
+
+<style>
+  .editor-container {
+    width: 100%;
+  }
+
+  .editor-img-uploader {
+    display: none;
+  }
+
+  .editor {
+    width: 100%;
+  }
+
+  .quill-editor {
+    border: 1px solid #e8e8e8;
+    border-radius: 8px;
+    overflow: hidden;
+  }
+
+  /* Quill缂栬緫鍣ㄦ牱寮� */
+  :deep(.ql-toolbar.ql-snow) {
+    border-bottom: 1px solid #e8e8e8;
+    border-radius: 8px 8px 0 0;
+    padding: 8px 12px;
+  }
+
+  :deep(.ql-container.ql-snow) {
+    min-height: 300px;
+    border-radius: 0 0 8px 8px;
+  }
+
+  :deep(.ql-editor) {
+    min-height: 300px;
+    font-size: 14px;
+    line-height: 1.5;
+    padding: 12px;
+  }
+
+  /* 绉诲姩绔�傞厤 */
+  @media (max-width: 768px) {
+    :deep(.ql-toolbar.ql-snow) {
+      padding: 6px 8px;
+    }
+
+    :deep(.ql-editor) {
+      font-size: 13px;
+      padding: 10px;
+    }
+  }
+
+  /* 鍥剧墖鏍峰紡 */
+  :deep(.ql-editor img) {
+    max-width: 100%;
+    height: auto;
+    border-radius: 4px;
+    margin: 8px 0;
+  }
+
+  /* 宸ュ叿鏍忔寜閽牱寮� */
+  :deep(.ql-toolbar.ql-snow .ql-button) {
+    height: 28px;
+    width: 28px;
+    padding: 4px;
+  }
+
+  :deep(.ql-toolbar.ql-snow .ql-picker-label) {
+    height: 28px;
+    padding: 4px 8px;
+  }
+
+  /* 鎻愮ず妗嗘牱寮� */
+  :deep(.ql-snow .ql-tooltip[data-mode="link"])::before {
+    content: "璇疯緭鍏ラ摼鎺ュ湴鍧�:";
+  }
+
+  :deep(.ql-snow .ql-tooltip.ql-editing a.ql-action)::after {
+    border-right: 0px;
+    content: "淇濆瓨";
+    padding-right: 0px;
+  }
+
+  :deep(.ql-snow .ql-tooltip[data-mode="video"])::before {
+    content: "璇疯緭鍏ヨ棰戝湴鍧�:";
+  }
+
+  /* 瀛椾綋澶у皬閫夐」 */
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-label)::before,
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-item)::before {
+    content: "14px";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"])::before,
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"])::before {
+    content: "10px";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"])::before,
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"])::before {
+    content: "18px";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"])::before,
+  :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"])::before {
+    content: "32px";
+  }
+
+  /* 鏍囬閫夐」 */
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-label)::before,
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-item)::before {
+    content: "鏂囨湰";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"])::before,
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"])::before {
+    content: "鏍囬1";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"])::before,
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"])::before {
+    content: "鏍囬2";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"])::before,
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"])::before {
+    content: "鏍囬3";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"])::before,
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"])::before {
+    content: "鏍囬4";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"])::before,
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"])::before {
+    content: "鏍囬5";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"])::before,
+  :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"])::before {
+    content: "鏍囬6";
+  }
+
+  /* 瀛椾綋閫夐」 */
+  :deep(.ql-snow .ql-picker.ql-font .ql-picker-label)::before,
+  :deep(.ql-snow .ql-picker.ql-font .ql-picker-item)::before {
+    content: "鏍囧噯瀛椾綋";
+  }
+
+  :deep(.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"])::before,
+  :deep(.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"])::before {
+    content: "琛嚎瀛椾綋";
+  }
+
+  :deep(
+      .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]
+    )::before,
+  :deep(
+      .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]
+    )::before {
+    content: "绛夊瀛椾綋";
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages.json b/src/pages.json
index d384630..d171cc2 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -324,6 +324,48 @@
       }
     },
     {
+      "path": "pages/managementMeetings/meetExamine/index",
+      "style": {
+        "navigationBarTitleText": "浼氳瀹℃壒",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/managementMeetings/meetExamine/approve",
+      "style": {
+        "navigationBarTitleText": "瀹℃壒",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/managementMeetings/meetPublish/index",
+      "style": {
+        "navigationBarTitleText": "浼氳鍙戝竷",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/managementMeetings/meetPublish/approve",
+      "style": {
+        "navigationBarTitleText": "鍙戝竷",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/managementMeetings/meetSummary/index",
+      "style": {
+        "navigationBarTitleText": "浼氳鎬荤粨",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/managementMeetings/meetSummary/approve",
+      "style": {
+        "navigationBarTitleText": "鎬荤粨",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/cooperativeOffice/collaborativeApproval/detail",
       "style": {
         "navigationBarTitleText": "瀹℃壒娴佺▼",
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 8abfb9e..68d3ab0 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -315,6 +315,18 @@
       label: "浼氳鐢宠",
     },
     {
+      icon: "/static/images/icon/qingjiaguanli@2x.png",
+      label: "浼氳瀹℃壒",
+    },
+    {
+      icon: "/static/images/icon/qingjiaguanli@2x.png",
+      label: "浼氳鍙戝竷",
+    },
+    {
+      icon: "/static/images/icon/qingjiaguanli@2x.png",
+      label: "浼氳鎬荤粨",
+    },
+    {
       icon: "/static/images/icon/xietongshenpi@2x.png",
       label: "鍗忓悓瀹℃壒",
     },
@@ -522,6 +534,21 @@
           url: "/pages/managementMeetings/meetApplication/index",
         });
         break;
+      case "浼氳瀹℃壒":
+        uni.navigateTo({
+          url: "/pages/managementMeetings/meetExamine/index",
+        });
+        break;
+      case "浼氳鍙戝竷":
+        uni.navigateTo({
+          url: "/pages/managementMeetings/meetPublish/index",
+        });
+        break;
+      case "浼氳鎬荤粨":
+        uni.navigateTo({
+          url: "/pages/managementMeetings/meetSummary/index",
+        });
+        break;
       case "鍗忓悓瀹℃壒":
         uni.navigateTo({
           url: "/pages/cooperativeOffice/collaborativeApproval/index",
diff --git a/src/pages/managementMeetings/meetExamine/approve.vue b/src/pages/managementMeetings/meetExamine/approve.vue
new file mode 100644
index 0000000..3ef296d
--- /dev/null
+++ b/src/pages/managementMeetings/meetExamine/approve.vue
@@ -0,0 +1,470 @@
+<template>
+  <view class="approve-page">
+    <PageHeader title="瀹℃壒"
+                @back="goBack" />
+    <!-- 鐢宠淇℃伅 -->
+    <view class="application-info">
+      <view class="info-header">
+        <text class="info-title">浼氳淇℃伅</text>
+      </view>
+      <view class="info-content">
+        <view class="info-row">
+          <text class="info-label">浼氳涓婚</text>
+          <text class="info-value">{{ approvalData.title }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鐢宠浜�</text>
+          <text class="info-value">{{ approvalData.applicant }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">涓荤悊浜�</text>
+          <text class="info-value">{{ approvalData.host }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳鏃堕棿</text>
+          <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳鍦扮偣</text>
+          <text class="info-value">{{ approvalData.location }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">瀹℃壒鐘舵��</text>
+          <text class="info-value tag"
+                :class="getTagClass(approvalData.approveNodeStatus)">
+            {{ formatReceiptType(approvalData.approveNodeStatus) }}
+          </text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鍙備細浜烘暟</text>
+          <text class="info-value">{{ approvalData.participants.length }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鍙備細浜哄憳</text>
+          <text class="info-value">{{ approvalData.participants.map(it => it.name).join("銆�") }}</text>
+        </view>
+      </view>
+    </view>
+    <!-- 搴曢儴鎿嶄綔鎸夐挳 -->
+    <view v-if="isEdit"
+          class="footer-actions">
+      <u-button class="reject-btn"
+                @click="handleReject">涓嶉�氳繃</u-button>
+      <u-button class="approve-btn"
+                @click="handleApprove">閫氳繃</u-button>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref, onMounted, computed } from "vue";
+  import { onLoad } from "@dcloudio/uni-app";
+  import { saveMeetingApplication } from "@/api/managementMeetings/meetExamine";
+  const showToast = message => {
+    uni.showToast({
+      title: message,
+      icon: "none",
+    });
+  };
+  import PageHeader from "@/components/PageHeader.vue";
+
+  const approvalData = ref({});
+  const approvalSteps = ref([]);
+  const isEdit = ref(false);
+
+  onLoad(options => {
+    console.log(options, "options");
+    if (options.item) {
+      approvalData.value = JSON.parse(options.item);
+    }
+    if (options.edit) {
+      isEdit.value = options.edit === "true" ? true : false;
+    }
+  });
+
+  const goBack = () => {
+    uni.removeStorageSync("approveId");
+    uni.navigateBack();
+  };
+  const formatDateTime = dateTime => {
+    if (!dateTime) return "";
+    return dateTime.replace(" ", "\n");
+  };
+
+  // 鏍煎紡鍖栧洖娆炬柟寮�
+  const formatReceiptType = params => {
+    if (params == 0) {
+      return "寰呭鏍�";
+    } else if (params == 1) {
+      return "宸查�氳繃";
+    } else if (params == 2) {
+      return "鏈�氳繃";
+    } else if (params == 3) {
+      return "宸插彇娑�";
+    } else {
+      return "鏈煡";
+    }
+  };
+  // 鑾峰彇鏍囩鏍峰紡绫�
+  const getTagClass = type => {
+    if (type == 0) {
+      return "info";
+    } else if (type == 1) {
+      return "success";
+    } else if (type == 2) {
+      return "warning";
+    } else if (type == 3) {
+      return "danger";
+    } else {
+      return "info";
+    }
+  };
+  const submitForm = status => {
+    // 璋冪敤鍚庣
+    saveMeetingApplication({ id: approvalData.value.id, status: status })
+      .then(res => {
+        if (res.code === 200) {
+          showToast("瀹℃壒鎻愪氦鎴愬姛");
+          // 鎻愮ず鍚庤繑鍥炰笂涓�涓〉闈�
+          setTimeout(() => {
+            goBack(); // 鍐呴儴鏄� uni.navigateBack()
+          }, 800);
+        } else {
+          showToast(res.message || "瀹℃壒鎿嶄綔澶辫触锛岃閲嶈瘯");
+        }
+      })
+      .catch(error => {
+        console.error("瀹℃壒鎿嶄綔澶辫触:", error);
+        showToast("瀹℃壒鎿嶄綔澶辫触锛岃閲嶈瘯");
+      });
+  };
+
+  const handleApprove = () => {
+    uni.showModal({
+      title: "纭鎿嶄綔",
+      content: "纭畾瑕侀�氳繃璇ヤ細璁敵璇峰悧锛�",
+      success: res => {
+        if (res.confirm) submitForm(1);
+      },
+    });
+  };
+
+  const handleReject = () => {
+    uni.showModal({
+      title: "纭鎿嶄綔",
+      content: "纭畾涓嶉�氳繃璇ヤ細璁敵璇峰悧锛�",
+      success: res => {
+        if (res.confirm) submitForm(2);
+      },
+    });
+  };
+  // 鍘熷鑺傜偣鏁版嵁锛堢敤浜庢彁浜ら�昏緫锛�
+  const activities = ref([]);
+</script>
+
+<style scoped lang="scss">
+  .approve-page {
+    min-height: 100vh;
+    background: #f8f9fa;
+    padding-bottom: 80px;
+  }
+
+  .header {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    padding: 16px 20px;
+    border-bottom: 1px solid #f0f0f0;
+    position: sticky;
+    top: 0;
+    z-index: 100;
+  }
+
+  .title {
+    flex: 1;
+    text-align: center;
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .application-info {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .info-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .info-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .info-content {
+    padding: 16px;
+  }
+
+  .info-row {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .info-label {
+    font-size: 14px;
+    color: #666;
+    width: 80px;
+    flex-shrink: 0;
+  }
+
+  .info-value {
+    font-size: 14px;
+    color: #333;
+    flex: 1;
+  }
+
+  .approval-process {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .process-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .process-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .process-steps {
+    padding: 20px;
+  }
+
+  .process-step {
+    display: flex;
+    position: relative;
+    margin-bottom: 24px;
+
+    &:last-child {
+      margin-bottom: 0;
+
+      .step-line {
+        display: none;
+      }
+    }
+  }
+
+  .step-indicator {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin-right: 16px;
+  }
+
+  .step-dot {
+    width: 32px;
+    height: 32px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 14px;
+    font-weight: 600;
+    position: relative;
+    z-index: 2;
+  }
+
+  .process-step.completed .step-dot {
+    background: #52c41a;
+    color: #fff;
+  }
+
+  .process-step.current .step-dot {
+    background: #1890ff;
+    color: #fff;
+    animation: pulse 2s infinite;
+  }
+
+  .process-step.pending .step-dot {
+    background: #d9d9d9;
+    color: #999;
+  }
+
+  .step-line {
+    width: 2px;
+    height: 40px;
+    background: #d9d9d9;
+    margin-top: 8px;
+  }
+
+  .process-step.completed .step-line {
+    background: #52c41a;
+  }
+
+  .process-step.rejected .step-dot {
+    background: #ff4d4f;
+    color: #fff;
+  }
+  .process-step.rejected .step-line {
+    background: #ff4d4f;
+  }
+
+  .step-content {
+    flex: 1;
+    padding-top: 4px;
+  }
+
+  .step-info {
+    margin-bottom: 8px;
+  }
+
+  .step-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .step-approver {
+    font-size: 14px;
+    color: #666;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .step-time {
+    font-size: 12px;
+    color: #999;
+    display: block;
+  }
+
+  .step-opinion {
+    background: #f8f9fa;
+    padding: 12px;
+    border-radius: 8px;
+    border-left: 4px solid #52c41a;
+  }
+
+  .opinion-label {
+    font-size: 12px;
+    color: #666;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .opinion-content {
+    font-size: 14px;
+    color: #333;
+    line-height: 1.5;
+  }
+
+  .approval-input {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .input-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .input-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .input-content {
+    padding: 16px;
+  }
+
+  .footer-actions {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: #fff;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    padding: 16px;
+    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
+    z-index: 1000;
+  }
+
+  .reject-btn {
+    width: 120px;
+    background: #ff4d4f;
+    color: #fff;
+  }
+
+  .approve-btn {
+    width: 120px;
+    background: #52c41a;
+    color: #fff;
+  }
+
+  /* 閫傞厤u-button鏍峰紡 */
+  :deep(.u-button) {
+    border-radius: 6px;
+  }
+
+  @keyframes pulse {
+    0% {
+      box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7);
+    }
+    70% {
+      box-shadow: 0 0 0 10px rgba(24, 144, 255, 0);
+    }
+    100% {
+      box-shadow: 0 0 0 0 rgba(24, 144, 255, 0);
+    }
+  }
+  .signature-section {
+    background: #fff;
+    padding: 12px 16px 16px;
+    border-top: 1px solid #f0f0f0;
+  }
+  .signature-header {
+    margin-bottom: 8px;
+  }
+  .signature-title {
+    font-size: 14px;
+    font-weight: 600;
+    color: #333;
+  }
+  .signature-box {
+    width: 100%;
+    height: 180px;
+    background: #fff;
+    border: 1px dashed #d9d9d9;
+    border-radius: 8px;
+    overflow: hidden;
+  }
+  .signature-actions {
+    margin-top: 8px;
+    display: flex;
+    justify-content: flex-end;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/managementMeetings/meetExamine/index.vue b/src/pages/managementMeetings/meetExamine/index.vue
new file mode 100644
index 0000000..ec96321
--- /dev/null
+++ b/src/pages/managementMeetings/meetExamine/index.vue
@@ -0,0 +1,352 @@
+// 瀹℃壒绠$悊涓婚〉闈�
+<template>
+  <view class="sales-account">
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+    <PageHeader title="浼氳瀹℃壒"
+                @back="goBack" />
+    <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text"
+                    placeholder="璇疯緭鍏ヤ細璁富棰�"
+                    v-model="searchForm.title"
+                    clearable />
+        </view>
+        <view class="search-button"
+              @click="getList">
+          <up-icon name="search"
+                   size="24"
+                   color="#999"></up-icon>
+        </view>
+      </view>
+    </view>
+    <!-- 瀹℃壒鍒楄〃 -->
+    <view class="ledger-list"
+          v-if="ledgerList.length > 0">
+      <view v-for="(item, index) in ledgerList"
+            :key="index">
+        <view class="ledger-item">
+          <view class="item-header">
+            <view class="item-left">
+              <view class="document-icon">
+                <up-icon name="file-text"
+                         size="16"
+                         color="#ffffff"></up-icon>
+              </view>
+              <text class="item-id">{{ item.title }}</text>
+            </view>
+            <view class="item-tag">
+              <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">鐢宠浜�</text>
+              <text class="detail-value">{{ item.applicant }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">涓荤悊浜�</text>
+              <text class="detail-value">{{ item.host }}</text>
+            </view>
+            <view class="detail-row-approveReason">
+              <text class="detail-label">浼氳鏃堕棿</text>
+              <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">浼氳鍦扮偣</text>
+              <text class="detail-value">{{ item.location }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍙備細浜烘暟</text>
+              <text class="detail-value">{{ item.participants.length }}</text>
+            </view>
+            <up-divider></up-divider>
+            <view class="actions">
+              <u-button type="primary"
+                        size="small"
+                        class="action-btn view"
+                        @click="viewDetail(item)">
+                璇︽儏
+              </u-button>
+              <u-button type="success"
+                        size="small"
+                        class="action-btn approve"
+                        :disabled="item.status != 0"
+                        @click="approve(item)">
+                瀹℃壒
+              </u-button>
+            </view>
+            <!-- <view class="detail-info"
+                  style="align-items: flex-end;">
+              <view class="detail-row">
+               
+              </view>
+            </view> -->
+          </view>
+        </view>
+      </view>
+    </view>
+    <view v-else
+          class="no-data">
+      <text>鏆傛棤鏁版嵁</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref, toRefs, reactive } from "vue";
+  import PageHeader from "@/components/PageHeader.vue";
+  import {
+    getExamineList,
+    getRoomEnum,
+  } from "@/api/managementMeetings/meetExamine";
+  import { getStaffOnJob } from "@/api/personnelManagement/onboarding";
+  import { onShow } from "@dcloudio/uni-app";
+  import useUserStore from "@/store/modules/user";
+  import dayjs from "dayjs";
+
+  const userStore = useUserStore();
+  // 鏁版嵁
+  const ledgerList = ref([]);
+  const data = reactive({
+    searchForm: {
+      title: "",
+    },
+  });
+  const { searchForm } = toRefs(data);
+
+  // 杩斿洖涓婁竴椤�
+  const goBack = () => {
+    uni.navigateBack();
+  };
+  // 鎴块棿鏋氫妇
+  const roomEnum = ref([]);
+  // 鎴块棿鏋氫妇鏌ヨ
+  const getRoomEnumList = () => {
+    return getRoomEnum()
+      .then(res => {
+        console.log(res.data, "res.data");
+        roomEnum.value = res.data;
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鍛樺伐鍒楄〃
+  const staffList = ref([]);
+  // 鍛樺伐鍒楄〃鏌ヨ
+  const getStaffOnJobList = () => {
+    return getStaffOnJob()
+      .then(res => {
+        console.log(res.data, "res.data");
+        staffList.value = res.data;
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鏌ヨ鍒楄〃
+  const getList = () => {
+    showLoadingToast("鍔犺浇涓�...");
+    const page = {
+      current: -1,
+      size: -1,
+    };
+    getExamineList({
+      ...page,
+      ...searchForm.value,
+    })
+      .then(res => {
+        console.log(res.data.records, "res.data.records");
+        ledgerList.value = res.data.records.map(it => {
+          console.log(it, "it1");
+          let room = roomEnum.value.find(room => it.roomId === room.id);
+          it.location = `${room.name}(${room.location})`;
+          let staffs = JSON.parse(it.participants);
+          it.staffCount = staffs.size;
+          it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format(
+            "HH:mm:ss"
+          )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`;
+          it.participants = staffList.value
+            .filter(staff => staffs.some(id => id == staff.id))
+            .map(staff => {
+              return {
+                id: staff.id,
+                name: `${staff.staffName}(${staff.postJob})`,
+              };
+            });
+          console.log(it, "it2");
+
+          return it;
+        });
+
+        closeToast();
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鏄剧ず鍔犺浇鎻愮ず
+  const showLoadingToast = message => {
+    uni.showLoading({
+      title: message,
+      mask: true,
+    });
+  };
+  const formatDateTime = dateTime => {
+    if (!dateTime) return "";
+    return dateTime.replace(" ", "\n");
+  };
+
+  // 鍏抽棴鎻愮ず
+  const closeToast = () => {
+    uni.hideLoading();
+  };
+
+  // 鏍煎紡鍖栧洖娆炬柟寮�
+  const formatReceiptType = params => {
+    if (params == 0) {
+      return "寰呭鏍�";
+    } else if (params == 1) {
+      return "宸查�氳繃";
+    } else if (params == 2) {
+      return "鏈�氳繃";
+    } else if (params == 3) {
+      return "宸插彇娑�";
+    } else {
+      return "鏈煡";
+    }
+  };
+  // 鑾峰彇鏍囩鏍峰紡绫�
+  const getTagClass = type => {
+    if (type == 0) {
+      return "info";
+    } else if (type == 1) {
+      return "success";
+    } else if (type == 2) {
+      return "warning";
+    } else if (type == 3) {
+      return "danger";
+    } else {
+      return "info";
+    }
+  };
+
+  // 鐐瑰嚮瀹℃牳
+  const approve = item => {
+    // uni.setStorageSync("approveId", item.approveId);
+    uni.navigateTo({
+      url:
+        "/pages/managementMeetings/meetExamine/approve?item=" +
+        JSON.stringify(item) +
+        "&edit=true",
+    });
+  };
+  // 鏌ョ湅璇︽儏
+  const viewDetail = item => {
+    uni.navigateTo({
+      url:
+        "/pages/managementMeetings/meetExamine/approve?item=" +
+        JSON.stringify(item) +
+        "&edit=false",
+    });
+  };
+
+  onShow(async () => {
+    // 椤甸潰鍔犺浇瀹屾垚鍚庣殑鍒濆鍖栭�昏緫
+    try {
+      // 绛夊緟涓や釜寮傛鏂规硶鎵ц瀹屾垚
+      await Promise.all([getRoomEnumList(), getStaffOnJobList()]);
+      // 涓や釜鏂规硶鎵ц瀹屾垚鍚庡啀鎵ц getList()
+      getList();
+    } catch (error) {
+      console.error("鍒濆鍖栨暟鎹け璐�:", error);
+      // 鍗充娇鍑洪敊涔熸墽琛� getList()锛岀‘淇濋〉闈㈣兘姝e父鍔犺浇
+      getList();
+    }
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "../../../styles/sales-common.scss";
+
+  .u-divider {
+    margin: 0 !important;
+  }
+
+  // 鏂囨。鍥炬爣鏍峰紡 - 瑕嗙洊鍏叡鏍峰紡涓殑鑳屾櫙鑹�
+  .document-icon {
+    background: #ed8d05;
+  }
+
+  // 娴姩鎸夐挳鏍峰紡 - 瑕嗙洊鍏叡鏍峰紡涓殑鑳屾櫙鑹�
+  .fab-button {
+    background: #ed8d05;
+  }
+
+  // 鐗规湁鏍峰紡
+  .detail-row-user {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  .detail-row-approveReason {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 8px;
+  }
+
+  .detail-value.highlightBlue {
+    color: #2979ff;
+    font-weight: 500;
+  }
+
+  .detail-value.highlightYellow {
+    color: #ed8d05;
+    font-weight: 500;
+  }
+
+  .approver-value {
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .approver-chip {
+    display: inline-flex;
+    align-items: center;
+    gap: 6px;
+    background: #f0f6ff;
+    color: #2b7cff;
+    border: 1px solid #e0efff;
+    border-radius: 999px;
+    padding: 4px 10px;
+    max-width: 100%;
+  }
+
+  .approver-name {
+    font-size: 12px;
+    color: #2b7cff;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .actions {
+    display: flex;
+    gap: 10px;
+    align-items: center;
+    justify-content: flex-end;
+    margin-top: 18rpx;
+  }
+
+  .action-btn {
+    border-radius: 16px;
+    height: 28px;
+    line-height: 28px;
+    padding: 0 12px;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/managementMeetings/meetPublish/approve.vue b/src/pages/managementMeetings/meetPublish/approve.vue
new file mode 100644
index 0000000..50a6f52
--- /dev/null
+++ b/src/pages/managementMeetings/meetPublish/approve.vue
@@ -0,0 +1,497 @@
+<template>
+  <view class="approve-page">
+    <PageHeader title="鍙戝竷"
+                @back="goBack" />
+    <!-- 鐢宠淇℃伅 -->
+    <view class="application-info">
+      <view class="info-header">
+        <text class="info-title">浼氳淇℃伅</text>
+      </view>
+      <view class="info-content">
+        <view class="info-row">
+          <text class="info-label">浼氳涓婚</text>
+          <text class="info-value">{{ approvalData.title }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鐢宠浜�</text>
+          <text class="info-value">{{ approvalData.applicant }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">涓荤悊浜�</text>
+          <text class="info-value">{{ approvalData.host }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳鏃堕棿</text>
+          <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳鍦扮偣</text>
+          <text class="info-value">{{ approvalData.location }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">瀹℃壒鐘舵��</text>
+          <text class="info-value tag"
+                :class="getTagClass(approvalData.approveNodeStatus)">
+            {{ formatReceiptType(approvalData.approveNodeStatus) }}
+          </text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳璇存槑</text>
+          <text class="info-value">{{ approvalData.description }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鍙備細浜烘暟</text>
+          <text class="info-value">{{ approvalData.participants.length }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鍙備細浜哄憳</text>
+          <text class="info-value">{{ approvalData.participants.map(it => it.name).join("銆�") }}</text>
+        </view>
+      </view>
+    </view>
+    <!-- 鍙戝竷鎰忚杈撳叆 -->
+    <view v-if="isEdit"
+          class="approval-input">
+      <view class="input-header">
+        <text class="input-title">鍙戝竷鎰忚</text>
+      </view>
+      <view class="input-content">
+        <u-textarea v-model="approvalOpinion"
+                    rows="4"
+                    placeholder="璇疯緭鍏ュ彂甯冩剰瑙�"
+                    maxlength="200"
+                    count />
+      </view>
+    </view>
+    <!-- 搴曢儴鎿嶄綔鎸夐挳 -->
+    <view v-if="isEdit"
+          class="footer-actions">
+      <!-- <u-button class="reject-btn"
+                @click="handleReject">涓嶉�氳繃</u-button> -->
+      <u-button class="approve-btn"
+                @click="handleApprove">鍙戝竷</u-button>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref, onMounted, computed } from "vue";
+  import { onLoad } from "@dcloudio/uni-app";
+  import { saveMeetingApplication } from "@/api/managementMeetings/meetExamine";
+  const showToast = message => {
+    uni.showToast({
+      title: message,
+      icon: "none",
+    });
+  };
+  import PageHeader from "@/components/PageHeader.vue";
+
+  const approvalData = ref({});
+  const approvalSteps = ref([]);
+  const approvalOpinion = ref("");
+  const isEdit = ref(false);
+
+  onLoad(options => {
+    console.log(options, "options");
+    if (options.item) {
+      approvalData.value = JSON.parse(options.item);
+    }
+    // 缂栬緫妯″紡涓嬶紝榛樿鍙戝竷鎰忚涓哄綋鍓嶅鎵规剰瑙�
+    if (options.edit) {
+      isEdit.value = options.edit === "true" ? true : false;
+    }
+    console.log(approvalData.value, "approvalData.value");
+  });
+
+  const goBack = () => {
+    uni.removeStorageSync("approveId");
+    uni.navigateBack();
+  };
+  const formatDateTime = dateTime => {
+    if (!dateTime) return "";
+    return dateTime.replace(" ", "\n");
+  };
+
+  // 鏍煎紡鍖栧洖娆炬柟寮�
+  const formatReceiptType = params => {
+    if (params == 0) {
+      return "寰呭彂甯�";
+    } else if (params == 1) {
+      return "宸插彂甯�";
+    } else if (params == 2) {
+      return "宸插彇娑�";
+    } else {
+      return "鏈煡";
+    }
+  };
+  // 鑾峰彇鏍囩鏍峰紡绫�
+  const getTagClass = type => {
+    if (type == 0) {
+      return "info";
+    } else if (type == 1) {
+      return "success";
+    } else if (type == 2) {
+      return "danger";
+    } else {
+      return "info";
+    }
+  };
+  const submitForm = status => {
+    // 鏍¢獙鍙戝竷鎰忚
+    if (!approvalOpinion.value?.trim()) {
+      showToast("璇疯緭鍏ュ彂甯冩剰瑙�");
+      return;
+    }
+
+    // 璋冪敤鍚庣
+    saveMeetingApplication({
+      id: approvalData.value.id,
+      publishStatus: status,
+      publishComment: approvalOpinion.value, // 娣诲姞鍙戝竷鎰忚
+    })
+      .then(res => {
+        if (res.code === 200) {
+          showToast("鍙戝竷鎴愬姛");
+          // 鎻愮ず鍚庤繑鍥炰笂涓�涓〉闈�
+          setTimeout(() => {
+            goBack(); // 鍐呴儴鏄� uni.navigateBack()
+          }, 800);
+        } else {
+          showToast(res.message || "鍙戝竷鎿嶄綔澶辫触锛岃閲嶈瘯");
+        }
+      })
+      .catch(error => {
+        console.error("鍙戝竷鎿嶄綔澶辫触:", error);
+        showToast("鍙戝竷鎿嶄綔澶辫触锛岃閲嶈瘯");
+      });
+  };
+
+  const handleApprove = () => {
+    uni.showModal({
+      title: "纭鎿嶄綔",
+      content: "纭畾瑕佸彂甯冭浼氳鍚楋紵",
+      success: res => {
+        if (res.confirm) submitForm(1);
+      },
+    });
+  };
+
+  const handleReject = () => {
+    uni.showModal({
+      title: "纭鎿嶄綔",
+      content: "纭畾涓嶉�氳繃璇ヤ細璁敵璇峰悧锛�",
+      success: res => {
+        if (res.confirm) submitForm(2);
+      },
+    });
+  };
+  // 鍘熷鑺傜偣鏁版嵁锛堢敤浜庢彁浜ら�昏緫锛�
+  const activities = ref([]);
+</script>
+
+<style scoped lang="scss">
+  .approve-page {
+    min-height: 100vh;
+    background: #f8f9fa;
+    padding-bottom: 80px;
+  }
+
+  .header {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    padding: 16px 20px;
+    border-bottom: 1px solid #f0f0f0;
+    position: sticky;
+    top: 0;
+    z-index: 100;
+  }
+
+  .title {
+    flex: 1;
+    text-align: center;
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .application-info {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .info-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .info-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .info-content {
+    padding: 16px;
+  }
+
+  .info-row {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .info-label {
+    font-size: 14px;
+    color: #666;
+    width: 80px;
+    flex-shrink: 0;
+  }
+
+  .info-value {
+    font-size: 14px;
+    color: #333;
+    flex: 1;
+  }
+
+  .approval-process {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .process-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .process-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .process-steps {
+    padding: 20px;
+  }
+
+  .process-step {
+    display: flex;
+    position: relative;
+    margin-bottom: 24px;
+
+    &:last-child {
+      margin-bottom: 0;
+
+      .step-line {
+        display: none;
+      }
+    }
+  }
+
+  .step-indicator {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin-right: 16px;
+  }
+
+  .step-dot {
+    width: 32px;
+    height: 32px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 14px;
+    font-weight: 600;
+    position: relative;
+    z-index: 2;
+  }
+
+  .process-step.completed .step-dot {
+    background: #52c41a;
+    color: #fff;
+  }
+
+  .process-step.current .step-dot {
+    background: #1890ff;
+    color: #fff;
+    animation: pulse 2s infinite;
+  }
+
+  .process-step.pending .step-dot {
+    background: #d9d9d9;
+    color: #999;
+  }
+
+  .step-line {
+    width: 2px;
+    height: 40px;
+    background: #d9d9d9;
+    margin-top: 8px;
+  }
+
+  .process-step.completed .step-line {
+    background: #52c41a;
+  }
+
+  .process-step.rejected .step-dot {
+    background: #ff4d4f;
+    color: #fff;
+  }
+  .process-step.rejected .step-line {
+    background: #ff4d4f;
+  }
+
+  .step-content {
+    flex: 1;
+    padding-top: 4px;
+  }
+
+  .step-info {
+    margin-bottom: 8px;
+  }
+
+  .step-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .step-approver {
+    font-size: 14px;
+    color: #666;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .step-time {
+    font-size: 12px;
+    color: #999;
+    display: block;
+  }
+
+  .step-opinion {
+    background: #f8f9fa;
+    padding: 12px;
+    border-radius: 8px;
+    border-left: 4px solid #52c41a;
+  }
+
+  .opinion-label {
+    font-size: 12px;
+    color: #666;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .opinion-content {
+    font-size: 14px;
+    color: #333;
+    line-height: 1.5;
+  }
+
+  .approval-input {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .input-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .input-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .input-content {
+    padding: 16px;
+  }
+
+  .footer-actions {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: #fff;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    padding: 16px;
+    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
+    z-index: 1000;
+  }
+
+  .reject-btn {
+    width: 120px;
+    background: #ff4d4f;
+    color: #fff;
+  }
+
+  .approve-btn {
+    width: 120px;
+    background: #52c41a;
+    color: #fff;
+  }
+
+  /* 閫傞厤u-button鏍峰紡 */
+  :deep(.u-button) {
+    border-radius: 6px;
+  }
+
+  @keyframes pulse {
+    0% {
+      box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7);
+    }
+    70% {
+      box-shadow: 0 0 0 10px rgba(24, 144, 255, 0);
+    }
+    100% {
+      box-shadow: 0 0 0 0 rgba(24, 144, 255, 0);
+    }
+  }
+  .signature-section {
+    background: #fff;
+    padding: 12px 16px 16px;
+    border-top: 1px solid #f0f0f0;
+  }
+  .signature-header {
+    margin-bottom: 8px;
+  }
+  .signature-title {
+    font-size: 14px;
+    font-weight: 600;
+    color: #333;
+  }
+  .signature-box {
+    width: 100%;
+    height: 180px;
+    background: #fff;
+    border: 1px dashed #d9d9d9;
+    border-radius: 8px;
+    overflow: hidden;
+  }
+  .signature-actions {
+    margin-top: 8px;
+    display: flex;
+    justify-content: flex-end;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/managementMeetings/meetPublish/index.vue b/src/pages/managementMeetings/meetPublish/index.vue
new file mode 100644
index 0000000..0cbfbbf
--- /dev/null
+++ b/src/pages/managementMeetings/meetPublish/index.vue
@@ -0,0 +1,348 @@
+// 瀹℃壒绠$悊涓婚〉闈�
+<template>
+  <view class="sales-account">
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+    <PageHeader title="浼氳鍙戝竷"
+                @back="goBack" />
+    <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text"
+                    placeholder="璇疯緭鍏ヤ細璁富棰�"
+                    v-model="searchForm.title"
+                    clearable />
+        </view>
+        <view class="search-button"
+              @click="getList">
+          <up-icon name="search"
+                   size="24"
+                   color="#999"></up-icon>
+        </view>
+      </view>
+    </view>
+    <!-- 瀹℃壒鍒楄〃 -->
+    <view class="ledger-list"
+          v-if="ledgerList.length > 0">
+      <view v-for="(item, index) in ledgerList"
+            :key="index">
+        <view class="ledger-item">
+          <view class="item-header">
+            <view class="item-left">
+              <view class="document-icon">
+                <up-icon name="file-text"
+                         size="16"
+                         color="#ffffff"></up-icon>
+              </view>
+              <text class="item-id">{{ item.title }}</text>
+            </view>
+            <view class="item-tag">
+              <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">鐢宠浜�</text>
+              <text class="detail-value">{{ item.applicant }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">涓荤悊浜�</text>
+              <text class="detail-value">{{ item.host }}</text>
+            </view>
+            <view class="detail-row-approveReason">
+              <text class="detail-label">浼氳鏃堕棿</text>
+              <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">浼氳鍦扮偣</text>
+              <text class="detail-value">{{ item.location }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍙備細浜烘暟</text>
+              <text class="detail-value">{{ item.participants.length }}</text>
+            </view>
+            <up-divider></up-divider>
+            <view class="actions">
+              <u-button type="primary"
+                        size="small"
+                        class="action-btn view"
+                        @click="viewDetail(item)">
+                璇︽儏
+              </u-button>
+              <u-button type="success"
+                        size="small"
+                        class="action-btn approve"
+                        :disabled="item.status != 0"
+                        @click="approve(item)">
+                鍙戝竷
+              </u-button>
+            </view>
+            <!-- <view class="detail-info"
+                  style="align-items: flex-end;">
+              <view class="detail-row">
+               
+              </view>
+            </view> -->
+          </view>
+        </view>
+      </view>
+    </view>
+    <view v-else
+          class="no-data">
+      <text>鏆傛棤鏁版嵁</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref, toRefs, reactive } from "vue";
+  import PageHeader from "@/components/PageHeader.vue";
+  import {
+    getMeetingPublish,
+    getRoomEnum,
+  } from "@/api/managementMeetings/meetExamine";
+  import { getStaffOnJob } from "@/api/personnelManagement/onboarding";
+  import { onShow } from "@dcloudio/uni-app";
+  import useUserStore from "@/store/modules/user";
+  import dayjs from "dayjs";
+
+  const userStore = useUserStore();
+  // 鏁版嵁
+  const ledgerList = ref([]);
+  const data = reactive({
+    searchForm: {
+      title: "",
+    },
+  });
+  const { searchForm } = toRefs(data);
+
+  // 杩斿洖涓婁竴椤�
+  const goBack = () => {
+    uni.navigateBack();
+  };
+  // 鎴块棿鏋氫妇
+  const roomEnum = ref([]);
+  // 鎴块棿鏋氫妇鏌ヨ
+  const getRoomEnumList = () => {
+    return getRoomEnum()
+      .then(res => {
+        console.log(res.data, "res.data");
+        roomEnum.value = res.data;
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鍛樺伐鍒楄〃
+  const staffList = ref([]);
+  // 鍛樺伐鍒楄〃鏌ヨ
+  const getStaffOnJobList = () => {
+    return getStaffOnJob()
+      .then(res => {
+        console.log(res.data, "res.data");
+        staffList.value = res.data;
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鏌ヨ鍒楄〃
+  const getList = () => {
+    showLoadingToast("鍔犺浇涓�...");
+    const page = {
+      current: -1,
+      size: -1,
+    };
+    getMeetingPublish({
+      ...page,
+      ...searchForm.value,
+    })
+      .then(res => {
+        console.log(res.data.records, "res.data.records");
+        ledgerList.value = res.data.records.map(it => {
+          console.log(it, "it1");
+          let room = roomEnum.value.find(room => it.roomId === room.id);
+          it.location = `${room.name}(${room.location})`;
+          let staffs = JSON.parse(it.participants);
+          it.staffCount = staffs.size;
+          it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format(
+            "HH:mm:ss"
+          )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`;
+          it.participants = staffList.value
+            .filter(staff => staffs.some(id => id == staff.id))
+            .map(staff => {
+              return {
+                id: staff.id,
+                name: `${staff.staffName}(${staff.postJob})`,
+              };
+            });
+          console.log(it, "it2");
+
+          return it;
+        });
+
+        closeToast();
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鏄剧ず鍔犺浇鎻愮ず
+  const showLoadingToast = message => {
+    uni.showLoading({
+      title: message,
+      mask: true,
+    });
+  };
+  const formatDateTime = dateTime => {
+    if (!dateTime) return "";
+    return dateTime.replace(" ", "\n");
+  };
+
+  // 鍏抽棴鎻愮ず
+  const closeToast = () => {
+    uni.hideLoading();
+  };
+
+  // 鏍煎紡鍖栧洖娆炬柟寮�
+  const formatReceiptType = params => {
+    if (params == 0) {
+      return "寰呭彂甯�";
+    } else if (params == 1) {
+      return "宸插彂甯�";
+    } else if (params == 2) {
+      return "宸插彇娑�";
+    } else {
+      return "鏈煡";
+    }
+  };
+  // 鑾峰彇鏍囩鏍峰紡绫�
+  const getTagClass = type => {
+    if (type == 0) {
+      return "info";
+    } else if (type == 1) {
+      return "success";
+    } else if (type == 2) {
+      return "danger";
+    } else {
+      return "info";
+    }
+  };
+
+  // 鐐瑰嚮瀹℃牳
+  const approve = item => {
+    // uni.setStorageSync("approveId", item.approveId);
+    uni.navigateTo({
+      url:
+        "/pages/managementMeetings/meetPublish/approve?item=" +
+        JSON.stringify(item) +
+        "&edit=true",
+    });
+  };
+  // 鏌ョ湅璇︽儏
+  const viewDetail = item => {
+    uni.navigateTo({
+      url:
+        "/pages/managementMeetings/meetPublish/approve?item=" +
+        JSON.stringify(item) +
+        "&edit=false",
+    });
+  };
+
+  onShow(async () => {
+    // 椤甸潰鍔犺浇瀹屾垚鍚庣殑鍒濆鍖栭�昏緫
+    try {
+      // 绛夊緟涓や釜寮傛鏂规硶鎵ц瀹屾垚
+      await Promise.all([getRoomEnumList(), getStaffOnJobList()]);
+      // 涓や釜鏂规硶鎵ц瀹屾垚鍚庡啀鎵ц getList()
+      getList();
+    } catch (error) {
+      console.error("鍒濆鍖栨暟鎹け璐�:", error);
+      // 鍗充娇鍑洪敊涔熸墽琛� getList()锛岀‘淇濋〉闈㈣兘姝e父鍔犺浇
+      getList();
+    }
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "../../../styles/sales-common.scss";
+
+  .u-divider {
+    margin: 0 !important;
+  }
+
+  // 鏂囨。鍥炬爣鏍峰紡 - 瑕嗙洊鍏叡鏍峰紡涓殑鑳屾櫙鑹�
+  .document-icon {
+    background: #ed8d05;
+  }
+
+  // 娴姩鎸夐挳鏍峰紡 - 瑕嗙洊鍏叡鏍峰紡涓殑鑳屾櫙鑹�
+  .fab-button {
+    background: #ed8d05;
+  }
+
+  // 鐗规湁鏍峰紡
+  .detail-row-user {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  .detail-row-approveReason {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 8px;
+  }
+
+  .detail-value.highlightBlue {
+    color: #2979ff;
+    font-weight: 500;
+  }
+
+  .detail-value.highlightYellow {
+    color: #ed8d05;
+    font-weight: 500;
+  }
+
+  .approver-value {
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .approver-chip {
+    display: inline-flex;
+    align-items: center;
+    gap: 6px;
+    background: #f0f6ff;
+    color: #2b7cff;
+    border: 1px solid #e0efff;
+    border-radius: 999px;
+    padding: 4px 10px;
+    max-width: 100%;
+  }
+
+  .approver-name {
+    font-size: 12px;
+    color: #2b7cff;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .actions {
+    display: flex;
+    gap: 10px;
+    align-items: center;
+    justify-content: flex-end;
+    margin-top: 18rpx;
+  }
+
+  .action-btn {
+    border-radius: 16px;
+    height: 28px;
+    line-height: 28px;
+    padding: 0 12px;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/managementMeetings/meetSummary/approve.vue b/src/pages/managementMeetings/meetSummary/approve.vue
new file mode 100644
index 0000000..f2b8193
--- /dev/null
+++ b/src/pages/managementMeetings/meetSummary/approve.vue
@@ -0,0 +1,554 @@
+<template>
+  <view class="approve-page">
+    <PageHeader title="鎬荤粨"
+                @back="goBack" />
+    <!-- 鐢宠淇℃伅 -->
+    <view class="application-info">
+      <view class="info-header">
+        <text class="info-title">浼氳淇℃伅</text>
+      </view>
+      <view class="info-content">
+        <view class="info-row">
+          <text class="info-label">浼氳涓婚</text>
+          <text class="info-value">{{ approvalData.title }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鐢宠浜�</text>
+          <text class="info-value">{{ approvalData.applicant }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">涓荤悊浜�</text>
+          <text class="info-value">{{ approvalData.host }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳鏃堕棿</text>
+          <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳鍦扮偣</text>
+          <text class="info-value">{{ approvalData.location }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">瀹℃壒鐘舵��</text>
+          <text class="info-value tag"
+                :class="getTagClass(approvalData.approveNodeStatus)">
+            {{ formatReceiptType(approvalData.approveNodeStatus) }}
+          </text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">浼氳璇存槑</text>
+          <text class="info-value">{{ approvalData.description }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鍙備細浜烘暟</text>
+          <text class="info-value">{{ approvalData.participants.length }}</text>
+        </view>
+        <view class="info-row">
+          <text class="info-label">鍙備細浜哄憳</text>
+          <text class="info-value">{{ approvalData.participants.map(it => it.name).join("銆�") }}</text>
+        </view>
+      </view>
+    </view>
+    <!-- 鎻愪氦鎰忚杈撳叆 -->
+    <view v-if="isEdit"
+          class="approval-input">
+      <view class="input-header">
+        <text class="input-title">浼氳绾</text>
+      </view>
+      <view class="input-content">
+        <Editor v-model:modelValue="minutesContent"
+                :height="300" />
+      </view>
+    </view>
+    <!-- 搴曢儴鎿嶄綔鎸夐挳 -->
+    <view v-if="isEdit"
+          class="footer-actions">
+      <u-button class="approve-btn"
+                @click="handleApprove">鎻愪氦</u-button>
+    </view>
+  </view>
+</template>
+<script setup>
+  import { ref, onMounted, nextTick } from "vue";
+  import { onLoad } from "@dcloudio/uni-app";
+  import {
+    saveMeetingMinutes,
+    getMeetingMinutesByMeetingId,
+  } from "@/api/managementMeetings/meetExamine";
+  import { getToken } from "@/utils/auth";
+  import PageHeader from "@/components/PageHeader.vue";
+  import Editor from "@/components/Editor/index.vue";
+
+  const approvalData = ref({});
+  const approvalSteps = ref([]);
+  const isEdit = ref(false);
+  onLoad(options => {
+    console.log(options, "options");
+    if (options.item) {
+      approvalData.value = JSON.parse(options.item);
+    }
+    // 缂栬緫妯″紡涓嬶紝榛樿鎻愪氦鎰忚涓哄綋鍓嶅鎵规剰瑙�
+    if (options.edit) {
+      isEdit.value = options.edit === "true" ? true : false;
+    }
+    getMeetingMinutes();
+    console.log(approvalData.value, "approvalData.value");
+  });
+  const goBack = () => {
+    uni.removeStorageSync("approveId");
+    uni.navigateBack();
+  };
+  const formatDateTime = dateTime => {
+    if (!dateTime) return "";
+    return dateTime.replace(" ", "\n");
+  };
+
+  // 鏍煎紡鍖栧洖娆炬柟寮�
+  const formatReceiptType = params => {
+    if (params == 0) {
+      return "寰呭鎵�";
+    } else if (params == 1) {
+      return "宸查�氳繃";
+    } else if (params == 2) {
+      return "鏈�氳繃";
+    } else if (params == 3) {
+      return "宸插彇娑�";
+    } else {
+      return "鏈煡";
+    }
+  };
+  // 鑾峰彇鏍囩鏍峰紡绫�
+  const getTagClass = type => {
+    if (type == 0) {
+      return "info";
+    } else if (type == 1) {
+      return "success";
+    } else if (type == 2) {
+      return "warning";
+    } else if (type == 3) {
+      return "danger";
+    } else {
+      return "info";
+    }
+  };
+  const minutesContent = ref("");
+  const minutesContentId = ref("");
+  const getMeetingMinutes = () => {
+    getMeetingMinutesByMeetingId(approvalData.value.id)
+      .then(res => {
+        console.log(res.data, "res.data");
+
+        if (res.data) {
+          minutesContent.value = res.data.content;
+          minutesContentId.value = res.data.id;
+        } else {
+          minutesContent.value = `<h2>${approvalData.value.title}浼氳绾</h2>
+                                                                              <p><strong>浼氳鏃堕棿锛�</strong>${
+                                                                                approvalData
+                                                                                  .value
+                                                                                  .meetingTime
+                                                                              }</p>
+                                                                              <p><strong>浼氳鍦扮偣锛�</strong>${
+                                                                                approvalData
+                                                                                  .value
+                                                                                  .location
+                                                                              }</p>
+                                                                              <p><strong>涓绘寔浜猴細</strong>${
+                                                                                approvalData
+                                                                                  .value
+                                                                                  .host
+                                                                              }</p>
+                                                                              <p><strong>鍙備細浜哄憳锛�</strong></p>
+                                                                              <ol>
+                                                                                ${approvalData.value.participants
+                                                                                  .map(
+                                                                                    p =>
+                                                                                      `<li>${p.name}</li>`
+                                                                                  )
+                                                                                  .join(
+                                                                                    ""
+                                                                                  )}
+                                                                              </ol>
+                                                                              <p><strong>浼氳鍐呭锛�</strong></p>
+                                                                              <ol>
+                                                                                <li>璁涓�锛�
+                                                                                  <ul>
+                                                                                    <li>璁ㄨ鍐呭锛�</li>
+                                                                                    <li>鍐宠浜嬮」锛�</li>
+                                                                                  </ul>
+                                                                                </li>
+                                                                                <li>璁浜岋細
+                                                                                  <ul>
+                                                                                    <li>璁ㄨ鍐呭锛�</li>
+                                                                                    <li>鍐宠浜嬮」锛�</li>
+                                                                                  </ul>
+                                                                                </li>
+                                                                              </ol>
+                                                                              <p><strong>澶囨敞锛�</strong></p>`;
+        }
+      })
+      .catch(error => {
+        console.error("鑾峰彇浼氳绾澶辫触:", error);
+        showToast("鑾峰彇浼氳绾澶辫触锛岃閲嶈瘯");
+      });
+  };
+  const submitForm = status => {
+    console.log(minutesContent.value, "瀵屾枃鏈�");
+    if (!minutesContent.value) {
+      ElMessage.warning("璇疯緭鍏ヤ細璁邯瑕佸唴瀹�");
+      return;
+    }
+
+    // 璋冪敤鍚庣
+    saveMeetingMinutes({
+      id: minutesContentId.value,
+      content: minutesContent.value,
+      meetingId: approvalData.value.id,
+      title: approvalData.value.title,
+    })
+      .then(res => {
+        if (res.code === 200) {
+          showToast("鎻愪氦鎴愬姛");
+          // 鎻愮ず鍚庤繑鍥炰笂涓�涓〉闈�
+          setTimeout(() => {
+            goBack(); // 鍐呴儴鏄� uni.navigateBack()
+          }, 800);
+        } else {
+          showToast(res.message || "鎻愪氦鎿嶄綔澶辫触锛岃閲嶈瘯");
+        }
+      })
+      .catch(error => {
+        console.error("鎻愪氦鎿嶄綔澶辫触:", error);
+        showToast("鎻愪氦鎿嶄綔澶辫触锛岃閲嶈瘯");
+      });
+  };
+
+  const handleApprove = () => {
+    uni.showModal({
+      title: "纭鎿嶄綔",
+      content: "纭畾瑕佹彁浜よ浼氳鎬荤粨鍚楋紵",
+      success: res => {
+        if (res.confirm) submitForm(1);
+      },
+    });
+  };
+  // 鍘熷鑺傜偣鏁版嵁锛堢敤浜庢彁浜ら�昏緫锛�
+  const activities = ref([]);
+</script>
+
+<style scoped lang="scss">
+  .approve-page {
+    min-height: 100vh;
+    background: #f8f9fa;
+    padding-bottom: 80px;
+  }
+
+  .header {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    padding: 16px 20px;
+    border-bottom: 1px solid #f0f0f0;
+    position: sticky;
+    top: 0;
+    z-index: 100;
+  }
+
+  .title {
+    flex: 1;
+    text-align: center;
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .application-info {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .info-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .info-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .info-content {
+    padding: 16px;
+  }
+
+  .info-row {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .info-label {
+    font-size: 14px;
+    color: #666;
+    width: 80px;
+    flex-shrink: 0;
+  }
+
+  .info-value {
+    font-size: 14px;
+    color: #333;
+    flex: 1;
+  }
+
+  .approval-process {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .process-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .process-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .process-steps {
+    padding: 20px;
+  }
+
+  .process-step {
+    display: flex;
+    position: relative;
+    margin-bottom: 24px;
+
+    &:last-child {
+      margin-bottom: 0;
+
+      .step-line {
+        display: none;
+      }
+    }
+  }
+
+  .step-indicator {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin-right: 16px;
+  }
+
+  .step-dot {
+    width: 32px;
+    height: 32px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 14px;
+    font-weight: 600;
+    position: relative;
+    z-index: 2;
+  }
+
+  .process-step.completed .step-dot {
+    background: #52c41a;
+    color: #fff;
+  }
+
+  .process-step.current .step-dot {
+    background: #1890ff;
+    color: #fff;
+    animation: pulse 2s infinite;
+  }
+
+  .process-step.pending .step-dot {
+    background: #d9d9d9;
+    color: #999;
+  }
+
+  .step-line {
+    width: 2px;
+    height: 40px;
+    background: #d9d9d9;
+    margin-top: 8px;
+  }
+
+  .process-step.completed .step-line {
+    background: #52c41a;
+  }
+
+  .process-step.rejected .step-dot {
+    background: #ff4d4f;
+    color: #fff;
+  }
+  .process-step.rejected .step-line {
+    background: #ff4d4f;
+  }
+
+  .step-content {
+    flex: 1;
+    padding-top: 4px;
+  }
+
+  .step-info {
+    margin-bottom: 8px;
+  }
+
+  .step-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .step-approver {
+    font-size: 14px;
+    color: #666;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .step-time {
+    font-size: 12px;
+    color: #999;
+    display: block;
+  }
+
+  .step-opinion {
+    background: #f8f9fa;
+    padding: 12px;
+    border-radius: 8px;
+    border-left: 4px solid #52c41a;
+  }
+
+  .opinion-label {
+    font-size: 12px;
+    color: #666;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  .opinion-content {
+    font-size: 14px;
+    color: #333;
+    line-height: 1.5;
+  }
+
+  .approval-input {
+    background: #fff;
+    margin: 16px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  .input-header {
+    padding: 16px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #f8f9fa;
+  }
+
+  .input-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  .input-content {
+    padding: 16px;
+  }
+
+  .footer-actions {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: #fff;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    padding: 16px;
+    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
+    z-index: 1000;
+  }
+
+  .reject-btn {
+    width: 120px;
+    background: #ff4d4f;
+    color: #fff;
+  }
+
+  .approve-btn {
+    width: 120px;
+    background: #52c41a;
+    color: #fff;
+  }
+
+  /* 閫傞厤u-button鏍峰紡 */
+  :deep(.u-button) {
+    border-radius: 6px;
+  }
+
+  @keyframes pulse {
+    0% {
+      box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7);
+    }
+    70% {
+      box-shadow: 0 0 0 10px rgba(24, 144, 255, 0);
+    }
+    100% {
+      box-shadow: 0 0 0 0 rgba(24, 144, 255, 0);
+    }
+  }
+  .signature-section {
+    background: #fff;
+    padding: 12px 16px 16px;
+    border-top: 1px solid #f0f0f0;
+  }
+  .signature-header {
+    margin-bottom: 8px;
+  }
+  .signature-title {
+    font-size: 14px;
+    font-weight: 600;
+    color: #333;
+  }
+  .signature-box {
+    width: 100%;
+    height: 180px;
+    background: #fff;
+    border: 1px dashed #d9d9d9;
+    border-radius: 8px;
+    overflow: hidden;
+  }
+  .signature-actions {
+    margin-top: 8px;
+    display: flex;
+    justify-content: flex-end;
+  }
+  /* 宸ュ叿鏍忔寜閽牱寮� */
+  :deep(.ql-toolbar.ql-snow .ql-button) {
+    height: 28px;
+    width: 28px;
+    padding: 4px;
+  }
+  :deep(.ql-toolbar.ql-snow .ql-picker-label) {
+    height: 28px;
+    padding: 4px 8px;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/managementMeetings/meetSummary/index.vue b/src/pages/managementMeetings/meetSummary/index.vue
new file mode 100644
index 0000000..05f06d9
--- /dev/null
+++ b/src/pages/managementMeetings/meetSummary/index.vue
@@ -0,0 +1,352 @@
+// 瀹℃壒绠$悊涓婚〉闈�
+<template>
+  <view class="sales-account">
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+    <PageHeader title="浼氳鎬荤粨"
+                @back="goBack" />
+    <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text"
+                    placeholder="璇疯緭鍏ヤ細璁富棰�"
+                    v-model="searchForm.title"
+                    clearable />
+        </view>
+        <view class="search-button"
+              @click="getList">
+          <up-icon name="search"
+                   size="24"
+                   color="#999"></up-icon>
+        </view>
+      </view>
+    </view>
+    <!-- 瀹℃壒鍒楄〃 -->
+    <view class="ledger-list"
+          v-if="ledgerList.length > 0">
+      <view v-for="(item, index) in ledgerList"
+            :key="index">
+        <view class="ledger-item">
+          <view class="item-header">
+            <view class="item-left">
+              <view class="document-icon">
+                <up-icon name="file-text"
+                         size="16"
+                         color="#ffffff"></up-icon>
+              </view>
+              <text class="item-id">{{ item.title }}</text>
+            </view>
+            <view class="item-tag">
+              <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">鐢宠浜�</text>
+              <text class="detail-value">{{ item.applicant }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">涓荤悊浜�</text>
+              <text class="detail-value">{{ item.host }}</text>
+            </view>
+            <view class="detail-row-approveReason">
+              <text class="detail-label">浼氳鏃堕棿</text>
+              <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">浼氳鍦扮偣</text>
+              <text class="detail-value">{{ item.location }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍙備細浜烘暟</text>
+              <text class="detail-value">{{ item.participants.length }}</text>
+            </view>
+            <up-divider></up-divider>
+            <view class="actions">
+              <u-button type="primary"
+                        size="small"
+                        class="action-btn view"
+                        @click="viewDetail(item)">
+                璇︽儏
+              </u-button>
+              <u-button type="success"
+                        size="small"
+                        class="action-btn approve"
+                        :disabled="item.status != 0"
+                        @click="approve(item)">
+                娣诲姞绾
+              </u-button>
+            </view>
+            <!-- <view class="detail-info"
+                  style="align-items: flex-end;">
+              <view class="detail-row">
+               
+              </view>
+            </view> -->
+          </view>
+        </view>
+      </view>
+    </view>
+    <view v-else
+          class="no-data">
+      <text>鏆傛棤鏁版嵁</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref, toRefs, reactive } from "vue";
+  import PageHeader from "@/components/PageHeader.vue";
+  import {
+    getMeetingPublish,
+    getRoomEnum,
+  } from "@/api/managementMeetings/meetExamine";
+  import { getStaffOnJob } from "@/api/personnelManagement/onboarding";
+  import { onShow } from "@dcloudio/uni-app";
+  import useUserStore from "@/store/modules/user";
+  import dayjs from "dayjs";
+
+  const userStore = useUserStore();
+  // 鏁版嵁
+  const ledgerList = ref([]);
+  const data = reactive({
+    searchForm: {
+      title: "",
+    },
+  });
+  const { searchForm } = toRefs(data);
+
+  // 杩斿洖涓婁竴椤�
+  const goBack = () => {
+    uni.navigateBack();
+  };
+  // 鎴块棿鏋氫妇
+  const roomEnum = ref([]);
+  // 鎴块棿鏋氫妇鏌ヨ
+  const getRoomEnumList = () => {
+    return getRoomEnum()
+      .then(res => {
+        console.log(res.data, "res.data");
+        roomEnum.value = res.data;
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鍛樺伐鍒楄〃
+  const staffList = ref([]);
+  // 鍛樺伐鍒楄〃鏌ヨ
+  const getStaffOnJobList = () => {
+    return getStaffOnJob()
+      .then(res => {
+        console.log(res.data, "res.data");
+        staffList.value = res.data;
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鏌ヨ鍒楄〃
+  const getList = () => {
+    showLoadingToast("鍔犺浇涓�...");
+    const page = {
+      current: -1,
+      size: -1,
+    };
+    getMeetingPublish({
+      ...page,
+      ...searchForm.value,
+    })
+      .then(res => {
+        console.log(res.data.records, "res.data.records");
+        ledgerList.value = res.data.records.map(it => {
+          console.log(it, "it1");
+          let room = roomEnum.value.find(room => it.roomId === room.id);
+          it.location = `${room.name}(${room.location})`;
+          let staffs = JSON.parse(it.participants);
+          it.staffCount = staffs.size;
+          it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format(
+            "HH:mm:ss"
+          )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`;
+          it.participants = staffList.value
+            .filter(staff => staffs.some(id => id == staff.id))
+            .map(staff => {
+              return {
+                id: staff.id,
+                name: `${staff.staffName}(${staff.postJob})`,
+              };
+            });
+          console.log(it, "it2");
+
+          return it;
+        });
+
+        closeToast();
+      })
+      .catch(() => {
+        closeToast();
+      });
+  };
+  // 鏄剧ず鍔犺浇鎻愮ず
+  const showLoadingToast = message => {
+    uni.showLoading({
+      title: message,
+      mask: true,
+    });
+  };
+  const formatDateTime = dateTime => {
+    if (!dateTime) return "";
+    return dateTime.replace(" ", "\n");
+  };
+
+  // 鍏抽棴鎻愮ず
+  const closeToast = () => {
+    uni.hideLoading();
+  };
+
+  // 鏍煎紡鍖栧洖娆炬柟寮�
+  const formatReceiptType = params => {
+    if (params == 0) {
+      return "寰呭鎵�";
+    } else if (params == 1) {
+      return "宸查�氳繃";
+    } else if (params == 2) {
+      return "鏈�氳繃";
+    } else if (params == 3) {
+      return "宸插彇娑�";
+    } else {
+      return "鏈煡";
+    }
+  };
+  // 鑾峰彇鏍囩鏍峰紡绫�
+  const getTagClass = type => {
+    if (type == 0) {
+      return "info";
+    } else if (type == 1) {
+      return "success";
+    } else if (type == 2) {
+      return "warning";
+    } else if (type == 3) {
+      return "danger";
+    } else {
+      return "info";
+    }
+  };
+
+  // 鐐瑰嚮瀹℃牳
+  const approve = item => {
+    // uni.setStorageSync("approveId", item.approveId);
+    uni.navigateTo({
+      url:
+        "/pages/managementMeetings/meetSummary/approve?item=" +
+        JSON.stringify(item) +
+        "&edit=true",
+    });
+  };
+  // 鏌ョ湅璇︽儏
+  const viewDetail = item => {
+    uni.navigateTo({
+      url:
+        "/pages/managementMeetings/meetSummary/approve?item=" +
+        JSON.stringify(item) +
+        "&edit=false",
+    });
+  };
+
+  onShow(async () => {
+    // 椤甸潰鍔犺浇瀹屾垚鍚庣殑鍒濆鍖栭�昏緫
+    try {
+      // 绛夊緟涓や釜寮傛鏂规硶鎵ц瀹屾垚
+      await Promise.all([getRoomEnumList(), getStaffOnJobList()]);
+      // 涓や釜鏂规硶鎵ц瀹屾垚鍚庡啀鎵ц getList()
+      getList();
+    } catch (error) {
+      console.error("鍒濆鍖栨暟鎹け璐�:", error);
+      // 鍗充娇鍑洪敊涔熸墽琛� getList()锛岀‘淇濋〉闈㈣兘姝e父鍔犺浇
+      getList();
+    }
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "../../../styles/sales-common.scss";
+
+  .u-divider {
+    margin: 0 !important;
+  }
+
+  // 鏂囨。鍥炬爣鏍峰紡 - 瑕嗙洊鍏叡鏍峰紡涓殑鑳屾櫙鑹�
+  .document-icon {
+    background: #ed8d05;
+  }
+
+  // 娴姩鎸夐挳鏍峰紡 - 瑕嗙洊鍏叡鏍峰紡涓殑鑳屾櫙鑹�
+  .fab-button {
+    background: #ed8d05;
+  }
+
+  // 鐗规湁鏍峰紡
+  .detail-row-user {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  .detail-row-approveReason {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 8px;
+  }
+
+  .detail-value.highlightBlue {
+    color: #2979ff;
+    font-weight: 500;
+  }
+
+  .detail-value.highlightYellow {
+    color: #ed8d05;
+    font-weight: 500;
+  }
+
+  .approver-value {
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .approver-chip {
+    display: inline-flex;
+    align-items: center;
+    gap: 6px;
+    background: #f0f6ff;
+    color: #2b7cff;
+    border: 1px solid #e0efff;
+    border-radius: 999px;
+    padding: 4px 10px;
+    max-width: 100%;
+  }
+
+  .approver-name {
+    font-size: 12px;
+    color: #2b7cff;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .actions {
+    display: flex;
+    gap: 10px;
+    align-items: center;
+    justify-content: flex-end;
+    margin-top: 18rpx;
+  }
+
+  .action-btn {
+    border-radius: 16px;
+    height: 28px;
+    line-height: 28px;
+    padding: 0 12px;
+  }
+</style>
\ No newline at end of file

--
Gitblit v1.9.3