Revert "新增活动电子档案模块;"

This reverts commit a8a4052c45.
This commit is contained in:
2026-07-28 17:42:37 +08:00
parent d90f87e453
commit a93cbc9704
11 changed files with 0 additions and 1975 deletions
-192
View File
@@ -1,192 +0,0 @@
-- 活动电子档案模块初始化脚本(MySQL 8)。
-- 表结构、索引和菜单均可独立部署,不包含数据库名限定。
CREATE TABLE IF NOT EXISTS act_archive_doc_type (
id VARCHAR(32) NOT NULL COMMENT '主键',
name VARCHAR(150) NOT NULL COMMENT '类型名称',
projectStage VARCHAR(32) NOT NULL COMMENT '项目阶段:PREPARE/PROCESS/SUMMARY',
sortNo INT NOT NULL DEFAULT 0 COMMENT '排序编号',
requiredFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否必选',
remark VARCHAR(600) NULL COMMENT '备注',
createdBy VARCHAR(32) NULL COMMENT '创建人',
createdAt BIGINT NULL COMMENT '创建时间',
updatedBy VARCHAR(32) NULL COMMENT '修改人',
updatedAt BIGINT NULL COMMENT '修改时间',
delFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
UNIQUE KEY uk_archive_doc_type_stage_name (projectStage, name),
KEY idx_archive_doc_type_stage_sort (projectStage, sortNo, createdAt)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动电子档案文档类型';
CREATE TABLE IF NOT EXISTS act_archive_project (
id VARCHAR(32) NOT NULL COMMENT '主键',
year INT NOT NULL COMMENT '年度',
projectName VARCHAR(300) NOT NULL COMMENT '项目名称',
status TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0草稿、1归档中、2已完成',
unionId VARCHAR(32) NOT NULL COMMENT '所属工会ID',
unionName VARCHAR(150) NOT NULL COMMENT '所属工会名称',
createdBy VARCHAR(32) NULL COMMENT '创建人',
createdAt BIGINT NULL COMMENT '创建时间',
updatedBy VARCHAR(32) NULL COMMENT '修改人',
updatedAt BIGINT NULL COMMENT '修改时间',
delFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
UNIQUE KEY uk_archive_project_year_name_union (year, projectName, unionId),
KEY idx_archive_project_year_created (year, createdAt),
KEY idx_archive_project_union (unionId)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动电子档案项目';
CREATE TABLE IF NOT EXISTS act_archive_document (
id VARCHAR(32) NOT NULL COMMENT '主键',
projectId VARCHAR(32) NOT NULL COMMENT '归档项目ID',
documentName VARCHAR(300) NOT NULL COMMENT '文档名称',
projectStage VARCHAR(32) NOT NULL COMMENT '项目阶段:PREPARE/PROCESS/SUMMARY',
docTypeId VARCHAR(32) NULL COMMENT '文档类型ID',
status TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0草稿、1已提交归档',
uploader VARCHAR(100) NULL COMMENT '上传人',
uploadTime BIGINT NULL COMMENT '上传时间',
files JSON NULL COMMENT '附件上传结果',
remark VARCHAR(600) NULL COMMENT '备注',
createdBy VARCHAR(32) NULL COMMENT '创建人',
createdAt BIGINT NULL COMMENT '创建时间',
updatedBy VARCHAR(32) NULL COMMENT '修改人',
updatedAt BIGINT NULL COMMENT '修改时间',
delFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_archive_document_query (projectId, projectStage, docTypeId, uploadTime),
KEY idx_archive_document_project_status (projectId, status),
CONSTRAINT fk_archive_document_project
FOREIGN KEY (projectId) REFERENCES act_archive_project (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动电子档案归档文档';
-- 一级菜单。
INSERT INTO sys_menu (
id, parentId, path, name, aliasName, type, href, target, icon, showit,
disabled, permission, note, location, hasChildren, createdBy, createdAt,
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
initialPinyinName, isRecommendApp, isRecommendService
)
SELECT
'9a7d8d84b14f4d6e8ab2000000000001',
'',
LPAD(IFNULL(MAX(CAST(path AS UNSIGNED)), 0) + 1, 4, '0'),
'活动电子档案',
'Archive',
'menu',
'',
'',
'ti-folder',
1,
0,
'archive',
NULL,
992,
1,
'',
UNIX_TIMESTAMP(NOW()) * 1000,
'',
UNIX_TIMESTAMP(NOW()) * 1000,
0,
'PC',
NULL,
NULL,
'h',
0,
0
FROM sys_menu
WHERE (parentId = '' OR parentId IS NULL)
AND CHAR_LENGTH(path) = 4
HAVING NOT EXISTS (
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive') t
);
-- 文档类型设置。
INSERT INTO sys_menu (
id, parentId, path, name, aliasName, type, href, target, icon, showit,
disabled, permission, note, location, hasChildren, createdBy, createdAt,
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
initialPinyinName, isRecommendApp, isRecommendService
)
SELECT
'9a7d8d84b14f4d6e8ab2000000000002', p.id, CONCAT(p.path, '0001'),
'文档类型设置', 'Archive Doc Type', 'menu', '/platform/archive/docType',
'data-pjax', '', 1, 0, 'archive.docType', NULL, 1, 0, '',
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
'PC', NULL, NULL, 'w', 0, 0
FROM sys_menu p
WHERE p.permission = 'archive'
AND NOT EXISTS (
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.docType') t
);
-- 创建项目。
INSERT INTO sys_menu (
id, parentId, path, name, aliasName, type, href, target, icon, showit,
disabled, permission, note, location, hasChildren, createdBy, createdAt,
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
initialPinyinName, isRecommendApp, isRecommendService
)
SELECT
'9a7d8d84b14f4d6e8ab2000000000003', p.id, CONCAT(p.path, '0002'),
'创建项目', 'Archive Project', 'menu', '/platform/archive/project',
'data-pjax', '', 1, 0, 'archive.project', NULL, 2, 0, '',
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
'PC', NULL, NULL, 'c', 0, 0
FROM sys_menu p
WHERE p.permission = 'archive'
AND NOT EXISTS (
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.project') t
);
-- 资料归档。
INSERT INTO sys_menu (
id, parentId, path, name, aliasName, type, href, target, icon, showit,
disabled, permission, note, location, hasChildren, createdBy, createdAt,
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
initialPinyinName, isRecommendApp, isRecommendService
)
SELECT
'9a7d8d84b14f4d6e8ab2000000000004', p.id, CONCAT(p.path, '0003'),
'资料归档', 'Archive Filing', 'menu', '/platform/archive/filing',
'data-pjax', '', 1, 0, 'archive.filing', NULL, 3, 0, '',
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
'PC', NULL, NULL, 'z', 0, 0
FROM sys_menu p
WHERE p.permission = 'archive'
AND NOT EXISTS (
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.filing') t
);
-- 档案台账。
INSERT INTO sys_menu (
id, parentId, path, name, aliasName, type, href, target, icon, showit,
disabled, permission, note, location, hasChildren, createdBy, createdAt,
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
initialPinyinName, isRecommendApp, isRecommendService
)
SELECT
'9a7d8d84b14f4d6e8ab2000000000005', p.id, CONCAT(p.path, '0004'),
'档案台账', 'Archive Ledger', 'menu', '/platform/archive/ledger',
'data-pjax', '', 1, 0, 'archive.ledger', NULL, 4, 0, '',
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
'PC', NULL, NULL, 'd', 0, 0
FROM sys_menu p
WHERE p.permission = 'archive'
AND NOT EXISTS (
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.ledger') t
);
-- 系统管理员默认授权,其他角色可在角色管理中按需分配。
INSERT INTO sys_role_menu (roleId, menuId)
SELECT r.id, m.id
FROM sys_role r
JOIN sys_menu m ON m.permission IN (
'archive',
'archive.docType',
'archive.project',
'archive.filing',
'archive.ledger'
)
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
WHERE r.code = 'SYSADMIN'
AND rm.roleId IS NULL;
@@ -1,166 +0,0 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="类型名称">
<el-input v-model="pageForm.name" clearable placeholder="请输入类型名称"
@keyup.enter.native="doSearch"></el-input>
</search-item>
<search-item label="项目阶段">
<el-select v-model="pageForm.projectStage" clearable placeholder="请选择项目阶段"
style="width: 100%" @change="doSearch">
<el-option v-for="item in stageOptions" :key="item.value"
:label="item.label" :value="item.value"></el-option>
</el-select>
</search-item>
<search-item label="是否必选">
<el-select v-model="pageForm.requiredFlag" clearable placeholder="请选择"
style="width: 100%" @change="doSearch">
<el-option label="是" :value="true"></el-option>
<el-option label="否" :value="false"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="文档类型设置">
<el-button type="primary" size="small" @click="openForm()">
<i class="ti-plus"></i> 新增类型
</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column label="项目阶段" prop="projectStageLabel" min-width="120" align="center">
<template v-slot="{row}">
<el-tag size="small">{{row.projectStageLabel}}</el-tag>
</template>
</el-table-column>
<el-table-column label="类型名称" prop="name" min-width="160" show-overflow-tooltip></el-table-column>
<el-table-column label="排序编号" prop="sortNo" width="100" align="center"></el-table-column>
<el-table-column label="是否必选" prop="requiredFlag" width="110" align="center">
<template v-slot="{row}">
<el-tag size="small" :type="row.requiredFlag ? 'danger' : 'info'">
{{row.requiredFlag ? '必选' : '非必选'}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="引用文档数" prop="documentCount" width="110" align="center"></el-table-column>
<el-table-column label="备注" prop="remark" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="150" align="center">
<template v-slot="{row}">
<el-button size="mini" type="primary" @click="openForm(row)">编辑</el-button>
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="formData.id ? '编辑文档类型' : '新增文档类型'"
:visible.sync="formVisible" width="560px" :close-on-click-modal="false">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-form-item label="类型名称" prop="name">
<el-input v-model.trim="formData.name" maxlength="150" show-word-limit></el-input>
</el-form-item>
<el-form-item label="项目阶段" prop="projectStage">
<el-select v-model="formData.projectStage" placeholder="请选择项目阶段" style="width: 100%">
<el-option v-for="item in stageOptions" :key="item.value"
:label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="排序编号" prop="sortNo">
<el-input-number v-model="formData.sortNo" :min="0" :step="1"
step-strictly controls-position="right" style="width: 100%"></el-input-number>
</el-form-item>
<el-form-item label="必选类型" prop="requiredFlag">
<el-switch v-model="formData.requiredFlag" active-text="是" inactive-text="否"></el-switch>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model.trim="formData.remark" type="textarea" :rows="3"
maxlength="600" show-word-limit></el-input>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="formVisible=false">取消</el-button>
<el-button type="primary" @click="onSubmit">保存</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
tableData: [],
stageOptions: [],
formVisible: false,
formData: {},
pageForm: {name: "", projectStage: "", requiredFlag: null},
formRules: {
name: [{required: true, message: "请输入类型名称", trigger: "blur"}],
projectStage: [{required: true, message: "请选择项目阶段", trigger: "change"}],
sortNo: [{required: true, message: "请输入排序编号", trigger: "blur"}]
}
}
},
methods: {
pageData() {
this.$axios.post("/platform/archive/docType/pageData", this.pageForm).then(res => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
loadStages() {
this.$axios.post("/platform/archive/common/stageOptions").then(res => {
if (res.code === 0) this.stageOptions = res.data || []
})
},
openForm(row) {
this.formData = row ? clone(row) : {sortNo: 0, requiredFlag: false}
this.formVisible = true
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
},
onSubmit() {
this.$refs.formRef.validate(async valid => {
if (!valid) return
const res = await this.$axios.post("/platform/archive/docType/onSubmit", this.formData)
if (res.code === 0) {
this.$message.success("保存成功")
this.formVisible = false
this.pageData()
} else {
this.$message.warning(res.msg)
}
})
},
onDelete(row) {
this.$confirm("确定删除文档类型“" + row.name + "”吗?", "提示", {type: "warning"})
.then(async () => {
const res = await this.$axios.post("/platform/archive/docType/onDelete", {id: row.id})
if (res.code === 0) {
this.$message.success("删除成功")
this.pageData()
} else {
this.$message.warning(res.msg)
}
}).catch(() => {})
}
},
created() {
this.loadStages()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -1,371 +0,0 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.archive-summary {display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px}
.archive-summary-title {font-size:16px; font-weight:600}
.archive-summary-meta {color:#909399; display:flex; gap:20px; flex-wrap:wrap}
.archive-file-count {cursor:pointer; color:#409eff}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy"
clearable placeholder="请选择年度" style="width: 100%"
@change="onYearChange"></el-date-picker>
</search-item>
<search-item label="归档项目">
<el-select v-model="pageForm.projectId" clearable filterable placeholder="请选择归档项目"
style="width: 100%" @change="onProjectChange">
<el-option v-for="item in filteredProjects" :key="item.id"
:label="item.year + ' ' + item.projectName" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="项目阶段">
<el-select v-model="pageForm.projectStage" clearable placeholder="请选择项目阶段"
style="width: 100%" @change="onStageSearchChange">
<el-option v-for="item in stageOptions" :key="item.value"
:label="item.label" :value="item.value"></el-option>
</el-select>
</search-item>
<search-item label="文档类型">
<el-select v-model="pageForm.docTypeId" clearable filterable placeholder="请选择文档类型"
style="width: 100%" @change="doSearch">
<el-option v-for="item in searchDocTypeOptions" :key="item.id"
:label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="文档名称">
<el-input v-model="pageForm.documentName" clearable placeholder="请输入文档名称"
@keyup.enter.native="doSearch"></el-input>
</search-item>
<search-item label="归档状态">
<el-select v-model="pageForm.status" clearable placeholder="请选择归档状态"
style="width: 100%" @change="doSearch">
<el-option label="草稿" :value="0"></el-option>
<el-option label="已提交归档" :value="1"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card v-if="currentProject" shadow="never" class="mt20">
<div class="archive-summary">
<div class="archive-summary-title">
{{currentProject.projectName}}
<el-tag size="small" :type="projectStatusType(currentProject.status)">
{{currentProject.statusLabel}}
</el-tag>
</div>
<div class="archive-summary-meta">
<span>年度:{{currentProject.year}}</span>
<span>所属工会:{{currentProject.unionName}}</span>
<span>归档文档:{{currentProject.documentCount || 0}}</span>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="资料归档">
<el-button type="primary" size="small" :disabled="!pageForm.projectId" @click="openForm()">
<i class="ti-plus"></i> 新增归档文档
</el-button>
</table-tool>
<el-alert v-if="!projectOptions.length" title="当前没有归档项目,请先到“创建项目”中新建项目。"
type="warning" :closable="false" show-icon class="mb10"></el-alert>
<el-table :data="tableData" :size="tableSize">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column label="项目阶段" prop="projectStageLabel" width="120" align="center">
<template v-slot="{row}"><el-tag size="small">{{row.projectStageLabel}}</el-tag></template>
</el-table-column>
<el-table-column label="文档名称" prop="documentName" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="文档类型" prop="docTypeName" min-width="150" show-overflow-tooltip>
<template v-slot="{row}">
{{row.docTypeName || "-"}}
<el-tag v-if="row.docTypeRequiredFlag" size="mini" type="danger">必选</el-tag>
</template>
</el-table-column>
<el-table-column label="上传人" prop="uploader" width="110" align="center"></el-table-column>
<el-table-column label="上传时间" prop="uploadTime" width="170" align="center">
<template v-slot="{row}">{{row.uploadTime ? $moment(row.uploadTime).format("YYYY-MM-DD HH:mm") : "-"}}</template>
</el-table-column>
<el-table-column label="附件" width="90" align="center">
<template v-slot="{row}">
<span class="archive-file-count" @click="openPreview(row)">{{fileCount(row.files)}} 个</span>
</template>
</el-table-column>
<el-table-column label="状态" prop="status" width="120" align="center">
<template v-slot="{row}">
<el-tag size="small" :type="row.status === 1 ? 'success' : 'info'">{{row.statusLabel}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220" align="center">
<template v-slot="{row}">
<el-button size="mini" @click="openView(row)">查看</el-button>
<el-button size="mini" type="primary" @click="openForm(row)">编辑</el-button>
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="readonly ? '查看归档文档' : (formData.id ? '编辑归档文档' : '新增归档文档')"
:visible.sync="formVisible" width="760px" :close-on-click-modal="false">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-form-item label="归档项目" prop="projectId">
<el-select v-model="formData.projectId" filterable placeholder="请选择归档项目"
style="width: 100%" :disabled="readonly">
<el-option v-for="item in projectOptions" :key="item.id"
:label="item.year + ' ' + item.projectName" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="文档名称" prop="documentName">
<el-input v-model.trim="formData.documentName" maxlength="300"
show-word-limit :disabled="readonly"></el-input>
</el-form-item>
<el-form-item label="项目阶段" prop="projectStage">
<el-select v-model="formData.projectStage" placeholder="请选择项目阶段"
style="width: 100%" :disabled="readonly" @change="onFormStageChange">
<el-option v-for="item in stageOptions" :key="item.value"
:label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="文档类型" prop="docTypeId">
<el-select v-model="formData.docTypeId" clearable filterable placeholder="请选择文档类型"
style="width: 100%" :disabled="readonly">
<el-option v-for="item in formDocTypeOptions" :key="item.id"
:label="item.name + (item.requiredFlag ? '(必选)' : '')"
:value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="上传附件" prop="files">
<file-upload v-if="!readonly" :value.sync="formData.files" :upload_number="20"
:upload_size="104857600" upload_result_type="url"
upload_result_category="array" complete_result upload_mode="drag"
accept=".doc,.docx,.pdf,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.bmp,.webp,.mp4,.mov,.avi,.wmv,.mkv">
</file-upload>
<file-preview v-else :files="formData.files" complete_result></file-preview>
</el-form-item>
<el-form-item v-if="formData.id" label="上传人">
<el-input :value="formData.uploader || '-'" disabled></el-input>
</el-form-item>
<el-form-item v-if="formData.id" label="上传时间">
<el-input :value="formData.uploadTime ? $moment(formData.uploadTime).format('YYYY-MM-DD HH:mm') : '-'" disabled></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input v-model.trim="formData.remark" type="textarea" :rows="3"
maxlength="600" show-word-limit :disabled="readonly"></el-input>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="formVisible=false">关闭</el-button>
<template v-if="!readonly">
<el-button @click="saveDocument(false)">保存草稿</el-button>
<el-button type="primary" @click="saveDocument(true)">提交归档</el-button>
</template>
</span>
</el-dialog>
<el-dialog title="附件预览" :visible.sync="previewVisible" width="760px">
<file-preview :files="previewFiles" complete_result></file-preview>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
tableData: [],
stageOptions: [],
projectOptions: [],
searchDocTypeOptions: [],
formDocTypeOptions: [],
currentProject: null,
formVisible: false,
previewVisible: false,
readonly: false,
previewFiles: [],
formData: {},
pageForm: {
year: String(new Date().getFullYear()),
projectId: "",
projectStage: "",
docTypeId: "",
documentName: "",
status: null
},
formRules: {
projectId: [{required: true, message: "请选择归档项目", trigger: "change"}],
documentName: [{required: true, message: "请输入文档名称", trigger: "blur"}],
projectStage: [{required: true, message: "请选择项目阶段", trigger: "change"}]
}
}
},
computed: {
filteredProjects() {
if (!this.pageForm.year) return this.projectOptions
return this.projectOptions.filter(item => String(item.year) === String(this.pageForm.year))
}
},
methods: {
normalizeFiles(files) {
if (Array.isArray(files)) return files
if (!files) return []
try { return JSON.parse(files) || [] } catch (e) { return [] }
},
fileCount(files) {
return this.normalizeFiles(files).length
},
projectStatusType(status) {
return status === 2 ? "success" : (status === 1 ? "warning" : "info")
},
pageData() {
if (!this.pageForm.projectId) {
this.tableData = []
this.pageForm.totalCount = 0
return
}
this.$axios.post("/platform/archive/filing/pageData", this.pageForm).then(res => {
if (res.code === 0) {
this.tableData = (res.data.list || []).map(item =>
Object.assign({}, item, {files: this.normalizeFiles(item.files)}))
this.pageForm.totalCount = res.data.totalCount
}
})
},
async loadBaseData() {
const [stages, projects] = await Promise.all([
this.$axios.post("/platform/archive/common/stageOptions"),
this.$axios.post("/platform/archive/project/listData")
])
this.stageOptions = stages.data || []
this.projectOptions = projects.data || []
const queryProjectId = new URLSearchParams(window.location.search).get("projectId")
if (queryProjectId && this.projectOptions.some(item => item.id === queryProjectId)) {
this.pageForm.projectId = queryProjectId
const project = this.projectOptions.find(item => item.id === queryProjectId)
this.pageForm.year = String(project.year)
} else if (this.filteredProjects.length) {
this.pageForm.projectId = this.filteredProjects[0].id
} else if (this.projectOptions.length) {
this.pageForm.projectId = this.projectOptions[0].id
this.pageForm.year = String(this.projectOptions[0].year)
}
this.syncProject()
this.pageData()
},
loadDocTypes(stage, target) {
if (!stage) {
this[target] = []
return Promise.resolve()
}
return this.$axios.post("/platform/archive/docType/listData", {projectStage: stage}).then(res => {
this[target] = res.data || []
})
},
syncProject() {
this.currentProject = this.projectOptions.find(item => item.id === this.pageForm.projectId) || null
},
onYearChange() {
if (!this.filteredProjects.some(item => item.id === this.pageForm.projectId)) {
this.pageForm.projectId = this.filteredProjects.length ? this.filteredProjects[0].id : ""
}
this.onProjectChange()
},
onProjectChange() {
this.syncProject()
this.doSearch()
},
async onStageSearchChange() {
this.pageForm.docTypeId = ""
await this.loadDocTypes(this.pageForm.projectStage, "searchDocTypeOptions")
this.doSearch()
},
async onFormStageChange() {
this.formData.docTypeId = ""
await this.loadDocTypes(this.formData.projectStage, "formDocTypeOptions")
},
async openForm(row) {
this.readonly = false
this.formData = row ? Object.assign({}, clone(row), {files: this.normalizeFiles(row.files)}) : {
projectId: this.pageForm.projectId,
documentName: "",
projectStage: "",
docTypeId: "",
files: [],
remark: ""
}
await this.loadDocTypes(this.formData.projectStage, "formDocTypeOptions")
this.formVisible = true
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
},
async openView(row) {
this.readonly = true
this.formData = Object.assign({}, clone(row), {files: this.normalizeFiles(row.files)})
await this.loadDocTypes(this.formData.projectStage, "formDocTypeOptions")
this.formVisible = true
},
openPreview(row) {
this.previewFiles = this.normalizeFiles(row.files)
if (!this.previewFiles.length) {
this.$message.warning("当前文档没有附件")
return
}
this.previewVisible = true
},
saveDocument(submit) {
this.$refs.formRef.validate(async valid => {
if (!valid) return
if (submit && !this.normalizeFiles(this.formData.files).length) {
this.$message.warning("提交归档前请先上传附件")
return
}
const data = Object.assign({}, this.formData, {
files: JSON.stringify(this.normalizeFiles(this.formData.files))
})
const url = submit ? "/platform/archive/filing/submit" : "/platform/archive/filing/saveDraft"
const res = await this.$axios.post(url, data)
if (res.code === 0) {
this.$message.success(submit ? "提交归档成功" : "草稿保存成功")
this.formVisible = false
await this.reloadProjects()
this.pageData()
} else {
this.$message.warning(res.msg)
}
})
},
onDelete(row) {
this.$confirm("确定删除归档文档“" + row.documentName + "”吗?", "提示", {type: "warning"})
.then(async () => {
const res = await this.$axios.post("/platform/archive/filing/onDelete", {id: row.id})
if (res.code === 0) {
this.$message.success("删除成功")
await this.reloadProjects()
this.pageData()
} else {
this.$message.warning(res.msg)
}
}).catch(() => {})
},
async reloadProjects() {
const res = await this.$axios.post("/platform/archive/project/listData")
this.projectOptions = res.data || []
this.syncProject()
}
},
created() {
this.loadBaseData()
}
})
</script>
<!--#
}
#-->
@@ -1,186 +0,0 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.archive-ledger-header {margin-bottom:16px}
.archive-ledger-title {font-size:17px; font-weight:600; margin-bottom:10px}
.archive-ledger-meta {display:flex; gap:20px; flex-wrap:wrap; color:#909399}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy"
clearable placeholder="请选择年度" style="width: 100%"
@change="doSearch"></el-date-picker>
</search-item>
<search-item label="项目名称">
<el-input v-model="pageForm.projectName" clearable placeholder="请输入项目名称"
@keyup.enter.native="doSearch"></el-input>
</search-item>
<search-item label="所属工会">
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择所属工会"
style="width: 100%" @change="doSearch">
<el-option v-for="item in unionOptions" :key="item.id"
:label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="档案台账"></table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column label="年度" prop="year" width="90" align="center"></el-table-column>
<el-table-column label="项目名称" prop="projectName" min-width="210" show-overflow-tooltip></el-table-column>
<el-table-column label="项目状态" width="110" align="center">
<template v-slot="{row}">
<el-tag size="small" :type="projectStatusType(row.status)">{{row.statusLabel}}</el-tag>
</template>
</el-table-column>
<el-table-column label="所属工会" prop="unionName" min-width="170" show-overflow-tooltip></el-table-column>
<el-table-column label="归档文档数" prop="documentCount" width="120" align="center"></el-table-column>
<el-table-column label="创建时间" prop="createdAt" width="170" align="center">
<template v-slot="{row}">{{$moment(row.createdAt).format("YYYY-MM-DD HH:mm")}}</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center">
<template v-slot="{row}">
<el-button size="mini" type="primary" @click="openLedger(row)">查阅</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-drawer title="项目归档台账" :visible.sync="drawerVisible" size="82%" :destroy-on-close="true">
<div v-if="currentProject" style="padding:0 20px 20px">
<div class="archive-ledger-header">
<div class="archive-ledger-title">
{{currentProject.projectName}}
<el-tag size="small" :type="projectStatusType(currentProject.status)">
{{currentProject.statusLabel}}
</el-tag>
</div>
<div class="archive-ledger-meta">
<span>年度:{{currentProject.year}}</span>
<span>所属工会:{{currentProject.unionName}}</span>
<span>归档文档:{{currentProject.documentCount || 0}}</span>
</div>
</div>
<el-table :data="detailData" size="small">
<el-table-column label="序号" type="index" width="60"></el-table-column>
<el-table-column label="项目阶段" prop="projectStageLabel" width="120"></el-table-column>
<el-table-column label="文档名称" prop="documentName" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="文档类型" prop="docTypeName" min-width="140" show-overflow-tooltip></el-table-column>
<el-table-column label="上传人" prop="uploader" width="110"></el-table-column>
<el-table-column label="上传时间" width="160">
<template v-slot="{row}">{{row.uploadTime ? $moment(row.uploadTime).format("YYYY-MM-DD HH:mm") : "-"}}</template>
</el-table-column>
<el-table-column label="状态" width="120" align="center">
<template v-slot="{row}">
<el-tag size="small" :type="row.status === 1 ? 'success' : 'info'">{{row.statusLabel}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center">
<template v-slot="{row}">
<el-button size="mini" type="primary" @click="preview(row)">查看附件</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination style="margin-top:15px;text-align:center"
:current-page="detailForm.pageNumber"
:page-size="detailForm.pageSize"
:page-sizes="[10,20,50]"
:total="detailForm.totalCount"
layout="total, sizes, prev, pager, next"
@current-change="val=>{detailForm.pageNumber=val;loadDetail()}"
@size-change="val=>{detailForm.pageSize=val;detailForm.pageNumber=1;loadDetail()}">
</el-pagination>
</div>
</el-drawer>
<el-dialog title="附件预览" :visible.sync="previewVisible" width="760px">
<file-preview :files="previewFiles" complete_result></file-preview>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
tableData: [],
detailData: [],
unionOptions: [],
drawerVisible: false,
previewVisible: false,
previewFiles: [],
currentProject: null,
pageForm: {
year: String(new Date().getFullYear()),
projectName: "",
unionId: ""
},
detailForm: {pageNumber: 1, pageSize: 10, totalCount: 0, projectId: ""}
}
},
methods: {
normalizeFiles(files) {
if (Array.isArray(files)) return files
if (!files) return []
try { return JSON.parse(files) || [] } catch (e) { return [] }
},
projectStatusType(status) {
return status === 2 ? "success" : (status === 1 ? "warning" : "info")
},
pageData() {
this.$axios.post("/platform/archive/ledger/pageData", this.pageForm).then(res => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
loadUnions() {
this.$axios.post("/platform/archive/common/unionOptions").then(res => {
if (res.code === 0) this.unionOptions = res.data || []
})
},
openLedger(row) {
this.currentProject = row
this.detailForm = {pageNumber: 1, pageSize: 10, totalCount: 0, projectId: row.id}
this.drawerVisible = true
this.loadDetail()
},
loadDetail() {
this.$axios.post("/platform/archive/ledger/detail", this.detailForm).then(res => {
if (res.code === 0) {
this.detailData = (res.data.list || []).map(item =>
Object.assign({}, item, {files: this.normalizeFiles(item.files)}))
this.detailForm.totalCount = res.data.totalCount
}
})
},
preview(row) {
this.previewFiles = this.normalizeFiles(row.files)
if (!this.previewFiles.length) {
this.$message.warning("当前文档没有附件")
return
}
this.previewVisible = true
}
},
created() {
this.loadUnions()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -1,183 +0,0 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy"
clearable placeholder="请选择年度" style="width: 100%"
@change="doSearch"></el-date-picker>
</search-item>
<search-item label="项目名称">
<el-input v-model="pageForm.projectName" clearable placeholder="请输入项目名称"
@keyup.enter.native="doSearch"></el-input>
</search-item>
<search-item label="所属工会">
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择所属工会"
style="width: 100%" @change="doSearch">
<el-option v-for="item in unionOptions" :key="item.id"
:label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="项目状态">
<el-select v-model="pageForm.status" clearable placeholder="请选择项目状态"
style="width: 100%" @change="doSearch">
<el-option label="草稿" :value="0"></el-option>
<el-option label="归档中" :value="1"></el-option>
<el-option label="已完成" :value="2"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="归档项目">
<el-button type="primary" size="small" @click="openForm()">
<i class="ti-plus"></i> 新建项目
</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column label="年度" prop="year" width="90" align="center"></el-table-column>
<el-table-column label="项目名称" prop="projectName" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column label="项目状态" prop="status" width="110" align="center">
<template v-slot="{row}">
<el-tag size="small" :type="statusType(row.status)">{{row.statusLabel}}</el-tag>
</template>
</el-table-column>
<el-table-column label="所属工会" prop="unionName" min-width="160" show-overflow-tooltip></el-table-column>
<el-table-column label="归档文档数" prop="documentCount" width="110" align="center"></el-table-column>
<el-table-column label="创建时间" prop="createdAt" width="170" align="center">
<template v-slot="{row}">{{$moment(row.createdAt).format("YYYY-MM-DD HH:mm")}}</template>
</el-table-column>
<el-table-column label="操作" width="240" align="center">
<template v-slot="{row}">
<el-button size="mini" type="primary" @click="openForm(row)">编辑</el-button>
<el-button size="mini" type="success" @click="goFiling(row)">资料归档</el-button>
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="formData.id ? '编辑归档项目' : '新建归档项目'"
:visible.sync="formVisible" width="560px" :close-on-click-modal="false">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-form-item label="年度" prop="year">
<el-date-picker v-model="formData.year" type="year" value-format="yyyy"
placeholder="请选择年度" style="width: 100%"></el-date-picker>
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input v-model.trim="formData.projectName" maxlength="300" show-word-limit></el-input>
</el-form-item>
<el-form-item label="所属工会" prop="unionId">
<el-select v-model="formData.unionId" filterable placeholder="请选择所属工会"
style="width: 100%">
<el-option v-for="item in unionOptions" :key="item.id"
:label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="formData.id" label="项目状态">
<el-input :value="formData.statusLabel || '草稿'" disabled></el-input>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="formVisible=false">取消</el-button>
<el-button type="primary" @click="onSubmit">保存</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
tableData: [],
unionOptions: [],
formVisible: false,
formData: {},
pageForm: {
year: String(new Date().getFullYear()),
projectName: "",
unionId: "",
status: null
},
formRules: {
year: [{required: true, message: "请选择年度", trigger: "change"}],
projectName: [{required: true, message: "请输入项目名称", trigger: "blur"}],
unionId: [{required: true, message: "请选择所属工会", trigger: "change"}]
}
}
},
methods: {
statusType(status) {
return status === 2 ? "success" : (status === 1 ? "warning" : "info")
},
pageData() {
this.$axios.post("/platform/archive/project/pageData", this.pageForm).then(res => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
loadUnions() {
this.$axios.post("/platform/archive/common/unionOptions").then(res => {
if (res.code === 0) this.unionOptions = res.data || []
})
},
openForm(row) {
this.formData = row ? clone(row) : {
year: String(new Date().getFullYear()),
projectName: "",
unionId: ""
}
if (this.formData.year != null) this.formData.year = String(this.formData.year)
this.formVisible = true
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
},
onSubmit() {
this.$refs.formRef.validate(async valid => {
if (!valid) return
const data = Object.assign({}, this.formData, {year: Number(this.formData.year)})
const res = await this.$axios.post("/platform/archive/project/onSubmit", data)
if (res.code === 0) {
this.$message.success("保存成功")
this.formVisible = false
this.pageData()
} else {
this.$message.warning(res.msg)
}
})
},
onDelete(row) {
this.$confirm("确定删除归档项目“" + row.projectName + "”吗?", "提示", {type: "warning"})
.then(async () => {
const res = await this.$axios.post("/platform/archive/project/onDelete", {id: row.id})
if (res.code === 0) {
this.$message.success("删除成功")
this.pageData()
} else {
this.$message.warning(res.msg)
}
}).catch(() => {})
},
goFiling(row) {
window.location.href = "/platform/archive/filing?projectId=" + encodeURIComponent(row.id)
}
},
created() {
this.loadUnions()
this.pageData()
}
})
</script>
<!--#
}
#-->