No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

2095 líneas
76 KiB

  1. <template>
  2. <div v-cloak>
  3. <app-header
  4. backBtnTitle="退出"
  5. :title="showTitle"
  6. :isWorkspaceTopBar="true"
  7. :showUserCenter="true"
  8. class="app-header-style workspace-header"
  9. v-if="!showWorkline"
  10. >
  11. <template #center>
  12. <!-- 工作链 -->
  13. <WorkLine class="my-workline"
  14. :class="{'adjust-workline-pos-client': isClient, 'adjust-workline-pos-web': !isClient}"
  15. :isShowlink="showWorkline"
  16. :listUserFolders="nodeFolders"
  17. :nowFolderIndex="nowFolderIndex"
  18. :nowFolderName="nowFolderName"
  19. :nestTemplateLists="nestTemplateLists"
  20. @goFolderAndBack="goFolderAndBack"
  21. @previousFolder="previousFolder"
  22. @showWorklinkPage="showWorklinkPage"
  23. @nowFolderClick="nowFolderClick"
  24. @hideWorklinkPage="hideWorklinkPage"
  25. @finishGetExchangeNodes="finishGetExchangeNodes"
  26. />
  27. </template>
  28. <template #right>
  29. <search-bar class="proj-search-bar"
  30. placeholder="请输入要搜索的文件名"
  31. @changeSearchContent="changeSearchContent"
  32. @hideSearchBar="hideSearchBar"
  33. @goToSearch="searchForFile"
  34. @showSearchBar="showSearchBar"
  35. @maxTextLengthArrived="maxTextLengthArrived"/>
  36. </template>
  37. </app-header>
  38. <div v-if="isShowSearchPage" class="search-res-page">
  39. <change-btn :titleList="titleList" class="operate-bar"
  40. @changeContentBtnClick="changeContentBtnClick"/>
  41. <div class="out-wrap">
  42. <div class="search-res-page-wrap">
  43. <div class="list-group" v-if="currentBtnIndex == 0">
  44. <!-- 工作文件 -->
  45. <FileItem
  46. class="lisy-group-item"
  47. v-for="file in searchWorkFileList"
  48. :key="file.id"
  49. :file="file"
  50. :clientDownLoad="clientDownLoad"
  51. :showFileMilestone="showFileMilestone"
  52. :nodeFolder="currentNodeFolder"
  53. :currentFolder="currentFolder"
  54. @commitFile="commitFile(file)"
  55. @dblclickFile="fileClick(file)"
  56. @filePreview="filePreview"
  57. @openFileWith="openFileWith(file)"
  58. @openfileBtnClick="fileClick(file)"
  59. @copyFileBtnClick="copyWorkFileBtnClick(file)"
  60. @oneFileRightBtnClick="oneFileRightBtnClick"
  61. @deleteFileClick="deleteFileClick"
  62. :tempRightFileId="tempRightFileId"
  63. :localFileHashMap="localFileHashMap"
  64. :loadingState="localFileLoadStateMap[file.id]"
  65. @dragstart.native="onfileDragStart(file, $event)"
  66. draggable
  67. />
  68. <div class="no-file-tips" v-if="searchWorkFileList && searchWorkFileList.length == 0">搜索不到与“{{searchContent}}”相关的工作文件</div>
  69. </div>
  70. <div class="list-group" v-else-if="currentBtnIndex == 1">
  71. <!-- 协作文件 -->
  72. <FileItem
  73. v-for="file in searchCoopFileList"
  74. :key="file.id"
  75. :file="file"
  76. :tempRightFileId="tempRightFileId"
  77. :clientDownLoad="clientDownLoad"
  78. :showFileMilestone="showFileMilestone"
  79. :nodeFolder="currentNodeFolder"
  80. :currentFolder="currentFolder"
  81. @dblclickFile="fileClick(file)"
  82. @filePreview="filePreview"
  83. @openFileWith="openFileWith(file)"
  84. @openfileBtnClick="fileClick(file)"
  85. @oneFileRightBtnClick="oneFileRightBtnClick"
  86. :localFileHashMap="localFileHashMap"
  87. :loadingState="localFileLoadStateMap[file.id]"
  88. @dragstart.native="onfileDragStart(file, $event)"
  89. draggable
  90. />
  91. <div class="no-file-tips" v-if="searchCoopFileList && searchCoopFileList.length == 0">搜索不到与“{{searchContent}}”相关的协作文件</div>
  92. </div>
  93. </div>
  94. </div>
  95. </div>
  96. <div v-else>
  97. <app-header
  98. class="app-header-style"
  99. :title="projectName"
  100. :showUserCenter="true"
  101. backBtnTitle="回到协作空间"
  102. :onBackBtnClick="hideWorklinkPage"
  103. :isWorkspaceTopBar="true"
  104. v-if="showWorkline"
  105. >
  106. </app-header>
  107. <div class="listfilewarp mt-0">
  108. <!-- 这里主要是用到该组件的工作链图表 -->
  109. <WorkLine class="my-workline hack-work-line" ref="hackworkline"
  110. :class="{
  111. 'height-0': !showWorkline}"
  112. :isHideWorkFolders="true"
  113. :isShowlink="showWorkline"
  114. :listUserFolders="nodeFolders"
  115. :isCalcuteExchangeNode="false"
  116. :nowFolderIndex="nowFolderIndex"
  117. :nowFolderName="nowFolderName"
  118. :nestTemplateLists="nestTemplateLists"
  119. @goFolderAndBack="goFolderAndBack"
  120. @previousFolder="previousFolder"
  121. @showWorklinkPage="showWorklinkPage"
  122. @nowFolderClick="nowFolderClick"
  123. @hideWorklinkPage="hideWorklinkPage"
  124. @finishGetExchangeNodes="finishGetExchangeNodes"
  125. />
  126. <div class="layout_content2" v-show="!showWorkline" v-loading="loading">
  127. <section
  128. id="workspace"
  129. :class="`${closepageH} layerout_H2`"
  130. @contextmenu.prevent="rightShowMenu($event, '新建文件夹', 4)"
  131. >
  132. <section class="yiyun_section_warp">
  133. <div class="yinyong_warpBox hidescollbar">
  134. <div class="titlebar_head" id="bignav">
  135. <!-- 面包屑导航 -->
  136. <div
  137. class="section_item section_item_aside_fl"
  138. >
  139. <span
  140. class="yiyun_text-title-workspace"
  141. >
  142. <el-breadcrumb class="folder_breadcrumb" separator-class="el-icon-arrow-right">
  143. <el-breadcrumb-item @click.native="clickBreadcrumb(-1, 0)">工作文件</el-breadcrumb-item>
  144. <el-breadcrumb-item
  145. v-for="(breadFolder, breadIdx) in breadcrumbFolderList"
  146. :key="breadFolder.id"
  147. @click.native="clickBreadcrumb(breadIdx, 0)"
  148. >{{breadFolder.folderName}}</el-breadcrumb-item>
  149. </el-breadcrumb>
  150. </span>
  151. </div>
  152. <!-- 工作列表主体 -->
  153. <div
  154. class="yiyun_row scollbarBox nobianju"
  155. >
  156. <AddFileButton
  157. v-if="isClient"
  158. @fileTempClick="fileTempClick"
  159. :listTempFiles="listTempFiles"
  160. :selectSystemFiles="selectSystemFiles"
  161. :selectSystemFolders="selectSystemFolders"
  162. />
  163. <!-- 文件上传队列 -->
  164. <div class="list-group">
  165. <FileItem
  166. class="lisy-group-item"
  167. v-for="file in filterFiles(uploadFileList)"
  168. :key="file.id"
  169. :file="file"
  170. :clientDownLoad="clientDownLoad"
  171. :showFileMilestone="showFileMilestone"
  172. :nodeFolder="currentNodeFolder"
  173. :currentFolder="currentFolder"
  174. :localFileHashMap="localFileHashMap"
  175. :loadingState="localFileLoadStateMap[file.id]"
  176. />
  177. </div>
  178. <div class="list-group">
  179. <FileItem
  180. class="lisy-group-item"
  181. v-for="file in filterFiles(workFileList)"
  182. :key="file.id"
  183. :file="file"
  184. :clientDownLoad="clientDownLoad"
  185. :showFileMilestone="showFileMilestone"
  186. :nodeFolder="currentNodeFolder"
  187. :currentFolder="currentFolder"
  188. @commitFile="commitFile(file)"
  189. @dblclickFile="fileClick(file)"
  190. @filePreview="filePreview"
  191. @openFileWith="openFileWith(file)"
  192. @openfileBtnClick="fileClick(file)"
  193. @copyFileBtnClick="copyWorkFileBtnClick(file)"
  194. @oneFileRightBtnClick="oneFileRightBtnClick"
  195. @deleteFileClick="deleteFileClick"
  196. :tempRightFileId="tempRightFileId"
  197. :localFileHashMap="localFileHashMap"
  198. :loadingState="localFileLoadStateMap[file.id]"
  199. @dragstart.native="onfileDragStart(file, $event)"
  200. draggable
  201. />
  202. </div>
  203. <!--显示文件夹组 -->
  204. <div class="list-group">
  205. <FolderItem
  206. v-for="folder in filterFolders(subFolderList)"
  207. :key="folder.id"
  208. :folder="folder"
  209. :isLoading="localFolderLoadStateMap[folder.folderPath]"
  210. @onRightMenuActive="oneFileRightBtnClick"
  211. @onDownloadAll="downloadFolder"
  212. :activeRightMenuId="tempRightFileId"
  213. @dblclick.native="intoSubFolder(folder, 0)"
  214. @commitFolder="commitFolder"
  215. />
  216. </div>
  217. </div>
  218. </div>
  219. </div>
  220. </section>
  221. </section>
  222. <div :class="[`${neibianju}`, {'coopBox-max-height': isShowShadow && isCollapse}]" id="bottomBox">
  223. <div class="titleBox">
  224. <span class="yiyun_zhediebtn DevtopIcon">
  225. <i
  226. class="Cicon text_gray icon font_family icon-icon_zhankai"
  227. title="展开面板"
  228. v-show="isCollapse"
  229. @click="openCopage"
  230. ></i>
  231. <i
  232. class="Cicon text_gray icon font_family icon-icon_shouqi"
  233. title="折叠面板"
  234. v-show="!isCollapse"
  235. @click="closeCopage"
  236. ></i>
  237. </span>
  238. <div class="title_warp">
  239. <div class=" " id="bignav">
  240. <div class="section_item fl section_item_aside_fl xiangdui">
  241. <div class="tabtltlebox">
  242. <div
  243. class="section_item section_item_aside_fl"
  244. >
  245. <span
  246. class="yiyun_text-title-workspace mr-20 ml-8"
  247. >
  248. <el-breadcrumb class="folder_breadcrumb" separator-class="el-icon-arrow-right">
  249. <el-breadcrumb-item @click.native="clickBreadcrumb(-1, 1)">协作文件</el-breadcrumb-item>
  250. <el-breadcrumb-item
  251. v-for="(breadFolder, breadIdx) in breadcrumbFolderListInCoop"
  252. :key="breadFolder.id"
  253. @click.native="clickBreadcrumb(breadIdx, 1)"
  254. >{{breadFolder.folderName}}</el-breadcrumb-item>
  255. </el-breadcrumb>
  256. </span>
  257. </div>
  258. </div>
  259. </div>
  260. <div class="section_item fr section_item_aside_fr">
  261. <div class="fr ml-10">
  262. <span class="bj_label">协作文件均只读</span>
  263. </div>
  264. <div class="fifle_search fr"></div>
  265. </div>
  266. </div>
  267. <div class="clear"></div>
  268. </div>
  269. </div>
  270. <div class="fifleBox" id="coopFileContainer">
  271. <div class="yiyun_section_warp layerout_H3" id="coopFileBox">
  272. <!-- 文件大box -->
  273. <div class="yinyong_warpBox">
  274. <!-- 协作文件 -->
  275. <div v-if="!isShowStartNodeFolders">
  276. <div
  277. class="mt-12"
  278. >
  279. <FileItem
  280. v-for="file in filterFilesInCoop(cooperationFileList)"
  281. :key="file.id"
  282. :file="file"
  283. :tempRightFileId="tempRightFileId"
  284. :clientDownLoad="clientDownLoad"
  285. :showFileMilestone="showFileMilestone"
  286. :nodeFolder="currentNodeFolder"
  287. :currentFolder="currentFolder"
  288. @dblclickFile="fileClick(file)"
  289. @filePreview="filePreview"
  290. @openFileWith="openFileWith(file)"
  291. @openfileBtnClick="fileClick(file)"
  292. @oneFileRightBtnClick="oneFileRightBtnClick"
  293. :localFileHashMap="localFileHashMap"
  294. :loadingState="localFileLoadStateMap[file.id]"
  295. @dragstart.native="onfileDragStart(file, $event)"
  296. draggable
  297. />
  298. </div>
  299. <!-- 协作文件以文件夹的形式展示 -->
  300. <div class="list-group">
  301. <FolderItem
  302. v-for="folder in filterFoldersInCoop(coopSubFolderList)"
  303. :key="folder.id"
  304. :folder="folder"
  305. :isWorkFolder=false
  306. :isLoading="localFolderLoadStateMap[folder.folderPath]"
  307. @onRightMenuActive="oneFileRightBtnClick"
  308. @onDownloadAll="downloadFolder"
  309. :activeRightMenuId="tempRightFileId"
  310. @dblclick.native="intoSubFolder(folder, 1)"
  311. @commitFolder="commitFolder"
  312. />
  313. </div>
  314. </div>
  315. <div v-else>
  316. <div class="list-group">
  317. <FolderItem
  318. v-for="folder in exchangeNodeListsInCoop"
  319. :key="folder.id"
  320. :folder="folder"
  321. :isWorkFolder=false
  322. :isLoading="localFolderLoadStateMap[folder.folderPath]"
  323. @onRightMenuActive="oneFileRightBtnClick"
  324. @onDownloadAll="downloadFolder"
  325. :activeRightMenuId="tempRightFileId"
  326. @dblclick.native="intoSubFolder(folder, 1), isShowStartNodeFolders = !isShowStartNodeFolders, topFolderInCoop = folder"
  327. @commitFolder="commitFolder"
  328. />
  329. </div>
  330. </div>
  331. </div>
  332. </div>
  333. </div>
  334. <div class="showdowfix" id="bottomoShadow" v-show="isShowShadow"></div>
  335. </div>
  336. <!-- 右键菜单 -->
  337. <div
  338. v-show="rightMenuvisible"
  339. :style="{ left: rightMenuleft + 'px', top: rightMenuTop + 'px' }"
  340. class="contextmenu"
  341. >
  342. <!--新建文件分组-->
  343. <ul
  344. class="rightMenu"
  345. >
  346. <li
  347. @click="newCreateFolderGroup"
  348. >
  349. 新建文件夹
  350. </li>
  351. <li
  352. @click="openNativeCurrentFolder"
  353. v-if="isClient && this.localWorkspacePrefix"
  354. >
  355. 打开本地工作目录
  356. </li>
  357. </ul>
  358. </div>
  359. </div>
  360. </div>
  361. </div>
  362. <!-- 文件在线预览 -->
  363. <el-dialog
  364. width="900px"
  365. :visible.sync="isVideo"
  366. :close-on-click-modal="false"
  367. @close="videoClose"
  368. >
  369. <div class="filePreview">
  370. <video :src="videoSrc" controls="controls"></video>
  371. </div>
  372. </el-dialog>
  373. <!-- 创建文件夹组 -->
  374. <el-dialog
  375. title="创建文件夹"
  376. @submit.native.prevent
  377. :visible.sync="dialogNewFolderGroup"
  378. width="460px"
  379. :close-on-click-modal="false"
  380. >
  381. <el-form>
  382. <div class="appImgiconbox">
  383. <img src="/static/img/folder.png" alt />
  384. </div>
  385. <el-form-item>
  386. <el-input
  387. v-model="folderGroupData.FolderName"
  388. @keyup.enter.native="createSubFolder"
  389. ></el-input>
  390. </el-form-item>
  391. </el-form>
  392. <div slot="footer" class="dialog-footer">
  393. <el-button @click="dialogNewFolderGroup = false">取 消</el-button>
  394. <el-button @click="createSubFolder()" type="primary">确 定</el-button>
  395. </div>
  396. </el-dialog>
  397. <!-- 创建样本文件分组 -->
  398. <el-dialog v-if="currentSelectTempFile" class="temp-file-dialog"
  399. :title="showNewTemplateFileDialogTitle"
  400. @submit.native.prevent
  401. :visible.sync="isShowNewTemplateFileDialog"
  402. width="460px"
  403. :show-close="false"
  404. :close-on-click-modal="false"
  405. >
  406. <el-form>
  407. <div class="appImgiconbox"
  408. v-if="oneOf(currentSelectTempFile.extension, ['doc','docx','dwg','dxf','gif','jpeg','jpg','max','nwc','pdf','png','ppt','pptx','rar','rvt','skp','txt','xls','xlsx','xmind','zip'])">
  409. <img
  410. :src="
  411. '/static/img/files/file_sample_' + currentSelectTempFile.extension + '.svg'
  412. "
  413. alt
  414. />
  415. </div>
  416. <div v-else class="img-container">
  417. <!-- 非图片文件图标 -->
  418. <div
  419. v-if="notPicIcon()"
  420. class="defultImage-small"
  421. :class="`${currentSelectTempFile.extension}-mid`"
  422. />
  423. <!-- 图片文件图标 -->
  424. <div
  425. v-else-if="picIcon()"
  426. class="defultImage-small img_bg-mid"
  427. >
  428. <div class="file_Im gbox-mid">
  429. <img v-lazy="currentSelectTempFile.alias" alt class="file_Img" />
  430. </div>
  431. </div>
  432. <!-- 视频文件图标 -->
  433. <div
  434. v-else
  435. class="video-small"
  436. >
  437. </div>
  438. </div>
  439. <div class="guide-template-file-name">{{projectName + '_' + currentNodeFolder.folderName + '_' + currentSelectTempFile.fileName + '.' + currentSelectTempFile.extension}}</div>
  440. <el-form-item>
  441. <el-input
  442. v-model="currentSelectTempFile.fileName"
  443. @keyup.enter.native="createTemplateFile"
  444. ></el-input>
  445. </el-form-item>
  446. </el-form>
  447. <div slot="footer" class="dialog-footer">
  448. <el-button @click="isShowNewTemplateFileDialog = false">取 消</el-button>
  449. <el-button @click.stop="createTemplateFile()" type="primary">完成创建</el-button>
  450. </div>
  451. </el-dialog>
  452. </div>
  453. </template>
  454. <script>
  455. import Vue from "vue";
  456. import AppHeader from "@/components/app-header";
  457. import SearchBar from "@/components/search-bar/search-bar";
  458. import ChangeBtn from "@/components/change-btn/change-btn";
  459. import commonJs from "@/common/webCommon";
  460. // import forgeview from "@/views/components/forgeview/forgeview.vue";
  461. // import gismap from "@/views/components/gismap/gismap.vue";
  462. // import officeview from "@/views/components/officeview/officeview.vue";
  463. // import imageview from "@/views/components/imageview/imageview.vue";
  464. // import BMapComponent from "@/views/components/map/bmap";
  465. // import DistWork from "@/views/components_web/distWork/distWork";
  466. import WorkLine from "./components/workLine";
  467. import AddFileButton from './components/add-file-button';
  468. // import ProjSetting from "@/views/components_web/projSetting/projSetting";
  469. // import FileShare from "@/views/components_web/share_setting/fileshare";
  470. // import draggable from "vuedraggable";
  471. import vuetify from "vuetify";
  472. import system from '@/services/system';
  473. import { queryAllTemplateNodeModelFile, queryNestTemplateByTemplateId } from '@/services/template.js';
  474. import * as services from './service';
  475. import * as tempalteService from '@/services/template.js';
  476. import { firstCharToLowerCase, firstCharToUpperCase, notify } from '@/utils/tool';
  477. import FileItem from './components/file-item';
  478. import FolderItem from './components/folder-item';
  479. import { FileWorkStatus, getFileStoreKey, injectionFileLocalStatus, LoadingEnum, VirtualFolder, analyzeRelativePath, imgExtensionList, RecExtensionList, VideoExtensionList, office, filePreviewList } from './helper';
  480. import { propertyOf, uniqBy, throttle, flatten, debounce, cloneDeep } from 'lodash';
  481. import { fetchApi } from '@/utils/request';
  482. import template_marketVue from '../../manage_company/template_market.vue';
  483. const $ = window.jQuery;
  484. const Velocity = window.Velocity;
  485. Vue.use(vuetify);
  486. const { DOWNLOADING, UPLOADING } = LoadingEnum;
  487. const { WORKING, NOT_WORKING } = FileWorkStatus;
  488. const initialTempFile = (folderGroupID, folderGroupName) => ({
  489. archID: null,
  490. childCount: 0,
  491. createTime: "",
  492. createUserID: "",
  493. deleted: 0,
  494. folderGroupID,
  495. folderGroupName,
  496. folderID: "",
  497. levelId: "",
  498. modifyTime: "",
  499. modifyUserID: "",
  500. superID: "",
  501. });
  502. const initialFolderData = () =>({
  503. Id:"",
  504. ProjId:"",
  505. SuperId:"",
  506. LevelId:"",
  507. FirstFolderId:"",
  508. FolderName:"",
  509. TemplateId:"",
  510. NodeId:"",
  511. SysCode:"",
  512. FileCount:0,
  513. ChildCount:0,
  514. Deleted:0,
  515. Customed:0,
  516. CreateUserId:"",
  517. CreateTime:"",
  518. ModifyUserId:"",
  519. ModifyTime:"",
  520. });
  521. // const fileIsDownloaded = file => file.downloadStatus === DownloadStatus.DOWNLOADED;
  522. export default {
  523. components: {
  524. AppHeader,
  525. SearchBar,
  526. ChangeBtn,
  527. WorkLine,
  528. AddFileButton,
  529. // draggable,
  530. FileItem,
  531. FolderItem,
  532. },
  533. data(){
  534. return {
  535. videoSrc:'',
  536. isVideo:false,
  537. loading: false, // 不一定用得上
  538. isClient: system.isClient,
  539. userId: sessionStorage.userId, // 当前用户id
  540. projectId: sessionStorage.projId, // 当前项目id
  541. projectName: sessionStorage.projName, // 当前项目名称
  542. isShowpageIcon: true, // 协作空间折叠按钮状态
  543. isCollapse: true,//协作空间底部协作文件一开始是属于折叠状态
  544. closepageH: '', // 底部协作文件展开高度 默认为空,展开后高度为closepageH
  545. showWorkline: false, // 工作链显示开关 原为isShowworklink
  546. nodeFolders: [], // 节点文件夹
  547. currentNodeFolder: {}, // 当前节点文件夹
  548. currentFolder: {}, // 当前文件夹,可以是节点文件夹,可以是子文件夹
  549. currentFolderInCoop: {},//协作文件下当前的文件夹
  550. topFolderInCoop: {},//在协作文件中 点击的文件夹
  551. /* 右键菜单 */
  552. rightMenuvisible: false,
  553. rightMenuleft: 0,
  554. rightMenuTop: 0,
  555. dialogNewFolderGroup: false, // 新建文件分组组弹窗
  556. folderGroupData: initialFolderData(), // 文件分组数据
  557. localWorkspacePrefix: '', // 本地工作目录前缀
  558. socketIns: null, // 监听文件变化的socket实例
  559. timerIns: null, // 文件定时任务实例
  560. folderMap: {}, // 节点文件夹id哈希: { [folderId]: folder }
  561. subFolderMap: {}, // 子文件夹哈希: { [folderPath]: VirtualFolder }
  562. breadcrumbFolderList: [], // 面包屑导航对应的文件夹队列
  563. breadcrumbFolderListInCoop: [],//协作文件夹对应额面包屑导航
  564. uploadFileList: [], // 上传文件的队列
  565. workFileList: [], // 工作文件队列
  566. listTempFiles: [],//样板文件列表
  567. currentSelectTempFile: null,//选择创建的样本文件
  568. isShowNewTemplateFileDialog: false,//显示新建样本文件弹框
  569. workSubFolderList: [], // 工作文件夹队列
  570. coopSubFolderList: [],//协作文件夹队列
  571. tempWorkSubFolderList: [], // 临时的工作文件夹队列
  572. cooperationFileList: [], // 协作文件队列
  573. neibianju: "neibianju", // 协作文件槽样式
  574. isShowShadow: false,
  575. localFileHashMap: null, // { `${节点名称}\\${文件名称}.${文件扩展名}`: `${ipfsCid}` }
  576. /**
  577. * 文件本地加载状态表
  578. * 格式: {
  579. * [file.id]: {
  580. * type: DOWNLOADING | UPLOADING
  581. * loadProgress: number | string
  582. * loadSize: number | string
  583. * totalSize: number | string
  584. * unit: string
  585. * }
  586. * }
  587. */
  588. localFileLoadStateMap: {},
  589. /**
  590. * 文件夹本地加载状态表
  591. * 格式: {
  592. * [folder.folderPath]: boolean
  593. * }
  594. */
  595. localFolderLoadStateMap: {},
  596. tempRightFileId: "", // 存储点击了右键菜单的id
  597. isShowStartNodeFolders: true,//协作文件是否显示一开始的节点文件夹
  598. isfinishGetExchangeNodes: false,
  599. allNodeFolders: [],//保存除去项目节点 公共文件夹后 的所有节点
  600. exchangeNodeListsInCoop: [],//存储与当前节点具有交换关系的节点列表
  601. reverseLocalFileHashMap: {},//键名是 ipfscid 键值是localFileHashMap的键名
  602. currentBtnIndex: 0,//0 是工作文件按钮 1是协作文件按钮
  603. titleList: ['工作文件', '协作文件'],
  604. isShowSearchBar: false,//控制搜索框显示隐藏
  605. searchContent: '',//搜索的文件名称
  606. searchWorkFileList: [],//搜索得到的工作文件列表
  607. searchCoopFileList: [],//搜索得到的协作文件列表
  608. isAllFileLoaded: false,//当前工作节点下的文件状态是否都加载完毕
  609. hackWorkLine: null,
  610. nestTemplateLists: [],
  611. };
  612. },
  613. mounted: function () {
  614. this.hackWorkLine = this.$refs.hackworkline;
  615. window.addEventListener("scroll", this.onscroll, true);
  616. this.$nextTick(()=> {
  617. this.listenBottomHeight();
  618. })
  619. // window.addEventListener("resize", this.listenBottomHeight, true);
  620. if(this.isClient) {
  621. this.initWorkspaceDropEvent();
  622. }
  623. //添加鼠标移入齿轮事件
  624. // window.addEventListener("mouseenter", this.setIconMouseEnter, true);
  625. this.fetchNodeFolders();
  626. this.fetchFoldersByProjId();
  627. this.getNestNode(sessionStorage.templateID);
  628. this.socketIns = system.entryProject(
  629. sessionStorage.projName, sessionStorage.accountName,
  630. this.onSocketFileChangeDetected.bind(this),
  631. (localWorkspacePrefix) => { this.localWorkspacePrefix = localWorkspacePrefix;},
  632. errorEvent => {
  633. this.$notify({
  634. message:'本地网关通讯失败',
  635. title:'502错误',
  636. type:'error'
  637. })
  638. }
  639. );
  640. this.timerIns = setTimeout(() => { this.intervalTask(); }, 3000);
  641. },
  642. destroyed: function () {
  643. window.removeEventListener("scroll", this.onscroll);
  644. // window.removeEventListener("resize", this.listenBottomHeight);
  645. // window.removeEventListener("mouseenter", this.setIconMouseEnter);
  646. window.clearTimeout(this.timerIns);
  647. this.timerIns = null;
  648. system.leaveProject(this.socketIns);
  649. sessionStorage.removeItem('nowFolderIndex');
  650. },
  651. computed: {
  652. // 搜索文件时 中间导航栏的标题
  653. showTitle() {
  654. return this.isShowSearchBar && this.searchContent ? `“${this.searchContent}”搜索结果` : this.projectName;
  655. },
  656. isShowSearchPage() {
  657. const rg = /^\s*$/;
  658. return this.isShowSearchBar && !rg.test(this.searchContent);
  659. },
  660. // 创建样板文件的标题 创建XXX文件
  661. showNewTemplateFileDialogTitle() {
  662. return `创建${this.currentSelectTempFile ? this.currentSelectTempFile.extension : ''}文件`;
  663. },
  664. // 当前节点文件夹在节点文件夹数组中的顺序
  665. nowFolderIndex() {
  666. return this.nodeFolders && this.nodeFolders.indexOf(this.currentNodeFolder);
  667. },
  668. // 当前节点文件夹的名称
  669. nowFolderName() {
  670. return this.currentNodeFolder.folderName;
  671. },
  672. subFolderList() {
  673. const uniqSubFolderList = uniqBy(this.workSubFolderList.concat(this.tempWorkSubFolderList), folder => folder.id);
  674. return uniqSubFolderList
  675. },
  676. // 得到协作文件展示区域的实际高度
  677. coopBoxRealHeight() {
  678. return document.getElementById('coopFileBox') ? document.getElementById('coopFileBox').offsetHeight : 0;
  679. }
  680. },
  681. methods: {
  682. async getNestNode(id){
  683. const res1 = await queryNestTemplateByTemplateId(id);
  684. const temp = res1.Data || [];
  685. const resList = [...res1.Data]
  686. circulateGetNestNode(temp, resList);
  687. this.nestTemplateLists= resList;
  688. function circulateGetNestNode(targetList, resList) {
  689. targetList.forEach(async item => {
  690. const res2 = await queryNestTemplateByTemplateId(item.TemplateId);
  691. const resData = res2.Data || [];
  692. if(resData.length > 0) {
  693. resList.push(...resData);
  694. }
  695. })
  696. }
  697. },
  698. // 搜索框字数超出35个字
  699. maxTextLengthArrived() {
  700. this.$notify({
  701. message: '请输入35个字之内的搜索内容',
  702. type: ["warning"],
  703. })
  704. },
  705. /**
  706. * 搜索文件
  707. */
  708. //切换点击工作文件 协作文件
  709. changeContentBtnClick(index) {
  710. this.currentBtnIndex = index;
  711. },
  712. changeSearchContent(content) {
  713. this.searchContent = content;
  714. },
  715. hideSearchBar() {
  716. this.isShowSearchBar = false;
  717. this.searchContent = '';
  718. this.currentBtnIndex = 0;
  719. },
  720. showSearchBar() {
  721. this.isShowSearchBar = true;
  722. },
  723. searchForFile: debounce(async function() {
  724. const rg = /^\s*$/;
  725. if(rg.test(this.searchContent)) {
  726. return;
  727. } else {
  728. const folderId = this.currentNodeFolder.id;
  729. const res = await services.searchFileListByFolderIdAndFileName(folderId, this.searchContent);
  730. if(res.Code === 0) {
  731. const tempWorkFileList = res.Data.workFile || [];
  732. const tempCoopFileList = res.Data.coordinationFiles || [];
  733. this.searchWorkFileList = tempWorkFileList.length > 0 ? tempWorkFileList.map(f => firstCharToLowerCase(f)) : [];
  734. this.searchCoopFileList = tempCoopFileList.length > 0 ? tempCoopFileList.map(cf => firstCharToLowerCase(cf)) : [];
  735. this.currentBtnIndex = 0;
  736. } else {
  737. this.$notify({
  738. type: ['error'],
  739. message:'查询数据失败, 请稍后重试。'
  740. })
  741. }
  742. }
  743. }, 500),
  744. notPicIcon() {
  745. return !this.oneOf(this.currentSelectTempFile.extension, imgExtensionList) && !this.oneOf(this.currentSelectTempFile.extension, VideoExtensionList)
  746. },
  747. picIcon() {
  748. return this.oneOf(this.currentSelectTempFile.extension, imgExtensionList);
  749. },
  750. // 创建样本文件
  751. async createTemplateFile() {
  752. let tempName = this.currentSelectTempFile.fileName;
  753. let temExtension = this.currentSelectTempFile.extension;
  754. //判断输入的名字是否重复
  755. let isExists = this.workFileList.findIndex(file => file.archName === tempName && file.extension == temExtension);
  756. if(isExists > -1) {
  757. this.$notify({
  758. type: "warning",
  759. message: `文件名重复 请重新输入。`,
  760. offset: 100,
  761. duration: 2500,
  762. });
  763. return;
  764. }
  765. const time = new Date();
  766. const fileRelativePath = this.currentFolder.folderPath ? this.currentFolder.folderPath : '';
  767. let file = {
  768. "id": this.currentSelectTempFile.id,
  769. "projId":this.projectId,
  770. "folderId": this.currentNodeFolder.id,
  771. "archName":tempName,
  772. "extension":temExtension,
  773. "ipfsCid":this.currentSelectTempFile.hash,
  774. "fileSize":this.currentSelectTempFile.fileSize,
  775. "folderLevelId":this.currentNodeFolder.levelId,
  776. "status":0,
  777. "workStatus":0,
  778. "commonStatus":0,
  779. "deleted":this.currentSelectTempFile.deleted,
  780. "milestone":0,
  781. "version":0,
  782. "showUrl":"",
  783. "createUserId":this.userId,
  784. "createTime":time,
  785. "modifyUserId":this.userId,
  786. "modifyTime":time,
  787. "isShowRecycle":0,
  788. "relativePath":fileRelativePath}
  789. const addFileRes = await services.addFile(file);
  790. if(addFileRes.Code == 0) {
  791. this.fetchFolderFiles();
  792. this.isShowNewTemplateFileDialog = false;
  793. this.$notify({
  794. message: `文件 “${tempName}” 创建成功。`,
  795. type: "success",
  796. offset: 100,
  797. duration: 2500,
  798. });
  799. return;
  800. } else {
  801. // this.fetchFolderFiles();
  802. this.isShowNewTemplateFileDialog = false;
  803. this.$notify({
  804. message: `文件 “${tempName}” 创建失败 请稍后重试。`,
  805. type: "error",
  806. offset: 100,
  807. duration: 2500,
  808. });
  809. return;
  810. }
  811. },
  812. // 点击了样本文件
  813. fileTempClick(item) {
  814. this.isShowNewTemplateFileDialog = true;
  815. this.currentSelectTempFile = {...item};
  816. },
  817. // 加载样本文件列表
  818. async loadListTempFiles() {
  819. if(this.nodeFolders && this.nodeFolders[this.nowFolderIndex]) {
  820. const nodeId = this.nodeFolders[this.nowFolderIndex].nodeId;
  821. const res = await queryAllTemplateNodeModelFile(nodeId);
  822. if (res.Code !== 0) return;
  823. if(res.Data.length > 0) {
  824. this.listTempFiles = res.Data.map(f => firstCharToLowerCase(f));
  825. } else {
  826. this.listTempFiles = [];
  827. }
  828. }
  829. },
  830. //预览文件
  831. async filePreview(file,type){
  832. const url = await services.filePreview(sessionStorage.companyId);
  833. const params={
  834. API:'company/queryFileOnlineUrlByCompanyId',
  835. Action:'打开文件',
  836. CompanyName:sessionStorage.CompanyName,
  837. Subject:file.archName+"."+file.extension,
  838. Source:sessionStorage.client,
  839. ProjectName:sessionStorage.projName,
  840. }
  841. fetchApi('operation/record',params);
  842. const Url="http://"+url.Data;
  843. if(type == 2){
  844. //const link=encodeURIComponent(Url)
  845. const officeApi="http://www.lockingos.org:8012/onlinePreview?url=";
  846. const fullfilename="?fullfilename="+file.archName+"."+file.extension;
  847. console.log(officeApi+Url + file.ipfsCid + fullfilename )
  848. const link = officeApi + encodeURIComponent(Url + file.ipfsCid + fullfilename) + '&officePreviewType=pdf';
  849. window.open(link,'');
  850. }else if(type == 1){
  851. this.isVideo=true;
  852. this.videoSrc=Url+file.ipfsCid;
  853. }else{
  854. return;
  855. }
  856. },
  857. //
  858. videoClose(){
  859. this.videoSrc="";
  860. },
  861. // 删除文件夹 递归删除文件夹下面的所有文件
  862. deleteFolderClick(id) {
  863. const { isClient, subFolderList, workFileList, subFolderMap, userId, localFileHashMap, reverseLocalFileHashMap } = this;
  864. const deleteFolderName = subFolderMap[id].folderName;
  865. const thisApp = this;
  866. const totalDeleteFileLists = [];
  867. this.$confirm(`确认删除文件夹“${deleteFolderName}”吗?`, "", {
  868. confirmButtonText: "确定",
  869. cancelButtonText: "取消",
  870. showClose: false,
  871. type: "warning",
  872. }).then(async function () {
  873. circulateDelete(id);
  874. const totalNum = totalDeleteFileLists.length;
  875. console.log('要删除的文件总数是', totalNum);
  876. let isFileInWorking = totalDeleteFileLists.find(f => f.workStatus == 2 && f.modifyUserId !== userId);
  877. if(isFileInWorking) {
  878. // 提示 该文件夹下有他人正在工作中的文件 -> 删除失败
  879. thisApp.$notify({
  880. message: `“${deleteFolderName}”文件夹下存在“工作中”文件,删除失败。`,
  881. type: "error",
  882. offset: 100,
  883. duration: 2500,
  884. });
  885. } else {
  886. // 删除文件夹
  887. let counter = 0;
  888. totalDeleteFileLists.forEach(async delFile => {
  889. isClient && delete localFileHashMap[reverseLocalFileHashMap[delFile.ipfsCid]];
  890. const res = await services.deleteFile(delFile.id);
  891. counter = res.Code == 0 ? counter+1 : counter;
  892. if(counter == totalNum) {
  893. thisApp.$notify({
  894. message: `“${deleteFolderName}”文件夹已删除。`,
  895. type: ["success"],
  896. duration: 2500,
  897. });
  898. }
  899. thisApp.fetchFolderFiles();
  900. })
  901. }
  902. })
  903. function circulateDelete(deleteFolderId) {
  904. const delFolderLists = subFolderList.filter(folder => folder.parentFolderPath == deleteFolderId);
  905. if(delFolderLists.length == 0) {
  906. //表明到了最底层的文件夹 删除deleteFolderId对应这个文件夹下面的所有文件
  907. let delFileLists = workFileList.filter(file => file.relativePath == deleteFolderId);
  908. // 删除与这个要删除文件夹同级的文件
  909. const parentFolderPath = subFolderMap[deleteFolderId].parentFolderPath
  910. if(parentFolderPath !== "") {
  911. const tempLists = workFileList.filter(wf => wf.relativePath == parentFolderPath);
  912. delFileLists.push(...tempLists);
  913. }
  914. totalDeleteFileLists.push(...delFileLists);
  915. }
  916. delFolderLists.forEach(df => {
  917. circulateDelete(df.id);
  918. })
  919. }
  920. },
  921. // 当workLine组件获得节点的交换节点的时候 调用函数
  922. finishGetExchangeNodes() {
  923. this.isfinishGetExchangeNodes = true;
  924. this.getExchangeNodes();
  925. },
  926. // 协作文件一开始显示的文件夹要显示具有节点交换关系的文件夹 但是这个时候listShareFrom[1]还没有塞入值
  927. getExchangeNodes() {
  928. const froms = this.currentNodeFolder.listsShareFrom[1];
  929. const tempMap = froms.map(f => f.id);
  930. this.exchangeNodeListsInCoop = this.allNodeFolders.filter(folder => tempMap.includes(folder.id));
  931. //注意: 这里的nodeFolders只会包含当前账户能看到的节点 不是全部的节点
  932. },
  933. async fetchFoldersByProjId() {
  934. const data = await this.$fetchApi('folder/queryNodeFolderListByProjectId', { projectId: sessionStorage.projId });
  935. let [topFoler, commonFolder, ...resFolders] = data.Data.folder;
  936. this.allNodeFolders = resFolders.map(f => firstCharToLowerCase(f)) || [];
  937. },
  938. // 对协作文件的relativePath处理 生成文件夹
  939. dealWithCoopFiles(fileList) {
  940. const folderList = [];
  941. const folderMap = {};
  942. fileList.forEach(file => {
  943. const relativePath = file.relativePath;
  944. if(relativePath) {
  945. const paths = relativePath.split('/');
  946. paths.forEach((folderName, idx) => {
  947. const fullRelativePath = paths.slice(0, idx + 1).join('/');
  948. if(folderMap[fullRelativePath]) return;
  949. const folder = new VirtualFolder(fullRelativePath);
  950. folder.topFolderId = file.folderId;
  951. const parentRelativePath = folder.parentFolderPath;
  952. folderList.push(folder);
  953. folderMap[fullRelativePath] = folder;
  954. if(folderMap[parentRelativePath]) {
  955. folderMap[parentRelativePath].childCount++;
  956. }
  957. });
  958. folderMap[relativePath].fileCount++;
  959. }
  960. });
  961. this.coopSubFolderList = folderList;
  962. },
  963. // 接收到了一个文件的右键菜单点击事件
  964. oneFileRightBtnClick(id) {
  965. this.tempRightFileId = id;
  966. this.rightMenuvisible = false;
  967. },
  968. // 文件展示过滤
  969. filterFiles(fileList) {
  970. // 子文件会有这个属性,节点文件夹不会有
  971. const { folderPath = '' } = this.currentFolder ;
  972. return fileList.filter(file => {
  973. if(file.relativePath !== folderPath) return false;
  974. return true;
  975. });
  976. },
  977. // 文件夹展示过滤
  978. filterFolders(folderList) {
  979. // 子文件会有这个属性,节点文件夹不会有
  980. const { folderPath = '' } = this.currentFolder;
  981. return folderList.filter(folder => {
  982. if(folder.parentFolderPath !== folderPath) return false;
  983. return true;
  984. });
  985. },
  986. // 协作文件下的文件展示过滤
  987. filterFilesInCoop(fileList){
  988. const { folderPath = '' } = this.currentFolderInCoop;
  989. return fileList.filter(file=> {
  990. if(file.relativePath !== folderPath) {
  991. return false;
  992. } else if(file.relativePath == folderPath && file.folderId == this.topFolderInCoop.id) {
  993. return true;
  994. }
  995. });
  996. },
  997. // 协作文件下的文件夹展示过滤
  998. filterFoldersInCoop(folderList) {
  999. const { folderPath = ''} = this.currentFolderInCoop;
  1000. return folderList.filter(folder => {
  1001. if(folder.parentFolderPath !== folderPath) {
  1002. return false;
  1003. } else if(folder.parentFolderPath == folderPath && folder.topFolderId == this.topFolderInCoop.id) {
  1004. return true;
  1005. }
  1006. });
  1007. },
  1008. // removeMilestone(filesList){
  1009. // return filesList.filter(file=>{
  1010. // return file.milestone != 2;
  1011. // })
  1012. // },
  1013. oneOf(target, list) {
  1014. return list.indexOf(target) !== -1;
  1015. },
  1016. /* 全局监听事件 */
  1017. initWorkspaceDropEvent() {
  1018. const dropbox = document.getElementById('workspace');
  1019. dropbox.addEventListener("dragenter", this.stopPropagation);
  1020. dropbox.addEventListener("dragover", this.stopPropagation);
  1021. dropbox.addEventListener("dragleave", this.stopPropagation);
  1022. dropbox.addEventListener('drop', this.fileDropEvent, false);
  1023. },
  1024. // 从客户端外拖入文件并上传
  1025. fileDropEvent(e) {
  1026. const files = propertyOf(e)('dataTransfer.files');
  1027. if(!files || files.length === 0 || e.dataTransfer.effectAllowed == 'copyLink') return;
  1028. const itemPaths = Array.from(files).map(file => file.path);
  1029. this.clientUpload(itemPaths);
  1030. // itemPaths.forEach(async fullPath => {
  1031. // const maybeTasks = await system.analyzeSystemPath(fullPath);
  1032. // const tasks = maybeTasks || [];
  1033. // tasks.forEach(uploadTask => this.clientUpload(uploadTask));
  1034. // });
  1035. },
  1036. stopPropagation(e) {
  1037. e.stopPropagation();
  1038. e.preventDefault();
  1039. },
  1040. // 从文件列表中拖到本地
  1041. onfileDragStart(file, e) {
  1042. e.dataTransfer.effectAllowed = 'move';
  1043. this.stopPropagation(e);
  1044. if(!this.isClient) return;
  1045. const { nodeName, id: fileId } = file;
  1046. const isCooperationFile = !!nodeName;
  1047. const fileStoreKey = getFileStoreKey(file, this.currentNodeFolder);
  1048. // 本地没文件,不能拖拽
  1049. if(!this.localFileHashMap[fileStoreKey]) return;
  1050. if(!isCooperationFile) {
  1051. if(file.workStatus === WORKING && sessionStorage.userId !== file.modifyUserId) { // 同节点其他人正在操作的文件不能拖拽
  1052. return;
  1053. }
  1054. services.changeFileWorkStatus(fileId, WORKING)
  1055. .then(flagRes => {
  1056. if(flagRes.Code !== 0) return;
  1057. file.workStatus = WORKING;
  1058. file.modifyUserId = sessionStorage.userId;
  1059. this.fetchFolderFiles();
  1060. });
  1061. }
  1062. // 协作文件可以打开
  1063. const { ipcRenderer } = global.electron;
  1064. ipcRenderer.invoke('project-file-dnd', `${this.localWorkspacePrefix}\\${fileStoreKey}`);
  1065. },
  1066. async intervalTask() {
  1067. await this.fetchFolderFiles();
  1068. this.timerIns ? setTimeout(()=> { this.intervalTask(); }, 3000) : "";
  1069. // this.timerIns = setTimeout(() => { this.intervalTask(); }, 3000);
  1070. },
  1071. /**
  1072. * @description: 滚动条
  1073. * @return:
  1074. */
  1075. onscroll: function () {
  1076. // if (this.$route.name == "workspace") {
  1077. // var topScroll = document.body.scrollTop; //滚动的距离,距离顶部的距离
  1078. // var bignav = document.getElementById("bignav"); //获取到导航栏id
  1079. // if (topScroll > 350) {
  1080. // //当滚动距离大于250px时执行下面的东西
  1081. // bignav.style.position = "fixed";
  1082. // bignav.style.top = "120px";
  1083. // bignav.style.zIndex = "9999";
  1084. // } else {
  1085. // //当滚动距离小于250的时候执行下面的内容,也就是让导航栏恢复原状
  1086. // bignav.style.position = "static";
  1087. // }
  1088. // }
  1089. },
  1090. listenBottomHeight() {
  1091. let oDivH = document.getElementById('coopFileBox') ? document.getElementById("coopFileBox").offsetHeight: 0;
  1092. if (oDivH > 259) {
  1093. this.isShowShadow = true;
  1094. } else {
  1095. this.isShowShadow = false;
  1096. }
  1097. },
  1098. onSocketFileChangeDetected({ data }){
  1099. try {
  1100. /**
  1101. * 格式:
  1102. * {
  1103. * `${节点名称}\\${文件名称}.${文件扩展名}`: `${ipfsCid}`
  1104. * }
  1105. */
  1106. const hash = JSON.parse(data);
  1107. this.localFileHashMap = hash;
  1108. }catch(e) {
  1109. console.log('socket file change message error:', e);
  1110. }
  1111. // console.log('socket file change message detected:', args);
  1112. },
  1113. addLocalFileRecord(fileStoreKey, ipfsCid) {
  1114. // this.localFileHashMap[fileStoreKey] = ipfsCid;
  1115. this.localFileHashMap = { ...this.localFileHashMap, [fileStoreKey]: ipfsCid };
  1116. },
  1117. updateFileLoadState(file, type, loadProgress = 0, loadSize, loadUnit, totalSize, unit){
  1118. if(!file.id) {
  1119. debugger;
  1120. }
  1121. const updateState = {
  1122. type, loadProgress, loadSize, totalSize, unit, loadUnit, fileRelativePath: file.relativePath || '',
  1123. }
  1124. this.localFileLoadStateMap = { ...this.localFileLoadStateMap, [file.id]: updateState };
  1125. },
  1126. removeFileLoadingState(fileId) {
  1127. console.log(`going to remove file: ${fileId}`);
  1128. delete this.localFileLoadStateMap[fileId];
  1129. this.localFileLoadStateMap = { ...this.localFileLoadStateMap };
  1130. },
  1131. /* 工作链API */
  1132. /**
  1133. * 工作链页面点击
  1134. */
  1135. goFolderAndBack(index) {
  1136. this.goFolder(index);
  1137. this.hideWorklinkPage();
  1138. },
  1139. /**
  1140. * todo Deprecated
  1141. * @description: 查看工作链页面
  1142. * @return:
  1143. */
  1144. showWorklinkPage: function () {
  1145. // this.$emit("isShowOutWorkSpace", true);
  1146. if(this.hackWorkLine) {
  1147. // this.hackWorkLine.showWorklinkPage();
  1148. this.hackWorkLine.isShowworklink = true;
  1149. this.hackWorkLine.workheight = "workheight";
  1150. }
  1151. this.showWorkline = true;
  1152. // this.workheight = "workheight";
  1153. },
  1154. /**
  1155. * @description: 隐藏工作链页面
  1156. * @return:
  1157. */
  1158. hideWorklinkPage: function () {
  1159. if(this.hackWorkLine) {
  1160. this.hackWorkLineisShowworklink = false;
  1161. this.hackWorkLine.workheight = "workheightinit";
  1162. }
  1163. this.showWorkline = false;
  1164. // this.workheight = " workheightinit";
  1165. },
  1166. /**
  1167. * 查看上一个文件夹文件
  1168. */
  1169. previousFolder () {
  1170. this.goFolder(this.nowFolderIndex - 1);
  1171. this.isShowStartNodeFolders = true;
  1172. },
  1173. /**
  1174. * 查看下一个文件夹文件
  1175. */
  1176. nextFolder(){
  1177. this.goFolder(this.nowFolderIndex + 1);
  1178. },
  1179. /**
  1180. * 跳转到当前工作
  1181. */
  1182. goFolder: function (nextFolderIndex) {
  1183. if(nextFolderIndex < 0) {
  1184. notify.error('不能再向前了');
  1185. return;
  1186. }
  1187. if(nextFolderIndex > this.nodeFolders.length - 1) {
  1188. notify.error('不能再向后了');
  1189. return;
  1190. }
  1191. sessionStorage.nowFolderIndex = nextFolderIndex; // 用于刷新页面时使用
  1192. this.currentNodeFolder = this.nodeFolders[nextFolderIndex];
  1193. if(this.currentNodeFolder !== this.currentFolder) {
  1194. this.clearCurrentFolderFiles();
  1195. }
  1196. this.currentFolder = this.currentNodeFolder;
  1197. this.currentFolderInCoop = this.currentNodeFolder;
  1198. this.breadcrumbFolderList = [];
  1199. this.breadcrumbFolderListInCoop = [];
  1200. this.fetchFolderFiles();
  1201. this.loadListTempFiles();
  1202. },
  1203. /**
  1204. * 进入子文件夹
  1205. */
  1206. intoSubFolder(folder, flag) {
  1207. if(flag == 0) {
  1208. this.currentFolder = folder;
  1209. this.breadcrumbFolderList.push(folder);
  1210. } else if(flag == 1) {
  1211. // this.listenBottomHeight();
  1212. this.currentFolderInCoop = folder;
  1213. this.breadcrumbFolderListInCoop.push(folder);
  1214. this.$nextTick(()=> {
  1215. this.listenBottomHeight();
  1216. })
  1217. }
  1218. // this.clearCurrentFolderFiles();
  1219. // this.fetchFolderFiles();
  1220. },
  1221. /**
  1222. * 当前工作点击
  1223. */
  1224. nowFolderClick(nextFolderIndex) {
  1225. this.goFolder(nextFolderIndex);
  1226. this.isShowStartNodeFolders = true;//上面切换点击到另一个工作节点的时候 协作文件先显示总的节点入口
  1227. },
  1228. /* 文件夹及文件API */
  1229. async fetchNodeFolders() {
  1230. const userId = this.userId;
  1231. const projId = this.projectId;
  1232. const workList = await services.fetchWorkFlow(projId, userId);
  1233. const folderList = workList.filter(folder => folder.nodeId !== folder.templateId && folder.folderName !== '公共文件夹');
  1234. this.nodeFolders = folderList;
  1235. this.copyNodeFolders = cloneDeep(folderList);
  1236. this.folderMap = folderList.reduce((h, f) => (h[f.id] = f, h), {});
  1237. if(!folderList.length) return;
  1238. const paramsFolderId = this.$route.params.folderId;
  1239. // 匹配存在
  1240. if (paramsFolderId) {
  1241. this.currentNodeFolder = folderList.find(folder => folder.id === paramsFolderId) || folderList[0];
  1242. } else if(sessionStorage.nowFolderIndex) {
  1243. this.currentNodeFolder = folderList[sessionStorage.nowFolderIndex] || folderList[0];
  1244. } else {
  1245. this.currentNodeFolder = folderList[0];
  1246. }
  1247. this.currentFolder = this.currentNodeFolder;
  1248. this.currentFolderInCoop = this.currentNodeFolder;
  1249. this.fetchFolderFiles();
  1250. this.loadListTempFiles();
  1251. },
  1252. /**
  1253. * 查询当前文件夹内容
  1254. */
  1255. fetchFolderFiles: throttle(async function fetchFolderFiles() {
  1256. const nodeFolder = this.currentNodeFolder;
  1257. const userId = this.userId;
  1258. if(!nodeFolder || !nodeFolder.id) return;
  1259. // 先清空当前的文件队列 在这清空队列会有闪烁问题,得放在切换显示文件夹内容的地方触发
  1260. // this.uploadFileList = [];
  1261. // this.workFileList = [];
  1262. // this.workSubFolderList = [];
  1263. // this.cooperationFileList = [];
  1264. // todo 接口去除公共文件夹配置
  1265. const folderResInfo = await services.fetchFolderFileList(nodeFolder.id, userId, nodeFolder.id);
  1266. if(!folderResInfo) return;
  1267. // 快速切换节点的时候
  1268. if(this.currentNodeFolder.id !== nodeFolder.id) return;
  1269. this.workFileList = folderResInfo.file;
  1270. this.subFolderMap = { ...this.subFolderMap, ...folderResInfo.folderMap };
  1271. this.resolveUploadFileList(this.workFileList);
  1272. this.workSubFolderList = folderResInfo.folder;
  1273. // this.workSubFolderList = uniqBy(this.workSubFolderList.concat(folderResInfo.folder), folder => folder.id);
  1274. // resolve dupilicate folders
  1275. this.tempWorkSubFolderList = this.tempWorkSubFolderList.filter(tempFolder => !folderResInfo.folder.some(folder => folder.id === tempFolder.id));
  1276. this.cooperationFileList = folderResInfo.coordinationFiles;
  1277. this.dealWithCoopFiles(this.cooperationFileList);
  1278. this.resolveUploadFileList(this.cooperationFileList);
  1279. }, 1000),
  1280. /**
  1281. * 去掉上传队列中已经上传成功的文件
  1282. */
  1283. resolveUploadFileList(fileList) {
  1284. this.uploadFileList = this.uploadFileList.filter(uploadFile => {
  1285. const targetFile = fileList.find(iFile => iFile.relativePath === uploadFile.relativePath && iFile.archName === uploadFile.archName && iFile.extension === uploadFile.extension);
  1286. this.removeFileLoadingState(uploadFile.id);
  1287. return !targetFile;
  1288. });
  1289. },
  1290. /**
  1291. * 点击确定 保存文件夹组
  1292. */
  1293. async createSubFolder(){
  1294. if (!this.folderGroupData.FolderName) {
  1295. notify.warning('请输入文件夹名称!');
  1296. return;
  1297. }
  1298. const folderName = this.folderGroupData.FolderName;
  1299. const parentFolderPath = this.currentFolder.folderPath || '';
  1300. const folderPath = parentFolderPath ? `${parentFolderPath}/${folderName}` : folderName;
  1301. if(this.subFolderMap[folderPath]) {
  1302. notify.warning('创建失败,已存在同名文件夹!');
  1303. return;
  1304. }
  1305. const newVirtualFolder = new VirtualFolder(folderPath, folderName, parentFolderPath);
  1306. this.subFolderMap[folderPath] = newVirtualFolder;
  1307. this.tempWorkSubFolderList.push(newVirtualFolder);
  1308. notify.success('文件夹创建成功!');
  1309. this.dialogNewFolderGroup = false;
  1310. },
  1311. /**
  1312. * 新建文件夹显示弹窗
  1313. */
  1314. newCreateFolderGroup: function () {
  1315. this.dialogNewFolderGroup = true;
  1316. this.folderGroupData = initialFolderData();
  1317. },
  1318. clearCurrentFolderFiles() {
  1319. this.uploadFileList = [];
  1320. this.workFileList = [];
  1321. this.workSubFolderList = [];
  1322. this.tempWorkSubFolderList = [];
  1323. this.cooperationFileList = [];
  1324. // this.localFileHashMap = {};
  1325. this.localFileLoadStateMap = {};
  1326. this.localFolderLoadStateMap = {};
  1327. this.tempRightFileId = '';
  1328. },
  1329. /**
  1330. * 面包屑导航点击
  1331. */
  1332. clickBreadcrumb(breadFolderIdx, flag) {
  1333. if(flag == 0) {
  1334. // 工作文件
  1335. const targetFolder = breadFolderIdx === -1
  1336. ? this.currentNodeFolder
  1337. : this.breadcrumbFolderList[breadFolderIdx];
  1338. this.currentFolder = targetFolder;
  1339. // this.fetchFolderFiles();
  1340. // 重置面包屑导航数组
  1341. this.breadcrumbFolderList = this.breadcrumbFolderList.slice(0, breadFolderIdx + 1);
  1342. } else if(flag == 1) {
  1343. // 协作文件
  1344. const targetFolderInCoop = breadFolderIdx === -1
  1345. ? this.currentNodeFolder
  1346. : this.breadcrumbFolderListInCoop[breadFolderIdx];
  1347. this.currentFolderInCoop = targetFolderInCoop;
  1348. this.isShowStartNodeFolders = breadFolderIdx === -1;
  1349. // this.fetchFolderFiles();
  1350. // 重置面包屑导航数组
  1351. this.breadcrumbFolderListInCoop = this.breadcrumbFolderListInCoop.slice(0, breadFolderIdx + 1);
  1352. }
  1353. },
  1354. /**
  1355. * 客户端选择文件列表并上传
  1356. */
  1357. async selectSystemFiles() {
  1358. if(!this.isClient) return;
  1359. const filePaths = await system.chooseFiles();
  1360. if(!filePaths) return;
  1361. this.clientUpload(filePaths);
  1362. // filePaths.forEach(async fullPath => {
  1363. // const maybeTasks = await system.analyzeSystemPath(fullPath);
  1364. // const tasks = maybeTasks || [];
  1365. // tasks.forEach(uploadTask => this.clientUpload(uploadTask));
  1366. // });
  1367. },
  1368. /**
  1369. * 客户端选择文件夹列表并上传
  1370. */
  1371. async selectSystemFolders() {
  1372. if(!this.isClient) return;
  1373. const folderPaths = await system.chooseFolders();
  1374. if(!folderPaths) return;
  1375. this.clientUpload(folderPaths);
  1376. // folderPaths.forEach(async fullPath => {
  1377. // const maybeTasks = await system.analyzeSystemPath(fullPath);
  1378. // const tasks = maybeTasks || [];
  1379. // tasks.forEach(uploadTask => this.clientUpload(uploadTask));
  1380. // });
  1381. },
  1382. generateVirtualFolder(relativePath, prefixPath = '') {
  1383. if(!relativePath) return;
  1384. const hash = {};
  1385. const list = [];
  1386. const subFolderMap = this.subFolderMap;
  1387. analyzeRelativePath(relativePath, prefixPath, (folderPath) => {
  1388. if(subFolderMap[folderPath]) return;
  1389. const newSubFolder = new VirtualFolder(folderPath);
  1390. hash[newSubFolder.folderPath] = newSubFolder;
  1391. list.push(newSubFolder);
  1392. });
  1393. this.subFolderMap = { ...subFolderMap, ...hash };
  1394. this.tempWorkSubFolderList = this.tempWorkSubFolderList.concat(list);
  1395. },
  1396. /**
  1397. * 客户端上传文件
  1398. * uploadTask: {
  1399. * fullPath: 本地完整路径
  1400. * fileName: 文件名
  1401. * extension: 扩展名
  1402. * relativePath: 相对路径
  1403. * }
  1404. */
  1405. async clientUpload(filePaths) { // uploadTask
  1406. const tasksGroup = await Promise.all(filePaths.map(path => system.analyzeSystemPath(path)));
  1407. const uploadTasks = flatten(tasksGroup);
  1408. const { folderName, levelId, id: folderId } = this.currentNodeFolder;
  1409. const { folderPath = '' } = this.currentFolder;
  1410. const workFileList = this.workFileList;
  1411. // 检查是否存在文件重名,有则提示
  1412. const ifHaveRepeatFile = uploadTasks.some(uploadTask => {
  1413. const { fileName, extension: fileExtension, relativePath } = uploadTask;
  1414. const extensionedFileName = fileExtension ? `${fileName}.${fileExtension}`: fileName;
  1415. const distFileRelativePath = `${folderPath ? `${folderPath}\\`:''}${relativePath ? `${relativePath}`:''}`.replace(/(\\)+/g, '/');
  1416. return workFileList.some(iFile => distFileRelativePath === iFile.relativePath && `${iFile.archName}${iFile.extension ? `.${iFile.extension}` : ''}` === extensionedFileName)
  1417. });
  1418. if(ifHaveRepeatFile) {
  1419. let confirmRes = false;
  1420. try {
  1421. await Vue.prototype.$confirm('监测到文件夹存在同名文件,是否继续上传并覆盖同名文件?',"",{
  1422. showClose: false,
  1423. type: "warning"
  1424. });
  1425. confirmRes = true;
  1426. } catch(e) { console.log('user canceled'); }
  1427. if(!confirmRes) return;
  1428. }
  1429. let tempNumWrap = {//为了了让这个数量被保存使用修改 这里用作为对象属性传递
  1430. tempNumCount: 0
  1431. }
  1432. const totalReadyUploadNum = uploadTasks ? uploadTasks.length : 0;//全部要上传的文件数量
  1433. uploadTasks.forEach(uploadTask => {
  1434. const { fullPath: sourceFilePath, fileName, extension: fileExtension, relativePath } = uploadTask;
  1435. // 生成
  1436. this.generateVirtualFolder(relativePath, folderPath);
  1437. const params = {
  1438. projectId: this.projectId,
  1439. projectName: this.projectName,
  1440. folderId, folderName, folderLevelId: levelId, distFileRelativePath: [folderPath, relativePath].filter(a => a).join('\\').replace(/(\\)+/g, '/'),
  1441. fileName, fileExtension, sourceFilePath,
  1442. fileList: workFileList,
  1443. onSuccess: (file) => { // onSuccess
  1444. const {ArchName, IpfsCid, Extension, RelativePath} = file;
  1445. // 注入到文件下载检测表中
  1446. const key = `${folderName}\\${RelativePath ? `${RelativePath.replace(/\//g, '\\')}\\`: ''}${ArchName}${Extension ? `.${Extension}`: ''}`;
  1447. this.addLocalFileRecord(key, IpfsCid);
  1448. this.removeFileLoadingState(file.Id);
  1449. this.fetchFolderFiles();
  1450. },
  1451. onProgress: (progressData, upperUploadFile) => { // onLoading
  1452. const { process, hash, size, currentSize, currentUnit, unit } = progressData;
  1453. const uploadFile = firstCharToLowerCase(upperUploadFile);
  1454. // 避免使用最后一次progreessData中size被修正为Kb的数据
  1455. if(!hash) {
  1456. this.updateFileLoadState(uploadFile, UPLOADING, process, currentSize, currentUnit, size, unit);
  1457. }
  1458. // 覆盖已有的同名文件
  1459. if(uploadFile.id.indexOf('upload:') === -1) {
  1460. return;
  1461. }
  1462. // 插入上传队列
  1463. if(!this.uploadFileList.find(f => f.id === uploadFile.id)) {
  1464. this.uploadFileList.push(uploadFile);
  1465. }
  1466. },
  1467. onError: (e, upperFile) => {
  1468. this.removeFileLoadingState(upperFile.Id);
  1469. this.uploadFileList = this.uploadFileList.filter(iFile => iFile.id !== upperFile.Id);
  1470. },
  1471. }
  1472. // console.log(folderName, levelId, folderId);
  1473. system.uploadFile({...params, totalReadyUploadNum, tempNumWrap});
  1474. })
  1475. },
  1476. /**
  1477. * 客户端下载方法
  1478. */
  1479. clientDownLoad: function (file) {
  1480. if(!this.isClient) return;
  1481. // console.log('下载的文件对象', file);
  1482. const { ipfsCid, archName: fileName, extension, folderId, nodeName, relativePath } = file;
  1483. const folderMap = this.folderMap;
  1484. // const { levelId } = folderMap[folderId] || {};
  1485. const nodeFolderName = nodeName || this.currentNodeFolder.folderName;
  1486. const extensionedFileName = `${fileName}${extension ? `.${extension}`:''}`;
  1487. const isCooperateFile = !!nodeName;
  1488. const targetFolderName = `${nodeFolderName}${isCooperateFile ? '\\协作文件': ''}`;
  1489. const dirName = `${targetFolderName}${relativePath ? `\\${relativePath}`:''}`.replace(/\//g, '\\');
  1490. // const fileStoreKey = `${targetFolderName}\\${extensionedFileName}`;
  1491. const fileStoreKey = getFileStoreKey(file, this.currentNodeFolder);
  1492. const errorHandler = () => {
  1493. this.removeFileLoadingState(file.id);
  1494. }
  1495. this.updateFileLoadState(file, DOWNLOADING, 0);
  1496. system.downloadFile(ipfsCid, sessionStorage.projName, extensionedFileName, dirName, (resMessage, socketIns) => {
  1497. console.log('receive download file message:', resMessage, socketIns);
  1498. // {"size":"11","currentSize":"11","unit":"B","process":100,"hash":""}
  1499. try {
  1500. const { process, hash } = JSON.parse(resMessage.data);
  1501. this.updateFileLoadState(file, DOWNLOADING, process);
  1502. if(process !== 100) return;
  1503. this.addLocalFileRecord(fileStoreKey, ipfsCid);
  1504. this.removeFileLoadingState(file.id);
  1505. this.$notify({
  1506. type:["success","download"],
  1507. title:"文件已下载",
  1508. message:`${fileName}`
  1509. })
  1510. socketIns.close();
  1511. // this.$forceUpdate();
  1512. } catch (e) {
  1513. console.error('socket-download-file parse data have error:', e);
  1514. errorHandler();
  1515. socketIns.close();
  1516. }
  1517. }, errorHandler);
  1518. },
  1519. /**
  1520. * 下载文件夹
  1521. */
  1522. downloadFolder(folder) {
  1523. this.workFileList.forEach(file => {
  1524. if(file.relativePath.indexOf(folder.folderPath) === 0) {
  1525. this.clientDownLoad(file);
  1526. }
  1527. })
  1528. },
  1529. /**
  1530. * 打开本地文件夹
  1531. */
  1532. openNativeCurrentFolder(){
  1533. const { folderName } = this.currentNodeFolder;
  1534. const path = `${this.localWorkspacePrefix}\\${folderName}`;
  1535. system.openFolder(path);
  1536. },
  1537. /**
  1538. * 提交本地文件
  1539. */
  1540. async commitFile(file) {
  1541. if(!this.isClient) return;
  1542. const { folderName, levelId, id: folderId } = this.currentNodeFolder;
  1543. const { archName, extension, id: fileId, relativePath } = file;
  1544. this.updateFileLoadState(file, UPLOADING, 0);
  1545. const errorHandler = () => {
  1546. this.removeFileLoadingState(file.id);
  1547. }
  1548. // const fileList = this.currentPageType === 0 ? this.folderFileList.listMyFiles : this.folderFileList.listOtherFiles;
  1549. // const fileKey = `${folderName}\\${archName}${extension ? `.${extension}`:''}`;
  1550. const fileStoreKey = getFileStoreKey(file, this.currentNodeFolder);
  1551. system.updateFile(
  1552. file, this.localWorkspacePrefix,
  1553. this.projectName, `${folderName}${relativePath ? `\\${relativePath}`.replace(/\//g, '\\'):''}`,
  1554. async (fileNewState) => {
  1555. const resFlag = await services.changeFileWorkStatus(file.id, 1);
  1556. if(resFlag.Code !== 0) return;
  1557. notify.success(`${file.archName},已更新。`);
  1558. const {IpfsCid} = fileNewState;
  1559. // 注入到文件下载检测表中
  1560. // 同时更新文件队列中file对象的ipfsCid属性这样才能在下次刷新前使文件的记录保持一致
  1561. this.addLocalFileRecord(fileStoreKey, IpfsCid);
  1562. this.removeFileLoadingState(fileId);
  1563. this.workFileList = this.workFileList.map(iFile => iFile.id === file.id ? { ...iFile, ipfsCid: IpfsCid, workStatus: NOT_WORKING } : iFile);
  1564. // 同步搜索栏中展示的工作文件状态
  1565. if(this.currentBtnIndex == 0 && this.isShowSearchPage) {
  1566. this.searchWorkFileList = this.searchWorkFileList.map(iFile => iFile.id === file.id ? { ...iFile, ipfsCid: IpfsCid, workStatus: NOT_WORKING } : iFile);
  1567. }
  1568. },
  1569. (progressData) => {
  1570. const { process, hash, size, currentSize, currentUnit, unit } = progressData;
  1571. // 避免使用最后一次progreessData中size被修正为Kb的数据
  1572. if(hash) return;
  1573. this.updateFileLoadState(file, UPLOADING, process, currentSize, currentUnit, size, unit);
  1574. },
  1575. errorHandler,
  1576. );
  1577. },
  1578. commitFolder(folder) {
  1579. const path = `${this.localWorkspacePrefix}\\${this.currentNodeFolder.folderName}${folder.folderPath ? `\\${folder.folderPath}`:''}`.replace(/\//g, '\\');
  1580. this.clientUpload([path]);
  1581. },
  1582. /**
  1583. * 文件打开方式
  1584. */
  1585. async openFileWith(file) {
  1586. const localWorkspacePrefix = this.localWorkspacePrefix;
  1587. const fileStoreKey = getFileStoreKey(file, this.currentNodeFolder);
  1588. if(!this.localFileHashMap[fileStoreKey]) return;
  1589. const filePath = `${localWorkspacePrefix}\\${fileStoreKey}`;
  1590. // 若文件在协作文件中,则不更改状态
  1591. const { archName, extension, id: fileId, nodeName } = file;
  1592. const isCooperationFile = !!nodeName;
  1593. console.log(filePath);
  1594. if(isCooperationFile) { system.clientOpenFileWith(filePath); return; }
  1595. // 将文件状态设置为编辑中
  1596. const flagRes = await services.changeFileWorkStatus(fileId, 2);
  1597. if(flagRes.Code !== 0) return;
  1598. file.workStatus = 2;
  1599. file.modifyUserId = sessionStorage.userId;
  1600. system.clientOpenFileWith(filePath);
  1601. this.fetchFolderFiles();
  1602. },
  1603. /**
  1604. * 点击文件事件:直接打开文件
  1605. */
  1606. fileClick: async function (file) {
  1607. //debugger;
  1608. if(!this.isClient) return;
  1609. const { archName, extension, id: fileId, nodeName } = file;
  1610. const folderName = nodeName || this.currentFolder.folderName;
  1611. const localWorkspacePrefix = this.localWorkspacePrefix;
  1612. const isCooperationFile = !!nodeName;
  1613. // const fileStoreKey = `${folderName}${isCooperationFile ? '\\协作文件': ''}\\${archName}${extension ? `.${extension}` : ''}`;
  1614. const fileStoreKey = getFileStoreKey(file, this.currentNodeFolder);
  1615. if(!this.localFileHashMap[fileStoreKey]) return;
  1616. const filePath = `${localWorkspacePrefix}\\${fileStoreKey}`;
  1617. if(!isCooperationFile && (file.workStatus === 2 && sessionStorage.userId !== file.modifyUserId)) {
  1618. console.log("1111")
  1619. this.$notify({
  1620. type:["warning"],
  1621. title:"暂不能打开此文件",
  1622. message:`${file.modifyName}正在编辑此文件,请在“工作中”标识消失后再尝试打开。`
  1623. })
  1624. return;
  1625. }
  1626. // 若文件在协作文件中,则不更改状态
  1627. if(isCooperationFile) { system.openFile(filePath); return; }
  1628. // 将文件状态设置为编辑中
  1629. const flagRes = await services.changeFileWorkStatus(fileId, 2);
  1630. if(flagRes.Code !== 0) return;
  1631. file.workStatus = 2;
  1632. file.modifyUserId = sessionStorage.userId;
  1633. system.openFile(filePath);
  1634. this.fetchFolderFiles();
  1635. },
  1636. /**
  1637. * 设置历史文件界面
  1638. */
  1639. showFileMilestone: function (file) {
  1640. // todo 待修正,思考是否可以放到file组件中去
  1641. debugger;
  1642. if (file.status == 1 && file.modifyUserID != sessionStorage.userId) {
  1643. this.$notify({
  1644. message: "其他人编辑中,不能设置历史文件",
  1645. type: "warning",
  1646. offset: 100,
  1647. duration: 5000,
  1648. });
  1649. return;
  1650. }
  1651. this.currentMilestone=file;
  1652. this.dialogFileHistory = true;
  1653. //返回与该文件同名的所有文件并把自己过滤掉
  1654. this.listMilestones=this.getMilstoneFile(file);
  1655. console.log(this.listMilestones)
  1656. this.currentArchID = file.archID;
  1657. },
  1658. /**
  1659. * 右键菜单
  1660. */
  1661. rightShowMenu(e, file, type) {
  1662. const menuMinWidth = 10;
  1663. const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left
  1664. const offsetWidth = this.$el.offsetWidth; // container width
  1665. const maxLeft = offsetWidth - menuMinWidth; // left boundary
  1666. const left = e.clientX - offsetLeft; // 15: margin right
  1667. this.rightMenuvisible = true;
  1668. this.tempRightFileId = 'currentWorkFolder';
  1669. // todo 边界修正
  1670. this.rightMenuleft = e.clientX; // fix 位置bug
  1671. this.rightMenuTop = e.clientY;
  1672. },
  1673. /**
  1674. * 关闭
  1675. */
  1676. closeShowMenu: function () {
  1677. this.rightMenuvisible = false;
  1678. },
  1679. /**
  1680. * 协作文件展开
  1681. */
  1682. openCopage: function () {
  1683. this.isShowpageIcon = false;
  1684. this.isCollapse = false;
  1685. this.neibianju = "neibianju1";
  1686. this.closepageH = "closepageH";
  1687. },
  1688. /**
  1689. * 协作文件折叠
  1690. */
  1691. closeCopage: function () {
  1692. this.isShowpageIcon = true;
  1693. this.isCollapse = true;
  1694. this.neibianju = "neibianju";
  1695. this.closepageH = "";
  1696. },
  1697. /**
  1698. * 点击了复制文件副本的按钮
  1699. */
  1700. async copyWorkFileBtnClick(targetFile) {
  1701. const copyFile = {...targetFile};
  1702. let nowNum = 1, tempName = "";
  1703. //先添加 - 副本字样 再判断是否重复 如果重复就修改版本信息
  1704. tempName = targetFile.archName + '-副本';
  1705. let isExists = this.workFileList.find(file => file.archName === tempName);
  1706. while(isExists) {
  1707. // - 副本存在 -》修改为 -副本(x) 的字样
  1708. tempName = targetFile.archName + `-副本(${ ++ nowNum})`;
  1709. isExists = this.workFileList.find(file => file.archName === tempName);
  1710. }
  1711. let hour = '0' + new Date().getHours();
  1712. let minute ='0' + new Date().getMinutes();
  1713. let seconds = '0' + new Date().getSeconds();
  1714. hour = hour.substr(hour.length-2);
  1715. minute = minute.substr(minute.length-2);
  1716. seconds = seconds.substr(seconds.length-2);
  1717. copyFile.archName = tempName + '-' + hour + minute + seconds;
  1718. copyFile.modifyUserId = sessionStorage.userId;
  1719. copyFile.modifyTime = new Date();
  1720. copyFile.createUserId = sessionStorage.userId;
  1721. copyFile.createTime = new Date();
  1722. // console.log(copyFile);
  1723. const addFileRes = await services.addFile(copyFile);
  1724. this.fetchFolderFiles();
  1725. },
  1726. deleteFileClick(fileId, createUserId, archName, ipfscid) {
  1727. var thisApp = this;
  1728. if (createUserId != sessionStorage.userId) {
  1729. thisApp.$notify({
  1730. message: "不能删除其他用户创建的文件。",
  1731. type: ["error"],
  1732. //offset: 100,
  1733. duration: 2500,
  1734. });
  1735. return;
  1736. }
  1737. this.$confirm(`确认删除“${archName}”吗?`, "", {
  1738. confirmButtonText: "确定",
  1739. cancelButtonText: "取消",
  1740. showClose: false,
  1741. type: "warning",
  1742. }).then(async function () {
  1743. const res = await services.deleteFile(fileId);
  1744. if(res.Code === 0) {
  1745. thisApp.$notify({
  1746. message: `“${archName}”文件已移除。`,
  1747. type: ["success"],
  1748. duration: 2500,
  1749. });
  1750. for(let key in thisApp.localFileHashMap) {
  1751. if(thisApp.localFileHashMap[key] === ipfscid) {
  1752. delete thisApp.localFileHashMap[key];
  1753. break;
  1754. }
  1755. }
  1756. thisApp.fetchFolderFiles();
  1757. }
  1758. })
  1759. }
  1760. },
  1761. watch: {
  1762. isShowSearchBar(val) {
  1763. if(!val) {
  1764. if(this.currentBtnIndex == 0) {
  1765. this.searchWorkFileList = [];
  1766. } else if(this.currentBtnIndex == 1) {
  1767. this.searchCoopFileList = [];
  1768. }
  1769. }
  1770. },
  1771. searchContent() {
  1772. this.searchForFile();
  1773. },
  1774. localFileHashMap(val) {
  1775. let temp = {};
  1776. for(let key in val) {
  1777. temp[val[key]] = key;
  1778. }
  1779. this.reverseLocalFileHashMap = temp;
  1780. },
  1781. nowFolderIndex() {
  1782. this.isfinishGetExchangeNodes && this.getExchangeNodes();
  1783. },
  1784. rightMenuvisible(value) {
  1785. if (value) {
  1786. document.body.addEventListener("click", this.closeShowMenu);
  1787. } else {
  1788. document.body.removeEventListener("click", this.closeShowMenu);
  1789. }
  1790. },
  1791. localFileLoadStateMap(obj) {
  1792. const hash = {};
  1793. Object.values(obj).forEach(state => {
  1794. const relativePath = state.fileRelativePath;
  1795. if(!relativePath) return;
  1796. analyzeRelativePath(relativePath, '', (folderPath) => {
  1797. hash[folderPath] = true;
  1798. });
  1799. })
  1800. this.localFolderLoadStateMap = hash;
  1801. }
  1802. }
  1803. }
  1804. </script>
  1805. <style>
  1806. .section_item.section_item_aside_fl {
  1807. overflow: hidden;
  1808. }
  1809. .el-message-box--center .el-message-box__status.el-icon-warning {
  1810. position: absolute;
  1811. left: 0;
  1812. }
  1813. .yywenjiantitle_text1 {
  1814. position: relative;
  1815. top: 2px;
  1816. }
  1817. .youbian {
  1818. color: #a7a8b7;
  1819. position: relative;
  1820. top: 2px;
  1821. }
  1822. .app-header-style {
  1823. background-color: #f0f0f0;
  1824. }
  1825. .app-header-style .app-header-content-right {
  1826. display: flex;
  1827. }
  1828. </style>
  1829. <style lang="scss" scoped>
  1830. .titleBox {
  1831. position: relative;
  1832. }
  1833. .app-header-style {
  1834. background-color: #f0f0f0;
  1835. }
  1836. .titlebar_head {
  1837. flex-direction: column;
  1838. }
  1839. .yiyun_section_top {
  1840. overflow: visible;
  1841. }
  1842. .folder_breadcrumb {
  1843. ::v-deep .el-breadcrumb__item {
  1844. user-select: none;
  1845. font-size: 18px;
  1846. display: inline-block;
  1847. height: 40px;
  1848. line-height: 40px;
  1849. .el-breadcrumb__separator {
  1850. color: #a7a8b7;
  1851. }
  1852. &:not(:last-child) {
  1853. cursor: pointer;
  1854. }
  1855. }
  1856. }
  1857. ::v-deep .readytodownload-icon {
  1858. position: relative;
  1859. top: 40px;
  1860. margin: 0 auto;
  1861. }
  1862. ::v-deep .progress-circle , ::v-deep .readytodownload-icon {
  1863. width: 45px;
  1864. height: 45px;
  1865. background-color: #fff;
  1866. border-radius: 50%;
  1867. }
  1868. ::v-deep .progress-circle , ::v-deep .readytodownload-icon img, ::v-deep .progress-circle .bg-pic{
  1869. position: absolute;
  1870. top: 50%;
  1871. left: 50%;
  1872. transform: translate(-50%, -50%);
  1873. }
  1874. ::v-deep .progress-circle svg {
  1875. position:relative !important;
  1876. }
  1877. ::v-deep .progress-circle svg .el-progress-circle__track {
  1878. stroke: #fff !important;
  1879. }
  1880. .filePreview{
  1881. text-align: center;
  1882. video{
  1883. width: 820px;
  1884. height: 600px;
  1885. }
  1886. }
  1887. .img-container {
  1888. margin: 0 auto;
  1889. }
  1890. /* 新建样本文件弹框样式 */
  1891. .temp-file-dialog {
  1892. /* 新建样板文件弹框的提示文件名 */
  1893. .guide-template-file-name {
  1894. color: rgba(0, 0, 0, 1);
  1895. font-size: 14px;
  1896. text-align: center;
  1897. font-family: PingFangSC-Regular;
  1898. padding: 16px;
  1899. text-align: center;
  1900. }
  1901. }
  1902. </style>
  1903. <style lang="scss">
  1904. .temp-file-dialog {
  1905. .el-dialog {
  1906. background-color: #fcfcfc;
  1907. .el-dialog__header {
  1908. padding: 19px 0;
  1909. }
  1910. .el-dialog__body {
  1911. padding: 0 !important;
  1912. .el-form {
  1913. padding: 20px 0 0 0;
  1914. background-color: #f1f1f1;
  1915. .el-form-item {
  1916. margin:0 0 0 0;
  1917. }
  1918. }
  1919. }
  1920. .el-form-item__content {
  1921. padding: 0 16px;
  1922. .el-input__inner {
  1923. background-color: #ddd;
  1924. margin: 0 0 20px 0;
  1925. }
  1926. }
  1927. .dialog-footer {
  1928. display: flex;
  1929. justify-content: space-between;
  1930. padding: 16px;
  1931. }
  1932. .el-dialog__footer {
  1933. padding: 0;
  1934. .el-button {
  1935. border-radius: 8px;
  1936. /* &.el-button--primary {
  1937. background-color: #7850ff;
  1938. } */
  1939. }
  1940. }
  1941. }
  1942. }
  1943. </style>
  1944. <style scoped lang="scss">
  1945. .set-bg {
  1946. background-color: #f6f6f6;
  1947. }
  1948. .operate-bar {
  1949. width: 162px;
  1950. margin: 28px auto 15px;
  1951. }
  1952. .search-res-page-wrap {
  1953. margin: 0 64px;
  1954. box-sizing: border-box;
  1955. }
  1956. .out-wrap {
  1957. height: calc(100vh - (60px + 28px + 28px + 15px));
  1958. overflow: scroll;
  1959. }
  1960. .out-wrap::-webkit-scrollbar{
  1961. width: 8px;
  1962. border-radius: 4px;
  1963. }
  1964. .out-wrap::-webkit-scrollbar-thumb {
  1965. -webkit-border-radius: 10px;
  1966. border-radius: 10px;
  1967. height: 10px;
  1968. background-color: #adadad;
  1969. }
  1970. /*当前窗口失去焦点时的滑块样式*/
  1971. .out-wrap::-webkit-scrollbar-thumb:window-inactive {
  1972. background-color: #adadad;
  1973. }
  1974. .no-file-tips {
  1975. font-size: 22px;
  1976. text-align: center;
  1977. margin: 100px auto;
  1978. }
  1979. </style>
  1980. <style scoped lang="scss">
  1981. .my-workline {
  1982. text-align: center;
  1983. }
  1984. .adjust-workline-pos-client {
  1985. position: relative;
  1986. top: -12px;
  1987. }
  1988. .adjust-workline-pos-web {
  1989. position: relative;
  1990. top: -2.5px;
  1991. }
  1992. .ml-4-mt-20 {
  1993. margin: 20px 0 0 4px;
  1994. }
  1995. .height-0 {
  1996. height: 0;
  1997. }
  1998. .layout_content2 {
  1999. height: calc(100vh - 64px);
  2000. }
  2001. // 调整协作文件显示区域的高度
  2002. .coopBox-max-height {
  2003. height: 300px;
  2004. }
  2005. </style>
  2006. <style scoped>
  2007. </style>