bd96ac239ba897edc2f8bed5cfb426e0f54ee877..1bda9babdf0316852ee5972690742f63c79595d6
6 天以前 zhangwencui
用印管理以及知识库部分逻辑修改
1bda9b 对比 | 目录
6 天以前 zhangwencui
会议看板富文本展示修改
77c75a 对比 | 目录
6 天以前 zhangwencui
知识库
27977c 对比 | 目录
6 天以前 zhangwencui
会议看板
8a22c1 对比 | 目录
已添加7个文件
已修改6个文件
2117 ■■■■■ 文件已修改
src/api/collaborativeApproval/approvalProcess.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/managementMeetings/knowledgeBase.js 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/managementMeetings/meetExamine.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/managementMeetings/sealManagement.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/collaborativeApproval/detail.vue 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/knowledgeBase/detail.vue 459 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/knowledgeBase/index.vue 310 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/meetSummary/approve.vue 90 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/meetingBoard/index.vue 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/sealManagement/detail.vue 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/sealManagement/index.vue 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/approvalProcess.js
@@ -30,6 +30,7 @@
        data: query,
    })
}
// ä¿®æ”¹å®¡æ‰¹æµç¨‹
export function approveProcessUpdate(query) {
    return request({
src/api/managementMeetings/knowledgeBase.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
// çŸ¥è¯†åº“相关 API
import request from '@/utils/request';
export function listKnowledgeBase(params) {
  return request({
    url: '/knowledgeBase/getList',
    method: 'get',
    params
  });
}
// æ–°å¢žçŸ¥è¯†åº“
export function addKnowledgeBase(data) {
  return request({
    url: "/knowledgeBase/add",
    method: "post",
    data: data,
  });
}
// ä¿®æ”¹çŸ¥è¯†åº“
export function updateKnowledgeBase(data) {
  return request({
    url: "/knowledgeBase/update",
    method: "post",
    data: data,
  });
}
// åˆ é™¤çŸ¥è¯†åº“
export function delKnowledgeBase(query) {
  return request({
    url: "/knowledgeBase/delete",
    method: "delete",
    data: query,
  });
}
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/api/managementMeetings/sealManagement.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
import request from "@/utils/request";
// æŸ¥è¯¢å°ç« ç”³è¯·åˆ—表
export function listSealApplication(page,query) {
  return request({
    url: "/sealApplicationManagement/getList",
    method: "get",
    params: {
      ...page,
      ...query},
  });
}
// ä¿®æ”¹å°ç« ç”³è¯·
export function updateSealApplication(data) {
  return request({
    url: "/sealApplicationManagement/update",
    method: "post",
    data: data,
  });
}
export function addSealApplication(data) {
  return request({
    url: "/sealApplicationManagement/add",
    method: "post",
    data: data,
  });
}
src/pages.json
@@ -359,6 +359,13 @@
      }
    },
    {
      "path": "pages/managementMeetings/meetingBoard/index",
      "style": {
        "navigationBarTitleText": "会议看板",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/managementMeetings/meetSummary/approve",
      "style": {
        "navigationBarTitleText": "总结",
@@ -366,6 +373,34 @@
      }
    },
    {
      "path": "pages/managementMeetings/knowledgeBase/index",
      "style": {
        "navigationBarTitleText": "知识库",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/managementMeetings/sealManagement/index",
      "style": {
        "navigationBarTitleText": "用印管理",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/managementMeetings/sealManagement/detail",
      "style": {
        "navigationBarTitleText": "用印详情",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/managementMeetings/knowledgeBase/detail",
      "style": {
        "navigationBarTitleText": "知识库详情",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/cooperativeOffice/collaborativeApproval/detail",
      "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,13 +331,29 @@
      label: "会议总结",
    },
    {
      icon: "/static/images/icon/xietongshenpi@2x.png",
      label: "协同审批",
      icon: "/static/images/icon/qingjiaguanli@2x.png",
      label: "会议看板",
    },
    {
      icon: "/static/images/icon/kehubaifang@2x.png",
      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: "协同审批",
    // },
    // {
    //   icon: "/static/images/icon/kehubaifang@2x.png",
    //   label: "客户拜访",
    // },
  ]);
  // ç”Ÿäº§ç®¡æŽ§åŠŸèƒ½æ•°æ®
@@ -538,6 +554,26 @@
          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/managementMeetings/knowledgeBase/index",
        });
        break;
      case "用印管理":
        uni.navigateTo({
          url: "/pages/managementMeetings/sealManagement/index",
        });
        break;
      case "协同审批":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/collaborativeApproval/index",
src/pages/managementMeetings/knowledgeBase/detail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,459 @@
<template>
  <view class="client-visit-detail">
    <PageHeader :title="detailType === 1 ? '新增知识库' : '知识库详情'"
                @back="goBack" />
    <u-form ref="formRef"
            label-width="90">
      <!-- å®¢æˆ·ä¿¡æ¯ -->
      <!-- <u-cell-group title="知识信息"> -->
      <u-form-item label="知识标题"
                   prop="title"
                   required
                   border-bottom>
        <u-input v-model="form.title"
                 :readonly="readonly"
                 placeholder="请输入知识标题" />
      </u-form-item>
      <u-form-item label="知识类型"
                   prop="type"
                   required
                   border-bottom>
        <u-input v-model="equipmentname"
                 readonly
                 placeholder="请选择知识类型"
                 @click="showEquipmentSheet = true" />
        <template v-if="!readonly"
                  #right>
          <up-icon name="arrow-right"
                   @click="openEquipmentSheet"></up-icon>
        </template>
      </u-form-item>
      <u-form-item label="适用场景"
                   prop="scenario"
                   border-bottom>
        <u-input v-model="form.scenario"
                 readonly="readonly"
                 placeholder="请输入适用场景" />
      </u-form-item>
      <u-form-item label="解决效率"
                   prop="status"
                   border-bottom>
        <u-input v-model="statusname"
                 readonly
                 placeholder="请选择解决效率"
                 @click="showStatusSheet = true" />
        <template v-if="!readonly"
                  #right>
          <up-icon name="arrow-right"
                   @click="showStatusSheet = true"></up-icon>
        </template>
      </u-form-item>
      <u-form-item label="问题描述"
                   required
                   prop="remark"
                   border-bottom>
        <u-textarea v-model="form.problem"
                    type="textarea"
                    rows="4"
                    :disabled="readonly"
                    placeholder="请输入问题描述" />
      </u-form-item>
      <u-form-item label="解决方案"
                   prop="solution"
                   required
                   border-bottom>
        <u-textarea v-model="form.solution"
                    type="textarea"
                    rows="4"
                    :disabled="readonly"
                    placeholder="请输入解决方案" />
      </u-form-item>
      <u-form-item label="关键要点"
                   prop="keyPoints"
                   border-bottom>
        <u-textarea v-model="form.keyPoints"
                    type="textarea"
                    rows="4"
                    :disabled="readonly"
                    placeholder="请输入关键要点,用逗号分隔" />
      </u-form-item>
      <u-form-item label="创建人"
                   prop="creator"
                   border-bottom>
        <u-input v-model="form.creator"
                 :readonly="readonly"
                 placeholder="请输入创建人" />
      </u-form-item>
      <u-form-item label="使用次数"
                   prop="usageCount"
                   border-bottom>
        <uni-number-box v-model="form.usageCount"
                        :min="0"
                        :disabled="readonly"
                        placeholder="请输入使用次数" />
      </u-form-item>
      <!-- </u-cell-group> -->
      <!-- æäº¤æŒ‰é’® -->
      <view v-if="!readonly"
            class="footer-btns">
        <u-button class="cancel-btn"
                  @click="goBack">取消</u-button>
        <u-button class="sign-btn"
                  type="primary"
                  @click="handleSubmit"
                  :loading="loading">保存</u-button>
      </view>
    </u-form>
    <!-- è®¾å¤‡é…ç½®é€‰æ‹©å™¨ -->
    <up-action-sheet :show="showEquipmentSheet"
                     :actions="equipmentOptions"
                     @select="handleEquipmentChange"
                     @close="showEquipmentSheet = false" />
    <!-- <u-popup :show="showEquipmentSheet"
             mode="bottom"
             @close="showEquipmentSheet = false"
             height="200px">
      <view class="popup-content">
        <view class="popup-body">
          <u-checkbox-group v-model="form.equipment"
                            @change="handleEquipmentChange"
                            icon-placement="right"
                            placement="row">
            <view style="width:100%;padding:10px;margin-top:20px;">
              <u-checkbox v-for="option in equipmentOptions"
                          :key="option.value"
                          :name="option.value"
                          :label="option.name"
                          class="checkbox-item"></u-checkbox>
            </view>
          </u-checkbox-group>
        </view>
      </view>
    </u-popup> -->
    <!-- çŠ¶æ€é€‰æ‹©å™¨ -->
    <up-action-sheet :show="showStatusSheet"
                     :actions="statusOptions"
                     @select="onStatusSelect"
                     @close="showStatusSheet = false" />
  </view>
</template>
<script setup>
  // æ›¿æ¢ toast æ–¹æ³•
  defineOptions({ name: "meeting-settings-detail" });
  const showToast = message => {
    uni.showToast({
      title: message,
      icon: "none",
    });
  };
  import { ref, onMounted, computed } from "vue";
  import PageHeader from "@/components/PageHeader.vue";
  import useUserStore from "@/store/modules/user";
  import { useDict } from "@/utils/dict";
  import { onLoad } from "@dcloudio/uni-app";
  import {
    addKnowledgeBase,
    updateKnowledgeBase,
  } from "@/api/managementMeetings/knowledgeBase";
  const userStore = useUserStore();
  // è¡¨å•数据
  const form = ref({
    title: "",
    type: "",
    scenario: "",
    efficiency: "",
    problem: "",
    solution: "",
    keyPoints: "",
    creator: "",
    usageCount: 0,
  });
  const { knowledge_type } = useDict("knowledge_type");
  const knowledgeTypeOptions = computed(() => knowledge_type?.value || []);
  const equipmentOptions = ref([]);
  const statusOptions = ref([
    { value: "high", name: "显著提升" },
    { value: "medium", name: "一般提升" },
    { value: "low", name: "轻微提升" },
  ]);
  //// é¡µé¢çŠ¶æ€
  const loading = ref(false);
  const formRef = ref(null);
  const showEquipmentSheet = ref(false);
  const showStatusSheet = ref(false);
  const openEquipmentSheet = () => {
    showEquipmentSheet.value = true;
  };
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  const statusname = ref("");
  // çŠ¶æ€é€‰æ‹©
  const onStatusSelect = action => {
    form.value.efficiency = action.value;
    statusname.value = action.name;
    showStatusSheet.value = false;
  };
  const equipmentname = ref("");
  // è®¾å¤‡é…ç½®é€‰æ‹©
  const handleEquipmentChange = val => {
    form.value.type = val.value;
    equipmentname.value = val.name;
    showEquipmentSheet.value = false;
  };
  // æäº¤è¡¨å•
  const handleSubmit = async () => {
    if (!form.value.title) {
      showToast("请输入标题");
      return;
    }
    if (!form.value.scenario) {
      showToast("请输入适用场景");
      return;
    }
    if (!form.value.problem) {
      showToast("请输入问题描述");
      return;
    }
    if (!form.value.solution) {
      showToast("请输入解决方案");
      return;
    }
    try {
      loading.value = true;
      if (detailType.value === 1) {
        addKnowledgeBase(form.value).then(res => {
          if (res.code !== 200) {
            showToast("保存失败,请重试");
            return;
          }
          loading.value = false;
          showToast("保存成功");
          setTimeout(() => {
            goBack();
          }, 500);
        });
      } else if (detailType.value === 2) {
        updateKnowledgeBase(form.value).then(res => {
          if (res.code !== 200) {
            showToast("保存失败,请重试");
            return;
          }
          loading.value = false;
          showToast("保存成功");
          setTimeout(() => {
            goBack();
          }, 500);
        });
      }
    } catch (e) {
      loading.value = false;
      console.error("保存失败:", e);
      showToast("保存失败,请重试");
    }
  };
  // åˆå§‹åŒ–页面数据
  const initPageData = () => {
    // ä»Žæœ¬åœ°å­˜å‚¨ä¸­èŽ·å–ä¼šè®® room æ•°æ®
    const meetingRoom = uni.getStorageSync("meetingRoom");
    if (meetingRoom) {
      form.value = JSON.parse(JSON.stringify(meetingRoom));
      if (meetingRoom.equipment) {
        if (Array.isArray(meetingRoom.equipment)) {
          form.value.equipment = meetingRoom.equipment;
        } else {
          form.value.equipment = meetingRoom.equipment.split(",");
        }
      }
      statusname.value = meetingRoom.status === 1 ? "启用" : "禁用";
      // æ¸…除本地存储中的数据,避免下次打开时仍然显示
      uni.removeStorageSync("meetingRoom");
    }
  };
  const readonly = ref(false);
  const detailType = ref(1);
  const knowledgeId = ref("");
  onLoad(options => {
    detailType.value = Number(options.detailType);
    knowledgeId.value = options.id || "";
    // å¦‚果是编辑或查看模式,获取知识详情
    if (knowledgeId.value && (detailType.value === 2 || detailType.value === 3)) {
      // getKnowledgeDetail(knowledgeId.value);
      equipmentname.value =
        equipmentOptions.value.find(item => item.value === form.value.type)
          ?.name || "";
      statusname.value =
        statusOptions.value.find(item => item.value === form.value.efficiency)
          ?.name || "";
    }
    // æŸ¥çœ‹æ¨¡å¼è®¾ç½®åªè¯»
    if (detailType.value === 3) {
      readonly.value = true;
    }
  });
  onMounted(() => {
    // ä»Žæœ¬åœ°å­˜å‚¨ä¸­èŽ·å–çŸ¥è¯†æ•°æ®
    const knowledgeBase = uni.getStorageSync("knowledgeBase");
    if (knowledgeBase) {
      form.value = JSON.parse(JSON.stringify(knowledgeBase));
    }
    initPageData();
    equipmentOptions.value = knowledgeTypeOptions.value.map(item => ({
      value: item.value,
      name: item.label,
    }));
    if (detailType.value === 1) {
      form.value = {
        title: "",
        type: "",
        scenario: "",
        efficiency: "",
        problem: "",
        solution: "",
        keyPoints: "",
        creator: "",
        usageCount: 0,
      };
      equipmentname.value = "";
      statusname.value = "";
    }
    if (detailType.value != 1) {
      equipmentname.value =
        equipmentOptions.value.find(item => item.value === form.value.type)
          ?.name || "";
      statusname.value =
        statusOptions.value.find(item => item.value === form.value.efficiency)
          ?.name || "";
    }
  });
</script>
<style scoped lang="scss">
  @import "@/static/scss/form-common.scss";
  .client-visit {
    min-height: 100vh;
    background: #f8f9fa;
    padding-bottom: 5rem;
  }
  .footer-btns {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background: #fff;
    display: flex;
    justify-content: space-around;
    align-items: center;
    padding: 0.75rem 0;
    box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05);
    z-index: 1000;
  }
  .cancel-btn {
    font-weight: 400;
    font-size: 1rem;
    color: #666;
    background: #f5f5f5;
    border: 1px solid #ddd;
    width: 45%;
    height: 2.5rem;
    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
  }
  .sign-btn {
    font-weight: 500;
    font-size: 1rem;
    color: #fff;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border: none;
    width: 45%;
    height: 2.5rem;
    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
  }
  .location-icon {
    color: #1989fa;
    font-size: 1.2rem;
  }
  .selector-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    height: 100%;
  }
  .selector-text {
    font-size: 14px;
    color: #333;
  }
  .popup-content {
    padding: 20rpx;
  }
  .popup-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20rpx;
  }
  .popup-title {
    font-size: 16px;
    font-weight: bold;
    color: #333;
  }
  .close-icon {
    font-size: 20px;
    color: #999;
  }
  .popup-body {
    max-height: 60vh;
    overflow-y: auto;
    margin-bottom: 20rpx;
  }
  .checkbox-item {
    margin-bottom: 15rpx;
    font-size: 14px;
  }
  .popup-footer {
    display: flex;
    justify-content: space-between;
    gap: 15rpx;
  }
  .cancel-btn-popup {
    flex: 1;
    border-radius: 8rpx;
  }
  .confirm-btn-popup {
    flex: 1;
    border-radius: 8rpx;
  }
  .checkbox-item {
    margin-top: 40rpx;
  }
