{
+ const history = useHistory();
+ // 渲染数据项
+ const renderDataItem = (
+ title: string,
+ number: string | number,
+ size?: number,
+ info?: string,
+ ) => {
+ return (
+
+
{title}
+
{number}
+ {size && size > 0 &&
大小:{formatSize(size)}
}
+ {info && info.length > 0 &&
{info}
}
+
+ );
+ };
+ // 渲染沟通信息
+ const RenderChat: React.FC = () => {
+ const [msgCount, setMsgCount] = useState(0);
+ const [loaded] = useFlagCmdEmitter('session', () => {
+ setMsgCount(
+ orgCtrl.chats
+ .map((i) => {
+ return i.isMyChat ? i.badgeCount : 0;
+ })
+ .reduce((total, count) => total + count, 0),
+ );
+ });
+ return (
+ <>
+
+ 沟通
+
+
+ 未读<>{msgCount}>条
+
+
+
+
+
+
+ } size={2}>
+ {renderDataItem('好友(人)', orgCtrl.user.members.length)}
+ {renderDataItem(
+ '同事(个)',
+ orgCtrl.user.companys
+ .map((i) => i.members.map((i) => i.id))
+ .reduce(
+ (ids, current) => [
+ ...ids,
+ ...current.filter((i) => !ids.includes(i)),
+ ],
+ [],
+ ).length,
+ )}
+ {renderDataItem(
+ '群聊(个)',
+ orgCtrl.chats.filter((i) => i.isMyChat && i.isGroup).length,
+ )}
+ {renderDataItem('单位(家)', orgCtrl.user.companys.length)}
+
+
+
+ >
+ );
+ };
+ // 渲染办事信息
+ const RenderWork: React.FC = () => {
+ const [todoCount, setTodoCount] = useState(0);
+ const [ApplyCount, setApplyCount] = useState(0);
+ const [CopysCount, setCopysCount] = useState(0);
+ const [CompletedCount, setCompletedCount] = useState(0);
+ useEffect(() => {
+ const id = orgCtrl.work.notity.subscribe(() => {
+ setTodoCount(orgCtrl.work.todos.length);
+ orgCtrl.work.loadTaskCount('已发起').then((v) => {
+ setApplyCount(v);
+ });
+ orgCtrl.work.loadTaskCount('抄送').then((v) => {
+ setCopysCount(v);
+ });
+ orgCtrl.work.loadTaskCount('已办').then((v) => {
+ setCompletedCount(v);
+ });
+ });
+ return () => {
+ orgCtrl.unsubscribe(id);
+ };
+ }, []);
+ return (
+ <>
+
+ 办事
+
+
+ 待办{todoCount}件
+
+
+
+
+
+ } size={2}>
+ {renderDataItem('待办', todoCount)}
+ {renderDataItem('已办', CompletedCount)}
+ {renderDataItem('抄送', CopysCount)}
+ {renderDataItem('已发起', ApplyCount)}
+
+
+ >
+ );
+ };
+ // 渲染存储数据信息
+ const RendeStore: React.FC = () => {
+ const [noStore, setNoStore] = useState(false);
+ const [diskInfo, setDiskInfo] = useState();
+ useEffect(() => {
+ orgCtrl.user.getDiskInfo().then((value) => {
+ setDiskInfo(value);
+ setNoStore(value === undefined);
+ });
+ }, []);
+ return (
+ <>
+
+
数据
+
+
+

+
+ 管理数据
+
+
+
+ } size={6}>
+ {diskInfo && (
+ <>
+ {renderDataItem(
+ `关系(个)`,
+ orgCtrl.chats.filter(
+ (i) => i.isMyChat && i.typeName !== TargetType.Group,
+ ).length,
+ -1,
+ `共计:${orgCtrl.chats.length}个`,
+ )}
+ {renderDataItem(`数据集(个)`, diskInfo.collections, diskInfo.dataSize)}
+ {renderDataItem(`对象数(个)`, diskInfo.objects, diskInfo.totalSize)}
+ {renderDataItem(`文件(个)`, diskInfo.filesCount, diskInfo.filesSize)}
+ {renderDataItem(
+ `硬件`,
+ formatSize(diskInfo.fsUsedSize),
+ diskInfo.fsTotalSize,
+ )}
+ >
+ )}
+ {noStore && (
+
+ {`您还未申请存储资源,
+ 您将无法使用本系统,
+ 请申请加入您的存储资源群(用来存储您的数据),
+ 个人用户试用存储群为(orginone_data),
+ 申请通过后请在关系中激活使用哦!`}
+
+ )}
+
+
+ >
+ );
+ };
+ // 渲染常用信息
+ const RendeCommonInfo: React.FC = () => {
+ const [editMode, setEditMode] = useState(false);
+ const [commonFiles, setCommonFiles] = useState([]);
+ const [groups, setGroups] = useState({});
+ const [loaded] = useFlagCmdEmitter('commons', async () => {
+ setCommonFiles(await orgCtrl.loadCommons());
+ });
+ const loadGroups = () => {
+ const letGroups: any = { 其它: [] };
+ for (const item of orgCtrl.user.commons) {
+ const file = commonFiles.find(
+ (i) => i.id === item.id && i.spaceId === item.spaceId,
+ );
+ if (file) {
+ const groupName = item.groupName ?? '其它';
+ letGroups[groupName] = letGroups[groupName] || [];
+ letGroups[groupName].push({
+ file,
+ common: item,
+ });
+ }
+ }
+
+ return letGroups;
+ };
+ useEffect(() => {
+ if (loaded) {
+ const groups = loadGroups();
+ setGroups(groups);
+ }
+ }, [loaded, commonFiles, orgCtrl.user.commons]);
+
+ const contextMenu = (file: IFile) => {
+ return {
+ items: cleanMenus(loadFileMenus(file)) || [],
+ onClick: ({ key }: { key: string }) => {
+ command.emitter('executor', key, file);
+ },
+ };
+ };
+ // 加载常用
+ const loadCommonCard = (item: IFile, index: number) => {
+ if (index < 3) {
+ return (
+
+ {
+ command.emitter('executor', 'open', item);
+ }}>
+ {item.cache.tags?.includes('常用') ? (
+
+
+
+ ) : (
+
+ )}
+
{item.name}
+
{item.directory.target.name}
+ {/*
{item.directory.target.space.name}
*/}
+
+
+ );
+ }
+ };
+
+ const loadGroupItem = (title: string, data: any[], index: number) => {
+ if (data.length < 1) return ;
+ if (index > 2) return ;
+ return (
+
+
+ {title}
+
+
+ } size={2}>
+ {
+ setGroups((pre: any) => {
+ const data = pre[e.fromData].splice(e.fromIndex, 1);
+ data.forEach((item: any) => {
+ item.common.groupName = e.toData;
+ if (item.common.groupName === '其它') {
+ delete item.common.groupName;
+ }
+ pre[e.toData].push(item);
+ });
+ return { ...pre };
+ });
+ }}>
+ {data.map((subapp, index) => {
+ return loadCommonCard(subapp.file, index);
+ })}
+
+
+
+
+ );
+ };
+ return (
+ <>
+
+
常用
+
setEditMode((pre) => !pre)}>
+
+

