From 496edb3a387d4f03c71620535901bfc87173bc3a Mon Sep 17 00:00:00 2001 From: linlh Date: Thu, 4 Jan 2024 17:03:51 +0800 Subject: [PATCH 01/35] =?UTF-8?q?fix:=20=E4=BB=A3=E7=A0=81=E4=BB=93?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + .../Common/FlowDesign/processType.tsx | 34 ++ src/executor/index.tsx | 1 + .../codeRepository/common/index.module.css | 0 .../open/codeRepository/common/index.tsx | 2 + .../common/widgets/contentFrame/index.tsx | 219 ++++++++ .../widgets/contentFrame/inputBox/index.tsx | 164 ++++++ .../widgets/contentFrame/labelBox/index.tsx | 27 + .../common/widgets/submissionList/index.tsx | 78 +++ .../fileTab/BranchPage/index.less | 66 +++ .../fileTab/BranchPage/index.tsx | 238 ++++++++ .../fileTab/FileHome/index.less | 8 + .../codeRepository/fileTab/FileHome/index.tsx | 379 +++++++++++++ .../HistoryCommit/CodeComparison/index.less | 36 ++ .../HistoryCommit/CodeComparison/index.tsx | 272 +++++++++ .../fileTab/HistoryCommit/index.less | 27 + .../fileTab/HistoryCommit/index.tsx | 131 +++++ .../fileTab/VersionPage/index.less | 13 + .../fileTab/VersionPage/index.tsx | 27 + .../open/codeRepository/fileTab/index.tsx | 121 ++++ .../open/codeRepository/hook/index.ts | 30 + src/executor/open/codeRepository/index.less | 394 ++++++++++++++ src/executor/open/codeRepository/index.tsx | 120 ++++ .../pullRequestTab/codeCommit/index.tsx | 52 ++ .../pullRequestTab/codeFiles/index.tsx | 41 ++ .../codeRepository/pullRequestTab/index.less | 60 ++ .../codeRepository/pullRequestTab/index.tsx | 515 ++++++++++++++++++ .../repositorySettings/index.less | 63 +++ .../repositorySettings/index.tsx | 245 +++++++++ .../codeRepository/wordOrderTab/index.tsx | 295 ++++++++++ src/executor/open/index.tsx | 3 + src/executor/operate/entityForm/index.tsx | 7 + .../operate/entityForm/repositoryForm.tsx | 65 +++ .../entityForm/warehousePermissionForm.tsx | 119 ++++ src/ts/base/model.ts | 53 ++ src/ts/core/public/index.ts | 1 + src/ts/core/public/operates.ts | 9 + src/ts/core/thing/directory.ts | 10 +- src/ts/core/thing/resource.ts | 3 + src/ts/core/thing/standard/index.ts | 44 ++ src/ts/core/thing/standard/repository.ts | 369 +++++++++++++ vite.config.ts | 5 + 42 files changed, 4347 insertions(+), 1 deletion(-) create mode 100644 src/executor/open/codeRepository/common/index.module.css create mode 100644 src/executor/open/codeRepository/common/index.tsx create mode 100644 src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx create mode 100644 src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx create mode 100644 src/executor/open/codeRepository/common/widgets/contentFrame/labelBox/index.tsx create mode 100644 src/executor/open/codeRepository/common/widgets/submissionList/index.tsx create mode 100644 src/executor/open/codeRepository/fileTab/BranchPage/index.less create mode 100644 src/executor/open/codeRepository/fileTab/BranchPage/index.tsx create mode 100644 src/executor/open/codeRepository/fileTab/FileHome/index.less create mode 100644 src/executor/open/codeRepository/fileTab/FileHome/index.tsx create mode 100644 src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.less create mode 100644 src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.tsx create mode 100644 src/executor/open/codeRepository/fileTab/HistoryCommit/index.less create mode 100644 src/executor/open/codeRepository/fileTab/HistoryCommit/index.tsx create mode 100644 src/executor/open/codeRepository/fileTab/VersionPage/index.less create mode 100644 src/executor/open/codeRepository/fileTab/VersionPage/index.tsx create mode 100644 src/executor/open/codeRepository/fileTab/index.tsx create mode 100644 src/executor/open/codeRepository/hook/index.ts create mode 100644 src/executor/open/codeRepository/index.less create mode 100644 src/executor/open/codeRepository/index.tsx create mode 100644 src/executor/open/codeRepository/pullRequestTab/codeCommit/index.tsx create mode 100644 src/executor/open/codeRepository/pullRequestTab/codeFiles/index.tsx create mode 100644 src/executor/open/codeRepository/pullRequestTab/index.less create mode 100644 src/executor/open/codeRepository/pullRequestTab/index.tsx create mode 100644 src/executor/open/codeRepository/repositorySettings/index.less create mode 100644 src/executor/open/codeRepository/repositorySettings/index.tsx create mode 100644 src/executor/open/codeRepository/wordOrderTab/index.tsx create mode 100644 src/executor/operate/entityForm/repositoryForm.tsx create mode 100644 src/executor/operate/entityForm/warehousePermissionForm.tsx create mode 100644 src/ts/core/thing/standard/repository.ts diff --git a/package.json b/package.json index 33472943c..5dc16eac8 100644 --- a/package.json +++ b/package.json @@ -75,9 +75,11 @@ "pako": "^2.1.0", "qrcode.react": "^3.1.0", "react": "^18.2.0", + "react-diff-viewer": "3.1.1", "react-dom": "^18.2.0", "react-grid-layout": "^1.4.4", "react-icons": "^4.12.0", + "react-markdown": "8.0.7", "react-office-viewer": "^1.0.4", "react-router-config": "^5.1.1", "react-router-dom": "^5.2.0", diff --git a/src/components/Common/FlowDesign/processType.tsx b/src/components/Common/FlowDesign/processType.tsx index 03c597a4e..e9e962668 100644 --- a/src/components/Common/FlowDesign/processType.tsx +++ b/src/components/Common/FlowDesign/processType.tsx @@ -181,6 +181,40 @@ export const loadNilResouce = () => { }; }; +export const loadcode=()=>{ + const nodecode1=getNodeCode() + const nodecode2=getNodeCode() + const codeNode = { + forms: [], + code: nodecode1, + parentCode:nodecode1, + type: '起始', + name: '发起', + num: 1, + destType: '身份', + primaryForms: [], + detailForms: [], + executors: [], + formRules: [], + children: { + forms: [], + code: nodecode2, + parentCode:nodecode1, + type: '审批', + name: '审批对象', + num: 1, + // destType: '身份', + primaryForms: [], + // destId: '456805351245877248', + // destName: '管理员', + resource: '{"forms":[],"executors":[],"formRules":[]}', + }, + resource: + '{"forms":[],"executors":[],"formRules":[]}', + }; + return codeNode; +} + const loadBranch = (resource: any, parentCode: string, parentType: string) => { if (resource) { let code = getNodeCode(); diff --git a/src/executor/index.tsx b/src/executor/index.tsx index b37dc7c93..fed283856 100644 --- a/src/executor/index.tsx +++ b/src/executor/index.tsx @@ -19,6 +19,7 @@ const Executor: React.FC = () => { }; useEffect(() => { const id = command.subscribe((type, cmd, ...args: any[]) => { + console.log(type, cmd, args); if (type != 'executor') return; if (cmd === 'link') return history.push(args[0]); if (executeCmd(cmd, args[0]) === false) { diff --git a/src/executor/open/codeRepository/common/index.module.css b/src/executor/open/codeRepository/common/index.module.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/executor/open/codeRepository/common/index.tsx b/src/executor/open/codeRepository/common/index.tsx new file mode 100644 index 000000000..024b85143 --- /dev/null +++ b/src/executor/open/codeRepository/common/index.tsx @@ -0,0 +1,2 @@ +export { ContentFrame } from './widgets/contentFrame'; +export { SubmissionList } from './widgets/submissionList'; diff --git a/src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx b/src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx new file mode 100644 index 000000000..0691165af --- /dev/null +++ b/src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx @@ -0,0 +1,219 @@ +import { + CheckOutlined, + CloseOutlined, + InfoCircleOutlined, + NodeIndexOutlined, + UserOutlined, +} from '@ant-design/icons'; +import { Avatar, Button, Input, message } from 'antd'; +import React, { useState, useEffect } from 'react'; +import { LabelBox } from './labelBox'; +import { InputBox } from './inputBox'; +import { model } from '@/ts/base'; +import { getTimeAgo } from '../../../hook'; +import orgCtrl from '@/ts/controller'; +import { IRepository } from '@/ts/core/thing/standard/repository'; + +interface IProps { + onCreate: (title: string, content: string) => void; //按钮方法 + PRlistData?: model.pullRequestList; //单条pr列表数据 PRlistData存在的时候需要传递onOpenPR,onClosePR + current: IRepository; + titleShow?: boolean; //默认值为显示 + onOpenPR?: () => void; //按钮开启pr方法 + onClosePR?: () => void; //按钮关闭pr方法 +} +const ContentFrame: React.FC = ({ + onCreate, + PRlistData, + current, + titleShow = true, + onOpenPR, + onClosePR, +}) => { + return ( +
+
+ {PRlistData && ( + <> + {PRlistData.comment.map((value) => { + return ( +
+ } + src={ + value.PosterUser ? JSON.parse(value.PosterUser.icon).shareLink : '' + } + /> +
+
+

+ {value.PosterUser?.name} 评论于 {getTimeAgo(value.UpdateUnix)} +

+

{value.Content}

+
+
+
+ ); + })} + {(() => { + if (PRlistData.HasMerged == true) { + return ( +
+
+ +
+
+
+

该合并请求已经成功合并!

+
+
+
+ ); + } + if (PRlistData.IsClosed == true) { + return ( +
+
+ +
+
+
+

请重新开启合并请求来完成合并操作。

+
+
+
+ ); + } + if (PRlistData.Status == 2) { + return ( +
+
+ +
+
+
+

+ + 该合并请求可以进行自动合并操作。 +

+

提交说明:

+

+ +

+ {orgCtrl.user.metadata.belongId == + current.target.metadata.belongId && ( + + )} +
+
+
+ ); + } + if (PRlistData.Status == 0) { + return ( +
+
+ +
+
+
+

+ + 该合并请求存在冲突,无法进行自动合并操作。 +

+

+ + 请手动拉取代码变更以解决冲突。 +

+
+
+
+ ); + } + })()} + + )} + +
+ +
+ ); +}; +export { ContentFrame }; diff --git a/src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx b/src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx new file mode 100644 index 000000000..dca883c69 --- /dev/null +++ b/src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx @@ -0,0 +1,164 @@ +import { model } from '@/ts/base'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { UserOutlined } from '@ant-design/icons'; +import { Avatar, Button, Input, Tabs, message } from 'antd'; +import React, { useState } from 'react'; +import orgCtrl from '@/ts/controller'; + +interface IProps { + onCreate: (title: string, content: string) => void; //按钮方法 + titleShow: boolean; + PRlistData?: model.pullRequestList; //单条pr列表数据 PRlistData存在的时候需要传递onOpenPR,onClosePR + current: IRepository; + onOpenPR?: () => void; //按钮开启pr方法 + onClosePR?: () => void; //按钮关闭pr方法 +} +const InputBox: React.FC = ({ + onCreate, + titleShow, + PRlistData, + current, + onOpenPR, + onClosePR, +}) => { + //标题 + const [title, setTitle] = useState(''); + const [error, setError] = useState(''); + //内容 + const [content, setContent] = useState(''); + return ( +
+ } /> +
+ {titleShow && ( + <> + { + setTitle(e.currentTarget.value); + if (title !== '') { + setError(''); + } + }} + /> + {error &&
{error}
} + + )} + + + + { + setContent(e.currentTarget.value); + console.log(e.currentTarget.value); + }} + /> + {/* +

+ +

+

文件拖拽到此处或者单击上传

+
*/} +
+
+ {PRlistData ? ( + <> + {PRlistData.IsClosed ? ( + + ) : ( + + )} + + + ) : ( + <> + + + )} +
+
+ {/* + +
+
+ +

+ +

+

文件拖拽到此处或者单击上传

+
+
+
+ +
+
*/} +
+
+
+ ); +}; +export { InputBox }; diff --git a/src/executor/open/codeRepository/common/widgets/contentFrame/labelBox/index.tsx b/src/executor/open/codeRepository/common/widgets/contentFrame/labelBox/index.tsx new file mode 100644 index 000000000..440e1c0b6 --- /dev/null +++ b/src/executor/open/codeRepository/common/widgets/contentFrame/labelBox/index.tsx @@ -0,0 +1,27 @@ +import { SettingFilled } from '@ant-design/icons'; +import React from 'react'; + +interface IProps {} +const LabelBox: React.FC = () => { + return ( +
+
+

+ 标签 +

+

未选择标签

+
+

+ 里程碑 +

+

未选里程碑

+
+

+ 指派成员 +

+

未指派成员

+
+
+ ); +}; +export { LabelBox }; diff --git a/src/executor/open/codeRepository/common/widgets/submissionList/index.tsx b/src/executor/open/codeRepository/common/widgets/submissionList/index.tsx new file mode 100644 index 000000000..8b48365ec --- /dev/null +++ b/src/executor/open/codeRepository/common/widgets/submissionList/index.tsx @@ -0,0 +1,78 @@ +import React, { useEffect, useState } from 'react'; +import { getTimeAgo } from '../../../hook'; +import { Avatar, Input } from 'antd'; +import { UserOutlined } from '@ant-design/icons'; +interface IProps { + onSearch?: (value: string) => void; //是否有搜索框,搜索框的方法 + onID: (_item: any) => any; //双击id方法 + historyCommitList: any; //提交历史 + title: string; + BeforeCommitID?: string; + AfterCommitID?: string; +} +const { Search } = Input; +const SubmissionList: React.FC = ({ + onSearch, + onID, + historyCommitList, + title, + BeforeCommitID, + AfterCommitID, +}) => { + return ( + <> +
+
+
+

{title}

+ {BeforeCommitID ? ( + <> + + {BeforeCommitID?.substring(0, 10)} + + ... + + {AfterCommitID?.substring(0, 10)} + + + ) : ( + <> + )} +
+ {onSearch ? ( + + ) : ( + <> + )} +
+ {historyCommitList?.map((_item: any, index) => ( +
+
+ } /> + + {_item?.Committer.Name} + + + {_item.ID?.substring(0, 10)} + + {_item.Message} +
+ {getTimeAgo(_item?.Committer.When)} +
+ ))} +
+ + ); +}; +export { SubmissionList }; diff --git a/src/executor/open/codeRepository/fileTab/BranchPage/index.less b/src/executor/open/codeRepository/fileTab/BranchPage/index.less new file mode 100644 index 000000000..b84d482be --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/BranchPage/index.less @@ -0,0 +1,66 @@ +.branch_box { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.4rem 6rem 0.6rem 1rem; + box-sizing: border-box; + margin-bottom: 0.4rem; + border-bottom: 1px solid #ddd; + cursor: pointer; + + &:hover { + background-color: #ffffee; + } + + &:last-child { + border-bottom: 0; + } + + .flex_public { + display: flex; + align-items: center; + + .master_tag { + display: block; + color: #3e5ed8; + padding: 0.1rem 0.6rem; + background-color: #ddd; + border-radius: 0.2rem; + margin-right: 0.6rem; + } + .commit_text { + color: #606266; + } + } +} + +.btn_list { + border-radius: 0.2rem; + overflow: hidden; + user-select: none; + min-width: 130px; + font-size: 14px; + // font-weight: 600; + margin-bottom: 10px; + .active{ + background: #f2f2f2; + } + + span { + color: black; + background-color: rgb(255, 255, 255); + padding: 0.4rem 0.6rem; + white-space: nowrap; + line-height: 3vh; + height: 4vh; + cursor: pointer; + border: 1px solid #ccc; + + // &:active { + // background: #f2f2f2; + // } + &:hover { + background: rgba(247, 247, 247, 0.8); + } + } +} \ No newline at end of file diff --git a/src/executor/open/codeRepository/fileTab/BranchPage/index.tsx b/src/executor/open/codeRepository/fileTab/BranchPage/index.tsx new file mode 100644 index 000000000..3d233a757 --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/BranchPage/index.tsx @@ -0,0 +1,238 @@ +import React, { useState, useEffect } from 'react'; +import './index.less'; +import { Button } from 'antd'; +import { ApiOutlined } from '@ant-design/icons'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { getTimeAgo } from '../../hook/index'; +import { InsuranceOutlined } from '@ant-design/icons'; +interface IProps { + current: IRepository; + branchesdata: any; + setbranchesdata: Function; +} + +const BranchPage: React.FC = ({ current, branchesdata, setbranchesdata }) => { + const [branchetype, setbranchetype] = useState(0); + if (!branchesdata) { + return <>; + } + return ( + <> +
+ { + const res = await current.Codebranches(); + setbranchetype(0); + setbranchesdata(res.data); + }} + className={branchetype == 0 ? 'active' : ''}> + 概况 + + { + const res = await current.Codebranches('/all'); + console.log(res); + + setbranchetype(1); + setbranchesdata(res.data); + }} + className={branchetype == 1 ? 'active' : ''}> + 所有分支 + +
+ {(() => { + switch (branchetype) { + case 0: + return ( + <> +
+

+ 默认分支 +

+
+
+ {branchesdata.DefaultBranch.IsProtected ? ( + + ) : ( + <> + )} + + {branchesdata.DefaultBranch.Name} + + {`由${ + branchesdata.DefaultBranch.Commit.Committer.Name + }更新于 ${getTimeAgo( + branchesdata.DefaultBranch.Commit.Committer.When, + )}`} +
+ +
+
+ {branchesdata.ActiveBranches?.length ? ( +
+

+ 活跃分支 +

+ {(() => { + return branchesdata.ActiveBranches?.map( + (active: any, i: number) => { + return ( +
+
+ {active.IsProtected ? ( + + ) : ( + <> + )} + {active.Name} + {`由${ + active.Commit.Committer.Name + }更新于 ${getTimeAgo( + active.Commit.Committer.When, + )}`} +
+ +
+ ); + }, + ); + })()} +
+ ) : ( + <> + )} + + {branchesdata.StaleBranches?.length ? ( +
+

+ 陈旧分支 +

+ {(() => { + return branchesdata.StaleBranches?.map((stale: any, i: number) => { + return ( +
+
+ {stale.IsProtected ? ( + + ) : ( + <> + )} + {stale.Name} + {`由${ + stale.Commit.Committer.Name + }更新于 ${getTimeAgo(stale.Commit.Committer.When)}`} +
+ +
+ ); + }); + })()} +
+ ) : ( + <> + )} + + ); + case 1: + return ( + <> +
+

+ 所有分支 +

+
+
+ {branchesdata.DefaultBranch.IsProtected ? ( + + ) : ( + <> + )} + + {branchesdata.DefaultBranch.Name} + + {`由${ + branchesdata.DefaultBranch.Commit.Committer.Name + }更新于 ${getTimeAgo( + branchesdata.DefaultBranch.Commit.Committer.When, + )}`} +
+ +
+
+ + {branchesdata.OtherBranches?.length ? ( +
+

+ 活跃分支 +

+ {(() => { + return branchesdata.OtherBranches?.map((active: any, i: number) => { + return ( +
+
+ {active.IsProtected ? ( + + ) : ( + <> + )} + {active.Name} + {`由${ + active.Commit.Committer.Name + }更新于 ${getTimeAgo(active.Commit.Committer.When)}`} +
+ +
+ ); + }); + })()} +
+ ) : ( + <> + )} + + ); + + default: + return <>; + } + })()} + + ); +}; + +export default BranchPage; diff --git a/src/executor/open/codeRepository/fileTab/FileHome/index.less b/src/executor/open/codeRepository/fileTab/FileHome/index.less new file mode 100644 index 000000000..b323d1bee --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/FileHome/index.less @@ -0,0 +1,8 @@ +.markdown-body { + img { + width: 100% !important; + } +} +.address { + width: 400px; +} diff --git a/src/executor/open/codeRepository/fileTab/FileHome/index.tsx b/src/executor/open/codeRepository/fileTab/FileHome/index.tsx new file mode 100644 index 000000000..f5592f78e --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/FileHome/index.tsx @@ -0,0 +1,379 @@ +import React, { useEffect, useRef, useState } from 'react'; + +import { Col, Divider, Input, Row, Select, Space, message, Avatar } from 'antd'; +import './index.less'; +import CodeMirror from '@uiw/react-codemirror'; +import { vscodeDark } from '@uiw/codemirror-theme-vscode'; +import { langs } from '@uiw/codemirror-extensions-langs'; +import ReactMarkdown from 'react-markdown'; + +import { + CopyOutlined, + DownloadOutlined, + FileDoneOutlined, + FileOutlined, + FolderOpenFilled, + PullRequestOutlined, + UserOutlined, +} from '@ant-design/icons'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { getTimeAgo } from '../../hook'; +interface IProps { + current: IRepository; + clickTrees: string; //当前分支 + setClickTrees: Function; //变更当前分支 +} + +const FileHome: React.FC = ({ current, clickTrees, setClickTrees }) => { + //分支列表选项 + const [trees, setTrees] = useState([]); + //select 选项 + const [branchStatus, setBranchStatus] = useState(0); + //复制git 地址 + const copyRef = useRef(null); + //仓库内容 + const [repoContent, setRepoContent]: any = useState({}); + //获取目录/文件内容 + const [fileHistory, setFileHistory] = useState>([]); + //当前文件标题 + // const [fileTitle, setFileTitle] = useState(''); + //当前文件类型 + const [filetype, setFiletype] = useState('tree'); + //文档内容 + const [mdContent, setMdContent] = React.useState(''); + const mdFile = async (filePath: RequestInfo | URL) => { + fetch(filePath) + .then((res) => res.text()) + .then((text) => setMdContent(text)); + }; + //代码编辑器颜色 + const [extensions] = useState(langs.markdown); + useEffect(() => { + getFiles(); + }, []); + // //刷新数据方法 + // interface Irefscontent { + // datauri?: string; + // ClickTree?: string; + // } + // const refscontent = async (data: Irefscontent) => { + // const results = await current.RepoContent(data?.datauri || ''); + // data?.ClickTree && setClickTrees(data?.ClickTree); //当前分支 + // setRepoContent(results.data); + // }; + const getFiles = async (datauri: string = '') => { + const results = await current.RepoContent(`/src/${clickTrees}`); + if (results.code === 200) { + const moveElementToFirst = (elementToMove: string = 'master') => { + const index = results.data.Branchs.indexOf(elementToMove); + if (index !== -1) { + const newArray: any = [...results.data.Branchs]; + newArray.splice(index, 1); + newArray.unshift(elementToMove); + setTrees(newArray); + } + }; + moveElementToFirst(); + // setClickTrees('master'); + setRepoContent(results.data); + } else { + message.warning(results.message); + } + }; + const fileDesc = async (item: any) => { + let fileNames = item.Entry.Name; //当前文件名称 + let filepath = [...fileHistory, fileNames]; //当前文件路径数组 + let url = ''; + for (let i = 0; i < filepath.length; i++) { + url += `/${filepath[i]}`; + } + const results = await current.RepoContent(`/src/${clickTrees}` + url); + if (results.code === 200) { + setRepoContent(results.data); + } else { + message.warning(results.message); + } + if (item.Entry.Typ === 'tree') { + setFiletype('tree'); + } + if (item.Entry.Typ === 'blob') { + const url = results.data?.Url; + if (url) { + const fileTyp = url.substring(url.lastIndexOf('.')); + setFiletype(fileTyp); + if (fileTyp != '.rar') { + mdFile(results.data.Url.replace('http://gittest.jx868.com', '/warehouse')); + } + } + } + setFileHistory(filepath); + }; + + return ( +
+ + + + + + + + +
+

{ + setBranchStatus(0); + }} + className={branchStatus == 0 ? 'active' : ''}> + 分支列表 +

+

{ + setBranchStatus(1); + }} + className={branchStatus == 1 ? 'active' : ''}> + 标签列表 +

+
+
+ {(() => { + switch (branchStatus) { + case 0: + return menu; + default: + return <>; + } + })()} + + + )} + onChange={async (value) => { + const results = await current.RepoContent(`/src/${value}`); + setRepoContent(results.data); + setClickTrees(value); + setFiletype('tree'); + setFileHistory([]); + }} + options={trees.map((item) => ({ label: item, value: item }))} + /> + + { + const results = await current.RepoContent(`/src/${clickTrees}`); + setRepoContent(results.data); + setFiletype('tree'); + setFileHistory([]); + }}> + {current.name + ` /`} + + {fileHistory.map((items, index) => { + return ( + { + const results = await current.RepoContent( + `/src/${clickTrees}/${fileHistory?.slice(0, index + 1).join('/')}`, + ); + setRepoContent(results.data); + setFiletype('tree'); + setFileHistory(fileHistory?.slice(0, index + 1)); + }}> + {items + ` /`} + + ); + })} + + + + {/*
+ 新的文件 + 上传文件 +
*/} +
+ { + copyRef.current.innerText = current.HTTPS; + }}> + HTTP + + { + copyRef.current.innerText = current.SSH; + }}> + SSH + + + {current.HTTPS} + + { + navigator.clipboard + .writeText(copyRef.current.outerText) + .then(() => { + message.success('复制成功'); + }) + .catch((_error) => { + message.error('复制失败'); + }); + }}> + + + + + +
+ +
+ {/*表头用户提交信息*/} + {(() => { + switch (filetype) { + case 'tree': + return ( +
+
+
+ } + /> + + {repoContent?.LatestCommit?.Committer + ? repoContent?.LatestCommit?.Committer.Name + : 'username'} + + + {repoContent?.LatestCommit?.ID?.substring(0, 10)} + + + {repoContent?.LatestCommit?.Message} + +
+ + {getTimeAgo( + repoContent?.LatestCommit?.Committer + ? repoContent?.LatestCommit?.Committer.When + : '', + )} + +
+ {repoContent?.EntryCommitInfo?.map((_item: any) => ( +
{ + fileDesc(_item); + }} + key={_item.Index} + className="flex_align_center file_list_table_item"> +
+ {_item.Entry.Typ == 'tree' ? ( + + ) : ( + + )} + + {_item.Entry.Name} + +
+
+ { + console.log(123); + }}> + {_item.Commit.ID?.substring(0, 10)} + + + {_item.Commit.Message} + +
+ + {getTimeAgo(_item.Commit.Committer.When)} + +
+ ))} +
+ ); + case '.png': + return ( +
+ +
+ ); + case '.md': + return ( + <> +
+

+ + {repoContent?.FileName} +

+
+ {mdContent} +
+
+ + ); + case '.rar': + return ( + <> +
压缩文件过大无法查看
+ + ); + default: + return ( +
+

+ + {repoContent?.FileName} +

+
+ +
+
+ ); + } + })()} +
+ ); +}; + +export default FileHome; diff --git a/src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.less b/src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.less new file mode 100644 index 000000000..fb0cadad3 --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.less @@ -0,0 +1,36 @@ +.commit_ins { + margin: 10px; +} +.Comparison { + .commit_info { + justify-content: space-between; + padding: 0.4rem 0.6rem; + border-bottom: 1px solid #ddd; + cursor: pointer; + + &:hover { + background-color: #ffffee; + } + } + .commit_ins_botton { + margin: 20px 0; + font-size: 16px; + display: flex; + justify-content: space-between; + } + .check { + font-weight: 800; + } + .flst { + padding: 0.4rem 0.7rem; + border: 1px solid #b5b5b5; + border-radius: 10%; + color: #676767; + font-size: 14px; + cursor: pointer; + // background-color: red; + } + .filecontent{ + margin: 2rem; + } +} diff --git a/src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.tsx b/src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.tsx new file mode 100644 index 000000000..a5e0bdb20 --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/HistoryCommit/CodeComparison/index.tsx @@ -0,0 +1,272 @@ +import React, { useState, useEffect } from 'react'; +import './index.less'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { getTimeAgo } from '../../../hook'; +import { UserOutlined, RetweetOutlined, FileDoneOutlined } from '@ant-design/icons'; +import { Button, Avatar } from 'antd'; +import DiffViewer, { DiffMethod } from 'react-diff-viewer'; +// import diffData from './test'; + +interface IProps { + current: IRepository; + node: any; + title?: any; + PRdata?: any; +} + +const CodeComparison: React.FC = ({ current, node, title, PRdata }) => { + const [splitView, setSplitView] = useState(false); + const [diffData, setDiffData] = useState(null); + // console.log(diffData); + // 从提供的数据中提取左侧和右侧的内容 + // 从提供的数据中提取左侧和右侧的内容,并去除前面的 + 和 - + //展开项是否展开 + const initiallyExpandedItems = [0, 1, 2, 3, 4, 5, 6]; // 默认展开前四项 + const [expandedItems, setExpandedItems] = useState>(initiallyExpandedItems); + //展开项展示内容 + // const [expandedcontent, setExpandedcontent] = useState(null); + + useEffect(() => { + (async () => { + if (PRdata) { + setDiffData(PRdata); + } else { + const data: any = await current.Codecomparison(`/${node.ID || node}`); + setDiffData(data); + console.log(data?.data?.Diff?.Files); + } + })(); + }, [node]); + if (diffData == null) { + return ( + <> +
+ + ); + } + return ( + <> +
+ {title ? ( + <> + ) : ( +
+

+ {` ${diffData.data.Commit.Message}`} +

+
+
+ } /> + {` ${diffData.data.Commit.Committer.Name}`} + {`<${diffData.data.Commit.Committer.Email}>`} + + {getTimeAgo(diffData.data.Commit.Committer.When)} + +
+
+ 父节点 + {`${diffData.data.Parents[0]?.substring( + 0, + 10, + )}`} + 当前提交 + {` ${diffData.data.Commit.ID.substring( + 0, + 10, + )}`} +
+
+
+ )} + +
+ + + 共有 + {` ${diffData?.data?.Diff?.Files.length} 个文件被更改`} + ,包括 + {` ${diffData.data.Diff.Changes.TotalAdditions} 次插入`} + 和 + {` ${diffData.data.Diff.Changes.TotalDeletions} 次删除`} + +
+
{ + setSplitView(!splitView); + }}> + {splitView ? '合并视图' : '分列视图'} +
+
{ + setExpandedItems([]); + }}> + {'收起全部'} +
+
+
+ {diffData?.data?.Diff?.Files?.map((File: any, i: number) => { + return ( +
+
+
+

+ + {(() => { + switch (File.Type) { + case 1: + return `${File.Name} 新建`; + case 2: + return `${File.Name} 更新`; + case 3: + return `${File.Name} 删除`; + default: + return `${File.Name}`; + } + })()} +

+ {(() => { + return ( +
+
{ + // setExpandedcontent(File.Sections.length); + if (expandedItems.includes(i)) { + setExpandedItems( + expandedItems.filter((item) => item !== i), + ); + } else { + setExpandedItems([...expandedItems, i]); + } + }}> + {expandedItems.includes(i) ? '收起查看' : '展开查看'} + {/* */} +
+ {expandedItems.includes(i) && + (() => { + if (!File.Sections.length) { + return ( +
{ + // console.log(val); + console.log(File); + console.log(current); + console.log(diffData.data.SourcePath); + }}> + {/\.(jpg|jpeg|png|gif)$/i.test(File.Name) ? ( + + ) : ( +
文件暂时无法查看
+ )} +
+ ); + } + return File.Sections?.map((val, ind) => { + const leftContent = val.Lines?.filter( + (line, index) => line.Type !== 2 && index != 0, + ) + .map((line) => + line.Content.replace(/^\+/, '').replace(/^-/, ''), + ) + .join('\n'); + + const rightContent = val.Lines?.filter( + (line, index) => line.Type !== 3 && index != 0, + ) + .map((line) => + line.Content.replace(/^\+/, '').replace(/^-/, ''), + ) + .join('\n'); + return ( +
+ { + //自定义渲染内容 + return ( +
+ {source} +
+ ); + }} + onLineNumberClick={( + //行号处理事件 + lineId: string, + event: React.MouseEvent< + HTMLTableCellElement, + MouseEvent + >, + ) => { + console.log(lineId, event); + console.log(File.Sections); + }} + // highlightLines={['L-31', 'R-31']} //黄线 写法:'L-1','R-1' + showDiffOnly={true} //仅显示差异线 并折叠 未更改的线 + extraLinesSurroundingDiff={3} //差异周围额外未更改的行数。与 showDiffOnly一起使用 + // codeFoldMessageRenderer={( //折叠信息渲染 + // totalFoldedLines: number, //总计折叠 + // leftStartLineNumber: number, //左侧 + // rightStartLineNumber: number, //右侧 + // ) => { + // return
1111
; + // }} + // styles={newStyles} //自定义修改内部样式 + leftTitle={ +
+
+
{val.Lines[0].Content}
+
+
+ } //左侧顶部标题 + // rightTitle={'11111'} //右侧顶部标题 + linesOffset={ + val.Lines[1].LeftLine + ? val.Lines[1].LeftLine - 1 + : 0 + } //开始行号 + /> +
+ ); + }); + })()} +
+ ); + })()} +
+
+
+ ); + })} +
+ + ); +}; + +export default CodeComparison; diff --git a/src/executor/open/codeRepository/fileTab/HistoryCommit/index.less b/src/executor/open/codeRepository/fileTab/HistoryCommit/index.less new file mode 100644 index 000000000..89555a51c --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/HistoryCommit/index.less @@ -0,0 +1,27 @@ +.history_top { + margin-bottom: 30px; +} +.history_commit { + border: 1px solid #ddd; + border-radius: 0.2rem; + .search_header { + padding: 0.2rem 0.6rem; + background: #ddd; + justify-content: space-between; + .commit_history_text { + color: #333; + font-weight: bold; + font-size: 16px; + } + } + .commit_info { + justify-content: space-between; + padding: 0.4rem 0.6rem; + border-bottom: 1px solid #ddd; + cursor: pointer; + + &:hover { + background-color: #ffffee; + } + } +} diff --git a/src/executor/open/codeRepository/fileTab/HistoryCommit/index.tsx b/src/executor/open/codeRepository/fileTab/HistoryCommit/index.tsx new file mode 100644 index 000000000..23a4d9e88 --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/HistoryCommit/index.tsx @@ -0,0 +1,131 @@ +import { Divider, Input, Select, Space, message, Avatar } from 'antd'; +import React, { useState, useEffect } from 'react'; +import './index.less'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { SubmissionList } from '../../common/index'; + +interface IProps { + current: IRepository; + setpage: (value: number) => void; + historyCommitList: any; //提交历史 + setHistoryCommitList: Function; //变更提交历史 + clickTrees: string; //当前分支 + setClickTrees: Function; //变更当前分支 + setnode: Function; +} + +const HistoryCommit: React.FC = ({ + current, + setpage, + clickTrees, + setClickTrees, + historyCommitList, + setHistoryCommitList, + setnode, +}) => { + //分支列表选项 + const [trees, setTrees] = useState([]); + + //当前分支 + // const [clickTrees, setClickTrees] = useState('master'); + //select 选项 + const [branchStatus, setBranchStatus] = useState(0); + // const [historyCommitList, setHistoryCommitList] = useState([]); + useEffect(() => { + getFiles(); + }, []); + const getFiles = async (datauri: string = '') => { + console.log(clickTrees); + const results = await current.RepoContent(`/src/${clickTrees}`); + if (results.code === 200) { + const moveElementToFirst = (elementToMove: string = 'master') => { + const index = results.data.Branchs.indexOf(elementToMove); + if (index !== -1) { + const newArray: any = [...results.data.Branchs]; + newArray.splice(index, 1); + newArray.unshift(elementToMove); + setTrees(newArray); + } + }; + moveElementToFirst(); + const commitList = await current.HistoryCommitList(`/${clickTrees}`); + setHistoryCommitList(commitList.data); + } else { + message.warning(results.message); + } + }; + const onID = (_item: any) => { + return () => { + console.log(_item); + setnode(_item); + setpage(4); + }; + }; + return ( + <> +
+
+ + + +
+

{ + setBranchStatus(0); + }} + className={branchStatus == 0 ? 'active' : ''}> + 分支列表 +

+

{ + setBranchStatus(1); + }} + className={branchStatus == 1 ? 'active' : ''}> + 标签列表 +

