diff --git a/src/api/doc/space.ts b/src/api/doc/space.ts index fbc3ff2..219160e 100644 --- a/src/api/doc/space.ts +++ b/src/api/doc/space.ts @@ -74,6 +74,22 @@ export function doDelSpace(uid:string,data?: any){ }); } +/** + * 重命名 + */ +export function spaceMatterRename(uid:string,data?: any){ + return request({ + url: '/hxpan/api/space/rename', + method: 'post', + headers: { + 'Identifier':uid, + 'Content-Type': 'application/x-www-form-urlencoded' + }, + data: data + }); +} + + /** * 删除文件或目录 */ diff --git a/src/components/DesignForm/assembly/index.ts b/src/components/DesignForm/assembly/index.ts index a896a3c..1d8c278 100644 --- a/src/components/DesignForm/assembly/index.ts +++ b/src/components/DesignForm/assembly/index.ts @@ -1063,6 +1063,8 @@ export default [ icon: 'sliders', iconFont: 'fa-sliders', control: { + range:[], + multiple: '', }, config: {}, styles: { diff --git a/src/components/DesignForm/formControlPropertiNew.vue b/src/components/DesignForm/formControlPropertiNew.vue index 086cc61..6f4cdfb 100644 --- a/src/components/DesignForm/formControlPropertiNew.vue +++ b/src/components/DesignForm/formControlPropertiNew.vue @@ -13,6 +13,8 @@ import validateInt from "./validateInt"; import { ValidateTextTypes } from "@/components/DesignForm/validateText"; import { ElMessage } from "element-plus"; import { formatNumber } from "@/api/DesignForm/utils"; +import { getOrgTreeList } from "@/api/hr/org/index"; +import { orgInfo } from "@/api/hr/org/type"; import { PublicAtrr, formStruct, @@ -833,6 +835,22 @@ const attrList = computed(() => { vIf: state.isSearch, vShow: ["lowcodeImage"], }, + { + label: "数据范围", + value: config.orgCentent, + path: "config.orgCentent", + type: "orgCentent_range", + vIf: state.isSearch, + vShow: ["orgCentent"], + }, + { + label: "是否多选", + value: config.orgCentent, + path: "config.orgCentent", + type: "orgCentent_Multiple", + vIf: state.isSearch, + vShow: ["orgCentent"], + }, /* { label: "添加时间水印", value: config.lowcodeImage, @@ -2048,6 +2066,8 @@ watch( controlData.value.control.fillRoles.child[0].id = uuidv4() .replaceAll("-", "") .toString(); + }else if(controlData.value.type === "orgCentent"){ + haveOrgTreeInfo() } //实现关联表单设置可选字段中没有当前字段效果 start // console.log(controlData.value.name) @@ -2086,6 +2106,34 @@ watch( //实现关联表单设置可选字段中没有当前字段效果 end } ); + + +const orgTreeProps = { + children: "child", + label: "name", +}; //行政组织树对照值 + + +const orgCententRange = ref(); +function haveOrgTreeInfo() { + //orgTreeLoading.value = true; + getOrgTreeList({ orgid: 309 }) + .then(({ data }) => { + console.log("行政组织树对照值", data); + + + + orgCententRange.value = data; + + console.log(orgCententRange.value) + }) + .finally(() => { + //orgTreeLoading.value = false; + }); +} + + + //轮播图图片上传成功钩子 function carouselImgUploadSuccess( response: any, @@ -4404,6 +4452,30 @@ const aiAgentList = ref([ + + + + + + + + + + + + + + + diff --git a/src/components/DesignForm/public/expand/org.vue b/src/components/DesignForm/public/expand/org.vue index 0a429af..2cf908b 100644 --- a/src/components/DesignForm/public/expand/org.vue +++ b/src/components/DesignForm/public/expand/org.vue @@ -11,6 +11,7 @@ const props = withDefaults( defineProps<{ modelValue?: string; disabled?: boolean; + data?: Object; }>(), {} ); @@ -20,13 +21,33 @@ const emits = defineEmits<{ const value = computed({ get: () => { if (props.modelValue != "" && props.modelValue != undefined) { - return props.modelValue * 1; + if(hasComma(props.modelValue)||multiple){ + return commaStringToNumberArray(props.modelValue) + }else{ + return props.modelValue * 1; + } } else { return props.modelValue; } }, set: (newVal: any) => { - emits("update:modelValue", newVal); + + //console.log(newVal) + if(isArray(newVal)){ + let str = arrayToCommaString(newVal) + //console.log(2) + //console.log(str) + emits("update:modelValue", str); + }else{ + //console.log(1) + //console.log(newVal) + emits("update:modelValue", newVal); + } + + + + + // let newValJson:criteriaForPeopleList[] = JSON.parse(newVal) // if(newValJson.length > 0){ // let userAry = new Array @@ -43,6 +64,62 @@ const value = computed({ // } }, }); + +function hasComma(str: any) { + // 检查输入是否为字符串类型 + if (typeof str !== 'string') { + return false + } + + // 使用indexOf检查是否包含逗号 + // 如果存在逗号,返回true;否则返回false + return str.indexOf(',') !== -1; +} + +function commaStringToNumberArray(str: string) { + // 检查输入是否为字符串 + if (typeof str !== 'string') { + throw new Error('输入必须是字符串'); + } + + // 处理空字符串的情况 + if (str.trim() === '') { + return []; + } + + // 按逗号分割字符串,处理可能的空格,并转换为数字 + return str.split(',').map(item => { + // 去除前后空格 + const trimmed = item.trim(); + // 转换为数字 + const number = Number(trimmed); + + // 检查是否为有效数字 + if (isNaN(number)) { + throw new Error(`无法将 "${trimmed}" 转换为有效数字`); + } + + return number; + }); +} +function isArray(variable: any) { + // 现代浏览器推荐使用的方法 + if (typeof Array.isArray === 'function') { + return Array.isArray(variable); + } else { + // 兼容旧环境的判断方式 + return Object.prototype.toString.call(variable) === '[object Array]'; + } +} +function arrayToCommaString(numbers: any[]) { + // 检查输入是否为数组 + if (!Array.isArray(numbers)) { + throw new Error('输入必须是一个数组'); + } + + // 使用join方法将数组元素用逗号连接 + return numbers.join(','); +} const orgTreeList = ref(); const orgTreeLoading = ref(false); //加载行政组织树 const orgTreeProps = { @@ -55,7 +132,27 @@ function haveOrgTreeInfo() { getOrgTreeList({ orgid: 309 }) .then(({ data }) => { console.log("行政组织树对照值", data); - orgTreeList.value = data; + + //liwenxuan 250916 start + + // 目标ID数组(需保留的核心节点ID)自动忽略id数组中为其他id子节点的id + const targetIds = props.data.control.range + console.log(targetIds) + if(targetIds&&targetIds.length>0){ + // 执行过滤 + const filteredTree = filterOrganizationTree(data, targetIds); + orgTreeList.value = filteredTree + }else{ + orgTreeList.value = data; + } + + + //liwenxuan 250916 end + + + + + }) .finally(() => { orgTreeLoading.value = false; @@ -72,6 +169,145 @@ onMounted(() => { haveOrgTreeInfo(); }); }); + + +/** + * 过滤组织架构树:仅保留「顶层目标ID」节点、其所有祖先节点和子孙节点 + * (顶层目标ID:目标数组中无其他ID是其祖先的ID,子节点ID会被自动忽略) + * @param {Array} originalTree - 原始组织架构树形结构(顶层为数组) + * @param {Array} targetIds - 目标节点ID数组(可能包含子节点ID) + * @returns {Array} 过滤后的组织架构树 + */ +function filterOrganizationTree(originalTree: orgInfo[], targetIds: any) { + // 1. 构建「节点ID→节点」映射表,方便快速查找父/子节点 + const nodeMap = new Map(); + buildNodeMap(originalTree, nodeMap); + + // 2. 预处理目标ID:过滤掉「是其他目标ID子节点」的ID,仅保留顶层目标ID + const topTargetIds = filterChildTargetIds(targetIds, nodeMap); + if (topTargetIds.length === 0) { + console.warn("警告:所有目标ID无效或均为其他目标ID的子节点,返回空树"); + return []; + } + + // 3. 收集所有需保留的节点ID(顶层目标ID + 所有祖先ID + 所有子孙ID) + const keepIds = collectKeepIds(topTargetIds, nodeMap); + + // 4. 递归过滤原始树,仅保留需保留的节点 + const filteredTree = filterTreeNodes(originalTree, keepIds); + + return filteredTree; +} + +/** + * 辅助函数1:遍历树形结构,构建「节点ID→节点」映射表 + * @param {Array} nodes - 当前层级的节点数组(顶层/子节点数组) + * @param {Map} nodeMap - 待构建的节点映射表 + */ +function buildNodeMap(nodes: any[], nodeMap: Map) { + if (!nodes || !Array.isArray(nodes)) return; + + nodes.forEach(node => { + nodeMap.set(node.id, node); + // 递归处理子节点(兼容child为null的情况) + buildNodeMap(Array.isArray(node.child) ? node.child : [], nodeMap); + }); +} + +/** + * 辅助函数2:预处理目标ID数组,过滤掉「是其他目标ID子节点」的ID + * @param {Array} targetIds - 原始目标ID数组 + * @param {Map} nodeMap - 节点映射表 + * @returns {Array} 仅包含顶层目标ID的数组(无父节点在目标数组内) + */ +function filterChildTargetIds(targetIds: any[], nodeMap: Map) { + if (!targetIds || !Array.isArray(targetIds)) return []; + + // 先过滤掉不存在于映射表中的无效ID + const validTargetIds = targetIds.filter(id => nodeMap.has(id)); + if (validTargetIds.length <= 1) return validTargetIds; // 仅1个有效ID,直接返回 + + // 过滤逻辑:若ID的祖先链中存在其他有效目标ID,则视为子节点ID,需排除 + return validTargetIds.filter(currentId => { + let parentId = nodeMap.get(currentId).superior; + // 向上追溯所有祖先,判断是否有祖先在有效目标ID中 + while (parentId !== undefined && nodeMap.has(parentId)) { + if (validTargetIds.includes(parentId)) { + console.log(`提示:ID ${currentId} 是目标ID ${parentId} 的子节点,已忽略`); + return false; // 是其他目标ID的子节点,排除 + } + parentId = nodeMap.get(parentId).superior; // 继续向上追溯 + } + return true; // 无祖先在目标数组内,保留为顶层目标ID + }); +} + +/** + * 辅助函数3:收集所有需保留的节点ID(顶层目标ID + 所有祖先ID + 所有子孙ID) + * @param {Array} topTargetIds - 预处理后的顶层目标ID数组 + * @param {Map} nodeMap - 节点映射表 + * @returns {Set} 需保留的节点ID集合(去重) + */ +function collectKeepIds(topTargetIds: any[], nodeMap: Map) { + const keepIds = new Set(); + + topTargetIds.forEach((targetId: unknown) => { + const targetNode = nodeMap.get(targetId); + + // 1. 保留顶层目标节点自身 + keepIds.add(targetId); + + // 2. 向上追溯:保留所有祖先节点(直到顶层节点) + let parentId = targetNode.superior; + while (parentId !== undefined && nodeMap.has(parentId)) { + keepIds.add(parentId); + parentId = nodeMap.get(parentId).superior; + } + + // 3. 向下递归:保留所有子孙节点(子→孙→曾孙...) + collectDescendants(targetNode.child, nodeMap, keepIds); + }); + + return keepIds; +} + +/** + * 辅助函数4:递归收集某个节点的所有子孙节点ID + * @param {Array} childNodes - 当前节点的子节点数组 + * @param {Map} nodeMap - 节点映射表 + * @param {Set} keepIds - 需保留的ID集合 + */ +function collectDescendants(childNodes: any[], nodeMap: any, keepIds: Set) { + if (!Array.isArray(childNodes)) return; + + childNodes.forEach(childNode => { + keepIds.add(childNode.id); + collectDescendants(childNode.child, nodeMap, keepIds); // 递归收集子节点的子节点 + }); +} + +/** + * 辅助函数5:递归过滤树形节点,仅保留在keepIds中的节点 + * @param {Array} nodes - 当前层级的节点数组 + * @param {Set} keepIds - 需保留的节点ID集合 + * @returns {Array} 过滤后的节点数组 + */ +function filterTreeNodes(nodes: any[], keepIds: Set) { + if (!Array.isArray(nodes) || !keepIds) return []; + + return nodes.reduce((filtered, node) => { + if (keepIds.has(node.id)) { + // 深拷贝节点(避免修改原始数据),并递归过滤子节点 + const clonedNode = { ...node }; + clonedNode.child = filterTreeNodes(Array.isArray(clonedNode.child) ? clonedNode.child : [], keepIds); + filtered.push(clonedNode); + } + return filtered; + }, []); +} + +const multiple = props.data.control.multiple=='1' + diff --git a/src/store/modules/orgMember.ts b/src/store/modules/orgMember.ts index 5cc4dc1..0d1bdce 100644 --- a/src/store/modules/orgMember.ts +++ b/src/store/modules/orgMember.ts @@ -1,33 +1,35 @@ import { defineStore } from 'pinia' import { ref} from 'vue'; import request from "@/utils/request"; +import { id } from 'element-plus/es/locale'; export const useOrgMemberStore = defineStore('orgMember', () => { interface OrgMemberItem { id: string; - label: string; - children?:OrgMemberItem[]; + name: string; + child?:OrgMemberItem[]; } const listMap = ref>({}) - const dataTree = ref({ id: '', label: '', children: [] }) + const dataTree = ref({ id: '', name: '', child: [] }) async function init() { await request({ - url: "/javasys/lowCode/transfer/getOrgAndManTree", + url: "/systemapi/app/get_org_everyone_people",//"172.20.2.87:39168", method: "post", + data:{id:"313",all: 1} }).then((response) => { // assuming response.data is an array of OrgMemberItem - dataTree.value=response.data - handleChildren(response.data.children) + dataTree.value={id:"313",name:"集团公司",child:response.data} + handleChildren(response.data) }); } function handleChildren(childs:any[]){ childs.forEach(item => { - listMap.value[item.id] = item.label; - if(item.children){ - handleChildren(item.children) + listMap.value[item.id] = item.name; + if(item.child){ + handleChildren(item.child) } }); } diff --git a/src/views/doc/agent.vue b/src/views/doc/agent.vue index 6952b09..ad59e20 100644 --- a/src/views/doc/agent.vue +++ b/src/views/doc/agent.vue @@ -26,7 +26,7 @@ const inputState=ref(true) const conversations=ref([]) const centHoverItem=ref("") -const interact_msg=ref<{ask:boolean,think:string,content:string}[]>([]) +const interact_msg=ref<{ask:boolean,think:string,content:string,docinfo?:any[]}[]>([]) const props = withDefaults(defineProps<{ userid:string, closefunc:()=>void, @@ -75,7 +75,7 @@ async function onSendTextToAI(){ }else{ interact_msg.value.push({ask:true,think:"", content:myquestion.value}) } - + let docinfo:any=[] controller.value = new AbortController(); try{ const res= await doAiChat(`${baseURL}/aibot/agents/${props.agent.uuid}/chat`,{ @@ -86,7 +86,7 @@ async function onSendTextToAI(){ user:atob(props.userid),//这里已经base64解析了 },controller.value.signal ) - + if (!res.ok) { throw new Error(`HTTP ${res.status} ${res.statusText}`); } @@ -94,11 +94,10 @@ async function onSendTextToAI(){ myquestion.value="" const reader = res.body!.getReader(); const decoder = new TextDecoder('utf-8'); - + let chunk = ''; // 行缓存 while (true) { const {done, value} = await reader.read() - if (done) break; // 服务器可能一次返回多行,需要手动按行拆分 chunk += decoder.decode(value, {stream: true}); @@ -112,9 +111,13 @@ async function onSendTextToAI(){ if(json.event==="message"){ conversation.value=json.conversation_id respMsg.value+=json.answer + }else if(json.event==="message_end"){ + docinfo=json.metadata.retriever_resources } } } + + if (done) break;//能否放到结尾??? } }catch (e: any) { if (e.name === 'AbortError') { @@ -126,14 +129,13 @@ async function onSendTextToAI(){ const arr=respMsg.value.split("") if(arr.length===1){ - interact_msg.value.push({ask:false,think:"",content:arr[0]}) + interact_msg.value.push({ask:false,think:"",content:arr[0],docinfo:docinfo}) }else{ //思考模式 - interact_msg.value.push({ask:false,think:arr[0],content:arr[1]}) + interact_msg.value.push({ask:false,think:arr[0],content:arr[1],docinfo:docinfo}) } respMsg.value="" - setAiChat({ "userid":atob(props.userid), "uuid":conversation.value, @@ -180,6 +182,16 @@ function handleMouseLeave(){ } function newContext(){ + const c =conversations.value.find(c=>c.uuid==conversation.value) + if(!c){ + conversations.value.push({ + "agentuuid":props.agent.uuid, + "uuid":conversation.value, + "brief":interact_msg.value[0].content, + "messages":interact_msg.value + }) + } + inputState.value=true interact_msg.value=[] conversation.value="" @@ -192,6 +204,13 @@ function resetContext(){ props.closefunc() } +//处理ai返回的引用信息 +function formatRefContent(content:string){ + let result=content.replaceAll(/"/g,'') + result=result.replaceAll(/Unnamed: /g,' ') + return result +} + //渲染完页面再执行 onMounted(() => { loadKnownLibList() @@ -212,7 +231,8 @@ onMounted(() => {
  • 【新建会话】
  • -
  • {{ item.brief }} +
  • + {{ item.brief }}
  • @@ -224,6 +244,15 @@ onMounted(() => {
    +
    + 引用
    + + + {{doc.document_name}} + +
    @@ -306,14 +335,38 @@ onMounted(() => { background-color: #dddddd; padding: 10px 8px; margin: 3px 14px 3px 0; - overflow: hidden; - text-overflow: ellipsis; border-radius: 8px; - text-wrap-mode: nowrap; + span{ + width: 90%; + overflow: hidden; + text-overflow: ellipsis; + text-wrap-mode: nowrap; + } button{ margin-left: auto; } } +.doc_ref{ + margin: 16px; + display: flex; + flex-wrap: wrap; + hr{ + width: 90%; + margin: inherit; + border: none; + border-top: .5px solid rgb(26 25 25 / 23%); + } + span{ + width: 300px; + overflow: hidden; + text-overflow: ellipsis; + text-wrap-mode: nowrap; + margin: 2px 10px; + padding: 0 10px; + background-color: #d7d5d5; + border-radius: 6px; + } +} \ No newline at end of file diff --git a/src/views/doc/manage.vue b/src/views/doc/manage.vue index 1392f46..8825cbc 100644 --- a/src/views/doc/manage.vue +++ b/src/views/doc/manage.vue @@ -22,7 +22,7 @@ import preview from './preview.vue'; import space from './space.vue'; import spacePermission from './spacePermission.vue'; import SvgIcon from "@/components/SvgIcon/index.vue"; -import {doDelSpace} from "@/api/doc/space" +import {doDelSpace,doAccessManage} from "@/api/doc/space" import Space from "./space.vue"; //TODO: add file icons done! @@ -254,10 +254,12 @@ function onMatterRename(row:matterInfo){ }, }), }).then(() => { - postMatterRename(uid,{ - uuid:row.uuid, - name:newname.value, - }).then(()=>onLoadMatterList()) + if(newname.value&&newname.value!=""){ + postMatterRename(uid,{ + uuid:row.uuid, + name:newname.value, + }).then(()=>onLoadMatterList()) + } }) } @@ -658,6 +660,31 @@ function flushSpaceTree(uuid:string,data:matterTree[]){ spaceTreeRef.value.updateKeyChildren(uuid,data) } +//空间成员管理 +function onAccessManage(){ + dynamicVNode.value = h(sharePermission, { + uid: uid, + uuid: "", + spaceid:SpaceID.value.uuid, // + confirmFunc: (_list: string[],_infos:string[]) => { + // 组织权限数据 + //_len=_list.length + let permited = btoa(_list.join("|")) + doAccessManage(uid,{ + "space":SpaceID.value.uuid, + "roles":permited, + "owner":SpaceID.value.userUuid, + "len":_list.length + }).then(()=>{ + + }) + }, + closeFunc: () => { + dynamicVNode.value=null + } + }) +} + //删除空间 function onDeleteSpace(row:matterInfo){ ElMessageBox.confirm(`确认删除空间 ( ${row.name}) ? 空间内所有文件将不可恢复!取消则放弃删除操作。`, "警告", { @@ -763,6 +790,7 @@ const handleSelectionChange = (val:matterInfo[]) => { - + @@ -876,10 +905,11 @@ const handleSelectionChange = (val:matterInfo[]) => {
    • 预览
    • -
    • 分享
    • -
    • 下载
    • -
    • 编辑
    • -
    • 删除
    • +
    • 分享
    • +
    • 下载
    • +
    • 编辑
    • +
    • 删除
    • +
    • 重命名
    @@ -976,12 +1006,13 @@ const handleSelectionChange = (val:matterInfo[]) => { .table-grid{ display: flex; flex-wrap: wrap; /* 关键属性,允许子元素自动换行 */ + align-content: flex-start; .grid-item{ position: relative; - width: 134px; + width: 134px; + height: 145px; margin: 5px; .grid-box{ - height: 150px; display: flex; flex-direction: column; overflow: hidden; @@ -997,6 +1028,7 @@ const handleSelectionChange = (val:matterInfo[]) => { line-height: 27px; text-align: center; color: #878989; + z-index: 90; box-shadow:0px 0px 12px rgba(0,0,0,0.12); li{ cursor: pointer; diff --git a/src/views/doc/onlyoffice.vue b/src/views/doc/onlyoffice.vue index dce2bfe..64a2ebe 100644 --- a/src/views/doc/onlyoffice.vue +++ b/src/views/doc/onlyoffice.vue @@ -53,22 +53,22 @@ onMounted(()=>{ const _url=decodeURIComponent(window.atob(query.fileurl)) const name=query.name?.toString()??"" const dtype=query.dtype?.toString()??"word" + //验证一下文件名是否合规 - if (_info.includes(name)){ - config.value.document.url=_url - config.value.document.title=name - const _key=_url.match(/(\w+-\w+-\w+)/)![0] - if(_key) config.value.document.key=_key+(new Date().getTime().toString()) //合作编辑必须要有一个unique key - config.value.documentType=dtype - config.value.editorConfig.callbackUrl+=`?info=${_info}` - //设置编辑模式 - if(!query.verify) return; - const _verify = atob(query.verify) - //1:必须是验证通过,以true结尾 2:校验uuid是否匹配 - if(_verify.endsWith("true") && _key.includes(_verify.replace("true",""))){ - config.value.editorConfig.mode="edit" - } + config.value.document.url=_url + config.value.document.title=name + const _key=_url.match(/(\w+-\w+-\w+)/)![0] + if(_key) config.value.document.key=_key+(new Date().getTime().toString()) //合作编辑必须要有一个unique key + config.value.documentType=dtype + config.value.editorConfig.callbackUrl+=`?info=${_info}` + //设置编辑模式 + if(!query.verify) return; + const _verify = atob(query.verify) + //1:必须是验证通过,以true结尾 2:校验uuid是否匹配 + if(_verify.endsWith("true") && _key.includes(_verify.replace("true",""))){ + config.value.editorConfig.mode="edit" } + } }) diff --git a/src/views/doc/recentVisited.vue b/src/views/doc/recentVisited.vue index 447f9e5..b700af9 100644 --- a/src/views/doc/recentVisited.vue +++ b/src/views/doc/recentVisited.vue @@ -24,9 +24,9 @@ const props = withDefaults(defineProps<{ function onlyOfficeView(row:shareItem){ const _type=fileType(row.name!) if(_type!==""){ //office file - const info =btoa(encodeURIComponent(`${row.userUuid}/root${row.matters[0].path}`)) + const info =btoa(encodeURIComponent(`${row.name}`)) const _url=`${siteHost}${apiURL}/share/zip?shareUuid=${row.uuid}&code=${row.code}&uid=${props.uid}&dprt=${props.udprt}&puuid=root&rootUuid=root` - window.open(`/#/onlyoffice?name=${row.name}&dtype=${_type}&info=${info}&fileurl=`+encodeURIComponent(_url),"_blank") + window.open(`/#/onlyoffice?name=${row.name}&dtype=${_type}&info=${info}&fileurl=`+window.btoa(encodeURIComponent(_url)),"_blank") }else{ //by kkFilePreview let a = row.name ?? ''; diff --git a/src/views/doc/space.vue b/src/views/doc/space.vue index bda7b1a..de14972 100644 --- a/src/views/doc/space.vue +++ b/src/views/doc/space.vue @@ -9,16 +9,16 @@ import sharePermission from './sharePermission.vue'; import spacePermission from './spacePermission.vue'; import { matterPage,matterInfo,matterTree,doFileUpload,matterPermit} from "@/api/doc/type" import { doAccessManage,getSpaceMatterList,doCreateSpaceDir,doDelSpaceMatter, - doAiTraining ,doCreateAiagent} from "@/api/doc/space" + doAiTraining ,doCreateAiagent,spaceMatterRename} from "@/api/doc/space" import { h } from 'vue' import { Delete, View, Download, - Plus, + Plus,Search, Edit, Setting, - Promotion, + Grid,List, } from '@element-plus/icons-vue' import {ElMessage,UploadFile,UploadFiles,ElPagination} from "element-plus"; import aiagent from './agent.vue'; @@ -29,6 +29,7 @@ const orgMembers = useOrgMemberStore() //为了初始化 const defaultAiAgent=import.meta.env.VITE_DEFAULT_AI_AGENT const matterList = ref([]) +const searchname=ref("") //按文件名查找文件 const newdirName=ref("") //创建新目录时的目录名 const currentHoverRow=ref("") //table 行的按钮控制 const breadcrumbList=ref([{name:"根目录",uuid:"root", dir:true}]) //面包屑导航 @@ -41,6 +42,7 @@ const dynamicVNode = ref(null) //permission 组件的父组件 const paginInfo = ref({ page: 0, total: 0 }) const CutLevelPermit=ref(0) +const modListOrGrild=ref(true) //列表显示还是栅格显示 enum PERMITS { FORBID, //0 VIEW, //1 @@ -88,8 +90,18 @@ const uploadFormData = computed(() => { } }); +function updateListOrGrid(val:boolean){ + modListOrGrild.value=val + if(val){ + localStorage.setItem("listOrGrid","true") + }else{ + localStorage.setItem("listOrGrid","false") + } +} + //--------------权限控制&添加空间成员------------- function onAccessManage(){ + //迁移到了manage文件中,暂时不需要了 dynamicVNode.value = h(sharePermission, { uid: props.uid, uuid: "", @@ -159,10 +171,9 @@ function onDownload(row:matterInfo){ }) } - //加载目录文件列表 -function onLoadMatterList(){ - let _page: matterPage = { +function onLoadMatterList(name?:string){ + let _page: matterPage= { page: paginInfo.value.page, pageSize: 50, orderCreateTime: "DESC", @@ -172,6 +183,18 @@ function onLoadMatterList(){ space:props.spaceid, }; + if(name){ + _page={ + pageSize: 50, + orderCreateTime: "DESC", + orderDir: "DESC", + deleted:false, + name:name, + space:props.spaceid, + } + } + + getSpaceMatterList(props.uid,_page).then((resp)=>{ //page+1 是由于分页的起始index是1,而后端api的分页index起始是0 paginInfo.value={total:resp.data.totalPages, page:resp.data.page} @@ -251,6 +274,31 @@ function onCreateDir(){ }) } +//文件重命名 +function onMatterRename(row:matterInfo){ + const newname=ref(row.name) + ElMessageBox({ + title:"请输入新的文件名", + confirmButtonText: "确定", + cancelButtonText: "取消", + message: () => h(ElInput, { + style: { width:'360px' }, + modelValue: newname.value, + 'onUpdate:modelValue': (val) => { + newname.value = val + }, + }), + }).then(() => { + if(newname.value&&newname.value!=""){ + spaceMatterRename(props.uid,{ + space:props.spaceid, + uuid:row.uuid, + name:newname.value, + }).then(()=>onLoadMatterList()) + } + }) +} + //------------------------------------------ // @cell-dblclick="handleDoubleClick" 取消了目录双击打开功能 //打开一个目录 @@ -445,7 +493,11 @@ function handleAiUpload(info:matterInfo){ //只有当前路径是智能体,上传文件才会进行训练 if (info.path?.startsWith(currentAgent.value.path)){ doAiTraining(`/agents/${currentAgent.value.uuid}/updates`,{"matter":info.uuid}).then(resp=>{ - console.log(resp) + ElMessage({ + message: '已成功安排训练', + type: 'success', + plain: true, + }) }) }else{ alert("当前路径没有智能体") @@ -508,6 +560,13 @@ onMounted(() => { //设置默认的AI智能体 currentAgent.value={name:"通用AI",model:false,uuid:defaultAiAgent,path:"root"} + let val =localStorage.getItem("listOrGrid") + if(val&&val=="false"){ + modListOrGrild.value=false + }else{ + modListOrGrild.value=true + } + if (props.ismanager) { CutLevelPermit.value=PERMITS.MANAGER }else{ @@ -537,7 +596,6 @@ function isOwner(){
    @@ -640,10 +709,13 @@ function isOwner(){
    • 预览
    • 下载
    • -
    • 编辑
    • + +
    • 编辑
    • +
    • 重命名
    • +
    • 删除
    • -
    • 权限
    • +
    • 权限
    @@ -653,7 +725,6 @@ function isOwner(){ - @@ -671,16 +742,22 @@ function isOwner(){ align-self: flex-start; } } +.search{ + margin-left: auto; + margin-right: 20px; + display:inherit; +} .table-grid{ display: flex; flex-wrap: wrap; /* 关键属性,允许子元素自动换行 */ + align-content: flex-start; .grid-item{ position: relative; width: 134px; + height: 135px; margin: 5px; .grid-box{ - height: 150px; display: flex; flex-direction: column; overflow: hidden; @@ -696,7 +773,7 @@ function isOwner(){ line-height: 27px; text-align: center; color: #878989; - z-index: 999; + z-index: 90; box-shadow:0px 0px 12px rgba(0,0,0,0.12); li{ cursor: pointer; diff --git a/src/views/doc/spacePermission.vue b/src/views/doc/spacePermission.vue index d407b49..8f61fd6 100644 --- a/src/views/doc/spacePermission.vue +++ b/src/views/doc/spacePermission.vue @@ -8,6 +8,7 @@ import { import { ElDialog, ElMessageBox,ElStep,TreeInstance} from 'element-plus'; import { useOrgMemberStore } from "@/store/modules/orgMember"; +import { dataTool } from 'echarts'; const props = withDefaults(defineProps<{ uid:string, //当前用户的uuid uuid:string, //文档的uuid @@ -21,16 +22,17 @@ const spacePermit=ref<{id:number,data:string,matterUid:string}>({}) //权限 const treeRef=ref() //tree组件的引用,为了实现初始选中状态 const managerMode=ref(false) const managers=ref([]) +const firstLevelKeys = ref([]) //默认展开的部门 let resultPermits: Record = {}; interface Tree { id: string - label:string - parentId?:string + name:string + superior?:string indeterminate?:boolean, radio?:number[]; - children?: Tree[] + child?: Tree[] ismanager?:boolean, } @@ -48,7 +50,7 @@ async function onSavePermChange(){ managers.value.push("p0"+item.id) } - if(item.children) collectManager(item) + if(item.child) collectManager(item) }) await addSpaceManager(btoa(props.uid),{ @@ -69,7 +71,7 @@ async function onSavePermChange(){ resultPermits[item.id]=item.radio[0] } - if(item.children) collectNodePermits(item) + if(item.child) collectNodePermits(item) }) spacePermit.value.data=JSON.stringify(resultPermits) @@ -85,18 +87,18 @@ async function onSavePermChange(){ } function collectManager(node:Tree){ - node.children?.forEach(ele => { + node.child?.forEach(ele => { if(ele.ismanager){ managers.value.push("p0"+ele.id) } - if(ele.children) collectManager(ele) + if(ele.child) collectManager(ele) }); } //去遍历查找特殊设置的节点,并保存 function collectNodePermits(node:Tree){ - node.children?.forEach(ele => { + node.child?.forEach(ele => { if(ele.radio&&ele.radio.length>0){ if(ele.indeterminate) { ele.radio[0]+=10 @@ -104,7 +106,7 @@ function collectNodePermits(node:Tree){ resultPermits[ele.id]=ele.radio[0] } - if(ele.children){ + if(ele.child){ collectNodePermits(ele) } }); @@ -114,25 +116,25 @@ function collectNodePermits(node:Tree){ //递归修改子级元素 function onGroupValueChange(node:Tree, val:number[]){ if(node.indeterminate) node.indeterminate=false; - node.children?.forEach(ele => { + node.child?.forEach(ele => { ele.radio=val - if(ele.children){ + if(ele.child){ onGroupValueChange(ele,val) } }); - if(node.parentId){ + if(node.superior){ updateParentNode(node) } } //递归更新父级 function updateParentNode(node:Tree){ - if(node.parentId){ + if(node.superior){ - const pnode = treeRef.value?.getNode(node.parentId); + const pnode = treeRef.value?.getNode(node.superior); if(pnode){ const tdata=pnode.data as Tree - if (tdata.children?.every(ele=>{ + if (tdata.child?.every(ele=>{ if(ele.indeterminate) return !ele.indeterminate;//注意这里有个取反计算 if(ele.radio?.length==0) return ele.radio.length==tdata.radio?.length; @@ -165,10 +167,23 @@ function onShowManagers(){ const node = treeRef.value?.getNode(item.replace("p0","")); if(node && node.data){ node.data.ismanager=true + setParentIndeterminate(node.data as Tree) } }) } +function setParentIndeterminate(node:Tree){ + if(node.superior){ + const pnode = treeRef.value?.getNode(node.superior); + if(pnode){ + const tdata=pnode.data as Tree + tdata.indeterminate=true + + setParentIndeterminate(tdata) + } + } +} + function refreshSpaceData(){ getSpaceMemberList( btoa(props.uid), @@ -183,21 +198,24 @@ function refreshSpaceData(){ addNode(item,orgMembers.dataTree) }); + if(dataSource.value.length>0){//只添加第一个最顶级部门 + firstLevelKeys.value.push(dataSource.value[0].id) + } + resp.data?.members?.forEach(item=>{ const mid=item.replace("p0","") for(let data of dataSource.value){ if(checkNode(mid,data)) return; } - dataSource.value.push({id:mid,label:orgMembers.listMap[mid],radio:[2]}) + dataSource.value.push({id:mid,name:orgMembers.listMap[mid],radio:[]}) }); - + managers.value=resp.data?.managers.split("|") spacePermit.value.id=resp.data?.permits.ID spacePermit.value.matterUid=resp.data?.permits.MatterUuid spacePermit.value.data=resp.data.permits.data!="" ? resp.data.permits.data : "{}" - nextTick(() => { const permitJson = JSON.parse(spacePermit.value.data) //object Object.keys(permitJson).forEach(key=>{ @@ -217,28 +235,28 @@ function refreshSpaceData(){ } function addNode(key:string,node:Tree){ - node.children?.forEach(ele => { + node.child?.forEach(ele => { if(ele.id==key){ const eleClone=structuredClone(toRaw(ele)) //这里ele是Proxy,无法clone,所以要toRaw拿到原始object - eleClone.radio=[2] - eleClone.parentId=ele.parentId - dataSource.value.push(eleClone) //{id:ele.id,label:ele.label,radio:2,stage:level,children:ele.children} + //eleClone.radio=[2] + eleClone.superior=ele.superior + dataSource.value.push(eleClone) //{id:ele.id,name:ele.name,radio:2,stage:level,children:ele.children} return } - if(ele.children){ + if(ele.child){ addNode(key,ele) } }); } function checkNode(key:string,node:Tree):boolean{ - for (const child of node.children||[]) { - if(child.id==key){ + for (const ch of node.child||[]) { + if(ch.id==key){ return true } - if(child.children){ + if(ch.child){ //这里不能直接return,因为return后,就中断了for循环,但是true的情况下可以直接return - if(checkNode(key,child)) return true; + if(checkNode(key,ch)) return true; } } @@ -266,11 +284,26 @@ onMounted(()=>{ 管理员
    - 禁止 - 仅预览 - 可下载 - 上传下载 - 编辑 + + 不可见 + + + 仅预览 + + + 可下载 + + + 上传下载 + + + 编辑 +
    @@ -278,15 +311,17 @@ onMounted(()=>{ ref="treeRef" :data="dataSource" node-key="id" - default-expand-all - :expand-on-click-node="false" + accordion + :props="{label: 'name',children:'child'}" + :default-expanded-keys="firstLevelKeys" + :expand-on-click-node="false" >