zhangwencui
7 天以前 1bda9babdf0316852ee5972690742f63c79595d6
用印管理以及知识库部分逻辑修改
已添加3个文件
已修改3个文件
783 ■■■■■ 文件已修改
src/api/managementMeetings/sealManagement.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/knowledgeBase/detail.vue 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/sealManagement/detail.vue 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/managementMeetings/sealManagement/index.vue 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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
@@ -380,6 +380,20 @@
      }
    },
    {
      "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": "知识库详情",
src/pages/index.vue
@@ -343,13 +343,17 @@
      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/xietongshenpi@2x.png",
    //   label: "协同审批",
    // },
    // {
    //   icon: "/static/images/icon/kehubaifang@2x.png",
    //   label: "客户拜访",
    // },
  ]);
  // ç”Ÿäº§ç®¡æŽ§åŠŸèƒ½æ•°æ®
@@ -565,6 +569,11 @@
          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
@@ -156,7 +156,6 @@
  import {
    addKnowledgeBase,
    updateKnowledgeBase,
    getKnowledgeBaseDetail,
  } from "@/api/managementMeetings/knowledgeBase";
  const userStore = useUserStore();
@@ -284,37 +283,19 @@
  const detailType = ref(1);
  const knowledgeId = ref("");
  // èŽ·å–çŸ¥è¯†è¯¦æƒ…
  const getKnowledgeDetail = id => {
    loading.value = true;
    getKnowledgeBaseDetail(id)
      .then(res => {
        loading.value = false;
        if (res.code === 200) {
          form.value = res.data;
          equipmentname.value =
            equipmentOptions.value.find(item => item.value === form.value.type)
              ?.name || "";
          statusname.value =
            statusOptions.value.find(item => item.value === form.value.efficiency)
              ?.name || "";
        } else {
          showToast("获取知识详情失败");
        }
      })
      .catch(err => {
        loading.value = false;
        showToast("获取知识详情失败");
      });
  };
  onLoad(options => {
    detailType.value = Number(options.detailType);
    knowledgeId.value = options.id || "";
    // å¦‚果是编辑或查看模式,获取知识详情
    if (knowledgeId.value && (detailType.value === 2 || detailType.value === 3)) {
      getKnowledgeDetail(knowledgeId.value);
      // 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 || "";
    }
    // æŸ¥çœ‹æ¨¡å¼è®¾ç½®åªè¯»
@@ -335,6 +316,21 @@
      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 =
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>