index.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. import { NPopover, NScrollbar, NTooltip } from 'naive-ui';
  2. import {
  3. PropType,
  4. computed,
  5. defineComponent,
  6. onMounted,
  7. reactive,
  8. ref,
  9. toRefs,
  10. watch
  11. } from 'vue';
  12. import styles from './index.module.less';
  13. import arrowDown from './images/icon-arrow-down.png';
  14. import arrowUp from './images/icon-arrow-up.png';
  15. import arrowDownSmall from './images/icon-arrow-down_small.png';
  16. import arrowUpSmall from './images/icon-arrow-up_small.png';
  17. import { audioPlayType } from '/src/utils/contants';
  18. export default defineComponent({
  19. name: 'c-cascader',
  20. props: {
  21. /** 是否显示场景搜索条件 */
  22. showAudioPlayType: {
  23. type: Boolean,
  24. default: false
  25. },
  26. /** 子选项是否显示全部类型 */
  27. childShowAllCheck: {
  28. type: Boolean,
  29. default: true
  30. },
  31. value: {
  32. type: String,
  33. default: ''
  34. },
  35. options: {
  36. type: Array as PropType<any[]>,
  37. default: () => []
  38. },
  39. arrowType: {
  40. type: String as PropType<'default' | 'small'>,
  41. default: 'default'
  42. },
  43. placeholder: {
  44. type: String,
  45. default: '请选择'
  46. },
  47. placement: {
  48. type: String,
  49. default: 'bottom-start'
  50. },
  51. showPath: {
  52. type: Boolean,
  53. default: false
  54. }
  55. },
  56. emits: ['update:value', 'moreId'],
  57. setup(props, { emit }) {
  58. const state = reactive({
  59. popoverShow: false,
  60. selectParents: {}, // 选中的数据
  61. tempAudioPlayTypes: '',
  62. audioPlayTypes: '',
  63. tagActiveId: '' as any,
  64. tagActive: {} as any,
  65. childSelectId: null as any,
  66. x: 0,
  67. y: 0
  68. });
  69. const audioPlayTypeList = ref([] as any);
  70. // const formatParentCurrentValue = (ids: any, list: any) => {
  71. // for (const item of list) {
  72. // if (ids.includes(item.id)) {
  73. // if (item.children && item.children.length > 0) {
  74. // let lastId: any;
  75. // item.children.forEach((child: any) => {
  76. // if (ids.includes(child.id)) {
  77. // lastId = child.id;
  78. // }
  79. // });
  80. // item.activeIndex = lastId;
  81. // }
  82. // }
  83. // if (item.children && item.children.length > 0) {
  84. // formatParentCurrentValue(ids, item.children);
  85. // }
  86. // }
  87. // };
  88. const initParentSelect = (subject: any) => {
  89. let children: any;
  90. let columnName = '';
  91. if (subject.children) {
  92. children = [...subject.children];
  93. let activeIndex = children.length > 0 ? children[0].id : '';
  94. if (props.childShowAllCheck) {
  95. children.unshift({
  96. columnName: subject.children[0].columnName,
  97. name: '全部' + subject.children[0].columnName || '',
  98. id: ''
  99. });
  100. activeIndex = '';
  101. }
  102. columnName = subject.children[0].columnName;
  103. state.childSelectId = activeIndex;
  104. state.selectParents = {
  105. ...subject,
  106. columnName,
  107. activeIndex,
  108. children
  109. };
  110. } else {
  111. state.selectParents = {};
  112. }
  113. };
  114. // watch(
  115. // () => state.popoverShow,
  116. // () => {
  117. // if (!state.popoverShow || !props.value) return;
  118. // let ids = formatParentId(props.value, props.options);
  119. // state.tagActiveId = ids[0].id;
  120. // props.options.forEach((item: any) => {
  121. // if (item.id === state.tagActiveId) {
  122. // initParentSelect(item);
  123. // }
  124. // });
  125. // //
  126. // const index = ids.findIndex((child: any) => child.id === props.value);
  127. // ids = ids.slice(0, index + 1);
  128. // const values = ids.map((item: any) => {
  129. // return item.id;
  130. // });
  131. // console.log(values, 'values');
  132. // formatParentCurrentValue(values, props.options);
  133. // }
  134. // );
  135. const valueText = computed(() => {
  136. const id = props.value;
  137. const values = getValues(id);
  138. const names: any = [];
  139. audioPlayTypeList.value.forEach((item: any) => {
  140. if (item.id === state.tempAudioPlayTypes && props.showAudioPlayType) {
  141. names.push(item.name);
  142. }
  143. });
  144. if (state.tempAudioPlayTypes !== 'SING') {
  145. values.forEach((item: any) => {
  146. names.push(item.name);
  147. });
  148. }
  149. if (props.showPath) {
  150. return names.join(' / ');
  151. } else {
  152. const lastName = names[names.length - 1];
  153. // console.log(lastName, 'last names');
  154. return lastName;
  155. }
  156. });
  157. // 递归获取数据
  158. const formatParentId = (id: any, list: any, ids = [] as any) => {
  159. for (const item of list) {
  160. if (item.children && item.children.length > 0) {
  161. const cIds: any = formatParentId(id, item.children, [
  162. ...ids,
  163. {
  164. name: item.name,
  165. id: item.id
  166. }
  167. ]);
  168. const index = cIds.findIndex((c: any) => c.id === id);
  169. if (index > -1) {
  170. return cIds;
  171. }
  172. }
  173. if (item.id === id) {
  174. return [
  175. ...ids,
  176. {
  177. name: item.name,
  178. id
  179. }
  180. ];
  181. }
  182. }
  183. return ids;
  184. };
  185. const getValues = (value: any) => {
  186. let ids = formatParentId(value, props.options);
  187. const index = ids.findIndex((child: any) => child.id === value);
  188. ids = ids.slice(0, index + 1);
  189. return ids;
  190. };
  191. // 重置
  192. const onReset = () => {
  193. state.childSelectId = null;
  194. state.tagActiveId = '';
  195. state.audioPlayTypes = '';
  196. state.tempAudioPlayTypes = '';
  197. state.selectParents = {};
  198. emit('update:value', '');
  199. emit('moreId', {
  200. childId: '',
  201. parentId: '',
  202. audioPlayTypes: ''
  203. });
  204. state.popoverShow = false;
  205. };
  206. // 提交
  207. const onConfirm = () => {
  208. if (state.audioPlayTypes !== 'SING') {
  209. emit('update:value', state.childSelectId || state.tagActiveId);
  210. emit('moreId', {
  211. childId: state.childSelectId,
  212. parentId: state.tagActiveId,
  213. audioPlayTypes: state.audioPlayTypes
  214. });
  215. } else {
  216. emit('update:value', '');
  217. emit('moreId', {
  218. childId: '',
  219. parentId: '',
  220. audioPlayTypes: state.audioPlayTypes
  221. });
  222. state.tagActiveId = '';
  223. state.childSelectId = null;
  224. }
  225. state.tempAudioPlayTypes = state.audioPlayTypes;
  226. state.popoverShow = false;
  227. };
  228. onMounted(() => {
  229. // 场景
  230. const tempAudio = Object.keys(audioPlayType).map(key => {
  231. return {
  232. id: key,
  233. name: audioPlayType[key]
  234. };
  235. });
  236. audioPlayTypeList.value = [{ name: '全部场景', id: '' }, ...tempAudio];
  237. });
  238. return () => (
  239. <>
  240. <NPopover
  241. placement={props.placement as any}
  242. v-model:show={state.popoverShow}
  243. showArrow={false}
  244. trigger="click"
  245. displayDirective="show"
  246. class={[styles.cascaderPopover, 'c-cascaderPopover']}>
  247. {{
  248. trigger: () => (
  249. <div
  250. class={[
  251. styles.nBaseCascaser,
  252. 'nBaseCascaser',
  253. state.popoverShow ? styles.nBaseCascaserActive : ''
  254. ]}
  255. title={valueText.value}>
  256. <div
  257. class={[
  258. styles['n-base-selection-tags'],
  259. 'n-base-selection-tags'
  260. ]}>
  261. <div class={styles['n-base-selection-input']}>
  262. <div class={styles['n-base-selection-input__content']}>
  263. {valueText.value}
  264. </div>
  265. </div>
  266. <div class={[styles['n-base-suffix']]}>
  267. <div
  268. class={[
  269. styles.arrow,
  270. props.arrowType === 'small' ? styles.arrowSmall : ''
  271. ]}>
  272. {props.arrowType === 'default' && (
  273. <img src={state.popoverShow ? arrowUp : arrowDown} />
  274. )}
  275. {props.arrowType === 'small' && (
  276. <img
  277. src={
  278. state.popoverShow ? arrowUpSmall : arrowDownSmall
  279. }
  280. />
  281. )}
  282. </div>
  283. </div>
  284. </div>
  285. <div
  286. class={[
  287. styles['n-base-selection-placeholder'],
  288. styles['n-base-selection-overlay']
  289. ]}>
  290. {!valueText.value && (
  291. <div class={styles.inner}>{props.placeholder}</div>
  292. )}
  293. </div>
  294. <div
  295. class={[
  296. styles['n-base-selection__border'],
  297. 'n-base-selection__border'
  298. ]}></div>
  299. <div class={styles['n-base-selection__state-border']}></div>
  300. </div>
  301. ),
  302. default: () => (
  303. <div class={styles.baseContent}>
  304. <NScrollbar
  305. class={styles.baseScrollBar}
  306. style={{ maxHeight: '400px' }}>
  307. {props.showAudioPlayType && (
  308. <>
  309. <div class={styles.baseContentTitle}>场景</div>
  310. <div class={styles.baseContentWrap}>
  311. {audioPlayTypeList.value.map((subject: any) => (
  312. <span
  313. class={[
  314. styles.tag,
  315. (state.audioPlayTypes || '') == subject.id &&
  316. styles.tagActive
  317. ]}
  318. onClick={() => {
  319. if (state.audioPlayTypes !== subject.id) {
  320. state.childSelectId = null;
  321. }
  322. state.audioPlayTypes = subject.id;
  323. }}>
  324. {subject.name}
  325. </span>
  326. ))}
  327. </div>
  328. </>
  329. )}
  330. {state.audioPlayTypes !== 'SING' && (
  331. <>
  332. <div class={styles.baseContentTitle}>
  333. {props.options[0].columnName}
  334. </div>
  335. <div class={styles.baseContentWrap}>
  336. {props.options.map((subject: any) => (
  337. <span
  338. class={[
  339. styles.tag,
  340. (state.tagActiveId || '') == subject.id &&
  341. styles.tagActive
  342. ]}
  343. onClick={() => {
  344. if (state.tagActiveId !== subject.id) {
  345. state.childSelectId = null;
  346. }
  347. state.tagActiveId = subject.id;
  348. initParentSelect(subject);
  349. }}>
  350. {subject.name}
  351. </span>
  352. ))}
  353. </div>
  354. <ChildNodeSearch
  355. childShowAllCheck={props.childShowAllCheck}
  356. activeRow={state.selectParents}
  357. onSelectChildTag={(val: any) => {
  358. state.childSelectId = val;
  359. }}
  360. />
  361. </>
  362. )}
  363. </NScrollbar>
  364. <div class={styles.btnGroup}>
  365. <div class={[styles.btn, styles.btnCancel]} onClick={onReset}>
  366. 重置
  367. </div>
  368. <div
  369. class={[styles.btn, styles.btnConfirm]}
  370. onClick={onConfirm}>
  371. 确认
  372. </div>
  373. </div>
  374. </div>
  375. )
  376. }}
  377. </NPopover>
  378. </>
  379. );
  380. }
  381. });
  382. const ChildNodeSearch = defineComponent({
  383. name: 'ChildNodeSearch',
  384. props: {
  385. /** 子选项是否显示全部类型 */
  386. childShowAllCheck: {
  387. type: Boolean,
  388. default: true
  389. },
  390. activeRow: {
  391. type: Object,
  392. default: () => ({})
  393. },
  394. list: {
  395. type: Array,
  396. default: () => []
  397. },
  398. loading: {
  399. type: Boolean,
  400. default: false
  401. }
  402. },
  403. emits: ['selectChildTag'],
  404. setup(props, { emit }) {
  405. const { activeRow } = toRefs(props);
  406. const selectItem = ref({});
  407. watch(
  408. () => props.activeRow,
  409. () => {
  410. activeRow.value = props.activeRow;
  411. initActiveRow();
  412. }
  413. );
  414. const initActiveRow = () => {
  415. if (activeRow.value.activeIndex) {
  416. const childList = activeRow.value.children || [];
  417. childList.forEach((subject: any) => {
  418. if (subject.id === activeRow.value.activeIndex) {
  419. let children: any;
  420. let columnName = '';
  421. if (subject.children) {
  422. children = [...subject.children];
  423. if (props.childShowAllCheck) {
  424. children.unshift({
  425. columnName: subject.children[0].columnName,
  426. name: '全部' + subject.children[0].columnName || '',
  427. id: ''
  428. });
  429. }
  430. columnName = subject.children[0].columnName;
  431. selectItem.value = {
  432. ...subject,
  433. columnName,
  434. activeIndex: subject.activeIndex || '',
  435. children
  436. };
  437. emit('selectChildTag', subject.activeIndex || '');
  438. }
  439. }
  440. });
  441. } else {
  442. selectItem.value = {};
  443. }
  444. };
  445. onMounted(() => {
  446. initActiveRow();
  447. });
  448. return () => (
  449. <>
  450. {activeRow.value?.id && (
  451. <>
  452. <div class={styles.baseContentTitle}>
  453. {activeRow.value.columnName}
  454. </div>
  455. <div class={styles.baseContentWrap}>
  456. {activeRow.value?.children.map((subject: any) => (
  457. <span
  458. class={[
  459. styles.tag,
  460. (activeRow.value.activeIndex || '') == subject.id &&
  461. styles.tagActive
  462. ]}
  463. onClick={() => {
  464. if (props.loading) return;
  465. activeRow.value.activeIndex = subject.id;
  466. let children: any;
  467. let columnName = '';
  468. if (subject.children) {
  469. children = [...subject.children];
  470. let activeIndex =
  471. children.length > 0 ? children[0].id : '';
  472. if (props.childShowAllCheck) {
  473. children.unshift({
  474. columnName: subject.children[0].columnName,
  475. name: '全部' + subject.children[0].columnName || '',
  476. id: ''
  477. });
  478. activeIndex = '';
  479. }
  480. columnName = subject.children[0].columnName;
  481. selectItem.value = {
  482. ...subject,
  483. columnName,
  484. activeIndex,
  485. children
  486. };
  487. } else {
  488. selectItem.value = {};
  489. }
  490. emit('selectChildTag', activeRow.value.activeIndex);
  491. }}>
  492. {subject.name}
  493. </span>
  494. ))}
  495. </div>
  496. <ChildNodeSearch
  497. activeRow={selectItem.value}
  498. onSelectChildTag={(item: any) => {
  499. emit('selectChildTag', item || activeRow.value.activeIndex);
  500. }}
  501. />
  502. </>
  503. )}
  504. </>
  505. );
  506. }
  507. });