增加文档管理功能
This commit is contained in:
@@ -114,6 +114,10 @@ func Init(_ string) {
|
||||
|
||||
new(OaSchedule),
|
||||
new(OaNotice),
|
||||
new(OaDocCategory),
|
||||
new(OaDoc),
|
||||
new(OaDocLink),
|
||||
new(OaDocShare),
|
||||
new(BackendOaCompensationScheme),
|
||||
new(BackendOaPayroll),
|
||||
new(BackendOaPayrollItem),
|
||||
@@ -127,4 +131,5 @@ func Init(_ string) {
|
||||
// 补齐历史库缺失的列(已存在时 MySQL 报 duplicate column,统一忽略)
|
||||
EnsureAdminRoleTenantColumn()
|
||||
EnsureAdminRoleCustomColumn()
|
||||
EnsureTenantUserOrgColumn()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// OA 文档管理(文档库 / 文档图谱)数据模型。
|
||||
//
|
||||
// 三张表按租户 tid 隔离:
|
||||
// - yz_backend_oa_doc_category 文档分类(树形,parent_id=0 为一级)
|
||||
// - yz_backend_oa_doc 文档主体(附件信息冗余存储,避免每次联查文件表)
|
||||
// - yz_backend_oa_doc_link 文档关联关系(引用/相关/版本/从属),文档图谱的连线来源
|
||||
|
||||
// OaDocCategory OA文档分类: yz_backend_oa_doc_category
|
||||
type OaDocCategory struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Tid int `orm:"column(tid)" json:"tid"`
|
||||
ParentID uint64 `orm:"column(parent_id);default(0)" json:"parent_id"`
|
||||
Name string `orm:"column(name);size(128)" json:"name"`
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"`
|
||||
Remark string `orm:"column(remark);size(255);default()" json:"remark"`
|
||||
IsDeleted int8 `orm:"column(is_deleted);default(0)" json:"is_deleted"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);auto_now;type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *OaDocCategory) TableName() string {
|
||||
return "yz_backend_oa_doc_category"
|
||||
}
|
||||
|
||||
// OaDoc OA文档: yz_backend_oa_doc
|
||||
// status: 0-草稿 1-已发布 2-已归档
|
||||
// doc_type: 0-其他 1-文档 2-表格 3-演示 4-PDF 5-图片 6-压缩包 7-视频 8-音频
|
||||
type OaDoc struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Tid int `orm:"column(tid)" json:"tid"`
|
||||
CategoryID uint64 `orm:"column(category_id);default(0)" json:"category_id"`
|
||||
Title string `orm:"column(title);size(255)" json:"title"`
|
||||
FileID uint64 `orm:"column(file_id);default(0)" json:"file_id"`
|
||||
FileURL string `orm:"column(file_url);size(512);default()" json:"file_url"`
|
||||
FileName string `orm:"column(file_name);size(255);default()" json:"file_name"`
|
||||
Ext string `orm:"column(ext);size(16);default()" json:"ext"`
|
||||
Size uint64 `orm:"column(size);default(0)" json:"size"`
|
||||
DocType int8 `orm:"column(doc_type);default(0)" json:"doc_type"`
|
||||
Tags string `orm:"column(tags);size(255);default()" json:"tags"`
|
||||
Summary string `orm:"column(summary);size(1000);default()" json:"summary"`
|
||||
Status int8 `orm:"column(status);default(0)" json:"status"`
|
||||
Version int `orm:"column(version);default(1)" json:"version"`
|
||||
IsStar int8 `orm:"column(is_star);default(0)" json:"is_star"`
|
||||
OwnerID uint64 `orm:"column(owner_id);default(0)" json:"owner_id"`
|
||||
OwnerName string `orm:"column(owner_name);size(100);default()" json:"owner_name"`
|
||||
ViewCount int `orm:"column(view_count);default(0)" json:"view_count"`
|
||||
DownCount int `orm:"column(download_count);default(0)" json:"download_count"`
|
||||
CreatorID uint64 `orm:"column(creator_id);default(0)" json:"creator_id"`
|
||||
CreatorName string `orm:"column(creator_name);size(100);default()" json:"creator_name"`
|
||||
// Visibility 可见性:0-租户公开(默认,租户内所有后台用户可见)1-私密(仅创建者与被共享者可见)
|
||||
Visibility int8 `orm:"column(visibility);default(0)" json:"visibility"`
|
||||
IsDeleted int8 `orm:"column(is_deleted);default(0)" json:"is_deleted"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);auto_now;type(datetime);null" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
|
||||
}
|
||||
|
||||
func (m *OaDoc) TableName() string {
|
||||
return "yz_backend_oa_doc"
|
||||
}
|
||||
|
||||
// OaDocLink OA文档关联: yz_backend_oa_doc_link
|
||||
// relation: reference-引用 related-相关 version-版本迭代 belong-从属
|
||||
type OaDocLink struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Tid int `orm:"column(tid)" json:"tid"`
|
||||
SourceID uint64 `orm:"column(source_id);default(0)" json:"source_id"`
|
||||
TargetID uint64 `orm:"column(target_id);default(0)" json:"target_id"`
|
||||
Relation string `orm:"column(relation);size(32);default(related)" json:"relation"`
|
||||
Remark string `orm:"column(remark);size(255);default()" json:"remark"`
|
||||
CreatorID uint64 `orm:"column(creator_id);default(0)" json:"creator_id"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
}
|
||||
|
||||
func (m *OaDocLink) TableName() string {
|
||||
return "yz_backend_oa_doc_link"
|
||||
}
|
||||
|
||||
// OaDocShare OA文档共享: yz_backend_oa_doc_share
|
||||
// 私密文档(visibility=1)在"创建者可见"之外,额外授权给指定用户或部门。
|
||||
// share_type: 0-用户(target_id 为 yz_system_tenant_user.uid)
|
||||
// 1-部门(target_id 为 yz_backend_organization.id,含其全部子部门)
|
||||
type OaDocShare struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
Tid int `orm:"column(tid)" json:"tid"`
|
||||
DocID uint64 `orm:"column(doc_id);default(0)" json:"doc_id"`
|
||||
ShareType int8 `orm:"column(share_type);default(0)" json:"share_type"`
|
||||
TargetID uint64 `orm:"column(target_id);default(0)" json:"target_id"`
|
||||
CreatorID uint64 `orm:"column(creator_id);default(0)" json:"creator_id"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
}
|
||||
|
||||
func (m *OaDocShare) TableName() string {
|
||||
return "yz_backend_oa_doc_share"
|
||||
}
|
||||
|
||||
// 文档类型常量(doc_type)
|
||||
const (
|
||||
DocTypeOther int8 = 0
|
||||
DocTypeDoc int8 = 1 // doc / docx / txt / md / rtf
|
||||
DocTypeSheet int8 = 2 // xls / xlsx / csv
|
||||
DocTypeSlide int8 = 3 // ppt / pptx
|
||||
DocTypePDF int8 = 4 // pdf
|
||||
DocTypeImage int8 = 5 // jpg / png / gif / bmp / webp
|
||||
DocTypeZip int8 = 6 // zip / rar / 7z / tar / gz
|
||||
DocTypeVideo int8 = 7
|
||||
DocTypeAudio int8 = 8
|
||||
)
|
||||
|
||||
// 文档状态常量(status)
|
||||
const (
|
||||
DocStatusDraft int8 = 0
|
||||
DocStatusPublish int8 = 1
|
||||
DocStatusArchive int8 = 2
|
||||
)
|
||||
|
||||
// 文档关联关系常量(relation)
|
||||
const (
|
||||
DocRelationReference = "reference"
|
||||
DocRelationRelated = "related"
|
||||
DocRelationVersion = "version"
|
||||
DocRelationBelong = "belong"
|
||||
)
|
||||
|
||||
// 文档可见性常量(visibility)
|
||||
const (
|
||||
DocVisibilityPublic int8 = 0 // 租户公开
|
||||
DocVisibilityPrivate int8 = 1 // 私密
|
||||
)
|
||||
|
||||
// 文档共享目标类型常量(share_type)
|
||||
const (
|
||||
DocShareTypeUser int8 = 0 // 共享给指定用户(target_id = yz_system_tenant_user.uid)
|
||||
DocShareTypeOrg int8 = 1 // 共享给部门(target_id = yz_backend_organization.id,含子部门)
|
||||
)
|
||||
|
||||
// extDocTypeMap 扩展名 -> 文档类型
|
||||
var extDocTypeMap = map[string]int8{
|
||||
"doc": DocTypeDoc, "docx": DocTypeDoc, "txt": DocTypeDoc, "md": DocTypeDoc,
|
||||
"rtf": DocTypeDoc, "wps": DocTypeDoc, "odt": DocTypeDoc,
|
||||
"xls": DocTypeSheet, "xlsx": DocTypeSheet, "csv": DocTypeSheet, "ods": DocTypeSheet,
|
||||
"ppt": DocTypeSlide, "pptx": DocTypeSlide, "odp": DocTypeSlide,
|
||||
"pdf": DocTypePDF,
|
||||
"jpg": DocTypeImage, "jpeg": DocTypeImage, "png": DocTypeImage,
|
||||
"gif": DocTypeImage, "bmp": DocTypeImage, "webp": DocTypeImage, "svg": DocTypeImage,
|
||||
"zip": DocTypeZip, "rar": DocTypeZip, "7z": DocTypeZip, "tar": DocTypeZip, "gz": DocTypeZip,
|
||||
"mp4": DocTypeVideo, "webm": DocTypeVideo, "mov": DocTypeVideo, "avi": DocTypeVideo,
|
||||
"mp3": DocTypeAudio, "wav": DocTypeAudio, "ogg": DocTypeAudio,
|
||||
}
|
||||
|
||||
// DocTypeByExt 根据扩展名推断文档类型,未知返回"其他"。
|
||||
func DocTypeByExt(ext string) int8 {
|
||||
if t, ok := extDocTypeMap[strings.ToLower(strings.TrimPrefix(strings.TrimSpace(ext), "."))]; ok {
|
||||
return t
|
||||
}
|
||||
return DocTypeOther
|
||||
}
|
||||
|
||||
var oaDocumentTableOnce sync.Once
|
||||
|
||||
// EnsureOaDocumentTables 首次访问文档接口时自动建表(若不存在)。
|
||||
// 与通知公告/日程保持一致的运行期自愈策略,避免新功能上线还需手工执行建表脚本。
|
||||
func EnsureOaDocumentTables() error {
|
||||
if Orm == nil {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
oaDocumentTableOnce.Do(func() {
|
||||
_, err = Orm.Raw(`
|
||||
CREATE TABLE IF NOT EXISTS yz_backend_oa_doc_category (
|
||||
id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
tid int NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||
parent_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '父级ID,0为一级分类',
|
||||
name varchar(128) NOT NULL DEFAULT '' COMMENT '分类名称',
|
||||
sort int NOT NULL DEFAULT 0 COMMENT '排序,越小越靠前',
|
||||
remark varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
is_deleted tinyint NOT NULL DEFAULT 0 COMMENT '是否删除 0-否 1-是',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
update_time datetime DEFAULT NULL COMMENT '更新时间',
|
||||
delete_time datetime DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_tid_parent (tid, parent_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='OA文档分类表'`).Exec()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Orm.Raw(`
|
||||
CREATE TABLE IF NOT EXISTS yz_backend_oa_doc (
|
||||
id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
tid int NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||
category_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '所属分类ID,0为未分类',
|
||||
title varchar(255) NOT NULL DEFAULT '' COMMENT '文档标题',
|
||||
file_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '关联附件ID(yz_system_files)',
|
||||
file_url varchar(512) NOT NULL DEFAULT '' COMMENT '附件访问地址',
|
||||
file_name varchar(255) NOT NULL DEFAULT '' COMMENT '原始文件名',
|
||||
ext varchar(16) NOT NULL DEFAULT '' COMMENT '扩展名',
|
||||
size bigint unsigned NOT NULL DEFAULT 0 COMMENT '文件大小(字节)',
|
||||
doc_type tinyint NOT NULL DEFAULT 0 COMMENT '类型 0-其他 1-文档 2-表格 3-演示 4-PDF 5-图片 6-压缩包 7-视频 8-音频',
|
||||
tags varchar(255) NOT NULL DEFAULT '' COMMENT '标签,逗号分隔',
|
||||
summary varchar(1000) NOT NULL DEFAULT '' COMMENT '摘要/描述',
|
||||
status tinyint NOT NULL DEFAULT 0 COMMENT '状态 0-草稿 1-已发布 2-已归档',
|
||||
version int NOT NULL DEFAULT 1 COMMENT '版本号',
|
||||
is_star tinyint NOT NULL DEFAULT 0 COMMENT '是否收藏 0-否 1-是',
|
||||
owner_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '负责人ID',
|
||||
owner_name varchar(100) NOT NULL DEFAULT '' COMMENT '负责人姓名',
|
||||
view_count int NOT NULL DEFAULT 0 COMMENT '查看次数',
|
||||
download_count int NOT NULL DEFAULT 0 COMMENT '下载次数',
|
||||
creator_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '创建人ID',
|
||||
creator_name varchar(100) NOT NULL DEFAULT '' COMMENT '创建人姓名',
|
||||
visibility tinyint NOT NULL DEFAULT 0 COMMENT '可见性 0-租户公开 1-私密(仅创建者与被共享者)',
|
||||
is_deleted tinyint NOT NULL DEFAULT 0 COMMENT '是否删除 0-否 1-是',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
update_time datetime DEFAULT NULL COMMENT '更新时间',
|
||||
delete_time datetime DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_tid_cate (tid, category_id, is_deleted),
|
||||
KEY idx_tid_status (tid, status, is_deleted),
|
||||
KEY idx_tid_title (tid, title)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='OA文档表'`).Exec()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Orm.Raw(`
|
||||
CREATE TABLE IF NOT EXISTS yz_backend_oa_doc_link (
|
||||
id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
tid int NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||
source_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '源文档ID',
|
||||
target_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '目标文档ID',
|
||||
relation varchar(32) NOT NULL DEFAULT 'related' COMMENT '关系 reference-引用 related-相关 version-版本 belong-从属',
|
||||
remark varchar(255) NOT NULL DEFAULT '' COMMENT '关系说明',
|
||||
creator_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '创建人ID',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_doc_pair (tid, source_id, target_id, relation),
|
||||
KEY idx_tid_source (tid, source_id),
|
||||
KEY idx_tid_target (tid, target_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='OA文档关联表'`).Exec()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 历史库补齐 visibility 列(已存在时 MySQL 报 duplicate column,忽略)
|
||||
_, _ = Orm.Raw(`
|
||||
ALTER TABLE yz_backend_oa_doc
|
||||
ADD COLUMN visibility tinyint NOT NULL DEFAULT 0 COMMENT '可见性 0-租户公开 1-私密(仅创建者与被共享者)'
|
||||
`).Exec()
|
||||
|
||||
_, err = Orm.Raw(`
|
||||
CREATE TABLE IF NOT EXISTS yz_backend_oa_doc_share (
|
||||
id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
tid int NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||
doc_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '文档ID',
|
||||
share_type tinyint NOT NULL DEFAULT 0 COMMENT '共享类型 0-用户(target_id=uid) 1-部门(target_id=org_id,含子部门)',
|
||||
target_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '共享目标ID',
|
||||
creator_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '授权人ID',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_doc_target (tid, doc_id, share_type, target_id),
|
||||
KEY idx_tid_doc (tid, doc_id),
|
||||
KEY idx_target (tid, share_type, target_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='OA文档共享表'`).Exec()
|
||||
})
|
||||
return err
|
||||
}
|
||||
@@ -19,6 +19,9 @@ type SystemTenantUser struct {
|
||||
Password *string `orm:"column(password);size(255);null" json:"password"`
|
||||
IsDefault int8 `orm:"column(is_default);default(0)" json:"is_default"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||
// OrgID 所属组织(部门),关联 yz_backend_organization(id);0 表示未分配。
|
||||
// 用于文档私密共享等需要按部门判定可见性的场景。
|
||||
OrgID uint64 `orm:"column(org_id);default(0)" json:"org_id"`
|
||||
Remark *string `orm:"column(remark);size(255);null" json:"remark"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);auto_now;type(datetime);null" json:"update_time"`
|
||||
@@ -44,3 +47,19 @@ func EnsureTenantUserGroupColumn() {
|
||||
`).Exec()
|
||||
})
|
||||
}
|
||||
|
||||
var tenantUserOrgColOnce sync.Once
|
||||
|
||||
// EnsureTenantUserOrgColumn 为租户用户表补齐 org_id(所属部门)列。
|
||||
// 与 group_id 同样的幂等策略:字段已存在时 MySQL 报 duplicate column,统一忽略。
|
||||
func EnsureTenantUserOrgColumn() {
|
||||
if Orm == nil {
|
||||
return
|
||||
}
|
||||
tenantUserOrgColOnce.Do(func() {
|
||||
_, _ = Orm.Raw(`
|
||||
ALTER TABLE yz_system_tenant_user
|
||||
ADD COLUMN org_id bigint unsigned NOT NULL DEFAULT 0 COMMENT '所属组织ID 关联 yz_backend_organization(id),0-未分配'
|
||||
`).Exec()
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user