+
+ 编辑分组
+
+
+
+
+
+ {Object.keys(groups).map((groupName, index) => {
+ return loadGroupItem(groupName, groups[groupName], index);
+ })}
+
+
+
+ {editMode && (
+ {
+ orgCtrl.user.updateCommons(commons);
+ setEditMode(false);
+ }}
+ />
+ )}
+ >
+ );
+ };
+ // 渲染全部应用
+ const RendelastInfo: React.FC = () => {
+ const [editMode, setEditMode] = useState(false);
+ const [appData, setappData] = useState([]);
+ const [loaded, setLoaded] = useState(false);
+ const [groupsData, setGroupsData] = useState([]);
+ useEffect(() => {
+ orgCtrl.loadApplications().then((res) => {
+ setappData(res);
+ changeGroups(res);
+ setLoaded(true);
+ });
+ }, []);
+ const changeGroups = (res: IApplication[]) => {
+ let result = res.reduce((acc: any, item) => {
+ let key = item.belong.name;
+ if (!acc[key]) {
+ acc[key] = [];
+ }
+ let targetKey = item.directory.target.name;
+ if (!acc[key][targetKey]) {
+ acc[key][targetKey] = [];
+ }
+ acc[key][targetKey].push(item);
+ return acc;
+ }, {});
+ setGroupsData(result);
+ };
+ const contextMenu = (file: IFile) => {
+ return {
+ items: cleanMenus(loadFileMenus(file)) || [],
+ onClick: ({ key }: { key: string }) => {
+ command.emitter('executor', key, file);
+ },
+ };
+ };
+ // 加载前8个应用
+ const loadCommonCard = (item: IFile) => (
+
+ {
+ command.emitter('executor', 'open', item);
+ }}>
+
+
{item.name}
+
+
+ );
+ // 根据三级分类显示全部应用
+ const loadAllGruopCard = () => {
+ let data: any = groupsData;
+ const items = [];
+ for (const key in data) {
+ items.push(
+
+
{key}
+ {data[key] &&
+ Object.keys(data[key]).map((subKey) => {
+ return (
+
+
{subKey}
+
+ {data[key][subKey].map((item: any) => {
+ return (
+
+ {
+ command.emitter('executor', 'open', item);
+ }}>
+
+
{item.name}
+
+
+ );
+ })}
+
+
+ );
+ })}
+
,
+ );
+ }
+ return items;
+ };
+
+ return (
+ <>
+
+
最近应用
+
setEditMode((pre) => !pre)}>
+
+

