index.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import { defineComponent, nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
  2. import styles from "./index.module.less";
  3. import { NButton, NCheckbox, NModal, NRadio, NSpace, NSpin, useDialog } from "naive-ui";
  4. import { getImage } from "../home/images";
  5. import TheCreate from "./component/the-create";
  6. import { storeData } from "/src/store";
  7. import { api_musicSheetCreationPage, api_musicSheetCreationRemove } from "../api";
  8. import { useRouter } from "vue-router";
  9. import ABCJS from "abcjs";
  10. import { usePageVisibility } from "@vant/use";
  11. import UploadToResources from "../component/upload-to-resources";
  12. import { getQuery } from "/src/utils/queryString";
  13. import { browser } from "/src/utils";
  14. export default defineComponent({
  15. name: "Create",
  16. setup() {
  17. const query = getQuery();
  18. const dialog = useDialog();
  19. console.log(storeData.user);
  20. const forms = reactive({
  21. teacherId: storeData.user.id,
  22. page: 1,
  23. keyword: "",
  24. rows: 20,
  25. });
  26. const data = reactive({
  27. list: [] as any[],
  28. addShow: query.addShow ? true : false,
  29. loading: false,
  30. finish: false,
  31. isCreated: false,
  32. uploadShow: false,
  33. item: {} as any,
  34. });
  35. const getList = async () => {
  36. data.loading = true;
  37. const res = await api_musicSheetCreationPage({ ...forms });
  38. if (res?.code == 200) {
  39. if (data.isCreated) {
  40. data.isCreated = false;
  41. handleOpenNotaion(res.data.rows[0]);
  42. }
  43. data.list = data.list.concat(res.data.rows);
  44. data.finish = res.data.rows.length < forms.rows;
  45. }
  46. // 重新登录
  47. if (res.code === 5000) {
  48. const browserInfo = browser();
  49. if (browserInfo.isApp) {
  50. postMessage({ api: "login" });
  51. } else {
  52. // 判断是否在应用中
  53. window.parent.postMessage(
  54. {
  55. api: "onLogin",
  56. },
  57. "*"
  58. );
  59. }
  60. return;
  61. }
  62. data.loading = false;
  63. };
  64. const handleReset = () => {
  65. forms.page = 1;
  66. data.finish = false;
  67. data.list = [];
  68. getList();
  69. };
  70. const pageVisibility = usePageVisibility();
  71. watch(pageVisibility, (val) => {
  72. if (val === "visible") {
  73. handleReset();
  74. }
  75. });
  76. const handleDelte = (item: any) => {
  77. const checked = ref(true);
  78. dialog.warning({
  79. autoFocus: false,
  80. class: "deleteDialog",
  81. title: "删除曲谱",
  82. content: () => (
  83. <div onClick={() => checked.value = !checked.value}>
  84. <NRadio checked={checked.value}>同步删除我的资源中的该曲目</NRadio>
  85. </div>
  86. ),
  87. // content: () => <div>确认删除当前曲谱?</div>,
  88. positiveText: "取消",
  89. positiveButtonProps: {
  90. type: "default",
  91. },
  92. negativeText: "删除",
  93. negativeButtonProps: {
  94. type: "primary",
  95. ghost: false,
  96. },
  97. onPositiveClick: () => {},
  98. onNegativeClick: async () => {
  99. await api_musicSheetCreationRemove(item.id, checked.value ? 1 : 0);
  100. handleReset();
  101. },
  102. });
  103. };
  104. const loadingRef = ref();
  105. const messageEvent = (params?: any) => {
  106. // 在老师端里面关闭要刷新
  107. if (params.data?.api == "reload") {
  108. handleReset();
  109. }
  110. };
  111. onMounted(() => {
  112. getList();
  113. if (loadingRef.value) {
  114. const obv = new IntersectionObserver((entries) => {
  115. if (entries[0].isIntersecting) {
  116. if (data.finish || data.loading) return;
  117. forms.page++;
  118. getList();
  119. }
  120. });
  121. obv.observe(loadingRef.value?.$el);
  122. }
  123. window.addEventListener("message", (params?: any) => {
  124. messageEvent(params);
  125. });
  126. });
  127. onUnmounted(() => {
  128. window.removeEventListener("message", messageEvent);
  129. });
  130. const handleOpenNotaion = (item: any) => {
  131. window.parent.postMessage(
  132. {
  133. api: "notation_open",
  134. url: `${location.origin}/notation/#/?v=1.0.3&id=${item.id}`,
  135. },
  136. "*"
  137. );
  138. };
  139. const productSvg = (abc: string, id: string) => {
  140. const a = ABCJS.renderAbc(id, abc, { selectTypes: false, add_classes: true })[0];
  141. return a;
  142. };
  143. const handleSuccess = () => {
  144. data.list.find((item: any) => item.id === data.item.id).uploadStatus = "YES";
  145. }
  146. return () => (
  147. <div class={styles.wrap}>
  148. <div class={styles.wrapBox}>
  149. <div class={styles.itemWrap}>
  150. <div class={styles.itemWrapBox}>
  151. <div class={styles.createItem} onClick={() => (data.addShow = true)}>
  152. <img src={getImage("icon_29.png")} />
  153. <div>新建乐谱</div>
  154. </div>
  155. </div>
  156. </div>
  157. {data.list.map((item, index: number) => (
  158. <div class={styles.itemWrap}>
  159. <div class={styles.itemWrapBox}>
  160. <div class={styles.item} onClick={() => handleOpenNotaion(item)}>
  161. <div class={styles.imgBox} id={"item_" + index}>
  162. <img
  163. src={getImage("icon_staff.png")}
  164. onLoad={() => {
  165. item.visualObj = productSvg(item.creationConfig, "item_" + index);
  166. }}
  167. />
  168. </div>
  169. <div class={styles.itemBottom}>
  170. <div class={styles.bottombox}>
  171. <div class={styles.bottomLeft}>
  172. <div class={styles.itemtitle}>
  173. <span>{item.name || `未命名乐谱-${index + 1}`}</span>
  174. </div>
  175. <div class={styles.time}>{item.updateTime}</div>
  176. </div>
  177. {item.uploadStatus !== "YES" && (
  178. <img
  179. class={styles.bottomBtn}
  180. src={getImage("icon_29_2.png")}
  181. onClick={(e: Event) => {
  182. e.stopPropagation();
  183. data.item = { ...item };
  184. nextTick(() => {
  185. data.uploadShow = true;
  186. });
  187. }}
  188. />
  189. )}
  190. <img
  191. class={styles.bottomBtn}
  192. src={getImage("icon_29_3.png")}
  193. onClick={(e: Event) => {
  194. e.stopPropagation();
  195. handleDelte(item);
  196. }}
  197. />
  198. </div>
  199. </div>
  200. {item.uploadStatus === "YES" && (
  201. <img class={styles.btn} src={getImage("icon_29_4.png")} />
  202. )}
  203. {item.uploadStatus === "UPDATE" && (
  204. <img class={styles.btn} src={getImage("icon_29_5.png")} />
  205. )}
  206. </div>
  207. </div>
  208. </div>
  209. ))}
  210. </div>
  211. {!data.finish && (
  212. <NSpace ref={loadingRef} justify="center" style={{ padding: "30px" }}>
  213. <NSpin size="large" />
  214. </NSpace>
  215. )}
  216. <TheCreate
  217. v-model:show={data.addShow}
  218. onCreate={() => {
  219. data.addShow = false;
  220. }}
  221. />
  222. <UploadToResources v-model:show={data.uploadShow} item={data.item} onSuccess={() => handleSuccess()} />
  223. </div>
  224. );
  225. },
  226. });