张诺
11 小时以前 ff5b4a4202405b26393c5f71999e43f3e2746499
src/pages/cooperativeOffice/collaborativeApproval/knowledgeBase/index.vue
@@ -2,7 +2,32 @@
  <view class="sales-accoun">
    <!-- 使用通用页面头部组件 -->
    <PageHeader title="知识库"
                @back="goBack" />
                @back="goBack">
      <template #right>
        <view class="header-actions">
          <uni-icons v-if="!batchMode"
                     type="download"
                     size="20"
                     color="#333"
                     @click="handleExport" />
          <uni-icons v-if="!batchMode"
                     type="trash"
                     size="20"
                     color="#333"
                     @click="enterBatchMode" />
          <uni-icons v-if="batchMode"
                     type="trash"
                     size="20"
                     color="#333"
                     @click="handleBatchDelete" />
          <uni-icons v-if="batchMode"
                     type="closeempty"
                     size="20"
                     color="#333"
                     @click="exitBatchMode" />
        </view>
      </template>
    </PageHeader>
    <!-- 搜索和筛选区域 -->
    <view class="search-section">
      <view class="search-bar">
@@ -20,6 +45,18 @@
                  color="#999"></u-icon>
        </view>
      </view>
      <view class="filter-row">
        <view class="filter-input">
          <up-input v-model="typeName"
                    readonly
                    placeholder="请选择知识类型"
                    @click="showTypeSheet = true" />
        </view>
        <view class="filter-reset"
              @click="resetFilters">
          重置
        </view>
      </view>
    </view>
    <!-- 拜访记录列表 -->
    <view class="ledger-list"
@@ -35,6 +72,13 @@
                         color="#ffffff"></up-icon>
              </view>
              <text class="item-id">知识标题:{{ item.title || '-' }}</text>
            </view>
            <view v-if="batchMode"
                  class="select-icon"
                  @click.stop="toggleSelection(item)">
              <uni-icons :type="isSelected(item) ? 'checkbox-filled' : 'checkbox'"
                         size="20"
                         :color="isSelected(item) ? '#667eea' : '#999'" />
            </view>
          </view>
          <up-divider></up-divider>
@@ -66,25 +110,26 @@
            </view>
          </view>
          <!-- 按钮区域 -->
          <view class="action-buttons">
          <view class="action-buttons"
                v-if="!batchMode">
            <u-button type="info"
                      size="small"
                      class="action-btn"
                      plain
                      @click="viewDetail(item, 3)">
                      @click.stop="viewDetail(item, 3)">
              查看详情
            </u-button>
            <u-button type="primary"
                      size="small"
                      class="action-btn"
                      @click="viewDetail(item, 2)">
                      @click.stop="viewDetail(item, 2)">
              编辑
            </u-button>
            <u-button type="error"
                      size="small"
                      class="action-btn"
                      plain
                      @click="confirmDelete(item)">
                      @click.stop="confirmDelete(item)">
              删除
            </u-button>
          </view>
@@ -102,6 +147,12 @@
               size="24"
               color="#ffffff"></up-icon>
    </view>
    <up-action-sheet :show="showTypeSheet"
                     :actions="typeOptions"
                     title="请选择知识类型"
                     @select="onTypeSelect"
                     @close="showTypeSheet = false" />
  </view>
</template>
@@ -115,6 +166,8 @@
    delKnowledgeBase,
  } from "@/api/managementMeetings/knowledgeBase";
  import useUserStore from "@/store/modules/user";
  import config from "@/config";
  import { getToken } from "@/utils/auth";
  defineOptions({ name: "knowledge-base-index" });
  