+
+
+ {(() => { + switch (branchStatus) { + case 0: + return menu; + default: + return <>; + } + })()} + + + )} + onChange={async (value) => { + const commitList = await current.HistoryCommitList(`/${value}`); + setHistoryCommitList(commitList.data); + setClickTrees(value); + }} + options={trees.map((item) => ({ label: item, value: item }))} + /> +
+ { + const commitList = await current.HistoryCommitList( + `/${clickTrees}${value ? '/search?q=' + value : ''}`, + ); + console.log(commitList); + setHistoryCommitList(commitList.data); + }} + onID={onID} + historyCommitList={historyCommitList} + title={'提交历史'} + /> +
+ + ); +}; + +export default HistoryCommit; diff --git a/src/executor/open/codeRepository/fileTab/VersionPage/index.less b/src/executor/open/codeRepository/fileTab/VersionPage/index.less new file mode 100644 index 000000000..a0f5bd423 --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/VersionPage/index.less @@ -0,0 +1,13 @@ +.version_page { + display: flex; + justify-content: space-between; + align-items: center; + padding-bottom: 1rem; + border-bottom: 1px solid #ddd; +} + +.bottom_btn { + display: flex; + justify-content: center; + align-items: center; +} diff --git a/src/executor/open/codeRepository/fileTab/VersionPage/index.tsx b/src/executor/open/codeRepository/fileTab/VersionPage/index.tsx new file mode 100644 index 000000000..45dd668b7 --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/VersionPage/index.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import './index.less'; +import { Button } from 'antd'; + +function VersionPage() { + return ( + <> +
+

版本发布

+ +
+
+
+ + +
+ + ); +} + +export default VersionPage; diff --git a/src/executor/open/codeRepository/fileTab/index.tsx b/src/executor/open/codeRepository/fileTab/index.tsx new file mode 100644 index 000000000..995e65dfd --- /dev/null +++ b/src/executor/open/codeRepository/fileTab/index.tsx @@ -0,0 +1,121 @@ +import React, { useEffect, useState } from 'react'; +import { Col, Row } from 'antd'; +import { BranchesOutlined, ClockCircleOutlined, TagOutlined } from '@ant-design/icons'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import HistoryCommit from './HistoryCommit'; +import BranchPage from './BranchPage'; +import VersionPage from './VersionPage'; +import FileHome from './FileHome'; +import CodeComparison from './HistoryCommit/CodeComparison'; + +interface IProps { + current: IRepository; + States: number; + setStates: Function; + historyCommitList: any; //提交历史 + setHistoryCommitList: Function; //变更提交历史 + clickTrees: string; //当前分支 + setClickTrees: Function; //变更当前分支 +} + +const FileTab: React.FC = ({ + current, + States, + setStates, + historyCommitList, + setHistoryCommitList, + clickTrees, + setClickTrees, +}) => { + const [node, setnode] = useState(null); + //初始化概况分支列表 + const [branchesdata, setbranchesdata] = useState(null); + //初始化所有分支列表 + const [allbranchesdata, setallbranchesdata] = useState(null); + useEffect(() => { + (async () => { + const res = await current.Codebranches(); + const res1 = await current.Codebranches('/all'); + setallbranchesdata(res1.data); + setbranchesdata(res.data); + })(); + }, []); + return ( +
+

{current.remark}

+ + {/*提交史,分支,版本发布*/} + + +

{ + setStates(1); + }}> + + {`${historyCommitList?.length ? historyCommitList?.length : 0} 次提交史`} +

+ + +

{ + setStates(2); + }}> + + {allbranchesdata?.OtherBranches?.length + 1 || 0}个代码分支 +

+ + +

setStates(3)}> + + 0版本发布 +

