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