zhangwencui
7 天以前 8a22c10dd6a1a635e44b97056efb6f5627b395e4
会议看板
已添加1个文件
已修改6个文件
475 ■■■■■ 文件已修改
src/api/collaborativeApproval/approvalProcess.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/managementMeetings/meetExamine.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/collaborativeApproval/detail.vue 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/meetSummary/approve.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/meetingBoard/index.vue 394 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/approvalProcess.js
@@ -30,6 +30,7 @@
        data: query,
    })
}
// ä¿®æ”¹å®¡æ‰¹æµç¨‹
export function approveProcessUpdate(query) {
    return request({
src/api/managementMeetings/meetExamine.js
@@ -45,3 +45,16 @@
        data: data,
    });
}
export function getMeetSummary(){
    return request({
        url: "/meeting/getMeetSummary",
        method: "get",
    });
}
export function getMeetSummaryItems(){
    return request({
        url: "/meeting/getMeetSummaryItems",
        method: "get",
    });
}
src/pages.json
@@ -359,6 +359,13 @@
      }
    },
    {
      "path": "pages/managementMeetings/meetingBoard/index",
      "style": {
        "navigationBarTitleText": "会议看板",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/managementMeetings/meetSummary/approve",
      "style": {
        "navigationBarTitleText": "总结",
src/pages/cooperativeOffice/collaborativeApproval/detail.vue
@@ -53,24 +53,36 @@
                 readonly
                 placeholder="请选择"
                 @click="showDatePicker" />
        <template #right>
          <up-icon name="arrow-right"
                   @click="showDatePicker"></up-icon>
        </template>
      </u-form-item>
      <!-- approveType=2 è¯·å‡ç›¸å…³å­—段 -->
      <template v-if="approveType === 2">
        <u-form-item prop="startDate"
                     label="请假开始时间"
                     label="开始时间"
                     required>
          <u-input v-model="form.startDate"
                   readonly
                   placeholder="请选择开始时间"
                   placeholder="请假开始时间"
                   @click="showStartDatePicker" />
          <template #right>
            <up-icon name="arrow-right"
                     @click="showStartDatePicker"></up-icon>
          </template>
        </u-form-item>
        <u-form-item prop="endDate"
                     label="请假结束时间"
                     label="结束时间"
                     required>
          <u-input v-model="form.endDate"
                   readonly
                   placeholder="请选择结束时间"
                   placeholder="请假结束时间"
                   @click="showEndDatePicker" />
          <template #right>
            <up-icon name="arrow-right"
                     @click="showEndDatePicker"></up-icon>
          </template>
        </u-form-item>
      </template>
      <!-- approveType=3 å‡ºå·®ç›¸å…³å­—段 -->
@@ -400,7 +412,21 @@
            .map(node => node.userId)
            .join(",");
          form.value.approveType = approveType.value;
          console.log("form.value---", form.value);
          form.value.approveDeptId = Number(form.value.approveDeptId);
          // const submitForm = {
          //   approveDeptId: form.value.approveDeptId,
          //   approveDeptName: form.value.approveDeptName,
          //   approveReason: form.value.approveReason,
          //   approveTime: form.value.approveTime,
          //   approveType: form.value.approveType,
          //   approveUser: form.value.approveUser,
          //   approveUserIds: form.value.approveUserIds,
          //   endDate: form.value.endDate,
          //   startDate: form.value.startDate,
          // };
          // console.log("form.value---", form.value);
          // console.log("submitForm", submitForm);
          if (operationType.value === "add" || currentApproveStatus.value == 3) {
            approveProcessAdd(form.value).then(res => {
              showToast("提交成功");
src/pages/index.vue
@@ -331,6 +331,14 @@
      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: "协同审批",
    },
@@ -538,6 +546,16 @@
          url: "/pages/managementMeetings/meetSummary/index",
        });
        break;
      case "会议看板":
        uni.navigateTo({
          url: "/pages/managementMeetings/meetingBoard/index",
        });
        break;
      case "通知公告":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/noticeManagement/index",
        });
        break;
      case "协同审批":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/collaborativeApproval/index",
src/pages/managementMeetings/meetSummary/approve.vue
@@ -82,6 +82,12 @@
  const approvalData = ref({});
  const approvalSteps = ref([]);
  const isEdit = ref(false);
  const showToast = message => {
    uni.showToast({
      title: message,
      icon: "none",
    });
  };
  onLoad(options => {
    console.log(options, "options");
    if (options.item) {
src/pages/managementMeetings/meetingBoard/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,394 @@
// å®¡æ‰¹ç®¡ç†ä¸»é¡µé¢
<template>
  <view class="sales-account">
    <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
    <PageHeader title="会议看板"
                @back="goBack" />
    <!-- å®¡æ‰¹åˆ—表 -->
    <view class="topbox">
      <view class="boxItem">
        <view class="boxItem-num">
          {{stats.total}}
        </view>
        <view class="boxItem-title">
          æ€»ä¼šè®®æ•°
        </view>
      </view>
      <view class="boxItem">
        <view class="boxItem-num">
          {{stats.underWay}}
        </view>
        <view class="boxItem-title">
          è¿›è¡Œä¸­
        </view>
      </view>
      <view class="boxItem">
        <view class="boxItem-num">
          {{stats.completed}}
        </view>
        <view class="boxItem-title">
          å·²å®Œæˆ
        </view>
      </view>
      <view class="boxItem">
        <view class="boxItem-num">
          {{stats.toStart}}
        </view>
        <view class="boxItem-title">
          å³å°†å¼€å§‹
        </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.host }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">参会人数</text>
              <text class="detail-value">{{ item.participants.length }}</text>
            </view>
            <view class="detail-row-approveReason">
              <text class="detail-label">会议时间</text>
              <text class="detail-value highlightBlue">{{dayjs(item.startTime).format("YYYY-MM-DD")}}
                {{ formatTime(item.startTime) }} - {{ formatTime(item.endTime) }}</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> -->
            <u-collapse @change="change"
                        @close="close"
                        @open="open"
                        accordion
                        border
                        :duration="300">
              <u-collapse-item :title="`会议纪要 ${item.content ? '' : '(无)'}`"
                               :name="`meeting-${index}`">
                <view class="meeting-content">
                  <view v-if="item.content"
                        v-html="item.content"
                        class="content-html"></view>
                  <view v-else
                        class="no-content">
                    <text>暂无会议纪要内容</text>
                  </view>
                </view>
              </u-collapse-item>
            </u-collapse>
          </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 {
    getMeetSummaryItems,
    getMeetSummary,
  } from "@/api/managementMeetings/meetExamine";
  import { onShow } from "@dcloudio/uni-app";
  import dayjs from "dayjs";
  import useUserStore from "@/store/modules/user";
  // æ•°æ®
  const ledgerList = ref([]);
  const data = reactive({
    searchForm: {
      title: "",
    },
  });
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  // ç»Ÿè®¡æ•°æ®
  const stats = ref({});
  const getnum = () => {
    getMeetSummary().then(res => {
      stats.value = res.data;
    });
  };
  // æ ¼å¼åŒ–æ—¶é—´
  const formatTime = timeStr => {
    const date = new Date(timeStr);
    return date.toLocaleTimeString("zh-CN", {
      hour: "2-digit",
      minute: "2-digit",
    });
  };
  // æŸ¥è¯¢åˆ—表
  const getList = () => {
    showLoadingToast("加载中...");
    getMeetSummaryItems()
      .then(res => {
        ledgerList.value = res.data.map(item => {
          return {
            ...item,
            participants: JSON.parse(item.participants),
          };
        });
        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 "warning";
    } else if (type == 2) {
      return "success";
    } else {
      return "info";
    }
  };
  // u-collapse äº‹ä»¶å¤„理函数
  const change = name => {
    console.log("展开的面板名:", name);
  };
  const close = name => {
    console.log("关闭的面板名:", name);
  };
  const open = name => {
    console.log("打开的面板名:", name);
  };
  onShow(async () => {
    // é¡µé¢åŠ è½½å®ŒæˆåŽçš„åˆå§‹åŒ–é€»è¾‘
    try {
      // ä¸¤ä¸ªæ–¹æ³•执行完成后再执行 getList()
      getList();
      getnum();
    } catch (error) {
      console.error("初始化数据失败:", error);
      // å³ä½¿å‡ºé”™ä¹Ÿæ‰§è¡Œ getList(),确保页面能正常加载
      getList();
      getnum();
    }
  });
</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;
  }
  .topbox {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-left: 20px;
    margin-right: 20px;
    margin-top: 10px;
  }
  .boxItem {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: #fff;
    width: 24%;
    padding-top: 10px;
    padding-bottom: 10px;
    border-radius: 6px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
  }
  .boxItem-num {
    margin-bottom: 5px;
    font-weight: 500;
    color: #2979ff;
  }
  // ä¼šè®®çºªè¦æ ·å¼
  .meeting-content {
    padding: 15px;
    line-height: 1.6;
    font-size: 14px;
  }
  .content-html {
    color: #333;
    word-break: break-word;
  }
  .content-html :deep(p) {
    margin-bottom: 10px;
  }
  .content-html :deep(ul),
  .content-html :deep(ol) {
    margin-bottom: 10px;
    padding-left: 20px;
  }
  .content-html :deep(li) {
    margin-bottom: 5px;
  }
  .no-content {
    color: #999;
    text-align: center;
    padding: 20px 0;
    font-size: 14px;
  }
  // u-collapse æ ·å¼ä¼˜åŒ–
  :deep(.u-collapse) {
    margin-top: 10px;
    border-radius: 6px;
    overflow: hidden;
  }
  :deep(.u-collapse-item__header) {
    font-size: 14px;
    font-weight: 500;
  }
  :deep(.u-collapse-item__content) {
    background-color: #fafafa;
    border-top: 1px solid #f0f0f0;
  }
</style>