classifylistV2.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. <template>
  2. <div class="classify-page">
  3. <div class="top-wrap">
  4. <div class="type-box">
  5. <!-- 中文分类 -->
  6. <div class="item active"
  7. v-permission="[
  8. permissionBtn.classifyBtn.classifyList_cnClassify,
  9. permissionBtn.enClassifyBtn.classifyList_enClassify,
  10. 'and'
  11. ]">
  12. {{ $t('ReportManage.CategoryList.chinese_tabs') }}
  13. </div>
  14. <!-- 英文分类 -->
  15. <div class="item" @click="$emit('typeChange','2')" style="margin-left: 20px;"
  16. v-permission="permissionBtn.enClassifyBtn.classifyList_enClassify">
  17. {{ $t('ReportManage.CategoryList.english_tabs') }}
  18. </div>
  19. </div>
  20. <div style="display:flex;padding:10px;gap:10px">
  21. <!-- 添加分类 -->
  22. <el-button
  23. type="primary"
  24. @click="addClassify"
  25. v-permission="permissionBtn.classifyBtn.classifyList_cnClassify_classifyAdd"
  26. >
  27. {{$t('ReportManage.CategoryList.add_category')}}
  28. </el-button>
  29. <el-input :placeholder="$t('ReportManage.CategoryList.category_name')" v-model="searchVal" style="max-width: 262px;" @change="getList" clearable>
  30. <i slot="prefix" class="el-input__icon el-icon-search"></i>
  31. </el-input>
  32. </div>
  33. </div>
  34. <div class="content-box">
  35. <el-tree
  36. :data="list"
  37. node-key="Id"
  38. :props="{
  39. label: 'ClassifyName',
  40. children: 'Child'
  41. }"
  42. check-strictly
  43. :empty-text="$t('Common.no_classify_msg')"
  44. draggable
  45. indent='76'
  46. :allow-drop="canDropHandle"
  47. @node-drop="dropOverHandle"
  48. >
  49. <div
  50. class="classify-item-wrap"
  51. slot-scope="{ data }"
  52. >
  53. <div>
  54. <span
  55. :class="['tag', data.Enabled==1?'open':'close']"
  56. @click.stop="handleEnableSet(data)">
  57. {{data.Enabled==1?$t('Common.enable'):$t('Common.disable')}}
  58. </span>
  59. <span>{{data.ClassifyName}}</span>
  60. </div>
  61. <div class="opt-box">
  62. <!-- 章节设置 -->
  63. <span class="editsty"
  64. v-if="(!data.Child||(data.Child&&!data.Child.length)) && data.ClassifyType===1"
  65. @click="chapterSetting(data)"
  66. v-permission="permissionBtn.classifyBtn.classifyList_cnClassify_chapterSetting">
  67. {{ $t('ReportManage.CategoryList.section_settings') }}
  68. </span>
  69. <el-button
  70. v-if="data.ReportNum===0&&permissionBtn.checkPermissionBtn(permissionBtn.classifyBtn.classifyList_cnClassify_delete)"
  71. type="text"
  72. style="color:#f00"
  73. @click.stop="handleDel(data)"
  74. >删除</el-button>
  75. <img class="icon-drag" src="~@/assets/img/data_m/move_ico2.png" alt="">
  76. <img class="icon-set" src="~@/assets/img/icons/variety_set.png" alt="" @click.stop="handleEdit(data)" v-permission="permissionBtn.classifyBtn.classifyList_cnClassify_classifyEdit">
  77. </div>
  78. </div>
  79. </el-tree>
  80. </div>
  81. <!-- 分类弹窗 -->
  82. <m-dialog
  83. :title="classifyForm.classify_id?$t('ReportManage.CategoryList.edit_category'):$t('ReportManage.CategoryList.add_category')"
  84. :show.sync="classifyForm.show"
  85. v-if="classifyForm.show"
  86. width="650px"
  87. >
  88. <div style="padding-left: 50px">
  89. <el-form
  90. :model="classifyForm"
  91. :rules="formRules"
  92. ref="formRef"
  93. hide-required-asterisk
  94. label-width="auto">
  95. <!-- 分类名称 -->
  96. <el-form-item prop="classify_name" :label="$t('ReportManage.CategoryList.category_name')">
  97. <el-input
  98. type="text"
  99. v-model="classifyForm.classify_name"
  100. :placeholder="$t('ReportManage.CategoryList.category_name_hint')"
  101. style="width:400px;"
  102. />
  103. </el-form-item>
  104. <!-- 上级分类 -->
  105. <el-form-item prop="parent_id" :label="$t('ReportManage.CategoryList.parent_category')">
  106. <el-cascader
  107. v-model="classifyForm.parent_id"
  108. :options="classifyparentArr"
  109. :disabled="classifyForm.classify_id"
  110. style="width:400px;"
  111. ref="classifyRef"
  112. :props="{
  113. checkStrictly: true,
  114. value: 'Id',
  115. label: 'ClassifyName',
  116. children:'Child',
  117. emitPath:false
  118. }"
  119. clearable
  120. @change="changeClassify"
  121. >
  122. </el-cascader>
  123. </el-form-item>
  124. <!-- 报告类型 -->
  125. <el-form-item prop="reportType" label="报告类型">
  126. <template slot="label">
  127. <span>报告类型</span>
  128. <el-tooltip content="研报对应研报中心可选分类,PPT对应PPT中心可选分类">
  129. <i class="el-icon-warning"/>
  130. </el-tooltip>
  131. </template>
  132. <el-select v-model="classifyForm.reportType" style="width:400px" :disabled="classifyForm.classify_id||(classifyForm.parent_id&&!classifyForm.hasClassifyChild)">
  133. <el-option label="研报" :value="1"/>
  134. <el-option label="PPT" :value="2"/>
  135. </el-select>
  136. </el-form-item>
  137. <!-- 可见权限 -->
  138. <el-form-item prop="reportType" label="可见权限">
  139. <template slot="label">
  140. <span>可见权限</span>
  141. <el-tooltip content="未设置可见权限表示所有用户可见,设置可见用户后,指定用户可见该分类下报告">
  142. <i class="el-icon-warning"/>
  143. </el-tooltip>
  144. </template>
  145. <el-cascader
  146. @change="getVal"
  147. style="width:400px"
  148. :disabled='classifyForm.Child'
  149. v-model="classifyForm.VisibleUserIds"
  150. :options="userOptions"
  151. :props="{
  152. value: 'NodeId',
  153. label: 'NodeName',
  154. children: 'Children',
  155. multiple: true,
  156. emitPath: false
  157. }"
  158. :show-all-levels="false"
  159. collapse-tags
  160. clearable
  161. filterable
  162. :placeholder="this.$t('SystemManage.OperateAuth.placeholder04')"
  163. />
  164. </el-form-item>
  165. <!-- 报告提醒 -->
  166. <el-form-item prop="warnTime" label="报告提醒">
  167. <template slot="label">
  168. <span>报告提醒</span>
  169. <el-tooltip content="开启后,指定的报告编辑人将在课题结束前定时收到写报告提醒">
  170. <i class="el-icon-warning"/>
  171. </el-tooltip>
  172. </template>
  173. <el-switch
  174. v-model="classifyForm.isReportWarn"
  175. :active-value="1"
  176. :inactive-value="0"
  177. />
  178. <el-time-picker
  179. v-if="classifyForm.isReportWarn"
  180. v-model="classifyForm.warnTime"
  181. format="HH:mm"
  182. value-format="HH:mm"
  183. style="width:120px;margin-left:20px"
  184. >
  185. </el-time-picker>
  186. </el-form-item>
  187. </el-form>
  188. <div v-html="tips" style="color:#999;"></div>
  189. </div>
  190. <div slot="footer" style="margin-top: 20px;">
  191. <el-button
  192. @click="cancelClassify"
  193. style="width: 132px; height: 40px"
  194. >{{ $t('Dialog.cancel_btn') }}</el-button>
  195. <el-button
  196. @click="setClassifyHandle"
  197. type="primary"
  198. style="width: 132px; height: 40px"
  199. >{{ $t('Dialog.confirm_save_btn') }}</el-button>
  200. </div>
  201. </m-dialog>
  202. <!-- 转移报告弹窗 -->
  203. <m-dialog
  204. title="分类报告转移"
  205. :show.sync="isTransferReport"
  206. width="650px"
  207. >
  208. <div>
  209. <el-form
  210. :model="transferForm"
  211. hide-required-asterisk
  212. label-width="auto"
  213. >
  214. <el-form-item prop="classify_name" label="原分类">
  215. <el-cascader
  216. v-model="transferForm.oldClassify"
  217. @change="filterChange"
  218. :options="classifyparentArr"
  219. clearable
  220. placeholder="请选择分类"
  221. style="width:100%;"
  222. ></el-cascader>
  223. </el-form-item>
  224. <!-- 上级分类 -->
  225. <el-form-item prop="parent_id" label="转移至分类">
  226. <el-cascader
  227. v-model="transferForm.newClassify"
  228. @change="filterChange"
  229. :options="classifyparentArr"
  230. clearable
  231. placeholder="请选择分类"
  232. style="width:100%;"
  233. ></el-cascader>
  234. </el-form-item>
  235. </el-form>
  236. </div>
  237. <div slot="footer" style="margin-top: 20px;">
  238. <el-button
  239. @click="isTransferReport=false"
  240. style="width: 132px; height: 40px"
  241. >{{ $t('Dialog.cancel_btn') }}</el-button>
  242. <el-button
  243. @click="handleSaveTransferReport"
  244. type="primary"
  245. style="width: 132px; height: 40px"
  246. >{{ $t('Dialog.confirm_save_btn') }}</el-button>
  247. </div>
  248. </m-dialog>
  249. </div>
  250. </template>
  251. <script>
  252. import mDialog from '@/components/mDialog.vue';
  253. import { classifylist,classifyparent,classifyadd,classifyedit,classifydelete } from 'api/api.js';
  254. import {classifyPermissionInterface} from '@/api/modules/classifyApi.js'
  255. import { departInterence } from '@/api/modules/setApi';
  256. export default {
  257. components:{mDialog},
  258. computed: {
  259. canSetPermission() {
  260. /* 编辑最小级分类可设置品种 新增分类可设置跑品种 */
  261. if(!this.permissionBtn.classifyBtn.classifyList_cnClassify_connect_variety) return false
  262. if(this.classifyForm.classify_id) {
  263. return this.classifyForm.isLastLevel?true:false
  264. }else {
  265. return true
  266. }
  267. }
  268. },
  269. data() {
  270. return {
  271. userOptions:[],
  272. typeVal:1,
  273. searchVal:'',
  274. list:[],
  275. classifyForm:{
  276. show:false,
  277. classify_id:0,
  278. classify_name:"",
  279. parent_id: 0,
  280. variety:'',//关联的品种
  281. reportType: 1,
  282. isReportWarn: 0,
  283. warnTime:'09:00',
  284. hasClassifyChild:false,
  285. VisibleUserIds:[]
  286. },
  287. formRules: {
  288. classify_name: [{ required:true,message:this.$t('ReportManage.CategoryList.category_name_hint'),trigger:'blur'}]
  289. },
  290. classifyparentArr:[],
  291. reportVarietyList:[],//中文品种列表
  292. /* 转移报告弹窗 */
  293. isTransferReport: false,
  294. transferForm: {},
  295. tips: `注:若上级分类已关联报告,则新建的第一个子分类默认继承上级分类(父分类)关联的报告。`
  296. }
  297. },
  298. mounted(){
  299. this.getList()
  300. this.getUserList()
  301. },
  302. methods: {
  303. getVal(val){
  304. console.log(val)
  305. },
  306. // 递归处理数组
  307. filterTreeEmpty(arr) {
  308. function dfs(node) {
  309. if (Array.isArray(node.Children)) {
  310. for (let child of node.Children) {
  311. dfs(child);
  312. }
  313. if(node.Children.length===0) delete node.Children
  314. }
  315. //若为叶子节点,且不为用户,禁止选中
  316. if(!node.Children||!Array.isArray(node.Children)){
  317. if(node.NodeType!==3) node.disabled = true
  318. }
  319. }
  320. dfs(arr);
  321. },
  322. // 获取用户可见权限列表
  323. getUserList(){
  324. departInterence.getSystemUser({}).then(res=>{
  325. if(res.Ret===200){
  326. this.userOptions=res.Data || []
  327. this.filterTreeEmpty({Children:this.userOptions})
  328. }
  329. })
  330. },
  331. /* 报告转移 */
  332. transferReport() {
  333. this.isTransferReport = true;
  334. this.transferForm = {
  335. oldClassify: '',
  336. newClassify: ''
  337. }
  338. },
  339. handleSaveTransferReport() {
  340. },
  341. async getList(type){
  342. const res=await classifylist({
  343. KeyWord:this.searchVal,
  344. })
  345. if(res.Ret===200){
  346. this.list=res.Data.List||[]
  347. this.classifyparentArr=_.cloneDeep(this.list)
  348. this.filterNodes(this.classifyparentArr)
  349. }
  350. },
  351. /* 添加分类默认关联父级报告类型 */
  352. async changeClassify(id) {
  353. let item = this.$refs.classifyRef.getCheckedNodes(true)
  354. console.log(item)
  355. if(item&&item[0]) {
  356. this.classifyForm.reportType = item[0].data.ClassifyType;
  357. this.classifyForm.hasClassifyChild = item[0].data.HasChild ? true : false;
  358. this.classifyForm.VisibleUserIds = item[0].data.VisiableUsers?item[0].data.VisiableUsers:[];
  359. }else {
  360. this.classifyForm.hasClassifyChild = false
  361. }
  362. },
  363. // 去设置章节
  364. chapterSetting(row){
  365. this.$router.push({path:'chapterSetting',query:{ id:row.Id,classifyName: row.ClassifyName }})
  366. },
  367. filterNodes(arr) {
  368. arr.length && arr.forEach(item => {
  369. item.Child && item.Child.length && this.filterNodes(item.Child)
  370. if(!item.Child || (item.Child&&!item.Child.length) || item.Level===2) {
  371. delete item.Child
  372. }
  373. })
  374. },
  375. async addClassify(){
  376. this.classifyForm={
  377. Child:null,
  378. show:true,
  379. classify_id:0,
  380. classify_name:"",
  381. parent_id: 0,
  382. variety:'',//关联的品种
  383. reportType: 1,
  384. isReportWarn: 0,
  385. warnTime:'09:00',
  386. hasClassifyChild:false,
  387. VisibleUserIds:[]
  388. }
  389. },
  390. async handleEdit(item){
  391. this.classifyForm={
  392. Child:item.Child,
  393. VisibleUserIds:item.VisiableUsers?item.VisiableUsers:[],
  394. show:true,
  395. classify_id:item.Id,
  396. classify_name:item.ClassifyName,
  397. parent_id: item.ParentId,
  398. isLastLevel: !item.Child,
  399. reportType: item.ClassifyType,
  400. isReportWarn: item.IsRemind,
  401. warnTime: item.RemindTime,
  402. hasClassifyChild:false
  403. }
  404. },
  405. async setClassifyHandle(){
  406. await this.$refs.formRef.validate();
  407. const { classify_name,parent_id,classify_id,reportType,isReportWarn,warnTime,VisibleUserIds } = this.classifyForm;
  408. let params = {
  409. ClassifyName: classify_name,
  410. ParentId: parent_id,
  411. ClassifyType: reportType,
  412. IsRemind: isReportWarn,
  413. RemindTime: warnTime,
  414. VisibleUserIds
  415. }
  416. const { Ret,Msg } = classify_id
  417. ? await classifyedit({...params,ClassifyId: classify_id})
  418. : await classifyadd(params)
  419. if(Ret !== 200) return
  420. //this.$message.success(Msg)
  421. this.$message.success(
  422. classify_id
  423. ?this.$t('ReportManage.CategoryList.modification_successful')
  424. :this.$t('ReportManage.CategoryList.addition_successful')
  425. )
  426. this.cancelClassify();
  427. this.getList();
  428. },
  429. /* 取消 */
  430. cancelClassify() {
  431. this.$refs.formRef.resetFields();
  432. this.classifyForm.show = false;
  433. },
  434. /* 删除分类 */
  435. async handleDel(item) {
  436. console.log(item)
  437. await this.$confirm('分类删除后不可恢复,是否确认删除?', '提示', {
  438. type: 'warning'
  439. })
  440. const res = await classifydelete({ClassifyId:item.Id})
  441. if(res.Ret!==200) return
  442. this.$message.success('删除成功')
  443. this.getList()
  444. },
  445. //启用\禁用设置
  446. handleEnableSet(item){
  447. // 判断权限
  448. const {classifyBtn,checkPermissionBtn} = this.permissionBtn
  449. if(!checkPermissionBtn(classifyBtn.classifyList_cnClassify_enable)) return
  450. classifyPermissionInterface.enableSet({
  451. ClassifyId:item.Id,
  452. Enabled:item.Enabled==1?0:1
  453. }).then(res=>{
  454. if(res.Ret===200){
  455. //设置成功
  456. this.$message.success(this.$t('ReportManage.CategoryList.setup_successful'))
  457. this.getList()
  458. }
  459. })
  460. },
  461. //控制只能同级拖动
  462. canDropHandle(draggingNode, dropNode, type){
  463. if(type==='inner') return false //禁止向内部拖动
  464. if(draggingNode.level!=dropNode.level) return false
  465. if(draggingNode.data.ParentId!=dropNode.data.ParentId) return false
  466. return true
  467. },
  468. //拖动结束
  469. dropOverHandle(b,a,i,e) {
  470. // 被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置
  471. const classifyId=b.data.Id
  472. let list=a.parent.childNodes;
  473. let PrevClassifyId=0,NextClassifyId=0,targetIndex=0;
  474. list.forEach((item,index) => {
  475. if(item.data.Id===classifyId){
  476. targetIndex=index
  477. }
  478. });
  479. if(targetIndex===0){
  480. NextClassifyId=list[1].data.Id
  481. }else if(targetIndex===list.length-1){
  482. PrevClassifyId=list[list.length-1].data.Id
  483. }else{
  484. PrevClassifyId=list[targetIndex-1].data.Id
  485. NextClassifyId=list[targetIndex+1].data.Id
  486. }
  487. const params={
  488. ClassifyId:classifyId,
  489. PrevClassifyId,
  490. NextClassifyId
  491. }
  492. console.log(params);
  493. classifyPermissionInterface.moveSort(params).then(res=>{
  494. if(res.Ret===200){
  495. this.$message.success(this.$t('ReportManage.CategoryList.move_successful'))
  496. }else{
  497. this.getList()
  498. }
  499. })
  500. },
  501. },
  502. }
  503. </script>
  504. <style lang="scss">
  505. .el-cascader .el-input{
  506. width: 100%;
  507. }
  508. .classify-page{
  509. .content-box{
  510. .el-tree-node__content{
  511. height: fit-content;
  512. padding-top: 10px;
  513. padding-bottom: 10px;
  514. border-bottom: 1px solid #C8CDD9;
  515. }
  516. }
  517. }
  518. </style>
  519. <style lang="scss" scoped>
  520. .top-wrap{
  521. display: flex;
  522. justify-content: space-between;
  523. background: #FFFFFF;
  524. border-radius: 4px;
  525. .type-box{
  526. display: flex;
  527. .item{
  528. position: relative;
  529. cursor: pointer;
  530. color: #666;
  531. min-width: 88px;
  532. line-height: 60px;
  533. text-align: center;
  534. }
  535. .active{
  536. color: #0052D9;
  537. &::after{
  538. content: '';
  539. display: block;
  540. width: 100%;
  541. height: 2px;
  542. position: absolute;
  543. bottom: 0px;
  544. left: 0;
  545. background-color: #0052D9;
  546. }
  547. }
  548. }
  549. }
  550. .content-box{
  551. padding: 20px;
  552. margin-top: 20px;
  553. height: calc(100vh - 230px);
  554. overflow-y: auto;
  555. background-color: #FFFFFF;
  556. .classify-item-wrap{
  557. flex: 1;
  558. padding-right: 20px;
  559. display: flex;
  560. justify-content: space-between;
  561. align-items: center;
  562. .tag{
  563. display: inline-block;
  564. min-width: 76px;
  565. line-height: 30px;
  566. text-align: center;
  567. &.open{
  568. background-color: #ECF2FE;
  569. color: #0052D9;
  570. }
  571. &.close{
  572. background-color: #0052D9;
  573. color: #fff;
  574. }
  575. }
  576. .opt-box{
  577. display: flex;
  578. align-items: center;
  579. gap: 10px;
  580. .icon-drag,.icon-set{
  581. width: 16px;
  582. height: 16px;
  583. margin-left: 10px;
  584. }
  585. }
  586. }
  587. }
  588. </style>