js-fn.js 15 KB

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