ComplexChoices.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. <template>
  2. <div class="filter-bar">
  3. <!-- 所选院系 -->
  4. <div class="filter-group">
  5. <span class="filter-group-title">所选单位:</span>
  6. <a-spin :spinning="spinningSelectedDepts" tip>
  7. <div class="radio-group-container">
  8. <MyRadioButtonGroup ref="Dept" v-show="selectedDepts.length > 0" v-model="selectedDept" @change="handleSelectedDept">
  9. <MyRadioButtonOffOut v-for="(item, index) in selectedDepts" :key="index" :value="index" :label="item.name" :index="index"></MyRadioButtonOffOut>
  10. </MyRadioButtonGroup>
  11. <div class="radio-group-spacing"></div>
  12. <MyRadioButtonGroup ref="Big" v-show="selectedDeptBigs.length > 0" v-model="selectedDeptBig" @change="handleSelectedCourses">
  13. <MyRadioButton v-for="(item, index) in selectedDeptBigs" :key="index" :value="index" :label="item.name" :index="index"></MyRadioButton>
  14. </MyRadioButtonGroup>
  15. <div class="radio-group-spacing"></div>
  16. <MyRadioButtonGroup ref="Smail" v-show="selectedDeptSmails.length > 0" v-model="selectedDeptSmail" @change="handleSelectedSmails">
  17. <MyRadioButton v-for="(item, index) in selectedDeptSmails" :key="index" :value="index" :label="item.name" :index="index"></MyRadioButton>
  18. </MyRadioButtonGroup>
  19. </div>
  20. </a-spin>
  21. </div>
  22. <div class="spacing-line"></div>
  23. <!-- 课程类型和课件格式(联动单选) -->
  24. <div class="filter-group">
  25. <span class="filter-group-title">资源类型:</span>
  26. <a-spin :spinning="spinningSelectedTypesBig" tip>
  27. <div class="radio-group-container">
  28. <MyRadioButtonGroup ref="TypeBig" v-show="selectedTypesBig.length > 0" v-model="selectedTypeBig" @change="handleTypeChangeBig">
  29. <MyRadioButton v-for="(item, index) in selectedTypesBig" :key="index" :value="index" :label="item.name" :index="index"></MyRadioButton>
  30. </MyRadioButtonGroup>
  31. <MyRadioButtonGroup ref="Type" v-show="selectedTypes.length > 0" v-model="selectedType" @change="handleTypeChange">
  32. <MyRadioButton v-for="(item, index) in selectedTypes" :key="index" :value="index" :label="item.name" :index="index"></MyRadioButton>
  33. </MyRadioButtonGroup>
  34. <MyRadioButtonGroup ref="TypeSmail" v-show="selectedTypesSmail.length > 0" v-model="selectedTypeSmail" @change="handleTypeChangeSmail">
  35. <MyRadioButton v-for="(item, index) in selectedTypesSmail" :key="index" :value="index" :label="item.name" :index="index"></MyRadioButton>
  36. </MyRadioButtonGroup>
  37. </div>
  38. </a-spin>
  39. </div>
  40. <div class="spacing-line"></div>
  41. <div class="filter-group">
  42. <span class="filter-group-title">课件格式:</span>
  43. <a-spin :spinning="spinningSelectedFormats" tip>
  44. <MyRadioButtonGroup ref="Format" v-model="selectedFormat" @change="handleFormatChange">
  45. <MyRadioButton v-for="(item, index) in selectedFormats" :key="item.id || index" :value="index" :label="item.fileExtendName" :index="index"></MyRadioButton>
  46. </MyRadioButtonGroup>
  47. </a-spin>
  48. </div>
  49. <div class="spacing-line"></div>
  50. <!-- 已选条件 -->
  51. <div class="filter-group">
  52. <span class="filter-group-title">已选条件:</span>
  53. <div class="selected-tags-container">
  54. <a-tag v-for="(tag, index) in selectedTagKeys" :key="index" :bordered="false" closable @close="handleTagClose(tag, index)">{{ tag.name }}</a-tag>
  55. <span v-if="selectedTagKeys.length > 0" class="clean" @click="handleTagCloseAll">清除筛选</span>
  56. </div>
  57. </div>
  58. </div>
  59. </template>
  60. <script setup>
  61. import { ref, onMounted } from 'vue'
  62. import MyRadioButtonGroup from '../components/MyRadioButtonGroup.vue'
  63. import MyRadioButton from '../components/MyRadioButton.vue'
  64. import MyRadioButtonOffOut from '../components/MyRadioButtonOffOut.vue'
  65. import collegeApi from '@/api/college'
  66. import EventBus from '@/utils/EventBus'
  67. import { getQueryTreeAll, getAllListFileFormat } from '@/api/portal'
  68. // 部门相关引用
  69. const selectedDept = ref('')
  70. const selectedDeptBig = ref('')
  71. const selectedDeptSmail = ref('')
  72. const Dept = ref(null)
  73. const Big = ref(null)
  74. const Smail = ref(null)
  75. // 类型相关引用
  76. const selectedTypeBig = ref('')
  77. const selectedType = ref('')
  78. const selectedTypeSmail = ref('')
  79. const TypeBig = ref(null)
  80. const Type = ref(null)
  81. const TypeSmail = ref(null)
  82. // 格式相关引用
  83. const selectedFormat = ref('')
  84. const Format = ref(null)
  85. // 已选标签
  86. const selectedTagKeys = ref([])
  87. // 部门数据
  88. const selectedDepts = ref([])
  89. const spinningSelectedDepts = ref(false)
  90. const selectedDeptBigs = ref([])
  91. const selectedDeptBigsList = ref([])
  92. const selectedDeptSmailsList = ref([])
  93. const selectedDeptSmails = ref([])
  94. // 课程数据(已注释)
  95. const selectedCourses = ref([
  96. '全部',
  97. '初级飞行训练',
  98. '高级飞行训练',
  99. '实弹训练',
  100. '低空战术飞行',
  101. '跨区转场训练',
  102. '空气动力学',
  103. '航空气象学',
  104. '航空电子设备',
  105. '飞机结构与系统',
  106. '空军作战指挥',
  107. '战场态势感知',
  108. '模拟对抗训练',
  109. '军队政治工作',
  110. '军事理论',
  111. '战斗精神培育',
  112. '机型改装训练',
  113. '应急程序训练'
  114. ])
  115. // 类型数据
  116. const selectedTypesBig = ref([])
  117. const spinningSelectedTypesBig = ref(false)
  118. const selectedTypes = ref([])
  119. const selectedTypesSmail = ref([])
  120. const selectedTypesBigList = ref([])
  121. const selectedTypesList = ref([])
  122. const selectedTypesLists = ref(new Map()) // 使用Map替代对象,提高性能
  123. // 格式数据
  124. const selectedFormats = ref([])
  125. const spinningSelectedFormats = ref(false)
  126. /**
  127. * 处理部门选择变化
  128. */
  129. const handleSelectedDept = (e) => {
  130. // 重置下级选项
  131. selectedDeptBig.value = ''
  132. selectedDeptSmail.value = ''
  133. if (e === 0) {
  134. selectedDeptBigs.value = []
  135. } else {
  136. selectedDeptBigs.value = selectedDeptBigsList.value[e] || []
  137. }
  138. selectedDeptSmails.value = []
  139. if (selectedDeptBigs.value.length > 0 && Big.value) {
  140. Big.value.setClean(-1)
  141. }
  142. selectedDeptBig.value = -1
  143. selectedDeptSmail.value = -1
  144. updateSelectedTags()
  145. }
  146. /**
  147. * 处理二级部门选择变化
  148. */
  149. const handleSelectedCourses = (e) => {
  150. if (e === 0) {
  151. selectedDeptSmails.value = []
  152. } else {
  153. selectedDeptSmails.value = selectedDeptSmailsList.value[e - 1] || []
  154. }
  155. if (selectedDeptSmails.value.length > 0 && Smail.value) {
  156. Smail.value.setClean(-1)
  157. }
  158. selectedDeptSmail.value = -1
  159. updateSelectedTags()
  160. }
  161. /**
  162. * 处理三级部门选择变化
  163. */
  164. const handleSelectedSmails = (e) => {
  165. updateSelectedTags()
  166. }
  167. /**
  168. * 处理一级资源类型选择变化
  169. */
  170. const handleTypeChangeBig = (e) => {
  171. selectedTypesSmail.value = []
  172. if (e === 0) {
  173. selectedTypes.value = []
  174. } else {
  175. selectedTypes.value = selectedTypesBigList.value[e] || []
  176. }
  177. if (selectedTypes.value.length > 0 && Type.value) {
  178. Type.value.setClean(-1)
  179. }
  180. if (selectedTypesSmail.value.length > 0 && TypeSmail.value) {
  181. TypeSmail.value.setClean(-1)
  182. }
  183. selectedType.value = -1
  184. selectedTypeSmail.value = -1
  185. updateSelectedTags()
  186. }
  187. /**
  188. * 处理二级资源类型选择变化
  189. */
  190. const handleTypeChange = (e) => {
  191. if (selectedTypes.value.length === 0 || e < 0 || e >= selectedTypes.value.length) {
  192. selectedTypesSmail.value = []
  193. updateSelectedTags()
  194. return
  195. }
  196. const item = selectedTypes.value[e]
  197. if (e === 0) {
  198. selectedTypesSmail.value = []
  199. } else {
  200. selectedTypesSmail.value = selectedTypesLists.value.get(item.id) || []
  201. }
  202. updateSelectedTags()
  203. }
  204. /**
  205. * 处理三级资源类型选择变化
  206. */
  207. const handleTypeChangeSmail = (e) => {
  208. updateSelectedTags()
  209. }
  210. /**
  211. * 处理文件格式选择变化
  212. */
  213. const handleFormatChange = (e) => {
  214. updateSelectedTags()
  215. }
  216. /**
  217. * 更新已选条件标签
  218. */
  219. const updateSelectedTags = () => {
  220. selectedTagKeys.value = []
  221. const queryData = {}
  222. // 部门筛选条件
  223. if (selectedDept.value > 0 && selectedDepts.value.length > selectedDept.value) {
  224. const dept = selectedDepts.value[selectedDept.value]
  225. if (dept) {
  226. selectedTagKeys.value.push({
  227. listType: 0,
  228. key: 'collegeId',
  229. index: selectedDept.value,
  230. name: dept.name,
  231. id: dept.id
  232. })
  233. queryData['collegeId'] = dept.id
  234. }
  235. }
  236. if (selectedDeptBig.value > 0 && selectedDeptBigs.value.length > selectedDeptBig.value) {
  237. const deptBig = selectedDeptBigs.value[selectedDeptBig.value]
  238. if (deptBig) {
  239. selectedTagKeys.value.push({
  240. listType: 1,
  241. key: 'collegeTwoId',
  242. index: selectedDeptBig.value,
  243. name: deptBig.name,
  244. id: deptBig.id
  245. })
  246. queryData['collegeTwoId'] = deptBig.id
  247. }
  248. }
  249. if (selectedDeptSmail.value > 0 && selectedDeptSmails.value.length > selectedDeptSmail.value) {
  250. const deptSmail = selectedDeptSmails.value[selectedDeptSmail.value]
  251. if (deptSmail) {
  252. selectedTagKeys.value.push({
  253. listType: 2,
  254. key: 'collegeThreeId',
  255. index: selectedDeptSmail.value - 1,
  256. name: deptSmail.name,
  257. id: deptSmail.id
  258. })
  259. queryData['collegeThreeId'] = deptSmail.id
  260. }
  261. }
  262. // 资源类型筛选条件
  263. if (selectedTypeBig.value > 0 && selectedTypesBig.value.length > selectedTypeBig.value) {
  264. const typeBig = selectedTypesBig.value[selectedTypeBig.value]
  265. if (typeBig) {
  266. selectedTagKeys.value.push({
  267. listType: 3,
  268. key: 'resourceType',
  269. index: selectedTypeBig.value,
  270. name: typeBig.name,
  271. id: typeBig.id
  272. })
  273. queryData['resourceType'] = typeBig.id
  274. }
  275. }
  276. if (selectedType.value > 0 && selectedTypes.value.length > selectedType.value) {
  277. const type = selectedTypes.value[selectedType.value]
  278. if (type) {
  279. selectedTagKeys.value.push({
  280. listType: 4,
  281. key: 'resourceTwoType',
  282. index: selectedType.value,
  283. name: type.name,
  284. id: type.id
  285. })
  286. queryData['resourceTwoType'] = type.id
  287. }
  288. }
  289. if (selectedTypeSmail.value > 0 && selectedTypesSmail.value.length > selectedTypeSmail.value) {
  290. const typeSmail = selectedTypesSmail.value[selectedTypeSmail.value]
  291. if (typeSmail) {
  292. selectedTagKeys.value.push({
  293. listType: 6,
  294. key: 'resourceThreeType',
  295. index: selectedTypeSmail.value,
  296. name: typeSmail.name,
  297. id: typeSmail.id
  298. })
  299. queryData['resourceThreeType'] = typeSmail.id
  300. }
  301. }
  302. // 文件格式筛选条件
  303. if (selectedFormat.value > 0 && selectedFormats.value.length > selectedFormat.value) {
  304. const format = selectedFormats.value[selectedFormat.value]
  305. if (format) {
  306. selectedTagKeys.value.push({
  307. listType: 5,
  308. key: 'suffix',
  309. index: selectedFormat.value,
  310. name: format.fileExtendName,
  311. id: format.id
  312. })
  313. queryData['suffix'] = format.fileExtendName
  314. }
  315. }
  316. EventBus.emit('upLoadList', queryData)
  317. }
  318. /**
  319. * 删除已选条件标签
  320. */
  321. const handleTagClose = (tag, index) => {
  322. switch (tag.key) {
  323. case 'suffix':
  324. if (Format.value) Format.value.setClean(-1)
  325. selectedFormat.value = -1
  326. break
  327. case 'resourceTwoType':
  328. if (Type.value) Type.value.setClean(-1)
  329. selectedType.value = -1
  330. break
  331. case 'resourceThreeType':
  332. if (TypeSmail.value) TypeSmail.value.setClean(-1)
  333. selectedTypeSmail.value = -1
  334. break
  335. case 'resourceType':
  336. if (Type.value) Type.value.setClean(-1)
  337. selectedType.value = -1
  338. if (TypeBig.value) TypeBig.value.setClean(-1)
  339. selectedTypeBig.value = -1
  340. break
  341. case 'collegeThreeId':
  342. if (Smail.value) Smail.value.setClean(-1)
  343. selectedDeptSmail.value = -1
  344. break
  345. case 'collegeTwoId':
  346. if (Smail.value) Smail.value.setClean(-1)
  347. selectedDeptSmail.value = -1
  348. if (Big.value) Big.value.setClean(-1)
  349. selectedDeptBig.value = -1
  350. break
  351. case 'collegeId':
  352. if (Smail.value) Smail.value.setClean(-1)
  353. selectedDeptSmail.value = -1
  354. if (Big.value) Big.value.setClean(-1)
  355. selectedDeptBig.value = -1
  356. if (Dept.value) Dept.value.setClean(-1)
  357. selectedDept.value = -1
  358. if (TypeSmail.value) TypeSmail.value.setClean(-1)
  359. selectedTypeSmail.value = -1
  360. break
  361. }
  362. updateSelectedTags()
  363. }
  364. /**
  365. * 清除所有筛选条件
  366. */
  367. const handleTagCloseAll = () => {
  368. // 重置所有选择器
  369. if (Format.value) Format.value.setClean(-1)
  370. selectedFormat.value = -1
  371. if (Type.value) Type.value.setClean(-1)
  372. selectedType.value = -1
  373. if (TypeBig.value) TypeBig.value.setClean(-1)
  374. selectedTypeBig.value = -1
  375. if (TypeSmail.value) TypeSmail.value.setClean(-1)
  376. selectedTypeSmail.value = -1
  377. if (Smail.value) Smail.value.setClean(-1)
  378. selectedDeptSmail.value = -1
  379. if (Big.value) Big.value.setClean(-1)
  380. selectedDeptBig.value = -1
  381. if (Dept.value) Dept.value.setClean(-1)
  382. selectedDept.value = -1
  383. updateSelectedTags()
  384. }
  385. /**
  386. * 初始化数据
  387. */
  388. const handleClean = () => {
  389. // 重置选择状态
  390. selectedDept.value = -1
  391. selectedDeptBig.value = -1
  392. selectedDeptSmail.value = -1
  393. selectedTypeBig.value = -1
  394. selectedType.value = -1
  395. selectedTypeSmail.value = -1
  396. selectedFormat.value = -1
  397. // 重置数据数组
  398. selectedDeptBigs.value = []
  399. selectedDeptSmails.value = []
  400. selectedTypes.value = []
  401. selectedTypesSmail.value = []
  402. selectedTypesBigList.value = []
  403. selectedTypesList.value = []
  404. selectedTypesLists.value = new Map()
  405. selectedDeptBigsList.value = []
  406. selectedDeptSmailsList.value = []
  407. // 加载部门数据
  408. spinningSelectedDepts.value = true
  409. collegeApi
  410. .treeAll()
  411. .then((data) => {
  412. selectedDepts.value = data.data || []
  413. // 构建部门层级关系
  414. selectedDepts.value.forEach((item) => {
  415. if (item.children) {
  416. selectedDeptBigsList.value.push(item.children)
  417. item.children.forEach((child) => {
  418. if (child.children && child.children.length>0) {
  419. selectedDeptSmailsList.value.push(child.children)
  420. }
  421. })
  422. } else {
  423. selectedDeptBigsList.value.push([])
  424. }
  425. })
  426. spinningSelectedDepts.value = false
  427. })
  428. .catch(() => {
  429. spinningSelectedDepts.value = false
  430. })
  431. // 加载资源类型数据
  432. spinningSelectedTypesBig.value = true
  433. getQueryTreeAll()
  434. .then((data) => {
  435. selectedTypesBig.value = data.data || []
  436. // 构建资源类型层级关系
  437. selectedTypesBig.value.forEach((item) => {
  438. if (item.children) {
  439. selectedTypesBigList.value.push(item.children)
  440. item.children.forEach((child) => {
  441. if (child.children) {
  442. // 使用Map存储父子关系,提高查找效率
  443. selectedTypesLists.value.set(child.id, child.children)
  444. }
  445. })
  446. } else {
  447. selectedTypesBigList.value.push([])
  448. }
  449. })
  450. spinningSelectedTypesBig.value = false
  451. })
  452. .catch(() => {
  453. spinningSelectedTypesBig.value = false
  454. })
  455. // 加载文件格式数据
  456. spinningSelectedFormats.value = true
  457. getAllListFileFormat()
  458. .then((data) => {
  459. selectedFormats.value = data.data || []
  460. spinningSelectedFormats.value = false
  461. })
  462. .catch(() => {
  463. spinningSelectedFormats.value = false
  464. })
  465. }
  466. onMounted(() => {
  467. handleClean()
  468. })
  469. </script>
  470. <style scoped>
  471. .filter-bar {
  472. background: white;
  473. padding: 30px 40px;
  474. border: 1px solid #00000011;
  475. }
  476. .filter-group {
  477. display: flex;
  478. align-items: flex-start;
  479. }
  480. .filter-group-title {
  481. color: rgba(0, 0, 0, 0.521);
  482. font-size: 14px;
  483. min-width: 80px;
  484. margin-top: 5px;
  485. }
  486. .radio-group-container {
  487. display: flex;
  488. flex-direction: column;
  489. }
  490. .radio-group-spacing {
  491. height: 5px;
  492. }
  493. .spacing-line {
  494. width: 100%;
  495. height: 0.25px;
  496. background-color: #00000013;
  497. margin: 10px 0;
  498. }
  499. .selected-tags-container {
  500. display: flex;
  501. align-items: center;
  502. flex-wrap: wrap;
  503. gap: 8px;
  504. margin-top: 7px;
  505. }
  506. .clean {
  507. color: rgb(133, 183, 224);
  508. cursor: pointer;
  509. padding: 2px 8px;
  510. }
  511. </style>