documentPage.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. <template>
  2. <!-- 文档管理 -->
  3. <div class="document-file-page-wrap">
  4. <!-- 目录栏 -->
  5. <div class="catalog-wrap page-block-wrap catalog-block" id="left">
  6. <div class="btn-box">
  7. <el-button v-permission="permissionBtn.semanticPermission.docPage_save"
  8. type="primary" @click="toPage('addFile')">{{$t('SemanticsManage.DocumentManagement.add_document_btn')}}</el-button>
  9. </div>
  10. <div class="select-wrap">
  11. <el-select
  12. filterable remote
  13. :placeholder="$t('SemanticsManage.DocumentManagement.input_enter_fiel_content')"
  14. v-model="searchTitle"
  15. :remote-method="searchHandle"
  16. value-key="SaDocId"
  17. clearable
  18. >
  19. <i slot="prefix" class="el-input__icon el-icon-search"></i>
  20. <el-option
  21. v-for="item in searchOptions"
  22. :key="item.SaDocId"
  23. :label="item.Title"
  24. :value="item"
  25. >
  26. </el-option>
  27. </el-select>
  28. </div>
  29. <div class="catalog-list-wrap">
  30. <div class="catalog-list">
  31. <el-tree
  32. ref="catalogTree"
  33. class="catalog-tree other-tree"
  34. empty-text="暂无分类"
  35. :data="listData"
  36. node-key="nodeKeyId"
  37. :expand-on-click-node="true"
  38. :default-expanded-keys="expandKeys"
  39. draggable
  40. :allow-drag="checkAllowDrag"
  41. :allow-drop="checkAllowDrop"
  42. @node-drop="handleDropOver"
  43. @node-expand="handleNodeExpand"
  44. @node-collapse="handleNodeCollapse"
  45. @current-change="(data,node)=>{nodeChange(data,node)}"
  46. >
  47. <span class="custom-tree-node" slot-scope="{ data,node }"
  48. >
  49. <span class="tree-label">{{ data.label }}</span>
  50. <span style="display: flex; align-items: center"
  51. v-if="data.nodeKeyId===selectNodeKey"
  52. >
  53. <img
  54. :src="require('@/assets/img/set_m/edit.png')"
  55. alt="" v-if="node.level!==2&&isShowTreeBtn(node.level,'edit')"
  56. style="width: 14px; height: 14px; margin-right: 5px"
  57. @click.stop="clickNodeHandle('edit', data)"
  58. />
  59. <img
  60. :src="require('@/assets/img/data_m/move_ico.png')"
  61. alt="" v-if="node.level === 2"
  62. style="width: 14px; height: 14px; margin-right: 5px"
  63. />
  64. <img
  65. :src="require('@/assets/img/set_m/del.png')"
  66. alt="" v-if="isShowTreeBtn(node.level,'delete')"
  67. style="width: 14px; height: 14px; margin-right: 5px"
  68. @click.stop="clickNodeHandle('del', data)"
  69. />
  70. </span>
  71. </span>
  72. </el-tree>
  73. </div>
  74. </div>
  75. <div class="catalog-tool">
  76. <div class="add-catalog" @click="isModifyClassifyShow=true" v-if="isShowTreeBtn(1,'edit')">
  77. <img
  78. src="~@/assets/img/set_m/add_ico.png"
  79. alt=""
  80. style="width: 16px; height: 16px; margin-right: 6px"
  81. />
  82. <span>{{$t('SemanticsManage.DocumentManagement.add_category')}}</span>
  83. </div>
  84. <span class="total-text" v-if="selectNode&&model==='list'">
  85. {{$t('SemanticsManage.DocumentManagement.all_num_document',{num:catalogList.length})}}</span>
  86. </div>
  87. <span class="move-btn resize" v-drag id="resize"></span>
  88. </div>
  89. <div class="detail-wrap page-block-wrap catalog-block" id="right">
  90. <!-- 列表栏 -->
  91. <div class="detail-list overflow-hide-scrollbar" v-if="model==='list'">
  92. <!-- 选择一级分类不再展示列表 -->
  93. <!-- <draggable
  94. class="drag-cont"
  95. v-model="catalogList"
  96. animation="300"
  97. @start="dragStartHandler"
  98. @update="dragenter"
  99. @end="moveListItem"
  100. :disabled="true">
  101. <div class="list-item"
  102. v-for="item in catalogList" :key="item.nodeKeyId"
  103. @click="changeModel('file',item)"
  104. >
  105. <div class="item-title">
  106. <span>{{item.label}}</span>
  107. <img
  108. src="~@/assets/img/data_m/move_ico.png"
  109. style="width: 14px; height: 14px; margin-right: 8px"
  110. />
  111. </div>
  112. <div style="height:1px;background:#ECECEC;margin:0 -10px;"></div>
  113. <div class="item-image" :style="`background-image:url(${item.CoverImg?item.CoverImg:require('@/assets/img/document_m/default-img.png')})`"></div>
  114. <div style="height:1px;background:#ECECEC;margin:0 -10px;"></div>
  115. <div class="item-info">
  116. <span style="font-size:14px;">{{item.Theme}}</span>
  117. <span @click.stop>
  118. <el-dropdown @command="handleOperateCommand" trigger="click">
  119. <span class="el-dropdown-link">
  120. <i class="el-icon-more" style="font-size: 16px;cursor: pointer"/>
  121. </span>
  122. <el-dropdown-menu slot="dropdown">
  123. <el-dropdown-item :command="{key:'edit',data:item}">编辑</el-dropdown-item>
  124. <el-dropdown-item :command="{key:'del',data:item}">删除</el-dropdown-item>
  125. </el-dropdown-menu>
  126. </el-dropdown>
  127. </span>
  128. </div>
  129. </div>
  130. </draggable> -->
  131. <div class="empty" v-if="catalogList.length===0">
  132. <tableNoData :text="$t('SemanticsManage.DocumentManagement.prompt_slogan')"/>
  133. </div>
  134. </div>
  135. <!-- 文件详情 -->
  136. <div class="detail-file" v-else>
  137. <div class="file-info">
  138. <ul>
  139. <li class="name">{{$t('SemanticsManage.DocumentManagement.document_name')}}:{{docInfo.Title}}</li>
  140. <!-- <li>文档主题:{{docInfo.Theme}}</li> -->
  141. <li>{{$t('SemanticsManage.DocumentManagement.document_category')}}:{{docInfo.ClassifyName}}</li>
  142. </ul>
  143. <el-button v-permission="permissionBtn.semanticPermission.docPage_save"
  144. type="primary" @click="handleEdit('file',selectNode)">{{$t('Table.edit_btn')}}</el-button>
  145. </div>
  146. <div class="file-content overflow-hide-scrollbar">
  147. <p v-for="block in docInfo.SectionList" :key="block.SaDocSectionId">{{block.innerText}}</p>
  148. </div>
  149. </div>
  150. </div>
  151. <!-- 添加/编辑分类弹窗 -->
  152. <el-dialog
  153. :title="classifyForm.classify_id? $t('SemanticsManage.DocumentManagement.edit_category') : $t('SemanticsManage.DocumentManagement.add_category') "
  154. :visible.sync="isModifyClassifyShow"
  155. :close-on-click-modal="false"
  156. :modal-append-to-body="false"
  157. @close="clearForm"
  158. width="589px"
  159. v-dialogDrag
  160. center
  161. >
  162. <div class="dialog-container">
  163. <el-form
  164. ref="formRef"
  165. label-position="left"
  166. hide-required-asterisk
  167. :model="classifyForm"
  168. :rules="classifyFormRules"
  169. >
  170. <el-form-item label-width="118px" :label="$t('SemanticsManage.DocumentManagement.add_category_name')" prop="classify_name">
  171. <el-input
  172. v-model="classifyForm.classify_name"
  173. style="width: 80%"
  174. :placeholder="$t('SemanticsManage.DocumentManagement.add_category_input_name')"
  175. />
  176. </el-form-item>
  177. <!-- 文档分类的封面图取消 -->
  178. <!-- <el-form-item label="封面图" prop="classify_img" ref="uploadImg">
  179. <el-upload
  180. action=""
  181. accept="image/png,image/jpg,image/jpeg"
  182. :http-request="handleUploadImg"
  183. :show-file-list="false"
  184. :key="uploadKey"
  185. >
  186. <div class="upload-box">
  187. <template v-if="!classifyForm.classify_img">
  188. <i class="el-icon-plus" style="font-size: 24px;"></i>
  189. <p class="form-hint">点击上传图片</p>
  190. </template>
  191. <template v-else>
  192. <img
  193. class="upload-img"
  194. :src="classifyForm.classify_img" alt="封面图"
  195. >
  196. <span class="upload-mask">
  197. <span
  198. class="mask-icon"
  199. @click.stop="handleRemove(file)"
  200. >
  201. <i class="el-icon-delete"></i>
  202. </span>
  203. </span>
  204. </template>
  205. </div>
  206. </el-upload>
  207. <p class="form-hint">支持格式:PNG、JPEG</p>
  208. </el-form-item> -->
  209. </el-form>
  210. </div>
  211. <div class="foot-container">
  212. <el-button @click="clearForm">{{ $t('Dialog.cancel_btn')}}</el-button>
  213. <el-button type="primary" @click="modifyClassify">{{ $t('Dialog.confirm_btn')}}</el-button>
  214. </div>
  215. </el-dialog>
  216. </div>
  217. </template>
  218. <script>
  219. /* js */
  220. import catalogMixin from "./mixins/catalogMixin";
  221. import { formatArr,formatFile } from './utils/index';
  222. /* components */
  223. //import draggable from 'vuedraggable';
  224. /* api */
  225. import {customInterence} from '@/api/api.js'
  226. import {documentInterface} from '@/api/modules/semanticsApi.js';
  227. export default {
  228. mixins:[catalogMixin],
  229. data() {
  230. return {
  231. classifyForm:{},//分类信息
  232. classifyFormRules:{
  233. classify_name:[{ required: true, message: "分类名称不能为空"}],
  234. //classify_img:[{ required: true, message: "分类图片不能为空"}] //el-upload 触发校验后再校验不会更新这个
  235. //classify_img:[{validator:this.checkImg}],//使用自定义规则
  236. },//分类校验规则
  237. isModifyClassifyShow:false,//控制分类显示弹窗
  238. uploadKey:0,//刷新上传图片
  239. docInfo:{},//文档详情
  240. };
  241. },
  242. watch:{
  243. searchTitle(newVal){ //选中搜索结果
  244. const {SaDocId,ClassifyId} = newVal
  245. if(SaDocId&&ClassifyId){ //展开对应项
  246. this.handleNodeExpand({nodeKeyId:ClassifyId+''})
  247. this.nodeChange({SaDocId,nodeKeyId:`children_${SaDocId}`},{level:2})
  248. this.searchOptions = []
  249. }
  250. }
  251. },
  252. methods: {
  253. //搜索文档
  254. searchHandle(keyword){
  255. documentInterface.getDocumentList({
  256. PageSize:1000,
  257. CurrentIndex:1,
  258. Keyword:keyword
  259. }).then(res=>{
  260. if(res.Ret!==200) return
  261. this.searchOptions = res.Data.List||[]
  262. })
  263. },
  264. //获取分类列表
  265. async getListData(){
  266. await documentInterface.getClassifyList().then(res=>{
  267. if(res.Ret!==200) return
  268. this.listData = formatArr(res.Data||[])
  269. })
  270. },
  271. //获取文档详情
  272. getDetail(data){
  273. const {SaDocId} = data
  274. documentInterface.getDocumentDetail({
  275. DocId:Number(SaDocId)
  276. }).then(res=>{
  277. if(res.Ret!==200) return
  278. this.docInfo = formatFile(res.Data)
  279. })
  280. },
  281. //新增/编辑分类
  282. async modifyClassify(){
  283. let res = null
  284. let flag = false
  285. const {classify_id,classify_name,/* classify_img */} = this.classifyForm
  286. this.$refs.formRef.validate((valid) => {
  287. flag = valid
  288. })
  289. if(!flag) return
  290. if(classify_id){
  291. res = await documentInterface.editClassify({
  292. SaDocClassifyId:Number(classify_id),
  293. ClassifyName:classify_name,
  294. /* CoverImg:classify_img */
  295. })
  296. }else{
  297. res = await documentInterface.addNewClassify({
  298. ClassifyName:classify_name,
  299. /* CoverImg:classify_img */
  300. })
  301. }
  302. if(res.Ret!==200) return
  303. this.$message.success(`${classify_id ? this.$t('MsgPrompt.edit_msg') : this.$t('MsgPrompt.add_msg') }`)
  304. await this.getListData()
  305. if(classify_id){//编辑后,重新选中该分类
  306. const catalog = this.listData.find(item=>{return item.nodeKeyId===classify_id})
  307. catalog&&this.nodeChange(catalog,{level:1})
  308. }
  309. this.clearForm()
  310. },
  311. //删除分类
  312. async deleteClassify(data){
  313. await documentInterface.deleteClassify({
  314. SaDocClassifyId:Number(data.SaDocClassifyId)
  315. }).then(res=>{
  316. if(res.Ret!==200) return
  317. this.$message.success(this.$t('MsgPrompt.delete_msg'))
  318. this.clearForm()
  319. })
  320. },
  321. //删除文档
  322. async deleteDocument(data){
  323. await documentInterface.deleteDocument({
  324. SaDocId:Number(data.SaDocId)
  325. }).then(async res=>{
  326. if(res.Ret!==200) return
  327. this.$message.success(this.$t('MsgPrompt.delete_msg'))
  328. this.chooseDataClassify(data)
  329. })
  330. },
  331. /**
  332. * 文档分类封面图相关的代码,由于封面图取消这部分代码都没用到,不过还是留着吧
  333. */
  334. //删除已上传的图片
  335. handleRemove(e){
  336. this.classifyForm.classify_img=''
  337. this.uploadKey++
  338. },
  339. //上传图片
  340. async handleUploadImg(e){
  341. //console.log('upload',e.file);
  342. //验证图片类型
  343. if(!['image/png','image/jpg','image/jpeg'].includes(e.file.type)){
  344. this.$message.warning(this.$t('SemanticsManage.DocumentManagement.select_img_mag') )
  345. return
  346. }
  347. let form = new FormData()
  348. form.append("file", e.file)
  349. const res=await customInterence.upload(form)
  350. if(res.Ret===200){
  351. this.$refs.formRef&&this.$refs.formRef.clearValidate();
  352. this.classifyForm.classify_img=res.Data.ResourceUrl
  353. this.uploadKey++
  354. }
  355. },
  356. checkImg(rule,value,callback){
  357. if(!this.classifyForm.classify_img){
  358. return callback(new Error(this.$t('SemanticsManage.DocumentManagement.img_no_empty_msg') ))
  359. }else{
  360. callback()
  361. }
  362. },
  363. /**------------------ */
  364. //切换页面
  365. toPage(pageName,params){
  366. const routerPathMap = {
  367. 'addFile':'/addDocument',
  368. 'editFile':'/editDocument',
  369. 'tag':'/tagPage'
  370. }
  371. this.$router.push({
  372. path:routerPathMap[pageName],
  373. query:params||{}
  374. })
  375. },
  376. //移动文档
  377. moveDocument(moveParams){
  378. documentInterface.moveDocument(moveParams).then(async res=>{
  379. if(res.Ret!==200) return
  380. await this.getListData()
  381. this.handleNodeExpand({
  382. nodeKeyId: moveParams.SaDocClassifyId
  383. })
  384. this.nodeChange({
  385. SaDocId:moveParams.SaDocId,
  386. nodeKeyId:`children_${moveParams.SaDocId}`},
  387. {
  388. level:2
  389. })
  390. this.$message.success(this.$t('ETable.Msg.move_success_msg') )
  391. })
  392. },
  393. //根据层级判断是否展示编辑/删除按钮
  394. isShowTreeBtn(level,btnType){
  395. return level===1
  396. ?this.permissionBtn.isShowBtn('semanticPermission',`docPage_classifyOpt_${btnType}`)
  397. :this.permissionBtn.isShowBtn('semanticPermission',`docPage_${btnType==='edit'?'save':btnType}`)
  398. }
  399. },
  400. };
  401. </script>
  402. <style lang="scss">
  403. @import "./css/catalogTree.scss";
  404. .document-file-page-wrap{
  405. .file-content{
  406. p{
  407. font-size: 16px !important;
  408. }
  409. }
  410. }
  411. </style>
  412. <style scoped lang="scss">
  413. @import "./css/basePage.scss";
  414. @import "./css/catalogPage.scss";
  415. .document-file-page-wrap{
  416. display: flex;
  417. width: 100%;
  418. .dialog-container{
  419. padding: 0 35px;
  420. .upload-box{
  421. position:relative;
  422. width:120px;
  423. height: 120px;
  424. background-color: #F5F7F9;
  425. border: 1px dashed #DCDFE6;
  426. display: flex;
  427. flex-direction: column;
  428. align-items: center;
  429. justify-content: center;
  430. &:hover{
  431. border: 1px dashed #409EFF;
  432. .upload-mask{
  433. opacity: 1;
  434. }
  435. }
  436. .upload-img,.upload-mask{
  437. width:100%;
  438. height:100%;
  439. }
  440. .upload-mask{
  441. position:absolute;
  442. left: 0;
  443. top: 0;
  444. cursor: default;
  445. text-align: center;
  446. color: #fff;
  447. opacity: 0;
  448. font-size: 20px;
  449. background-color: rgba(0,0,0,.5);
  450. transition: opacity .3s;
  451. z-index: 2;
  452. line-height: 120px;
  453. .mask-icon{
  454. cursor: pointer;
  455. }
  456. }
  457. }
  458. }
  459. .file-info{
  460. padding:20px 30px;
  461. display: flex;
  462. align-items: center;
  463. justify-content: space-between;
  464. }
  465. .file-content{
  466. padding:30px;
  467. }
  468. }
  469. </style>