EDBClassify.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <script setup>
  2. import {computed, reactive, ref,watch} from 'vue'
  3. import { useWindowSize } from '@vueuse/core'
  4. import apiDataEDB from '@/api/dataEDB'
  5. import { showDialog , showToast } from 'vant';
  6. import {useEDBDelete} from '../hooks/useEDBDelete'
  7. import {deleteClassifyItemEmpty} from '../util/util'
  8. const {edbClassifyDelete}=useEDBDelete()
  9. const { width } = useWindowSize()
  10. const props=defineProps({
  11. modelValue:{
  12. type:Boolean,
  13. default:false
  14. }
  15. })
  16. const emits=defineEmits(['update:modelValue','change'])
  17. // 处理分类数据 index为要过滤的层级数
  18. // 如index 为3 则获取arr的前三层数据
  19. function formatClassifyArr(arr,index){
  20. index--
  21. arr.length&&arr.forEach(item=>{
  22. item.Children.length&&formatClassifyArr(item.Children,index)
  23. if(!item.Children.length||index<=0){
  24. delete item.Children
  25. }
  26. })
  27. }
  28. const langType=ref('zh')
  29. function langTypeChange(type){
  30. langType.value=type
  31. }
  32. const selectClassifyArr=ref([])//当前选择的哪些目录
  33. function findClassifyList(arr,id){
  34. let temarr=[]
  35. arr.forEach(item=>{
  36. if(item.ClassifyId===id){
  37. if(item.Children?.length){
  38. temarr=item.Children
  39. }else{// 如果选中了最后一级目录或者这个目录没有子目录则就返回他本身
  40. temarr=arr
  41. }
  42. }
  43. })
  44. return temarr
  45. }
  46. //显示的目录数据
  47. const showClassifyArrData=computed(()=>{
  48. if(selectClassifyArr.value.length===0) return classifyList.value
  49. let arr=classifyList.value
  50. for (let index = 0; index < selectClassifyArr.value.length; index++) {
  51. arr=findClassifyList(arr,selectClassifyArr.value[index].ClassifyId)
  52. }
  53. return arr
  54. })
  55. //点击目录
  56. function handleSelectClassify(item){
  57. // 如果当前选择的分类的最后一个在当前这个显示的目录里则将最后一个替换掉
  58. const last=selectClassifyArr.value[selectClassifyArr.value.length-1]
  59. // console.log(last);
  60. const flag=showClassifyArrData.value.some(e=>e.ClassifyId===last?.ClassifyId)
  61. if(flag){
  62. selectClassifyArr.value[selectClassifyArr.value.length-1]=item
  63. return
  64. }
  65. if(item.ClassifyId!==selectClassifyArr.value[selectClassifyArr.value.length-1]?.ClassifyId){
  66. selectClassifyArr.value.push(item)
  67. }
  68. }
  69. //返回上级目录
  70. function handleBackClassify(index){
  71. if(index===-1){
  72. const flag=showClassifyArrData.value.some(item=>item.ClassifyId===selectClassifyArr.value[selectClassifyArr.value.length-1]?.ClassifyId)
  73. if(flag){
  74. selectClassifyArr.value.length=selectClassifyArr.value.length-2
  75. }else{
  76. selectClassifyArr.value.length=selectClassifyArr.value.length-1
  77. }
  78. return
  79. }
  80. selectClassifyArr.value.length=selectClassifyArr.value.length-index
  81. }
  82. // 显示选择的父级目录
  83. const showParentClassifyData=computed(()=>{
  84. const id=selectClassifyArr.value[selectClassifyArr.value.length-1]?.ClassifyId
  85. const flag=showClassifyArrData.value.some(item=>item.ClassifyId===id)
  86. if(flag) return selectClassifyArr.value.slice(0,selectClassifyArr.value.length-1)
  87. return selectClassifyArr.value
  88. })
  89. // 关闭弹窗
  90. function handleClose(){
  91. let selectClassifyId=selectClassifyArr.value[selectClassifyArr.value.length-1]?.ClassifyId||0
  92. let selectClassifyNameArr=selectClassifyArr.value.map(item=>getClassifyItemName(item))
  93. emits('change',{selectClassifyNameStr:selectClassifyNameArr.join('/'),selectClassifyId})
  94. emits('update:modelValue',false)
  95. }
  96. // 设置显示的分类名称(中英文)
  97. function getClassifyItemName(item){
  98. return langType.value==='zh'?item.ClassifyName:item.ClassifyNameEn||item.ClassifyName
  99. }
  100. // 获取分类数据
  101. let classifyList=ref([])
  102. async function getEDBClassifyList(){
  103. const res=await apiDataEDB.edbClassifyList()
  104. if(res.Ret===200){
  105. deleteClassifyItemEmpty(res.Data.AllNodes||[])
  106. classifyList.value=res.Data.AllNodes||[]
  107. }
  108. }
  109. getEDBClassifyList()
  110. // 分类操作数据
  111. const classifyState=reactive({
  112. show:false,
  113. title:'',
  114. name:'',//输入框中的值
  115. placeholderText:'',
  116. type:'add',//新增、编辑
  117. parentText:'',
  118. parentId:0,
  119. classifyId:0,
  120. })
  121. watch(
  122. ()=>classifyState.show,
  123. (n)=>{
  124. if(!n){
  125. classifyState.title=''
  126. classifyState.name=''
  127. classifyState.placeholderText=''
  128. classifyState.type='add'
  129. classifyState.parentText=''
  130. classifyState.parentId=0
  131. classifyState.classifyId=0
  132. }
  133. }
  134. )
  135. function handleAddLevel1(){
  136. classifyState.title='添加一级目录'
  137. classifyState.placeholderText='请输入一级目录名称'
  138. classifyState.show=true
  139. }
  140. async function handleConfirmClassifyState(){
  141. let params={}
  142. if(classifyState.type==='add'){
  143. params={
  144. ClassifyName:classifyState.name,
  145. Level:classifyState.level,
  146. ParentId:classifyState.parentId
  147. }
  148. }else{
  149. params={
  150. ClassifyName:classifyState.name,
  151. ClassifyId:classifyState.classifyId
  152. }
  153. }
  154. const res=classifyState.type==='add'?await apiDataEDB.edbClassifyAdd(params):await apiDataEDB.edbClassifyEdit(params)
  155. if(res.Ret===200){
  156. getEDBClassifyList()
  157. classifyState.show=false
  158. }
  159. }
  160. // 显示分类操作按钮数据
  161. const classifyOptState=reactive({
  162. show:false,
  163. actions:[],
  164. data:{}
  165. })
  166. watch(
  167. ()=>classifyOptState.show,
  168. (n)=>{
  169. if(!n){
  170. classifyOptState.actions=[]
  171. classifyOptState.data={}
  172. }
  173. }
  174. )
  175. // 显示分类的具体操作选项
  176. function handleShowClassifyOpt(item){
  177. let optArr=[
  178. {name:'重命名',type:'edit'},
  179. {name:'删除',type:'delete',color:"#C54322"},
  180. ]
  181. if(item.Button.AddButton){//添加权限
  182. optArr.unshift({name:'添加下级目录',type:'add'})
  183. }
  184. if(!item.Button.DeleteButton){//删除
  185. optArr=optArr.filter(item=>item.type!='delete')
  186. }
  187. if(item.Button.MoveButton){//移动权限
  188. // 一级目录不能移动至
  189. if(selectClassifyArr.value.length){
  190. optArr.push({name:'移动至',type:'move'})
  191. }
  192. }
  193. classifyOptState.actions=optArr
  194. classifyOptState.data=item
  195. classifyOptState.show=true
  196. }
  197. function handleSelectOpt(e){
  198. if(e.type==='add'){
  199. const temarr=[...showParentClassifyData.value,{...classifyOptState.data}]
  200. const selectClassifyNameArr=temarr.map(item=>getClassifyItemName(item))
  201. classifyState.parentText=selectClassifyNameArr.join('/')
  202. classifyState.title=e.name
  203. classifyState.placeholderText='请输入目录名称'
  204. classifyState.type='add'
  205. classifyState.parentId=classifyOptState.data.ClassifyId
  206. classifyState.show=true
  207. }
  208. if(e.type==='edit'){
  209. const temarr=[...showParentClassifyData.value]
  210. const selectClassifyNameArr=temarr.map(item=>getClassifyItemName(item))
  211. classifyState.parentText=selectClassifyNameArr.join('/')
  212. classifyState.title='重命名'
  213. classifyState.placeholderText='请输入目录名称'
  214. classifyState.type='edit'
  215. classifyState.name=classifyOptState.data.ClassifyName
  216. classifyState.classifyId=classifyOptState.data.ClassifyId
  217. classifyState.show=true
  218. }
  219. if(e.type==='delete'){
  220. let data=classifyOptState.data
  221. edbClassifyDelete(data).then(res=>{
  222. // console.log(res===true);
  223. if(res===true){
  224. getEDBClassifyList()
  225. }
  226. })
  227. }
  228. if(e.type==='move'){
  229. classifyMoveState.selectValue=''
  230. classifyMoveState.tabIndex=0
  231. const level=showParentClassifyData.value.length
  232. const arr=JSON.parse(JSON.stringify(classifyList.value))
  233. formatClassifyArr(arr,level)
  234. classifyMoveState.options=arr||[]
  235. classifyMoveState.classifyId=classifyOptState.data.ClassifyId
  236. classifyMoveState.show=true
  237. }
  238. classifyOptState.show=false
  239. }
  240. // 移动分类数据
  241. const classifyMoveState=reactive({
  242. show:false,
  243. selectValue:'',
  244. options:[],
  245. classifyId:0,//要移动的分类id
  246. })
  247. function handleSelectMoveClassifyChange({value,selectedOptions,tabIndex}){
  248. // classifyMoveState.tabIndex=tabIndex
  249. }
  250. function handleConfirmMove(){
  251. if(!classifyMoveState.selectValue){
  252. showToast('请选择要移动至的目录')
  253. return
  254. }
  255. // 只会将目录移动到某个目录里面所有下面有很多都是0
  256. apiDataEDB.edbCatalogMove({
  257. ClassifyId:classifyMoveState.classifyId,
  258. ParentClassifyId:classifyMoveState.selectValue,
  259. EdbInfoId:0,
  260. PrevClassifyId:0,
  261. NextClassifyId:0,
  262. PrevEdbInfoId:0,
  263. NextEdbInfoId:0,
  264. }).then(res=>{
  265. if(res.Ret===200){
  266. showToast('移动成功')
  267. getEDBClassifyList()
  268. classifyMoveState.show=false
  269. }
  270. })
  271. }
  272. defineExpose({classifyList,langTypeChange})
  273. </script>
  274. <template>
  275. <van-popup
  276. :show="props.modelValue"
  277. position="right"
  278. closeable
  279. :style="{width:width>650?'400px':'100%',height:'100%'}"
  280. @click-close-icon="handleClose"
  281. >
  282. <div class="edb-classify-wrap">
  283. <div class="top-box">
  284. <van-icon name="arrow-left" size='20' @click="handleBackClassify(-1)" v-if="showParentClassifyData.length>0"/>
  285. <div class="catalog-text-box">
  286. <span
  287. v-for="item,index in showParentClassifyData"
  288. :key="item.ClassifyId"
  289. @click="handleBackClassify(selectClassifyArr.length-index)"
  290. >{{getClassifyItemName(item)}}</span>
  291. </div>
  292. </div>
  293. <ul class="classify-box">
  294. <li class="classify-item" v-for="item in showClassifyArrData" :key="item.UniqueCode">
  295. <span
  296. class="van-ellipsis title"
  297. :style="{color:selectClassifyArr[selectClassifyArr.length-1]?.ClassifyId===item.ClassifyId?'#0052D9':''}"
  298. @click.stop="handleSelectClassify(item)"
  299. >{{getClassifyItemName(item)}}</span>
  300. <img style="width:22px;height:22px;cursor: pointer;" src="@/assets/imgs/dataEDB/icon_opt.png" alt="" @click.stop="handleShowClassifyOpt(item)">
  301. </li>
  302. </ul>
  303. <div class="bot-btn-box">
  304. <van-button type="primary" block @click="handleAddLevel1">添加一级目录</van-button>
  305. </div>
  306. </div>
  307. </van-popup>
  308. <!-- 分类操作选项 -->
  309. <van-action-sheet
  310. v-model:show="classifyOptState.show"
  311. :actions="classifyOptState.actions"
  312. cancel-text="取消"
  313. @select="handleSelectOpt"
  314. />
  315. <!-- 创建/编辑分类 -->
  316. <van-dialog
  317. v-model:show="classifyState.show"
  318. :title="classifyState.title"
  319. show-cancel-button
  320. @confirm="handleConfirmClassifyState"
  321. >
  322. <div class="edit-classify-wrap">
  323. <p class="van-ellipsis" v-if="classifyState.parentText" style="margin-bottom:8px">上级目录:{{classifyState.parentText}}</p>
  324. <input class="input-box" type="text" :placeholder="classifyState.placeholderText" v-model="classifyState.name">
  325. </div>
  326. </van-dialog>
  327. <!-- 移动分类 -->
  328. <van-popup
  329. v-model:show="classifyMoveState.show"
  330. round
  331. position="bottom"
  332. >
  333. <van-cascader
  334. v-model="classifyMoveState.selectValue"
  335. title="移动至"
  336. :options="classifyMoveState.options"
  337. :field-names="{text:'ClassifyName',value:'ClassifyId',children:'Children'}"
  338. @close="classifyMoveState.show = false"
  339. @change="handleSelectMoveClassifyChange"
  340. />
  341. <div style="width:300px;margin:0 auto;padding:20px 0">
  342. <van-button type="primary" round block @click="handleConfirmMove">确定</van-button>
  343. </div>
  344. </van-popup>
  345. </template>
  346. <style lang="scss" scoped>
  347. .edb-classify-wrap{
  348. height: 100%;
  349. display: flex;
  350. flex-direction: column;
  351. .top-box{
  352. height: calc(var(--van-popup-close-icon-margin) + 50px);
  353. background-color: #fff;
  354. flex-shrink: 0;
  355. display: flex;
  356. align-items: center;
  357. padding-right: calc(var(--van-popup-close-icon-margin) + var(--van-popup-close-icon-size));
  358. padding-top: var(--van-popup-close-icon-margin);
  359. padding-left: 28px;
  360. .catalog-text-box{
  361. margin-left: 20px;
  362. flex: 1;
  363. overflow-x: auto;
  364. display: flex;
  365. &::-webkit-scrollbar{
  366. display: none;
  367. height: 0;
  368. }
  369. span{
  370. display: block;
  371. flex-shrink: 0;
  372. font-size: 32px;
  373. font-weight: 600;
  374. &::after{
  375. content:'/'
  376. }
  377. &:last-child::after{
  378. content:''
  379. }
  380. }
  381. }
  382. }
  383. .classify-box{
  384. flex: 1;
  385. overflow-y: auto;
  386. padding: 0 32px;
  387. .classify-item{
  388. display: flex;
  389. align-items: center;
  390. padding: 10px 0;
  391. .title{
  392. flex: 1;
  393. display: block;
  394. }
  395. }
  396. }
  397. .bot-btn-box{
  398. padding: 48px;
  399. flex-shrink: 0;
  400. }
  401. }
  402. .edit-classify-wrap{
  403. padding: 32px 48px;
  404. .input-box{
  405. width: 100%;
  406. box-sizing: border-box;
  407. display: block;
  408. padding: 24px 32px;
  409. background-color: #f6f6f6;
  410. border-radius: 12px;
  411. }
  412. }
  413. @media screen and (min-width:$media-width){
  414. .edb-classify-wrap{
  415. .top-box{
  416. height: calc(var(--van-popup-close-icon-margin) + 50px);
  417. padding-left: 14px;
  418. .catalog-text-box{
  419. margin-left: 10px;
  420. span{
  421. font-size: 16px;
  422. }
  423. }
  424. }
  425. .classify-box{
  426. padding: 0 16px;
  427. .classify-item{
  428. padding: 5px 0;
  429. }
  430. }
  431. .bot-btn-box{
  432. padding: 24px;
  433. }
  434. }
  435. .edit-classify-wrap{
  436. padding: 16px 24px;
  437. .input-box{
  438. padding: 12px 16px;
  439. border-radius: 6px;
  440. }
  441. }
  442. }
  443. </style>