+ +
+ {(() => { + switch (States) { + case 0: + return ( + { + setClickTrees(value); + }} + /> + ); + case 1: + return ( + { + setStates(value); + }} + clickTrees={clickTrees} + setClickTrees={setClickTrees} + historyCommitList={historyCommitList} + setHistoryCommitList={setHistoryCommitList} + setnode={setnode} + /> + ); + case 2: + return ( + + ); + case 3: + return ; + case 4: + return ; + default: + return <>; + } + })()} +
+ ); +}; +export default FileTab; diff --git a/src/executor/open/codeRepository/hook/index.ts b/src/executor/open/codeRepository/hook/index.ts new file mode 100644 index 000000000..64df659d0 --- /dev/null +++ b/src/executor/open/codeRepository/hook/index.ts @@ -0,0 +1,30 @@ +/** + * 代码仓库时间处理函数 + */ +function getTimeAgo(timestamp: any) { + const currentDate = new Date(); + const pastDate = new Date(timestamp); + + const millisecondsDiff = currentDate.getTime() - pastDate.getTime(); + const secondsDiff = Math.floor(millisecondsDiff / 1000); + const minutesDiff = Math.floor(secondsDiff / 60); + const hoursDiff = Math.floor(minutesDiff / 60); + const daysDiff = Math.floor(hoursDiff / 24); + const monthsDiff = Math.floor(daysDiff / 30); + const yearsDiff = Math.floor(monthsDiff / 12); + + if (yearsDiff > 0) { + return yearsDiff === 1 ? '1年前' : `${yearsDiff}年前`; + } else if (monthsDiff > 0) { + return monthsDiff === 1 ? '1个月前' : `${monthsDiff}个月前`; + } else if (daysDiff > 0) { + return daysDiff === 1 ? '1天前' : `${daysDiff}天前`; + } else if (hoursDiff > 0) { + return hoursDiff === 1 ? '1小时前' : `${hoursDiff}小时前`; + } else if (minutesDiff > 0) { + return minutesDiff === 1 ? '1分钟前' : `${minutesDiff}分钟前`; + } else { + return '刚刚'; + } +} +export { getTimeAgo }; diff --git a/src/executor/open/codeRepository/index.less b/src/executor/open/codeRepository/index.less new file mode 100644 index 000000000..d976063c4 --- /dev/null +++ b/src/executor/open/codeRepository/index.less @@ -0,0 +1,394 @@ +.flex_align_center { + display: flex !important; + align-items: center !important; +} +.margin_lefts { + margin-left: 0.8rem; + span { + cursor: pointer; + } +} +.text_warp { + white-space: nowrap; +} +.address { + width: 400px; +} +.markdown-body { + img { + width: 100% !important; + } +} +.content { + padding: 0 14%; + .file_name{ + margin: 1vh 0; + } + .FileTab{ + .history_contianer { + border-radius: 0.2rem; + overflow: hidden; + border: 1px solid #ddd; + height: 48px; + margin-bottom: 2vh; + .public_text_center { + text-align: center; + cursor: pointer; + user-select: none; + line-height: 48px; + .topicon{ + margin-right: 0.4rem; + } + } + } + + } + +} +.filehome{ + .contrast { + display: block; + padding: 0.26rem 1rem; + background-color: #21ba45; + color: #ffffff; + text-align: center; + border-radius: 0.4rem; + max-width: 4rem; + cursor: pointer; + user-select: none; + border: 1px solid #21ba45; + box-sizing: border-box; + transition: all 0.3s; + margin-right: 0.8rem; + + &:hover { + border: 1px solid #b7eb8f; + } + + &:active { + background: rgba(33, 186, 69, 0.4); + } + } + .btn_list { + border-radius: 0.2rem; + overflow: hidden; + user-select: none; + min-width: 130px; + font-size: 12px; + + span { + color: #fff; + background-color: #2185d0; + padding: 0.4rem 0.6rem; + white-space: nowrap; + cursor: pointer; + + &:active { + background: rgba(33, 133, 208, 0.8); + } + } + } + .file_url { + border-radius: 0.2rem; + overflow: hidden; + border: 1px solid #ddd; + user-select: none; + font-size: 12px; + min-width: 200px; + + span { + padding: 0.3rem 0.6rem; + white-space: nowrap; + cursor: pointer; + + &:first-child { + &:active { + background-color: #ddd; + } + } + + &:nth-child(2) { + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + + &:active { + background-color: #ddd; + } + } + + &:nth-child(4) { + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + padding: 0.3rem 0.2rem; + + &:active { + background-color: #ddd; + } + } + + &:nth-child(5) { + padding: 0.3rem 0.2rem; + + &:active { + background-color: #ddd; + } + } + + &:nth-child(3) { + user-select: all; + max-width: 200px; + white-space: nowrap; /* 禁止换行 */ + overflow: hidden; /* 隐藏超出部分的文本 */ + text-overflow: ellipsis; /* 使用省略号来表示被隐藏的文本 */ + } + } + } +} +.select_tabs { + width: 210px; + + p { + cursor: pointer; + width: 50%; + margin-bottom: 0.4rem !important; + } + + .active { + font-weight: bold; + color: #1e70bf; + } +} +.file_list_table { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + //min-height: 40vh; + border: 1px solid #ddd; + border-radius: 0.2rem; + //background-color: #fff; + + + .file_list_header { + border-bottom: 1px solid #ddd; + width: 100%; + height: 50px; + padding: 0 0.8rem; + user-select: none; + //background-color: #fff; + justify-content: space-between; + } + + .file_list_table_item { + border-bottom: 1px solid #ddd; + height: 50px; + padding: 0 0.8rem 0 1.2rem; + user-select: none; + justify-content: space-between; + //background-color: #fff; + cursor: pointer; + + &:last-child { + border-bottom: 0; + } + + &:hover { + background-color: #ffffee; + } + .file_cloum { + min-width: 20%; + //background-color: #f00; + } + } +} +.upload_file_color { + color: #606266; +} +.commit_desc { + user-select: none; + max-width: 300px; + white-space: nowrap; /* 禁止换行 */ + overflow: hidden; /* 隐藏超出部分的文本 */ + text-overflow: ellipsis; /* 使用省略号来表示被隐藏的文本 */ + color: #606266; +} +.md_contianer { + border: 1px solid #ddd; + box-sizing: border-box; + border-radius: 0.2rem; +} +.git_verson { + padding: 0.1rem 0.6rem; + border-radius: 0.2rem; + background: #e8e8e8; + color: #606266; +} +.git_verson2 { + padding: 0.3rem 0.6rem; + border-radius: 0.2rem; + background: #2185d0; + color: #e8e8e8; +} +.git_verson3 { + padding: 0.3rem 0.6rem; + border-radius: 0.2rem; + background: #21ba45; + color: #e8e8e8; + font-weight: normal; + margin: 0 1rem; +} +.file_name_color { + color: #3e5ed8; +} + +.word_order { + display: flex; + justify-content: space-between; + border-bottom: 1px solid #ddd; + padding-bottom: 1rem; + margin-bottom: 1rem; + + .word_order_controller_btn_two { + background: #21ba45 !important; + border: 1px solid #21ba45 !important; + color: #fffff7 !important; + &:hover { + background-color: #21ba45; + border: #21ba45; + color: #fffff7; + } + } + + .word_order_controller_btn { + border: 1px solid #ddd; + padding: 0.6rem 0.8rem; + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; + cursor: pointer; + user-select: none; + + &:active { + background-color: #ddd; + } + + &:last-child { + border-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; + } + } +} + +.tags_list_content { + display: flex; + flex-direction: column; + justify-content: center; + .tag{ + margin-bottom: 1vh; + } + + .tags_list_items { + padding: 0.6rem 0; + border-bottom: 1px dashed #ddd; + .tags_list_items_tag { + cursor: pointer; + user-select: none; + padding: 0.3rem 0.6rem; + } + } + .tags_list_btn_list { + display: flex; + align-items: center; + user-select: none; + + .tags_list_btn_list_item { + color: #606266; + cursor: pointer; + + &:first-child { + margin-right: 2rem; + } + + &:nth-child(2) { + margin-right: 1rem; + } + + &:hover { + color: #333333; + } + } + } +} + +.content_edit_style { + flex: 1; + border: 1px solid #ddd; + min-width: 70%; + margin-left: 1rem; + margin-bottom: 0.4rem; + border-radius: 0.2rem; + padding: 0.6rem 0.6rem; + box-sizing: border-box; + + .content_edit_title { + line-height: 40px; + background: #ddd; + padding-left: 0.6rem; + color: #606266; + } + .common_content { + padding: 0rem 0.8rem; + color: #606266; + } +} +.upload_style { + min-height: 200px; + display: flex; + flex-direction: column; + justify-content: center; +} +.tags_content_right { + min-width: 20% !important; + border: 1px solid #ddd; + margin-left: 1rem; + border-radius: 0.2rem; + padding: 0.6rem 1rem; + box-sizing: border-box; + + .tags_content_right_title { + color: #606266; + line-height: 30px; + } + .tags_content_right_desc { + border-bottom: 1px solid #ddd; + line-height: 40px; + } +} + +.merge { + border: 1px solid #ddd; + border-radius: 0.2rem; + padding: 0.6rem 0.6rem; + display: flex; + align-items: center; +} + +.merge_file { + // border: 1px solid #ddd; + // margin-top: 10px; + padding: 0.6rem 0.6rem; + border-radius: 0.2rem; +} +.merge_font { + border: 1px solid #ddd; + font-size: 16px; + margin-top: 10px; + padding: 0.6rem 0.6rem; + border-radius: 0.2rem; +} +.ccodepull{ + padding: 0.3rem 0.8rem; + background: #ddd; +} \ No newline at end of file diff --git a/src/executor/open/codeRepository/index.tsx b/src/executor/open/codeRepository/index.tsx new file mode 100644 index 000000000..dae394d27 --- /dev/null +++ b/src/executor/open/codeRepository/index.tsx @@ -0,0 +1,120 @@ +import React, { useEffect, useState } from 'react'; +import FullScreenModal from '@/components/Common/fullScreen'; +import { ProConfigProvider } from '@ant-design/pro-components'; +import './index.less'; +import FileTab from './fileTab'; +import WordOrderTab from './wordOrderTab'; +import RepositorySettings from './repositorySettings'; +import PullRequestTab from './pullRequestTab'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { Tabs } from 'antd'; +interface IProps { + current: IRepository; + finished: () => void; +} + +const CodeRepository: React.FC = ({ current, finished }) => { + //tabs的选中标签 + const [activeTabKey, setActiveTabKey] = useState('1'); // 初始选中的标签 + //当前分支 + const [clickTrees, setClickTrees] = useState('master'); + //FileTab 提交史,分支,版本发布的点击 + const [States, setStates] = useState(0); + //WordOrderTab 标签,里程碑,工单的点击 + const [WordOrder, setWordOrder] = useState(0); + //PullRequestTab 创建合并请求的点击 + const [pullRequest, setPullRequest] = useState(0); + //提交史数据 + const [historyCommitList, setHistoryCommitList] = useState(null); + const [Node, setNode] = useState(); + useEffect(() => { + (async () => { + const commitList = await current.HistoryCommitList(`/${clickTrees}`); + //查询办事节点 + const workNode = await current.works[0].loadNode(); + setNode(workNode); + setHistoryCommitList(commitList.data); + })(); + }, [clickTrees]); + return ( + + { + finished(); + }}> + {Node && Node.code ? ( +
+

+ {current.directory.target.code}/{current.name} +

+ { + // return <> + // }} + onTabClick={(key: any) => { + setActiveTabKey(key); + if (key == 1) { + setStates(0); + } + if (key == 2) { + setWordOrder(2); + } + if (key == 3) { + setPullRequest(0); + } + }} + defaultActiveKey="1" + activeKey={activeTabKey} + type={'card'} + tabBarGutter={0} + className="file_name"> + + { + setClickTrees(value); + }} + /> + + + + + + + + + + + +
+ ) : ( + <> +
请先设置管理者
+ + )} +
+
+ ); +}; +export default CodeRepository; diff --git a/src/executor/open/codeRepository/pullRequestTab/codeCommit/index.tsx b/src/executor/open/codeRepository/pullRequestTab/codeCommit/index.tsx new file mode 100644 index 000000000..0a985ec00 --- /dev/null +++ b/src/executor/open/codeRepository/pullRequestTab/codeCommit/index.tsx @@ -0,0 +1,52 @@ +import { SettingFilled } from '@ant-design/icons'; +import React, { useEffect, useState } from 'react'; +import { SubmissionList } from '../../common/index'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { model } from '@/ts/base'; +import CodeComparison from '../../fileTab/HistoryCommit/CodeComparison'; + +interface IProps { + current: IRepository; + PRlistData: model.pullRequestList; +} +const CodeCommit: React.FC = ({ current, PRlistData }) => { + const [PRCommits, setPRCommits] = useState(); + const [node, setnode] = useState(); + useEffect(() => { + (async () => { + const res = await current.PRCommits({ + IssueId: PRlistData.IssueId, + UserName: PRlistData.PosterUser.name, + HeadRepo: PRlistData.HeadRepo, + BaseRepo: PRlistData.BaseRepo, + Status: PRlistData.Status, + HeadBranch: PRlistData.HeadBranch, + BaseBranch: PRlistData.BaseBranch, + HasMerged: PRlistData.HasMerged, + MergeCommitId: PRlistData.MergeCommitId, + MergeBase: PRlistData.MergeBase, + }); + console.log(res); + setPRCommits(res.data); + })(); + }, []); + if (!PRCommits) { + return <>; + } + return ( + <> + { + return () => { + console.log(_item); + setnode(_item); + }; + }} + historyCommitList={PRCommits.Commits} + title={`${PRCommits.Commits.length}次代码提交`} + /> + {node && } + + ); +}; +export { CodeCommit }; diff --git a/src/executor/open/codeRepository/pullRequestTab/codeFiles/index.tsx b/src/executor/open/codeRepository/pullRequestTab/codeFiles/index.tsx new file mode 100644 index 000000000..d7e21d333 --- /dev/null +++ b/src/executor/open/codeRepository/pullRequestTab/codeFiles/index.tsx @@ -0,0 +1,41 @@ +import { SettingFilled } from '@ant-design/icons'; +import React, { useEffect, useState } from 'react'; +import { SubmissionList } from '../../common/index'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { model } from '@/ts/base'; +import CodeComparison from '../../fileTab/HistoryCommit/CodeComparison'; + +interface IProps { + current: IRepository; + PRlistData: model.pullRequestList; +} +const CodeFiles: React.FC = ({ current, PRlistData }) => { + const [PRCommits, setPRCommits] = useState(); + useEffect(() => { + (async () => { + const res = await current.PRFiles({ + IssueId: PRlistData.IssueId, + UserName: PRlistData.PosterUser.name, + HeadRepo: PRlistData.HeadRepo, + BaseRepo: PRlistData.BaseRepo, + Status: PRlistData.Status, + HeadBranch: PRlistData.HeadBranch, + BaseBranch: PRlistData.BaseBranch, + HasMerged: PRlistData.HasMerged, + MergeCommitId: PRlistData.MergeCommitId, + MergeBase: PRlistData.MergeBase, + }); + console.log(res); + setPRCommits(res); + })(); + }, []); + if (!PRCommits) { + return <>; + } + return ( + <> + + + ); +}; +export { CodeFiles }; diff --git a/src/executor/open/codeRepository/pullRequestTab/index.less b/src/executor/open/codeRepository/pullRequestTab/index.less new file mode 100644 index 000000000..db5ad2a7e --- /dev/null +++ b/src/executor/open/codeRepository/pullRequestTab/index.less @@ -0,0 +1,60 @@ +.mar{ + font-weight: 800; +} +.messagehint{ + display: inline-block; + background-color: #2185d0; + height: 18px; + padding: 0 5px; + color: white; + border-radius: 10%; + font-size: 12px; + margin-left: 5px; +} +.gev{ + padding: 0rem 0.8rem; +} +.gev1 { + margin-top: 10px; + color:#d95c5c; + } +.gev2 { + margin-top: 10px; + color:#21ba45; + } +.gev3{ + margin-top: 10px; + color:#6e5494; +} +.gev4{ + margin-top: 10px; + color:#767676; +} +.btn_content{ + margin: 20px 0; + height: 40px; +} +.controller_btn { + border: 1px solid #ddd; + padding: 0.8rem 0.8rem; + // border-top-left-radius: 0.2rem; + // border-bottom-left-radius: 0.2rem; + cursor: pointer; + user-select: none; + &:last-child { + border-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; + } + &.active { + color: #13ae38; + border: 1px solid #13ae38; + } + + &.active2 { + color: #d41515; + border: 1px solid #d41515; + } + } diff --git a/src/executor/open/codeRepository/pullRequestTab/index.tsx b/src/executor/open/codeRepository/pullRequestTab/index.tsx new file mode 100644 index 000000000..806c3f14c --- /dev/null +++ b/src/executor/open/codeRepository/pullRequestTab/index.tsx @@ -0,0 +1,515 @@ +import React, { useEffect, useState } from 'react'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { Button, Tabs, Tag, Select, message } from 'antd'; +import { + InfoCircleOutlined, + PartitionOutlined, + MessageOutlined, + SubnodeOutlined, + FileAddOutlined, +} from '@ant-design/icons'; +import './index.less'; +import CodeComparison from '../fileTab/HistoryCommit/CodeComparison'; +import { getTimeAgo } from '../hook/index'; +import orgCtrl from '@/ts/controller'; +import { model } from '@/ts/base'; +import { SubmissionList, ContentFrame } from '../common/index'; +import { CodeCommit } from './codeCommit'; +import { CodeFiles } from './codeFiles'; +interface IProps { + current: IRepository; + States: number; + setStates: Function; + setActiveTabKey: Function; + setWordOrder: Function; +} + +const PullRequestTab: React.FC = ({ + current, + States, + setStates, + setActiveTabKey, + setWordOrder, +}) => { + const [PRdata, setPRdata] = useState(null); + //代码提交历史 + const [historyCommitList, setHistoryCommitList] = useState(null); + //分支列表选项 + const [trees, setTrees] = useState([]); + //第一个Select框 + const [Select1, setSelect1] = useState('master'); + // + const [Select2, setSelect2] = useState('master'); + //是否需要比对 + const [IsCompare, setIsCompare] = useState(); + const [PRlistTabKey, setPRlistTabKey] = useState(); + //开启pr列表关闭状态 + const [PRlistType, setPRlistType] = useState(0); + //选择的单条pr列表数据 + const [PRlistData, setPRlistData] = useState(); + //选择的单条pr列表id + const [PRId, setPRId] = useState(); + // 代码提交文件变动的数量 + const [titleKeyData, setTitleKeyData] = useState(); + useEffect(() => { + (async () => { + const data = await current.PullRequestcomparison(`/${Select1 + '...' + Select2}`); + console.log(data); + console.log(current); + setPRdata(data); + setIsCompare(data.data.IsCompare); + setHistoryCommitList(data.data.Commit); + setTrees(data.data.BaseBranches); + })(); + }, [Select1, Select2]); + // if (!historyCommitList) { + // return <>; + // } + return ( +
+
+
+ { + setActiveTabKey('2'); + setWordOrder(0); + }}> + 标签管理 + + { + setActiveTabKey('2'); + setWordOrder(1); + }}> + 里程碑 + +
+ +
+ {(() => { + switch (States) { + case 0: + return ( + <> +
+ { + setPRlistType(0); + console.log(current); + }}> + {current.isPullList(0)?.length}个开启中 + + { + setPRlistType(1); + }}> + {current.isPullList(1)?.length}个已关闭 + +
+
+ {current.isPullList(PRlistType)?.map((pull, i) => { + return ( +
+
{ + const res = await current.PRCommits({ + IssueId: pull.IssueId, + UserName: pull.PosterUser.name, + HeadRepo: pull.HeadRepo, + BaseRepo: pull.BaseRepo, + Status: pull.Status, + HeadBranch: pull.HeadBranch, + BaseBranch: pull.BaseBranch, + HasMerged: pull.HasMerged, + MergeCommitId: pull.MergeCommitId, + MergeBase: pull.MergeBase, + }); + console.log(res); + + setTitleKeyData(res.data); + setStates(2); + setPRlistData(pull); + setPRId(pull.IssueId); + + // console.log(current.findPRByIssueId(pull.IssueId)); + }}> +
+ #{pull.IssueId} + {pull.Name} +
+
+

+ 由 + + {pull.PosterUser.name} + + 于{getTimeAgo(pull.CreateUnix)}创建 +

+
+
+
+
+ ); + })} +
+ + ); + case 1: + return ( + <> +

对比文件变化

+

对比两个分支间的文件变化并发起一个合并请求。

+
+ + { + setSelect2(value); + console.log(current); + }} + options={trees.map((item) => ({ label: item, value: item }))} + /> +
+
+ {IsCompare ? ( + current.pullRequestList.some((item) => { + const ishas = + item.IsClosed == false && + item.HeadRepo == + `${current.directory.target.code}/${current.name}` && + item.BaseRepo == + `${current.directory.target.code}/${current.name}` && + item.HeadBranch == Select2 && + item.BaseBranch == Select1; + return ishas; + }) ? ( +
+ 已经存在目标分支的合并请求: + + {(() => { + const data = current.pullRequestList.find((item) => { + const ishas = + item.IsClosed === false && + item.HeadRepo === + `${current.directory.target.code}/${current.name}` && + item.BaseRepo === + `${current.directory.target.code}/${current.name}` && + item.HeadBranch === Select2 && + item.BaseBranch === Select1; + return ishas; + }); + return data.HeadRepo + ` #${data.IssueId}`; + })()} + +
+ ) : ( + <> + { + const res = await current.IsPullRequestcomparison( + `/${Select1 + '...' + Select2}`, + ); + const pulldata: model.pullRequestList = { + IssueId: current.pullRequestList.length, + RepoName: current.RepoName, + PosterUser: orgCtrl.user.metadata, + Name: title, + Content: content, + IsClosed: false, + NumComment: 0, + CreateUnix: Date.now(), + UpdateUnix: Date.now(), + Status: res.data.Status, + HeadRepo: `${current.directory.target.code}/${current.name}`, + BaseRepo: `${current.directory.target.code}/${current.name}`, + HeadBranch: Select2, + BaseBranch: Select1, + HasMerged: false, + MergeBase: res.data.MergeBase, + MergeCommitId: '', + MergerUser: '', + MergedUnix: 0, + comment: [ + { + Id: Date.now(), + RepoName: current.RepoName, + IssueId: current.pullRequestList.length, + Content: content || '这个人很懒,什么都没有留下', + CreateUnix: Date.now(), + UpdateUnix: Date.now(), + PosterUser: orgCtrl.user.metadata, + }, + ], + }; + current.pullRequestList.push(pulldata); + await current.update(current.metadata); + const apply = await current.works[0].createCodeApply(); + if (!apply) { + throw new Error('创建办事申请失败!'); + } + console.log(apply); + await apply.createCodeApply(apply.belong.id, { + pulldata: pulldata, + }); + setStates(0); + }} + current={current} + /> + { + return () => { + console.log(_item); + }; + }} + historyCommitList={historyCommitList} + title={`${historyCommitList?.length}次代码提交`} + BeforeCommitID={PRdata?.data.BeforeCommitID} + AfterCommitID={PRdata?.data.AfterCommitID} + /> + + + ) + ) : ( +
+ 基准和对比分支代码已经同步,无需进行对比。 +
+ )} + + ); + case 2: + if (!PRlistData) { + return <>; + } + return ( + <> +
+
+

+ #{PRlistData.IssueId} + {PRlistData.Name} +

+ +
+
+ {PRlistData.HasMerged ? ( +
+ + 已合并 +
+ ) : PRlistData.IsClosed ? ( +
+ + 已关闭 +
+ ) : ( +
+ + 开启中 +
+ )} + +
+ + {PRlistData.PosterUser.name} + + 请求将 1 次代码提交从 + {`${PRlistData.RepoName}/${PRlistData.HeadBranch}`} + 合并至 + {`${PRlistData.RepoName}/${PRlistData.BaseBranch}`} +
+
+
+
+ { + console.log(key); + setPRlistTabKey(key); + }} + defaultActiveKey="1" + activeKey={PRlistTabKey} + type={'card'} + tabBarGutter={0} + className="file_name"> + + + + 对话内容 + + {PRlistData.comment.length} + + } + key="1"> + <> + { + current.pullRequestList[PRlistData.IssueId].comment.push({ + Id: Date.now(), + RepoName: current.RepoName, + IssueId: PRlistData.IssueId, + Content: content, + CreateUnix: Date.now(), + UpdateUnix: Date.now(), + PosterUser: orgCtrl.user.metadata, + }); + await current.update(current.metadata); + setPRlistData(current.pullRequestList[PRlistData.IssueId]); + }} + current={current} + PRlistData={PRlistData} + titleShow={false} + onOpenPR={async () => { + const isexist = current.pullRequestList.find((value) => { + return ( + value.IsClosed == false && + value.BaseBranch == PRlistData.BaseBranch && + value.HeadBranch == PRlistData.HeadBranch + ); + }); + if (isexist) { + message.warning( + `由于已经存在来自相同仓库和合并信息的未合并请求(#${isexist.IssueId}),您无法执行重新开启操作。`, + ); + return; + } + current.pullRequestList[PRlistData.IssueId].IsClosed = false; + await current.update(current.metadata); + setStates(0); + setPRlistType(0); + }} + onClosePR={async () => { + current.pullRequestList[PRlistData.IssueId].IsClosed = true; + console.log(current); + await current.update(current.metadata); + setStates(0); + setPRlistType(1); + }} + /> + + + + + + 代码提交 + + + {titleKeyData?.NumInfo?.NumCommits} + + + } + key="2"> + + + + + + 文件变动 + + + {titleKeyData?.NumInfo?.NumFiles} + + + } + key="3"> + + + +
+ + ); + default: + return <>; + } + })()} +
+ ); +}; +export default PullRequestTab; diff --git a/src/executor/open/codeRepository/repositorySettings/index.less b/src/executor/open/codeRepository/repositorySettings/index.less new file mode 100644 index 000000000..a73b073ad --- /dev/null +++ b/src/executor/open/codeRepository/repositorySettings/index.less @@ -0,0 +1,63 @@ +.Settingleft{ + // position: absolute; + width: 14rem; + // left: -5vw; + h3{ + margin: 0; + } +} +.Settingright{ + margin-left: 2rem; + width: 100%; + h3{ + margin: 0; + } +} +.flex_align_Setting{ + display: flex; + align-items: flex-start; + // justify-content: flex-start; +} +.action{ + background-color: #f0f0f0; + } +.Settingbox{ + padding: 0.6rem 0rem 0.6rem 1rem; + box-sizing: border-box; +} +.branch_box { + // background-color: #3e5ed8; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.6rem 0rem 0.6rem 1rem; + box-sizing: border-box; + margin-bottom: 0rem; + border-bottom: 1px solid #ddd; + cursor: pointer; + + &:hover { + background-color: #f0f0f0; + } + + &:last-child { + border-bottom: 0; + } + + .flex_public { + display: flex; + align-items: center; + + .master_tag { + display: block; + color: #3e5ed8; + padding: 0.1rem 0.6rem; + background-color: #ddd; + border-radius: 0.2rem; + margin-right: 0.6rem; + } + .commit_text { + color: #606266; + } + } + } \ No newline at end of file diff --git a/src/executor/open/codeRepository/repositorySettings/index.tsx b/src/executor/open/codeRepository/repositorySettings/index.tsx new file mode 100644 index 000000000..03367dbba --- /dev/null +++ b/src/executor/open/codeRepository/repositorySettings/index.tsx @@ -0,0 +1,245 @@ +import React, { useEffect, useState } from 'react'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { Button, Select, Checkbox, Divider, message } from 'antd'; +import './index.less'; + +interface IProps { + current: IRepository; +} + +const RepositorySettings: React.FC = ({ current }) => { + const [content, setcontent] = useState('基本设置'); + const title = [ + { + name: '基本设置', + key: 1, + }, + { + name: '管理协作者', + key: 2, + }, + { + name: '管理分支', + key: 3, + }, + { + name: '管理Web钩子', + key: 4, + }, + { + name: '管理部署私钥', + key: 5, + }, + ]; + //管理分支信息 + const [settingbranchesdata, setSettingbranchesdata] = useState(null); + //单条保护分支信息 + const [protectedData, setProtectedData] = useState(null); + //单条保护分支信息 + const [defaultBranch, setDefaultBranch] = useState(null); + useEffect(() => { + (async () => { + try { + const settingbranchesdata = await current.Codesettingbranches(); + console.log(settingbranchesdata); + setSettingbranchesdata(settingbranchesdata.data); + setDefaultBranch(settingbranchesdata.data.DefaultBranch); + } catch (error) { + console.log(error); + } + })(); + }, []); + return ( + <> +
+
+

+ 仓库设置 +

+ {title.map((value, i) => { + return ( +
{ + setcontent(value.name); + }}> + {value.name} +
+ ); + })} +
+ {(() => { + switch (content) { + case '管理分支': + return ( + <> +
+
+

+ 默认分支 +

+
+ 默认分支是被用于代码提交、合并请求和在线编辑的基准分支。 +
+ { + // console.log(value); + // }} + onSelect={async (val) => { + const res = await current.Codesettingbranches(`/${val}`); + setProtectedData(res.data); + setcontent('管理分支.分支保护'); + }} + options={settingbranchesdata?.AllBranches?.map((item) => ({ + label: item, + value: item, + }))} + /> +
+
+
+
+ + ); + case '管理分支.分支保护': + return ( + <> +
+
+

+ 分支保护 +

+
+ 请选择应用于{' '} + {protectedData?.Branch}{' '} + 分支的保护选项。 +
+ { + // console.log(e, e.target.checked); + setProtectedData({ + ...protectedData, + IsProtected: e.target.checked, + }); + }}> + 启用分支保护 +
+ 禁止强制推送和删除分支。 +
+
+ + +
+
+
+
+ + ); + default: + return ( +
+
+

+ {content} +

+
+
+
+ ); + } + })()} +
+ + ); +}; +export default RepositorySettings; diff --git a/src/executor/open/codeRepository/wordOrderTab/index.tsx b/src/executor/open/codeRepository/wordOrderTab/index.tsx new file mode 100644 index 000000000..bfadd44c6 --- /dev/null +++ b/src/executor/open/codeRepository/wordOrderTab/index.tsx @@ -0,0 +1,295 @@ +import React, { useEffect, useState } from 'react'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { Avatar, Button, Input, Tabs, Tag, Upload } from 'antd'; +import type { UploadProps } from 'antd'; +import { + DeleteOutlined, + EditOutlined, + InboxOutlined, + InfoCircleOutlined, + SettingFilled, + TagOutlined, + UserOutlined, +} from '@ant-design/icons'; + +interface IProps { + current: IRepository; + States: number; + setStates: Function; +} + +const WordOrderTab: React.FC = ({ current, States, setStates }) => { + //0标签管理,1里程碑,2工单列表,3创建功能按钮状态 + const [tagsController, setTagsController] = useState(0); + //创建工单按钮状态 + const [createOrder, setCreateOrder] = useState(false); + + /** + * 颜色自行加键值对 + */ + const tagsList = [ + { + id: 1, + tagsName: 'bug', + tagCount: 0, + btnColor: '#3D5A80', + }, + { + id: 2, + tagsName: 'duplicate', + tagCount: 0, + btnColor: '#1F2D3D', + }, + { + id: 3, + tagsName: 'enhancement', + tagCount: 0, + btnColor: '#385E7C', + }, + { + id: 4, + tagsName: 'help wanted', + tagCount: 0, + btnColor: '#2D4561', + }, + { + id: 5, + tagsName: 'invalid', + tagCount: 0, + btnColor: '#1F2D3D', + }, + { + id: 6, + tagsName: 'question', + tagCount: 0, + btnColor: '#1D2D3D', + }, + { + id: 7, + tagsName: 'ree', + tagCount: 0, + btnColor: '#2F5082', + }, + ]; + const uploadProps: UploadProps = { + name: 'file', + multiple: true, + action: 'https://www.io/v2/5cc8019d300000980a055e76', + onChange(info) { + const { status } = info.file; + if (status !== 'uploading') { + console.log(info.file, info.fileList); + } + if (status === 'done') { + message.success(`${info.file.name} file uploaded successfully.`); + } else if (status === 'error') { + message.error(`${info.file.name} file upload failed.`); + } + }, + onDrop(e) { + console.log('Dropped files', e.dataTransfer.files); + }, + }; + return ( +
+
+
+ { + setStates(0); + }}> + 标签管理 + + { + setStates(1); + }}> + 里程碑 + +
+ {(() => { + switch (States) { + case 0: + return ; + case 1: + return ( + + ); + case 2: + case 3: + return ( + + ); + default: + return <>; + } + })()} +
+ {(() => { + switch (States) { + case 0: + return ( +
+
+ {tagsList?.length}个标签 +
+ {tagsList?.map((item) => ( +
+ } + color={item.btnColor}> + {item.tagsName} + +
+ + + {item.tagCount}个已开启的工单 + + + + 编辑 + + + + 删除 + +
+
+ ))} +
+ ); + case 1: + return ( +
+
+ 0开启中 + 标签管理 +
+
+ ); + case 2: + return ( +
{ + setStates(3); + }}> +
+ #2 + 124 +
+
+

+ 由小泥人于38分钟前创建 +

+
+
+
+ ); + case 3: + return ( + <> +
+ } /> +
+ +
+ + + +
+
+ +

+ +

+

文件拖拽到此处或者单击上传

+
+
+
+ +
+
+ + +
+
+ +

+ +

+

文件拖拽到此处或者单击上传

+
+
+
+ +
+
+
+
+
+

+ 标签 +

+

未选择标签

+
+

+ 里程碑 +

+

未选里程碑

+
+

+ 指派成员 +

+

未指派成员

+
+
+
+
+
+ } /> +
+

小泥人 评论于 刚刚

+

这人很懒,留下了个毛

+
+
+
+ + ); + default: + return <>; + } + })()} +
+ ); +}; +export default WordOrderTab; diff --git a/src/executor/open/index.tsx b/src/executor/open/index.tsx index 187a26e15..e974f1002 100644 --- a/src/executor/open/index.tsx +++ b/src/executor/open/index.tsx @@ -11,6 +11,7 @@ import EntityPreview from './entity'; import CodeEditor from './codeeditor'; import Directory from './directory'; import EntityForm from '../operate/entityForm'; +import CodeRepository from './codeRepository'; import { IEntity, ISysFileInfo, TargetType } from '@/ts/core'; import JoinApply from './task/joinApply'; import { model, schema } from '@/ts/base'; @@ -96,6 +97,8 @@ const ExecutorOpen: React.FC = (props: IOpenProps) => { finished={props.finished} /> ); + case '代码仓库配置': + return ; default: if (remarkTypes[props.entity.typeName]) { return ( diff --git a/src/executor/operate/entityForm/index.tsx b/src/executor/operate/entityForm/index.tsx index 37dcc14e7..3d8b2ad46 100644 --- a/src/executor/operate/entityForm/index.tsx +++ b/src/executor/operate/entityForm/index.tsx @@ -12,6 +12,8 @@ import LabelsForm from './labelsForm'; import RenameForm from './renameForm'; import TransferForm from './transferForm'; import PageTemplateForm from './templateForm'; +import RepositoryForm from './repositoryForm'; +import WarehousePermissionForm from './warehousePermissionForm'; interface IProps { cmd: string; @@ -93,6 +95,11 @@ const EntityForm: React.FC = ({ cmd, entity, finished }) => { finished={reloadFinish} /> ); + case 'newWarehouse': + case 'updateWarehouse': + return ; + case 'WarehousePermission': + return ; default: { return ( diff --git a/src/executor/operate/entityForm/repositoryForm.tsx b/src/executor/operate/entityForm/repositoryForm.tsx new file mode 100644 index 000000000..a34079667 --- /dev/null +++ b/src/executor/operate/entityForm/repositoryForm.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { IEntity } from '@/ts/core'; +import { schema, kernel } from '@/ts/base'; +import { ProFormColumnsType } from '@ant-design/pro-components'; +import SchemaForm from '@/components/SchemaForm'; +import { IDirectory } from '@/ts/core'; +import { message } from 'antd'; + +interface IProps { + cmd: string; + entity: IEntity; + finished: () => void; +} + +/* + 新建仓库弹出框 +*/ +const repositoryForm: React.FC = ({ cmd, entity, finished }) => { + const columns: ProFormColumnsType[] = [ + { + title: '仓库名称', + dataIndex: 'name', + readonly: false, + formItemProps: { + rules: [{ required: true, message: '仓库名称为必填项' }], + }, + }, + { + title: '仓库描述', + dataIndex: 'remark', + valueType: 'textarea', + readonly: false, + colProps: { span: 24 }, + }, + ]; + + return ( + { + if (!open) { + finished(); + } + }} + onFinish={async (values) => { + values.typeName = '代码仓库配置'; + let directory = entity as IDirectory; + try { + await directory.standard.createRepository(values); + } catch (error) { + message.error('创建仓库失败或仓库已存在'); + } + finished(); + }}> + ); +}; + +export default repositoryForm; diff --git a/src/executor/operate/entityForm/warehousePermissionForm.tsx b/src/executor/operate/entityForm/warehousePermissionForm.tsx new file mode 100644 index 000000000..0e28a9923 --- /dev/null +++ b/src/executor/operate/entityForm/warehousePermissionForm.tsx @@ -0,0 +1,119 @@ +import { IDirectory } from '@/ts/core'; +import { Modal, Button, Spin, message } from 'antd'; +import React, { useState, useEffect } from 'react'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import SelectIdentity from '@/components/Common/SelectIdentity'; +import ShareShowComp from '@/components/Common/ShareShowComp'; +import { + convertNode, + loadNilResouce, + loadResource, + loadcode, +} from '@/components/Common/FlowDesign/processType'; +import useAsyncLoad from '@/hooks/useAsyncLoad'; +interface Iprops { + current: IRepository; + finished: () => void; +} + +const WarehousePermission = (props: Iprops) => { + const [isOpen, setIsOpen] = useState(false); + const [currentData, setCurrentData] = useState(); + const [loaded, resource] = useAsyncLoad(async () => { + const node = await props.current.works[0].loadNode(); + if (node && node.code) { + return loadResource(node, ''); + } + return loadcode(); + }); + useEffect(() => { + (async () => { + const workNode = await props.current.works[0].loadNode(); + if (workNode && workNode.code) { + setCurrentData({ + id: workNode.children?.destId, + name: workNode.children?.destName, + }); + } + })(); + return () => { + setCurrentData(null); + }; + }, []); + return ( + <> + { + if (!currentData) { + message.warning('请先设置管理员'); + return; + } + const a = resource; + a.children.destId = currentData.id; + a.children.destName = currentData.name; + a.children.destType = currentData.typeName; + console.log(resource); + if ( + await props.current.works[0].update({ + ...props.current.works[0].metadata, + resource: a, + }) + ) { + props.current.loadWorks(true); + console.log(props.current.works[0].metadata, a); + message.info('保存成功'); + props.finished(); + } + }} + onCancel={() => props.finished()}> + {loaded ? ( + <> + + {currentData && currentData.id != '1' && ( + { + // props.current.destId = ''; + // props.current.destName = ''; + setCurrentData(undefined); + // props.refresh(); + }} + /> + )} + + ) : ( + +
+
+ )} +
+ { + console.log(selected); + setCurrentData(selected[0]); + setIsOpen(false); + }} + /> + + ); +}; + +export default WarehousePermission; diff --git a/src/ts/base/model.ts b/src/ts/base/model.ts index c70ca0c9c..b5f1aead8 100644 --- a/src/ts/base/model.ts +++ b/src/ts/base/model.ts @@ -1411,3 +1411,56 @@ export type DiskInfoType = { // 查询时间 getTime: string; }; + +export type pullRequestList = { + IssueId: number; + //仓库名称 + RepoName: string; + //提交合并请求的人 + PosterUser: XTarget; + //issue的标题 + Name: string; + //issue的内容 + Content: string; + //是否关闭 + IsClosed: boolean; + //评论数 + NumComment: number; + //创建时间 + CreateUnix: number | Date; + //更新时间 + UpdateUnix: number | Date; + //是否存在冲突,0为存在冲突,2为不存在冲突 + Status: number; + //需要合并进来的仓库(13684856438/pre) + HeadRepo: string; + //基本的仓库(13684856438/pre) + BaseRepo: string; + //需要合并进来的分支(test) + HeadBranch: string; + //基本分支(master) + BaseBranch: string; + //hash值 + MergeBase: string; + //hash值 + MergeCommitId: string; + //是否合并 + HasMerged: boolean; + //合并请求的人 + MergerUser: string | XTarget; + //合并时间 + MergedUnix: number; + comment: comment[]; + } +export type comment = { + Id: number; + //仓库名称 + RepoName: string ; + IssueId: number; + //评论内容 + Content: string; + CreateUnix: number | Date; + UpdateUnix: number | Date; + //评论人 + PosterUser: XTarget; + } \ No newline at end of file diff --git a/src/ts/core/public/index.ts b/src/ts/core/public/index.ts index cbf427eba..e94b89041 100644 --- a/src/ts/core/public/index.ts +++ b/src/ts/core/public/index.ts @@ -19,4 +19,5 @@ export { personJoins, targetOperates, teamOperates, + warehouseOperates, } from './operates'; diff --git a/src/ts/core/public/operates.ts b/src/ts/core/public/operates.ts index 5627e1c4f..ed11cdfe5 100644 --- a/src/ts/core/public/operates.ts +++ b/src/ts/core/public/operates.ts @@ -240,6 +240,15 @@ export const newWarehouse = { }, ], }; +/** 仓库的操作 */ +export const warehouseOperates = { + WarehousePermission: { + sort: -1, + cmd: 'WarehousePermission', + label: '设立管理者', + iconType: 'WarehousePermission', + }, +}; /** 团队的操作 */ export const teamOperates = { diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index b52eed5fe..d8e83faa6 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -1,5 +1,11 @@ import { common, model, schema } from '../../base'; -import { directoryNew, directoryOperates, entityOperates, fileOperates } from '../public'; +import { + directoryNew, + directoryOperates, + entityOperates, + fileOperates, + newWarehouse, +} from '../public'; import { ITarget } from '../target/base/target'; import { IStandardFileInfo, StandardFileInfo, IFile } from './fileinfo'; import { StandardFiles } from './standard'; @@ -140,6 +146,7 @@ export class Directory extends StandardFileInfo implements ID cnt.push(...this.standard.specieses); cnt.push(...this.standard.transfers); cnt.push(...this.standard.templates); + cnt.push(...this.standard.repository); } return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); } @@ -313,6 +320,7 @@ export class Directory extends StandardFileInfo implements ID }); } else { operates.push(directoryNew); + operates.push(newWarehouse); } if (this.target.user.copyFiles.size > 0) { operates.push(fileOperates.Parse); diff --git a/src/ts/core/thing/resource.ts b/src/ts/core/thing/resource.ts index f53875536..d6688d6a2 100644 --- a/src/ts/core/thing/resource.ts +++ b/src/ts/core/thing/resource.ts @@ -37,6 +37,7 @@ export class DataResource { this.templateColl = this.genTargetColl('standard-page-template'); this.stagingColl = this.genTargetColl('resource-staging'); this.thingColl = this.genTargetColl('_system-things'); + this.repositoryColl = this.genTargetColl('code-repository'); } /** 表单集合 */ @@ -61,6 +62,8 @@ export class DataResource { stagingColl: XCollection; /** 实体集合 */ thingColl: XCollection; + /** 代码仓库集合 */ + repositoryColl: XCollection; /** 资源对应的用户信息 */ get targetMetadata() { return this.target; diff --git a/src/ts/core/thing/standard/index.ts b/src/ts/core/thing/standard/index.ts index 5561feea2..a3fc20207 100644 --- a/src/ts/core/thing/standard/index.ts +++ b/src/ts/core/thing/standard/index.ts @@ -8,6 +8,7 @@ import { IPageTemplate, PageTemplate } from './page'; import { IProperty, Property } from './property'; import { ISpecies, Species } from './species'; import { ITransfer, Transfer } from './transfer'; +import { Repository, IRepository } from './repository'; export class StandardFiles { /** 目录对象 */ @@ -28,6 +29,8 @@ export class StandardFiles { xApplications: schema.XApplication[] = []; /** 页面模板 */ templates: IPageTemplate[] = []; + /** 代码仓库 */ + repository: IRepository[] = []; /** 表单加载完成标志 */ formLoaded: boolean = false; /** 迁移配置加载完成标志 */ @@ -36,6 +39,8 @@ export class StandardFiles { speciesesLoaded: boolean = false; /** 属性加载完成标志 */ propertysLoaded: boolean = false; + /** 代码仓库加载完成标志 */ + repositoryLoaded: boolean = false; constructor(_directory: IDirectory) { this.directory = _directory; if (this.directory.parent === undefined) { @@ -57,6 +62,7 @@ export class StandardFiles { ...this.directorys, ...this.applications, ...this.templates, + ...this.repository, ]; } async loadStandardFiles(reload: boolean = false): Promise { @@ -66,6 +72,7 @@ export class StandardFiles { this.loadPropertys(reload), this.loadSpecieses(reload), this.loadTemplates(reload), + this.loadRepository(reload), ]); return this.standardFiles; } @@ -109,6 +116,16 @@ export class StandardFiles { } return this.transfers; } + async loadRepository(reload: boolean = false): Promise { + if (this.repositoryLoaded === false || reload) { + this.repositoryLoaded = true; + const data = await this.resource.repositoryColl.load({ + options: { match: { directoryId: this.id } }, + }); + this.repository = data.map((i) => new Repository(i, this.directory)); + } + return this.repository; + } async loadApplications(_: boolean = false): Promise { this.xApplications = this.resource.applicationColl.cache.filter( (i) => i.directoryId === this.id, @@ -180,6 +197,21 @@ export class StandardFiles { return result; } } + async createRepository(data: any): Promise { + let colldata = data; + let res1 = await Repository.createRepo(data, this.directory.target); + colldata.HTTPS = res1.data.data.HTTPS; + colldata.SSH = res1.data.data.SSH; + const res = await this.resource.repositoryColl.insert({ + ...colldata, + pullRequestList: [], + directoryId: this.id, + }); + if (res) { + await this.resource.repositoryColl.notity({ data: res, operate: 'insert' }); + return res; + } + } async createApplication( data: schema.XApplication, ): Promise { @@ -269,6 +301,7 @@ export class StandardFiles { await to.speciesColl.replaceMany(this.specieses.map((a) => a.metadata)); await to.propertyColl.replaceMany(this.propertys.map((a) => a.metadata)); await to.directoryColl.replaceMany(this.directorys.map((a) => a.metadata)); + await to.repositoryColl.replaceMany(this.repository.map((a) => a.metadata)); var apps = this.resource.applicationColl.cache.filter( (i) => i.directoryId === this.id, ); @@ -298,6 +331,9 @@ const subscribeNotity = (directory: IDirectory) => { directory.resource.applicationColl.subscribe([directory.key], (data) => { subscribeCallback(directory, '应用', data); }); + directory.resource.repositoryColl.subscribe([directory.key], (data) => { + subscribeCallback(directory, '代码仓库配置', data); + }); directory.resource.templateColl.subscribe([directory.key], (data) => { subscribeCallback(directory, '模板', data); }); @@ -415,6 +451,14 @@ function standardFilesChanged( directory.resource.directoryColl.removeCache((i) => i.id != data.id); } break; + case '代码仓库配置': + directory.standard.repository = ArrayChanged( + directory.standard.repository, + operate, + data, + () => new Repository(data, directory), + ); + break; case '应用': if (data.typeName === '模块') { directory.standard.applications.forEach((i) => i.receive(operate, data)); diff --git a/src/ts/core/thing/standard/repository.ts b/src/ts/core/thing/standard/repository.ts new file mode 100644 index 000000000..ff620c2d4 --- /dev/null +++ b/src/ts/core/thing/standard/repository.ts @@ -0,0 +1,369 @@ +import { Command, common, kernel, model } from '@/ts/base'; +import { IDirectory } from '../directory'; +import { IStandardFileInfo, StandardFileInfo } from '../fileinfo'; +import { ITarget } from '@/ts/core'; +import axios from 'axios'; +import { + PageAll, + directoryNew, + directoryOperates, + entityOperates, + fileOperates, + newWarehouse, + warehouseOperates, +} from '../../public'; +import { Work, IWork } from '../../work'; + +export interface IRepository extends IStandardFileInfo { + works: IWork[]; + /** 触发器 */ + command: Command; + /** http链接 */ + HTTPS: string; + /** ssh链接 */ + SSH: string; + /** pr列表 */ + pullRequestList: model.pullRequestList[]; + /** 这个是其他的合并信息,查询其他合并到BaseBranch分支(这里是master) + * 的pr信息(查询条件为Pull.BaseBranch == Pulls[i].BaseBranch&&Pulls[i].IsClosed==false), + * 因为合并完一个后,需要判断其他的合并是否存在冲突 + **/ + // Pulls: any[]; + /** 仓库名称 */ + RepoName: string; + /** target */ + target: ITarget; + /** 创建仓库 */ + // createRepo(data: any, target: ITarget): Promise; + /** 获取仓库目录内容或文件内容 */ + RepoContent(datauri?: string): Promise; + /** 获取仓库提交历史列表 */ + HistoryCommitList(datauri?: string): Promise; + /** 获取提交代码比对信息 */ + Codecomparison(datauri?: string): Promise; + /** 获取代码分支列表 默认活跃陈旧 */ + Codebranches(datauri?: string): Promise; + /** 仓库设置->管理分支信息+保护分支信息 */ + Codesettingbranches(datauri?: string): Promise; + /** 仓库设置->保护分支更改 */ + SetProtectedbranches(datauri?: string, requestData?: object): Promise; + /** 仓库设置->默认分支更改 */ + SetDefaultBranch(branch: string): Promise; + /** 请求创建pr比对 */ + PullRequestcomparison(datauri?: string): Promise; + /** 判断合并请求是否存在冲突 */ + IsPullRequestcomparison(datauri?: string): Promise; + /** 点击页面上的“合并请求” */ + MergePull(requestData: PullRequest): Promise; + /** PR列表内的提交史 */ + PRCommits(requestData: PullRequest): Promise; + /** PR列表内的文件变动 */ + PRFiles(requestData: PullRequest): Promise; + // eslint-disable-next-line prettier/prettier + + /** 获取pr列表 0开启 1关闭 */ + isPullList(is: number): model.pullRequestList[]; + /** 根据id查找办事 */ + findWork(id: string): Promise; + /** 加载办事如果没有创建 */ + loadWorks(reload?: boolean | undefined): Promise; +} + +interface PullRequest { + IssueId: number; + UserName: string; + HeadRepo: string; + BaseRepo: string; + Status: number; + HeadBranch: string; + BaseBranch: string; + HasMerged: boolean; + MergeCommitId: string; // 根据实际情况调整数据类型 + MergeBase: string; // 根据实际情况调整数据类型 +} + +export class Repository extends StandardFileInfo implements IRepository { + HTTPS: string; + SSH: string; + command: Command; + works: IWork[]; + node: model.WorkNodeModel | undefined; + constructor(metadata: any, dir: IDirectory) { + console.log(metadata, dir); + super(metadata, dir, dir.resource.repositoryColl); + this.HTTPS = metadata.HTTPS; + this.SSH = metadata.SSH; + this.command = new Command(); + this.works = []; + this.loadWorks(true); + this.loadNode(true); + } + + get cacheFlag(): string { + return 'Repository'; + } + + get pullRequestList(): model.pullRequestList[] { + return this.metadata.pullRequestList; + } + get RepoName() { + return this.metadata.name; + } + // get target(): ITarget { + // return this.target; + // } + // 根据 IssueId 查找单个条目的方法 + findPRByIssueId(issueId: number): model.pullRequestList | undefined { + return this.metadata.pullRequestList.find( + (pr: model.pullRequestList) => pr.IssueId === issueId, + ); + } + + async copy(destination: IDirectory): Promise { + if (this.allowCopy(destination)) { + return await super.copyTo(destination.id, destination.resource.repositoryColl); + } + return false; + } + + async move(destination: IDirectory): Promise { + if (this.allowCopy(destination)) { + return await super.copyTo(destination.id, destination.resource.repositoryColl); + } + return false; + } + + override operates(): model.OperateModel[] { + const operates: model.OperateModel[] = []; + if (this.target.hasRelationAuth()) { + operates.push(newWarehouse, warehouseOperates.WarehousePermission); + } + return operates; + } + + public getPulls(): PullRequest[] { + return this.pullRequestList.map((value) => { + return { + IssueId: value.IssueId, + UserName: value.PosterUser.name, + HeadRepo: value.HeadRepo, + BaseRepo: value.BaseRepo, + Status: value.Status, + HeadBranch: value.HeadBranch, + BaseBranch: value.BaseBranch, + HasMerged: value.HasMerged, + MergeCommitId: value.MergeCommitId, + MergeBase: value.MergeBase, + }; + }); + } + public isPullList(is: number = 0) { + if (is == 0) { + return this.pullRequestList?.filter((item) => !item.IsClosed); + } + if (is == 1) { + return this.pullRequestList?.filter((item) => item.IsClosed); + } + return this.pullRequestList; + } + async RepoContent(datauri: string = '') { + // console.log(`/warehouse/${this.directory.target.code}/${this.name}` + datauri); + // let res = await axios.get(`/warehouse/${this.directory.target.code}/${this.name}` + datauri) + try { + let res = await axios.get( + `/warehouse/${this.directory.target.code}/${this.name}` + datauri, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + // return res; + } + async HistoryCommitList(datauri: string = '') { + try { + let res = await axios.get( + `/warehouse/${this.directory.target.code}/${this.name}/commits` + datauri, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + async Codecomparison(datauri: string = '') { + try { + let res = await axios.get( + `/warehouse/${this.directory.target.code}/${this.name}/commit` + datauri, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + public static async createRepo(data: any, target: ITarget) { + let res = await axios.post('/warehouse/repo/create', { + Code: target.code, + RepoName: data.name, + }); + return res; + } + /* + 没有则分集合返回 + all 所有分支集合 + */ + async Codebranches(datauri: string = '') { + try { + let res = await axios.get( + `/warehouse/${this.directory.target.code}/${this.name}/branches` + datauri, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + /* + /master 分支名 此分支保护信息 + */ + async Codesettingbranches(datauri: string = '') { + try { + let res = await axios.get( + `/warehouse/${this.directory.target.code}/${this.name}/settings/branches` + + datauri, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + async SetProtectedbranches(datauri: string = '', requestData: object = {}) { + try { + let res = await axios.post( + `/warehouse/${this.directory.target.code}/${this.name}/settings/branches` + + datauri, + requestData, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + async SetDefaultBranch(branch: string) { + try { + let res = await axios.get( + `/warehouse/${this.directory.target.code}/${this.name}/settings/branches/default_branch?branch=${branch}`, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + async PullRequestcomparison(datauri: string = '') { + try { + let res = await axios.get( + `/warehouse/${this.directory.target.code}/${this.name}/compare${datauri}`, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + async IsPullRequestcomparison(datauri: string = '') { + try { + let res = await axios.post( + `/warehouse/${this.directory.target.code}/${this.name}/compare${datauri}`, + ); + return res.data; + } catch (error) { + console.log(error); + return ''; + } + } + async MergePull(requestData: PullRequest) { + let res = await axios.post( + `/warehouse/${this.directory.target.code}/${this.name}/pulls/merge?merge_style=create_merge_commit`, + { + Pull: requestData, + Pulls: this.getPulls(), + }, + ); + return res.data; + } + async PRCommits(requestData: PullRequest) { + let res = await axios.post( + `/warehouse/${this.directory.target.code}/${this.name}/pulls/commits`, + { + ...requestData, + }, + ); + return res.data; + } + async PRFiles(requestData: PullRequest) { + let res = await axios.post( + `/warehouse/${this.directory.target.code}/${this.name}/pulls/files`, + { + ...requestData, + }, + ); + return res.data; + } + + async loadNode(reload: boolean = false): Promise { + if (this.node === undefined || reload) { + const res = await kernel.queryWorkNodes({ id: this.id }); + if (res.success) { + this.node = res.data; + } + } + return this.node; + } + async findWork(id: string): Promise { + await this.loadWorks(); + const find = this.works.find((i) => i.id === id); + if (find) { + return find; + } + } + async loadWorks(reload?: boolean | undefined): Promise { + if (reload) { + const res = await kernel.queryWorkDefine({ + id: this.id, + page: PageAll, + }); + console.log(res, '看看有没有办事节点'); + if (res.success) { + if (res.data.result) { + this.works = res.data.result.map((a) => new Work(a, this)); + } else { + this.createWork(); + } + } + } + return this.works; + } + async createWork(): Promise { + const data: any = {}; + data.applicationId = this.id; + data.shareId = this.directory.target.id; + data.applyAuth = '0'; + data.applyAuths = ['0']; + data.code = 'pr审批'; + data.name = 'pr审批'; + data.remark = '这是一个自定义的pr审批办事'; + const res = await kernel.createWorkDefine(data); + console.log(data, res); + if (res.success && res.data.id) { + let work = new Work(res.data, this); + console.log(work); + work.notify('workReplace', work.metadata); + this.works.push(work); + return work; + } + } +} diff --git a/vite.config.ts b/vite.config.ts index d98b81c0e..5160ba168 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -53,6 +53,11 @@ export default ({ command, mode }: ConfigEnv): UserConfig => { changeOrigin: true, // 是否允许跨域 ws: true, }, + '/warehouse': { + target: 'http://gittest.jx868.com', // 后台接口 + changeOrigin: true, // 是否允许跨域 + rewrite: (path) => path.replace(/^\/warehouse/, ''), + }, }, }, build: { -- Gitee From 9d755db015bf8bdb06a2ce9cf9d353c1782fc313 Mon Sep 17 00:00:00 2001 From: linlh Date: Thu, 4 Jan 2024 17:04:27 +0800 Subject: [PATCH 02/35] =?UTF-8?q?fix:pr=E5=AE=A1=E6=89=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/executor/index.tsx | 1 - .../codeRepository/common/index.module.css | 0 .../common/widgets/contentFrame/index.tsx | 30 +- .../widgets/contentFrame/inputBox/index.tsx | 4 +- .../codeRepository/pullRequestTab/index.tsx | 19 +- .../entityForm/warehousePermissionForm.tsx | 10 +- .../tools/task/codePR/contentFrame/index.tsx | 255 +++++++++++++++ src/executor/tools/task/codePR/index.tsx | 293 ++++++++++++++++++ src/executor/tools/task/index.tsx | 14 +- src/ts/core/thing/directory.ts | 11 + src/ts/core/thing/resource.ts | 1 + src/ts/core/thing/standard/index.ts | 6 +- src/ts/core/thing/standard/repository.ts | 13 +- src/ts/core/work/apply.ts | 15 + src/ts/core/work/index.ts | 40 +++ src/ts/core/work/task.ts | 123 +++++++- 16 files changed, 787 insertions(+), 48 deletions(-) delete mode 100644 src/executor/open/codeRepository/common/index.module.css create mode 100644 src/executor/tools/task/codePR/contentFrame/index.tsx create mode 100644 src/executor/tools/task/codePR/index.tsx diff --git a/src/executor/index.tsx b/src/executor/index.tsx index fed283856..b37dc7c93 100644 --- a/src/executor/index.tsx +++ b/src/executor/index.tsx @@ -19,7 +19,6 @@ const Executor: React.FC = () => { }; useEffect(() => { const id = command.subscribe((type, cmd, ...args: any[]) => { - console.log(type, cmd, args); if (type != 'executor') return; if (cmd === 'link') return history.push(args[0]); if (executeCmd(cmd, args[0]) === false) { diff --git a/src/executor/open/codeRepository/common/index.module.css b/src/executor/open/codeRepository/common/index.module.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx b/src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx index 0691165af..339704c29 100644 --- a/src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx +++ b/src/executor/open/codeRepository/common/widgets/contentFrame/index.tsx @@ -6,7 +6,7 @@ import { UserOutlined, } from '@ant-design/icons'; import { Avatar, Button, Input, message } from 'antd'; -import React, { useState, useEffect } from 'react'; +import React from 'react'; import { LabelBox } from './labelBox'; import { InputBox } from './inputBox'; import { model } from '@/ts/base'; @@ -21,6 +21,7 @@ interface IProps { titleShow?: boolean; //默认值为显示 onOpenPR?: () => void; //按钮开启pr方法 onClosePR?: () => void; //按钮关闭pr方法 + setStates?: Function; } const ContentFrame: React.FC = ({ onCreate, @@ -29,6 +30,7 @@ const ContentFrame: React.FC = ({ titleShow = true, onOpenPR, onClosePR, + setStates, }) => { return (
= ({ 该合并请求可以进行自动合并操作。

-

提交说明:

+ {/*

提交说明:

-

- {orgCtrl.user.metadata.belongId == +

*/} + {/* {orgCtrl.user.metadata.belongId == current.target.metadata.belongId && ( - )} + )} */}
diff --git a/src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx b/src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx index dca883c69..3591a1b5c 100644 --- a/src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx +++ b/src/executor/open/codeRepository/common/widgets/contentFrame/inputBox/index.tsx @@ -67,7 +67,7 @@ const InputBox: React.FC = ({
{PRlistData ? ( <> - {PRlistData.IsClosed ? ( + {/* {PRlistData.IsClosed ? ( - )} + )} */} + + + )} +
+ + + ); + } + if (PRlistData.Status == 0) { + return ( +
+
+ +
+
+
+

+ + 该合并请求存在冲突,无法进行自动合并操作。 +

+

+ + 请手动拉取代码变更以解决冲突。 +

+

+ { + setTextarea(e.target.value); + }} + /> +

+ {current?.instance?.status == 1 && + current.taskdata.approveType == '审批' && ( + <> + + + )} +
+
+
+ ); + } + })()} + + )} + +
+ {/* */} + + ); +}; +export { ContentFrame }; diff --git a/src/executor/tools/task/codePR/index.tsx b/src/executor/tools/task/codePR/index.tsx new file mode 100644 index 000000000..c0bb88df0 --- /dev/null +++ b/src/executor/tools/task/codePR/index.tsx @@ -0,0 +1,293 @@ +import React, { useState, useEffect } from 'react'; +import { Card, Tabs, Timeline } from 'antd'; +import { IWorkTask } from '@/ts/core/work/task'; +import { + FileAddOutlined, + InfoCircleOutlined, + MessageOutlined, + SubnodeOutlined, +} from '@ant-design/icons'; +// import { ContentFrame } from '@/executor/open/codeRepository/common'; +import { ContentFrame } from './contentFrame'; +import { CodeCommit } from '@/executor/open/codeRepository/pullRequestTab/codeCommit'; +import { CodeFiles } from '@/executor/open/codeRepository/pullRequestTab/codeFiles'; +import EntityIcon from '@/components/Common/GlobalComps/entityIcon'; +import { IRepository } from '@/ts/core/thing/standard/repository'; +import { IWork } from '@/ts/core'; +/** + * @description: 流程设置抽屉 + * @return {*} + */ +interface IProps { + current: IWorkTask; + finished: () => void; +} + +const CodePR: React.FC = ({ current, finished }) => { + //流程实例内的单条pr instanceData + const [PRlistData, setPRlistData] = useState(); + const [PRlistTabKey, setPRlistTabKey] = useState('1'); + const [titleKeyData, setTitleKeyData] = useState(null); + const [Repository, setRepository] = useState(); + const [Work, setWork] = useState(); + const a = async () => { + // setPRlistData(current?.instanceData?.data?.[0]?.pulldata); + const result = await current.findCodeWorkById(current.taskdata.defineId); + if (result) { + const [repository, work] = result; + const prdata = repository.findPRByIssueId( + current?.instanceData?.data?.[0]?.pulldata.IssueId, + ); + setPRlistData(prdata); + setRepository(repository); + setWork(work); + if (prdata) { + const res = await repository.PRCommits({ + IssueId: prdata?.IssueId, + UserName: prdata?.PosterUser.name, + HeadRepo: prdata?.HeadRepo, + BaseRepo: prdata?.BaseRepo, + Status: prdata?.Status, + HeadBranch: prdata?.HeadBranch, + BaseBranch: prdata?.BaseBranch, + HasMerged: prdata?.HasMerged, + MergeCommitId: prdata?.MergeCommitId, + MergeBase: prdata?.MergeBase, + }); + setTitleKeyData(res.data); + } + } + }; + useEffect(() => { + a(); + }, []); + /** 加载时间条 */ + const loadTimeline = () => { + if (current.instance) { + return ( + + + +
+
起始
+
+ {current.instance.createTime.substring( + 0, + current.instance.createTime.length - 4, + )} +
+
+ 发起人: + +
+
{current.instance.content}
+
+
+
+ {current.instance.tasks + ?.filter((a) => a.status >= 100) + ?.sort((a, b) => (a.createTime < b.createTime ? -1 : 1)) + .map((item, index) => { + return ( +
+ {item.records?.map((record) => { + return ( + + +
+
+ {item.node?.nodeType} +
+
+ {item.createTime.substring(0, item.createTime.length - 4)} +
+
+ 审批人: + +
+
审批结果:{record.status < 200 ? '通过' : '拒绝'}
+
+ {record.comment &&
审批意见:{record.comment}
} +
+
+
+
+ ); + })} +
+ ); + })} + {current.instance.tasks + ?.filter((a) => a.status < 100) + ?.sort((a, b) => (a.createTime < b.createTime ? -1 : 1)) + .map((item, index) => { + return ( +
+ + +
+
{item.node?.nodeType}
+
+ {item.createTime.substring(0, item.createTime.length - 4)} +
+
待审批
+
+
+
+
+ ); + })} +
+ ); + } + return <>; + }; + if (!PRlistData || !Repository || !Work) { + return <>; + } + return ( + <> +
+
+

+ #{PRlistData.IssueId} + {PRlistData.Name} +

+
+
+ {(() => { + if (PRlistData.HasMerged) { + return ( +
+ + 已合并 +
+ ); + } else if (current.taskdata.status == 200) { + return ( +
+ + 已关闭 +
+ ); + } else { + return ( +
+ + 开启中 +
+ ); + } + })()} + +
+ {PRlistData.PosterUser.name} + 请求将 1 次代码提交从 + {`${PRlistData.RepoName}/${PRlistData.HeadBranch}`} + 合并至 + {`${PRlistData.RepoName}/${PRlistData.BaseBranch}`} +
+
+
+
+ { + setPRlistTabKey(key); + }} + defaultActiveKey="1" + activeKey={PRlistTabKey} + type={'card'} + tabBarGutter={0} + className="file_name"> + + + + 对话内容 + + {PRlistData.comment.length} + + } + key="1"> + <> + + + + + + + 代码提交 + + {titleKeyData?.NumInfo?.NumCommits} + + } + key="2"> + + + + + + 文件变动 + + {titleKeyData?.NumInfo?.NumFiles} + + } + key="3"> + + + + {loadTimeline()} +
+ + // <>123 + ); +}; + +export default CodePR; diff --git a/src/executor/tools/task/index.tsx b/src/executor/tools/task/index.tsx index 29d7e4a5c..aba0ed437 100644 --- a/src/executor/tools/task/index.tsx +++ b/src/executor/tools/task/index.tsx @@ -21,8 +21,9 @@ import TaskDrawer from './drawer'; import useAsyncLoad from '@/hooks/useAsyncLoad'; import TaskApproval from './approval'; import { getNodeByNodeId } from '@/utils/tools'; -import { model } from '@/ts/base'; +import { command, model } from '@/ts/base'; import { IExecutor } from '@/ts/core/work/executor'; +import CodePR from './codePR'; export interface TaskDetailType { current: IWorkTask; @@ -229,6 +230,17 @@ const TaskContent: React.FC = ({ current, finished }) => { ); } + if (current.instanceData?.data?.[0]?.pulldata) { + return ( + { + command.emitter('preview', 'work'); + }} + /> + ); + } if (current.instance && current.instanceData?.node) { return ( <> diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index d8e83faa6..0a120113c 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -15,6 +15,7 @@ import { encodeKey, formatDate, sleep } from '@/ts/base/common'; import { DataResource } from './resource'; import { ISysFileInfo, SysFileInfo } from './systemfile'; import { IPageTemplate } from './standard/page'; +import { IRepository } from './standard/repository'; /** 可为空的进度回调 */ export type OnProgress = (p: number) => void; @@ -47,6 +48,8 @@ export interface IDirectory extends IStandardFileInfo { readonly isShortcut: boolean; /** 加载模板配置 */ loadAllTemplate(reload?: boolean): Promise; + /** 加载代码仓库配置 */ + loadAllRepository(): Promise; /** 加载文件 */ loadFiles(reload?: boolean): Promise; /** 上传文件 */ @@ -267,6 +270,13 @@ export class Directory extends StandardFileInfo implements ID } return applications; } + async loadAllRepository(): Promise { + const repositorys: IRepository[] = [...this.standard.repository]; + for (const item of this.children) { + repositorys.push(...(await item.loadAllRepository())); + } + return repositorys; + } async loadAllTemplate(reload?: boolean | undefined): Promise { const templates: IPageTemplate[] = [...this.standard.templates]; for (const item of this.children) { @@ -341,6 +351,7 @@ export class Directory extends StandardFileInfo implements ID await this.standard.loadApplications(); await this.standard.loadDirectorys(); await this.standard.loadTemplates(); + await this.standard.loadRepository(); } /** 文件夹递归拷贝 */ private async recursionCopy(directory: IDirectory, destDirectory: IDirectory) { diff --git a/src/ts/core/thing/resource.ts b/src/ts/core/thing/resource.ts index d6688d6a2..034a22f04 100644 --- a/src/ts/core/thing/resource.ts +++ b/src/ts/core/thing/resource.ts @@ -75,6 +75,7 @@ export class DataResource { this.directoryColl.all(reload), this.applicationColl.all(reload), this.templateColl.all(reload), + this.repositoryColl.all(reload), ]); } this._proLoaded = true; diff --git a/src/ts/core/thing/standard/index.ts b/src/ts/core/thing/standard/index.ts index a3fc20207..3c876e16c 100644 --- a/src/ts/core/thing/standard/index.ts +++ b/src/ts/core/thing/standard/index.ts @@ -119,9 +119,9 @@ export class StandardFiles { async loadRepository(reload: boolean = false): Promise { if (this.repositoryLoaded === false || reload) { this.repositoryLoaded = true; - const data = await this.resource.repositoryColl.load({ - options: { match: { directoryId: this.id } }, - }); + const data = await this.resource.repositoryColl.cache.filter( + (i) => i.directoryId === this.directory.id, + ); this.repository = data.map((i) => new Repository(i, this.directory)); } return this.repository; diff --git a/src/ts/core/thing/standard/repository.ts b/src/ts/core/thing/standard/repository.ts index ff620c2d4..3632eefb9 100644 --- a/src/ts/core/thing/standard/repository.ts +++ b/src/ts/core/thing/standard/repository.ts @@ -67,6 +67,8 @@ export interface IRepository extends IStandardFileInfo { findWork(id: string): Promise; /** 加载办事如果没有创建 */ loadWorks(reload?: boolean | undefined): Promise; + /** 根据 IssueId 查找单个条目的方法 */ + findPRByIssueId(issueId: number): model.pullRequestList | undefined; } interface PullRequest { @@ -80,6 +82,7 @@ interface PullRequest { HasMerged: boolean; MergeCommitId: string; // 根据实际情况调整数据类型 MergeBase: string; // 根据实际情况调整数据类型 + IsClosed?: boolean; //MergePull需要 } export class Repository extends StandardFileInfo implements IRepository { @@ -89,7 +92,7 @@ export class Repository extends StandardFileInfo implements IRepository { works: IWork[]; node: model.WorkNodeModel | undefined; constructor(metadata: any, dir: IDirectory) { - console.log(metadata, dir); + // console.log(metadata, dir); super(metadata, dir, dir.resource.repositoryColl); this.HTTPS = metadata.HTTPS; this.SSH = metadata.SSH; @@ -154,6 +157,7 @@ export class Repository extends StandardFileInfo implements IRepository { HasMerged: value.HasMerged, MergeCommitId: value.MergeCommitId, MergeBase: value.MergeBase, + IsClosed: value.IsClosed, }; }); } @@ -290,7 +294,9 @@ export class Repository extends StandardFileInfo implements IRepository { `/warehouse/${this.directory.target.code}/${this.name}/pulls/merge?merge_style=create_merge_commit`, { Pull: requestData, - Pulls: this.getPulls(), + Pulls: this.getPulls().filter( + (pull) => pull.IssueId !== requestData.IssueId && !pull.IsClosed, + ), }, ); return res.data; @@ -336,7 +342,6 @@ export class Repository extends StandardFileInfo implements IRepository { id: this.id, page: PageAll, }); - console.log(res, '看看有没有办事节点'); if (res.success) { if (res.data.result) { this.works = res.data.result.map((a) => new Work(a, this)); @@ -357,10 +362,8 @@ export class Repository extends StandardFileInfo implements IRepository { data.name = 'pr审批'; data.remark = '这是一个自定义的pr审批办事'; const res = await kernel.createWorkDefine(data); - console.log(data, res); if (res.success && res.data.id) { let work = new Work(res.data, this); - console.log(work); work.notify('workReplace', work.metadata); this.works.push(work); return work; diff --git a/src/ts/core/work/apply.ts b/src/ts/core/work/apply.ts index b6f487c30..fc204e9da 100644 --- a/src/ts/core/work/apply.ts +++ b/src/ts/core/work/apply.ts @@ -16,6 +16,8 @@ export interface IWorkApply { content: string, gateways: Map, ): Promise; + /** 发起代码仓库申请 */ + createCodeApply(applyId: string, instanceData: any): Promise; } export class WorkApply implements IWorkApply { @@ -97,6 +99,19 @@ export class WorkApply implements IWorkApply { }); return res.success; } + async createCodeApply(applyId: string, instanceData: any): Promise { + this.instanceData.data[0] = instanceData; + const res = await kernel.createWorkInstance({ + ...this.metadata, + applyId: applyId, + content: 'pr审批写入', + contentType: 'Text', + data: JSON.stringify(this.instanceData), + gateways: '[]', + }); + console.log(res); + return res.success; + } private getHideForms = () => { return this.instanceData.rules .filter((a) => a.typeName == 'visable' && !a.value && a.formId == a.destId) diff --git a/src/ts/core/work/index.ts b/src/ts/core/work/index.ts index b38f940e1..6755fa097 100644 --- a/src/ts/core/work/index.ts +++ b/src/ts/core/work/index.ts @@ -41,6 +41,11 @@ export interface IWork extends IFileInfo { taskId?: string, pdata?: model.InstanceDataModel, ): Promise; + /** 生成代码仓库办事申请单 */ + createCodeApply( + taskId?: string, + pdata?: model.InstanceDataModel, + ): Promise; /** 通知变更 */ notify(operate: string, data: any): void; /** 接收通知 */ @@ -284,6 +289,41 @@ export class Work extends FileInfo implements IWork { ); } } + async createCodeApply( + taskId: string = '0', + pdata?: model.InstanceDataModel, + ): Promise { + await this.loadNode(); + if (this.node) { + const data: model.InstanceDataModel = { + data: {}, + fields: {}, + primary: {}, + node: this.node, + rules: [], + }; + this.forms.forEach((form) => { + data.fields[form.id] = form.fields; + if (pdata && pdata.data[form.id]) { + const after = pdata.data[form.id]?.at(-1); + if (after) { + data.data[form.id] = [{ ...after, nodeId: this.node!.id }]; + } + } + }); + return new WorkApply( + { + hook: '', + taskId: taskId, + title: this.name, + defineId: this.id, + } as model.WorkInstanceModel, + data, + this.directory.target.space, + this.forms, + ); + } + } async toggleCommon(): Promise { let set: boolean = false; if (this.cache.tags?.includes('常用')) { diff --git a/src/ts/core/work/task.ts b/src/ts/core/work/task.ts index 73bf8e512..607154c9c 100644 --- a/src/ts/core/work/task.ts +++ b/src/ts/core/work/task.ts @@ -1,4 +1,5 @@ import { logger } from '@/ts/base/common'; +import orgCtrl from '@/ts/controller'; import { IWork } from '.'; import { schema, model, kernel } from '../../base'; import { TaskStatus, entityOperates } from '../public'; @@ -8,6 +9,7 @@ import { IWorkApply } from './apply'; import { FileInfo, IFile } from '../thing/fileinfo'; import { Acquire } from './executor/acquire'; import { IExecutor } from './executor'; +import { IRepository } from '../thing/standard/repository'; export type TaskTypeName = '待办' | '已办' | '抄送' | '发起的'; export interface IWorkTask extends IFile { @@ -51,6 +53,15 @@ export interface IWorkTask extends IFile { findWorkById(wrokId: string): Promise; /** 加载执行器 */ loadExecutors(node: model.WorkNodeModel): IExecutor[]; + /** 获取代码仓库和代码仓库办事 */ + findCodeWorkById(wrokId: string): Promise<[IRepository, IWork] | undefined>; + /** 代码仓库合并和驳回审批 */ + approvalCodeTask( + status: number, + comment: string, + Repository?: any, + PRlistData?: any, + ): Promise; } export class WorkTask extends FileInfo implements IWorkTask { @@ -168,16 +179,19 @@ export class WorkTask extends FileInfo implements IWorkTask { } loadExecutors(node: model.WorkNodeModel) { let executors: IExecutor[] = []; - for (const item of node.executors) { - switch (item.funcName) { - case '数据申领': - executors.push(new Acquire(item, this)); - break; - case '归属权变更': - break; + if (node.executors) { + for (const item of node.executors) { + switch (item.funcName) { + case '数据申领': + executors.push(new Acquire(item, this)); + break; + case '归属权变更': + break; + } } + return executors; } - return executors; + return []; } async recallApply(): Promise { if ((await this.loadInstance()) && this.instance) { @@ -260,4 +274,97 @@ export class WorkTask extends FileInfo implements IWorkTask { } return false; } + //代码仓库审批 + async approvalCodeTask( + status: number, + comment: string, + Repository?: IRepository, + PRlistData?: any, + ): Promise { + if (await this.loadInstance(true)) { + if (this.instanceData) { + if ( + this.taskdata.status < TaskStatus.ApprovalStart && + status == TaskStatus.ApprovalStart && + Repository + ) { + const res1 = await Repository.MergePull({ + IssueId: PRlistData.IssueId, + UserName: PRlistData.PosterUser.name, + HeadRepo: PRlistData.HeadRepo, + BaseRepo: PRlistData.BaseRepo, + Status: PRlistData.Status, + HeadBranch: PRlistData.HeadBranch, + BaseBranch: PRlistData.BaseBranch, + HasMerged: PRlistData.HasMerged, + MergeCommitId: PRlistData.MergeCommitId, + MergeBase: PRlistData.MergeBase, + }); + this.instanceData.data[0] = { + pulldata: { ...PRlistData, ...res1.data.Pull }, + }; + let data = JSON.parse(JSON.stringify(res1.data)); + data.Pulls.push(data.Pull); + data.Pulls.sort((a: any, b: any) => a.IssueId - b.IssueId); + Repository.pullRequestList.forEach((val, i) => { + const matchingObject = data.Pulls.find((obj: any) => obj.IssueId === val.IssueId); + if (matchingObject) { + Repository.pullRequestList[i] = { + ...Repository.pullRequestList[i], + ...matchingObject, + MergerUser: orgCtrl.user.metadata, + MergedUnix: Date.now(), + }; + } + }); + await Repository.update(Repository.metadata); + const res = await kernel.approvalTask({ + id: this.taskdata.id, + status: status, + comment: comment, + data: JSON.stringify(this.instanceData), + }); + return res.data === true; + } + + if ( + this.taskdata.status < TaskStatus.ApprovalStart && + status == TaskStatus.RefuseStart && + Repository + ) { + this.instanceData.data[0] = { + pulldata: { ...this.instanceData.data[0].pulldata, IsClosed: true }, + }; + Repository.pullRequestList.forEach((val, i) => { + if (val.IssueId === this.instanceData?.data[0].pulldata.IssueId) { + Repository.pullRequestList[i] = { + ...Repository.pullRequestList[i], + IsClosed: true, + }; + } + }); + await Repository.update(Repository.metadata); + const res = await kernel.approvalTask({ + id: this.taskdata.id, + status: status, + comment: comment, + data: JSON.stringify(this.instanceData), + }); + return res.data === true; + } + } + } + return false; + } + async findCodeWorkById(wrokId: string): Promise<[IRepository, IWork] | undefined> { + for (let target of this.user.targets) { + for (let app of await target.directory.loadAllRepository()) { + const work = await app.findWork(wrokId); + if (work) { + return [app, work]; + } + } + } + return undefined; + } } -- Gitee From 62e058c1b60b036b5b953ebb3c219ac213f43136 Mon Sep 17 00:00:00 2001 From: linlh Date: Thu, 11 Jan 2024 14:14:27 +0800 Subject: [PATCH 03/35] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=8A=9E?= =?UTF-8?q?=E4=BA=8B=E5=B1=95=E7=A4=BA=EF=BC=8C=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/executor/tools/task/codePR/contentFrame/index.tsx | 2 +- src/ts/core/work/task.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/executor/tools/task/codePR/contentFrame/index.tsx b/src/executor/tools/task/codePR/contentFrame/index.tsx index 87804619c..06c9143fa 100644 --- a/src/executor/tools/task/codePR/contentFrame/index.tsx +++ b/src/executor/tools/task/codePR/contentFrame/index.tsx @@ -184,7 +184,7 @@ const ContentFrame: React.FC = ({ ); } - if (PRlistData.Status == 0) { + if (PRlistData.Status == 0 || PRlistData.Status == -1) { return (
implements IWorkTask { data.Pulls.push(data.Pull); data.Pulls.sort((a: any, b: any) => a.IssueId - b.IssueId); Repository.pullRequestList.forEach((val, i) => { - const matchingObject = data.Pulls.find((obj: any) => obj.IssueId === val.IssueId); + const matchingObject = data.Pulls.find( + (obj: any) => obj.IssueId === val.IssueId, + ); if (matchingObject) { Repository.pullRequestList[i] = { ...Repository.pullRequestList[i], -- Gitee From 31aed21a00a4411e2f344e1ac516fcc0855ec09f Mon Sep 17 00:00:00 2001 From: SEN Date: Wed, 24 Jan 2024 10:10:13 +0800 Subject: [PATCH 04/35] =?UTF-8?q?feat:=20=E5=A4=84=E7=90=86=E9=9C=80?= =?UTF-8?q?=E6=B1=82:=E9=9A=90=E8=97=8F=E8=A1=A8=E5=8D=95=E9=87=8C?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=AD=97=E6=AE=B5,=E5=A6=82=E5=94=AF?= =?UTF-8?q?=E4=B8=80=E6=A0=87=E8=AF=86/=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/column.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/column.tsx b/src/config/column.tsx index 43aab0452..c7d1e45ac 100644 --- a/src/config/column.tsx +++ b/src/config/column.tsx @@ -150,7 +150,7 @@ export const FullEntityColumns = (fields: model.FieldModel[]) => { remark: '由系统生成的唯一标记,无实义.', options: { fixed: true, - visible: true, + visible: false, }, }, { @@ -160,7 +160,7 @@ export const FullEntityColumns = (fields: model.FieldModel[]) => { valueType: '描述型', remark: '描述信息', options: { - visible: true, + visible: false, }, }, { -- Gitee From 45cf9d10150a2e1206d6cd8cd59b20eb40b2c36a Mon Sep 17 00:00:00 2001 From: freshzxf Date: Sat, 27 Jan 2024 14:02:49 +0800 Subject: [PATCH 05/35] =?UTF-8?q?feat:=20=E5=BC=95=E7=94=A8=E5=9E=8B?= =?UTF-8?q?=E5=9B=9E=E5=A1=AB=E6=95=B0=E6=8D=AE=E7=AD=89=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=88=9D=E6=AD=A5=E6=8F=90=E4=BA=A4=EF=BC=88=E5=BE=85=E5=AE=8C?= =?UTF-8?q?=E5=96=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkForm/Design/config/attribute.tsx | 9 +- .../Design/form/customItem/dataBox.tsx | 56 ++++++++----- .../WorkForm/Viewer/customItem/dataBox.tsx | 83 +++++++++++++------ .../DataStandard/WorkForm/Viewer/formItem.tsx | 8 +- .../DataStandard/WorkForm/Viewer/index.tsx | 18 +++- .../elements/widgets/card/List.tsx | 3 + .../tools/editModal/formEditModal.tsx | 5 +- src/executor/tools/generate/columns.tsx | 27 ++++++ src/executor/tools/task/start/default.tsx | 1 + src/executor/tools/workForm/detail.tsx | 6 +- src/executor/tools/workForm/index.tsx | 4 +- src/executor/tools/workForm/primary.tsx | 3 +- src/utils/tools.ts | 2 +- 13 files changed, 168 insertions(+), 57 deletions(-) diff --git a/src/components/DataStandard/WorkForm/Design/config/attribute.tsx b/src/components/DataStandard/WorkForm/Design/config/attribute.tsx index 2dbe32c52..03e9ab1e9 100644 --- a/src/components/DataStandard/WorkForm/Design/config/attribute.tsx +++ b/src/components/DataStandard/WorkForm/Design/config/attribute.tsx @@ -135,10 +135,15 @@ const AttributeConfig: React.FC = ({ // disabled: true, // }} />, + , = ({ = (props) => { @@ -27,14 +27,14 @@ const DataBox: React.FC = (props) => { height, readOnly, field, - attributes, defaultValue, + attributes, // allowViewDetail, multiple, nameAttribute, } = props; - const attr = attributes.find((item: schema.XAttribute) => item.id === props.name)!; - const targetFormId = attr.property?.formId; + const attr = attributes?.find((item: schema.XAttribute) => item.id === props.name)!; + const targetFormId = attr?.property?.formId; const [form, setForm] = useState(); const [formInst, setFormInst] = useState(); const [formBelong, setFormBelong] = useState(); @@ -44,6 +44,9 @@ const DataBox: React.FC = (props) => { ); // 点击选择数据 const onClick = () => { + if (!targetFormId) { + return message.warning('该属性未关联表单,请更新属性信息!'); + } EditModal.showFormSelect({ form: form!, fields: formInst?.fields!, @@ -80,23 +83,32 @@ const DataBox: React.FC = (props) => { // 初始化 useAsyncLoad(async () => { if (targetFormId) { - const targetFormMetadata = orgCtrl.user.findMetadata(targetFormId); - if (targetFormMetadata) { - const targetFormBelong = orgCtrl.targets.find( - (i) => i.id === targetFormMetadata.belongId, - )!; + let formList: XForm[] = []; + let targetFormMetadata = orgCtrl.user.findMetadata(targetFormId); + if (!targetFormMetadata && props.target) { + formList = await props.target?.resource.formColl.find([targetFormId]); + } + if (targetFormMetadata || formList.length) { + const targetFormBelong = targetFormMetadata + ? orgCtrl.targets.find((i) => i.id === targetFormMetadata?.belongId)! + : props.target; // 设置归属 setFormBelong(targetFormBelong as IBelong); - const formList = await targetFormBelong?.resource.formColl.find([targetFormId]); - // 设置表单 - setForm(formList[0]); - const formInst = new Form( - { ...formList[0], id: formList[0].id + '_' }, - targetFormBelong.directory, - ); - await formInst.loadFields(); - // 设置表单实例 - setFormInst(formInst); + if (!formList.length) { + formList = + (await targetFormBelong?.resource.formColl.find([targetFormId])) || []; + } + if (formList.length && targetFormBelong) { + // 设置表单 + setForm(formList[0]); + const formInst = new Form( + { ...formList[0], id: formList[0].id + '_' }, + targetFormBelong.directory, + ); + await formInst.loadFields(); + // 设置表单实例 + setFormInst(formInst); + } return formInst; } } diff --git a/src/components/DataStandard/WorkForm/Viewer/customItem/dataBox.tsx b/src/components/DataStandard/WorkForm/Viewer/customItem/dataBox.tsx index 7b2bafa02..dad105388 100644 --- a/src/components/DataStandard/WorkForm/Viewer/customItem/dataBox.tsx +++ b/src/components/DataStandard/WorkForm/Viewer/customItem/dataBox.tsx @@ -1,8 +1,8 @@ import React, { useState, useEffect, useCallback } from 'react'; -import { Button } from 'antd'; +import { Button, message } from 'antd'; import _ from 'lodash'; import { EditModal } from '@/executor/tools/editModal'; -import { IBelong, IForm } from '@/ts/core'; +import { IBelong, IForm, ITarget } from '@/ts/core'; import { schema } from '@/utils/excel'; import orgCtrl from '@/ts/controller'; import { Form } from '@/ts/core/thing/standard/form'; @@ -14,12 +14,14 @@ import { jsonParse } from '@/utils/tools'; import { FieldModel, FiledLookup } from '@/ts/base/model'; interface DataBoxProps extends ISelectBoxOptions { + form?: schema.XForm; field: FieldModel; attributes: XAttribute[]; multiple: boolean; + allowSetFieldsValue?: boolean; nameAttribute: string; - target: schema.XTarget; - // onValueChange?: any; + target?: ITarget; + setFieldsValue?: (data: any) => void; } const DataBox: React.FC = (props) => { const { @@ -27,14 +29,15 @@ const DataBox: React.FC = (props) => { height, readOnly, field, - attributes, defaultValue, + attributes, // allowViewDetail, + allowSetFieldsValue, multiple, nameAttribute, } = props; - const attr = attributes.find((item: schema.XAttribute) => item.id === props.name)!; - const targetFormId = attr.property?.formId; + const attr = attributes?.find((item: schema.XAttribute) => item.id === props.name)!; + const targetFormId = attr?.property?.formId; const [form, setForm] = useState(); const [formInst, setFormInst] = useState(); const [formBelong, setFormBelong] = useState(); @@ -42,8 +45,20 @@ const DataBox: React.FC = (props) => { const [selectTarget, setSelectTarget] = useState( jsonParse(defaultValue, defaultValue), ); + + // 设置当前字段值 + const setFieldValue = (dataSource: FiledLookup[]) => { + setDataSource(dataSource); + field.lookups = dataSource; + setSelectTarget( + multiple ? dataSource?.map((item) => item.value) : dataSource?.[0]?.value, + ); + }; // 点击选择数据 const onClick = () => { + if (!form) { + return message.warning('未查询到关联表单,无法选择数据!'); + } EditModal.showFormSelect({ form: form!, fields: formInst?.fields!, @@ -55,7 +70,18 @@ const DataBox: React.FC = (props) => { value: item.id, text: item[nameAttribute], })); - setDataSource(dataSource); + + // 需要设置表单值 + if (allowSetFieldsValue) { + const toSetData = Object.keys(values[0]) + .filter((id: any) => !isNaN(id) && id !== field.id) + .reduce((pre: any, cur) => { + pre[cur] = values[0][cur]; + return pre; + }, {}); + props.setFieldsValue && props.setFieldsValue(toSetData); + } + setFieldValue(dataSource); }, }); }; @@ -63,7 +89,7 @@ const DataBox: React.FC = (props) => { const onValueChanged = useCallback((e: any) => { const value = e.value; setSelectTarget(value); - if (!value) setDataSource([]); + if (!value) setFieldValue([]); props.onValueChanged?.apply(this, [ { value: JSON.stringify(Array.isArray(value) ? value : [value]) } as any, ]); @@ -80,23 +106,32 @@ const DataBox: React.FC = (props) => { // 初始化 useAsyncLoad(async () => { if (targetFormId) { - const targetFormMetadata = orgCtrl.user.findMetadata(targetFormId); - if (targetFormMetadata) { - const targetFormBelong = orgCtrl.targets.find( - (i) => i.id === targetFormMetadata.belongId, - )!; + let formList: XForm[] = []; + let targetFormMetadata = orgCtrl.user.findMetadata(targetFormId); + if (!targetFormMetadata && props.target) { + formList = await props.target?.resource.formColl.find([targetFormId]); + } + if (targetFormMetadata || formList.length) { + const targetFormBelong = targetFormMetadata + ? orgCtrl.targets.find((i) => i.id === targetFormMetadata?.belongId)! + : props.target; // 设置归属 setFormBelong(targetFormBelong as IBelong); - const formList = await targetFormBelong?.resource.formColl.find([targetFormId]); - // 设置表单 - setForm(formList[0]); - const formInst = new Form( - { ...formList[0], id: formList[0].id + '_' }, - targetFormBelong.directory, - ); - await formInst.loadFields(); - // 设置表单实例 - setFormInst(formInst); + if (!formList.length) { + formList = + (await targetFormBelong?.resource.formColl.find([targetFormId])) || []; + } + if (formList.length && targetFormBelong) { + // 设置表单 + setForm(formList[0]); + const formInst = new Form( + { ...formList[0], id: formList[0].id + '_' }, + targetFormBelong.directory, + ); + await formInst.loadFields(); + // 设置表单实例 + setFormInst(formInst); + } return formInst; } } diff --git a/src/components/DataStandard/WorkForm/Viewer/formItem.tsx b/src/components/DataStandard/WorkForm/Viewer/formItem.tsx index 75d903857..834afef84 100644 --- a/src/components/DataStandard/WorkForm/Viewer/formItem.tsx +++ b/src/components/DataStandard/WorkForm/Viewer/formItem.tsx @@ -13,7 +13,7 @@ import { DateBox, NumberBox, SelectBox, TextArea, TextBox } from 'devextreme-rea import React, { useEffect, useState } from 'react'; import { ValueChangedEvent } from 'devextreme/ui/text_box'; import { formatDate } from '@/utils'; -import { IBelong, TargetType } from '@/ts/core'; +import { IBelong, ITarget, TargetType } from '@/ts/core'; import { useEffectOnce } from 'react-use'; interface IFormItemProps { @@ -26,6 +26,8 @@ interface IFormItemProps { belong: IBelong; rules: model.RenderRule[]; onValuesChange?: (field: string, value: any) => void; + setFieldsValue?: (data: any) => void; + target?: ITarget; } const FormItem: React.FC = (props) => { @@ -67,6 +69,7 @@ const FormItem: React.FC = (props) => { props.onValuesChange?.apply(this, [props.field.id, e.value]); } }, + setFieldsValue: props.setFieldsValue, width: getItemWidth(props.numStr), }; @@ -107,8 +110,9 @@ const FormItem: React.FC = (props) => { return ( ); case '多级选择框': diff --git a/src/components/DataStandard/WorkForm/Viewer/index.tsx b/src/components/DataStandard/WorkForm/Viewer/index.tsx index 6beda6418..64357ac4c 100644 --- a/src/components/DataStandard/WorkForm/Viewer/index.tsx +++ b/src/components/DataStandard/WorkForm/Viewer/index.tsx @@ -1,5 +1,5 @@ import { common, model, schema } from '@/ts/base'; -import { IBelong } from '@/ts/core'; +import { IBelong, ITarget } from '@/ts/core'; import React, { useEffect } from 'react'; import Toolbar, { Item } from 'devextreme-react/toolbar'; import FormItem from './formItem'; @@ -21,6 +21,7 @@ const WorkFormViewer: React.FC<{ rules: model.RenderRule[]; formData?: model.FormEditData; onValuesChange?: (fieldId: string, value: any, data: any) => void; + target?: ITarget; }> = (props) => { props.data.name = props.form.name; const [key, forceUpdate] = useObjectUpdate(props.rules); @@ -192,6 +193,13 @@ const WorkFormViewer: React.FC<{ } } }; + const setFieldsValue = (data: any) => { + Object.keys(data).forEach((fieldId) => { + onValueChange(fieldId, data[fieldId], true); + }); + forceUpdate(); + }; + useEffect(() => { if (props.changedFields) { props.changedFields @@ -285,10 +293,17 @@ const WorkFormViewer: React.FC<{ onValuesChange={onValueChange} /> {props.fields.map((field) => { + if (field.valueType === '引用型') { + field.formId = props.form?.attributes?.find( + (attr) => attr.id === field.id, + )?.formId; + } return ( a.destId == field.id, @@ -298,6 +313,7 @@ const WorkFormViewer: React.FC<{ belong={props.belong} notifyEmitter={notifyEmitter} onValuesChange={onValueChange} + setFieldsValue={setFieldsValue} /> ); })} diff --git a/src/executor/design/pageBuilder/elements/widgets/card/List.tsx b/src/executor/design/pageBuilder/elements/widgets/card/List.tsx index a490d5d06..73580166b 100644 --- a/src/executor/design/pageBuilder/elements/widgets/card/List.tsx +++ b/src/executor/design/pageBuilder/elements/widgets/card/List.tsx @@ -143,6 +143,9 @@ const View: React.FC> = (props) => { if (props.work?.id) { const work = await props.ctx.view.pageInfo.loadWork(props.work.id); const node = await work?.loadNode(); + if (!keys.length) { + return message.warning('未选择商品,发起失败!'); + } if (work && node) { const instance: model.InstanceDataModel = { data: {}, diff --git a/src/executor/tools/editModal/formEditModal.tsx b/src/executor/tools/editModal/formEditModal.tsx index fbe5c264c..fbf8ca4e5 100644 --- a/src/executor/tools/editModal/formEditModal.tsx +++ b/src/executor/tools/editModal/formEditModal.tsx @@ -1,7 +1,7 @@ import { Modal } from 'antd'; import React from 'react'; import { kernel, model, schema } from '@/ts/base'; -import { IBelong } from '@/ts/core'; +import { IBelong, ITarget } from '@/ts/core'; import WorkFormViewer from '@/components/DataStandard/WorkForm/Viewer'; interface IFormEditProps { @@ -11,6 +11,7 @@ interface IFormEditProps { create: boolean; initialValues?: any; onSave: (values: any) => void; + target?: ITarget; } const FormEditModal = ({ @@ -20,6 +21,7 @@ const FormEditModal = ({ create, initialValues, onSave, + target, }: IFormEditProps) => { const editData: any = { ...initialValues }; const modal = Modal.confirm({ @@ -38,6 +40,7 @@ const FormEditModal = ({ fields={fields} data={editData} belong={belong} + target={target} />
), diff --git a/src/executor/tools/generate/columns.tsx b/src/executor/tools/generate/columns.tsx index bbfe5f303..0e2a73266 100644 --- a/src/executor/tools/generate/columns.tsx +++ b/src/executor/tools/generate/columns.tsx @@ -5,6 +5,8 @@ import EntityIcon from '@/components/Common/GlobalComps/entityIcon'; import { generateUuid } from '@/ts/base/common'; import { ellipsisText, formatDate } from '@/utils'; import { Button } from 'antd'; +import { jsonParse } from '@/utils/tools'; +import { FiledLookup } from '@/ts/base/model'; /** 使用form生成表单列 */ export const GenerateColumn = ( @@ -63,6 +65,31 @@ export const GenerateColumn = ( return (field.lookups || []).find((i) => i.value === value)?.text || value; }; break; + case '引用型': + props.dataType = 'string'; + props.width = 150; + props.allowFiltering = false; + cellRender.render = (data: any) => { + const arrData = jsonParse(data.value, data.value); + const lookups = field.lookups?.filter((item) => arrData.includes(item.value)); + if (lookups) { + return lookups.map((lookup: FiledLookup, i: number) => { + return ( + + ); + }); + } + return ''; + }; + break; case '数值型': props.dataType = 'number'; props.width = 150; diff --git a/src/executor/tools/task/start/default.tsx b/src/executor/tools/task/start/default.tsx index ea7d6543c..3885b968a 100644 --- a/src/executor/tools/task/start/default.tsx +++ b/src/executor/tools/task/start/default.tsx @@ -101,6 +101,7 @@ const DefaultWayStart: React.FC = ({ allowEdit belong={apply.belong} data={apply.instanceData} + target={target} nodeId={apply.instanceData.node.id} /> {loadGateway(apply)} diff --git a/src/executor/tools/workForm/detail.tsx b/src/executor/tools/workForm/detail.tsx index ea8af345a..563b6cda0 100644 --- a/src/executor/tools/workForm/detail.tsx +++ b/src/executor/tools/workForm/detail.tsx @@ -1,5 +1,5 @@ import { model, schema } from '../../../ts/base'; -import { IBelong } from '@/ts/core'; +import { IBelong, ITarget } from '@/ts/core'; import { useEffect, useState } from 'react'; import React from 'react'; import { Tabs } from 'antd'; @@ -17,6 +17,7 @@ interface IProps { data: model.InstanceDataModel; getFormData: (form: schema.XForm) => model.FormEditData; onChanged?: (id: string, data: model.FormEditData, field: string, value: any) => void; + target?: ITarget; } const DetailTable: React.FC = (props) => { @@ -94,6 +95,7 @@ const DetailTable: React.FC = (props) => { }; } }; + console.log(formData.after); return ( = (props) => { form: form, fields: fields, belong: props.belong, + target: props.target, create: true, onSave: (values) => { + console.log(values); formData.after.push(values); setFormData({ ...formData }); }, diff --git a/src/executor/tools/workForm/index.tsx b/src/executor/tools/workForm/index.tsx index 8f001acaa..f6f3f8f13 100644 --- a/src/executor/tools/workForm/index.tsx +++ b/src/executor/tools/workForm/index.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { common, model, schema } from '../../../ts/base'; -import { IBelong } from '@/ts/core'; +import { IBelong, ITarget } from '@/ts/core'; import PrimaryForms from './primary'; import DetailForms from './detail'; import { formatDate } from '@/utils'; @@ -13,6 +13,7 @@ interface IWorkFormProps { belong: IBelong; nodeId: string; data: model.InstanceDataModel; + target?: ITarget; } /** 流程节点表单 */ @@ -217,7 +218,6 @@ const WorkForm: React.FC = (props) => { setChangedFields(refreshFields); } }; - return (
{node.primaryForms && node.primaryForms.length > 0 && ( diff --git a/src/executor/tools/workForm/primary.tsx b/src/executor/tools/workForm/primary.tsx index 26295f157..79dcf1c40 100644 --- a/src/executor/tools/workForm/primary.tsx +++ b/src/executor/tools/workForm/primary.tsx @@ -1,5 +1,5 @@ import { kernel, model, schema } from '../../../ts/base'; -import { IBelong } from '@/ts/core'; +import { IBelong, ITarget } from '@/ts/core'; import { useState } from 'react'; import React from 'react'; import { Tabs } from 'antd'; @@ -15,6 +15,7 @@ interface IProps { data: model.InstanceDataModel; getFormData: (form: schema.XForm) => model.FormEditData; onChanged?: (id: string, data: model.FormEditData, field: string, value: any) => void; + target?: ITarget; } const PrimaryForm: React.FC = (props) => { diff --git a/src/utils/tools.ts b/src/utils/tools.ts index d04612b5f..77684e60a 100644 --- a/src/utils/tools.ts +++ b/src/utils/tools.ts @@ -362,7 +362,7 @@ const loadGatewayNodes = ( return memberNodes; }; -const jsonParse = (val: any, defaultVal = null) => { +const jsonParse = (val: any, defaultVal: any = null) => { if (!val || typeof val !== 'string') { // console.warn('JSON.parse need string param'); return defaultVal; -- Gitee From 55793fd66949d6adfa1f1ee1c96481d734e15199 Mon Sep 17 00:00:00 2001 From: SEN Date: Mon, 29 Jan 2024 17:45:32 +0800 Subject: [PATCH 06/35] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/GlobalComps/typeIcon.tsx | 2 +- src/config/column.tsx | 4 +- src/executor/action.tsx | 7 ++- src/pages/Store/index.tsx | 4 +- src/ts/base/model.ts | 14 +++++ src/ts/core/public/consts.ts | 57 +++++++++++++++++- src/ts/core/public/enums.ts | 20 +++++++ src/ts/core/public/operates.ts | 6 ++ src/ts/core/target/outTeam/storage.ts | 58 ++++++++++++++++++- src/ts/core/target/team/company.ts | 6 +- src/ts/core/thing/directory.ts | 5 +- 11 files changed, 171 insertions(+), 12 deletions(-) diff --git a/src/components/Common/GlobalComps/typeIcon.tsx b/src/components/Common/GlobalComps/typeIcon.tsx index 7e1e3165e..483f191f4 100644 --- a/src/components/Common/GlobalComps/typeIcon.tsx +++ b/src/components/Common/GlobalComps/typeIcon.tsx @@ -41,7 +41,7 @@ const TypeIcon = ({ avatar, iconType, size }: TypeIconInfo) => { case '动态': return ; case '目录': - return ; + return ; case '成员目录': return ; case '标准': diff --git a/src/config/column.tsx b/src/config/column.tsx index c7d1e45ac..43aab0452 100644 --- a/src/config/column.tsx +++ b/src/config/column.tsx @@ -150,7 +150,7 @@ export const FullEntityColumns = (fields: model.FieldModel[]) => { remark: '由系统生成的唯一标记,无实义.', options: { fixed: true, - visible: false, + visible: true, }, }, { @@ -160,7 +160,7 @@ export const FullEntityColumns = (fields: model.FieldModel[]) => { valueType: '描述型', remark: '描述信息', options: { - visible: false, + visible: true, }, }, { diff --git a/src/executor/action.tsx b/src/executor/action.tsx index a0124c4c5..b5073e953 100644 --- a/src/executor/action.tsx +++ b/src/executor/action.tsx @@ -71,6 +71,8 @@ export const executeCmd = (cmd: string, entity: any) => { return onlineChanged(cmd, entity); case 'activate': return activateStorage(entity); + case 'checkStorage': + return checkStorage(entity); case 'hslSplit': return videoHslSplit(entity); case 'removeSession': @@ -98,7 +100,10 @@ const directoryRefresh = (dir: IDirectory | IApplication, reload: boolean) => { const activateStorage = (store: IStorage) => { store.activateStorage(); }; - +/** 初始化存储 */ +const checkStorage = (store: IStorage) => { + store.checkStorage(); +}; /** 视频切片 */ const videoHslSplit = (file: ISysFileInfo) => { const modal = Modal.confirm({ diff --git a/src/pages/Store/index.tsx b/src/pages/Store/index.tsx index 63399d64b..14c7aeb03 100644 --- a/src/pages/Store/index.tsx +++ b/src/pages/Store/index.tsx @@ -51,7 +51,7 @@ const FileBrowser: React.FC = () => { if (current === 'disk') { contents.push(orgCtrl.user, ...orgCtrl.user.companys); } else { - contents.push(...current.content()); + contents.push(...current.content(true)); } return contents; }; @@ -64,7 +64,7 @@ const FileBrowser: React.FC = () => { type="link" title="返回" icon={} - onClick={() => setCurrent(current.superior as ITarget)} + onClick={() => setCurrent((current.superior as ITarget) ?? 'disk')} /> )} {current != 'disk' ? ( diff --git a/src/ts/base/model.ts b/src/ts/base/model.ts index d036f5723..c5d4fd25b 100644 --- a/src/ts/base/model.ts +++ b/src/ts/base/model.ts @@ -1476,3 +1476,17 @@ export type DraftsType = { // 节点信息 data: model.InstanceDataModel; } & Xbase; + +// 标准目录 +export type StandardDirectoryType = { + // 目录名称 + name: string; + // 目录编码 + code: string; + // 排序 + sort: number; + // 内容支持类型 + accept?: string[]; + // 子级目录 + children?: StandardDirectoryType[]; +}; diff --git a/src/ts/core/public/consts.ts b/src/ts/core/public/consts.ts index a96955143..fcfc8f0c8 100644 --- a/src/ts/core/public/consts.ts +++ b/src/ts/core/public/consts.ts @@ -1,5 +1,5 @@ -import { PageModel } from '../../base/model'; -import { TargetType, ValueType } from './enums'; +import { PageModel, StandardDirectoryType } from '../../base/model'; +import { DirectoryType, TargetType, ValueType } from './enums'; /** 资产共享云模块权限Id */ export const orgAuth = { @@ -47,6 +47,59 @@ export const PageAll: PageModel = { limit: (2 << 15) - 1, //ushort.max filter: '', }; +/** 固定标准目录 */ +export const StandardDirectory: StandardDirectoryType[] = [ + { + name: DirectoryType.DataStandard, + code: 'standardData', + sort: 1, + accept: [DirectoryType.Attribute, DirectoryType.Dict, DirectoryType.Species], + children: [ + { + name: DirectoryType.Attribute, + code: 'standardAttribute', + sort: 1, + }, + { + name: DirectoryType.Dict, + code: 'standardDict', + sort: 2, + }, + { name: DirectoryType.Species, code: 'standardSpecies', sort: 3 }, + ], + }, + { + name: DirectoryType.Model, + code: 'standardModel', + sort: 2, + children: [ + { + name: DirectoryType.Form, + code: 'standardForm', + sort: 1, + }, + { + name: DirectoryType.Report, + code: 'standardReport', + sort: 2, + }, + { + name: DirectoryType.Transfer, + code: 'standardTransfer', + sort: 3, + }, + { + name: DirectoryType.PageTemplate, + code: 'standardPageTemplate', + sort: 4, + }, + ], + }, + { name: DirectoryType.App, code: 'standardApp', sort: 3 }, + { name: DirectoryType.File, code: 'standardFile', sort: 4 }, + { name: DirectoryType.Code, code: 'standardCode', sort: 5 }, + { name: DirectoryType.Mirror, code: 'standardMirror', sort: 6 }, +]; /** 通用状态信息Map */ export const StatusMap = new Map([ diff --git a/src/ts/core/public/enums.ts b/src/ts/core/public/enums.ts index bebd476bf..7624ba88c 100644 --- a/src/ts/core/public/enums.ts +++ b/src/ts/core/public/enums.ts @@ -89,3 +89,23 @@ export enum FromOrigin { 'Person' = 'Person', 'Group' = 'Group', } + +/** 文件类型 */ +export enum DirectoryType { + /* 一级类目 */ + 'Storage' = '存储资源', + 'DataStandard' = '数据标准', + 'Model' = '业务模型', + 'App' = '应用', + 'File' = '文件', + 'Code' = '代码', + 'Mirror' = '镜像', + /* 二级类目 */ + 'Attribute' = '属性', + 'Species' = '分类', + 'Dict' = '字典', + 'Form' = '表单', + 'Report' = '报表', + 'PageTemplate' = '模板', + 'Transfer' = '迁移', +} diff --git a/src/ts/core/public/operates.ts b/src/ts/core/public/operates.ts index 5627e1c4f..756321654 100644 --- a/src/ts/core/public/operates.ts +++ b/src/ts/core/public/operates.ts @@ -48,6 +48,12 @@ export const entityOperates = { label: '分享二维码', iconType: 'qrcode', }, + InitStorage: { + sort: 102, + cmd: 'checkStorage', + label: '校验文件夹', + iconType: 'update', + }, }; /** 文件支持的操作 */ export const fileOperates = { diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index 391aba461..82b8c3aff 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -1,9 +1,12 @@ -import { OperateModel } from '@/ts/base/model'; +import { IDirectory } from '@/ts/core'; +import { OperateModel, StandardDirectoryType } from '@/ts/base/model'; import { kernel, schema } from '../../../base'; import { OperateType, TargetType, entityOperates, targetOperates } from '../../public'; import { IBelong } from '../base/belong'; import { ITarget, Target } from '../base/target'; import { ISession } from '../../chat/session'; +import { IFile } from '../../thing/fileinfo'; +import { StandardDirectory } from '../../public/consts'; /** 存储资源接口 */ export interface IStorage extends ITarget { @@ -11,6 +14,8 @@ export interface IStorage extends ITarget { isActivate: boolean; /** 激活存储 */ activateStorage(): Promise; + /** 初始化存储 */ + checkStorage(): Promise; } export class Storage extends Target implements IStorage { @@ -42,7 +47,11 @@ export class Storage extends Target implements IStorage { return success; } override operates(): OperateModel[] { - const operates = [entityOperates.Remark, entityOperates.QrCode]; + const operates = [ + entityOperates.Remark, + entityOperates.QrCode, + entityOperates.InitStorage, + ]; if (this.hasRelationAuth()) { operates.unshift(entityOperates.Update, entityOperates.HardDelete); } @@ -72,11 +81,16 @@ export class Storage extends Target implements IStorage { if (res.success) { this.space.updateMetadata(res.data); this.space.sendTargetNotity(OperateType.Update); + this.checkDirectory(); } return res.success; } return false; } + async checkStorage() { + this.checkDirectory(); + return true; + } async deepLoad(reload: boolean = false): Promise { if (this.hasRelationAuth()) { await this.loadIdentitys(reload); @@ -84,6 +98,10 @@ export class Storage extends Target implements IStorage { } this.directory.loadDirectoryResource(reload); } + content(): IFile[] { + return this.space.directory.children; + } + override async pullMembers( members: schema.XTarget[], notity?: boolean, @@ -93,4 +111,40 @@ export class Storage extends Target implements IStorage { } return await super.pullMembers(members, notity); } + async checkDirectory() { + await this.space.directory.loadContent(true); + this.space.directory.standard.loadDirectorys(true).then((dirs) => { + console.log('检测文件系统', dirs); + if (dirs.length < 6) { + this.creatStandardDirectory(this.space.directory, StandardDirectory); + } + }); + } + async creatStandardDirectory(directory: IDirectory, tasks: StandardDirectoryType[]) { + for (let i = 0; i < tasks.length; i++) { + const dirItem = tasks[i]; + //若 已存在目标文件夹,禁止创建 + if (!directory.children.find((child) => child.code === dirItem.code)) { + const params = { + name: dirItem.name, + code: dirItem.code, + sort: dirItem.sort, + accept: dirItem.accept ?? [dirItem.name], + typeName: '目录', + directoryId: directory.id, + } as unknown as schema.XDirectory; + directory.create(params).then((res) => { + console.log('创建文件:', dirItem.name); + if (dirItem.children && dirItem.children.length > 0 && res?.id) { + setTimeout(() => { + const _dir = directory.children.find((child) => child.id === res.id); + _dir && this.creatStandardDirectory(_dir, dirItem.children!); + }, 300); + } + }); + } else { + console.warn('跳过创建,已存在文件夹:', dirItem.name); + } + } + } } diff --git a/src/ts/core/target/team/company.ts b/src/ts/core/target/team/company.ts index b072a792f..17942f4c8 100644 --- a/src/ts/core/target/team/company.ts +++ b/src/ts/core/target/team/company.ts @@ -249,7 +249,11 @@ export class Company extends Belong implements ICompany { return operates; } - content(): IFile[] { + content(isStore?: boolean): IFile[] { + if (isStore) { + return this.storages.filter((i) => i.isMyTeam); + } + return [ ...this.groups, ...this.departments, diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 0a8fd813c..af3b09178 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -237,7 +237,10 @@ export class Directory extends StandardFileInfo implements ID } return this.files; } - async createFile(file: Blob, p?: OnProgress): Promise { + async createFile( + file: Blob & { name: string }, + p?: OnProgress, + ): Promise { while (this.taskList.filter((i) => i.finished < i.size).length > 2) { await sleep(1000); } -- Gitee From 1bafcc10197d32a1a8b5afe2bbefcb75da65ab08 Mon Sep 17 00:00:00 2001 From: SEN Date: Mon, 29 Jan 2024 18:32:50 +0800 Subject: [PATCH 07/35] =?UTF-8?q?feat:=20=E5=8E=BB=E9=99=A4=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E5=8C=BA=20=E5=B1=95=E7=A4=BA=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/SegmentContent/index.tsx | 80 ++++++++++--------- src/components/Directory/views/index.tsx | 2 + src/pages/Store/index.tsx | 1 + 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/components/Common/SegmentContent/index.tsx b/src/components/Common/SegmentContent/index.tsx index 2573bf8f3..d0655047d 100644 --- a/src/components/Common/SegmentContent/index.tsx +++ b/src/components/Common/SegmentContent/index.tsx @@ -10,6 +10,7 @@ type segmentedTypes = 'icon' | 'table' | 'list'; interface IProps { height?: number | string; descriptions: string; + hiddenSegment?: Boolean; children?: React.ReactNode; // 子组件 onSegmentChanged: (type: segmentedTypes) => void; } @@ -20,6 +21,7 @@ const SegmentContent: React.FC = ({ height, children, descriptions, + hiddenSegment, onSegmentChanged, }: IProps) => { const [segmented, setSegmented] = useStorage('segmented', 'list'); @@ -30,44 +32,46 @@ const SegmentContent: React.FC = ({
{children && children}
- - { - setSegmented(value as segmentedTypes); - onSegmentChanged(value as segmentedTypes); - }} - options={[ - { - value: 'list', - icon: ( - - ), - }, - { - value: 'icon', - icon: ( - - ), - }, - // { - // value: 'table', - // icon: ( - // - // ), - // }, - ]} - /> - + {!hiddenSegment && ( + + { + setSegmented(value as segmentedTypes); + onSegmentChanged(value as segmentedTypes); + }} + options={[ + { + value: 'list', + icon: ( + + ), + }, + { + value: 'icon', + icon: ( + + ), + }, + // { + // value: 'table', + // icon: ( + // + // ), + // }, + ]} + /> + + )} }> {descriptions} diff --git a/src/components/Directory/views/index.tsx b/src/components/Directory/views/index.tsx index 841b46c28..71494f442 100644 --- a/src/components/Directory/views/index.tsx +++ b/src/components/Directory/views/index.tsx @@ -21,6 +21,7 @@ interface IProps { focusFile?: IDEntity; rightBars?: ReactNode; height?: number | string; + hiddenSegment?: boolean; currentTag: string; badgeCount?: (tag: string) => number; tagChanged?: (tag: string) => void; @@ -114,6 +115,7 @@ const DirectoryView: React.FC = (props) => { onChanged={(t) => props.tagChanged && props.tagChanged(t)}> {segmented === 'icon' ? ( diff --git a/src/pages/Store/index.tsx b/src/pages/Store/index.tsx index 14c7aeb03..8703adfca 100644 --- a/src/pages/Store/index.tsx +++ b/src/pages/Store/index.tsx @@ -90,6 +90,7 @@ const FileBrowser: React.FC = () => { initTags={['全部']} selectFiles={[]} extraTags={true} + hiddenSegment focusFile={focusFile} content={getContent()} currentTag={currentTag} -- Gitee From cf5c4263e05e9646c7c13064cc286c012ade1788 Mon Sep 17 00:00:00 2001 From: SEN Date: Mon, 29 Jan 2024 18:33:06 +0800 Subject: [PATCH 08/35] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E6=94=AF=E6=8C=81=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/base/schema.ts | 2 ++ src/ts/core/thing/directory.ts | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/ts/base/schema.ts b/src/ts/base/schema.ts index d4cee3fca..8587e4206 100644 --- a/src/ts/base/schema.ts +++ b/src/ts/base/schema.ts @@ -171,6 +171,8 @@ export type XAuthority = { export type XDirectory = { // 共享用户ID shareId: string; + // 目录支持类型 + accept?: string[]; // 目录下的属性 propertys: XProperty[] | undefined; // 目录下的单 diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index af3b09178..ed73f6e3f 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -1,3 +1,4 @@ +import { DirectoryType } from './../public/enums'; import { common, model, schema } from '../../base'; import { directoryNew, directoryOperates, entityOperates, fileOperates } from '../public'; import { ITarget } from '../target/base/target'; @@ -19,6 +20,8 @@ export interface IDirectory extends IStandardFileInfo { directoryId: string; /** 目录下标准类 */ standard: StandardFiles; + /** 目录下支持的标准类 */ + accept: DirectoryType[]; /** 当前加载目录的用户 */ target: ITarget; /** 资源类 */ @@ -75,10 +78,12 @@ export class Directory extends StandardFileInfo implements ID _parent ?? (_target as unknown as IDirectory), _target.resource.directoryColl, ); + this.accept = (_metadata.accept as DirectoryType[]) ?? []; this.parent = _parent; this.taskEmitter = new common.Emitter(); this.standard = new StandardFiles(this); } + accept: DirectoryType[]; standard: StandardFiles; taskEmitter: common.Emitter; parent: IDirectory | undefined; @@ -128,6 +133,8 @@ export class Directory extends StandardFileInfo implements ID return this.target.resource; } content(store: boolean = false): IFile[] { + console.log("storecontent",store); + const cnt: IFile[] = [...this.children]; if (this.target.session.isMyChat || this.target.hasRelationAuth()) { cnt.push(...this.files); -- Gitee From a167b470ed0c7f211bb019700151606e97d98efe Mon Sep 17 00:00:00 2001 From: SEN Date: Mon, 29 Jan 2024 18:52:01 +0800 Subject: [PATCH 09/35] =?UTF-8?q?feat:=20=E5=85=B3=E7=B3=BB=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=20=E7=A6=81=E6=AD=A2=E6=B7=B1=E5=85=A5=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E5=B1=82=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/core/target/outTeam/storage.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index 82b8c3aff..786e0b695 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -98,8 +98,8 @@ export class Storage extends Target implements IStorage { } this.directory.loadDirectoryResource(reload); } - content(): IFile[] { - return this.space.directory.children; + content(srore?: boolean): IFile[] { + return srore ? this.space.directory.children : []; } override async pullMembers( -- Gitee From c100ff7a11b2c4cda92f4aea47fce537792ed9eb Mon Sep 17 00:00:00 2001 From: SEN Date: Mon, 29 Jan 2024 18:55:41 +0800 Subject: [PATCH 10/35] =?UTF-8?q?feat:=20=E7=9B=AE=E5=BD=95=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/core/public/consts.ts | 6 ++++++ src/ts/core/thing/directory.ts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ts/core/public/consts.ts b/src/ts/core/public/consts.ts index fcfc8f0c8..7d924cdb6 100644 --- a/src/ts/core/public/consts.ts +++ b/src/ts/core/public/consts.ts @@ -72,6 +72,12 @@ export const StandardDirectory: StandardDirectoryType[] = [ name: DirectoryType.Model, code: 'standardModel', sort: 2, + accept: [ + DirectoryType.Form, + DirectoryType.Report, + DirectoryType.Transfer, + DirectoryType.PageTemplate, + ], children: [ { name: DirectoryType.Form, diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index ed73f6e3f..713a2c32b 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -133,7 +133,7 @@ export class Directory extends StandardFileInfo implements ID return this.target.resource; } content(store: boolean = false): IFile[] { - console.log("storecontent",store); + console.log('storecontent', store, this.accept); const cnt: IFile[] = [...this.children]; if (this.target.session.isMyChat || this.target.hasRelationAuth()) { -- Gitee From 1d47f8eb6aee46015d6a13909ce67d4736b0e0a4 Mon Sep 17 00:00:00 2001 From: SEN Date: Mon, 29 Jan 2024 19:14:16 +0800 Subject: [PATCH 11/35] =?UTF-8?q?feat:=20=E7=9B=AE=E5=BD=95=E6=8E=92?= =?UTF-8?q?=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/base/schema.ts | 2 ++ src/ts/core/target/outTeam/storage.ts | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ts/base/schema.ts b/src/ts/base/schema.ts index 8587e4206..dce1dc21e 100644 --- a/src/ts/base/schema.ts +++ b/src/ts/base/schema.ts @@ -173,6 +173,8 @@ export type XDirectory = { shareId: string; // 目录支持类型 accept?: string[]; + // 目录排序标识 + sort?: number; // 目录下的属性 propertys: XProperty[] | undefined; // 目录下的单 diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index 786e0b695..131e028fb 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -99,7 +99,12 @@ export class Storage extends Target implements IStorage { this.directory.loadDirectoryResource(reload); } content(srore?: boolean): IFile[] { - return srore ? this.space.directory.children : []; + const items = this.space.directory.children.sort((a, b) => { + const curr = a.metadata.sort ?? a.metadata.updateTime; + const next = b.metadata.sort ?? b.metadata.updateTime; + return curr > next ? 1 : -1; + }); + return srore ? items : []; } override async pullMembers( @@ -115,9 +120,7 @@ export class Storage extends Target implements IStorage { await this.space.directory.loadContent(true); this.space.directory.standard.loadDirectorys(true).then((dirs) => { console.log('检测文件系统', dirs); - if (dirs.length < 6) { - this.creatStandardDirectory(this.space.directory, StandardDirectory); - } + this.creatStandardDirectory(this.space.directory, StandardDirectory); }); } async creatStandardDirectory(directory: IDirectory, tasks: StandardDirectoryType[]) { -- Gitee From f5b7d6815333c2078829da4f98c111f3c3711636 Mon Sep 17 00:00:00 2001 From: SEN Date: Tue, 30 Jan 2024 13:14:34 +0800 Subject: [PATCH 12/35] =?UTF-8?q?feat:=20=E5=86=85=E5=AE=B9=E5=8C=BA?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E5=8F=8A=E6=93=8D=E4=BD=9C=E5=8C=BA=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Directory/index.tsx | 5 +- src/components/MainLayout/preview/index.tsx | 33 ++++++++++- src/ts/core/public/operates.ts | 47 ++++++++++++++++ src/ts/core/thing/directory.ts | 61 +++++++++++++++++---- 4 files changed, 130 insertions(+), 16 deletions(-) diff --git a/src/components/Directory/index.tsx b/src/components/Directory/index.tsx index d0ed2a515..e27dc0433 100644 --- a/src/components/Directory/index.tsx +++ b/src/components/Directory/index.tsx @@ -9,7 +9,7 @@ import { cleanMenus } from '@/utils/tools'; * @description: 默认目录 * @return {*} */ -const Directory: React.FC<{ root: IFile }> = ({ root }) => { +const Directory: React.FC<{ root: IFile; isStore?: boolean }> = ({ root, isStore }) => { const [currentTag, setCurrentTag] = useState('全部'); const [preDirectory, setPreDirectory] = useState(); const [directory, setDirectory] = useState(root); @@ -35,7 +35,8 @@ const Directory: React.FC<{ root: IFile }> = ({ root }) => { file.loadContent(reload).then(() => { if (file.key === directory.key) { setCurrentTag('全部'); - setContent(directory.content()); + console.log('加载目录内容', isStore); + setContent(directory.content(isStore)); } setLoaded(true); }); diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index 2098b2017..9200c29c2 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -2,6 +2,7 @@ import ImageView from './image'; import VideoView from './video'; import { IEntity, + IFile, IForm, ISession, ISysFileInfo, @@ -56,6 +57,7 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { const [entity, setEntity] = useState(); useEffect(() => { const id = command.subscribe((type, flag, ...args: any[]) => { + console.log('实体预览subscribe', type, flag, ...args); if (type != 'preview' || flag != props.flag) return; if (args && args.length > 0) { setEntity(args[0]); @@ -68,8 +70,12 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { }; }, [props]); - const renderEntityBody = (entity: any, children?: React.ReactNode) => { - return {children && children}; + const renderEntityBody = (entity: any, children?: React.ReactNode, actions?: any[]) => { + return ( + + {children && children} + + ); }; if (entity && typeof entity != 'string') { @@ -126,6 +132,29 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { return ; } } + //数据查看 + if (location.hash.startsWith('#/store')) { + console.log('打印数据选择内容', entity); + return renderEntityBody( + entity, + , + [ + { + key: 'activity', + label: '动态', + }, + { + key: 'store', + label: '数据', + }, + { + key: 'relation', + label: '关系', + }, + ], + ); + } + return renderEntityBody(entity); } return <>; diff --git a/src/ts/core/public/operates.ts b/src/ts/core/public/operates.ts index 756321654..39733d54c 100644 --- a/src/ts/core/public/operates.ts +++ b/src/ts/core/public/operates.ts @@ -1,3 +1,4 @@ +import { DirectoryType } from './enums'; /** 实体的操作 */ export const entityOperates = { Open: { @@ -230,6 +231,52 @@ export const directoryNew = { directoryOperates.NewPageTemplate, ], }; +/** 目录下新增 */ +export const getDirectoryNew = (accept: DirectoryType[]) => { + const menus = [directoryOperates.NewDir]; + // directoryOperates.NewDir, + // directoryOperates.NewDict, + // directoryOperates.NewSpecies, + // directoryOperates.NewProperty, + // directoryOperates.NewApp, + // directoryOperates.NewForm, + // directoryOperates.NewTransferConfig, + // directoryOperates.NewPageTemplate, + for (const item of accept) { + switch (item) { + case DirectoryType.App: + menus.push(directoryOperates.NewApp); + break; + case DirectoryType.Attribute: + menus.push(directoryOperates.NewProperty); + break; + case DirectoryType.Form: + menus.push(directoryOperates.NewForm); + break; + case DirectoryType.Species: + menus.push(directoryOperates.NewSpecies); + break; + case DirectoryType.Dict: + menus.push(directoryOperates.NewDict); + break; + case DirectoryType.Transfer: + menus.push(directoryOperates.NewTransferConfig); + break; + case DirectoryType.PageTemplate: + menus.push(directoryOperates.NewPageTemplate); + break; + default: + break; + } + } + return { + sort: 0, + cmd: 'new', + label: '新建更多', + iconType: 'new', + menus: menus, + }; +}; /** 新建仓库 */ export const newWarehouse = { diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 713a2c32b..853326769 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -1,3 +1,4 @@ +import { getDirectoryNew } from './../public/operates'; import { DirectoryType } from './../public/enums'; import { common, model, schema } from '../../base'; import { directoryNew, directoryOperates, entityOperates, fileOperates } from '../public'; @@ -133,18 +134,53 @@ export class Directory extends StandardFileInfo implements ID return this.target.resource; } content(store: boolean = false): IFile[] { + const cnt: IFile[] = [...this.children]; console.log('storecontent', store, this.accept); - const cnt: IFile[] = [...this.children]; if (this.target.session.isMyChat || this.target.hasRelationAuth()) { - cnt.push(...this.files); - cnt.push(...this.standard.forms); - cnt.push(...this.standard.applications); - cnt.push(...this.standard.propertys); - cnt.push(...this.standard.specieses); - cnt.push(...this.standard.transfers); - cnt.push(...this.standard.templates); + if (store && this.accept.length > 0) { + for (const typeItem of this.accept) { + switch (typeItem) { + case DirectoryType.App: + cnt.push(...this.standard.applications); + break; + case DirectoryType.Species: + cnt.push(...this.standard.specieses); + break; + case DirectoryType.File: + cnt.push(...this.files); + break; + case DirectoryType.Attribute: + cnt.push(...this.standard.propertys); + break; + case DirectoryType.Transfer: + cnt.push(...this.standard.transfers); + break; + case DirectoryType.PageTemplate: + cnt.push(...this.standard.templates); + break; + case DirectoryType.Form: + cnt.push(...this.standard.forms); + break; + case DirectoryType.Report: + // cnt.push(...this.standard.report); + break; + default: + break; + } + } + } else { + cnt.push(...this.children); + cnt.push(...this.files); + cnt.push(...this.standard.forms); + cnt.push(...this.standard.applications); + cnt.push(...this.standard.propertys); + cnt.push(...this.standard.specieses); + cnt.push(...this.standard.transfers); + cnt.push(...this.standard.templates); + } } + console.log('store内容', cnt); return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); } async loadContent(reload: boolean = false): Promise { @@ -318,19 +354,20 @@ export class Directory extends StandardFileInfo implements ID directoryOperates.TaskList, directoryOperates.Refesh, ); + const _directoryNew = getDirectoryNew(this.accept); if (this.target.hasRelationAuth()) { if (this.name.includes('业务')) { operates.push({ - ...directoryNew, + ..._directoryNew, menus: [...directoryNew.menus, directoryOperates.Business], }); } else if (this.name.includes('标准')) { operates.push({ - ...directoryNew, + ..._directoryNew, menus: [...directoryNew.menus, directoryOperates.Standard], }); } else { - operates.push(directoryNew); + operates.push(_directoryNew); } if (this.target.user.copyFiles.size > 0) { operates.push(fileOperates.Parse); @@ -340,7 +377,7 @@ export class Directory extends StandardFileInfo implements ID if (this.target.hasRelationAuth()) { operates.push(directoryOperates.Shortcut); } - operates.push(...super.operates()); + // operates.push(...super.operates()); } else { operates.push(entityOperates.Open); } -- Gitee From 54b3850c003bfd2704756aa9ddaacde7619827a7 Mon Sep 17 00:00:00 2001 From: SEN Date: Tue, 30 Jan 2024 13:23:01 +0800 Subject: [PATCH 13/35] =?UTF-8?q?feat:=20=E8=BF=94=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E9=87=8D=E5=A4=8D=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/core/thing/directory.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 853326769..77a7c87f2 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -170,7 +170,6 @@ export class Directory extends StandardFileInfo implements ID } } } else { - cnt.push(...this.children); cnt.push(...this.files); cnt.push(...this.standard.forms); cnt.push(...this.standard.applications); @@ -181,7 +180,9 @@ export class Directory extends StandardFileInfo implements ID } } console.log('store内容', cnt); - return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); + return this.uniqueBy(cnt, 'id').sort((a, b) => + a.metadata.updateTime < b.metadata.updateTime ? 1 : -1, + ); } async loadContent(reload: boolean = false): Promise { await this.loadFiles(reload); @@ -449,4 +450,18 @@ export class Directory extends StandardFileInfo implements ID directoryId: this.id, }); } + uniqueBy(arr: T[], key: K): T[] { + const result = []; + const map = new Map(); + + for (const item of arr) { + const keyValue = item[key]; + if (!map.has(keyValue)) { + map.set(keyValue, true); + result.push(item); + } + } + + return result; + } } -- Gitee From f3d1a50798a87277842b80b3c156f5a4bdfec396 Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 09:40:49 +0800 Subject: [PATCH 14/35] =?UTF-8?q?style:=20=E4=BF=AE=E6=94=B9=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=96=87=E4=BB=B6icon=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Common/GlobalComps/typeIcon.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Common/GlobalComps/typeIcon.tsx b/src/components/Common/GlobalComps/typeIcon.tsx index 7e1e3165e..483f191f4 100644 --- a/src/components/Common/GlobalComps/typeIcon.tsx +++ b/src/components/Common/GlobalComps/typeIcon.tsx @@ -41,7 +41,7 @@ const TypeIcon = ({ avatar, iconType, size }: TypeIconInfo) => { case '动态': return ; case '目录': - return ; + return ; case '成员目录': return ; case '标准': -- Gitee From 9145f12b6cea83f7f573a0cd3aad8fae234887b1 Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 09:43:56 +0800 Subject: [PATCH 15/35] =?UTF-8?q?fix:=20=E9=9A=90=E8=97=8F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=20=E5=AF=BC=E8=88=AA=E5=8C=BA=E5=9F=9F=E5=BA=95?= =?UTF-8?q?=E9=83=A8icon=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/SegmentContent/index.tsx | 80 ++++++++++--------- src/components/Directory/views/index.tsx | 2 + 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/components/Common/SegmentContent/index.tsx b/src/components/Common/SegmentContent/index.tsx index 2573bf8f3..d0655047d 100644 --- a/src/components/Common/SegmentContent/index.tsx +++ b/src/components/Common/SegmentContent/index.tsx @@ -10,6 +10,7 @@ type segmentedTypes = 'icon' | 'table' | 'list'; interface IProps { height?: number | string; descriptions: string; + hiddenSegment?: Boolean; children?: React.ReactNode; // 子组件 onSegmentChanged: (type: segmentedTypes) => void; } @@ -20,6 +21,7 @@ const SegmentContent: React.FC = ({ height, children, descriptions, + hiddenSegment, onSegmentChanged, }: IProps) => { const [segmented, setSegmented] = useStorage('segmented', 'list'); @@ -30,44 +32,46 @@ const SegmentContent: React.FC = ({
{children && children}
- - { - setSegmented(value as segmentedTypes); - onSegmentChanged(value as segmentedTypes); - }} - options={[ - { - value: 'list', - icon: ( - - ), - }, - { - value: 'icon', - icon: ( - - ), - }, - // { - // value: 'table', - // icon: ( - // - // ), - // }, - ]} - /> - + {!hiddenSegment && ( + + { + setSegmented(value as segmentedTypes); + onSegmentChanged(value as segmentedTypes); + }} + options={[ + { + value: 'list', + icon: ( + + ), + }, + { + value: 'icon', + icon: ( + + ), + }, + // { + // value: 'table', + // icon: ( + // + // ), + // }, + ]} + /> + + )} }> {descriptions} diff --git a/src/components/Directory/views/index.tsx b/src/components/Directory/views/index.tsx index 841b46c28..71494f442 100644 --- a/src/components/Directory/views/index.tsx +++ b/src/components/Directory/views/index.tsx @@ -21,6 +21,7 @@ interface IProps { focusFile?: IDEntity; rightBars?: ReactNode; height?: number | string; + hiddenSegment?: boolean; currentTag: string; badgeCount?: (tag: string) => number; tagChanged?: (tag: string) => void; @@ -114,6 +115,7 @@ const DirectoryView: React.FC = (props) => { onChanged={(t) => props.tagChanged && props.tagChanged(t)}> {segmented === 'icon' ? ( -- Gitee From 0a3ede0dac6f2bfc43dc1c74d434bb6b6fa5e3ee Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 09:44:49 +0800 Subject: [PATCH 16/35] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=A0=87?= =?UTF-8?q?=E5=87=86=E6=96=87=E4=BB=B6=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/core/public/consts.ts | 63 ++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/src/ts/core/public/consts.ts b/src/ts/core/public/consts.ts index a96955143..7d924cdb6 100644 --- a/src/ts/core/public/consts.ts +++ b/src/ts/core/public/consts.ts @@ -1,5 +1,5 @@ -import { PageModel } from '../../base/model'; -import { TargetType, ValueType } from './enums'; +import { PageModel, StandardDirectoryType } from '../../base/model'; +import { DirectoryType, TargetType, ValueType } from './enums'; /** 资产共享云模块权限Id */ export const orgAuth = { @@ -47,6 +47,65 @@ export const PageAll: PageModel = { limit: (2 << 15) - 1, //ushort.max filter: '', }; +/** 固定标准目录 */ +export const StandardDirectory: StandardDirectoryType[] = [ + { + name: DirectoryType.DataStandard, + code: 'standardData', + sort: 1, + accept: [DirectoryType.Attribute, DirectoryType.Dict, DirectoryType.Species], + children: [ + { + name: DirectoryType.Attribute, + code: 'standardAttribute', + sort: 1, + }, + { + name: DirectoryType.Dict, + code: 'standardDict', + sort: 2, + }, + { name: DirectoryType.Species, code: 'standardSpecies', sort: 3 }, + ], + }, + { + name: DirectoryType.Model, + code: 'standardModel', + sort: 2, + accept: [ + DirectoryType.Form, + DirectoryType.Report, + DirectoryType.Transfer, + DirectoryType.PageTemplate, + ], + children: [ + { + name: DirectoryType.Form, + code: 'standardForm', + sort: 1, + }, + { + name: DirectoryType.Report, + code: 'standardReport', + sort: 2, + }, + { + name: DirectoryType.Transfer, + code: 'standardTransfer', + sort: 3, + }, + { + name: DirectoryType.PageTemplate, + code: 'standardPageTemplate', + sort: 4, + }, + ], + }, + { name: DirectoryType.App, code: 'standardApp', sort: 3 }, + { name: DirectoryType.File, code: 'standardFile', sort: 4 }, + { name: DirectoryType.Code, code: 'standardCode', sort: 5 }, + { name: DirectoryType.Mirror, code: 'standardMirror', sort: 6 }, +]; /** 通用状态信息Map */ export const StatusMap = new Map([ -- Gitee From 46e92ae8d4200bce6db2ff6fa4bf1a81340f0a61 Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 13:58:08 +0800 Subject: [PATCH 17/35] =?UTF-8?q?feat:=20=E6=A0=87=E5=87=86=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/executor/action.tsx | 7 ++- src/ts/core/public/enums.ts | 20 +++++++++ src/ts/core/target/outTeam/storage.ts | 64 ++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/executor/action.tsx b/src/executor/action.tsx index a0124c4c5..82f65dd67 100644 --- a/src/executor/action.tsx +++ b/src/executor/action.tsx @@ -71,6 +71,8 @@ export const executeCmd = (cmd: string, entity: any) => { return onlineChanged(cmd, entity); case 'activate': return activateStorage(entity); + case 'checkDirectory': + return checkDirectory(entity); case 'hslSplit': return videoHslSplit(entity); case 'removeSession': @@ -98,7 +100,10 @@ const directoryRefresh = (dir: IDirectory | IApplication, reload: boolean) => { const activateStorage = (store: IStorage) => { store.activateStorage(); }; - +/** 初始化存储 */ +const checkDirectory = (store: IStorage) => { + store.checkDirectory(); +}; /** 视频切片 */ const videoHslSplit = (file: ISysFileInfo) => { const modal = Modal.confirm({ diff --git a/src/ts/core/public/enums.ts b/src/ts/core/public/enums.ts index bebd476bf..7624ba88c 100644 --- a/src/ts/core/public/enums.ts +++ b/src/ts/core/public/enums.ts @@ -89,3 +89,23 @@ export enum FromOrigin { 'Person' = 'Person', 'Group' = 'Group', } + +/** 文件类型 */ +export enum DirectoryType { + /* 一级类目 */ + 'Storage' = '存储资源', + 'DataStandard' = '数据标准', + 'Model' = '业务模型', + 'App' = '应用', + 'File' = '文件', + 'Code' = '代码', + 'Mirror' = '镜像', + /* 二级类目 */ + 'Attribute' = '属性', + 'Species' = '分类', + 'Dict' = '字典', + 'Form' = '表单', + 'Report' = '报表', + 'PageTemplate' = '模板', + 'Transfer' = '迁移', +} diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index 391aba461..51793b9f5 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -1,9 +1,12 @@ -import { OperateModel } from '@/ts/base/model'; +import { IDirectory } from '@/ts/core'; +import { OperateModel, StandardDirectoryType } from '@/ts/base/model'; import { kernel, schema } from '../../../base'; import { OperateType, TargetType, entityOperates, targetOperates } from '../../public'; import { IBelong } from '../base/belong'; import { ITarget, Target } from '../base/target'; import { ISession } from '../../chat/session'; +import { IFile } from '../../thing/fileinfo'; +import { StandardDirectory } from '../../public/consts'; /** 存储资源接口 */ export interface IStorage extends ITarget { @@ -11,6 +14,8 @@ export interface IStorage extends ITarget { isActivate: boolean; /** 激活存储 */ activateStorage(): Promise; + /** 初始化存储 */ + checkDirectory(): void; } export class Storage extends Target implements IStorage { @@ -42,7 +47,11 @@ export class Storage extends Target implements IStorage { return success; } override operates(): OperateModel[] { - const operates = [entityOperates.Remark, entityOperates.QrCode]; + const operates = [ + entityOperates.Remark, + entityOperates.QrCode, + entityOperates.CheckDirectory, + ]; if (this.hasRelationAuth()) { operates.unshift(entityOperates.Update, entityOperates.HardDelete); } @@ -72,6 +81,7 @@ export class Storage extends Target implements IStorage { if (res.success) { this.space.updateMetadata(res.data); this.space.sendTargetNotity(OperateType.Update); + this.checkDirectory(); } return res.success; } @@ -84,6 +94,16 @@ export class Storage extends Target implements IStorage { } this.directory.loadDirectoryResource(reload); } + content(store?: boolean, isSidebar?: boolean): IFile[] { + console.log('存储展示是否数据展示:', store, '----是否侧边栏:', isSidebar); + const items = this.space.directory.children.sort((a, b) => { + const curr = a.metadata.sort ?? a.metadata.updateTime; + const next = b.metadata.sort ?? b.metadata.updateTime; + return curr > next ? 1 : -1; + }); + return store ? items : []; + } + override async pullMembers( members: schema.XTarget[], notity?: boolean, @@ -93,4 +113,44 @@ export class Storage extends Target implements IStorage { } return await super.pullMembers(members, notity); } + async checkDirectory() { + await this.space.directory.loadContent(true); + await this.space.directory.standard.loadDirectorys(true); + this.creatStandardDirectory(this.space.directory, StandardDirectory); + } + async creatStandardDirectory( + directory: IDirectory, + standardDirectorys: StandardDirectoryType[], + ) { + if (standardDirectorys.length > 0) { + for (const dirItem of standardDirectorys) { + //若 已存在目标文件夹,禁止创建 + if (!directory.children.find((child) => child.code === dirItem.code)) { + const params = { + name: dirItem.name, + code: dirItem.code, + sort: dirItem.sort, + accept: dirItem.accept ?? [dirItem.name], + typeName: '目录', + directoryId: directory.id, + } as schema.XDirectory; + directory.create(params).then((res) => { + console.log('创建文件:', dirItem.name); + if (dirItem.children && dirItem.children.length > 0 && res?.id) { + setTimeout(() => { + const newDirectory = directory.children.find( + (child) => child.id === res.id, + ); + if (newDirectory) { + this.creatStandardDirectory(newDirectory, dirItem.children!); + } + }, 300); + } + }); + } else { + console.warn('跳过创建,已存在文件夹:', dirItem.name); + } + } + } + } } -- Gitee From da17db9d701e9b4eedc5901471e2eb1112b46c25 Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 13:58:42 +0800 Subject: [PATCH 18/35] =?UTF-8?q?feat:=20=E7=9B=AE=E5=BD=95=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/base/model.ts | 30 ++++++++++++++++++++++++++++++ src/ts/base/schema.ts | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/src/ts/base/model.ts b/src/ts/base/model.ts index 07ebf3d85..f1defc45c 100644 --- a/src/ts/base/model.ts +++ b/src/ts/base/model.ts @@ -1496,3 +1496,33 @@ export type DiskInfoType = { // 查询时间 getTime: string; }; + +// 草稿 +export type DraftsType = { + // 数据 + typeName: string; + // 关系 + relations: string; + // 办事id + workId: string; + // 备注信息 + contentText: string; + // 办事名称 + name?: string; + // 节点信息 + data: model.InstanceDataModel; +} & Xbase; + +// 标准目录 +export type StandardDirectoryType = { + // 目录名称 + name: string; + // 目录编码 + code: string; + // 排序 + sort: number; + // 内容支持类型 + accept?: string[]; + // 子级目录 + children?: StandardDirectoryType[]; +}; diff --git a/src/ts/base/schema.ts b/src/ts/base/schema.ts index 60809f163..739a9822f 100644 --- a/src/ts/base/schema.ts +++ b/src/ts/base/schema.ts @@ -177,6 +177,10 @@ export type XAuthority = { export type XDirectory = { // 共享用户ID shareId: string; + // 目录支持类型 + accept?: string[]; + // 目录排序标识 + sort?: number; // 目录下的属性 propertys: XProperty[] | undefined; // 目录下的单 -- Gitee From 153c6547175539b4797b541bfbe79259c72b3608 Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 14:00:08 +0800 Subject: [PATCH 19/35] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=20=E5=B1=95=E7=A4=BA=E8=B0=83=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Directory/index.tsx | 8 +- src/components/MainLayout/preview/index.tsx | 32 ++++++- src/pages/Store/index.tsx | 5 +- src/ts/core/public/operates.ts | 53 ++++++++++++ src/ts/core/target/team/company.ts | 6 +- src/ts/core/thing/directory.ts | 95 +++++++++++++++++---- src/ts/core/thing/fileinfo.ts | 2 +- src/ts/core/thing/standard/index.ts | 44 ++++++++-- 8 files changed, 212 insertions(+), 33 deletions(-) diff --git a/src/components/Directory/index.tsx b/src/components/Directory/index.tsx index d0ed2a515..afcffcdf2 100644 --- a/src/components/Directory/index.tsx +++ b/src/components/Directory/index.tsx @@ -9,7 +9,11 @@ import { cleanMenus } from '@/utils/tools'; * @description: 默认目录 * @return {*} */ -const Directory: React.FC<{ root: IFile }> = ({ root }) => { +const Directory: React.FC<{ + root: IFile; + isStore?: boolean; + isSidebar?: boolean; +}> = ({ root, isStore, isSidebar }) => { const [currentTag, setCurrentTag] = useState('全部'); const [preDirectory, setPreDirectory] = useState(); const [directory, setDirectory] = useState(root); @@ -35,7 +39,7 @@ const Directory: React.FC<{ root: IFile }> = ({ root }) => { file.loadContent(reload).then(() => { if (file.key === directory.key) { setCurrentTag('全部'); - setContent(directory.content()); + setContent(directory.content(isStore, isSidebar)); } setLoaded(true); }); diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index 2098b2017..692658f3f 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -2,6 +2,7 @@ import ImageView from './image'; import VideoView from './video'; import { IEntity, + IFile, IForm, ISession, ISysFileInfo, @@ -68,8 +69,12 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { }; }, [props]); - const renderEntityBody = (entity: any, children?: React.ReactNode) => { - return {children && children}; + const renderEntityBody = (entity: any, children?: React.ReactNode, actions?: any[]) => { + return ( + + {children && children} + + ); }; if (entity && typeof entity != 'string') { @@ -126,6 +131,29 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { return ; } } + //数据查看 + if (location.hash.startsWith('#/store')) { + console.log('数据查看选择内容', entity); + return renderEntityBody( + entity, + , + [ + { + key: 'activity', + label: '动态', + }, + { + key: 'store', + label: '数据', + }, + { + key: 'relation', + label: '关系', + }, + ], + ); + } + return renderEntityBody(entity); } return <>; diff --git a/src/pages/Store/index.tsx b/src/pages/Store/index.tsx index 63399d64b..8703adfca 100644 --- a/src/pages/Store/index.tsx +++ b/src/pages/Store/index.tsx @@ -51,7 +51,7 @@ const FileBrowser: React.FC = () => { if (current === 'disk') { contents.push(orgCtrl.user, ...orgCtrl.user.companys); } else { - contents.push(...current.content()); + contents.push(...current.content(true)); } return contents; }; @@ -64,7 +64,7 @@ const FileBrowser: React.FC = () => { type="link" title="返回" icon={} - onClick={() => setCurrent(current.superior as ITarget)} + onClick={() => setCurrent((current.superior as ITarget) ?? 'disk')} /> )} {current != 'disk' ? ( @@ -90,6 +90,7 @@ const FileBrowser: React.FC = () => { initTags={['全部']} selectFiles={[]} extraTags={true} + hiddenSegment focusFile={focusFile} content={getContent()} currentTag={currentTag} diff --git a/src/ts/core/public/operates.ts b/src/ts/core/public/operates.ts index 5627e1c4f..e977fe0af 100644 --- a/src/ts/core/public/operates.ts +++ b/src/ts/core/public/operates.ts @@ -1,3 +1,4 @@ +import { DirectoryType } from './enums'; /** 实体的操作 */ export const entityOperates = { Open: { @@ -48,6 +49,12 @@ export const entityOperates = { label: '分享二维码', iconType: 'qrcode', }, + CheckDirectory: { + sort: 102, + cmd: 'checkDirectory', + label: '校验文件夹', + iconType: 'update', + }, }; /** 文件支持的操作 */ export const fileOperates = { @@ -224,6 +231,52 @@ export const directoryNew = { directoryOperates.NewPageTemplate, ], }; +/** 目录下新增 */ +export const getDirectoryNew = (accept: DirectoryType[]) => { + const menus = [directoryOperates.NewDir]; + // directoryOperates.NewDir, + // directoryOperates.NewDict, + // directoryOperates.NewSpecies, + // directoryOperates.NewProperty, + // directoryOperates.NewApp, + // directoryOperates.NewForm, + // directoryOperates.NewTransferConfig, + // directoryOperates.NewPageTemplate, + for (const item of accept) { + switch (item) { + case DirectoryType.App: + menus.push(directoryOperates.NewApp); + break; + case DirectoryType.Attribute: + menus.push(directoryOperates.NewProperty); + break; + case DirectoryType.Form: + menus.push(directoryOperates.NewForm); + break; + case DirectoryType.Species: + menus.push(directoryOperates.NewSpecies); + break; + case DirectoryType.Dict: + menus.push(directoryOperates.NewDict); + break; + case DirectoryType.Transfer: + menus.push(directoryOperates.NewTransferConfig); + break; + case DirectoryType.PageTemplate: + menus.push(directoryOperates.NewPageTemplate); + break; + default: + break; + } + } + return { + sort: 0, + cmd: 'new', + label: '新建更多', + iconType: 'new', + menus: menus, + }; +}; /** 新建仓库 */ export const newWarehouse = { diff --git a/src/ts/core/target/team/company.ts b/src/ts/core/target/team/company.ts index b072a792f..17942f4c8 100644 --- a/src/ts/core/target/team/company.ts +++ b/src/ts/core/target/team/company.ts @@ -249,7 +249,11 @@ export class Company extends Belong implements ICompany { return operates; } - content(): IFile[] { + content(isStore?: boolean): IFile[] { + if (isStore) { + return this.storages.filter((i) => i.isMyTeam); + } + return [ ...this.groups, ...this.departments, diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 0a8fd813c..946f290ff 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -1,3 +1,5 @@ +import { getDirectoryNew } from './../public/operates'; +import { DirectoryType } from './../public/enums'; import { common, model, schema } from '../../base'; import { directoryNew, directoryOperates, entityOperates, fileOperates } from '../public'; import { ITarget } from '../target/base/target'; @@ -19,6 +21,8 @@ export interface IDirectory extends IStandardFileInfo { directoryId: string; /** 目录下标准类 */ standard: StandardFiles; + /** 目录下支持的标准类 */ + accept: DirectoryType[]; /** 当前加载目录的用户 */ target: ITarget; /** 资源类 */ @@ -32,7 +36,7 @@ export interface IDirectory extends IStandardFileInfo { /** 任务发射器 */ taskEmitter: common.Emitter; /** 目录下的内容 */ - content(store?: boolean): IFile[]; + content(store?: boolean, isSidebar?: boolean): IFile[]; /** 创建子目录 */ create(data: schema.XDirectory): Promise; /** 目录下的文件 */ @@ -75,10 +79,12 @@ export class Directory extends StandardFileInfo implements ID _parent ?? (_target as unknown as IDirectory), _target.resource.directoryColl, ); + this.accept = (_metadata.accept as DirectoryType[]) ?? []; this.parent = _parent; this.taskEmitter = new common.Emitter(); this.standard = new StandardFiles(this); } + accept: DirectoryType[]; standard: StandardFiles; taskEmitter: common.Emitter; parent: IDirectory | undefined; @@ -127,22 +133,73 @@ export class Directory extends StandardFileInfo implements ID get resource(): DataResource { return this.target.resource; } - content(store: boolean = false): IFile[] { - const cnt: IFile[] = [...this.children]; + content(store: boolean = false, isSidebar: boolean = true): IFile[] { + console.log( + '文件夹展示是否数据展示:', + store, + '----是否侧边栏:', + isSidebar, + this.accept, + ); + const cnt: IFile[] = []; + console.log(this.name, store, this.accept); if (this.target.session.isMyChat || this.target.hasRelationAuth()) { - cnt.push(...this.files); - cnt.push(...this.standard.forms); - cnt.push(...this.standard.applications); - cnt.push(...this.standard.propertys); - cnt.push(...this.standard.specieses); - cnt.push(...this.standard.transfers); - cnt.push(...this.standard.templates); + if (store && this.accept.length > 0) { + if (isSidebar) { + cnt.push(...this.children); + } else { + for (const typeItem of this.accept) { + switch (typeItem) { + case DirectoryType.App: + cnt.push(...this.standard.applications); + break; + case DirectoryType.Species: + cnt.push(...this.standard.specieses); + break; + case DirectoryType.File: + cnt.push(...this.files); + break; + case DirectoryType.Attribute: + cnt.push(...this.standard.propertys); + break; + case DirectoryType.Transfer: + cnt.push(...this.standard.transfers); + break; + case DirectoryType.PageTemplate: + cnt.push(...this.standard.templates); + break; + case DirectoryType.Form: + cnt.push(...this.standard.forms); + break; + case DirectoryType.Report: + // cnt.push(...this.standard.report); + break; + default: + break; + } + } + for (const childrenDir of this.children) { + cnt.push(...childrenDir.content(store, isSidebar)); + } + } + } else { + cnt.push(...this.children); + cnt.push(...this.files); + cnt.push(...this.standard.forms); + cnt.push(...this.standard.applications); + cnt.push(...this.standard.propertys); + cnt.push(...this.standard.specieses); + cnt.push(...this.standard.transfers); + cnt.push(...this.standard.templates); + } } return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); } async loadContent(reload: boolean = false): Promise { - await this.loadFiles(reload); - await this.standard.loadStandardFiles(reload); + if (this.accept.length == 0 || this.accept.includes(DirectoryType.File)) { + await this.loadFiles(reload); + } + await this.standard.loadStandardFiles(reload, this.accept); if (reload) { await this.loadDirectoryResource(reload); } @@ -237,7 +294,10 @@ export class Directory extends StandardFileInfo implements ID } return this.files; } - async createFile(file: Blob, p?: OnProgress): Promise { + async createFile( + file: Blob & { name: string }, + p?: OnProgress, + ): Promise { while (this.taskList.filter((i) => i.finished < i.size).length > 2) { await sleep(1000); } @@ -308,19 +368,20 @@ export class Directory extends StandardFileInfo implements ID directoryOperates.TaskList, directoryOperates.Refesh, ); + const _directoryNew = getDirectoryNew(this.accept); if (this.target.hasRelationAuth()) { if (this.name.includes('业务')) { operates.push({ - ...directoryNew, + ..._directoryNew, menus: [...directoryNew.menus, directoryOperates.Business], }); } else if (this.name.includes('标准')) { operates.push({ - ...directoryNew, + ..._directoryNew, menus: [...directoryNew.menus, directoryOperates.Standard], }); } else { - operates.push(directoryNew); + operates.push(_directoryNew); } if (this.target.user.copyFiles.size > 0) { operates.push(fileOperates.Parse); @@ -330,7 +391,7 @@ export class Directory extends StandardFileInfo implements ID if (this.target.hasRelationAuth()) { operates.push(directoryOperates.Shortcut); } - operates.push(...super.operates()); + // operates.push(...super.operates()); } else { operates.push(entityOperates.Open); } diff --git a/src/ts/core/thing/fileinfo.ts b/src/ts/core/thing/fileinfo.ts index 81eba58b4..1d6f5f040 100644 --- a/src/ts/core/thing/fileinfo.ts +++ b/src/ts/core/thing/fileinfo.ts @@ -51,7 +51,7 @@ export interface IFileInfo extends IEntity { /** 加载文件内容 */ loadContent(reload?: boolean): Promise; /** 目录下的内容 */ - content(args?: boolean): IFile[]; + content(...args: any): IFile[]; /** 缓存用户数据 */ cacheUserData(notify?: boolean): Promise; } diff --git a/src/ts/core/thing/standard/index.ts b/src/ts/core/thing/standard/index.ts index 539cb1b3e..e14afb3c4 100644 --- a/src/ts/core/thing/standard/index.ts +++ b/src/ts/core/thing/standard/index.ts @@ -1,3 +1,4 @@ +import { DirectoryType } from './../../public/enums'; import { model, schema } from '../../../base'; import { Directory, IDirectory } from '../directory'; import { IStandard } from '../fileinfo'; @@ -59,14 +60,41 @@ export class StandardFiles { ...this.templates, ]; } - async loadStandardFiles(reload: boolean = false): Promise { - await Promise.all([ - this.loadForms(reload), - this.loadTransfers(reload), - this.loadPropertys(reload), - this.loadSpecieses(reload), - this.loadTemplates(reload), - ]); + async loadStandardFiles( + reload: boolean = false, + accept: DirectoryType[], + ): Promise { + let waitPromises: Promise[] = []; + if (accept.length > 0) { + for (const type of accept) { + switch (type) { + case DirectoryType.Form: + waitPromises.push(this.loadForms(reload)); + break; + case DirectoryType.Transfer: + waitPromises.push(this.loadTransfers(reload)); + break; + case DirectoryType.Attribute: + waitPromises.push(this.loadPropertys(reload)); + break; + case DirectoryType.Species: + waitPromises.push(this.loadSpecieses(reload)); + break; + case DirectoryType.PageTemplate: + waitPromises.push(this.loadTemplates(reload)); + break; + } + } + } else { + waitPromises = [ + this.loadForms(reload), + this.loadTransfers(reload), + this.loadPropertys(reload), + this.loadSpecieses(reload), + this.loadTemplates(reload), + ]; + } + await Promise.all(waitPromises); return this.standardFiles; } async loadForms(reload: boolean = false): Promise { -- Gitee From caf07c4422869f123b1929caf9bcb3649a1568dc Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 15:42:11 +0800 Subject: [PATCH 20/35] =?UTF-8?q?delete:=20=E5=88=A0=E9=99=A4=E5=A4=9A?= =?UTF-8?q?=E4=BD=99=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MainLayout/preview/index.tsx | 1 - src/ts/core/thing/directory.ts | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index 692658f3f..6b368414a 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -133,7 +133,6 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { } //数据查看 if (location.hash.startsWith('#/store')) { - console.log('数据查看选择内容', entity); return renderEntityBody( entity, , diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 946f290ff..82f1f93e7 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -135,14 +135,15 @@ export class Directory extends StandardFileInfo implements ID } content(store: boolean = false, isSidebar: boolean = true): IFile[] { console.log( + this.name, '文件夹展示是否数据展示:', store, '----是否侧边栏:', isSidebar, + '----支持类型:', this.accept, ); const cnt: IFile[] = []; - console.log(this.name, store, this.accept); if (this.target.session.isMyChat || this.target.hasRelationAuth()) { if (store && this.accept.length > 0) { if (isSidebar) { -- Gitee From 7b11a5ac24457b2b842fba87098487a81c3dc47d Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 15:56:12 +0800 Subject: [PATCH 21/35] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E6=A0=B8?= =?UTF-8?q?=E6=BF=80=E6=B4=BB=E7=8A=B6=E6=80=81=E5=8C=BA=E5=88=86=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/core/target/outTeam/storage.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index 51793b9f5..dcb83e909 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -47,16 +47,14 @@ export class Storage extends Target implements IStorage { return success; } override operates(): OperateModel[] { - const operates = [ - entityOperates.Remark, - entityOperates.QrCode, - entityOperates.CheckDirectory, - ]; + const operates = [entityOperates.Remark, entityOperates.QrCode]; if (this.hasRelationAuth()) { operates.unshift(entityOperates.Update, entityOperates.HardDelete); } if (!this.isActivate) { operates.push(targetOperates.Activate); + } else { + operates.push(entityOperates.CheckDirectory); } return operates; } @@ -95,6 +93,9 @@ export class Storage extends Target implements IStorage { this.directory.loadDirectoryResource(reload); } content(store?: boolean, isSidebar?: boolean): IFile[] { + if (!this.isActivate) { + return []; + } console.log('存储展示是否数据展示:', store, '----是否侧边栏:', isSidebar); const items = this.space.directory.children.sort((a, b) => { const curr = a.metadata.sort ?? a.metadata.updateTime; @@ -114,9 +115,11 @@ export class Storage extends Target implements IStorage { return await super.pullMembers(members, notity); } async checkDirectory() { - await this.space.directory.loadContent(true); - await this.space.directory.standard.loadDirectorys(true); - this.creatStandardDirectory(this.space.directory, StandardDirectory); + if (this.isActivate) { + await this.space.directory.loadContent(true); + await this.space.directory.standard.loadDirectorys(true); + this.creatStandardDirectory(this.space.directory, StandardDirectory); + } } async creatStandardDirectory( directory: IDirectory, -- Gitee From bd8a3e01163ed896571d66a34efbdc1359c2547c Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 18:06:37 +0800 Subject: [PATCH 22/35] =?UTF-8?q?feat:=20=E7=A6=81=E6=AD=A2=E6=97=A0?= =?UTF-8?q?=E5=AD=90=E6=96=87=E4=BB=B6=E5=A4=B9=20=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Directory/views/listMode.tsx | 9 +++++++-- src/components/Directory/views/vlistMode.tsx | 9 +++++++-- src/ts/core/target/outTeam/storage.ts | 8 ++++++-- src/ts/core/thing/directory.ts | 5 +++++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/components/Directory/views/listMode.tsx b/src/components/Directory/views/listMode.tsx index 0c3fe2559..f32820f6f 100644 --- a/src/components/Directory/views/listMode.tsx +++ b/src/components/Directory/views/listMode.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { IDEntity } from '@/ts/core'; +import { IDEntity, IDirectory } from '@/ts/core'; import { Badge, Dropdown, List, MenuProps, Tag } from 'antd'; import { showChatTime } from '@/utils/tools'; import css from './less/list.module.less'; @@ -41,7 +41,12 @@ const ListMode = ({ fileOpen(item, false); }} onDoubleClick={() => { - fileOpen(item, true); + const directory = item as IDirectory; + const isStorView = location.hash.startsWith('#/store'); + const canIinit = directory.canIinit ?? true; + if (!isStorView || (isStorView && canIinit)) { + fileOpen(item, true); + } }} onContextMenu={() => setCxtItem(item)} actions={[ diff --git a/src/components/Directory/views/vlistMode.tsx b/src/components/Directory/views/vlistMode.tsx index 376267f72..9d28bffbc 100644 --- a/src/components/Directory/views/vlistMode.tsx +++ b/src/components/Directory/views/vlistMode.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { IDEntity } from '@/ts/core'; +import { IDEntity, IDirectory } from '@/ts/core'; import { Badge, Dropdown, List, MenuProps, Tag } from 'antd'; import { showChatTime } from '@/utils/tools'; import css from './less/list.module.less'; @@ -51,7 +51,12 @@ const VListMode = ({ fileOpen(item, false); }} onDoubleClick={() => { - fileOpen(item, true); + const directory = item as IDirectory; + const isStorView = location.hash.startsWith('#/store'); + const canIinit = directory.canIinit ?? true; + if (!isStorView || (isStorView && canIinit)) { + fileOpen(item, true); + } }} actions={[
diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index dcb83e909..74372b8db 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -28,6 +28,11 @@ export class Storage extends Target implements IStorage { get isMyTeam(): boolean { return true; } + get groupTags(): string[] { + const activeTag = this.isActivate ? '已激活' : '未激活'; + const gtags: string[] = [...super.groupTags, activeTag]; + return gtags.filter((item) => item !== this.typeName); + } async exit(): Promise { if (this.metadata.belongId !== this.space.id) { if (await this.removeMembers([this.user.metadata])) { @@ -92,11 +97,10 @@ export class Storage extends Target implements IStorage { } this.directory.loadDirectoryResource(reload); } - content(store?: boolean, isSidebar?: boolean): IFile[] { + content(store?: boolean): IFile[] { if (!this.isActivate) { return []; } - console.log('存储展示是否数据展示:', store, '----是否侧边栏:', isSidebar); const items = this.space.directory.children.sort((a, b) => { const curr = a.metadata.sort ?? a.metadata.updateTime; const next = b.metadata.sort ?? b.metadata.updateTime; diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 82f1f93e7..5c19b66d5 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -43,6 +43,8 @@ export interface IDirectory extends IStandardFileInfo { files: ISysFileInfo[]; /** 是否快捷方式 */ readonly isShortcut: boolean; + /** 是否可进入子级 */ + readonly canIinit: boolean; /** 加载模板配置 */ loadAllTemplate(reload?: boolean): Promise; /** 加载文件 */ @@ -133,6 +135,9 @@ export class Directory extends StandardFileInfo implements ID get resource(): DataResource { return this.target.resource; } + get canIinit(): boolean { + return this.children.length > 0; + } content(store: boolean = false, isSidebar: boolean = true): IFile[] { console.log( this.name, -- Gitee From e8f1aa41158be47eb1dfb869bf4d02c471ce980a Mon Sep 17 00:00:00 2001 From: SEN Date: Thu, 1 Feb 2024 18:26:42 +0800 Subject: [PATCH 23/35] =?UTF-8?q?feat:=20=E4=B8=B4=E6=97=B6=E5=A4=84?= =?UTF-8?q?=E7=90=86=20=E6=B7=B1=E5=B1=82=E6=96=87=E4=BB=B6=E8=8E=B7?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Directory/index.tsx | 2 +- src/ts/core/thing/directory.ts | 8 +++++++- src/ts/core/thing/fileinfo.ts | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/Directory/index.tsx b/src/components/Directory/index.tsx index afcffcdf2..cb32987ea 100644 --- a/src/components/Directory/index.tsx +++ b/src/components/Directory/index.tsx @@ -36,7 +36,7 @@ const Directory: React.FC<{ /** 加载目录内容 */ const loadContent = (file: IFile, directory: IFile, reload: boolean) => { setLoaded(false); - file.loadContent(reload).then(() => { + file.loadContent(reload, true).then(() => { if (file.key === directory.key) { setCurrentTag('全部'); setContent(directory.content(isStore, isSidebar)); diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 5c19b66d5..6cb6e589a 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -201,7 +201,7 @@ export class Directory extends StandardFileInfo implements ID } return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); } - async loadContent(reload: boolean = false): Promise { + async loadContent(reload: boolean = false, isDeep = false): Promise { if (this.accept.length == 0 || this.accept.includes(DirectoryType.File)) { await this.loadFiles(reload); } @@ -209,6 +209,11 @@ export class Directory extends StandardFileInfo implements ID if (reload) { await this.loadDirectoryResource(reload); } + if (isDeep) { + for (const childrenDir of this.children) { + await childrenDir.loadContent(reload, isDeep); + } + } return true; } override async copy(destination: IDirectory): Promise { @@ -277,6 +282,7 @@ export class Directory extends StandardFileInfo implements ID const result = await this.resource.directoryColl.insert({ ...data, typeName: '目录', + accept: this.accept, directoryId: this.id, }); if (result) { diff --git a/src/ts/core/thing/fileinfo.ts b/src/ts/core/thing/fileinfo.ts index 1d6f5f040..6de56aebf 100644 --- a/src/ts/core/thing/fileinfo.ts +++ b/src/ts/core/thing/fileinfo.ts @@ -49,7 +49,7 @@ export interface IFileInfo extends IEntity { */ move(destination: IDirectory): Promise; /** 加载文件内容 */ - loadContent(reload?: boolean): Promise; + loadContent(reload?: boolean, isDeep?: boolean): Promise; /** 目录下的内容 */ content(...args: any): IFile[]; /** 缓存用户数据 */ @@ -146,8 +146,8 @@ export abstract class FileInfo return success; } - async loadContent(reload: boolean = false): Promise { - return await sleep(reload ? 10 : 0); + async loadContent(reload: boolean = false, isDeep: boolean = false): Promise { + return await sleep(reload || isDeep ? 10 : 0); } content(): IFile[] { return []; -- Gitee From 10bb4f936c2f6be01474ca0068a171d7e1977b87 Mon Sep 17 00:00:00 2001 From: jiangyang <1140938202@qq.com> Date: Fri, 2 Feb 2024 13:55:55 +0800 Subject: [PATCH 24/35] =?UTF-8?q?fix:=E6=96=B0=E7=89=88=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/svg/chevron-up.svg | 3 + public/svg/fileAuth.svg | 5 + public/svg/fileInfo.svg | 8 + public/svg/fileSetting.svg | 5 + src/components/Directory/index.tsx | 11 +- src/components/Directory/views/index.tsx | 40 ++-- .../Directory/views/less/list.module.less | 50 ++++- src/components/Directory/views/listMode.tsx | 174 +++++++++++------- .../preview/content/index.module.less | 71 +++++++ .../MainLayout/preview/content/index.tsx | 38 ++++ src/components/MainLayout/preview/index.tsx | 40 +++- .../MainLayout/preview/info/index.module.less | 35 ++++ .../MainLayout/preview/info/index.tsx | 115 ++++++++++++ 13 files changed, 499 insertions(+), 96 deletions(-) create mode 100644 public/svg/chevron-up.svg create mode 100755 public/svg/fileAuth.svg create mode 100755 public/svg/fileInfo.svg create mode 100755 public/svg/fileSetting.svg create mode 100644 src/components/MainLayout/preview/content/index.module.less create mode 100644 src/components/MainLayout/preview/content/index.tsx create mode 100644 src/components/MainLayout/preview/info/index.module.less create mode 100644 src/components/MainLayout/preview/info/index.tsx diff --git a/public/svg/chevron-up.svg b/public/svg/chevron-up.svg new file mode 100644 index 000000000..1832e4321 --- /dev/null +++ b/public/svg/chevron-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/svg/fileAuth.svg b/public/svg/fileAuth.svg new file mode 100755 index 000000000..c2dbf34f9 --- /dev/null +++ b/public/svg/fileAuth.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/svg/fileInfo.svg b/public/svg/fileInfo.svg new file mode 100755 index 000000000..2e783fe49 --- /dev/null +++ b/public/svg/fileInfo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/svg/fileSetting.svg b/public/svg/fileSetting.svg new file mode 100755 index 000000000..4dd091a1a --- /dev/null +++ b/public/svg/fileSetting.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/Directory/index.tsx b/src/components/Directory/index.tsx index e27dc0433..0c18ad58f 100644 --- a/src/components/Directory/index.tsx +++ b/src/components/Directory/index.tsx @@ -50,11 +50,14 @@ const Directory: React.FC<{ root: IFile; isStore?: boolean }> = ({ root, isStore content={content} currentTag={currentTag} tagChanged={(t) => setCurrentTag(t)} + isStore={isStore} fileOpen={(file) => { - if (file && 'isContainer' in file && file.isContainer) { - setDirectory(file as IFile); - } else { - command.emitter('executor', 'open', file); + if (!isStore) { + if (file && 'isContainer' in file && file.isContainer) { + setDirectory(file as IFile); + } else { + command.emitter('executor', 'open', file); + } } }} preDirectory={preDirectory} diff --git a/src/components/Directory/views/index.tsx b/src/components/Directory/views/index.tsx index 71494f442..c6d0ebb77 100644 --- a/src/components/Directory/views/index.tsx +++ b/src/components/Directory/views/index.tsx @@ -27,6 +27,7 @@ interface IProps { tagChanged?: (tag: string) => void; fileOpen: (file: IDEntity | undefined, dblclick: boolean) => void; contextMenu: (file?: IDEntity) => MenuProps; + isStore?: boolean; } /** * 存储-文件系统 @@ -87,6 +88,7 @@ const DirectoryView: React.FC = (props) => { selectFiles={props.selectFiles} focusFile={props.focusFile} content={getContent()} + isStore={props.isStore} fileOpen={props.fileOpen} contextMenu={props.contextMenu} /> @@ -96,23 +98,27 @@ const DirectoryView: React.FC = (props) => { return ( <> - setFilter(value)} - menus={props.contextMenu()} - /> - props.fileOpen(props.preDirectory, true)} - onChanged={(t) => props.tagChanged && props.tagChanged(t)}> + {!props.isStore ? ( + <> + setFilter(value)} + menus={props.contextMenu()} + /> + props.fileOpen(props.preDirectory, true)} + onChanged={(t) => props.tagChanged && props.tagChanged(t)}> + + ):<>} void; contextMenu: (file?: IDEntity) => MenuProps; + isStore?: boolean; }) => { - const [cxtItem, setCxtItem] = useState(); const getItemClassName = (item: IDEntity) => { if (focusFile?.key === item.key || selectFiles.some((i) => i.key === item.key)) { return css.list_item_select; } return css.list_item; }; + const headList = ['文件', '用户', '归属', '创建时间', '操作']; + const sortConetnt = (type: string) => ( +
+ {type} +
+ + +
+
+ ); + const showContnt = (item: IDEntity) => { + return ( +
+ + +
{showChatTime(item.updateTime)}
+
+
command.emitter('executor', 'open', item)}> + + 打开 +
+
command.emitter('executor', 'copy', item)}> + + 复制 +
+ + + +
+
+ ); + }; return ( - +
e.stopPropagation()}> + + {headList.map((item) => { + return sortConetnt(item); + })} +
+ ) + } + itemLayout="horizontal" + dataSource={content} + renderItem={(item) => { + return ( +
+ { + fileOpen(item, false); + }} + onDoubleClick={() => { + fileOpen(item, true); + }} + actions={ + !isStore + ? [ +
+ {showChatTime(item.updateTime)} +
, + ] + : [] + }> + +
{item.name}
+ {item.metadata.sourceId ? ( + 快捷方式 + ) : ( + <> + )} + {item.groupTags + .filter((i) => i.length > 0) + .map((label) => { + return ( + + {label} + + ); + })} + + } + avatar={ + + + + } + description={ +
{item.remark || item.code}
+ } + /> + {isStore && showContnt(item)} +
+
+ ); + }} + />
e.stopPropagation()}> - { - return ( -
- { - fileOpen(item, false); - }} - onDoubleClick={() => { - fileOpen(item, true); - }} - onContextMenu={() => setCxtItem(item)} - actions={[ -
- {showChatTime(item.updateTime)} -
, - ]}> - -
{item.name}
- {item.metadata.sourceId ? ( - 快捷方式 - ) : ( - <> - )} - {item.groupTags - .filter((i) => i.length > 0) - .map((label) => { - return ( - - {label} - - ); - })} - - } - avatar={ - - - - } - description={ -
{item.remark || item.code}
- } - /> -
-
- ); - }} - /> -
setCxtItem(undefined)}>
-
-
+ style={{ height: `calc(100% - ${content.length * 78}px)` }} + className={css.blank_area}>
+
); }; export default ListMode; diff --git a/src/components/MainLayout/preview/content/index.module.less b/src/components/MainLayout/preview/content/index.module.less new file mode 100644 index 000000000..42dbe0783 --- /dev/null +++ b/src/components/MainLayout/preview/content/index.module.less @@ -0,0 +1,71 @@ +.content { + padding: 24px; + .head { + display: flex; + justify-content: space-between; + .title { + font-size: 18px; + } + .edit { + display: flex; + justify-content: space-between; + button { + margin-left: 10px; + } + } + } +} + +.seek { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 16px; + + .tag { + display: flex; + .tags_item { + cursor: pointer; + white-space: nowrap; + padding: 4px 12px; + font-size: 12px; + height: 26px; + border-radius: 6px; + background-color: #efefef; + margin-right: 6px; + & > * { + font-size: 12px; + } + .item_count { + color: #2b00ff; + font-style: italic; + transform: scale(0.9); + } + &:hover { + background-color: @active-background; + } + &_active { + cursor: not-allowed; + white-space: nowrap; + border-radius: 6px; + padding: 4px 12px; + font-size: 12px; + height: 26px; + .item_count { + font-style: italic; + transform: scale(0.9); + } + & > * { + font-size: 12px; + color: @text-color-inverse; + } + color: @text-color-inverse; + background-color: @focus-background; + } + } + } + .search { + width: 50%; + max-width: 300px; + } +} diff --git a/src/components/MainLayout/preview/content/index.tsx b/src/components/MainLayout/preview/content/index.tsx new file mode 100644 index 000000000..4944824cb --- /dev/null +++ b/src/components/MainLayout/preview/content/index.tsx @@ -0,0 +1,38 @@ +import { Button, Tag, Input } from 'antd'; +import { SearchOutlined } from '@ant-design/icons'; + +import React from 'react'; +import css from './index.module.less'; + +interface IProps {} + +const PreviewLayout: React.FC = (props) => { + console.log('props', props); + return ( + <> +
+
+
访问权限
+
+ + +
+
+
+
+
全部
+
内设机构
+
群组
+
集群
+
+
+ } /> +
+
+
+
+ + ); +}; + +export default PreviewLayout; diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index 9200c29c2..0613ccd18 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -22,7 +22,8 @@ import Directory from '@/components/Directory'; import TaskApproval from '@/executor/tools/task/approval'; import TaskStart from '@/executor/tools/task/start'; import PreviewLayout from './layout'; - +import Content from './content'; +import Info from './info'; const officeExt = ['.md', '.pdf', '.xls', '.xlsx', '.doc', '.docx', '.ppt', '.pptx']; const videoExt = ['.mp4', '.avi', '.mov', '.mpg', '.swf', '.flv', '.mpeg']; @@ -55,7 +56,10 @@ const FilePreview: React.FC<{ file: ISysFileInfo }> = ({ file }) => { const EntityPreview: React.FC<{ flag?: string }> = (props) => { if (!(props.flag && props.flag.length > 0)) return <>; const [entity, setEntity] = useState(); + const [bodyType, setBodyType] = useState(''); + useEffect(() => { + setBodyType(''); const id = command.subscribe((type, flag, ...args: any[]) => { console.log('实体预览subscribe', type, flag, ...args); if (type != 'preview' || flag != props.flag) return; @@ -69,11 +73,27 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { command.unsubscribe(id); }; }, [props]); + const renderEntityBodyInfo = (entity: any, children?: React.ReactNode) => { + console.log('children', children); + switch (bodyType) { + case 'fileSetting': + return ; + case 'fileAuth': + return ; + default: + return children; + } + }; const renderEntityBody = (entity: any, children?: React.ReactNode, actions?: any[]) => { return ( - - {children && children} + { + setBodyType(key); + }}> + {renderEntityBodyInfo(entity, children)} ); }; @@ -134,22 +154,22 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { } //数据查看 if (location.hash.startsWith('#/store')) { - console.log('打印数据选择内容', entity); + console.log('打印数据选择内容', entity.remark); return renderEntityBody( entity, , [ { - key: 'activity', - label: '动态', + key: 'fileInfo', + label: '详情', }, { - key: 'store', - label: '数据', + key: 'fileAuth', + label: '权限', }, { - key: 'relation', - label: '关系', + key: 'fileSetting', + label: '设置', }, ], ); diff --git a/src/components/MainLayout/preview/info/index.module.less b/src/components/MainLayout/preview/info/index.module.less new file mode 100644 index 000000000..f1733c449 --- /dev/null +++ b/src/components/MainLayout/preview/info/index.module.less @@ -0,0 +1,35 @@ +.content { + padding: 24px; + .head { + display: flex; + justify-content: space-between; + .title { + font-size: 18px; + } + .edit { + display: flex; + justify-content: space-between; + button { + margin-left: 10px; + } + } + } +} + +.contnt { + margin-top: 16px; + display: flex; + flex-flow: wrap; + .item { + display: flex; + flex-direction: column; + font-size: 14px; + line-height: 22px; + width: 25%; + margin-bottom: 16px; + .item_title { + color: rgba(0, 0, 0, 0.4); + margin-bottom: 16px; + } + } +} diff --git a/src/components/MainLayout/preview/info/index.tsx b/src/components/MainLayout/preview/info/index.tsx new file mode 100644 index 000000000..3966f720a --- /dev/null +++ b/src/components/MainLayout/preview/info/index.tsx @@ -0,0 +1,115 @@ +import { Button, Tag, Input } from 'antd'; + +import React, { useEffect, useState, useRef } from 'react'; +import css from './index.module.less'; +import { model, parseAvatar, schema, command } from '@/ts/base'; +import QrCode from 'qrcode.react'; +import { formatZhDate } from '@/utils/tools'; +import orgCtrl from '@/ts/controller'; +import EntityIcon from '@/components/Common/GlobalComps/entityIcon'; +import TypeIcon from '@/components/Common/GlobalComps/typeIcon'; +import UploadItem from '../../../../executor/tools/uploadItem'; + +import { Theme } from '@/config/theme'; +interface IProps { + entity: schema.XEntity | schema.XTarget; +} + +const Info: React.FC = (props) => { + const [entity, setEntity] = useState(props.entity); + const avatar: model.FileItemShare = parseAvatar(props.entity.icon); + return ( + <> +
+
+
文件信息
+
+ +
+
+
+
+
图标
+
+ {}} + directory={orgCtrl.user.directory} + /> +
+
+
+
名称
+
{props.entity.name}
+
+
+
类型
+
{props.entity.typeName}
+
+
+
代码
+
{props.entity.code}
+
+
+
归属
+
+ +
+
+ {props.entity.createUser && ( +
+
创建人
+
+ +
+
+ )} +
+
创建时间
+
+ {formatZhDate(props.entity.createTime)} +
+
+
+
更新时间
+
+ {formatZhDate(props.entity.updateTime)} +
+
+
+
简介
+
{props.entity.remark || '-'}
+
+
+
二维码
+
+ +
+
+
+
+ + ); +}; + +export default Info; -- Gitee From b7fb7c2fa60a472ca803ea7d3733146b64afa648 Mon Sep 17 00:00:00 2001 From: SEN Date: Fri, 2 Feb 2024 14:44:45 +0800 Subject: [PATCH 25/35] =?UTF-8?q?feat:=20=E5=A4=84=E7=90=86=E9=9C=80?= =?UTF-8?q?=E6=B1=82:=E9=9A=90=E8=97=8F=E8=A1=A8=E5=8D=95=E9=87=8C?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=AD=97=E6=AE=B5,=E5=A6=82=E5=94=AF?= =?UTF-8?q?=E4=B8=80=E6=A0=87=E8=AF=86/=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/column.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/column.tsx b/src/config/column.tsx index a21853b03..504e3bffb 100644 --- a/src/config/column.tsx +++ b/src/config/column.tsx @@ -150,7 +150,7 @@ export const FullEntityColumns = (fields: model.FieldModel[]) => { remark: '由系统生成的唯一标记,无实义.', options: { fixed: true, - visible: true, + visible: false, }, }, { -- Gitee From cacea23115e34ff34ce80851ced8ffb3fc82f47f Mon Sep 17 00:00:00 2001 From: SEN Date: Fri, 2 Feb 2024 14:46:40 +0800 Subject: [PATCH 26/35] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/column.tsx | 2 +- src/ts/core/target/outTeam/storage.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/config/column.tsx b/src/config/column.tsx index 504e3bffb..a21853b03 100644 --- a/src/config/column.tsx +++ b/src/config/column.tsx @@ -150,7 +150,7 @@ export const FullEntityColumns = (fields: model.FieldModel[]) => { remark: '由系统生成的唯一标记,无实义.', options: { fixed: true, - visible: false, + visible: true, }, }, { diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index 74372b8db..891c439e9 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -90,6 +90,10 @@ export class Storage extends Target implements IStorage { } return false; } + async checkStorage() { + this.checkDirectory(); + return true; + } async deepLoad(reload: boolean = false): Promise { if (this.hasRelationAuth()) { await this.loadIdentitys(reload); -- Gitee From 977da3c818c7e7951f4713284d6dfc6525e3661a Mon Sep 17 00:00:00 2001 From: jiangyang <1140938202@qq.com> Date: Fri, 2 Feb 2024 14:47:31 +0800 Subject: [PATCH 27/35] =?UTF-8?q?Revert=20"feat:=20=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86=20=E6=B7=B1=E5=B1=82=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=8E=B7=E5=8F=96"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e8f1aa41158be47eb1dfb869bf4d02c471ce980a. --- src/components/Directory/index.tsx | 2 +- src/ts/core/thing/directory.ts | 8 +------- src/ts/core/thing/fileinfo.ts | 6 +++--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/components/Directory/index.tsx b/src/components/Directory/index.tsx index 7f6d7bc01..dd9a562a2 100644 --- a/src/components/Directory/index.tsx +++ b/src/components/Directory/index.tsx @@ -36,7 +36,7 @@ const Directory: React.FC<{ /** 加载目录内容 */ const loadContent = (file: IFile, directory: IFile, reload: boolean) => { setLoaded(false); - file.loadContent(reload, true).then(() => { + file.loadContent(reload).then(() => { if (file.key === directory.key) { setCurrentTag('全部'); setContent(directory.content(isStore, isSidebar)); diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index f72656f49..40167607e 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -204,7 +204,7 @@ export class Directory extends StandardFileInfo implements ID a.metadata.updateTime < b.metadata.updateTime ? 1 : -1, ); } - async loadContent(reload: boolean = false, isDeep = false): Promise { + async loadContent(reload: boolean = false): Promise { if (this.accept.length == 0 || this.accept.includes(DirectoryType.File)) { await this.loadFiles(reload); } @@ -212,11 +212,6 @@ export class Directory extends StandardFileInfo implements ID if (reload) { await this.loadDirectoryResource(reload); } - if (isDeep) { - for (const childrenDir of this.children) { - await childrenDir.loadContent(reload, isDeep); - } - } return true; } override async copy(destination: IDirectory): Promise { @@ -285,7 +280,6 @@ export class Directory extends StandardFileInfo implements ID const result = await this.resource.directoryColl.insert({ ...data, typeName: '目录', - accept: this.accept, directoryId: this.id, }); if (result) { diff --git a/src/ts/core/thing/fileinfo.ts b/src/ts/core/thing/fileinfo.ts index 6de56aebf..1d6f5f040 100644 --- a/src/ts/core/thing/fileinfo.ts +++ b/src/ts/core/thing/fileinfo.ts @@ -49,7 +49,7 @@ export interface IFileInfo extends IEntity { */ move(destination: IDirectory): Promise; /** 加载文件内容 */ - loadContent(reload?: boolean, isDeep?: boolean): Promise; + loadContent(reload?: boolean): Promise; /** 目录下的内容 */ content(...args: any): IFile[]; /** 缓存用户数据 */ @@ -146,8 +146,8 @@ export abstract class FileInfo return success; } - async loadContent(reload: boolean = false, isDeep: boolean = false): Promise { - return await sleep(reload || isDeep ? 10 : 0); + async loadContent(reload: boolean = false): Promise { + return await sleep(reload ? 10 : 0); } content(): IFile[] { return []; -- Gitee From ed4fcd3b5f0505fd8dd8eea616845b89253d801d Mon Sep 17 00:00:00 2001 From: SEN Date: Fri, 2 Feb 2024 14:49:51 +0800 Subject: [PATCH 28/35] =?UTF-8?q?feat:=20=E5=86=85=E5=AE=B9=E5=8C=BA?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E5=8F=8A=E6=93=8D=E4=BD=9C=E5=8C=BA=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MainLayout/preview/index.tsx | 1 + src/ts/core/thing/directory.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index 6b368414a..9752597d4 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -57,6 +57,7 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { const [entity, setEntity] = useState(); useEffect(() => { const id = command.subscribe((type, flag, ...args: any[]) => { + console.log('实体预览subscribe', type, flag, ...args); if (type != 'preview' || flag != props.flag) return; if (args && args.length > 0) { setEntity(args[0]); diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 6cb6e589a..19d16653c 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -199,6 +199,7 @@ export class Directory extends StandardFileInfo implements ID cnt.push(...this.standard.templates); } } + console.log('store内容', cnt); return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); } async loadContent(reload: boolean = false, isDeep = false): Promise { -- Gitee From cd9de145d85645f83897960c4dbb18c66c53ffd7 Mon Sep 17 00:00:00 2001 From: SEN Date: Fri, 2 Feb 2024 14:49:51 +0800 Subject: [PATCH 29/35] =?UTF-8?q?feat:=20=E8=BF=94=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E9=87=8D=E5=A4=8D=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ts/core/thing/directory.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 19d16653c..228e144d9 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -189,7 +189,6 @@ export class Directory extends StandardFileInfo implements ID } } } else { - cnt.push(...this.children); cnt.push(...this.files); cnt.push(...this.standard.forms); cnt.push(...this.standard.applications); @@ -200,7 +199,9 @@ export class Directory extends StandardFileInfo implements ID } } console.log('store内容', cnt); - return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); + return this.uniqueBy(cnt, 'id').sort((a, b) => + a.metadata.updateTime < b.metadata.updateTime ? 1 : -1, + ); } async loadContent(reload: boolean = false, isDeep = false): Promise { if (this.accept.length == 0 || this.accept.includes(DirectoryType.File)) { @@ -476,4 +477,18 @@ export class Directory extends StandardFileInfo implements ID directoryId: this.id, }); } + uniqueBy(arr: T[], key: K): T[] { + const result = []; + const map = new Map(); + + for (const item of arr) { + const keyValue = item[key]; + if (!map.has(keyValue)) { + map.set(keyValue, true); + result.push(item); + } + } + + return result; + } } -- Gitee From a42be008158dae69747983f3e3b92cbef284dde2 Mon Sep 17 00:00:00 2001 From: jiangyang <1140938202@qq.com> Date: Fri, 2 Feb 2024 14:51:59 +0800 Subject: [PATCH 30/35] =?UTF-8?q?fix:=E6=96=B0=E7=89=88=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/svg/chevron-up.svg | 3 + public/svg/fileAuth.svg | 5 + public/svg/fileInfo.svg | 8 + public/svg/fileSetting.svg | 5 + src/components/Directory/index.tsx | 11 +- src/components/Directory/views/index.tsx | 40 ++-- .../Directory/views/less/list.module.less | 50 ++++- src/components/Directory/views/listMode.tsx | 186 +++++++++++------- .../preview/content/index.module.less | 71 +++++++ .../MainLayout/preview/content/index.tsx | 38 ++++ src/components/MainLayout/preview/index.tsx | 38 +++- .../MainLayout/preview/info/index.module.less | 35 ++++ .../MainLayout/preview/info/index.tsx | 115 +++++++++++ 13 files changed, 504 insertions(+), 101 deletions(-) create mode 100644 public/svg/chevron-up.svg create mode 100755 public/svg/fileAuth.svg create mode 100755 public/svg/fileInfo.svg create mode 100755 public/svg/fileSetting.svg create mode 100644 src/components/MainLayout/preview/content/index.module.less create mode 100644 src/components/MainLayout/preview/content/index.tsx create mode 100644 src/components/MainLayout/preview/info/index.module.less create mode 100644 src/components/MainLayout/preview/info/index.tsx diff --git a/public/svg/chevron-up.svg b/public/svg/chevron-up.svg new file mode 100644 index 000000000..1832e4321 --- /dev/null +++ b/public/svg/chevron-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/svg/fileAuth.svg b/public/svg/fileAuth.svg new file mode 100755 index 000000000..c2dbf34f9 --- /dev/null +++ b/public/svg/fileAuth.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/svg/fileInfo.svg b/public/svg/fileInfo.svg new file mode 100755 index 000000000..2e783fe49 --- /dev/null +++ b/public/svg/fileInfo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/svg/fileSetting.svg b/public/svg/fileSetting.svg new file mode 100755 index 000000000..4dd091a1a --- /dev/null +++ b/public/svg/fileSetting.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/Directory/index.tsx b/src/components/Directory/index.tsx index cb32987ea..7f6d7bc01 100644 --- a/src/components/Directory/index.tsx +++ b/src/components/Directory/index.tsx @@ -53,11 +53,14 @@ const Directory: React.FC<{ content={content} currentTag={currentTag} tagChanged={(t) => setCurrentTag(t)} + isStore={isStore} fileOpen={(file) => { - if (file && 'isContainer' in file && file.isContainer) { - setDirectory(file as IFile); - } else { - command.emitter('executor', 'open', file); + if (!isStore) { + if (file && 'isContainer' in file && file.isContainer) { + setDirectory(file as IFile); + } else { + command.emitter('executor', 'open', file); + } } }} preDirectory={preDirectory} diff --git a/src/components/Directory/views/index.tsx b/src/components/Directory/views/index.tsx index 71494f442..c6d0ebb77 100644 --- a/src/components/Directory/views/index.tsx +++ b/src/components/Directory/views/index.tsx @@ -27,6 +27,7 @@ interface IProps { tagChanged?: (tag: string) => void; fileOpen: (file: IDEntity | undefined, dblclick: boolean) => void; contextMenu: (file?: IDEntity) => MenuProps; + isStore?: boolean; } /** * 存储-文件系统 @@ -87,6 +88,7 @@ const DirectoryView: React.FC = (props) => { selectFiles={props.selectFiles} focusFile={props.focusFile} content={getContent()} + isStore={props.isStore} fileOpen={props.fileOpen} contextMenu={props.contextMenu} /> @@ -96,23 +98,27 @@ const DirectoryView: React.FC = (props) => { return ( <> - setFilter(value)} - menus={props.contextMenu()} - /> - props.fileOpen(props.preDirectory, true)} - onChanged={(t) => props.tagChanged && props.tagChanged(t)}> + {!props.isStore ? ( + <> + setFilter(value)} + menus={props.contextMenu()} + /> + props.fileOpen(props.preDirectory, true)} + onChanged={(t) => props.tagChanged && props.tagChanged(t)}> + + ):<>} void; contextMenu: (file?: IDEntity) => MenuProps; + isStore?: boolean; }) => { - const [cxtItem, setCxtItem] = useState(); const getItemClassName = (item: IDEntity) => { if (focusFile?.key === item.key || selectFiles.some((i) => i.key === item.key)) { return css.list_item_select; } return css.list_item; }; + const headList = ['文件', '用户', '归属', '创建时间', '操作']; + const sortConetnt = (type: string) => ( +
+ {type} +
+ + +
+
+ ); + const showContnt = (item: IDEntity) => { + return ( +
+ + +
{showChatTime(item.updateTime)}
+
+
command.emitter('executor', 'open', item)}> + + 打开 +
+
command.emitter('executor', 'copy', item)}> + + 复制 +
+ + + +
+
+ ); + }; return ( - +
e.stopPropagation()}> + + {headList.map((item) => { + return sortConetnt(item); + })} +
+ ) + } + itemLayout="horizontal" + dataSource={content} + renderItem={(item) => { + return ( +
+ { + fileOpen(item, false); + }} + onDoubleClick={() => { + const directory = item as IDirectory; + const isStorView = location.hash.startsWith('#/store'); + const canIinit = directory.canIinit ?? true; + if (!isStorView || (isStorView && canIinit)) { + fileOpen(item, true); + } + }} + actions={ + !isStore + ? [ +
+ {showChatTime(item.updateTime)} +
, + ] + : [] + }> + +
{item.name}
+ {item.metadata.sourceId ? ( + 快捷方式 + ) : ( + <> + )} + {item.groupTags + .filter((i) => i.length > 0) + .map((label) => { + return ( + + {label} + + ); + })} + + } + avatar={ + + + + } + description={ +
{item.remark || item.code}
+ } + /> + {isStore && showContnt(item)} +
+
+ ); + }} + />
e.stopPropagation()}> - { - return ( -
- { - fileOpen(item, false); - }} - onDoubleClick={() => { - const directory = item as IDirectory; - const isStorView = location.hash.startsWith('#/store'); - const canIinit = directory.canIinit ?? true; - if (!isStorView || (isStorView && canIinit)) { - fileOpen(item, true); - } - }} - onContextMenu={() => setCxtItem(item)} - actions={[ -
- {showChatTime(item.updateTime)} -
, - ]}> - -
{item.name}
- {item.metadata.sourceId ? ( - 快捷方式 - ) : ( - <> - )} - {item.groupTags - .filter((i) => i.length > 0) - .map((label) => { - return ( - - {label} - - ); - })} - - } - avatar={ - - - - } - description={ -
{item.remark || item.code}
- } - /> -
-
- ); - }} - /> -
setCxtItem(undefined)}>
-
-
+ style={{ height: `calc(100% - ${content.length * 78}px)` }} + className={css.blank_area}> + ); }; export default ListMode; diff --git a/src/components/MainLayout/preview/content/index.module.less b/src/components/MainLayout/preview/content/index.module.less new file mode 100644 index 000000000..42dbe0783 --- /dev/null +++ b/src/components/MainLayout/preview/content/index.module.less @@ -0,0 +1,71 @@ +.content { + padding: 24px; + .head { + display: flex; + justify-content: space-between; + .title { + font-size: 18px; + } + .edit { + display: flex; + justify-content: space-between; + button { + margin-left: 10px; + } + } + } +} + +.seek { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 16px; + + .tag { + display: flex; + .tags_item { + cursor: pointer; + white-space: nowrap; + padding: 4px 12px; + font-size: 12px; + height: 26px; + border-radius: 6px; + background-color: #efefef; + margin-right: 6px; + & > * { + font-size: 12px; + } + .item_count { + color: #2b00ff; + font-style: italic; + transform: scale(0.9); + } + &:hover { + background-color: @active-background; + } + &_active { + cursor: not-allowed; + white-space: nowrap; + border-radius: 6px; + padding: 4px 12px; + font-size: 12px; + height: 26px; + .item_count { + font-style: italic; + transform: scale(0.9); + } + & > * { + font-size: 12px; + color: @text-color-inverse; + } + color: @text-color-inverse; + background-color: @focus-background; + } + } + } + .search { + width: 50%; + max-width: 300px; + } +} diff --git a/src/components/MainLayout/preview/content/index.tsx b/src/components/MainLayout/preview/content/index.tsx new file mode 100644 index 000000000..4944824cb --- /dev/null +++ b/src/components/MainLayout/preview/content/index.tsx @@ -0,0 +1,38 @@ +import { Button, Tag, Input } from 'antd'; +import { SearchOutlined } from '@ant-design/icons'; + +import React from 'react'; +import css from './index.module.less'; + +interface IProps {} + +const PreviewLayout: React.FC = (props) => { + console.log('props', props); + return ( + <> +
+
+
访问权限
+
+ + +
+
+
+
+
全部
+
内设机构
+
群组
+
集群
+
+
+ } /> +
+
+
+
+ + ); +}; + +export default PreviewLayout; diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index 9752597d4..a87ac9759 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -22,7 +22,8 @@ import Directory from '@/components/Directory'; import TaskApproval from '@/executor/tools/task/approval'; import TaskStart from '@/executor/tools/task/start'; import PreviewLayout from './layout'; - +import Content from './content'; +import Info from './info'; const officeExt = ['.md', '.pdf', '.xls', '.xlsx', '.doc', '.docx', '.ppt', '.pptx']; const videoExt = ['.mp4', '.avi', '.mov', '.mpg', '.swf', '.flv', '.mpeg']; @@ -55,7 +56,10 @@ const FilePreview: React.FC<{ file: ISysFileInfo }> = ({ file }) => { const EntityPreview: React.FC<{ flag?: string }> = (props) => { if (!(props.flag && props.flag.length > 0)) return <>; const [entity, setEntity] = useState(); + const [bodyType, setBodyType] = useState(''); + useEffect(() => { + setBodyType(''); const id = command.subscribe((type, flag, ...args: any[]) => { console.log('实体预览subscribe', type, flag, ...args); if (type != 'preview' || flag != props.flag) return; @@ -69,11 +73,27 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { command.unsubscribe(id); }; }, [props]); + const renderEntityBodyInfo = (entity: any, children?: React.ReactNode) => { + console.log('children', children); + switch (bodyType) { + case 'fileSetting': + return ; + case 'fileAuth': + return ; + default: + return children; + } + }; const renderEntityBody = (entity: any, children?: React.ReactNode, actions?: any[]) => { return ( - - {children && children} + { + setBodyType(key); + }}> + {renderEntityBodyInfo(entity, children)} ); }; @@ -139,16 +159,16 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { , [ { - key: 'activity', - label: '动态', + key: 'fileInfo', + label: '详情', }, { - key: 'store', - label: '数据', + key: 'fileAuth', + label: '权限', }, { - key: 'relation', - label: '关系', + key: 'fileSetting', + label: '设置', }, ], ); diff --git a/src/components/MainLayout/preview/info/index.module.less b/src/components/MainLayout/preview/info/index.module.less new file mode 100644 index 000000000..f1733c449 --- /dev/null +++ b/src/components/MainLayout/preview/info/index.module.less @@ -0,0 +1,35 @@ +.content { + padding: 24px; + .head { + display: flex; + justify-content: space-between; + .title { + font-size: 18px; + } + .edit { + display: flex; + justify-content: space-between; + button { + margin-left: 10px; + } + } + } +} + +.contnt { + margin-top: 16px; + display: flex; + flex-flow: wrap; + .item { + display: flex; + flex-direction: column; + font-size: 14px; + line-height: 22px; + width: 25%; + margin-bottom: 16px; + .item_title { + color: rgba(0, 0, 0, 0.4); + margin-bottom: 16px; + } + } +} diff --git a/src/components/MainLayout/preview/info/index.tsx b/src/components/MainLayout/preview/info/index.tsx new file mode 100644 index 000000000..3966f720a --- /dev/null +++ b/src/components/MainLayout/preview/info/index.tsx @@ -0,0 +1,115 @@ +import { Button, Tag, Input } from 'antd'; + +import React, { useEffect, useState, useRef } from 'react'; +import css from './index.module.less'; +import { model, parseAvatar, schema, command } from '@/ts/base'; +import QrCode from 'qrcode.react'; +import { formatZhDate } from '@/utils/tools'; +import orgCtrl from '@/ts/controller'; +import EntityIcon from '@/components/Common/GlobalComps/entityIcon'; +import TypeIcon from '@/components/Common/GlobalComps/typeIcon'; +import UploadItem from '../../../../executor/tools/uploadItem'; + +import { Theme } from '@/config/theme'; +interface IProps { + entity: schema.XEntity | schema.XTarget; +} + +const Info: React.FC = (props) => { + const [entity, setEntity] = useState(props.entity); + const avatar: model.FileItemShare = parseAvatar(props.entity.icon); + return ( + <> +
+
+
文件信息
+
+ +
+
+
+
+
图标
+
+ {}} + directory={orgCtrl.user.directory} + /> +
+
+
+
名称
+
{props.entity.name}
+
+
+
类型
+
{props.entity.typeName}
+
+
+
代码
+
{props.entity.code}
+
+
+
归属
+
+ +
+
+ {props.entity.createUser && ( +
+
创建人
+
+ +
+
+ )} +
+
创建时间
+
+ {formatZhDate(props.entity.createTime)} +
+
+
+
更新时间
+
+ {formatZhDate(props.entity.updateTime)} +
+
+
+
简介
+
{props.entity.remark || '-'}
+
+
+
二维码
+
+ +
+
+
+
+ + ); +}; + +export default Info; -- Gitee From a140f16a0766272e36e18a0ea7122c83b3657bbe Mon Sep 17 00:00:00 2001 From: SEN Date: Fri, 2 Feb 2024 14:59:20 +0800 Subject: [PATCH 31/35] =?UTF-8?q?delete:=20=E5=8E=BB=E9=99=A4=E6=89=93?= =?UTF-8?q?=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MainLayout/preview/index.tsx | 2 -- src/ts/core/thing/directory.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index a87ac9759..05faa097c 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -61,7 +61,6 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { useEffect(() => { setBodyType(''); const id = command.subscribe((type, flag, ...args: any[]) => { - console.log('实体预览subscribe', type, flag, ...args); if (type != 'preview' || flag != props.flag) return; if (args && args.length > 0) { setEntity(args[0]); @@ -74,7 +73,6 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { }; }, [props]); const renderEntityBodyInfo = (entity: any, children?: React.ReactNode) => { - console.log('children', children); switch (bodyType) { case 'fileSetting': return ; diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index 228e144d9..840d964b8 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -198,7 +198,6 @@ export class Directory extends StandardFileInfo implements ID cnt.push(...this.standard.templates); } } - console.log('store内容', cnt); return this.uniqueBy(cnt, 'id').sort((a, b) => a.metadata.updateTime < b.metadata.updateTime ? 1 : -1, ); -- Gitee From 978f347cb896388a03bf245f8a78bfebe5505684 Mon Sep 17 00:00:00 2001 From: SEN Date: Fri, 2 Feb 2024 15:01:15 +0800 Subject: [PATCH 32/35] =?UTF-8?q?style:=20=E6=A0=BC=E5=BC=8F=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Directory/views/index.tsx | 4 +++- src/components/MainLayout/preview/content/index.tsx | 2 +- src/components/MainLayout/preview/info/index.tsx | 7 ++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/Directory/views/index.tsx b/src/components/Directory/views/index.tsx index c6d0ebb77..303183868 100644 --- a/src/components/Directory/views/index.tsx +++ b/src/components/Directory/views/index.tsx @@ -118,7 +118,9 @@ const DirectoryView: React.FC = (props) => { onBack={() => props.fileOpen(props.preDirectory, true)} onChanged={(t) => props.tagChanged && props.tagChanged(t)}> - ):<>} + ) : ( + <> + )} = (props) => { - const [entity, setEntity] = useState(props.entity); const avatar: model.FileItemShare = parseAvatar(props.entity.icon); return ( <> -- Gitee From 3e795906d7bd56b6bbe0b17aaa191155d4852eeb Mon Sep 17 00:00:00 2001 From: linlh Date: Sat, 3 Feb 2024 13:15:57 +0800 Subject: [PATCH 33/35] =?UTF-8?q?feat:=20=E4=BB=A3=E7=A0=81=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/svg/chevron-up.svg | 3 + public/svg/fileAuth.svg | 5 + public/svg/fileInfo.svg | 8 + public/svg/fileSetting.svg | 5 + .../Common/GlobalComps/typeIcon.tsx | 2 +- .../Common/SegmentContent/index.tsx | 80 ++++---- src/components/Directory/index.tsx | 21 +- src/components/Directory/views/index.tsx | 44 +++-- .../Directory/views/less/list.module.less | 50 ++++- src/components/Directory/views/listMode.tsx | 180 +++++++++++------- src/components/Directory/views/vlistMode.tsx | 9 +- .../preview/content/index.module.less | 71 +++++++ .../MainLayout/preview/content/index.tsx | 38 ++++ src/components/MainLayout/preview/index.tsx | 52 ++++- .../MainLayout/preview/info/index.module.less | 35 ++++ .../MainLayout/preview/info/index.tsx | 112 +++++++++++ src/executor/action.tsx | 7 +- src/pages/Store/index.tsx | 5 +- src/ts/base/model.ts | 29 +++ src/ts/base/schema.ts | 4 + src/ts/core/public/consts.ts | 63 +++++- src/ts/core/public/enums.ts | 20 ++ src/ts/core/public/operates.ts | 53 ++++++ src/ts/core/target/outTeam/storage.ts | 73 ++++++- src/ts/core/target/team/company.ts | 6 +- src/ts/core/thing/directory.ts | 126 ++++++++++-- src/ts/core/thing/fileinfo.ts | 8 +- src/ts/core/thing/standard/index.ts | 46 ++++- 28 files changed, 981 insertions(+), 174 deletions(-) create mode 100644 public/svg/chevron-up.svg create mode 100755 public/svg/fileAuth.svg create mode 100755 public/svg/fileInfo.svg create mode 100755 public/svg/fileSetting.svg create mode 100644 src/components/MainLayout/preview/content/index.module.less create mode 100644 src/components/MainLayout/preview/content/index.tsx create mode 100644 src/components/MainLayout/preview/info/index.module.less create mode 100644 src/components/MainLayout/preview/info/index.tsx diff --git a/public/svg/chevron-up.svg b/public/svg/chevron-up.svg new file mode 100644 index 000000000..1832e4321 --- /dev/null +++ b/public/svg/chevron-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/svg/fileAuth.svg b/public/svg/fileAuth.svg new file mode 100755 index 000000000..c2dbf34f9 --- /dev/null +++ b/public/svg/fileAuth.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/svg/fileInfo.svg b/public/svg/fileInfo.svg new file mode 100755 index 000000000..2e783fe49 --- /dev/null +++ b/public/svg/fileInfo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/svg/fileSetting.svg b/public/svg/fileSetting.svg new file mode 100755 index 000000000..4dd091a1a --- /dev/null +++ b/public/svg/fileSetting.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/Common/GlobalComps/typeIcon.tsx b/src/components/Common/GlobalComps/typeIcon.tsx index 7e1e3165e..483f191f4 100644 --- a/src/components/Common/GlobalComps/typeIcon.tsx +++ b/src/components/Common/GlobalComps/typeIcon.tsx @@ -41,7 +41,7 @@ const TypeIcon = ({ avatar, iconType, size }: TypeIconInfo) => { case '动态': return ; case '目录': - return ; + return ; case '成员目录': return ; case '标准': diff --git a/src/components/Common/SegmentContent/index.tsx b/src/components/Common/SegmentContent/index.tsx index 2573bf8f3..d0655047d 100644 --- a/src/components/Common/SegmentContent/index.tsx +++ b/src/components/Common/SegmentContent/index.tsx @@ -10,6 +10,7 @@ type segmentedTypes = 'icon' | 'table' | 'list'; interface IProps { height?: number | string; descriptions: string; + hiddenSegment?: Boolean; children?: React.ReactNode; // 子组件 onSegmentChanged: (type: segmentedTypes) => void; } @@ -20,6 +21,7 @@ const SegmentContent: React.FC = ({ height, children, descriptions, + hiddenSegment, onSegmentChanged, }: IProps) => { const [segmented, setSegmented] = useStorage('segmented', 'list'); @@ -30,44 +32,46 @@ const SegmentContent: React.FC = ({
{children && children}
- - { - setSegmented(value as segmentedTypes); - onSegmentChanged(value as segmentedTypes); - }} - options={[ - { - value: 'list', - icon: ( - - ), - }, - { - value: 'icon', - icon: ( - - ), - }, - // { - // value: 'table', - // icon: ( - // - // ), - // }, - ]} - /> - + {!hiddenSegment && ( + + { + setSegmented(value as segmentedTypes); + onSegmentChanged(value as segmentedTypes); + }} + options={[ + { + value: 'list', + icon: ( + + ), + }, + { + value: 'icon', + icon: ( + + ), + }, + // { + // value: 'table', + // icon: ( + // + // ), + // }, + ]} + /> + + )} }> {descriptions} diff --git a/src/components/Directory/index.tsx b/src/components/Directory/index.tsx index d0ed2a515..7f6d7bc01 100644 --- a/src/components/Directory/index.tsx +++ b/src/components/Directory/index.tsx @@ -9,7 +9,11 @@ import { cleanMenus } from '@/utils/tools'; * @description: 默认目录 * @return {*} */ -const Directory: React.FC<{ root: IFile }> = ({ root }) => { +const Directory: React.FC<{ + root: IFile; + isStore?: boolean; + isSidebar?: boolean; +}> = ({ root, isStore, isSidebar }) => { const [currentTag, setCurrentTag] = useState('全部'); const [preDirectory, setPreDirectory] = useState(); const [directory, setDirectory] = useState(root); @@ -32,10 +36,10 @@ const Directory: React.FC<{ root: IFile }> = ({ root }) => { /** 加载目录内容 */ const loadContent = (file: IFile, directory: IFile, reload: boolean) => { setLoaded(false); - file.loadContent(reload).then(() => { + file.loadContent(reload, true).then(() => { if (file.key === directory.key) { setCurrentTag('全部'); - setContent(directory.content()); + setContent(directory.content(isStore, isSidebar)); } setLoaded(true); }); @@ -49,11 +53,14 @@ const Directory: React.FC<{ root: IFile }> = ({ root }) => { content={content} currentTag={currentTag} tagChanged={(t) => setCurrentTag(t)} + isStore={isStore} fileOpen={(file) => { - if (file && 'isContainer' in file && file.isContainer) { - setDirectory(file as IFile); - } else { - command.emitter('executor', 'open', file); + if (!isStore) { + if (file && 'isContainer' in file && file.isContainer) { + setDirectory(file as IFile); + } else { + command.emitter('executor', 'open', file); + } } }} preDirectory={preDirectory} diff --git a/src/components/Directory/views/index.tsx b/src/components/Directory/views/index.tsx index 841b46c28..303183868 100644 --- a/src/components/Directory/views/index.tsx +++ b/src/components/Directory/views/index.tsx @@ -21,11 +21,13 @@ interface IProps { focusFile?: IDEntity; rightBars?: ReactNode; height?: number | string; + hiddenSegment?: boolean; currentTag: string; badgeCount?: (tag: string) => number; tagChanged?: (tag: string) => void; fileOpen: (file: IDEntity | undefined, dblclick: boolean) => void; contextMenu: (file?: IDEntity) => MenuProps; + isStore?: boolean; } /** * 存储-文件系统 @@ -86,6 +88,7 @@ const DirectoryView: React.FC = (props) => { selectFiles={props.selectFiles} focusFile={props.focusFile} content={getContent()} + isStore={props.isStore} fileOpen={props.fileOpen} contextMenu={props.contextMenu} /> @@ -95,25 +98,32 @@ const DirectoryView: React.FC = (props) => { return ( <> - setFilter(value)} - menus={props.contextMenu()} - /> - props.fileOpen(props.preDirectory, true)} - onChanged={(t) => props.tagChanged && props.tagChanged(t)}> + {!props.isStore ? ( + <> + setFilter(value)} + menus={props.contextMenu()} + /> + props.fileOpen(props.preDirectory, true)} + onChanged={(t) => props.tagChanged && props.tagChanged(t)}> + + ) : ( + <> + )} {segmented === 'icon' ? ( diff --git a/src/components/Directory/views/less/list.module.less b/src/components/Directory/views/less/list.module.less index bca891c24..2c255791b 100644 --- a/src/components/Directory/views/less/list.module.less +++ b/src/components/Directory/views/less/list.module.less @@ -16,7 +16,8 @@ margin-right: 10px; } -.list_item:hover, .vlist_item:hover { +.list_item:hover, +.vlist_item:hover { background-color: #f1f1f1; } @@ -35,9 +36,54 @@ background-color: @active-background; } - .blank_area { width: 100%; min-height: 160px; max-height: calc(100% - 80px); } +.head { + display: flex; + flex: 1; + justify-content: space-between; + box-sizing: border-box; + padding: 0 10px; + .headItem { + width: 17.5%; + display: flex; + justify-content: left; + align-items: center; + .sort { + display: flex; + margin-left: 5px; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: 10px; + color: rgba(0, 0, 0, 0.4); + } + } + .headItem:first-child { + width: 30%; + } +} +.storeContent { + display: flex; + align-items: center; + min-width: 70%; + div { + width: 25%; + } +} +.edit { + display: flex; + color: #366ef4; + align-items: center; + div{ + display: flex; + align-items: center; + margin-right: 8px; + } + span{ + margin-left: 3px; + } +} diff --git a/src/components/Directory/views/listMode.tsx b/src/components/Directory/views/listMode.tsx index 0c3fe2559..981a09466 100644 --- a/src/components/Directory/views/listMode.tsx +++ b/src/components/Directory/views/listMode.tsx @@ -1,9 +1,14 @@ -import React, { useState } from 'react'; -import { IDEntity } from '@/ts/core'; +import React from 'react'; +import { IDEntity, IDirectory } from '@/ts/core'; import { Badge, Dropdown, List, MenuProps, Tag } from 'antd'; import { showChatTime } from '@/utils/tools'; import css from './less/list.module.less'; import EntityIcon from '@/components/Common/GlobalComps/entityIcon'; +import { UpOutlined, DownOutlined } from '@ant-design/icons'; +import { RiMore2Fill } from 'react-icons/ri'; +import { command } from '@/ts/base'; +import { GoArrowUpRight } from 'react-icons/go'; +import { FaRegCopy } from 'react-icons/fa'; const ListMode = ({ focusFile, @@ -11,84 +16,129 @@ const ListMode = ({ fileOpen, contextMenu, selectFiles, + isStore, }: { content: IDEntity[]; selectFiles: IDEntity[]; focusFile: IDEntity | undefined; fileOpen: (file: IDEntity | undefined, dblclick: boolean) => void; contextMenu: (file?: IDEntity) => MenuProps; + isStore?: boolean; }) => { - const [cxtItem, setCxtItem] = useState(); const getItemClassName = (item: IDEntity) => { if (focusFile?.key === item.key || selectFiles.some((i) => i.key === item.key)) { return css.list_item_select; } return css.list_item; }; + const headList = ['文件', '用户', '归属', '创建时间', '操作']; + const sortConetnt = (type: string) => ( +
+ {type} +
+ + +
+
+ ); + const showContnt = (item: IDEntity) => { + return ( +
+ + +
{showChatTime(item.updateTime)}
+
+
command.emitter('executor', 'open', item)}> + + 打开 +
+
command.emitter('executor', 'copy', item)}> + + 复制 +
+ + + +
+
+ ); + }; return ( - -
e.stopPropagation()}> - { - return ( -
- { - fileOpen(item, false); - }} - onDoubleClick={() => { +
e.stopPropagation()}> + + {headList.map((item) => { + return sortConetnt(item); + })} +
+ ) + } + itemLayout="horizontal" + dataSource={content} + renderItem={(item) => { + return ( +
+ { + fileOpen(item, false); + }} + onDoubleClick={() => { + const directory = item as IDirectory; + const isStorView = location.hash.startsWith('#/store'); + const canIinit = directory.canIinit ?? true; + if (!isStorView || (isStorView && canIinit)) { fileOpen(item, true); - }} - onContextMenu={() => setCxtItem(item)} - actions={[ -
- {showChatTime(item.updateTime)} -
, - ]}> - -
{item.name}
- {item.metadata.sourceId ? ( - 快捷方式 - ) : ( - <> - )} - {item.groupTags - .filter((i) => i.length > 0) - .map((label) => { - return ( - - {label} - - ); - })} - - } - avatar={ - - - - } - description={ -
{item.remark || item.code}
- } - /> -
-
- ); - }} - /> -
setCxtItem(undefined)}>
-
- + } + }} + actions={ + !isStore + ? [ +
+ {showChatTime(item.updateTime)} +
, + ] + : [] + }> + +
{item.name}
+ {item.metadata.sourceId ? ( + 快捷方式 + ) : ( + <> + )} + {item.groupTags + .filter((i) => i.length > 0) + .map((label) => { + return ( + + {label} + + ); + })} + + } + avatar={ + + + + } + description={ +
{item.remark || item.code}
+ } + /> + {isStore && showContnt(item)} + +
+ ); + }} + /> + ); }; export default ListMode; diff --git a/src/components/Directory/views/vlistMode.tsx b/src/components/Directory/views/vlistMode.tsx index 376267f72..9d28bffbc 100644 --- a/src/components/Directory/views/vlistMode.tsx +++ b/src/components/Directory/views/vlistMode.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { IDEntity } from '@/ts/core'; +import { IDEntity, IDirectory } from '@/ts/core'; import { Badge, Dropdown, List, MenuProps, Tag } from 'antd'; import { showChatTime } from '@/utils/tools'; import css from './less/list.module.less'; @@ -51,7 +51,12 @@ const VListMode = ({ fileOpen(item, false); }} onDoubleClick={() => { - fileOpen(item, true); + const directory = item as IDirectory; + const isStorView = location.hash.startsWith('#/store'); + const canIinit = directory.canIinit ?? true; + if (!isStorView || (isStorView && canIinit)) { + fileOpen(item, true); + } }} actions={[
diff --git a/src/components/MainLayout/preview/content/index.module.less b/src/components/MainLayout/preview/content/index.module.less new file mode 100644 index 000000000..42dbe0783 --- /dev/null +++ b/src/components/MainLayout/preview/content/index.module.less @@ -0,0 +1,71 @@ +.content { + padding: 24px; + .head { + display: flex; + justify-content: space-between; + .title { + font-size: 18px; + } + .edit { + display: flex; + justify-content: space-between; + button { + margin-left: 10px; + } + } + } +} + +.seek { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 16px; + + .tag { + display: flex; + .tags_item { + cursor: pointer; + white-space: nowrap; + padding: 4px 12px; + font-size: 12px; + height: 26px; + border-radius: 6px; + background-color: #efefef; + margin-right: 6px; + & > * { + font-size: 12px; + } + .item_count { + color: #2b00ff; + font-style: italic; + transform: scale(0.9); + } + &:hover { + background-color: @active-background; + } + &_active { + cursor: not-allowed; + white-space: nowrap; + border-radius: 6px; + padding: 4px 12px; + font-size: 12px; + height: 26px; + .item_count { + font-style: italic; + transform: scale(0.9); + } + & > * { + font-size: 12px; + color: @text-color-inverse; + } + color: @text-color-inverse; + background-color: @focus-background; + } + } + } + .search { + width: 50%; + max-width: 300px; + } +} diff --git a/src/components/MainLayout/preview/content/index.tsx b/src/components/MainLayout/preview/content/index.tsx new file mode 100644 index 000000000..8f6098ece --- /dev/null +++ b/src/components/MainLayout/preview/content/index.tsx @@ -0,0 +1,38 @@ +import { Button, Input } from 'antd'; +import { SearchOutlined } from '@ant-design/icons'; + +import React from 'react'; +import css from './index.module.less'; + +interface IProps {} + +const PreviewLayout: React.FC = (props) => { + console.log('props', props); + return ( + <> +
+
+
访问权限
+
+ + +
+
+
+
+
全部
+
内设机构
+
群组
+
集群
+
+
+ } /> +
+
+
+
+ + ); +}; + +export default PreviewLayout; diff --git a/src/components/MainLayout/preview/index.tsx b/src/components/MainLayout/preview/index.tsx index 2098b2017..05faa097c 100644 --- a/src/components/MainLayout/preview/index.tsx +++ b/src/components/MainLayout/preview/index.tsx @@ -2,6 +2,7 @@ import ImageView from './image'; import VideoView from './video'; import { IEntity, + IFile, IForm, ISession, ISysFileInfo, @@ -21,7 +22,8 @@ import Directory from '@/components/Directory'; import TaskApproval from '@/executor/tools/task/approval'; import TaskStart from '@/executor/tools/task/start'; import PreviewLayout from './layout'; - +import Content from './content'; +import Info from './info'; const officeExt = ['.md', '.pdf', '.xls', '.xlsx', '.doc', '.docx', '.ppt', '.pptx']; const videoExt = ['.mp4', '.avi', '.mov', '.mpg', '.swf', '.flv', '.mpeg']; @@ -54,7 +56,10 @@ const FilePreview: React.FC<{ file: ISysFileInfo }> = ({ file }) => { const EntityPreview: React.FC<{ flag?: string }> = (props) => { if (!(props.flag && props.flag.length > 0)) return <>; const [entity, setEntity] = useState(); + const [bodyType, setBodyType] = useState(''); + useEffect(() => { + setBodyType(''); const id = command.subscribe((type, flag, ...args: any[]) => { if (type != 'preview' || flag != props.flag) return; if (args && args.length > 0) { @@ -67,9 +72,28 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { command.unsubscribe(id); }; }, [props]); + const renderEntityBodyInfo = (entity: any, children?: React.ReactNode) => { + switch (bodyType) { + case 'fileSetting': + return ; + case 'fileAuth': + return ; + default: + return children; + } + }; - const renderEntityBody = (entity: any, children?: React.ReactNode) => { - return {children && children}; + const renderEntityBody = (entity: any, children?: React.ReactNode, actions?: any[]) => { + return ( + { + setBodyType(key); + }}> + {renderEntityBodyInfo(entity, children)} + + ); }; if (entity && typeof entity != 'string') { @@ -126,6 +150,28 @@ const EntityPreview: React.FC<{ flag?: string }> = (props) => { return ; } } + //数据查看 + if (location.hash.startsWith('#/store')) { + return renderEntityBody( + entity, + , + [ + { + key: 'fileInfo', + label: '详情', + }, + { + key: 'fileAuth', + label: '权限', + }, + { + key: 'fileSetting', + label: '设置', + }, + ], + ); + } + return renderEntityBody(entity); } return <>; diff --git a/src/components/MainLayout/preview/info/index.module.less b/src/components/MainLayout/preview/info/index.module.less new file mode 100644 index 000000000..f1733c449 --- /dev/null +++ b/src/components/MainLayout/preview/info/index.module.less @@ -0,0 +1,35 @@ +.content { + padding: 24px; + .head { + display: flex; + justify-content: space-between; + .title { + font-size: 18px; + } + .edit { + display: flex; + justify-content: space-between; + button { + margin-left: 10px; + } + } + } +} + +.contnt { + margin-top: 16px; + display: flex; + flex-flow: wrap; + .item { + display: flex; + flex-direction: column; + font-size: 14px; + line-height: 22px; + width: 25%; + margin-bottom: 16px; + .item_title { + color: rgba(0, 0, 0, 0.4); + margin-bottom: 16px; + } + } +} diff --git a/src/components/MainLayout/preview/info/index.tsx b/src/components/MainLayout/preview/info/index.tsx new file mode 100644 index 000000000..58dfbe808 --- /dev/null +++ b/src/components/MainLayout/preview/info/index.tsx @@ -0,0 +1,112 @@ +import { Button } from 'antd'; +import React from 'react'; +import css from './index.module.less'; +import { model, parseAvatar, schema, command } from '@/ts/base'; +import QrCode from 'qrcode.react'; +import { formatZhDate } from '@/utils/tools'; +import orgCtrl from '@/ts/controller'; +import EntityIcon from '@/components/Common/GlobalComps/entityIcon'; +import UploadItem from '../../../../executor/tools/uploadItem'; + +import { Theme } from '@/config/theme'; +interface IProps { + entity: schema.XEntity | schema.XTarget; +} + +const Info: React.FC = (props) => { + const avatar: model.FileItemShare = parseAvatar(props.entity.icon); + return ( + <> +
+
+
文件信息
+
+ +
+
+
+
+
图标
+
+ {}} + directory={orgCtrl.user.directory} + /> +
+
+
+
名称
+
{props.entity.name}
+
+
+
类型
+
{props.entity.typeName}
+
+
+
代码
+
{props.entity.code}
+
+
+
归属
+
+ +
+
+ {props.entity.createUser && ( +
+
创建人
+
+ +
+
+ )} +
+
创建时间
+
+ {formatZhDate(props.entity.createTime)} +
+
+
+
更新时间
+
+ {formatZhDate(props.entity.updateTime)} +
+
+
+
简介
+
{props.entity.remark || '-'}
+
+
+
二维码
+
+ +
+
+
+
+ + ); +}; + +export default Info; diff --git a/src/executor/action.tsx b/src/executor/action.tsx index a0124c4c5..82f65dd67 100644 --- a/src/executor/action.tsx +++ b/src/executor/action.tsx @@ -71,6 +71,8 @@ export const executeCmd = (cmd: string, entity: any) => { return onlineChanged(cmd, entity); case 'activate': return activateStorage(entity); + case 'checkDirectory': + return checkDirectory(entity); case 'hslSplit': return videoHslSplit(entity); case 'removeSession': @@ -98,7 +100,10 @@ const directoryRefresh = (dir: IDirectory | IApplication, reload: boolean) => { const activateStorage = (store: IStorage) => { store.activateStorage(); }; - +/** 初始化存储 */ +const checkDirectory = (store: IStorage) => { + store.checkDirectory(); +}; /** 视频切片 */ const videoHslSplit = (file: ISysFileInfo) => { const modal = Modal.confirm({ diff --git a/src/pages/Store/index.tsx b/src/pages/Store/index.tsx index 63399d64b..8703adfca 100644 --- a/src/pages/Store/index.tsx +++ b/src/pages/Store/index.tsx @@ -51,7 +51,7 @@ const FileBrowser: React.FC = () => { if (current === 'disk') { contents.push(orgCtrl.user, ...orgCtrl.user.companys); } else { - contents.push(...current.content()); + contents.push(...current.content(true)); } return contents; }; @@ -64,7 +64,7 @@ const FileBrowser: React.FC = () => { type="link" title="返回" icon={} - onClick={() => setCurrent(current.superior as ITarget)} + onClick={() => setCurrent((current.superior as ITarget) ?? 'disk')} /> )} {current != 'disk' ? ( @@ -90,6 +90,7 @@ const FileBrowser: React.FC = () => { initTags={['全部']} selectFiles={[]} extraTags={true} + hiddenSegment focusFile={focusFile} content={getContent()} currentTag={currentTag} diff --git a/src/ts/base/model.ts b/src/ts/base/model.ts index 1e5090994..2d504592d 100644 --- a/src/ts/base/model.ts +++ b/src/ts/base/model.ts @@ -1549,3 +1549,32 @@ export type comment = { //评论人 PosterUser: XTarget; } +// 草稿 +export type DraftsType = { + // 数据 + typeName: string; + // 关系 + relations: string; + // 办事id + workId: string; + // 备注信息 + contentText: string; + // 办事名称 + name?: string; + // 节点信息 + data: model.InstanceDataModel; +} & Xbase; + +// 标准目录 +export type StandardDirectoryType = { + // 目录名称 + name: string; + // 目录编码 + code: string; + // 排序 + sort: number; + // 内容支持类型 + accept?: string[]; + // 子级目录 + children?: StandardDirectoryType[]; +}; diff --git a/src/ts/base/schema.ts b/src/ts/base/schema.ts index 60809f163..739a9822f 100644 --- a/src/ts/base/schema.ts +++ b/src/ts/base/schema.ts @@ -177,6 +177,10 @@ export type XAuthority = { export type XDirectory = { // 共享用户ID shareId: string; + // 目录支持类型 + accept?: string[]; + // 目录排序标识 + sort?: number; // 目录下的属性 propertys: XProperty[] | undefined; // 目录下的单 diff --git a/src/ts/core/public/consts.ts b/src/ts/core/public/consts.ts index a96955143..7d924cdb6 100644 --- a/src/ts/core/public/consts.ts +++ b/src/ts/core/public/consts.ts @@ -1,5 +1,5 @@ -import { PageModel } from '../../base/model'; -import { TargetType, ValueType } from './enums'; +import { PageModel, StandardDirectoryType } from '../../base/model'; +import { DirectoryType, TargetType, ValueType } from './enums'; /** 资产共享云模块权限Id */ export const orgAuth = { @@ -47,6 +47,65 @@ export const PageAll: PageModel = { limit: (2 << 15) - 1, //ushort.max filter: '', }; +/** 固定标准目录 */ +export const StandardDirectory: StandardDirectoryType[] = [ + { + name: DirectoryType.DataStandard, + code: 'standardData', + sort: 1, + accept: [DirectoryType.Attribute, DirectoryType.Dict, DirectoryType.Species], + children: [ + { + name: DirectoryType.Attribute, + code: 'standardAttribute', + sort: 1, + }, + { + name: DirectoryType.Dict, + code: 'standardDict', + sort: 2, + }, + { name: DirectoryType.Species, code: 'standardSpecies', sort: 3 }, + ], + }, + { + name: DirectoryType.Model, + code: 'standardModel', + sort: 2, + accept: [ + DirectoryType.Form, + DirectoryType.Report, + DirectoryType.Transfer, + DirectoryType.PageTemplate, + ], + children: [ + { + name: DirectoryType.Form, + code: 'standardForm', + sort: 1, + }, + { + name: DirectoryType.Report, + code: 'standardReport', + sort: 2, + }, + { + name: DirectoryType.Transfer, + code: 'standardTransfer', + sort: 3, + }, + { + name: DirectoryType.PageTemplate, + code: 'standardPageTemplate', + sort: 4, + }, + ], + }, + { name: DirectoryType.App, code: 'standardApp', sort: 3 }, + { name: DirectoryType.File, code: 'standardFile', sort: 4 }, + { name: DirectoryType.Code, code: 'standardCode', sort: 5 }, + { name: DirectoryType.Mirror, code: 'standardMirror', sort: 6 }, +]; /** 通用状态信息Map */ export const StatusMap = new Map([ diff --git a/src/ts/core/public/enums.ts b/src/ts/core/public/enums.ts index bebd476bf..7624ba88c 100644 --- a/src/ts/core/public/enums.ts +++ b/src/ts/core/public/enums.ts @@ -89,3 +89,23 @@ export enum FromOrigin { 'Person' = 'Person', 'Group' = 'Group', } + +/** 文件类型 */ +export enum DirectoryType { + /* 一级类目 */ + 'Storage' = '存储资源', + 'DataStandard' = '数据标准', + 'Model' = '业务模型', + 'App' = '应用', + 'File' = '文件', + 'Code' = '代码', + 'Mirror' = '镜像', + /* 二级类目 */ + 'Attribute' = '属性', + 'Species' = '分类', + 'Dict' = '字典', + 'Form' = '表单', + 'Report' = '报表', + 'PageTemplate' = '模板', + 'Transfer' = '迁移', +} diff --git a/src/ts/core/public/operates.ts b/src/ts/core/public/operates.ts index ed11cdfe5..e1f3df44b 100644 --- a/src/ts/core/public/operates.ts +++ b/src/ts/core/public/operates.ts @@ -1,3 +1,4 @@ +import { DirectoryType } from './enums'; /** 实体的操作 */ export const entityOperates = { Open: { @@ -48,6 +49,12 @@ export const entityOperates = { label: '分享二维码', iconType: 'qrcode', }, + CheckDirectory: { + sort: 102, + cmd: 'checkDirectory', + label: '校验文件夹', + iconType: 'update', + }, }; /** 文件支持的操作 */ export const fileOperates = { @@ -224,6 +231,52 @@ export const directoryNew = { directoryOperates.NewPageTemplate, ], }; +/** 目录下新增 */ +export const getDirectoryNew = (accept: DirectoryType[]) => { + const menus = [directoryOperates.NewDir]; + // directoryOperates.NewDir, + // directoryOperates.NewDict, + // directoryOperates.NewSpecies, + // directoryOperates.NewProperty, + // directoryOperates.NewApp, + // directoryOperates.NewForm, + // directoryOperates.NewTransferConfig, + // directoryOperates.NewPageTemplate, + for (const item of accept) { + switch (item) { + case DirectoryType.App: + menus.push(directoryOperates.NewApp); + break; + case DirectoryType.Attribute: + menus.push(directoryOperates.NewProperty); + break; + case DirectoryType.Form: + menus.push(directoryOperates.NewForm); + break; + case DirectoryType.Species: + menus.push(directoryOperates.NewSpecies); + break; + case DirectoryType.Dict: + menus.push(directoryOperates.NewDict); + break; + case DirectoryType.Transfer: + menus.push(directoryOperates.NewTransferConfig); + break; + case DirectoryType.PageTemplate: + menus.push(directoryOperates.NewPageTemplate); + break; + default: + break; + } + } + return { + sort: 0, + cmd: 'new', + label: '新建更多', + iconType: 'new', + menus: menus, + }; +}; /** 新建仓库 */ export const newWarehouse = { diff --git a/src/ts/core/target/outTeam/storage.ts b/src/ts/core/target/outTeam/storage.ts index 391aba461..891c439e9 100644 --- a/src/ts/core/target/outTeam/storage.ts +++ b/src/ts/core/target/outTeam/storage.ts @@ -1,9 +1,12 @@ -import { OperateModel } from '@/ts/base/model'; +import { IDirectory } from '@/ts/core'; +import { OperateModel, StandardDirectoryType } from '@/ts/base/model'; import { kernel, schema } from '../../../base'; import { OperateType, TargetType, entityOperates, targetOperates } from '../../public'; import { IBelong } from '../base/belong'; import { ITarget, Target } from '../base/target'; import { ISession } from '../../chat/session'; +import { IFile } from '../../thing/fileinfo'; +import { StandardDirectory } from '../../public/consts'; /** 存储资源接口 */ export interface IStorage extends ITarget { @@ -11,6 +14,8 @@ export interface IStorage extends ITarget { isActivate: boolean; /** 激活存储 */ activateStorage(): Promise; + /** 初始化存储 */ + checkDirectory(): void; } export class Storage extends Target implements IStorage { @@ -23,6 +28,11 @@ export class Storage extends Target implements IStorage { get isMyTeam(): boolean { return true; } + get groupTags(): string[] { + const activeTag = this.isActivate ? '已激活' : '未激活'; + const gtags: string[] = [...super.groupTags, activeTag]; + return gtags.filter((item) => item !== this.typeName); + } async exit(): Promise { if (this.metadata.belongId !== this.space.id) { if (await this.removeMembers([this.user.metadata])) { @@ -48,6 +58,8 @@ export class Storage extends Target implements IStorage { } if (!this.isActivate) { operates.push(targetOperates.Activate); + } else { + operates.push(entityOperates.CheckDirectory); } return operates; } @@ -72,11 +84,16 @@ export class Storage extends Target implements IStorage { if (res.success) { this.space.updateMetadata(res.data); this.space.sendTargetNotity(OperateType.Update); + this.checkDirectory(); } return res.success; } return false; } + async checkStorage() { + this.checkDirectory(); + return true; + } async deepLoad(reload: boolean = false): Promise { if (this.hasRelationAuth()) { await this.loadIdentitys(reload); @@ -84,6 +101,18 @@ export class Storage extends Target implements IStorage { } this.directory.loadDirectoryResource(reload); } + content(store?: boolean): IFile[] { + if (!this.isActivate) { + return []; + } + const items = this.space.directory.children.sort((a, b) => { + const curr = a.metadata.sort ?? a.metadata.updateTime; + const next = b.metadata.sort ?? b.metadata.updateTime; + return curr > next ? 1 : -1; + }); + return store ? items : []; + } + override async pullMembers( members: schema.XTarget[], notity?: boolean, @@ -93,4 +122,46 @@ export class Storage extends Target implements IStorage { } return await super.pullMembers(members, notity); } + async checkDirectory() { + if (this.isActivate) { + await this.space.directory.loadContent(true); + await this.space.directory.standard.loadDirectorys(true); + this.creatStandardDirectory(this.space.directory, StandardDirectory); + } + } + async creatStandardDirectory( + directory: IDirectory, + standardDirectorys: StandardDirectoryType[], + ) { + if (standardDirectorys.length > 0) { + for (const dirItem of standardDirectorys) { + //若 已存在目标文件夹,禁止创建 + if (!directory.children.find((child) => child.code === dirItem.code)) { + const params = { + name: dirItem.name, + code: dirItem.code, + sort: dirItem.sort, + accept: dirItem.accept ?? [dirItem.name], + typeName: '目录', + directoryId: directory.id, + } as schema.XDirectory; + directory.create(params).then((res) => { + console.log('创建文件:', dirItem.name); + if (dirItem.children && dirItem.children.length > 0 && res?.id) { + setTimeout(() => { + const newDirectory = directory.children.find( + (child) => child.id === res.id, + ); + if (newDirectory) { + this.creatStandardDirectory(newDirectory, dirItem.children!); + } + }, 300); + } + }); + } else { + console.warn('跳过创建,已存在文件夹:', dirItem.name); + } + } + } + } } diff --git a/src/ts/core/target/team/company.ts b/src/ts/core/target/team/company.ts index b072a792f..17942f4c8 100644 --- a/src/ts/core/target/team/company.ts +++ b/src/ts/core/target/team/company.ts @@ -249,7 +249,11 @@ export class Company extends Belong implements ICompany { return operates; } - content(): IFile[] { + content(isStore?: boolean): IFile[] { + if (isStore) { + return this.storages.filter((i) => i.isMyTeam); + } + return [ ...this.groups, ...this.departments, diff --git a/src/ts/core/thing/directory.ts b/src/ts/core/thing/directory.ts index e91850768..e21f7cfda 100644 --- a/src/ts/core/thing/directory.ts +++ b/src/ts/core/thing/directory.ts @@ -1,3 +1,5 @@ +import { getDirectoryNew } from './../public/operates'; +import { DirectoryType } from './../public/enums'; import { common, model, schema } from '../../base'; import { directoryNew, @@ -26,6 +28,8 @@ export interface IDirectory extends IStandardFileInfo { directoryId: string; /** 目录下标准类 */ standard: StandardFiles; + /** 目录下支持的标准类 */ + accept: DirectoryType[]; /** 当前加载目录的用户 */ target: ITarget; /** 资源类 */ @@ -39,13 +43,15 @@ export interface IDirectory extends IStandardFileInfo { /** 任务发射器 */ taskEmitter: common.Emitter; /** 目录下的内容 */ - content(store?: boolean): IFile[]; + content(store?: boolean, isSidebar?: boolean): IFile[]; /** 创建子目录 */ create(data: schema.XDirectory): Promise; /** 目录下的文件 */ files: ISysFileInfo[]; /** 是否快捷方式 */ readonly isShortcut: boolean; + /** 是否可进入子级 */ + readonly canIinit: boolean; /** 加载模板配置 */ loadAllTemplate(reload?: boolean): Promise; /** 加载代码仓库配置 */ @@ -84,10 +90,12 @@ export class Directory extends StandardFileInfo implements ID _parent ?? (_target as unknown as IDirectory), _target.resource.directoryColl, ); + this.accept = (_metadata.accept as DirectoryType[]) ?? []; this.parent = _parent; this.taskEmitter = new common.Emitter(); this.standard = new StandardFiles(this); } + accept: DirectoryType[]; standard: StandardFiles; taskEmitter: common.Emitter; parent: IDirectory | undefined; @@ -136,26 +144,87 @@ export class Directory extends StandardFileInfo implements ID get resource(): DataResource { return this.target.resource; } - content(store: boolean = false): IFile[] { - const cnt: IFile[] = [...this.children]; + get canIinit(): boolean { + return this.children.length > 0; + } + content(store: boolean = false, isSidebar: boolean = true): IFile[] { + console.log( + this.name, + '文件夹展示是否数据展示:', + store, + '----是否侧边栏:', + isSidebar, + '----支持类型:', + this.accept, + ); + const cnt: IFile[] = []; if (this.target.session.isMyChat || this.target.hasRelationAuth()) { - cnt.push(...this.files); - cnt.push(...this.standard.forms); - cnt.push(...this.standard.applications); - cnt.push(...this.standard.propertys); - cnt.push(...this.standard.specieses); - cnt.push(...this.standard.transfers); - cnt.push(...this.standard.templates); - cnt.push(...this.standard.repository); + if (store && this.accept.length > 0) { + if (isSidebar) { + cnt.push(...this.children); + } else { + for (const typeItem of this.accept) { + switch (typeItem) { + case DirectoryType.App: + cnt.push(...this.standard.applications); + break; + case DirectoryType.Species: + cnt.push(...this.standard.specieses); + break; + case DirectoryType.File: + cnt.push(...this.files); + break; + case DirectoryType.Attribute: + cnt.push(...this.standard.propertys); + break; + case DirectoryType.Transfer: + cnt.push(...this.standard.transfers); + break; + case DirectoryType.PageTemplate: + cnt.push(...this.standard.templates); + break; + case DirectoryType.Form: + cnt.push(...this.standard.forms); + break; + case DirectoryType.Report: + // cnt.push(...this.standard.report); + break; + default: + break; + } + } + for (const childrenDir of this.children) { + cnt.push(...childrenDir.content(store, isSidebar)); + } + } + } else { + cnt.push(...this.files); + cnt.push(...this.standard.forms); + cnt.push(...this.standard.applications); + cnt.push(...this.standard.propertys); + cnt.push(...this.standard.specieses); + cnt.push(...this.standard.transfers); + cnt.push(...this.standard.templates); + cnt.push(...this.standard.repository); + } } - return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); + return this.uniqueBy(cnt, 'id').sort((a, b) => + a.metadata.updateTime < b.metadata.updateTime ? 1 : -1, + ); } - async loadContent(reload: boolean = false): Promise { - await this.loadFiles(reload); - await this.standard.loadStandardFiles(reload); + async loadContent(reload: boolean = false, isDeep = false): Promise { + if (this.accept.length == 0 || this.accept.includes(DirectoryType.File)) { + await this.loadFiles(reload); + } + await this.standard.loadStandardFiles(reload, this.accept); if (reload) { await this.loadDirectoryResource(reload); } + if (isDeep) { + for (const childrenDir of this.children) { + await childrenDir.loadContent(reload, isDeep); + } + } return true; } override async copy(destination: IDirectory): Promise { @@ -224,6 +293,7 @@ export class Directory extends StandardFileInfo implements ID const result = await this.resource.directoryColl.insert({ ...data, typeName: '目录', + accept: this.accept, directoryId: this.id, }); if (result) { @@ -247,7 +317,10 @@ export class Directory extends StandardFileInfo implements ID } return this.files; } - async createFile(file: Blob, p?: OnProgress): Promise { + async createFile( + file: Blob & { name: string }, + p?: OnProgress, + ): Promise { while (this.taskList.filter((i) => i.finished < i.size).length > 2) { await sleep(1000); } @@ -325,15 +398,16 @@ export class Directory extends StandardFileInfo implements ID directoryOperates.TaskList, directoryOperates.Refesh, ); + const _directoryNew = getDirectoryNew(this.accept); if (this.target.hasRelationAuth()) { if (this.name.includes('业务')) { operates.push({ - ...directoryNew, + ..._directoryNew, menus: [...directoryNew.menus, directoryOperates.Business], }); } else if (this.name.includes('标准')) { operates.push({ - ...directoryNew, + ..._directoryNew, menus: [...directoryNew.menus, directoryOperates.Standard], }); } else { @@ -348,7 +422,7 @@ export class Directory extends StandardFileInfo implements ID if (this.target.hasRelationAuth()) { operates.push(directoryOperates.Shortcut); } - operates.push(...super.operates()); + // operates.push(...super.operates()); } else { operates.push(entityOperates.Open); } @@ -421,4 +495,18 @@ export class Directory extends StandardFileInfo implements ID directoryId: this.id, }); } + uniqueBy(arr: T[], key: K): T[] { + const result = []; + const map = new Map(); + + for (const item of arr) { + const keyValue = item[key]; + if (!map.has(keyValue)) { + map.set(keyValue, true); + result.push(item); + } + } + + return result; + } } diff --git a/src/ts/core/thing/fileinfo.ts b/src/ts/core/thing/fileinfo.ts index 81eba58b4..6de56aebf 100644 --- a/src/ts/core/thing/fileinfo.ts +++ b/src/ts/core/thing/fileinfo.ts @@ -49,9 +49,9 @@ export interface IFileInfo extends IEntity { */ move(destination: IDirectory): Promise; /** 加载文件内容 */ - loadContent(reload?: boolean): Promise; + loadContent(reload?: boolean, isDeep?: boolean): Promise; /** 目录下的内容 */ - content(args?: boolean): IFile[]; + content(...args: any): IFile[]; /** 缓存用户数据 */ cacheUserData(notify?: boolean): Promise; } @@ -146,8 +146,8 @@ export abstract class FileInfo return success; } - async loadContent(reload: boolean = false): Promise { - return await sleep(reload ? 10 : 0); + async loadContent(reload: boolean = false, isDeep: boolean = false): Promise { + return await sleep(reload || isDeep ? 10 : 0); } content(): IFile[] { return []; diff --git a/src/ts/core/thing/standard/index.ts b/src/ts/core/thing/standard/index.ts index bcb521033..18c215f0a 100644 --- a/src/ts/core/thing/standard/index.ts +++ b/src/ts/core/thing/standard/index.ts @@ -1,3 +1,4 @@ +import { DirectoryType } from './../../public/enums'; import { model, schema } from '../../../base'; import { Directory, IDirectory } from '../directory'; import { IStandard } from '../fileinfo'; @@ -65,15 +66,42 @@ export class StandardFiles { ...this.repository, ]; } - async loadStandardFiles(reload: boolean = false): Promise { - await Promise.all([ - this.loadForms(reload), - this.loadTransfers(reload), - this.loadPropertys(reload), - this.loadSpecieses(reload), - this.loadTemplates(reload), - this.loadRepository(reload), - ]); + async loadStandardFiles( + reload: boolean = false, + accept: DirectoryType[], + ): Promise { + let waitPromises: Promise[] = []; + if (accept.length > 0) { + for (const type of accept) { + switch (type) { + case DirectoryType.Form: + waitPromises.push(this.loadForms(reload)); + break; + case DirectoryType.Transfer: + waitPromises.push(this.loadTransfers(reload)); + break; + case DirectoryType.Attribute: + waitPromises.push(this.loadPropertys(reload)); + break; + case DirectoryType.Species: + waitPromises.push(this.loadSpecieses(reload)); + break; + case DirectoryType.PageTemplate: + waitPromises.push(this.loadTemplates(reload)); + break; + } + } + } else { + waitPromises = [ + this.loadForms(reload), + this.loadTransfers(reload), + this.loadPropertys(reload), + this.loadSpecieses(reload), + this.loadTemplates(reload), + this.loadRepository(reload), + ]; + } + await Promise.all(waitPromises); return this.standardFiles; } async loadForms(reload: boolean = false): Promise { -- Gitee From 8eac2a1caa7a8baca0d25451e07d982b5593b7a0 Mon Sep 17 00:00:00 2001 From: laokai <466256830@qq.com> Date: Mon, 5 Feb 2024 14:03:51 +0800 Subject: [PATCH 34/35] =?UTF-8?q?=E7=B1=BB=E7=AD=9B=E9=80=89=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkForm/Design/config/form.tsx | 51 ++++- .../formRule/filter/builder/conditionTree.tsx | 186 ++++++++++++++++++ .../filter/builder/filterCondition.tsx | 135 +++++++++++++ .../config/formRule/filter/builder/index.less | 57 ++++++ src/executor/open/form/index.tsx | 16 +- .../tools/editModal/formSelectModal.tsx | 13 +- src/ts/base/schema.ts | 1 + src/ts/core/thing/standard/form.ts | 7 +- 8 files changed, 444 insertions(+), 22 deletions(-) create mode 100644 src/components/DataStandard/WorkForm/Design/config/formRule/filter/builder/conditionTree.tsx create mode 100644 src/components/DataStandard/WorkForm/Design/config/formRule/filter/builder/filterCondition.tsx create mode 100644 src/components/DataStandard/WorkForm/Design/config/formRule/filter/builder/index.less diff --git a/src/components/DataStandard/WorkForm/Design/config/form.tsx b/src/components/DataStandard/WorkForm/Design/config/form.tsx index abc1fe495..4a00ce47c 100644 --- a/src/components/DataStandard/WorkForm/Design/config/form.tsx +++ b/src/components/DataStandard/WorkForm/Design/config/form.tsx @@ -6,7 +6,7 @@ import React, { useEffect, useState } from 'react'; import CustomBuilder from './formRule/filter/builder'; import { FieldInfo } from 'typings/globelType'; import useAsyncLoad from '@/hooks/useAsyncLoad'; -import SpeciesList from './formRule/filter/tags/speciesList'; +import FilterCondition from './formRule/filter/builder/filterCondition'; interface IAttributeProps { current: IForm; @@ -15,6 +15,10 @@ interface IAttributeProps { const FormConfig: React.FC = ({ notifyEmitter, current }) => { const [fields, setFields] = useState<(FieldInfo & { fieldType?: string })[]>([]); + const [speciesTreeData, setSpeciesTreeData] = useState([]); + const [conditionText, setConditionText] = useState(current.metadata.options?.dataRange!['filterDisplay'] ??'[]'); + const [speciesText, setSpeciesText] = useState(current.metadata.options?.dataRange!['speciesDisplay'] ?? '{}'); + const [loaded] = useAsyncLoad(async () => { const resultFields = await current.loadFields(); const ss = resultFields.map((a) => { @@ -99,9 +103,31 @@ const FormConfig: React.FC = ({ notifyEmitter, current }) => { }, ...(ss as FieldInfo[]), ]); - }, [current]); - const [conditionText, setConditionText] = useState('[]'); + const speciesArr = ss.filter((a) => a.fieldType === '分类型'); + const _treeData: any[] = speciesArr.map((item, index) => { + const obj: any = { + ...item, + value: item.id, + title: item.caption, + tempId: String(index), + children: [] + } + const dataSource = item?.lookup?.dataSource ?? []; + obj['children'] = dataSource.map((it, inx) => { + return { + ...it, + title: it.text, + tempId: String(index) + '-' + String(inx), + parentId: obj.value, + parentTitle: obj.title + } + }) + return obj; + }) + setSpeciesTreeData(_treeData) + + }, [current]); const notityAttrChanged = () => { notifyEmitter.changCallback('form'); @@ -112,6 +138,10 @@ const FormConfig: React.FC = ({ notifyEmitter, current }) => { current.metadata.options!.dataRange!['filterDisplay'] = text; }; + const onFilterConditionChange = (value: any) => { + current.metadata.options!.dataRange!['speciesDisplay'] = JSON.stringify(value); + } + useEffect(() => { if (!current.metadata.options) { current.metadata.options = { itemWidth: 300 }; @@ -125,7 +155,12 @@ const FormConfig: React.FC = ({ notifyEmitter, current }) => { if (current.metadata.options.dataRange.filterDisplay) { setConditionText(current.metadata.options?.dataRange['filterDisplay']); } + if (current.metadata.options.dataRange.speciesDisplay) { + setSpeciesText(current.metadata.options?.dataRange['speciesDisplay']); + } + }, [current]); + return ( <>
= ({ notifyEmitter, current }) => { /> } + render={() => + loaded && ( + + ) + } /> diff --git a/src/components/DataStandard/WorkForm/Design/config/formRule/filter/builder/conditionTree.tsx b/src/components/DataStandard/WorkForm/Design/config/formRule/filter/builder/conditionTree.tsx new file mode 100644 index 000000000..0fd892763 --- /dev/null +++ b/src/components/DataStandard/WorkForm/Design/config/formRule/filter/builder/conditionTree.tsx @@ -0,0 +1,186 @@ +import React, { useEffect, useState } from 'react'; +import type { MenuProps } from 'antd'; +import { Select, Dropdown, Button, TreeSelect } from 'antd'; +import { CloseOutlined, PlusOutlined } from '@ant-design/icons'; +import useObjectUpdate from '@/hooks/useObjectUpdate'; +import message from '@/utils/message'; + +import './index.less' + +interface treeOptionsType { + value: string; + title: string; + children?: treeOptionsType[]; +} + +interface conditionType { + type: string; + value: string[]; +} + +interface conditionGroupType { + relation: string; + type: string; + isTop?: Boolean; + _tempId?: string; + children: (conditionType | conditionGroupType )[]; +} + +interface IProps { + conditionData: conditionGroupType; + options: treeOptionsType[]; + _tempId?: string; + onDelete: Function; + onChange: Function; +} + +const ConditionTree: React.FC = (props) => { + const [conditionData, setConditionData] = useState(props.conditionData); + const [key, forceUpdate] = useObjectUpdate(conditionData); + + useEffect(() => { + setConditionData(props.conditionData) + }, [props.conditionData]) + + const handleChange = (value: string) => { + conditionData.relation = value; + forceUpdate(); + props.onChange(); + }; + + const getEmptyData = (type: string, _tempId: string) => { + if(type == 'group'){ + return { relation: 'and', type: 'group', children: [], _tempId } + } else { + return { type: 'condition', value: [], _tempId } + } + } + + const findNodeById = (tree:any, id:string) => { + for (const node of tree) { + if (node.value === id) { + return node; + } + if (node.children && node.children.length > 0) { + const childNode: any = findNodeById(node.children, id); + if (childNode) { + return childNode; + } + } + } + return null; + } + + const items: MenuProps['items'] = [ + { + key: '1', + label: ( + + ), + }, + { + key: '2', + label: ( + + ), + } + ]; + + if(!props.conditionData || !props.conditionData.relation){ + return <> + } + + return ( +
+
+ {!conditionData?.isTop &&
+
} +
+