</style>
src/pages/managementMeetings/knowledgeBase/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,310 @@
<template>
  <view class="sales-accoun">
    <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
    <PageHeader title="知识库"
                @back="goBack" />
    <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
    <view class="search-section">
      <view class="search-bar">
        <view class="search-input">
          <up-input class="search-text"
                    placeholder="请输入知识标题"
                    v-model="name"
                    @blur="getList"
                    clearable />
        </view>
        <view class="filter-button"
              @click="getList">
          <u-icon name="search"
                  size="24"
                  color="#999"></u-icon>
        </view>
      </view>
    </view>
    <!-- æ‹œè®¿è®°å½•列表 -->
    <view class="ledger-list"
          v-if="visitList.length > 0">
      <view v-for="(item, index) in visitList"
            :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>
          <up-divider></up-divider>
          <view class="item-details">
            <view class="detail-row">
              <text class="detail-label">知识类型</text>
              <text class="detail-value">{{ formatReceiptType(item.type) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">适用场景</text>
              <text class="detail-value">{{ item.scenario || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">解决效率</text>
              <u-tag size="mini"
                     :type="getTagClass(item.efficiency)">{{ formatReceiptType1(item.efficiency) }}</u-tag>
            </view>
            <view class="detail-row">
              <text class="detail-label">使用次数</text>
              <text class="detail-value">{{ item.usageCount }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">创建人</text>
              <text class="detail-value">{{ item.creator }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">创建时间</text>
              <text class="detail-value">{{ item.createTime }}</text>
            </view>
          </view>
          <!-- æŒ‰é’®åŒºåŸŸ -->
          <view class="action-buttons">
            <u-button type="info"
                      size="small"
                      class="action-btn"
                      @click="viewDetail(item,3)">
              æŸ¥çœ‹
            </u-button>
            <u-button type="error"
                      size="small"
                      class="action-btn"
                      @click="confirmDelete(item)">
              åˆ é™¤
            </u-button>
            <u-button type="primary"
                      size="small"
                      class="action-btn"
                      @click="viewDetail(item,2)">
              ç¼–辑
            </u-button>
          </view>
        </view>
      </view>
    </view>
    <view v-else
          class="no-data">
      <text>暂无会议室记录</text>
    </view>
    <!-- æµ®åŠ¨æ–°å¢žæŒ‰é’® -->
    <view class="fab-button"
          @click="addVisit">
      <up-icon name="plus"
               size="24"
               color="#ffffff"></up-icon>
    </view>
  </view>
</template>
<script setup>
  import { ref, onMounted, computed } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import { useDict } from "@/utils/dict";
  import PageHeader from "@/components/PageHeader.vue";
  import {
    listKnowledgeBase,
    delKnowledgeBase,
  } from "@/api/managementMeetings/knowledgeBase";
  import useUserStore from "@/store/modules/user";
  // æ›¿æ¢ toast æ–¹æ³•
  defineOptions({ name: "client-visit-index" });
  const showToast = message => {
    uni.showToast({
      title: message,
      icon: "none",
    });
  };
  import dayjs from "dayjs";
  const userStore = useUserStore();
  // æœç´¢å…³é”®è¯
  const name = ref("");
  // æ‹œè®¿è®°å½•数据
  const visitList = ref([]);
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  const { knowledge_type } = useDict("knowledge_type");
  // æ ¼å¼åŒ–回款方式
  const formatReceiptType = params => {
    return getKnowledgeTypeLabel(params);
  };
  const formatReceiptType1 = params => {
    if (params == "high") {
      return "显著提升";
    } else if (params == "medium") {
      return "一般提升";
    } else if (params == "low") {
      return "轻微提升";
    } else {
      return "未知";
    }
  };
  const getTagClass = type => {
    if (type == "high") {
      return "success";
    } else if (type == "medium") {
      return "warning";
    } else if (type == "low") {
      return "info";
    } else {
      return "info";
    }
  };
  const knowledgeTypeOptions = computed(() => knowledge_type?.value || []);
  // èŽ·å–çŸ¥è¯†ç±»åž‹æ ‡ç­¾
  const getKnowledgeTypeLabel = val => {
    console.log(knowledgeTypeOptions, "knowledgeTypeOptions");
    const item = knowledgeTypeOptions.value.find(
      i => String(i.value) === String(val)
    );
    return item ? item.label : val;
  };
  // æŸ¥è¯¢åˆ—表
  const getList = () => {
    showLoadingToast("加载中...");
    const params = {
      current: -1,
      size: -1,
      title: name.value,
    };
    listKnowledgeBase(params)
      .then(res => {
        visitList.value = res.data.records;
        closeToast();
      })
      .catch(() => {
        closeToast();
        showToast("获取数据失败");
      });
  };
  // æ˜¾ç¤ºåŠ è½½æç¤º
  const showLoadingToast = message => {
    uni.showLoading({
      title: message,
      mask: true,
    });
  };
  // å…³é—­æç¤º
  const closeToast = () => {
    uni.hideLoading();
  };
  // æ–°å¢žæ‹œè®¿ - è·³è½¬åˆ°ç™»è®°é¡µé¢
  const addVisit = () => {
    uni.navigateTo({
      url: "/pages/managementMeetings/knowledgeBase/detail?detailType=1",
    });
  };
  // ç¼–辑
  const viewDetail = (item, detailType) => {
    uni.setStorageSync("knowledgeBase", item);
    uni.navigateTo({
      url:
        "/pages/managementMeetings/knowledgeBase/detail?detailType=" +
        detailType +
        "&id=" +
        item.id,
    });
  };
  // åˆ é™¤ç¡®è®¤
  const confirmDelete = item => {
    uni.showModal({
      title: "删除确认",
      content: `确定要删除知识 "${item.title}" å—?`,
      success: res => {
        if (res.confirm) {
          deleteKnowledge(item.id);
        }
      },
    });
  };
  // æ‰§è¡Œåˆ é™¤
  const deleteKnowledge = id => {
    showLoadingToast("删除中...");
    delKnowledgeBase([id])
      .then(res => {
        closeToast();
        if (res.code === 200) {
          showToast("删除成功");
          getList(); // é‡æ–°èŽ·å–åˆ—è¡¨
        } else {
          showToast("删除失败");
        }
      })
      .catch(() => {
        closeToast();
        showToast("删除失败");
      });
  };
  onMounted(() => {
    getList();
  });
  onShow(() => {
    getList();
  });
</script>
<style scoped lang="scss">
  @import "../../../styles/sales-common.scss";
  // é¡µé¢ç‰¹å®šçš„æ ·å¼è¦†ç›–
  .sales-accoun {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
    padding-bottom: 80px;
  }
  // ç‰¹å®šçš„图标样式
  .document-icon {
    background: #667eea; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„背景色
  }
  // ç‰¹æœ‰æ ·å¼
  .visit-status {
    display: flex;
    align-items: center;
  }
  .detail-value {
    word-break: break-all; // ä¿ç•™é¡µé¢ç‰¹æœ‰çš„æ–‡æœ¬æ¢è¡Œæ ·å¼
    color: #333; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„æ–‡æœ¬é¢œè‰²
  }
  // çŠ¶æ€æ ·å¼
  .status-enabled {
    color: #28a745; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„æˆåŠŸé¢œè‰²
  }
  .status-disabled {
    color: #dc3545; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„错误颜色
  }
  // ç‰¹å®šçš„æµ®åŠ¨æŒ‰é’®æ ·å¼
  .fab-button {
    background: #667eea; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„背景色
    box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3); // ä¿æŒé¡µé¢ç‰¹æœ‰çš„阴影效果
  }
</style>
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) {
@@ -143,48 +149,48 @@
          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>`;
                                                                                                      <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 => {
src/pages/managementMeetings/meetingBoard/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,393 @@
// å®¡æ‰¹ç®¡ç†ä¸»é¡µé¢
<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"
                        class="content-html"><rich-text :nodes="item.content"></rich-text></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>
src/pages/managementMeetings/sealManagement/detail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,330 @@
<template>
  <view class="client-visit-detail">
    <PageHeader :title="detailType === 1 ? '新增知识库' : '知识库详情'"
                @back="goBack" />
    <u-form ref="formRef"
            label-width="90">
      <!-- å®¢æˆ·ä¿¡æ¯ -->
      <!-- <u-cell-group title="知识信息"> -->
      <u-form-item label="申请编号"
                   prop="applicationNum"
                   required
                   border-bottom>
        <u-input v-model="form.applicationNum"
                 :readonly="readonly"
                 placeholder="请输入申请编号" />
      </u-form-item>
      <u-form-item label="申请标题"
                   prop="title"
                   required
                   border-bottom>
        <u-input v-model="form.title"
                 :readonly="readonly"
                 placeholder="请输入申请标题" />
      </u-form-item>
      <u-form-item label="用印类型"
                   prop="sealType"
                   required
                   border-bottom>
        <u-input v-model="equipmentname"
                 readonly
                 placeholder="请选择用印类型"
                 @click="showEquipmentSheet = true" />
        <template v-if="!readonly"
                  #right>
          <up-icon name="arrow-right"
                   @click="openEquipmentSheet"></up-icon>
        </template>
      </u-form-item>
      <u-form-item label="申请原因"
                   prop="reason"
                   border-bottom>
        <u-textarea v-model="form.reason"
                    type="textarea"
                    rows="4"
                    :disabled="readonly"
                    placeholder="请输入申请原因" />
      </u-form-item>
      <u-form-item label="审批人"
                   prop="sealType"
                   required
                   border-bottom>
        <u-input v-model="statusname"
                 readonly
                 placeholder="请选择审批人"
                 @click="showStatusSheet = true" />
        <template v-if="!readonly"
                  #right>
          <up-icon name="arrow-right"
                   @click="showStatusSheet = true"></up-icon>
        </template>
      </u-form-item>
      <u-form-item label="紧急程度"
                   prop="urgency"
                   required
                   border-bottom>
        <u-radio-group v-model="form.urgency"
                       :disabled="readonly">
          <u-radio name="normal"
                   label="普通"
                   size="16" />
          <u-radio name="urgent"
                   label="紧急"
                   size="16" />
          <u-radio name="very-urgent"
                   label="特急"
                   size="16" />
        </u-radio-group>
      </u-form-item>
      <!-- </u-cell-group> -->
      <!-- æäº¤æŒ‰é’® -->
      <view v-if="!readonly"
            class="footer-btns">
        <u-button class="cancel-btn"
                  @click="goBack">取消</u-button>
        <u-button class="sign-btn"
                  type="primary"
                  @click="handleSubmit"
                  :loading="loading">保存</u-button>
      </view>
    </u-form>
    <!-- è®¾å¤‡é…ç½®é€‰æ‹©å™¨ -->
    <up-action-sheet :show="showEquipmentSheet"
                     :actions="equipmentOptions"
                     @select="handleEquipmentChange"
                     @close="showEquipmentSheet = false" />
    <!-- çŠ¶æ€é€‰æ‹©å™¨ -->
    <up-action-sheet :show="showStatusSheet"
                     :actions="userList"
                     @select="onStatusSelect"
                     @close="showStatusSheet = false" />
  </view>
</template>
<script setup>
  // æ›¿æ¢ toast æ–¹æ³•
  defineOptions({ name: "meeting-settings-detail" });
  const showToast = message => {
    uni.showToast({
      title: message,
      icon: "none",
    });
  };
  import { ref, onMounted, computed } from "vue";
  import PageHeader from "@/components/PageHeader.vue";
  import useUserStore from "@/store/modules/user";
  import { useDict } from "@/utils/dict";
  import { onLoad } from "@dcloudio/uni-app";
  import { userListNoPageByTenantId } from "@/api/system/user";
  import { addSealApplication } from "@/api/managementMeetings/sealManagement";
  const userStore = useUserStore();
  // è¡¨å•数据
  const form = ref({
    applicationNum: "",
    title: "",
    sealType: "",
    reason: "",
    approveUserId: "",
    urgency: "normal",
    status: "pending",
  });
  const { knowledge_type } = useDict("knowledge_type");
  const knowledgeTypeOptions = computed(() => knowledge_type?.value || []);
  const equipmentOptions = ref([
    { value: "official", name: "公章" },
    { value: "contract", name: "合同专用章" },
    { value: "finance", name: "财务专用章" },
    { value: "legal", name: "法人章" },
  ]);
  const statusOptions = ref([
    { value: "high", name: "显著提升" },
    { value: "medium", name: "一般提升" },
    { value: "low", name: "轻微提升" },
  ]);
  //// é¡µé¢çŠ¶æ€
  const loading = ref(false);
  const formRef = ref(null);
  const showEquipmentSheet = ref(false);
  const showStatusSheet = ref(false);
  const openEquipmentSheet = () => {
    showEquipmentSheet.value = true;
  };
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  const statusname = ref("");
  // çŠ¶æ€é€‰æ‹©
  const onStatusSelect = action => {
    form.value.approveUserId = action.value;
    statusname.value = action.name;
    showStatusSheet.value = false;
  };
  const equipmentname = ref("");
  // è®¾å¤‡é…ç½®é€‰æ‹©
  const handleEquipmentChange = val => {
    form.value.sealType = val.value;
    equipmentname.value = val.name;
    showEquipmentSheet.value = false;
  };
  // æäº¤è¡¨å•
  const handleSubmit = async () => {
    if (!form.value.applicationNum) {
      showToast("请输入申请编号");
      return;
    }
    if (!form.value.title) {
      showToast("请输入标题");
      return;
    }
    if (!form.value.sealType) {
      showToast("请选择用印类型");
      return;
    }
    if (!form.value.reason) {
      showToast("请输入申请理由");
      return;
    }
    if (!statusname.value) {
      showToast("请选择审批人");
      return;
    }
    try {
      loading.value = true;
      addSealApplication(form.value).then(res => {
        if (res.code !== 200) {
          showToast("保存失败,请重试");
          return;
        }
        loading.value = false;
        showToast("保存成功");
        setTimeout(() => {
          goBack();
        }, 500);
      });
    } catch (e) {
      loading.value = false;
      console.error("保存失败:", e);
      showToast("保存失败,请重试");
    }
  };
  // åˆå§‹åŒ–页面数据
  const readonly = ref(false);
  const detailType = ref(1);
  const knowledgeId = ref("");
  const userList = ref([]);
  onLoad(options => {
    detailType.value = Number(options.detailType);
    knowledgeId.value = options.id || "";
    // æŸ¥çœ‹æ¨¡å¼è®¾ç½®åªè¯»
    if (detailType.value === 3) {
      readonly.value = true;
    }
    userListNoPageByTenantId().then(res => {
      userList.value = res.data.map(item => ({
        value: item.userId,
        name: item.nickName,
      }));
    });
  });
  onMounted(() => {
    // ä»Žæœ¬åœ°å­˜å‚¨ä¸­èŽ·å–çŸ¥è¯†æ•°æ®
    const knowledgeBase = uni.getStorageSync("knowledgeBase");
    if (knowledgeBase) {
      form.value = JSON.parse(JSON.stringify(knowledgeBase));
    }
    if (detailType.value === 1) {
      form.value = {
        applicationNum: "",
        title: "",
        sealType: "",
        reason: "",
        approveUserId: "",
        urgency: "normal",
        status: "pending",
      };
      statusname.value = "";
      equipmentname.value = "";
    }
    console.log(form.value, "userList.value");
    if (detailType.value != 1) {
      equipmentname.value =
        equipmentOptions.value.find(item => item.value === form.value.sealType)
          ?.name || "";
      statusname.value = form.value.approveUserName || "";
    }
  });
</script>
<style scoped lang="scss">
  @import "@/static/scss/form-common.scss";
  .client-visit {
    min-height: 100vh;
    background: #f8f9fa;
    padding-bottom: 5rem;
  }
  .footer-btns {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background: #fff;
    display: flex;
    justify-content: space-around;
    align-items: center;
    padding: 0.75rem 0;
    box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05);
    z-index: 1000;
  }
  .cancel-btn {
    font-weight: 400;
    font-size: 1rem;
    color: #666;
    background: #f5f5f5;
    border: 1px solid #ddd;
    width: 45%;
    height: 2.5rem;
    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
  }
  .sign-btn {
    font-weight: 500;
    font-size: 1rem;
    color: #fff;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border: none;
    width: 45%;
    height: 2.5rem;
    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
  }
  .location-icon {
    color: #1989fa;
    font-size: 1.2rem;
  }
  /* ç´§æ€¥ç¨‹åº¦å•选框样式 */
  :deep(.u-radio-group) {
    display: flex;
    align-items: center;
    gap: 40rpx;
  }
  :deep(.u-radio) {
    display: flex;
    align-items: center;
  }
</style>
src/pages/managementMeetings/sealManagement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,342 @@
<template>
  <view class="sales-accoun">
    <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
    <PageHeader title="用印管理"
                @back="goBack" />
    <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
    <view class="search-section">
      <view class="search-bar">
        <view class="search-input">
          <up-input class="search-text"
                    placeholder="请输入申请标题"
                    v-model="name"
                    @blur="getList"
                    clearable />
        </view>
        <view class="filter-button"
              @click="getList">
          <u-icon name="search"
                  size="24"
                  color="#999"></u-icon>
        </view>
      </view>
    </view>
    <!-- æ‹œè®¿è®°å½•列表 -->
    <view class="ledger-list"
          v-if="visitList.length > 0">
      <view v-for="(item, index) in visitList"
            :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>
          <up-divider></up-divider>
          <view class="item-details">
            <view class="detail-row">
              <text class="detail-label">申请编号</text>
              <text class="detail-value">{{ item.applicationNum || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">申请人</text>
              <text class="detail-value">{{ item.createUserName || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">所属部门</text>
              <text class="detail-value">{{ item.department || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">用印类型</text>
              <text class="detail-value">{{ formatReceiptType(item.sealType) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">申请时间</text>
              <text class="detail-value">{{ item.createTime || '-' }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">状态</text>
              <u-tag size="mini"
                     :type="getTagClass(item.status)">{{ formatReceiptType1(item.status) }}</u-tag>
            </view>
            <view class="detail-row">
              <text class="detail-label">申请原因</text>
              <text class="detail-value"><span style="display: block;height: auto;word-break: break-word;">{{ item.reason || '-' }}</span></text>
            </view>
          </view>
          <!-- æŒ‰é’®åŒºåŸŸ -->
          <view class="action-buttons">
            <u-button type="info"
                      size="small"
                      class="action-btn"
                      @click="viewDetail(item,3)">
              æŸ¥çœ‹
            </u-button>
            <u-button type="primary"
                      size="small"
                      class="action-btn"
                      v-if="item.status === 'pending'"
                      @click="confirmApprove(item,true)">
              å®¡æ‰¹
            </u-button>
            <u-button type="error"
                      size="small"
                      class="action-btn"
                      v-if="item.status === 'pending'"
                      @click="confirmApprove(item,false)">
              æ‹’绝
            </u-button>
          </view>
        </view>
      </view>
    </view>
    <view v-else
          class="no-data">
      <text>暂无会议室记录</text>
    </view>
    <!-- æµ®åŠ¨æ–°å¢žæŒ‰é’® -->
    <view class="fab-button"
          @click="addVisit">
      <up-icon name="plus"
               size="24"
               color="#ffffff"></up-icon>
    </view>
  </view>
</template>
<script setup>
  import { ref, onMounted, computed } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import { useDict } from "@/utils/dict";
  import PageHeader from "@/components/PageHeader.vue";
  import {
    listSealApplication,
    updateSealApplication,
  } from "@/api/managementMeetings/sealManagement";
  import useUserStore from "@/store/modules/user";
  // æ›¿æ¢ toast æ–¹æ³•
  defineOptions({ name: "client-visit-index" });
  const showToast = message => {
    uni.showToast({
      title: message,
      icon: "none",
    });
  };
  import dayjs from "dayjs";
  const userStore = useUserStore();
  // æœç´¢å…³é”®è¯
  const name = ref("");
  // æ‹œè®¿è®°å½•数据
  const visitList = ref([]);
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  const { knowledge_type } = useDict("knowledge_type");
  // æ ¼å¼åŒ–回款方式
  const formatReceiptType = params => {
    if (params == "official") {
      return "公章";
    } else if (params == "contract") {
      return "合同专用章";
    } else if (params == "finance") {
      return "财务专用章";
    } else if (params == "tegal") {
      return "法人章";
    } else {
      return "未知";
    }
  };
  const formatReceiptType1 = params => {
    if (params == "pending") {
      return "待审批";
    } else if (params == "approved") {
      return "已通过";
    } else if (params == "rejected") {
      return "已拒绝";
    } else {
      return "未知";
    }
  };
  const getTagClass = type => {
    if (type == "pending") {
      return "warning";
    } else if (type == "approved") {
      return "success";
    } else if (type == "rejected") {
      return "danger";
    } else {
      return "info";
    }
  };
  const knowledgeTypeOptions = computed(() => knowledge_type?.value || []);
  // èŽ·å–çŸ¥è¯†ç±»åž‹æ ‡ç­¾
  const getKnowledgeTypeLabel = val => {
    console.log(knowledgeTypeOptions, "knowledgeTypeOptions");
    const item = knowledgeTypeOptions.value.find(
      i => String(i.value) === String(val)
    );
    return item ? item.label : val;
  };
  // æŸ¥è¯¢åˆ—表
  const getList = () => {
    showLoadingToast("加载中...");
    const params = {
      current: -1,
      size: -1,
      title: name.value,
    };
    listSealApplication(params)
      .then(res => {
        const currentFactoryName = userStore.currentFactoryName;
        if (currentFactoryName) {
          visitList.value = res.data.records.filter(
            item => item.department === currentFactoryName
          );
        } else {
          visitList.value = res.data.records;
        }
        closeToast();
      })
      .catch(() => {
        closeToast();
        showToast("获取数据失败");
      });
  };
  // æ˜¾ç¤ºåŠ è½½æç¤º
  const showLoadingToast = message => {
    uni.showLoading({
      title: message,
      mask: true,
    });
  };
  // å…³é—­æç¤º
  const closeToast = () => {
    uni.hideLoading();
  };
  // æ–°å¢žæ‹œè®¿ - è·³è½¬åˆ°ç™»è®°é¡µé¢
  const addVisit = () => {
    uni.navigateTo({
      url: "/pages/managementMeetings/sealManagement/detail?detailType=1",
    });
  };
  const confirmApprove = (item, isApprove) => {
    if (isApprove) {
      uni.showModal({
        title: "审批确认",
        content: `确定要审批该用印申请吗?`,
        success: res => {
          item.status = "approved";
          updateSealApplication(item).then(res => {
            if (res.code == 200) {
              showToast("审批通过");
            }
          });
        },
      });
    } else {
      uni.showModal({
        title: "审批确认",
        content: `确定要拒绝该用印申请吗?`,
        success: res => {
          item.status = "rejected";
          updateSealApplication(item).then(res => {
            if (res.code == 200) {
              showToast("审批拒绝");
            }
          });
        },
      });
    }
  };
  // ç¼–辑
  const viewDetail = (item, detailType) => {
    uni.setStorageSync("knowledgeBase", item);
    uni.navigateTo({
      url:
        "/pages/managementMeetings/sealManagement/detail?detailType=" +
        detailType +
        "&id=" +
        item.id,
    });
  };
  // åˆ é™¤ç¡®è®¤
  const confirmDelete = item => {
    uni.showModal({
      title: "删除确认",
      content: `确定要删除知识 "${item.title}" å—?`,
      success: res => {
        if (res.confirm) {
          // deleteKnowledge(item.id);
        }
      },
    });
  };
  onMounted(() => {
    getList();
  });
  onShow(() => {
    getList();
  });
</script>
<style scoped lang="scss">
  @import "../../../styles/sales-common.scss";
  // é¡µé¢ç‰¹å®šçš„æ ·å¼è¦†ç›–
  .sales-accoun {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
    padding-bottom: 80px;
  }
  // ç‰¹å®šçš„图标样式
  .document-icon {
    background: #667eea; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„背景色
  }
  // ç‰¹æœ‰æ ·å¼
  .visit-status {
    display: flex;
    align-items: center;
  }
  .detail-value {
    word-break: break-all; // ä¿ç•™é¡µé¢ç‰¹æœ‰çš„æ–‡æœ¬æ¢è¡Œæ ·å¼
    color: #333; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„æ–‡æœ¬é¢œè‰²
  }
  // çŠ¶æ€æ ·å¼
  .status-enabled {
    color: #28a745; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„æˆåŠŸé¢œè‰²
  }
  .status-disabled {
    color: #dc3545; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„错误颜色
  }
  // ç‰¹å®šçš„æµ®åŠ¨æŒ‰é’®æ ·å¼
  .fab-button {
    background: #667eea; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„背景色
    box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3); // ä¿æŒé¡µé¢ç‰¹æœ‰çš„阴影效果
  }
</style>