index.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. import {
  2. PropType,
  3. computed,
  4. defineComponent,
  5. onMounted,
  6. reactive,
  7. watch
  8. } from 'vue';
  9. import styles from './index.module.less';
  10. import { Button, Collapse, CollapseItem, showToast } from 'vant';
  11. import {
  12. barLineList,
  13. beatList,
  14. elementList,
  15. initSelectScorePartModal,
  16. renderScore,
  17. renderScoreModal,
  18. setting,
  19. setting_modal,
  20. getTempList,
  21. tempo4,
  22. tempo8
  23. } from '../setting';
  24. import { getImage } from '../images/music';
  25. import { hendleEndTick } from '../tick';
  26. import { hendleEndBeat } from '../beat-tick';
  27. import { useRoute } from 'vue-router';
  28. import settingArrowActive from '../images/setting-arrow-active.png';
  29. import settingArrowDefault from '../images/setting-arrow-default.png';
  30. import Draggable from 'vuedraggable';
  31. export default defineComponent({
  32. emits: ['close'],
  33. props: {
  34. class: {
  35. type: Object as PropType<any>,
  36. default: () => {}
  37. }
  38. // dataJson: {
  39. // type: Object,
  40. // default: () => {}
  41. // }
  42. },
  43. name: 'setting-modal',
  44. setup(props, { emit, expose }) {
  45. const route = useRoute();
  46. // const { element, beat, barLine, tempo } = props.dataJson;
  47. const tempDeepClone = (val: any) => {
  48. return JSON.parse(JSON.stringify(val));
  49. };
  50. const state = reactive({
  51. win: route.query.win,
  52. platform: route.query.platform,
  53. activeNames: ['base', 'beat'] as any, // 折叠面板
  54. element:
  55. tempDeepClone(setting_modal.element) ||
  56. ('jianpu' as 'jianpu' | 'staff'), // 元素
  57. beat:
  58. tempDeepClone(setting_modal.beat) ||
  59. ('4-4' as '4-2' | '4-3' | '4-4' | '8-3' | '8-6'), // 拍号
  60. barLine: tempDeepClone(setting_modal.barLine) || ('1' as '1' | '2' | '4'), // 小节数
  61. tempo: tempDeepClone(setting_modal.tempo) || (['1', '2', '3'] as any[]) // 节奏形筛选
  62. });
  63. const tempoList = computed(() => {
  64. if (['4-2', '4-3', '4-4'].includes(state.beat)) {
  65. return getTempList(state.element).tempo4;
  66. } else if (['8-3', '8-6'].includes(state.beat)) {
  67. return getTempList(state.element).tempo8;
  68. }
  69. return getTempList(state.element).tempo4;
  70. });
  71. const tempoListNum = computed(() => {
  72. if (['4-2', '4-3', '4-4'].includes(state.beat)) {
  73. return getTempList(state.element).tempo4Num;
  74. } else if (['8-3', '8-6'].includes(state.beat)) {
  75. return getTempList(state.element).tempo8Num;
  76. }
  77. return getTempList(state.element).tempo4Num;
  78. });
  79. // 重置选中数据
  80. watch(
  81. () => setting_modal,
  82. () => {
  83. state.element =
  84. tempDeepClone(setting_modal.element) ||
  85. ('jianpu' as 'jianpu' | 'staff'); // 元素
  86. state.beat =
  87. tempDeepClone(setting_modal.beat) ||
  88. ('4-4' as '4-2' | '4-3' | '4-4' | '8-3' | '8-6'); // 拍号
  89. state.barLine =
  90. tempDeepClone(setting_modal.barLine) || ('1' as '1' | '2' | '4'); // 小节数
  91. state.tempo =
  92. tempDeepClone(setting_modal.tempo) || (['1', '2', '3'] as any[]); // 节奏形筛选
  93. },
  94. {
  95. deep: true
  96. }
  97. );
  98. const getBeatUrl = (value: any) => {
  99. const prefix = state.element === 'jianpu' ? 'j-' : 'f-';
  100. return prefix + value + '.png';
  101. };
  102. const onChangeTempo = (item: any) => {
  103. let si = 0,
  104. ji = 0;
  105. let status = false;
  106. setting_modal.scorePart.forEach((part: Array<any>, i: number) => {
  107. part.forEach((child: any, j: number) => {
  108. if (child.selected) {
  109. child.url = getBeatUrl(item);
  110. child.index = item;
  111. child.selected = false;
  112. si = i;
  113. ji = j;
  114. status = true;
  115. }
  116. });
  117. });
  118. if (status) {
  119. const indexs = toNext(si, ji);
  120. if (indexs && indexs.length > 0) {
  121. initSelectScorePartModal(indexs[0], indexs[1]);
  122. }
  123. }
  124. };
  125. const toNext = (i: number, j: number) => {
  126. const scorePart = setting_modal.scorePart;
  127. let tempJ = j + 1;
  128. for (let si = i; si < scorePart.length; si++) {
  129. for (let ji = tempJ; ji < scorePart[si].length; ji++) {
  130. return [si, ji];
  131. }
  132. tempJ = 0;
  133. }
  134. };
  135. const handleStop = () => {
  136. setting_modal.playState = 'pause';
  137. if (setting_modal.playType === 'beat') {
  138. hendleEndTick();
  139. } else {
  140. hendleEndBeat();
  141. }
  142. };
  143. /** 数据有变化时重置 */
  144. const onChangeResetTempo = () => {
  145. // if (state.tempo.length <= 0) {
  146. // showToast('节奏型不能为空');
  147. // return;
  148. // }
  149. let status = false; // 是否有更改
  150. if (
  151. setting_modal.element !== state.element ||
  152. setting_modal.beat !== state.beat ||
  153. setting_modal.barLine !== state.barLine ||
  154. setting_modal.tempo.join(',') !== state.tempo.join(',')
  155. ) {
  156. status = true;
  157. }
  158. // 判断是否有数据变化
  159. handleStop();
  160. if (status) {
  161. setting_modal.element = tempDeepClone(state.element);
  162. setting_modal.beat = tempDeepClone(state.beat); //state.beat;
  163. setting_modal.barLine = tempDeepClone(state.barLine); // state.barLine;
  164. setting_modal.tempo = tempDeepClone(state.tempo); // state.tempo;
  165. renderScoreModal();
  166. }
  167. };
  168. const onSubmit = () => {
  169. // 初始化设置的数据
  170. for (let i in setting_modal) {
  171. setting[i] = JSON.parse(JSON.stringify(setting_modal[i]));
  172. }
  173. emit('close');
  174. };
  175. const tempoListData = computed(() => {
  176. const list = tempoListNum.value // Object.keys(tempoList.value);
  177. console.log(list, 'list')
  178. return list.map(key => {
  179. return {
  180. index: key,
  181. key: key,
  182. url: getBeatUrl(key),
  183. sourceFrom: 'setting-modal'
  184. };
  185. });
  186. });
  187. expose({
  188. onSubmit
  189. });
  190. return () => (
  191. <div
  192. class={[
  193. props.class,
  194. styles.settingContainer,
  195. state.win === 'pc' ? styles.pcS : '',
  196. state.platform === 'modal' && state.win !== 'pc' ? styles.modalS : ''
  197. ]}>
  198. {/* <div class={styles.title}></div> */}
  199. <div class={[styles.iconTitBox, 'iconTitBoxMove']}>
  200. <i
  201. class={styles.iconClose}
  202. onClick={() => {
  203. emit('close');
  204. setTimeout(() => {
  205. state.element = tempDeepClone(setting_modal.element);
  206. state.beat = tempDeepClone(setting_modal.beat); //state.beat;
  207. state.barLine = tempDeepClone(setting_modal.barLine); // state.barLine;
  208. state.tempo = tempDeepClone(setting_modal.tempo); // state.tempo;
  209. }, 300);
  210. }}></i>
  211. </div>
  212. <div class={[styles.settingContent]}>
  213. <Collapse v-model={state.activeNames} border={false}>
  214. <CollapseItem
  215. title="基础设置"
  216. name="base"
  217. border={false}
  218. isLink={false}
  219. class={[
  220. styles.collapseContainer,
  221. state.activeNames.includes('base') ? '' : styles.paddingBottom
  222. ]}>
  223. {{
  224. icon: () => (
  225. <img
  226. src={
  227. state.activeNames.includes('base')
  228. ? settingArrowActive
  229. : settingArrowDefault
  230. }
  231. class={styles.iArrow}
  232. />
  233. ),
  234. default: () => (
  235. <>
  236. <div class={styles.parmaTitle}>元素</div>
  237. <div class={styles.paramContent}>
  238. {Object.keys(elementList).map((item: any) => (
  239. <Button
  240. round
  241. class={[
  242. styles.btn,
  243. state.element === item && styles.active
  244. ]}
  245. onClick={() => {
  246. state.element = item;
  247. onChangeResetTempo();
  248. }}>
  249. {elementList[item]}
  250. </Button>
  251. ))}
  252. </div>
  253. <div class={styles.parmaTitle}>拍号</div>
  254. <div class={[styles.paramContent, styles.beatContent]}>
  255. {Object.keys(beatList).map((item: any) => (
  256. <Button
  257. round
  258. class={[
  259. styles.btn,
  260. state.beat === item && styles.active
  261. ]}
  262. onClick={() => {
  263. state.beat = item;
  264. if (['4-2', '4-3', '4-4'].includes(state.beat)) {
  265. state.tempo = ['1', '2', '3'];
  266. } else if (['8-3', '8-6'].includes(state.beat)) {
  267. state.tempo = ['15', '16', '17'];
  268. }
  269. onChangeResetTempo();
  270. }}>
  271. {beatList[item]}
  272. </Button>
  273. ))}
  274. </div>
  275. <div class={styles.parmaTitle}>每页显示小节数量</div>
  276. <div class={styles.paramContent}>
  277. {Object.keys(barLineList).map((item: any) => (
  278. <Button
  279. round
  280. class={[
  281. styles.btn,
  282. state.barLine === item && styles.active
  283. ]}
  284. onClick={() => {
  285. state.barLine = item;
  286. onChangeResetTempo();
  287. }}>
  288. {barLineList[item]}
  289. </Button>
  290. ))}
  291. </div>
  292. </>
  293. )
  294. }}
  295. </CollapseItem>
  296. <CollapseItem
  297. title="节奏型"
  298. name="beat"
  299. border={false}
  300. isLink={false}
  301. class={styles.collapseContainer}>
  302. {{
  303. icon: () => (
  304. <img
  305. src={
  306. state.activeNames.includes('beat')
  307. ? settingArrowActive
  308. : settingArrowDefault
  309. }
  310. class={styles.iArrow}
  311. />
  312. ),
  313. default: () => (
  314. <>
  315. {/* <div class={styles.parmaTitle}>节奏型筛选</div> */}
  316. <Draggable
  317. modelValue={tempoListData.value}
  318. itemKey="id"
  319. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  320. // @ts-ignore
  321. // group="description"
  322. group={{
  323. name: 'description',
  324. pull: 'clone',
  325. put: false
  326. }}
  327. animation={200}
  328. sort={false}
  329. onMove={(evt: any) => {
  330. return evt.from !== evt.to;
  331. }}
  332. onStart={(evt: any) => {
  333. evt.from.classList.add('onstart');
  334. }}
  335. onEnd={(evt: any) => {
  336. evt.from.classList.remove('onstart');
  337. }}
  338. componentData={{
  339. draggable: 'row-nav',
  340. itemKey: 'id',
  341. tag: 'div',
  342. pull: 'clone',
  343. put: false,
  344. animation: 200,
  345. group: 'description'
  346. }}
  347. class={[styles.paramContent, styles.tempo]}>
  348. {{
  349. item: (element: any) => {
  350. const item = element.element;
  351. return (
  352. <div
  353. data-id={item.key}
  354. onClick={() => onChangeTempo(item.key)}>
  355. <img
  356. class={'draggable'}
  357. // class={state.tempo.includes(item) && styles.active}
  358. src={getImage(
  359. (state.element === 'jianpu' ? 'j-' : 'f-') +
  360. tempoList.value[item.key]
  361. )}
  362. />
  363. </div>
  364. );
  365. }
  366. }}
  367. </Draggable>
  368. </>
  369. )
  370. }}
  371. </CollapseItem>
  372. </Collapse>
  373. {/* <div class={styles.settingParams}></div> */}
  374. </div>
  375. {!state.win && !state.platform && (
  376. <div class={styles.btnGroup}>
  377. <Button class={styles.btnSubmit} onClick={onSubmit}></Button>
  378. </div>
  379. )}
  380. </div>
  381. );
  382. }
  383. });