js-fn.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. import store from '@/store'
  2. import {
  3. app
  4. } from '@/boot-app.js'
  5. import _tools from "./public.js"
  6. import _editorTools from "./editorTools.js"
  7. /*
  8. * 根据某个属性进行分组
  9. */
  10. function groupBy(array, key) {
  11. const groups = {}
  12. array.forEach(function (item) {
  13. const group = JSON.stringify(item[key])
  14. groups[group] = groups[group] || []
  15. groups[group].push(item)
  16. })
  17. return Object.keys(groups).map(function (group) {
  18. return groups[group]
  19. })
  20. }
  21. /*
  22. * 判断两个对象是否相等
  23. */
  24. function isObjEqual(o1, o2) {
  25. var props1 = Object.keys(o1)
  26. var props2 = Object.keys(o2)
  27. if (props1.length != props2.length) {
  28. return false
  29. }
  30. for (var i = 0, max = props1.length; i < max; i++) {
  31. var propName = props1[i]
  32. if (o1[propName] !== o2[propName]) {
  33. return false
  34. }
  35. }
  36. return true
  37. }
  38. /*
  39. * 获取对象在对象数组的index
  40. */
  41. function getIndex(_arr, _obj) {
  42. var len = _arr.length
  43. for (let i = 0; i < len; i++) {
  44. if (isObjEqual(_arr[i], _obj)) {
  45. return parseInt(i)
  46. }
  47. }
  48. return -1
  49. }
  50. /*
  51. * 产生某个范围的随机数
  52. */
  53. function getBtwRandom(start, end) {
  54. return Math.floor(Math.random() * (end - start)) + start
  55. }
  56. /*
  57. *根据图片链接压缩图片得到缩略图
  58. * @params url: 文件url
  59. */
  60. function compressImgByUrl(url, name, quality) {
  61. return new Promise((r, j) => {
  62. try {
  63. let img = new Image()
  64. img.setAttribute('crossOrigin', 'Anonymous')
  65. img.src = url
  66. img.onload = function () {
  67. let canvas = document.createElement('canvas')
  68. canvas.width = 200
  69. canvas.height = 200 * img.height / img.width
  70. let ctx = canvas.getContext('2d')
  71. ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height)
  72. let newImgData = canvas.toDataURL('image/png', quality)
  73. //let resultFile = dataURLtoFile(newImgData, name)
  74. //r(resultFile)
  75. r(newImgData)
  76. }
  77. img.onerror = function (e) {
  78. console.error('图片Error', e)
  79. j('Format Error')
  80. }
  81. }
  82. catch (err) {
  83. j(err)
  84. }
  85. })
  86. }
  87. /*
  88. *根据视频链接创建封面图
  89. * @params url: 文件url
  90. */
  91. function createVideoPoster(url, name, quality) {
  92. return new Promise(
  93. (r, j) => {
  94. try {
  95. let video = document.createElement('video')
  96. video.setAttribute('crossOrigin', 'Anonymous')
  97. video.setAttribute('width', '300')
  98. video.setAttribute('controls', 'controls')
  99. video.setAttribute('crossOrigin', 'Anonymous')
  100. video.setAttribute('src', url)
  101. video.currentTime = 1
  102. console.log(url)
  103. video.addEventListener('loadeddata', () => {
  104. let canvas = document.createElement('canvas')
  105. canvas.width = 300
  106. canvas.height = 300 * video.videoHeight / video.videoWidth
  107. let ctx = canvas.getContext('2d')
  108. ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, canvas.width, canvas.height)
  109. let newVideoData = canvas.toDataURL('image/png', quality)
  110. //let resultFile = dataURLtoFile(newVideoData, name)
  111. r(newVideoData)
  112. })
  113. video.addEventListener('error', (e) => {
  114. console.error(e)
  115. j('Format Error')
  116. })
  117. }
  118. catch (err) {
  119. j(err)
  120. }
  121. }
  122. )
  123. }
  124. /*
  125. *dataUrl转文件
  126. */
  127. function dataURLtoFile(dataurl, filename) {
  128. console.log(...arguments);
  129. let arr = dataurl.split(',')
  130. let mime = arr[0].match(/:(.*?);/)[1]
  131. let bstr = atob(arr[1])
  132. let n = bstr.length
  133. let u8arr = new Uint8Array(n)
  134. while (n--) {
  135. u8arr[n] = bstr.charCodeAt(n)
  136. }
  137. return new File([u8arr], filename, { type: mime })
  138. }
  139. /*
  140. *文件转dataUrl
  141. */
  142. function fileToURL(file) {
  143. return new Promise((r, j) => {
  144. try {
  145. var reader = new FileReader()
  146. reader.onloadend = function (e) {
  147. r(e.target.result)
  148. }
  149. reader.readAsDataURL(file)
  150. } catch (e) {
  151. j(e)
  152. }
  153. })
  154. }
  155. /*
  156. * 函数防抖
  157. */
  158. function debounce(func, delay) {
  159. return function () {
  160. window.clearTimeout(window.timeout)
  161. window.timeout = setTimeout(() => {
  162. clearTimeout(window.timeout)
  163. func.apply(this, arguments)
  164. }, delay)
  165. }
  166. }
  167. /*
  168. * 函数节流
  169. */
  170. function throttle(func, delay) {
  171. let run = true
  172. return function () {
  173. if (!run) {
  174. return // 如果开关关闭了,那就直接不执行下边的代码
  175. }
  176. run = false // 持续触发的话,run一直是false,就会停在上边的判断那里
  177. setTimeout(() => {
  178. func.apply(this, arguments)
  179. run = true // 定时器到时间之后,会把开关打开,我们的函数就会被执行
  180. }, delay)
  181. }
  182. }
  183. //转换bytes
  184. function formatBytes(bytes) {
  185. bytes = bytes || 0
  186. return bytes / 1024 < 1024 ? (bytes / 1024).toFixed(1) + 'KB' : bytes / 1024 / 1024 < 1024 ? (bytes / 1024 / 1024).toFixed(1) + 'M' : (bytes / 1024 / 1024 / 1024).toFixed(1) + 'G'
  187. }
  188. //生成uuid
  189. function uuid() {
  190. function S4() {
  191. return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
  192. }
  193. return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
  194. }
  195. // 获取某个字符在字符串中第num次出现的index
  196. function findChartIndex(str, cha, num) {
  197. var x = str.indexOf(cha);
  198. for (var i = 0; i < num; i++) {
  199. x = str.indexOf(cha, x + 1);
  200. }
  201. return x;
  202. }
  203. function timeFormat(timestamp) {
  204. timestamp = timestamp < 10000000000 ? timestamp * 1000 : timestamp
  205. let date = new Date(timestamp)
  206. let Y = date.getFullYear()
  207. let M = date.getMonth()
  208. let D = date.getDate()
  209. let H = date.getHours()
  210. let MIN = date.getMinutes()
  211. return `${Y}/${M < 9 ? '0' + (M + 1) : M + 1}/${D} ${H < 10 ? '0' + H : H}:${MIN < 10 ? '00' : MIN}`
  212. }
  213. function dateFormat(timestamp) {
  214. if (timestamp <= 0) return ''
  215. timestamp = timestamp < 10000000000 ? timestamp * 1000 : timestamp
  216. let date = new Date(timestamp)
  217. let Y = date.getFullYear()
  218. let M = date.getMonth()
  219. let D = date.getDate()
  220. return `${Y}/${M < 9 ? '0' + (M + 1) : M + 1}/${D}`
  221. }
  222. /**
  223. * 根据学年获取年级名称
  224. * @param year 学年
  225. */
  226. function getGradeNameByYear(year) {
  227. if (year && year > 0) {
  228. let curPeriod = store.state.user?.curPeriod
  229. if (curPeriod) {
  230. let date = new Date()
  231. let curYear = date.getFullYear()
  232. let month = date.getMonth() + 1
  233. let start = curPeriod.semesters.find(item => {
  234. return item.start == 1
  235. })
  236. // 根据入学月份确定当前年级和学级的关系
  237. if (start && month < start.month) {
  238. curYear--
  239. }
  240. let res = curPeriod.grades[curYear - year]
  241. if (curYear - year >= curPeriod.grades.length) {
  242. return app.$t('schoolBaseInfo.graduated')
  243. }
  244. return res ? res : app.$t('schoolBaseInfo.untimed')
  245. } else {
  246. return '--'
  247. }
  248. } else {
  249. return '--'
  250. }
  251. }
  252. /**
  253. * 根据学年获取年级信息
  254. * @param year 学年
  255. * @param periodId 学段id(非必填)
  256. */
  257. function getGradeInfoByYear(year, periodId) {
  258. if (year && year > 0) {
  259. let curPeriod
  260. if (periodId) {
  261. curPeriod = store.state.user?.schoolProfile?.school_base?.period?.find(item => item.id == periodId)
  262. } else {
  263. curPeriod = store.state.user?.curPeriod
  264. }
  265. if (curPeriod) {
  266. let date = new Date()
  267. let curYear = date.getFullYear()
  268. let month = date.getMonth() + 1
  269. let start = curPeriod.semesters.find(item => {
  270. return item.start == 1
  271. })
  272. // 根据入学月份确定当前年级和学级的关系
  273. if (start && month < start.month) {
  274. curYear--
  275. }
  276. let res = curPeriod.grades[curYear - year]
  277. let gradeName
  278. if (curYear - year >= curPeriod.grades.length) {
  279. gradeName = app.$t('schoolBaseInfo.graduated')
  280. }
  281. gradeName = res ? res : app.$t('schoolBaseInfo.untimed')
  282. return {
  283. id: curYear - year,
  284. name: gradeName
  285. }
  286. } else {
  287. return undefined
  288. }
  289. } else {
  290. return undefined
  291. }
  292. }
  293. /**
  294. * 根据班级学年年级名称
  295. * @param data 学校基础数据 schoolProfile.school_base
  296. * @param curPd 当前学段id
  297. * @param grade 年级index
  298. */
  299. function getYearByGrade(grade) {
  300. let date = new Date()
  301. let curYear = date.getFullYear()
  302. let month = date.getMonth() + 1
  303. grade = parseInt(grade)
  304. let curPeriod = store.state.user?.curPeriod
  305. if (grade > -1 && curPeriod) {
  306. let start = curPeriod.semesters.find(item => {
  307. return item.start == 1
  308. })
  309. // 根据入学月份确定当前年级和学级的关系
  310. if (start && month < start.month) {
  311. curYear--
  312. }
  313. return curYear - grade
  314. } else {
  315. return curYear
  316. }
  317. }
  318. /**
  319. * 根据教师绑定的学科id获取学科和学段名称
  320. * @param ids 学科ids
  321. * @returns
  322. * [
  323. * {
  324. * periodId:'ddd'
  325. * periodName:'小学',
  326. * subjectId:'wwww',
  327. * subjectName:'语文'
  328. * }
  329. * ]
  330. */
  331. function getTeacherSubjects(ids) {
  332. let schoolPeriod = store.state.user?.schoolProfile?.school_base?.period
  333. if (ids && ids.length && schoolPeriod) {
  334. let data = []
  335. ids.forEach(sid => {
  336. for (let i = 0; i < schoolPeriod.length; i++) {
  337. let subjectInfo = schoolPeriod[i].subjects.find(subject => subject.id === sid)
  338. if (subjectInfo) {
  339. data.push({
  340. periodId: schoolPeriod[i].id,
  341. periodName: schoolPeriod[i].name,
  342. subjectId: subjectInfo.id,
  343. subjectName: subjectInfo.name
  344. })
  345. break
  346. }
  347. }
  348. })
  349. return data
  350. } else {
  351. return []
  352. }
  353. }
  354. //根据域名判断菜单是否显示
  355. function checkJinNiu() {
  356. let host = window.location.host
  357. return host == 'jinniu.teammodel.cn'
  358. }
  359. //根据域名判断菜单是否显示
  360. function checkTrain() {
  361. let host = window.location.host
  362. return host == 'scyx.teammodel.cn'
  363. }
  364. /**
  365. * 统一处理学生作答数据
  366. * @param {string} fullUrl ans.json完成路径含授权
  367. * @param {string} richPrefix 富文本前缀(到stuId)
  368. * @param {string} sas 授权(不需要“?”)
  369. */
  370. function handleStudentAnswer(fullUrl, richPrefix, sas) {
  371. return new Promise(async (r, j) => {
  372. try {
  373. let ansStr = await _tools.getFile(fullUrl)
  374. if (ansStr) {
  375. let ans = JSON.parse(ansStr)
  376. ans.forEach((item, index) => {
  377. // 数据异常
  378. if (!item) {
  379. ans[index] = [app.$t('learnActivity.score.ansErr')]
  380. }
  381. // 未作答
  382. else if (!item.length) {
  383. ans[index] = [app.$t('learnActivity.score.noStuAns')]
  384. }
  385. // 处理富文本中多媒体
  386. else {
  387. item.forEach((as, ai) => {
  388. item[ai] = _editorTools.getMideaFullPath(as, richPrefix + '/', '?' + sas)
  389. })
  390. ans[index] = item
  391. }
  392. })
  393. r(ans)
  394. } else {
  395. r([])
  396. }
  397. } catch (e) {
  398. r([])
  399. }
  400. })
  401. }
  402. function getBlobInfo(scope) {
  403. console.log(store)
  404. let blobProfile
  405. if (scope == 'school') {
  406. blobProfile = store.state.user.schoolProfile
  407. } else if (scope == 'private') {
  408. blobProfile = store.state.user.userProfile
  409. }
  410. if (blobProfile) {
  411. let blobUrl = blobProfile.blob_uri
  412. let blobName = blobUrl.substring(blobUrl.lastIndexOf('/') + 1)
  413. let blobHost = blobUrl.substring(0, blobUrl.lastIndexOf('/'))
  414. let blobSas = blobProfile.blob_sas
  415. return {
  416. blobUrl, blobName, blobHost, blobSas
  417. }
  418. } else {
  419. return {}
  420. }
  421. }
  422. function setLocalLang() {
  423. // 自动根据浏览器系统语言设置语言(优先判断本地设置的语言,如果有则使用本地设置的语言,如果没有则使用浏览器系统语言)
  424. const curLang = localStorage.getItem('cloudSetting') ? JSON.parse(localStorage.getItem('cloudSetting')).curLang : null
  425. const navLang = curLang || navigator.language.toLowerCase()
  426. const localLang = (navLang === 'zh' || navLang === 'zh-tw' || navLang === 'zh-cn' || navLang === 'zh-hk') ? navLang : false
  427. let lang = localLang || 'en-us'
  428. localStorage.setItem('local', lang)
  429. return lang
  430. }
  431. export default {
  432. groupBy,
  433. isObjEqual,
  434. getIndex,
  435. getBtwRandom,
  436. compressImgByUrl,
  437. createVideoPoster,
  438. dataURLtoFile,
  439. fileToURL,
  440. debounce,
  441. throttle,
  442. formatBytes,
  443. uuid,
  444. findChartIndex,
  445. getGradeNameByYear,
  446. getGradeInfoByYear,
  447. getYearByGrade,
  448. dateFormat,
  449. timeFormat,
  450. getTeacherSubjects,
  451. checkJinNiu,
  452. checkTrain,
  453. handleStudentAnswer,
  454. getBlobInfo,
  455. setLocalLang
  456. }