@@ -129,9 +182,13 @@
  // 搜索关键词
  const name = ref("");
  const type = ref("");
  const showTypeSheet = ref(false);
  // 拜访记录数据
  const visitList = ref([]);
  const batchMode = ref(false);
  const selectedIds = ref([]);
  // 返回上一页
  const goBack = () => {
@@ -139,6 +196,30 @@
  };
  
  const { knowledge_type } = useDict("knowledge_type");
  const typeOptions = computed(() => {
    const opts = (knowledge_type?.value || []).map(item => ({
      name: item.label,
      value: item.value
    }));
    return [{ name: "全部", value: "" }, ...opts];
  });
  const typeName = computed(() => {
    const item = typeOptions.value.find(i => String(i.value) === String(type.value));
    return item ? item.name : (type.value || "");
  });
  const onTypeSelect = (action) => {
    type.value = action.value;
    showTypeSheet.value = false;
    handleQuery();
  };
  const resetFilters = () => {
    name.value = "";
    type.value = "";
    handleQuery();
  };
  
  // 格式化回款方式
  const formatReceiptType = params => {
@@ -190,6 +271,7 @@
      current: -1,
      size: -1,
      title: name.value,
      type: type.value || undefined,
    };
    listKnowledgeBase(params)
      .then(res => {
@@ -234,6 +316,49 @@
    });
  };
  const enterBatchMode = () => {
    batchMode.value = true;
    selectedIds.value = [];
  };
  const exitBatchMode = () => {
    batchMode.value = false;
    selectedIds.value = [];
  };
  const toggleSelection = item => {
    const id = item?.id;
    if (!id) return;
    const idx = selectedIds.value.findIndex(v => String(v) === String(id));
    if (idx > -1) {
      selectedIds.value.splice(idx, 1);
    } else {
      selectedIds.value.push(id);
    }
  };
  const isSelected = item => {
    const id = item?.id;
    if (!id) return false;
    return selectedIds.value.some(v => String(v) === String(id));
  };
  const handleBatchDelete = () => {
    if (selectedIds.value.length === 0) {
      showToast("请选择要删除的知识");
      return;
    }
    uni.showModal({
      title: "删除确认",
      content: `确定要删除选中的 ${selectedIds.value.length} 条知识吗?`,
      success: res => {
        if (res.confirm) {
          deleteKnowledge(selectedIds.value);
        }
      },
    });
  };
  // 删除确认
  const confirmDelete = item => {
    uni.showModal({
@@ -250,11 +375,15 @@
  // 执行删除
  const deleteKnowledge = id => {
    showLoadingToast("删除中...");
    delKnowledgeBase([id])
    const ids = Array.isArray(id) ? id : [id];
    delKnowledgeBase(ids)
      .then(res => {
        closeToast();
        if (res.code === 200) {
          showToast("删除成功");
          if (batchMode.value) {
            exitBatchMode();
          }
          getList(); // 重新获取列表
        } else {
          showToast("删除失败");
@@ -264,6 +393,41 @@
        closeToast();
        showToast("删除失败");
      });
  };
  const handleExport = async () => {
    try {
      uni.showLoading({ title: "导出中...", mask: true });
      const params = {
        title: name.value || undefined,
        type: type.value || undefined,
      };
      const query = Object.entries(params)
        .filter(([, v]) => v !== undefined && v !== null && v !== "")
        .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
        .join("&");
      const url = config.baseUrl + "/knowledgeBase/export" + (query ? `?${query}` : "");
      const res = await uni.downloadFile({
        url,
        header: {
          Authorization: "Bearer " + getToken(),
        },
      });
      uni.hideLoading();
      if (res.statusCode !== 200) {
        showToast("导出失败");
        return;
      }
      uni.openDocument({
        filePath: res.tempFilePath,
        showMenu: true,
        fail: () => showToast("打开文件失败"),
      });
    } catch (e) {
      uni.hideLoading();
      showToast("导出失败");
    }
  };
  onMounted(() => {
@@ -318,6 +482,36 @@
    z-index: 100;
  }
  .header-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-right: 8px;
  }
  .filter-row {
    margin-top: 10px;
    display: flex;
    align-items: center;
    gap: 10px;
  }
  .filter-input {
    flex: 1;
  }
  .filter-reset {
    padding: 6px 12px;
    background: #f5f7fa;
    border-radius: 6px;
    color: #666;
    font-size: 12px;
  }
  .select-icon {
    padding-left: 10px;
  }
  .action-buttons {
    display: flex;
    justify-content: flex-end;