index.tsx 6.9 KB

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