main.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never" v-loading="loading">
  4. <ele-split-layout
  5. width="210px"
  6. allow-collapse
  7. :right-style="{ overflow: 'hidden' }"
  8. >
  9. <div>
  10. <!-- 操作按钮 -->
  11. <ele-toolbar class="ele-toolbar-actions">
  12. <div style="margin: 5px 0">
  13. <!-- <el-button
  14. size="small"
  15. type="primary"
  16. icon="el-icon-plus"
  17. class="ele-btn-icon"
  18. @click="openEdit()"
  19. >
  20. 添加
  21. </el-button>
  22. <el-button
  23. size="small"
  24. type="warning"
  25. icon="el-icon-edit"
  26. class="ele-btn-icon"
  27. :disabled="!current"
  28. @click="openEdit(current)"
  29. >
  30. 修改
  31. </el-button>
  32. <el-button
  33. size="small"
  34. type="danger"
  35. icon="el-icon-delete"
  36. class="ele-btn-icon"
  37. :disabled="!current"
  38. @click="remove"
  39. >
  40. 删除
  41. </el-button> -->
  42. </div>
  43. </ele-toolbar>
  44. <div class="ele-border-lighter sys-organization-list">
  45. <el-tree
  46. ref="tree"
  47. :data="data"
  48. highlight-current
  49. :draggable="true"
  50. node-key="id"
  51. :props="{ label: 'name', children: 'sonDirectoryList' }"
  52. :expand-on-click-node="false"
  53. :default-expanded-keys="defaultExpandedKeys"
  54. @node-click="onNodeClick"
  55. @node-drop="nodeDrop"
  56. :allow-drop="allowDrop"
  57. >
  58. <span
  59. class="custom-tree-node"
  60. slot-scope="{ node, data }"
  61. @contextmenu.prevent="onRightClick(data, $event)"
  62. @click.prevent="clicka"
  63. ref="trueNodeRef"
  64. >
  65. <el-popover
  66. style="position: fixed; z-index: 2000"
  67. width="130"
  68. ref="popoverRef"
  69. v-model="visible"
  70. @click.native="visible = false"
  71. v-if="data.id == rightData.id && fileType === 0 && !isPop"
  72. >
  73. <div>
  74. <el-link
  75. v-if="lcyStatus == 1 && isPower(current)"
  76. :underline="false"
  77. @click.native="setPower(data)"
  78. >更改权限
  79. </el-link></div
  80. >
  81. <div>
  82. <el-link
  83. v-if="lcyStatus != 1"
  84. :underline="false"
  85. @click.native="goTo('文档工作区', data)"
  86. >转到文档工作区
  87. </el-link></div
  88. >
  89. <div>
  90. <el-link
  91. v-if="lcyStatus != '2'"
  92. :underline="false"
  93. @click.native="goTo('文档归档区', data)"
  94. >转到文档归档区
  95. </el-link></div
  96. >
  97. <div>
  98. <el-link
  99. v-if="lcyStatus != '3'"
  100. :underline="false"
  101. @click.native="goTo('文档发布区', data)"
  102. >转到文档发布区
  103. </el-link></div
  104. >
  105. </el-popover>
  106. <ElementTreeLine
  107. :node="node"
  108. :showLabelLine="true"
  109. :indent="20"
  110. >
  111. <img src="../../../assets/wjj.png" />
  112. <span>{{ node.label }}</span>
  113. </ElementTreeLine>
  114. </span>
  115. </el-tree>
  116. </div>
  117. </div>
  118. <template v-slot:content>
  119. <FileTableList
  120. ref="tableRef"
  121. :parentData="current"
  122. :folderList="data"
  123. @parenOpen="openEdit"
  124. :fileType="fileType"
  125. :lcyStatus="lcyStatus"
  126. :isPop="isPop"
  127. :disabledTableList="disabledTableList"
  128. />
  129. </template>
  130. </ele-split-layout>
  131. </el-card>
  132. <!-- 编辑弹窗 -->
  133. <folder-edit @done="query" ref="editRef" :fileType="fileType" />
  134. <!-- 文件夹权限 -->
  135. <ele-modal
  136. width="50vw"
  137. :visible="powerVisible"
  138. @close="powerVisible = false"
  139. :close-on-click-modal="false"
  140. append-to-body
  141. >
  142. <Power @powerSave="powerSave" ref="PowerRef" :powerArr="powerArr" />
  143. </ele-modal>
  144. <!-- {{current?.id}} -->
  145. </div>
  146. </template>
  147. <script>
  148. //
  149. import FileTableList from '@/views/doc/components/file-table-list.vue';
  150. import folderEdit from '@/views/doc/components/folder-edit.vue';
  151. import {
  152. directoryDeleteAPI,
  153. getDocTreeListAPI,
  154. directoryUpdateAPi,
  155. validationPersonal,
  156. moveDirectory
  157. } from '@/api/doc-manage';
  158. import { mapGetters } from 'vuex';
  159. import Power from './power/index.vue';
  160. import { isPower } from '../util.js';
  161. import ElementTreeLine from 'element-tree-line';
  162. // css
  163. import 'element-tree-line/dist/style.scss';
  164. export default {
  165. components: { FileTableList, folderEdit, ElementTreeLine, Power },
  166. props: {
  167. fileType: '', //0:公共文档 1:个人文档 2:文档模板
  168. lcyStatus: '', //1:文档工作区 2:文档归档区 3:文档发布区 4:文档废止区
  169. isPop: {
  170. //是否弹出
  171. default: false
  172. },
  173. disabledTableList: {
  174. //已选择列表
  175. default: () => []
  176. }
  177. },
  178. data() {
  179. return {
  180. isPower,
  181. powerArr: [
  182. { name: 'add', label: '新建' },
  183. { name: 'revise', label: '修改' },
  184. { name: 'del', label: '删除' }
  185. ],
  186. visible: false,
  187. powerVisible: false,
  188. rightData: {},
  189. // 加载状态
  190. loading: true,
  191. // 列表数据
  192. data: [],
  193. institutionList: [],
  194. // 选中数据
  195. current: {},
  196. // 是否显示表单弹窗
  197. showFolderEditFlag: false,
  198. // 编辑回显数据
  199. editData: null,
  200. // 上级id
  201. parentId: null,
  202. defaultExpandedKeys: []
  203. };
  204. },
  205. computed: {
  206. ...mapGetters(['user'])
  207. },
  208. created() {
  209. this.query();
  210. },
  211. mounted() {
  212. document.addEventListener('click', this.clicka);
  213. },
  214. destroyed() {
  215. document.removeEventListener('click', this.clicka);
  216. },
  217. methods: {
  218. /* 查询 */
  219. async query(row) {
  220. this.loading = true;
  221. let query = {
  222. type: this.fileType,
  223. currentUserId: this.user.info.userId
  224. };
  225. this.data = await getDocTreeListAPI(query);
  226. if (this.fileType == 1 && this.data.length == 0) {
  227. await validationPersonal();
  228. await this.query();
  229. }
  230. // if (this.data.length) {
  231. // this.defaultExpandedKeys = [this.data[0].id];
  232. // }
  233. this.$nextTick(() => {
  234. // alert(row)
  235. if (this.$route.params.row) {
  236. this.$refs.tree.setCurrentKey(this.$route.params.row.id);
  237. this.defaultExpandedKeys = [this.$route.params.row.id];
  238. this.onNodeClick(this.$route.params.row);
  239. } else if (row && row.id) {
  240. this.$refs.tree.setCurrentKey(row.id);
  241. this.defaultExpandedKeys = [row.id];
  242. this.onNodeClick(row);
  243. } else if (row == 'isDefaultExpandedKeys'&&this.current?.id) {
  244. this.$refs.tree.setCurrentKey(this.current.id);
  245. this.defaultExpandedKeys = [this.current.id];
  246. this.onNodeClick(this.current);
  247. } else {
  248. this.$refs.tree.setCurrentKey(this.data[0].id);
  249. this.defaultExpandedKeys = [this.data[0].id];
  250. this.onNodeClick(this.data[0]);
  251. }
  252. });
  253. this.loading = false;
  254. },
  255. /* 选择数据 */
  256. onNodeClick(row, node, list) {
  257. console.log('row', row, node, list);
  258. if (row) {
  259. // 构建完整路径
  260. const fullPath = this.buildFullPath(row, this.data);
  261. // 将完整路径添加到current对象中
  262. this.current = {
  263. ...row,
  264. fullPath: fullPath
  265. };
  266. this.$nextTick(() => {
  267. this.$refs.tableRef.reload();
  268. });
  269. } else {
  270. this.current = null;
  271. }
  272. },
  273. /* 构建完整路径 */
  274. buildFullPath(currentNode, folderList) {
  275. // 如果节点没有parentId,直接返回节点名称
  276. if (!currentNode.parentId || currentNode.parentId === 0) {
  277. return currentNode.name;
  278. }
  279. // 递归查找上级节点
  280. function findParent(node, list) {
  281. let path = [node.name];
  282. let parentId = node.parentId;
  283. // 递归查找所有父节点
  284. function searchParent(id) {
  285. for (const item of list) {
  286. if (item.id === id) {
  287. path.unshift(item.name); // 将父节点名称添加到路径开头
  288. if (item.parentId && item.parentId !== 0) {
  289. searchParent(item.parentId); // 继续查找上一级
  290. }
  291. return;
  292. }
  293. // 如果当前节点有子节点,继续在子节点中查找
  294. if (item.sonDirectoryList && item.sonDirectoryList.length > 0) {
  295. searchParentInChildren(item.sonDirectoryList, id);
  296. }
  297. }
  298. }
  299. // 在子节点列表中查找父节点
  300. function searchParentInChildren(children, id) {
  301. for (const child of children) {
  302. if (child.id === id) {
  303. path.unshift(child.name);
  304. if (child.parentId && child.parentId !== 0) {
  305. searchParent(child.parentId);
  306. }
  307. return;
  308. }
  309. if (child.sonDirectoryList && child.sonDirectoryList.length > 0) {
  310. searchParentInChildren(child.sonDirectoryList, id);
  311. }
  312. }
  313. }
  314. if (parentId) {
  315. searchParent(parentId);
  316. }
  317. return path.join(' / ');
  318. }
  319. return findParent(currentNode, folderList);
  320. },
  321. allowDrop(draggingNode, dropNode, type) {
  322. //拖拽限制
  323. return dropNode.parent.id == draggingNode.parent.id && type != 'inner';
  324. },
  325. clicka() {
  326. this.visible = false;
  327. },
  328. onRightClick(data, PointerEvent) {
  329. this.rightData = data;
  330. this.visible = true;
  331. this.$nextTick(() => {
  332. let y = PointerEvent.pageY;
  333. let x = PointerEvent.pageX + 10;
  334. if (PointerEvent.screenY >= PointerEvent.view.innerHeight) {
  335. y -= 80;
  336. }
  337. this.$refs.popoverRef.$el.style.top = y + 'px';
  338. this.$refs.popoverRef.$el.style.left = x + 'px';
  339. });
  340. },
  341. setPower(data) {
  342. this.powerVisible = true;
  343. this.$nextTick(() => {
  344. this.$refs.PowerRef &&
  345. this.$refs.PowerRef.setTableList(data.userAuthority || []);
  346. });
  347. },
  348. //权限保存
  349. powerSave(tableList) {
  350. directoryUpdateAPi({
  351. id: this.current.id,
  352. userAuthority: tableList,
  353. authority: 1
  354. }).then((msg) => {
  355. this.powerVisible = false;
  356. this.query(this.current);
  357. });
  358. },
  359. goTo(name, row) {
  360. this.$router.push({
  361. name,
  362. params: {
  363. row
  364. }
  365. });
  366. },
  367. /* 显示编辑 */
  368. openEdit(type) {
  369. if (type == 'del') {
  370. this.remove();
  371. return;
  372. }
  373. this.$refs.editRef.open(
  374. type,
  375. JSON.parse(JSON.stringify(this.current)),
  376. this.data
  377. );
  378. },
  379. /* 删除 */
  380. remove() {
  381. this.$confirm('确定要删除选中文件夹吗?', '提示', {
  382. type: 'warning'
  383. })
  384. .then(() => {
  385. const loading = this.$loading({ lock: true });
  386. directoryDeleteAPI([this.current.id])
  387. .then((msg) => {
  388. loading.close();
  389. this.$message.success('操作成功');
  390. this.query();
  391. })
  392. .catch((e) => {
  393. loading.close();
  394. });
  395. })
  396. .catch(() => {});
  397. },
  398. nodeDrop(to, form) {
  399. moveDirectory({
  400. targetId: form.data.id,
  401. replaceId: to.data.id
  402. });
  403. },
  404. getTableList() {
  405. return this.$refs.tableRef.getTableList();
  406. }
  407. }
  408. };
  409. </script>
  410. <style lang="scss" scoped>
  411. .sys-organization-list {
  412. height: calc(100vh - 180px);
  413. box-sizing: border-box;
  414. border-width: 1px;
  415. border-style: solid;
  416. overflow: auto;
  417. }
  418. .sys-organization-list :deep(.el-tree-node__content) {
  419. height: 25px;
  420. & > .el-tree-node__expand-icon {
  421. margin-left: 10px;
  422. }
  423. }
  424. .custom-tree-node {
  425. display: flex;
  426. align-items: center;
  427. }
  428. :deep(.el-popover) {
  429. min-width: 50px;
  430. position: fixed;
  431. background: #409eff;
  432. }
  433. :deep(.el-link--inner) {
  434. padding: 3px 0;
  435. }
  436. :deep(.el-link.el-link--default) {
  437. color: #fff;
  438. }
  439. // :deep(.element-tree-node-line-hor) {
  440. // border-bottom: 1px solid #dcdfe6;
  441. // }
  442. // :deep(.element-tree-node-line-ver) {
  443. // border-left: 1px solid #dcdfe6;
  444. // }
  445. </style>
  446. <style lang="scss">
  447. .el-tree
  448. > .el-tree-node
  449. > .el-tree-node__content:nth-of-type(1)
  450. .element-tree-node-line-hor {
  451. border: none;
  452. }
  453. .el-tree
  454. > .el-tree-node
  455. > .el-tree-node__content:nth-of-type(1)
  456. .element-tree-node-line-ver {
  457. border: none;
  458. }
  459. .el-tree-node > .el-tree-node__children {
  460. overflow: inherit;
  461. }
  462. </style>