index.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import {
  2. NButton,
  3. NCard,
  4. NCheckbox,
  5. NGi,
  6. NGrid,
  7. NIcon,
  8. NInputNumber,
  9. NLayout,
  10. NLayoutContent,
  11. NLayoutSider,
  12. NModal,
  13. NPopover,
  14. NRadio,
  15. NRadioGroup,
  16. NScrollbar,
  17. NSpace,
  18. NTabPane,
  19. NTable,
  20. NTabs,
  21. useMessage,
  22. } from "naive-ui";
  23. import { defineComponent, onMounted, reactive, watch } from "vue";
  24. import { Close } from "@vicons/ionicons5";
  25. import styles from "./index.module.less";
  26. import { getImage } from "/src/pc/home/images";
  27. import { ABC_DATA } from "/src/pc/home/runtime";
  28. import TheIcon from "/src/components/The-icon";
  29. import { encodeUrl } from "/src/utils";
  30. const instruments = [
  31. {
  32. label: "竖笛",
  33. key: "recorder",
  34. id: 4,
  35. icon: getImage("icon_27_0.png"),
  36. range: {
  37. min: 36,
  38. max: 62,
  39. },
  40. },
  41. {
  42. label: "排箫",
  43. key: "pan_flute",
  44. id: 1,
  45. icon: getImage("icon_27_1.png"),
  46. range: {
  47. min: 31,
  48. max: 66,
  49. },
  50. },
  51. {
  52. label: "口风琴",
  53. key: "piccolo",
  54. id: 5,
  55. icon: getImage("icon_27_2.png"),
  56. range: {
  57. min: 41,
  58. max: 72,
  59. },
  60. },
  61. {
  62. label: "陶笛",
  63. key: "blown_bottle",
  64. id: 2,
  65. icon: getImage("icon_27_3.png"),
  66. range: {
  67. min: 33,
  68. max: 53,
  69. },
  70. },
  71. {
  72. label: "葫芦丝",
  73. key: "clarinet",
  74. id: 3,
  75. icon: getImage("icon_27_4.png"),
  76. range: {
  77. min: 40,
  78. max: 57,
  79. },
  80. },
  81. ];
  82. export const notationInstruments = instruments;
  83. export default defineComponent({
  84. name: "TheCreate",
  85. props: {
  86. show: {
  87. type: Boolean,
  88. default: false,
  89. },
  90. },
  91. emits: ["update:show", "create"],
  92. setup(props, { emit }) {
  93. const message = useMessage();
  94. const formsOptions = reactive({
  95. loading: false,
  96. });
  97. const froms = reactive({
  98. key: ABC_DATA.key[0],
  99. meter: ABC_DATA.meter[0],
  100. speed: 80,
  101. measure: 30,
  102. subjectCode: "recorder",
  103. subjectId: 4,
  104. });
  105. const handleCreate = async () => {
  106. if (!froms.speed) {
  107. message.warning("请输入开始速度");
  108. return;
  109. }
  110. if (!froms.measure) {
  111. message.warning("请输入小节数量");
  112. return;
  113. }
  114. formsOptions.loading = true;
  115. handleOpenNotaion({
  116. meter: froms.meter.value,
  117. speed: `Q:1/4=${froms.speed}`,
  118. key: froms.key.value,
  119. subjectCode: froms.subjectCode,
  120. measure: froms.measure,
  121. subjectId: froms.subjectId
  122. });
  123. emit("create");
  124. formsOptions.loading = false;
  125. };
  126. const handleOpenNotaion = (data: any) => {
  127. const url = `${location.origin}/notation/#/?v=${Date.now()}&config=${encodeUrl(data)}`;
  128. // console.log("🚀 ~ url:", url);
  129. window.parent.postMessage(
  130. {
  131. api: "notation_open",
  132. url: url,
  133. },
  134. "*"
  135. );
  136. // window.open(url, "_blank");
  137. };
  138. return () => (
  139. <NModal
  140. unstableShowMask={false}
  141. transformOrigin="center"
  142. autoFocus={false}
  143. show={props.show}
  144. onUpdate:show={(val) => emit("update:show", val)}
  145. >
  146. <div class={styles.setbox}>
  147. <div class={styles.head}>
  148. <div>新建乐谱</div>
  149. <NButton
  150. class={styles.close}
  151. quaternary
  152. circle
  153. size="small"
  154. onClick={() => emit("update:show", false)}
  155. >
  156. <NIcon component={Close} size={18} />
  157. </NButton>
  158. </div>
  159. <div class={styles.content}>
  160. <div class={styles.lineTitle}>声部</div>
  161. <NSpace size={32} style={{ paddingBottom: "45px" }}>
  162. {instruments.map((item) => (
  163. <div
  164. class={[styles.item, froms.subjectCode === item.key && styles.itemActive]}
  165. onClick={() => {
  166. froms.subjectCode = item.key;
  167. froms.subjectId = item.id;
  168. }}
  169. >
  170. <div class={styles.itemImg}>
  171. <img class={styles.icon} src={item.icon} />
  172. </div>
  173. <div>{item.label}</div>
  174. <img class={styles.itemIcon} src={getImage("icon_check.png")} />
  175. </div>
  176. ))}
  177. </NSpace>
  178. <NSpace style={{ paddingBottom: "45px" }}>
  179. <NPopover to="body" trigger="click">
  180. {{
  181. trigger: () => (
  182. <div>
  183. <div class={styles.lineTitle}>调号</div>
  184. <div class={styles.beatItem}>
  185. <div class={[styles.beatIcon]}>
  186. <TheIcon iconClassName={froms.key.icon} />
  187. </div>
  188. <div>{froms.key.name}</div>
  189. </div>
  190. </div>
  191. ),
  192. default: () => (
  193. <NGrid cols={5} xGap={20} yGap={8}>
  194. {ABC_DATA.key.map((item) => (
  195. <NGi>
  196. <div
  197. class={[styles.btnItem, froms.key.value === item.value && styles.active]}
  198. onClick={() => (froms.key = item)}
  199. >
  200. <div class={[styles.btnItemIcon]}>
  201. <TheIcon iconClassName={item.icon} />
  202. </div>
  203. <div class={styles.btnItemName}>{item.name}</div>
  204. </div>
  205. </NGi>
  206. ))}
  207. </NGrid>
  208. ),
  209. }}
  210. </NPopover>
  211. <NPopover to="body" trigger="click">
  212. {{
  213. trigger: () => (
  214. <div>
  215. <div class={styles.lineTitle}>拍号</div>
  216. <div class={styles.beatItem}>
  217. <div class={[styles.beatIcon]}>
  218. <TheIcon iconClassName={froms.meter.icon} />
  219. </div>
  220. <div>{froms.meter.name}</div>
  221. </div>
  222. </div>
  223. ),
  224. default: () => (
  225. <NGrid cols={5} xGap={50} yGap={20}>
  226. {ABC_DATA.meter.map((item) => (
  227. <NGi>
  228. <div
  229. class={[styles.btnItem, froms.meter.value === item.value && styles.active]}
  230. onClick={() => (froms.meter = item)}
  231. >
  232. <div class={[styles.btnItemIcon]}>
  233. <TheIcon iconClassName={item.icon} />
  234. </div>
  235. <div class={styles.btnItemName}>{item.name}</div>
  236. </div>
  237. </NGi>
  238. ))}
  239. </NGrid>
  240. ),
  241. }}
  242. </NPopover>
  243. <div>
  244. <div class={styles.lineTitle}>速度</div>
  245. <div class={styles.beatItem}>
  246. <NInputNumber
  247. size="large"
  248. v-model:value={froms.speed}
  249. placeholder="开始速度"
  250. showButton={false}
  251. min={50}
  252. >
  253. {{
  254. prefix: () => (
  255. <div class={styles.speedIcon}>
  256. <TheIcon iconClassName="icon-a-sudu-4fenyinfu" size={["2em", "1em"]} />
  257. </div>
  258. ),
  259. }}
  260. </NInputNumber>
  261. </div>
  262. </div>
  263. <div>
  264. <div class={styles.lineTitle}>小节</div>
  265. <div class={styles.beatItem}>
  266. <NInputNumber
  267. placeholder="小节数量"
  268. size="large"
  269. v-model:value={froms.measure}
  270. min={4}
  271. ></NInputNumber>
  272. </div>
  273. </div>
  274. </NSpace>
  275. <div class={styles.btns}>
  276. <NButton round onClick={() => emit("update:show", false)}>
  277. 取消
  278. </NButton>
  279. <NButton
  280. loading={formsOptions.loading}
  281. round
  282. type="primary"
  283. onClick={() => handleCreate()}
  284. >
  285. 确定
  286. </NButton>
  287. </div>
  288. </div>
  289. </div>
  290. </NModal>
  291. );
  292. },
  293. });