+
+ 全部应用
+
+
+
+
+
+ {appData.slice(-8).map((app) => {
+ return loadCommonCard(app);
+ })}
+
+
+
+ {editMode && (
+ setEditMode((pre) => !pre)}>
+ {loadAllGruopCard()}
+
+ )}
+ >
+ );
+ };
+ // 日历组件
+ const calendarItem = () => {
+ return (
+
+
+ 日历
+ {/*
+
+ */}
+
+
+
+ );
+ };
+ // 操作组件
+ const RenderOperate = () => {
+ // 发送快捷命令
+ const renderCmdBtn = (cmd: string, title: string) => {
+ return (
+
+ );
+ };
+ return (
+ <>
+
+ 快捷操作
+ history.push('relation')}>
+ 更多操作
+
+
+
+ } size={6}>
+ {renderCmdBtn('joinFriend', '添加好友')}
+ {renderCmdBtn('joinStorage', '申请存储')}
+ {renderCmdBtn('newCohort', '创建群聊')}
+ {renderCmdBtn('joinCohort', '加入群聊')}
+ {renderCmdBtn('newCompany', '设立单位')}
+ {renderCmdBtn('joinCompany', '加入单位')}
+
+
+ >
+ );
+ };
+ return (
+
+
+
+
+
history.push('chat')}>
+
+
+
history.push('work')}>
+
+
+
+
+
+
history.push('store')}>
+
+
+
+
{calendarItem()}
+
+ );
+};
+
+export default WorkBench;
diff --git a/src/pages/Home/components/NavigationBar/index.tsx b/src/pages/Home/components/NavigationBar/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1482505ade80299567484fda54ea754be0d0e95e
--- /dev/null
+++ b/src/pages/Home/components/NavigationBar/index.tsx
@@ -0,0 +1,189 @@
+import React, { useEffect, useState } from 'react';
+
+import BasicTitle from '@/pages/Home/components/BaseTitle';
+import { command } from '@/ts/base';
+import orgCtrl from '@/ts/controller';
+import { IPageTemplate } from '@/ts/core/thing/standard/page';
+import { EllipsisOutlined, MinusCircleFilled, PlusCircleFilled } from '@ant-design/icons';
+import { Badge, Button, Row, Typography, message } from 'antd';
+import { NavigationItem } from '../..';
+import { ViewerHost } from '@/executor/open/page/view/ViewerHost';
+import ViewerManager from '@/executor/open/page/view/ViewerManager';
+import { getResouces } from '@/config/location';
+import { generateUuid } from '@/utils/excel';
+const resource = getResouces();
+
+export const allPages: NavigationItem[] = [
+ {
+ key: 'workbench',
+ label: '工作台',
+ type: 'inner',
+ backgroundImageUrl: `/img/${resource.location}/banner/workbench.png`,
+ component: React.lazy(() => import('../Content/WorkBench')),
+ },
+ {
+ key: 'activity',
+ label: '群动态',
+ type: 'inner',
+ backgroundImageUrl: `/img/${resource.location}/banner/groupactivity.png`,
+ component: React.lazy(() => import('../Content/Activity/cohort')),
+ },
+ {
+ key: 'circle',
+ label: '好友圈',
+ type: 'inner',
+ backgroundImageUrl: `/img/${resource.location}/banner/friendactivity.png`,
+ component: React.lazy(() => import('../Content/Activity/friends')),
+ },
+];
+
+const NavigationBar: React.FC<{
+ list: NavigationItem[];
+ onChange: (item: NavigationItem) => void;
+}> = ({ list, onChange }) => {
+ const [current, setCurrent] = useState(0);
+ const [more, setMore] = useState(false);
+ const [pages, setPages] = useState([]);
+ const mapping = (item: IPageTemplate) => {
+ const navigation: NavigationItem = {
+ key: generateUuid(),
+ label: item.name,
+ backgroundImageUrl: '',
+ type: 'page',
+ component: ,
+ };
+ return navigation;
+ };
+ useEffect(() => {
+ const id = command.subscribeByFlag('pages', async () => {
+ setPages(await orgCtrl.loadPages());
+ });
+ return () => {
+ command.unsubscribeByFlag(id);
+ };
+ }, []);
+ const regularNavigation = (
+ <>
+
+ {[
+ ...list,
+ ...pages.filter((item) => item.cache.tags?.includes('常用')).map(mapping),
+ ].map((item, index) => {
+ return (
+
{
+ setCurrent(index);
+ onChange(item);
+ }}>
+ {item.label}
+
+ );
+ })}
+
+ {
+ setMore(true);
+ }}
+ className="navigationBar-more"
+ />
+ >
+ );
+
+ const configNavigation = (
+ <>
+
+
+
+
+
+
+
常用页面
+
+ {pages
+ .filter((item) => item.cache.tags?.includes('常用'))
+ .map((item, index) => {
+ return (
+ {
+ removeRegularNavigationItem(item);
+ }}
+ style={{ color: 'red' }}
+ />
+ }
+ key={index}>
+
+
{item.name}
+
{item.title}
+
+
+ );
+ })}
+
+
+
+
全部页面
+
+ {pages.map((item, index) => {
+ return (
+ {
+ addRegularNavigationItem(item);
+ }}
+ style={{ color: 'blue' }}
+ />
+ )
+ }
+ key={index}>
+
+
{item.name}
+
{item.title}
+
+
+ );
+ })}
+
+
+
+ >
+ );
+
+ const removeRegularNavigationItem = (item: IPageTemplate) => {
+ item.cache.tags = item.cache.tags?.filter((i) => i != '常用');
+ item.cacheUserData(true);
+ message.success('移除页面');
+ };
+
+ const addRegularNavigationItem = (item: IPageTemplate) => {
+ item.cache.tags = item.cache.tags || [];
+ item.cache.tags.push('常用');
+ item.cacheUserData(true);
+ message.success('添加页面');
+ };
+
+ const onSave = () => {
+ message.success('保存成功');
+ setMore(false);
+ };
+ return (
+
+ {more ? configNavigation : regularNavigation}
+
+ );
+};
+
+export default NavigationBar;
diff --git a/src/ts/base/model.ts b/src/ts/base/model.ts
index 07ebf3d852ed167eb8dd3d7762ffb14f8496bb7a..efb983df3a6c73ec4d5c4d7fc5fc0af548fc193a 100644
--- a/src/ts/base/model.ts
+++ b/src/ts/base/model.ts
@@ -12,7 +12,7 @@ import {
XStandard,
XTarget,
XThing,
- XTagFilter
+ XTagFilter,
} from './schema';
// 请求类型定义
export type ReqestType = {
@@ -691,6 +691,8 @@ export type FieldModel = {
name: string;
/** 代码(属性代码) */
code: string;
+ /** 代码(原始特性代码) */
+ info?: string;
/** 类型(属性类型) */
valueType: string;
/** 规则(特性规则) */
@@ -826,7 +828,7 @@ export type speciesListItem = {
// 筛选名称
name: string;
// 分类名称
- typeName: string
+ typeName: string;
// 编码
code: string;
// 值
@@ -913,7 +915,7 @@ export type speciesFilter = {
// 条件文本
remark: string;
// 分类数据
- speciesList: XTagFilter[]
+ speciesList: XTagFilter[];
};
export type MappingData = {
@@ -1104,6 +1106,10 @@ export type FileItemModel = {
isDirectory: boolean;
/** 是否包含子目录 */
hasSubDirectories: boolean;
+ /** 归属id */
+ belongId: string;
+ // /** 是否引用文件 */
+ isLinkFile?: boolean;
} & FileItemShare;
/** 桶支持的操作 */
diff --git a/src/ts/base/schema.ts b/src/ts/base/schema.ts
index 60809f16358486de9bf0362bb6ea12d8e0a82f2d..f0cb04cc7c6146aae740484fb2e628296bf08a32 100644
--- a/src/ts/base/schema.ts
+++ b/src/ts/base/schema.ts
@@ -752,3 +752,9 @@ export interface XPageTemplate extends XStandard {
// 模板类型
kind?: string;
}
+
+export type XFileLink = {
+ // 文件目录id
+ directoryId: string;
+} & model.FileItemModel &
+ Xbase;
diff --git a/src/ts/controller/index.ts b/src/ts/controller/index.ts
index ab4c502d276df365416bdd6fd8272a6622f1a5ae..45e071e34972e2af8f9cd3d0db3794bd7959f6f1 100644
--- a/src/ts/controller/index.ts
+++ b/src/ts/controller/index.ts
@@ -4,6 +4,7 @@ import { IWorkProvider } from '../core/work/provider';
import { IPageTemplate } from '../core/thing/standard/page';
import { IBoxProvider } from '../core/work/box';
import { AuthProvider } from '../core/auth';
+import { uniqueArrayBy } from '@/utils';
/** 控制器基类 */
export class Controller extends common.Emitter {
public currentKey: string;
@@ -108,7 +109,7 @@ class IndexController extends Controller {
const templates = await directory.loadAllTemplate();
pages.push(...templates.filter((item) => item.metadata.public));
}
- return pages;
+ return uniqueArrayBy(pages, 'fromPath');
}
}
diff --git a/src/ts/core/public/operates.ts b/src/ts/core/public/operates.ts
index 5627e1c4f767ae90a6eb381c3db9d622e3d5b17a..6d197fd61a5334ddd4451ffc64c5bd9a9e79cfcf 100644
--- a/src/ts/core/public/operates.ts
+++ b/src/ts/core/public/operates.ts
@@ -67,7 +67,7 @@ export const fileOperates = {
sort: 20,
cmd: 'download',
label: '下载文件',
- iconType: 'rename',
+ iconType: 'download',
},
Copy: {
sort: 21,
@@ -143,7 +143,7 @@ export const directoryOperates = {
sort: 1,
cmd: 'newApp',
label: '新建应用',
- iconType: '应用',
+ iconType: '新建应用',
},
Standard: {
sort: 2,
@@ -161,19 +161,19 @@ export const directoryOperates = {
sort: 3,
cmd: 'newSpecies',
label: '新建分类',
- iconType: '分类',
+ iconType: '新建分类',
},
NewDict: {
sort: 4,
cmd: 'newDict',
label: '新建字典',
- iconType: '字典',
+ iconType: '新建字典',
},
NewProperty: {
sort: 5,
cmd: 'newProperty',
label: '新建属性',
- iconType: '属性',
+ iconType: 'newProperty',
},
NewWork: {
sort: 6,
@@ -185,13 +185,13 @@ export const directoryOperates = {
sort: 7,
cmd: 'newModule',
label: '新建模块',
- iconType: '模块',
+ iconType: '新建模块',
},
NewForm: {
sort: 8,
cmd: 'newForm',
label: '新建表单',
- iconType: '事项配置',
+ iconType: '新建表单',
},
NewTransferConfig: {
sort: 9,
@@ -203,7 +203,7 @@ export const directoryOperates = {
sort: 11,
cmd: 'newPageTemplate',
label: '新建页面模板',
- iconType: '页面模板',
+ iconType: '新建页面模板',
},
};
@@ -293,7 +293,7 @@ export const targetOperates = {
sort: 35,
cmd: 'newGroup',
label: '设立集群',
- iconType: '组织群',
+ iconType: 'setCluster',
},
NewDepartment: {
sort: 36,
@@ -317,7 +317,7 @@ export const targetOperates = {
sort: 43,
cmd: 'joinStorage',
label: '加入存储资源群',
- iconType: '存储资源',
+ iconType: 'joinStorage',
},
Chat: {
sort: 15,
diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts
index 0a8fd813cd303d49bc2fee75359b992b2de48ec6..9796eff3c9628de828702bd0ad6b42de21cbc3d2 100644
--- a/src/ts/core/thing/directory.ts
+++ b/src/ts/core/thing/directory.ts
@@ -234,6 +234,16 @@ export class Directory extends StandardFileInfo implements ID
return new SysFileInfo(item, this);
});
}
+ // 查询是否包含引用文件
+ const fileLinks = this.resource.fileLinkColl.cache.filter(
+ (i) => i.directoryId === this.id,
+ );
+ if (Array.isArray(fileLinks) && fileLinks.length > 0) {
+ const linkFiles = fileLinks.map((item) => {
+ return new SysFileInfo(item, this);
+ });
+ this.files.push(...linkFiles);
+ }
}
return this.files;
}
@@ -366,6 +376,10 @@ export class Directory extends StandardFileInfo implements ID
destDirectory.id,
isSameBelong,
);
+ await directory.loadFiles();
+ for (const file of await directory.files) {
+ await file.copy(destDirectory);
+ }
for (const app of await directory.standard.applications) {
await app.copy(destDirectory);
}
diff --git a/src/ts/core/thing/resource.ts b/src/ts/core/thing/resource.ts
index 17953847fb4aa1327036a718ea13d2a2d2e40397..9882929979842bb6a24adb6495b43a46a6d4053f 100644
--- a/src/ts/core/thing/resource.ts
+++ b/src/ts/core/thing/resource.ts
@@ -11,6 +11,7 @@ import {
XPageTemplate,
XStaging,
XThing,
+ XFileLink,
} from '../../base/schema';
import { BucketOpreates, ChatMessageType, Transfer } from '@/ts/base/model';
import { kernel, model } from '@/ts/base';
@@ -38,6 +39,7 @@ export class DataResource {
this.templateColl = this.genTargetColl('standard-page-template');
this.stagingColl = this.genTargetColl('resource-staging');
this.thingColl = this.genTargetColl('_system-things');
+ this.fileLinkColl = this.genTargetColl('resource-file-link');
}
/** 表单集合 */
@@ -64,6 +66,8 @@ export class DataResource {
stagingColl: XCollection;
/** 实体集合 */
thingColl: XCollection;
+ /** 文件引用数据集合 */
+ fileLinkColl: XCollection;
/** 资源对应的用户信息 */
get targetMetadata() {
return this.target;
@@ -75,6 +79,7 @@ export class DataResource {
this.directoryColl.all(reload),
this.applicationColl.all(reload),
this.templateColl.all(reload),
+ this.fileLinkColl.all(reload),
]);
}
this._proLoaded = true;
diff --git a/src/ts/core/thing/standard/form.ts b/src/ts/core/thing/standard/form.ts
index c00b038af6a947435bfcddbb6637988aa80d7709..11e1fcf6fa490c24d49c00e9011534f6fd82424e 100644
--- a/src/ts/core/thing/standard/form.ts
+++ b/src/ts/core/thing/standard/form.ts
@@ -154,6 +154,7 @@ export class Form extends StandardFileInfo implements IForm {
widget: attr.widget,
options: attr.options,
code: `T${attr.propId}`,
+ info: attr.code,
remark: attr.remark,
lookups: [],
valueType: attr.property!.valueType,
@@ -167,6 +168,8 @@ export class Form extends StandardFileInfo implements IForm {
text: i.name,
value: `S${i.id}`,
icon: i.icon,
+ info: i.info,
+ remark: i.remark,
parentId: i.parentId,
};
});
diff --git a/src/ts/core/thing/standard/page.ts b/src/ts/core/thing/standard/page.ts
index e1525426fffdf7e29e242ad18bce5b682fe4c89f..0b1ee0caac2a1180fb6303ae8889b9e35425fcc0 100644
--- a/src/ts/core/thing/standard/page.ts
+++ b/src/ts/core/thing/standard/page.ts
@@ -3,10 +3,14 @@ import { IDirectory } from '../directory';
import { IStandardFileInfo, StandardFileInfo } from '../fileinfo';
import { ISpecies, Species } from './species';
import { IWork } from '../../work';
-import { IForm } from '../..';
+import { IForm, TargetType } from '../..';
import { Form } from './form';
export interface IPageTemplate extends IStandardFileInfo {
+ /** 来源名称 */
+ title?: string;
+ /** 数据来源 */
+ fromPath?: string;
/** 触发器 */
command: Command;
/** 关系 */
@@ -45,6 +49,26 @@ export class PageTemplate
[this.directory.target.spaceId, this.directory.target.id].join('-')
);
}
+ get title() {
+ const companyName = this.directory.target.user.findShareById(
+ this.directory.target.spaceId,
+ ).name;
+ const { name: targetName, typeName: targetTypeName } = this.directory.target;
+ return companyName === targetName || targetTypeName === TargetType.Group
+ ? `(${targetName})`
+ : `(${companyName}-${targetName})`;
+ }
+ get fromPath() {
+ return (
+ this.directory.target.typeName +
+ '-' +
+ this.directory.target.id +
+ '-' +
+ this.belongId +
+ '-' +
+ this.id
+ );
+ }
async copy(destination: IDirectory): Promise {
if (this.allowCopy(destination)) {
return await super.copyTo(destination.id, destination.resource.templateColl);
diff --git a/src/ts/core/thing/systemfile.ts b/src/ts/core/thing/systemfile.ts
index 698ca75a1fca33192af3dd1031f0ad9af518323e..fb1df28ebcadd25e4f8e4a3b27f1952a62ff0559 100644
--- a/src/ts/core/thing/systemfile.ts
+++ b/src/ts/core/thing/systemfile.ts
@@ -1,5 +1,5 @@
import { model, schema } from '@/ts/base';
-import { encodeKey, formatSize, generateUuid } from '../../base/common';
+import { encodeKey, formatDate, formatSize, generateUuid } from '../../base/common';
import { BucketOpreates, FileItemModel, FileItemShare } from '../../base/model';
import { FileInfo, IFile, IFileInfo } from './fileinfo';
import { IDirectory } from './directory';
@@ -18,7 +18,7 @@ export const fileToEntity = (
version: directory.version,
icon: JSON.stringify(data),
belong: directory.belong,
- belongId: directory.belongId,
+ belongId: data.belongId ?? directory.belongId,
shareId: directory.shareId,
typeName: data.contentType ?? '文件',
createTime: data.dateCreated,
@@ -26,8 +26,9 @@ export const fileToEntity = (
directoryId: directory.id,
createUser: directory.createUser,
updateUser: directory.updateUser,
+ isLinkFile: data.isLinkFile,
remark: `${data.name}(${formatSize(data.size)})`,
- };
+ } as schema.XStandard;
};
/** 系统文件接口 */
@@ -64,6 +65,9 @@ export class SysFileInfo extends FileInfo implements ISysFileInf
}
return [...gtags, '文件'];
}
+ get belongId(): string {
+ return this.filedata.belongId ?? this.target.belongId;
+ }
filedata: FileItemModel;
shareInfo(): model.FileItemShare {
return {
@@ -92,21 +96,37 @@ export class SysFileInfo extends FileInfo implements ISysFileInf
return false;
}
async delete(): Promise {
- const res = await this.directory.resource.bucketOpreate({
- key: encodeKey(this.filedata.key),
- operate: BucketOpreates.Delete,
- });
- if (res.success) {
- this.directory.notifyReloadFiles();
- this.directory.files = this.directory.files.filter((i) => i.key != this.key);
+ if (this.filedata.isLinkFile) {
+ return await this.linkFileDelete();
+ } else {
+ const res = await this.directory.resource.bucketOpreate({
+ key: encodeKey(this.filedata.key),
+ operate: BucketOpreates.Delete,
+ });
+ if (res.success) {
+ this.directory.notifyReloadFiles();
+ this.directory.files = this.directory.files.filter((i) => i.key != this.key);
+ }
+ return res.success;
}
- return res.success;
+ }
+ async linkFileDelete(): Promise {
+ await this.directory.resource.fileLinkColl.removeMany([
+ this.filedata as schema.XFileLink,
+ ]);
+ this.directory.files = this.directory.files.filter((i) => i.key != this.key);
+ await this.directory.resource.fileLinkColl.all(true);
+ this.directory.notifyReloadFiles();
+ this.directory.files = this.directory.files.filter((i) => i.key != this.key);
+ return true;
}
async hardDelete(): Promise {
return await this.delete();
}
async copy(destination: IDirectory): Promise {
- if (destination.id != this.directory.id) {
+ if (destination.spaceId !== this.directory.spaceId) {
+ return await this.linkFileCopy(destination);
+ } else if (destination.id != this.directory.id) {
const res = await this.directory.resource.bucketOpreate({
key: encodeKey(this.filedata.key),
destination: destination.id,
@@ -120,6 +140,25 @@ export class SysFileInfo extends FileInfo implements ISysFileInf
}
return false;
}
+ async linkFileCopy(destination: IDirectory): Promise {
+ const params = {
+ ...this.filedata,
+ belongId: this.belongId,
+ directoryId: destination.id,
+ name: this.filedata.name,
+ typeName: this.typeName,
+ dateCreated: formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss.S'),
+ isLinkFile: true,
+ id: 'snowId()',
+ } as unknown as schema.XFileLink;
+ const data = await destination.resource.fileLinkColl.replace(params);
+ if (data) {
+ await destination.resource.fileLinkColl.all(true);
+ destination.notifyReloadFiles();
+ destination.files.push(new SysFileInfo(params, destination));
+ }
+ return true;
+ }
async move(destination: IDirectory): Promise {
if (destination.id != this.directory.id) {
const res = await this.directory.resource.bucketOpreate({
diff --git a/src/ts/core/work/apply.ts b/src/ts/core/work/apply.ts
index c81b98cd4b44311ffd2f007f9702bfea8668ca61..92b628ea9fb0ba3d66d68e7dde6ee505467d8303 100644
--- a/src/ts/core/work/apply.ts
+++ b/src/ts/core/work/apply.ts
@@ -82,9 +82,9 @@ export class WorkApply implements IWorkApply {
}
}
}
- if (isRequired && valueIsNull(data[item.id])) {
- return false;
- }
+ }
+ if (isRequired && valueIsNull(data[item.id])) {
+ return false;
}
}
}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index e37a0a37097f551edbcddb0cec70ed6c35b6ec2b..adcbf1b763af05196a71fe49a537f1f746d6bdc9 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -333,6 +333,24 @@ function assignment(oldObj: { [key: string]: any }, newObj: { [key: string]: any
});
}
+/**
+ * 对象数组中 根据key,进行除重
+ * @param arr 数据源
+ * @param key 过滤凭证
+ */
+function uniqueArrayBy(arr: T[], key: keyof T): T[] {
+ const uniqueValues = new Set();
+ const result: T[] = [];
+
+ for (const item of arr) {
+ const findValue = uniqueValues.has(item[key]);
+ if (!findValue) {
+ uniqueValues.add(item[key]);
+ result.push(item);
+ }
+ }
+ return result;
+}
export {
assignment,
ellipsisText,
@@ -345,5 +363,6 @@ export {
isEmoji,
isSpecialChar,
sortObjByKeys,
+ uniqueArrayBy,
visitTree,
};
diff --git a/tsconfig.json b/tsconfig.json
index f3962dfc492c43842a97754ef5206ef763e97f3a..6f0a7d583807c0d643086219262076ad73fafca3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -7,7 +7,7 @@
"types": ["vite/client", "node"],
"allowJs": true,
"skipLibCheck": false,
- "esModuleInterop": false,
+ "esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
@@ -21,7 +21,7 @@
"paths": {
"@/*": ["src/*"],
"@cfg/*": ["config/*"]
- }
+ },
},
"include": [
"src/**/*.ts",
diff --git a/vite.config.ts b/vite.config.ts
index d98b81c0ecbb096273de7cf5c5361ae1148cf7a9..b2edc19679b7a4046e28c1d43daad334a60d0557 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -125,6 +125,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
},
],
},
+ commonjsOptions: { transformMixedEsModules: true }, // Change
},
define: {
// 设置应用信息