|
@@ -11,17 +11,12 @@
|
|
|
<div class="content-wrapper">
|
|
<div class="content-wrapper">
|
|
|
<div class="tree-container">
|
|
<div class="tree-container">
|
|
|
<div class="tree-header">
|
|
<div class="tree-header">
|
|
|
- <el-button v-hasPermi="['document:folder:add']" type="primary" icon="Plus" size="small" @click="handleAddFolder">{{ t('document.document.button.newFolder') }}</el-button>
|
|
|
|
|
|
|
+ <el-button v-hasPermi="['document:folder:add']" type="primary" icon="Plus" size="small"
|
|
|
|
|
+ @click="handleAddFolder">{{ t('document.document.button.newFolder') }}</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<el-scrollbar class="tree-scrollbar">
|
|
<el-scrollbar class="tree-scrollbar">
|
|
|
- <el-tree
|
|
|
|
|
- v-loading="loading"
|
|
|
|
|
- :data="treeData"
|
|
|
|
|
- :props="treeProps"
|
|
|
|
|
- node-key="id"
|
|
|
|
|
- default-expand-all
|
|
|
|
|
- :expand-on-click-node="false"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <el-tree v-loading="loading" :data="treeData" :props="treeProps" node-key="id" default-expand-all
|
|
|
|
|
+ :expand-on-click-node="false">
|
|
|
<template #default="{ node, data }">
|
|
<template #default="{ node, data }">
|
|
|
<span class="custom-tree-node">
|
|
<span class="custom-tree-node">
|
|
|
<el-icon>
|
|
<el-icon>
|
|
@@ -33,7 +28,9 @@
|
|
|
<span class="node-label" @click="handleFolderClick(data)">{{ node.label }}</span>
|
|
<span class="node-label" @click="handleFolderClick(data)">{{ node.label }}</span>
|
|
|
<span class="node-actions">
|
|
<span class="node-actions">
|
|
|
<span class="menu-trigger" @click="toggleMenu($event, data)">
|
|
<span class="menu-trigger" @click="toggleMenu($event, data)">
|
|
|
- <el-icon><MoreFilled /></el-icon>
|
|
|
|
|
|
|
+ <el-icon>
|
|
|
|
|
+ <MoreFilled />
|
|
|
|
|
+ </el-icon>
|
|
|
</span>
|
|
</span>
|
|
|
</span>
|
|
</span>
|
|
|
</span>
|
|
</span>
|
|
@@ -41,39 +38,27 @@
|
|
|
</el-tree>
|
|
</el-tree>
|
|
|
</el-scrollbar>
|
|
</el-scrollbar>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<!-- 一级菜单 -->
|
|
<!-- 一级菜单 -->
|
|
|
<ul class="primary-menu" v-if="activeMenu !== null" :style="primaryMenuStyle">
|
|
<ul class="primary-menu" v-if="activeMenu !== null" :style="primaryMenuStyle">
|
|
|
- <li
|
|
|
|
|
- class="menu-item has-submenu"
|
|
|
|
|
- v-hasPermi="['document:folder:add']"
|
|
|
|
|
- @click.stop="toggleSubmenu($event)"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <li class="menu-item has-submenu" v-hasPermi="['document:folder:add']" @click.stop="toggleSubmenu($event)">
|
|
|
<span>{{ t('document.document.menu.add') }}</span>
|
|
<span>{{ t('document.document.menu.add') }}</span>
|
|
|
- <el-icon class="arrow-icon"><ArrowRight /></el-icon>
|
|
|
|
|
|
|
+ <el-icon class="arrow-icon">
|
|
|
|
|
+ <ArrowRight />
|
|
|
|
|
+ </el-icon>
|
|
|
</li>
|
|
</li>
|
|
|
- <li
|
|
|
|
|
- class="menu-item"
|
|
|
|
|
- v-hasPermi="['document:folder:edit']"
|
|
|
|
|
- @click="handleMenuItemClick('edit', currentMenuData)"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <li class="menu-item" v-hasPermi="['document:folder:edit']"
|
|
|
|
|
+ @click="handleMenuItemClick('edit', currentMenuData)">
|
|
|
<span>{{ t('document.document.menu.edit') }}</span>
|
|
<span>{{ t('document.document.menu.edit') }}</span>
|
|
|
</li>
|
|
</li>
|
|
|
- <li
|
|
|
|
|
- class="menu-item"
|
|
|
|
|
- v-hasPermi="['document:folder:remove']"
|
|
|
|
|
- @click="handleMenuItemClick('delete', currentMenuData)"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <li class="menu-item" v-hasPermi="['document:folder:remove']"
|
|
|
|
|
+ @click="handleMenuItemClick('delete', currentMenuData)">
|
|
|
<span>{{ t('document.document.menu.delete') }}</span>
|
|
<span>{{ t('document.document.menu.delete') }}</span>
|
|
|
</li>
|
|
</li>
|
|
|
</ul>
|
|
</ul>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<!-- 二级菜单 -->
|
|
<!-- 二级菜单 -->
|
|
|
- <ul
|
|
|
|
|
- class="secondary-menu"
|
|
|
|
|
- v-if="showSecondaryMenu"
|
|
|
|
|
- :style="secondaryMenuStyle"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <ul class="secondary-menu" v-if="showSecondaryMenu" :style="secondaryMenuStyle">
|
|
|
<!-- 国家或中心:显示中心和文件夹 -->
|
|
<!-- 国家或中心:显示中心和文件夹 -->
|
|
|
<template v-if="currentMenuData && (currentMenuData.type === 1 || currentMenuData.type === 2)">
|
|
<template v-if="currentMenuData && (currentMenuData.type === 1 || currentMenuData.type === 2)">
|
|
|
<li class="menu-item" @click="handleMenuItemClick('add:2', currentMenuData)">
|
|
<li class="menu-item" @click="handleMenuItemClick('add:2', currentMenuData)">
|
|
@@ -88,51 +73,59 @@
|
|
|
<li class="menu-item" @click="handleMenuItemClick('add:0', currentMenuData)">
|
|
<li class="menu-item" @click="handleMenuItemClick('add:0', currentMenuData)">
|
|
|
<span>{{ t('document.document.menu.folder') }}</span>
|
|
<span>{{ t('document.document.menu.folder') }}</span>
|
|
|
</li>
|
|
</li>
|
|
|
- <li class="menu-item" v-hasPermi="['document:document:add']" @click="handleMenuItemClick('add:document', currentMenuData)">
|
|
|
|
|
|
|
+ <li class="menu-item" v-hasPermi="['document:document:add']"
|
|
|
|
|
+ @click="handleMenuItemClick('add:document', currentMenuData)">
|
|
|
<span>{{ t('document.document.menu.document') }}</span>
|
|
<span>{{ t('document.document.menu.document') }}</span>
|
|
|
</li>
|
|
</li>
|
|
|
</template>
|
|
</template>
|
|
|
</ul>
|
|
</ul>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<div class="content-container">
|
|
<div class="content-container">
|
|
|
<!-- 文档列表展示区域 -->
|
|
<!-- 文档列表展示区域 -->
|
|
|
<div v-if="selectedFolder" class="document-list-container">
|
|
<div v-if="selectedFolder" class="document-list-container">
|
|
|
<!-- 搜索栏 -->
|
|
<!-- 搜索栏 -->
|
|
|
<el-form :model="documentQueryParams" :inline="true" class="search-form">
|
|
<el-form :model="documentQueryParams" :inline="true" class="search-form">
|
|
|
<el-form-item :label="t('document.document.documentList.fileName')">
|
|
<el-form-item :label="t('document.document.documentList.fileName')">
|
|
|
- <el-input
|
|
|
|
|
- v-model="documentQueryParams.name"
|
|
|
|
|
- :placeholder="t('document.document.documentList.fileNamePlaceholder')"
|
|
|
|
|
- clearable
|
|
|
|
|
- style="width: 240px"
|
|
|
|
|
- @keyup.enter="handleDocumentQuery"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <el-input v-model="documentQueryParams.name"
|
|
|
|
|
+ :placeholder="t('document.document.documentList.fileNamePlaceholder')" clearable style="width: 240px"
|
|
|
|
|
+ @keyup.enter="handleDocumentQuery" />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
<el-form-item>
|
|
|
- <el-button type="primary" icon="Search" @click="handleDocumentQuery">{{ t('document.document.button.search') }}</el-button>
|
|
|
|
|
- <el-button icon="Refresh" @click="handleDocumentReset">{{ t('document.document.button.reset') }}</el-button>
|
|
|
|
|
|
|
+ <el-button type="primary" icon="Search" @click="handleDocumentQuery">{{
|
|
|
|
|
+ t('document.document.button.search')
|
|
|
|
|
+ }}</el-button>
|
|
|
|
|
+ <el-button icon="Refresh" @click="handleDocumentReset">{{ t('document.document.button.reset')
|
|
|
|
|
+ }}</el-button>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-form>
|
|
</el-form>
|
|
|
|
|
|
|
|
<!-- 文档列表 -->
|
|
<!-- 文档列表 -->
|
|
|
<el-table v-loading="documentLoading" :data="documentList" border style="margin-top: 10px">
|
|
<el-table v-loading="documentLoading" :data="documentList" border style="margin-top: 10px">
|
|
|
- <el-table-column type="index" width="55" align="center" :label="t('document.document.documentList.index')" />
|
|
|
|
|
- <el-table-column prop="name" :label="t('document.document.documentList.name')" min-width="150" show-overflow-tooltip />
|
|
|
|
|
- <el-table-column prop="specification" :label="t('document.document.documentList.specification')" min-width="120" show-overflow-tooltip />
|
|
|
|
|
- <el-table-column prop="planDocumentType" :label="t('document.document.documentList.planDocumentType')" width="120" align="center">
|
|
|
|
|
|
|
+ <el-table-column type="index" width="55" align="center"
|
|
|
|
|
+ :label="t('document.document.documentList.index')" />
|
|
|
|
|
+ <el-table-column prop="name" :label="t('document.document.documentList.name')" min-width="150"
|
|
|
|
|
+ show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column prop="specification" :label="t('document.document.documentList.specification')"
|
|
|
|
|
+ min-width="120" show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column prop="planDocumentType" :label="t('document.document.documentList.planDocumentType')"
|
|
|
|
|
+ width="120" align="center">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
- <dict-tag v-if="scope.row.planDocumentType" :options="plan_document_type" :value="scope.row.planDocumentType" />
|
|
|
|
|
|
|
+ <dict-tag v-if="scope.row.planDocumentType" :options="plan_document_type"
|
|
|
|
|
+ :value="scope.row.planDocumentType" />
|
|
|
<span v-else>-</span>
|
|
<span v-else>-</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="submitter" :label="t('document.document.documentList.submitter')" width="120" align="center" />
|
|
|
|
|
- <el-table-column prop="submitDeadline" :label="t('document.document.documentList.submitDeadline')" width="110" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="submitter" :label="t('document.document.documentList.submitter')" width="120"
|
|
|
|
|
+ align="center" />
|
|
|
|
|
+ <el-table-column prop="submitDeadline" :label="t('document.document.documentList.submitDeadline')"
|
|
|
|
|
+ width="110" align="center">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
<span v-if="scope.row.submitDeadline">{{ parseTime(scope.row.submitDeadline, '{y}-{m}-{d}') }}</span>
|
|
<span v-if="scope.row.submitDeadline">{{ parseTime(scope.row.submitDeadline, '{y}-{m}-{d}') }}</span>
|
|
|
<span v-else>-</span>
|
|
<span v-else>-</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="submitTime" :label="t('document.document.documentList.submitTime')" width="160" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="submitTime" :label="t('document.document.documentList.submitTime')" width="160"
|
|
|
|
|
+ align="center">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
<span v-if="scope.row.submitTime">{{ parseTime(scope.row.submitTime) }}</span>
|
|
<span v-if="scope.row.submitTime">{{ parseTime(scope.row.submitTime) }}</span>
|
|
|
<span v-else>-</span>
|
|
<span v-else>-</span>
|
|
@@ -157,43 +150,40 @@
|
|
|
<span v-else>-</span>
|
|
<span v-else>-</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="note" :label="t('document.document.documentList.note')" min-width="150" show-overflow-tooltip />
|
|
|
|
|
- <el-table-column prop="createTime" :label="t('document.document.documentList.createTime')" width="160" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="note" :label="t('document.document.documentList.note')" min-width="150"
|
|
|
|
|
+ show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column prop="createTime" :label="t('document.document.documentList.createTime')" width="160"
|
|
|
|
|
+ align="center">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
<span v-if="scope.row.createTime">{{ parseTime(scope.row.createTime) }}</span>
|
|
<span v-if="scope.row.createTime">{{ parseTime(scope.row.createTime) }}</span>
|
|
|
<span v-else>-</span>
|
|
<span v-else>-</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="updateTime" :label="t('document.document.documentList.updateTime')" width="160" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="updateTime" :label="t('document.document.documentList.updateTime')" width="160"
|
|
|
|
|
+ align="center">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
<span v-if="scope.row.updateTime">{{ parseTime(scope.row.updateTime) }}</span>
|
|
<span v-if="scope.row.updateTime">{{ parseTime(scope.row.updateTime) }}</span>
|
|
|
<span v-else>-</span>
|
|
<span v-else>-</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column :label="t('document.document.documentList.action')" width="100" align="center" fixed="right">
|
|
|
|
|
|
|
+ <el-table-column :label="t('document.document.documentList.action')" width="150" align="center"
|
|
|
|
|
+ fixed="right">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
- <el-button
|
|
|
|
|
- v-hasPermi="['document:document:audit']"
|
|
|
|
|
- type="primary"
|
|
|
|
|
- link
|
|
|
|
|
- :icon="Select"
|
|
|
|
|
- @click="handleAudit(scope.row)"
|
|
|
|
|
- :title="t('document.document.button.audit')"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <el-button v-hasPermi="['document:document:audit']" type="primary" link :icon="Select"
|
|
|
|
|
+ @click="handleAudit(scope.row)" :title="t('document.document.button.audit')" />
|
|
|
|
|
+ <el-button v-hasPermi="['document:document:mark']" type="primary" link icon="Flag"
|
|
|
|
|
+ @click="handleMark(scope.row)" :title="t('document.document.button.mark')" />
|
|
|
|
|
+ <el-button type="primary" link icon="Download" @click="handleDownload(scope.row)"
|
|
|
|
|
+ :title="t('document.document.button.download')" :disabled="!scope.row.url" />
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
</el-table>
|
|
</el-table>
|
|
|
|
|
|
|
|
<!-- 分页 -->
|
|
<!-- 分页 -->
|
|
|
- <pagination
|
|
|
|
|
- v-show="documentTotal > 0"
|
|
|
|
|
- v-model:page="documentQueryParams.pageNum"
|
|
|
|
|
- v-model:limit="documentQueryParams.pageSize"
|
|
|
|
|
- :total="documentTotal"
|
|
|
|
|
- @pagination="getDocumentList"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <pagination v-show="documentTotal > 0" v-model:page="documentQueryParams.pageNum"
|
|
|
|
|
+ v-model:limit="documentQueryParams.pageSize" :total="documentTotal" @pagination="getDocumentList" />
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<!-- 空状态 -->
|
|
<!-- 空状态 -->
|
|
|
<el-empty v-else :description="t('document.document.empty.description')">
|
|
<el-empty v-else :description="t('document.document.empty.description')">
|
|
|
</el-empty>
|
|
</el-empty>
|
|
@@ -212,22 +202,19 @@
|
|
|
<el-radio :label="false">{{ t('document.document.form.noRestriction') }}</el-radio>
|
|
<el-radio :label="false">{{ t('document.document.form.noRestriction') }}</el-radio>
|
|
|
<el-radio :label="true">{{ t('document.document.form.restricted') }}</el-radio>
|
|
<el-radio :label="true">{{ t('document.document.form.restricted') }}</el-radio>
|
|
|
</el-radio-group>
|
|
</el-radio-group>
|
|
|
- <el-input-number
|
|
|
|
|
- v-if="isRestricted"
|
|
|
|
|
- v-model="restrictionLevelValue"
|
|
|
|
|
- :min="0"
|
|
|
|
|
- :max="10000"
|
|
|
|
|
- style="width: 100%; margin-top: 10px;"
|
|
|
|
|
- :placeholder="t('document.document.form.restrictionLevelPlaceholder')"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <el-input-number v-if="isRestricted" v-model="restrictionLevelValue" :min="0" :max="10000"
|
|
|
|
|
+ style="width: 100%; margin-top: 10px;"
|
|
|
|
|
+ :placeholder="t('document.document.form.restrictionLevelPlaceholder')" />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
<el-form-item :label="t('document.document.form.note')" prop="note">
|
|
<el-form-item :label="t('document.document.form.note')" prop="note">
|
|
|
- <el-input v-model="form.note" type="textarea" :rows="4" :placeholder="t('document.document.form.notePlaceholder')" />
|
|
|
|
|
|
|
+ <el-input v-model="form.note" type="textarea" :rows="4"
|
|
|
|
|
+ :placeholder="t('document.document.form.notePlaceholder')" />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-form>
|
|
</el-form>
|
|
|
<template #footer>
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
<div class="dialog-footer">
|
|
|
- <el-button :loading="buttonLoading" type="primary" @click="submitForm">{{ t('document.document.button.submit') }}</el-button>
|
|
|
|
|
|
|
+ <el-button :loading="buttonLoading" type="primary" @click="submitForm">{{ t('document.document.button.submit')
|
|
|
|
|
+ }}</el-button>
|
|
|
<el-button @click="cancel">{{ t('document.document.button.cancel') }}</el-button>
|
|
<el-button @click="cancel">{{ t('document.document.button.cancel') }}</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
@@ -236,77 +223,111 @@
|
|
|
<!-- 添加文档对话框 -->
|
|
<!-- 添加文档对话框 -->
|
|
|
<el-dialog v-model="documentDialog.visible" :title="documentDialog.title" width="700px" append-to-body>
|
|
<el-dialog v-model="documentDialog.visible" :title="documentDialog.title" width="700px" append-to-body>
|
|
|
<el-form ref="documentFormRef" :model="documentForm" :rules="documentRules" label-width="140px">
|
|
<el-form ref="documentFormRef" :model="documentForm" :rules="documentRules" label-width="140px">
|
|
|
- <el-form-item :label="documentForm.type === 1 ? t('document.document.documentForm.planName') : t('document.document.documentForm.name')" prop="name">
|
|
|
|
|
- <el-input v-model="documentForm.name" :placeholder="t('document.document.documentForm.namePlaceholder')" clearable />
|
|
|
|
|
|
|
+ <el-form-item
|
|
|
|
|
+ :label="documentForm.type === 1 ? t('document.document.documentForm.planName') : t('document.document.documentForm.name')"
|
|
|
|
|
+ prop="name">
|
|
|
|
|
+ <el-input v-model="documentForm.name" :placeholder="t('document.document.documentForm.namePlaceholder')"
|
|
|
|
|
+ clearable />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<el-form-item :label="t('document.document.documentForm.type')" prop="type" v-if="hasAddPlanPermission">
|
|
<el-form-item :label="t('document.document.documentForm.type')" prop="type" v-if="hasAddPlanPermission">
|
|
|
<el-radio-group v-model="documentForm.type" @change="handleDocumentTypeChange">
|
|
<el-radio-group v-model="documentForm.type" @change="handleDocumentTypeChange">
|
|
|
<el-radio :label="0">{{ t('document.document.documentForm.normalDocument') }}</el-radio>
|
|
<el-radio :label="0">{{ t('document.document.documentForm.normalDocument') }}</el-radio>
|
|
|
<el-radio :label="1">{{ t('document.document.documentForm.planDocument') }}</el-radio>
|
|
<el-radio :label="1">{{ t('document.document.documentForm.planDocument') }}</el-radio>
|
|
|
</el-radio-group>
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<el-form-item :label="t('document.document.documentForm.submitter')" prop="submitterId">
|
|
<el-form-item :label="t('document.document.documentForm.submitter')" prop="submitterId">
|
|
|
<template v-if="documentForm.type === 0">
|
|
<template v-if="documentForm.type === 0">
|
|
|
<el-input v-model="currentUserName" disabled />
|
|
<el-input v-model="currentUserName" disabled />
|
|
|
</template>
|
|
</template>
|
|
|
<template v-else>
|
|
<template v-else>
|
|
|
- <el-select
|
|
|
|
|
- v-model="documentForm.submitterId"
|
|
|
|
|
- filterable
|
|
|
|
|
- remote
|
|
|
|
|
- reserve-keyword
|
|
|
|
|
- :placeholder="t('document.document.documentForm.submitterPlaceholder')"
|
|
|
|
|
- :remote-method="searchSubmitters"
|
|
|
|
|
- :loading="submitterSearchLoading"
|
|
|
|
|
- style="width: 100%"
|
|
|
|
|
- >
|
|
|
|
|
- <el-option
|
|
|
|
|
- v-for="submitter in submitterOptions"
|
|
|
|
|
- :key="submitter.id"
|
|
|
|
|
- :label="`${submitter.name} / ${submitter.dept} --- ${submitter.phoneNumber}`"
|
|
|
|
|
- :value="submitter.id"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <el-select v-model="documentForm.submitterId" filterable remote reserve-keyword
|
|
|
|
|
+ :placeholder="t('document.document.documentForm.submitterPlaceholder')" :remote-method="searchSubmitters"
|
|
|
|
|
+ :loading="submitterSearchLoading" style="width: 100%">
|
|
|
|
|
+ <el-option v-for="submitter in submitterOptions" :key="submitter.id"
|
|
|
|
|
+ :label="`${submitter.name} / ${submitter.dept} --- ${submitter.phoneNumber}`" :value="submitter.id" />
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</template>
|
|
</template>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
-
|
|
|
|
|
- <el-form-item v-if="documentForm.type === 1" :label="t('document.document.documentForm.submitDeadline')" prop="submitDeadline">
|
|
|
|
|
- <el-date-picker
|
|
|
|
|
- v-model="documentForm.submitDeadline"
|
|
|
|
|
- type="date"
|
|
|
|
|
- value-format="YYYY-MM-DD"
|
|
|
|
|
- :placeholder="t('document.document.documentForm.submitDeadlinePlaceholder')"
|
|
|
|
|
- style="width: 100%"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item v-if="documentForm.type === 1" :label="t('document.document.documentForm.submitDeadline')"
|
|
|
|
|
+ prop="submitDeadline">
|
|
|
|
|
+ <el-date-picker v-model="documentForm.submitDeadline" type="date" value-format="YYYY-MM-DD"
|
|
|
|
|
+ :placeholder="t('document.document.documentForm.submitDeadlinePlaceholder')" style="width: 100%" />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
-
|
|
|
|
|
- <el-form-item v-if="documentForm.type === 1" :label="t('document.document.documentForm.planType')" prop="planType">
|
|
|
|
|
- <el-select v-model="documentForm.planType" :placeholder="t('document.document.documentForm.planTypePlaceholder')" clearable style="width: 100%">
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item v-if="documentForm.type === 1" :label="t('document.document.documentForm.planType')"
|
|
|
|
|
+ prop="planType">
|
|
|
|
|
+ <el-select v-model="documentForm.planType"
|
|
|
|
|
+ :placeholder="t('document.document.documentForm.planTypePlaceholder')" clearable style="width: 100%">
|
|
|
<el-option v-for="dict in plan_document_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
<el-option v-for="dict in plan_document_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<el-form-item :label="t('document.document.documentForm.file')" :prop="documentForm.type === 0 ? 'ossId' : ''">
|
|
<el-form-item :label="t('document.document.documentForm.file')" :prop="documentForm.type === 0 ? 'ossId' : ''">
|
|
|
<fileUpload v-model="uploadedFileId" :limit="1" />
|
|
<fileUpload v-model="uploadedFileId" :limit="1" />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<el-form-item v-if="documentForm.submitTime" :label="t('document.document.documentForm.submitTime')">
|
|
<el-form-item v-if="documentForm.submitTime" :label="t('document.document.documentForm.submitTime')">
|
|
|
<el-input v-model="documentForm.submitTime" disabled />
|
|
<el-input v-model="documentForm.submitTime" disabled />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<el-form-item :label="t('document.document.documentForm.note')" prop="note">
|
|
<el-form-item :label="t('document.document.documentForm.note')" prop="note">
|
|
|
- <el-input v-model="documentForm.note" type="textarea" :rows="4" :placeholder="t('document.document.documentForm.notePlaceholder')" />
|
|
|
|
|
|
|
+ <el-input v-model="documentForm.note" type="textarea" :rows="4"
|
|
|
|
|
+ :placeholder="t('document.document.documentForm.notePlaceholder')" />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-form>
|
|
</el-form>
|
|
|
<template #footer>
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
<div class="dialog-footer">
|
|
|
- <el-button :loading="documentButtonLoading" type="primary" @click="submitDocumentForm">{{ t('document.document.button.submit') }}</el-button>
|
|
|
|
|
|
|
+ <el-button :loading="documentButtonLoading" type="primary" @click="submitDocumentForm">{{
|
|
|
|
|
+ t('document.document.button.submit') }}</el-button>
|
|
|
<el-button @click="cancelDocument">{{ t('document.document.button.cancel') }}</el-button>
|
|
<el-button @click="cancelDocument">{{ t('document.document.button.cancel') }}</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 标识文档对话框 -->
|
|
|
|
|
+ <el-dialog v-model="markDialog.visible" :title="markDialog.title" width="500px" append-to-body>
|
|
|
|
|
+ <el-form ref="markFormRef" :model="markForm" :rules="markRules" label-width="120px">
|
|
|
|
|
+ <el-form-item :label="t('document.document.markForm.specification')" prop="type">
|
|
|
|
|
+ <el-select v-model="markForm.type" :placeholder="t('document.document.markForm.specificationPlaceholder')"
|
|
|
|
|
+ clearable style="width: 100%">
|
|
|
|
|
+ <el-option v-for="dict in specificationDict" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <div class="dialog-footer">
|
|
|
|
|
+ <el-button :loading="markButtonLoading" type="primary" @click="submitMarkForm">{{
|
|
|
|
|
+ t('document.document.button.submit') }}</el-button>
|
|
|
|
|
+ <el-button @click="cancelMark">{{ t('document.document.button.cancel') }}</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 审核文档对话框 -->
|
|
|
|
|
+ <el-dialog v-model="auditDialog.visible" :title="auditDialog.title" width="500px" append-to-body>
|
|
|
|
|
+ <el-form ref="auditFormRef" :model="auditForm" :rules="auditRules" label-width="120px">
|
|
|
|
|
+ <el-form-item :label="t('document.document.auditForm.result')" prop="result">
|
|
|
|
|
+ <el-radio-group v-model="auditForm.result">
|
|
|
|
|
+ <el-radio label="0">{{ t('document.document.auditForm.pass') }}</el-radio>
|
|
|
|
|
+ <el-radio label="1">{{ t('document.document.auditForm.reject') }}</el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item v-if="auditForm.result === '1'" :label="t('document.document.auditForm.reason')" prop="reason">
|
|
|
|
|
+ <el-input v-model="auditForm.reason" type="textarea" :rows="4"
|
|
|
|
|
+ placeholder="{{ t('document.document.auditForm.reasonPlaceholder') }}" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <div class="dialog-footer">
|
|
|
|
|
+ <el-button :loading="auditButtonLoading" type="primary" @click="submitAuditForm">{{
|
|
|
|
|
+ t('document.document.button.submit') }}</el-button>
|
|
|
|
|
+ <el-button @click="cancelAudit">{{ t('document.document.button.cancel') }}</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -315,11 +336,11 @@ import { ref, reactive, onMounted, onUnmounted, nextTick, getCurrentInstance, wa
|
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
import { listFolder, addFolder, delFolder, getFolder, updateFolder } from '@/api/document/folder';
|
|
import { listFolder, addFolder, delFolder, getFolder, updateFolder } from '@/api/document/folder';
|
|
|
import { FolderListVO, FolderForm } from '@/api/document/folder/types';
|
|
import { FolderListVO, FolderForm } from '@/api/document/folder/types';
|
|
|
-import { addDocument, listDocument } from '@/api/document/document';
|
|
|
|
|
-import { DocumentForm, DocumentQuery, DocumentVO } from '@/api/document/document/types';
|
|
|
|
|
|
|
+import { addDocument, listDocument, markDocument } from '@/api/document/document';
|
|
|
|
|
+import { DocumentForm, DocumentQuery, DocumentVO, DocumentMarkForm } from '@/api/document/document/types';
|
|
|
import { queryMemberNotInCenter } from '@/api/project/management';
|
|
import { queryMemberNotInCenter } from '@/api/project/management';
|
|
|
import { MemberNotInCenterVO, MemberNotInCenterQuery } from '@/api/project/management/types';
|
|
import { MemberNotInCenterVO, MemberNotInCenterQuery } from '@/api/project/management/types';
|
|
|
-import { Folder, Document, Edit, Delete, Plus, MoreFilled, Location, OfficeBuilding, ArrowRight, Download, Select, Grid, Monitor, Reading } from '@element-plus/icons-vue';
|
|
|
|
|
|
|
+import { Folder, Document, Edit, Delete, Plus, MoreFilled, Location, OfficeBuilding, ArrowRight, Download, Select, Grid, Monitor, Reading, Flag } from '@element-plus/icons-vue';
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
import type { FormInstance } from 'element-plus';
|
|
import type { FormInstance } from 'element-plus';
|
|
|
import type { ComponentInternalInstance } from 'vue';
|
|
import type { ComponentInternalInstance } from 'vue';
|
|
@@ -340,7 +361,7 @@ const emit = defineEmits<{
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
const { t } = useI18n();
|
|
const { t } = useI18n();
|
|
|
const userStore = useUserStore();
|
|
const userStore = useUserStore();
|
|
|
-const { plan_document_type } = toRefs<any>(proxy?.useDict('plan_document_type'));
|
|
|
|
|
|
|
+const { plan_document_type, center_file_specification, project_file_specification } = toRefs<any>(proxy?.useDict('plan_document_type', 'center_file_specification', 'project_file_specification'));
|
|
|
|
|
|
|
|
// 数据定义
|
|
// 数据定义
|
|
|
const loading = ref(false);
|
|
const loading = ref(false);
|
|
@@ -369,6 +390,26 @@ const documentDialog = reactive({
|
|
|
title: ''
|
|
title: ''
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+// 标识文档对话框
|
|
|
|
|
+const markDialog = reactive({
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ title: ''
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 标识表单ref
|
|
|
|
|
+const markFormRef = ref<FormInstance>();
|
|
|
|
|
+const markButtonLoading = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+// 审核文档对话框
|
|
|
|
|
+const auditDialog = reactive({
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ title: ''
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 审核表单ref
|
|
|
|
|
+const auditFormRef = ref<FormInstance>();
|
|
|
|
|
+const auditButtonLoading = ref(false);
|
|
|
|
|
+
|
|
|
// 当前操作的节点
|
|
// 当前操作的节点
|
|
|
const currentNode = ref<FolderListVO | null>(null);
|
|
const currentNode = ref<FolderListVO | null>(null);
|
|
|
|
|
|
|
@@ -411,6 +452,46 @@ const uploadedFileId = ref<string>('');
|
|
|
// 文档表单数据
|
|
// 文档表单数据
|
|
|
const documentForm = ref<DocumentForm>({ ...initDocumentFormData });
|
|
const documentForm = ref<DocumentForm>({ ...initDocumentFormData });
|
|
|
|
|
|
|
|
|
|
+// 标识表单数据
|
|
|
|
|
+const markForm = ref<DocumentMarkForm>({
|
|
|
|
|
+ id: 0,
|
|
|
|
|
+ type: ''
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 审核表单数据
|
|
|
|
|
+interface AuditForm {
|
|
|
|
|
+ id: number;
|
|
|
|
|
+ result: string; // 0: 通过, 1: 驳回
|
|
|
|
|
+ reason: string; // 驳回理由
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const auditForm = ref<AuditForm>({
|
|
|
|
|
+ id: 0,
|
|
|
|
|
+ result: '0', // 默认通过
|
|
|
|
|
+ reason: ''
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 审核表单验证规则
|
|
|
|
|
+const auditRules = reactive({
|
|
|
|
|
+ result: [
|
|
|
|
|
+ {
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ message: t('document.document.auditRule.resultRequired'),
|
|
|
|
|
+ trigger: 'change'
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ reason: [
|
|
|
|
|
+ {
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ message: t('document.document.auditRule.reasonRequired'),
|
|
|
|
|
+ trigger: 'blur'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 当前选中的文档
|
|
|
|
|
+const currentDocument = ref<DocumentVO | null>(null);
|
|
|
|
|
+
|
|
|
// 递交人搜索相关
|
|
// 递交人搜索相关
|
|
|
const submitterSearchLoading = ref(false);
|
|
const submitterSearchLoading = ref(false);
|
|
|
const submitterOptions = ref<MemberNotInCenterVO[]>([]);
|
|
const submitterOptions = ref<MemberNotInCenterVO[]>([]);
|
|
@@ -456,19 +537,75 @@ const documentRules = {
|
|
|
]
|
|
]
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 标识表单验证规则
|
|
|
|
|
+const markRules = {
|
|
|
|
|
+ type: [
|
|
|
|
|
+ { required: true, message: t('document.document.markRule.typeRequired'), trigger: 'change' }
|
|
|
|
|
+ ]
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 树形组件配置
|
|
// 树形组件配置
|
|
|
const treeProps = {
|
|
const treeProps = {
|
|
|
children: 'children',
|
|
children: 'children',
|
|
|
label: 'name'
|
|
label: 'name'
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 根据当前文件夹获取对应的字典
|
|
|
|
|
+const specificationDict = computed(() => {
|
|
|
|
|
+ if (!selectedFolder.value) return [];
|
|
|
|
|
+
|
|
|
|
|
+ // 判断是否在中心底下
|
|
|
|
|
+ const isUnderCenter = checkIfUnderCenter(selectedFolder.value.id);
|
|
|
|
|
+
|
|
|
|
|
+ if (isUnderCenter) {
|
|
|
|
|
+ return center_file_specification?.value || [];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return project_file_specification?.value || [];
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 检查文件夹是否在中心底下
|
|
|
|
|
+const checkIfUnderCenter = (folderId: string | number): boolean => {
|
|
|
|
|
+ // 从当前文件夹往上遍历,如果中间存在着中心类型的文件夹,那么他就是中心层级文件
|
|
|
|
|
+ // 递归查找目标节点并收集从根到目标的路径
|
|
|
|
|
+ const findPathToNode = (tree: FolderListVO[], targetId: string | number, path: FolderListVO[] = []): FolderListVO[] | null => {
|
|
|
|
|
+ for (const node of tree) {
|
|
|
|
|
+ const currentPath = [...path, node];
|
|
|
|
|
+
|
|
|
|
|
+ if (node.id === targetId) {
|
|
|
|
|
+ // 找到目标节点,返回路径
|
|
|
|
|
+ return currentPath;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 在子节点中递归查找
|
|
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
|
|
+ const result = findPathToNode(node.children, targetId, currentPath);
|
|
|
|
|
+ if (result) {
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 获取从根到目标文件夹的路径
|
|
|
|
|
+ const path = findPathToNode(treeData.value, folderId);
|
|
|
|
|
+
|
|
|
|
|
+ if (!path) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查路径中是否存在type为1或2的节点(国家或中心)
|
|
|
|
|
+ return path.some(node => node.type === 1 || node.type === 2);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 获取文件夹列表
|
|
// 获取文件夹列表
|
|
|
const getList = async () => {
|
|
const getList = async () => {
|
|
|
if (!props.projectId) {
|
|
if (!props.projectId) {
|
|
|
ElMessage.warning(t('document.document.message.projectIdNotExist'));
|
|
ElMessage.warning(t('document.document.message.projectIdNotExist'));
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
loading.value = true;
|
|
loading.value = true;
|
|
|
try {
|
|
try {
|
|
|
const res = await listFolder({ projectId: props.projectId } as any);
|
|
const res = await listFolder({ projectId: props.projectId } as any);
|
|
@@ -550,9 +687,9 @@ const getAvailableTypes = () => {
|
|
|
{ label: t('document.document.type.center'), value: 2 }
|
|
{ label: t('document.document.type.center'), value: 2 }
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
const parentType = currentNode.value.type;
|
|
const parentType = currentNode.value.type;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (parentType === 1 || parentType === 2) {
|
|
if (parentType === 1 || parentType === 2) {
|
|
|
// 父节点是国家或中心,子节点只能是中心或文件夹
|
|
// 父节点是国家或中心,子节点只能是中心或文件夹
|
|
|
return [
|
|
return [
|
|
@@ -621,7 +758,7 @@ const submitForm = () => {
|
|
|
return; // 用户取消
|
|
return; // 用户取消
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
buttonLoading.value = true;
|
|
buttonLoading.value = true;
|
|
|
try {
|
|
try {
|
|
|
if (dialog.isEdit) {
|
|
if (dialog.isEdit) {
|
|
@@ -649,7 +786,7 @@ const handleEdit = async (data: FolderListVO) => {
|
|
|
try {
|
|
try {
|
|
|
const res = await getFolder(data.id);
|
|
const res = await getFolder(data.id);
|
|
|
Object.assign(form.value, res.data);
|
|
Object.assign(form.value, res.data);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 设置限制层级状态
|
|
// 设置限制层级状态
|
|
|
if (form.value.restrictionLevel === -1) {
|
|
if (form.value.restrictionLevel === -1) {
|
|
|
isRestricted.value = false;
|
|
isRestricted.value = false;
|
|
@@ -658,7 +795,7 @@ const handleEdit = async (data: FolderListVO) => {
|
|
|
isRestricted.value = true;
|
|
isRestricted.value = true;
|
|
|
restrictionLevelValue.value = form.value.restrictionLevel;
|
|
restrictionLevelValue.value = form.value.restrictionLevel;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
currentNode.value = null; // 编辑时不限制类型
|
|
currentNode.value = null; // 编辑时不限制类型
|
|
|
dialog.visible = true;
|
|
dialog.visible = true;
|
|
|
dialog.title = t('document.document.dialog.editFolder');
|
|
dialog.title = t('document.document.dialog.editFolder');
|
|
@@ -678,14 +815,14 @@ const handleDelete = async (data: FolderListVO) => {
|
|
|
ElMessage.warning(t('document.document.message.hasChildren'));
|
|
ElMessage.warning(t('document.document.message.hasChildren'));
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
await ElMessageBox.confirm(t('document.document.message.deleteConfirm', { name: data.name }), t('document.document.message.deleteTitle'), {
|
|
await ElMessageBox.confirm(t('document.document.message.deleteConfirm', { name: data.name }), t('document.document.message.deleteTitle'), {
|
|
|
confirmButtonText: t('document.document.message.confirmButton'),
|
|
confirmButtonText: t('document.document.message.confirmButton'),
|
|
|
cancelButtonText: t('document.document.message.cancelButton'),
|
|
cancelButtonText: t('document.document.message.cancelButton'),
|
|
|
type: 'warning'
|
|
type: 'warning'
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
loading.value = true;
|
|
loading.value = true;
|
|
|
await delFolder(data.id);
|
|
await delFolder(data.id);
|
|
|
ElMessage.success(t('document.document.message.deleteSuccess'));
|
|
ElMessage.success(t('document.document.message.deleteSuccess'));
|
|
@@ -713,13 +850,13 @@ const toggleMenu = (event: MouseEvent, data: FolderListVO) => {
|
|
|
if (event.type !== 'click') {
|
|
if (event.type !== 'click') {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
event.stopPropagation();
|
|
event.stopPropagation();
|
|
|
event.preventDefault();
|
|
event.preventDefault();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
const trigger = event.currentTarget as HTMLElement;
|
|
const trigger = event.currentTarget as HTMLElement;
|
|
|
const rect = trigger.getBoundingClientRect();
|
|
const rect = trigger.getBoundingClientRect();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (activeMenu.value === data.id) {
|
|
if (activeMenu.value === data.id) {
|
|
|
// 如果点击的是同一个菜单,关闭它
|
|
// 如果点击的是同一个菜单,关闭它
|
|
|
closeAllMenus();
|
|
closeAllMenus();
|
|
@@ -730,7 +867,7 @@ const toggleMenu = (event: MouseEvent, data: FolderListVO) => {
|
|
|
left: `${rect.left}px`,
|
|
left: `${rect.left}px`,
|
|
|
top: `${rect.bottom + 2}px`
|
|
top: `${rect.bottom + 2}px`
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
activeMenu.value = data.id;
|
|
activeMenu.value = data.id;
|
|
|
currentMenuData.value = data;
|
|
currentMenuData.value = data;
|
|
|
showSecondaryMenu.value = false;
|
|
showSecondaryMenu.value = false;
|
|
@@ -743,13 +880,13 @@ const toggleSubmenu = (event: MouseEvent) => {
|
|
|
if (event.type !== 'click') {
|
|
if (event.type !== 'click') {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
event.stopPropagation();
|
|
event.stopPropagation();
|
|
|
event.preventDefault();
|
|
event.preventDefault();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
const target = event.currentTarget as HTMLElement;
|
|
const target = event.currentTarget as HTMLElement;
|
|
|
const rect = target.getBoundingClientRect();
|
|
const rect = target.getBoundingClientRect();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (showSecondaryMenu.value) {
|
|
if (showSecondaryMenu.value) {
|
|
|
// 如果已经显示,则关闭
|
|
// 如果已经显示,则关闭
|
|
|
showSecondaryMenu.value = false;
|
|
showSecondaryMenu.value = false;
|
|
@@ -759,7 +896,7 @@ const toggleSubmenu = (event: MouseEvent) => {
|
|
|
left: `${rect.right + 5}px`,
|
|
left: `${rect.right + 5}px`,
|
|
|
top: `${rect.top}px`
|
|
top: `${rect.top}px`
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 使用 nextTick 确保位置设置后再显示
|
|
// 使用 nextTick 确保位置设置后再显示
|
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
|
showSecondaryMenu.value = true;
|
|
showSecondaryMenu.value = true;
|
|
@@ -770,10 +907,10 @@ const toggleSubmenu = (event: MouseEvent) => {
|
|
|
// 处理菜单项点击
|
|
// 处理菜单项点击
|
|
|
const handleMenuItemClick = (command: string, data: FolderListVO | null) => {
|
|
const handleMenuItemClick = (command: string, data: FolderListVO | null) => {
|
|
|
if (!data) return;
|
|
if (!data) return;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 执行命令
|
|
// 执行命令
|
|
|
handleCommand(command, data);
|
|
handleCommand(command, data);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 关闭所有菜单
|
|
// 关闭所有菜单
|
|
|
closeAllMenus();
|
|
closeAllMenus();
|
|
|
};
|
|
};
|
|
@@ -821,12 +958,12 @@ const searchSubmitters = async (query: string) => {
|
|
|
submitterOptions.value = [];
|
|
submitterOptions.value = [];
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 清除之前的定时器
|
|
// 清除之前的定时器
|
|
|
if (submitterSearchTimer) {
|
|
if (submitterSearchTimer) {
|
|
|
clearTimeout(submitterSearchTimer);
|
|
clearTimeout(submitterSearchTimer);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 设置防抖
|
|
// 设置防抖
|
|
|
submitterSearchTimer = setTimeout(async () => {
|
|
submitterSearchTimer = setTimeout(async () => {
|
|
|
submitterSearchLoading.value = true;
|
|
submitterSearchLoading.value = true;
|
|
@@ -891,7 +1028,7 @@ const submitDocumentForm = () => {
|
|
|
submitTime: documentForm.value.submitTime || '',
|
|
submitTime: documentForm.value.submitTime || '',
|
|
|
note: documentForm.value.note || ''
|
|
note: documentForm.value.note || ''
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
await addDocument(submitData);
|
|
await addDocument(submitData);
|
|
|
proxy?.$modal.msgSuccess(t('document.document.message.addDocumentSuccess'));
|
|
proxy?.$modal.msgSuccess(t('document.document.message.addDocumentSuccess'));
|
|
|
documentDialog.visible = false;
|
|
documentDialog.visible = false;
|
|
@@ -928,10 +1065,10 @@ const handleFolderClick = (data: FolderListVO) => {
|
|
|
// 查询文档列表
|
|
// 查询文档列表
|
|
|
const getDocumentList = async () => {
|
|
const getDocumentList = async () => {
|
|
|
if (!selectedFolder.value) return;
|
|
if (!selectedFolder.value) return;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
documentLoading.value = true;
|
|
documentLoading.value = true;
|
|
|
documentQueryParams.folderId = selectedFolder.value.id;
|
|
documentQueryParams.folderId = selectedFolder.value.id;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
const res = await listDocument(documentQueryParams);
|
|
const res = await listDocument(documentQueryParams);
|
|
|
documentList.value = res.rows || [];
|
|
documentList.value = res.rows || [];
|
|
@@ -959,8 +1096,110 @@ const handleDocumentReset = () => {
|
|
|
|
|
|
|
|
// 审核文档
|
|
// 审核文档
|
|
|
const handleAudit = (row: DocumentVO) => {
|
|
const handleAudit = (row: DocumentVO) => {
|
|
|
- console.log('审核文档:', row);
|
|
|
|
|
- ElMessage.info('审核功能待实现');
|
|
|
|
|
|
|
+ currentDocument.value = row;
|
|
|
|
|
+ auditForm.value = {
|
|
|
|
|
+ id: row.id,
|
|
|
|
|
+ result: '0', // 默认通过
|
|
|
|
|
+ reason: ''
|
|
|
|
|
+ };
|
|
|
|
|
+ auditDialog.visible = true;
|
|
|
|
|
+ auditDialog.title = t('document.document.dialog.auditDocument');
|
|
|
|
|
+ // 重置表单验证
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ auditFormRef.value?.clearValidate();
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 取消审核
|
|
|
|
|
+const cancelAudit = () => {
|
|
|
|
|
+ auditDialog.visible = false;
|
|
|
|
|
+ auditForm.value = {
|
|
|
|
|
+ id: 0,
|
|
|
|
|
+ result: '0',
|
|
|
|
|
+ reason: ''
|
|
|
|
|
+ };
|
|
|
|
|
+ currentDocument.value = null;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 提交审核表单
|
|
|
|
|
+const submitAuditForm = () => {
|
|
|
|
|
+ auditFormRef.value?.validate(async (valid: boolean) => {
|
|
|
|
|
+ if (valid) {
|
|
|
|
|
+ auditButtonLoading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 暂时不与后端进行交互,仅关闭弹窗
|
|
|
|
|
+ proxy?.$modal.msgSuccess(t('document.document.message.auditSuccess'));
|
|
|
|
|
+ auditDialog.visible = false;
|
|
|
|
|
+ // 刷新文档列表
|
|
|
|
|
+ await getDocumentList();
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(t('document.document.message.auditFailed'), error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ auditButtonLoading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 下载文档
|
|
|
|
|
+const handleDownload = (row: DocumentVO) => {
|
|
|
|
|
+ if (!row.url) {
|
|
|
|
|
+ ElMessage.warning(t('document.document.message.noFileToDownload'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 新建a标签下载文件
|
|
|
|
|
+ const a = document.createElement('a');
|
|
|
|
|
+ a.href = row.url;
|
|
|
|
|
+ a.download = row.fileName || row.name || 'document';
|
|
|
|
|
+ document.body.appendChild(a);
|
|
|
|
|
+ a.click();
|
|
|
|
|
+ document.body.removeChild(a);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 标识文档
|
|
|
|
|
+const handleMark = (row: DocumentVO) => {
|
|
|
|
|
+ currentDocument.value = row;
|
|
|
|
|
+ markForm.value = {
|
|
|
|
|
+ id: row.id,
|
|
|
|
|
+ type: ''
|
|
|
|
|
+ };
|
|
|
|
|
+ markDialog.visible = true;
|
|
|
|
|
+ markDialog.title = t('document.document.dialog.markDocument');
|
|
|
|
|
+ // 重置表单验证
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ markFormRef.value?.clearValidate();
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 取消标识
|
|
|
|
|
+const cancelMark = () => {
|
|
|
|
|
+ markDialog.visible = false;
|
|
|
|
|
+ markForm.value = {
|
|
|
|
|
+ id: 0,
|
|
|
|
|
+ type: ''
|
|
|
|
|
+ };
|
|
|
|
|
+ currentDocument.value = null;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 提交标识表单
|
|
|
|
|
+const submitMarkForm = () => {
|
|
|
|
|
+ markFormRef.value?.validate(async (valid: boolean) => {
|
|
|
|
|
+ if (valid) {
|
|
|
|
|
+ markButtonLoading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ await markDocument(markForm.value);
|
|
|
|
|
+ proxy?.$modal.msgSuccess(t('document.document.message.markSuccess'));
|
|
|
|
|
+ markDialog.visible = false;
|
|
|
|
|
+ // 刷新文档列表
|
|
|
|
|
+ await getDocumentList();
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(t('document.document.message.markFailed'), error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ markButtonLoading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// ========== 文件类型判断函数 ==========
|
|
// ========== 文件类型判断函数 ==========
|
|
@@ -976,9 +1215,9 @@ const isWordFile = (fileName: string): boolean => {
|
|
|
const isExcelFile = (fileName: string): boolean => {
|
|
const isExcelFile = (fileName: string): boolean => {
|
|
|
if (!fileName) return false;
|
|
if (!fileName) return false;
|
|
|
const lowerFileName = fileName.toLowerCase();
|
|
const lowerFileName = fileName.toLowerCase();
|
|
|
- return lowerFileName.endsWith('.xls') ||
|
|
|
|
|
- lowerFileName.endsWith('.xlsx') ||
|
|
|
|
|
- lowerFileName.endsWith('.csv');
|
|
|
|
|
|
|
+ return lowerFileName.endsWith('.xls') ||
|
|
|
|
|
+ lowerFileName.endsWith('.xlsx') ||
|
|
|
|
|
+ lowerFileName.endsWith('.csv');
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 判断是否为PPT文档
|
|
// 判断是否为PPT文档
|
|
@@ -1009,14 +1248,14 @@ const handleClickOutside = (event: Event) => {
|
|
|
if (!activeMenu.value && !showSecondaryMenu.value) {
|
|
if (!activeMenu.value && !showSecondaryMenu.value) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
const target = event.target as HTMLElement;
|
|
const target = event.target as HTMLElement;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 检查点击是否在菜单内部或触发器上
|
|
// 检查点击是否在菜单内部或触发器上
|
|
|
- const isClickInsideMenu = target.closest('.primary-menu') ||
|
|
|
|
|
- target.closest('.secondary-menu') ||
|
|
|
|
|
- target.closest('.menu-trigger');
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const isClickInsideMenu = target.closest('.primary-menu') ||
|
|
|
|
|
+ target.closest('.secondary-menu') ||
|
|
|
|
|
+ target.closest('.menu-trigger');
|
|
|
|
|
+
|
|
|
// 如果点击在菜单外部,立即关闭所有菜单
|
|
// 如果点击在菜单外部,立即关闭所有菜单
|
|
|
if (!isClickInsideMenu) {
|
|
if (!isClickInsideMenu) {
|
|
|
closeAllMenus();
|
|
closeAllMenus();
|
|
@@ -1097,7 +1336,7 @@ onUnmounted(() => {
|
|
|
.tree-scrollbar {
|
|
.tree-scrollbar {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
:deep(.el-scrollbar__view) {
|
|
:deep(.el-scrollbar__view) {
|
|
|
padding: 10px;
|
|
padding: 10px;
|
|
|
}
|
|
}
|
|
@@ -1109,29 +1348,29 @@ onUnmounted(() => {
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
|
padding-right: 8px;
|
|
padding-right: 8px;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.el-icon {
|
|
.el-icon {
|
|
|
margin-right: 8px;
|
|
margin-right: 8px;
|
|
|
font-size: 16px;
|
|
font-size: 16px;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.node-label {
|
|
.node-label {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
&:hover {
|
|
&:hover {
|
|
|
color: var(--el-color-primary);
|
|
color: var(--el-color-primary);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.node-actions {
|
|
.node-actions {
|
|
|
display: none;
|
|
display: none;
|
|
|
position: relative;
|
|
position: relative;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
&:hover .node-actions {
|
|
&:hover .node-actions {
|
|
|
display: inline-flex;
|
|
display: inline-flex;
|
|
|
gap: 4px;
|
|
gap: 4px;
|
|
@@ -1146,7 +1385,7 @@ onUnmounted(() => {
|
|
|
padding: 4px;
|
|
padding: 4px;
|
|
|
border-radius: 4px;
|
|
border-radius: 4px;
|
|
|
transition: background-color 0.3s, color 0.3s;
|
|
transition: background-color 0.3s, color 0.3s;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
&:hover {
|
|
&:hover {
|
|
|
background-color: #f5f7fa;
|
|
background-color: #f5f7fa;
|
|
|
color: var(--el-color-primary);
|
|
color: var(--el-color-primary);
|
|
@@ -1161,21 +1400,21 @@ onUnmounted(() => {
|
|
|
|
|
|
|
|
.document-list-container {
|
|
.document-list-container {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.search-form {
|
|
.search-form {
|
|
|
margin-bottom: 16px;
|
|
margin-bottom: 16px;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.file-name-cell {
|
|
.file-name-cell {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: 8px;
|
|
gap: 8px;
|
|
|
padding: 0 8px;
|
|
padding: 0 8px;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.file-icon {
|
|
.file-icon {
|
|
|
flex-shrink: 0;
|
|
flex-shrink: 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.file-name-text {
|
|
.file-name-text {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
text-align: left;
|
|
text-align: left;
|
|
@@ -1183,11 +1422,11 @@ onUnmounted(() => {
|
|
|
text-overflow: ellipsis;
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.download-btn {
|
|
.download-btn {
|
|
|
flex-shrink: 0;
|
|
flex-shrink: 0;
|
|
|
font-size: 16px;
|
|
font-size: 16px;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
&:hover {
|
|
&:hover {
|
|
|
transform: scale(1.1);
|
|
transform: scale(1.1);
|
|
|
}
|
|
}
|
|
@@ -1211,7 +1450,7 @@ onUnmounted(() => {
|
|
|
margin: 0;
|
|
margin: 0;
|
|
|
list-style: none;
|
|
list-style: none;
|
|
|
z-index: 2000;
|
|
z-index: 2000;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.menu-item {
|
|
.menu-item {
|
|
|
padding: 8px 16px;
|
|
padding: 8px 16px;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
@@ -1249,7 +1488,7 @@ onUnmounted(() => {
|
|
|
margin: 0;
|
|
margin: 0;
|
|
|
list-style: none;
|
|
list-style: none;
|
|
|
z-index: 3000;
|
|
z-index: 3000;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.menu-item {
|
|
.menu-item {
|
|
|
padding: 8px 16px;
|
|
padding: 8px 16px;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
@@ -1263,4 +1502,4 @@ onUnmounted(() => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-</style>
|
|
|
|
|
|
|
+</style>
|