Переглянути джерело

课程中心详情接口对接

canghailong 7 місяців тому
батько
коміт
dbad0677f3

+ 2 - 3
package.json

@@ -64,15 +64,14 @@
 		"vue": "3.2.44",
 		"vue-codemirror": "^6.1.1",
 		"vue-cropper": "1.0.5",
-		"vue-demi": "0.13.11",
+		"vue-demi": "0.14.6",
 		"vue-i18n": "9.2.2",
 		"vue-router": "4.1.6",
 		"vue-simple-uploader": "^1.0.3",
 		"vue3-colorpicker": "2.0.4",
 		"vue3-print-nb": "0.1.4",
 		"vue3-tree-org": "4.2.2",
-		"vuedraggable-es": "4.1.1",
-		"xgplayer": "^3.0.22"
+		"vuedraggable-es": "4.1.1"
 	},
 	"devDependencies": {
 		"@antfu/eslint-config": "0.29.4",

+ 27 - 130
pnpm-lock.yaml

@@ -49,13 +49,13 @@ importers:
         version: 5.0.0(vue@3.2.44)
       '@vue-office/docx':
         specifier: ^1.2.0
-        version: 1.2.0(vue-demi@0.13.11(vue@3.2.44))(vue@3.2.44)
+        version: 1.2.0(vue-demi@0.14.6(vue@3.2.44))(vue@3.2.44)
       '@vue-office/excel':
         specifier: 1.2.0
-        version: 1.2.0(vue-demi@0.13.11(vue@3.2.44))(vue@3.2.44)
+        version: 1.2.0(vue-demi@0.14.6(vue@3.2.44))(vue@3.2.44)
       '@vue-office/pdf':
         specifier: 1.2.0
-        version: 1.2.0(vue-demi@0.13.11(vue@3.2.44))(vue@3.2.44)
+        version: 1.2.0(vue-demi@0.14.6(vue@3.2.44))(vue@3.2.44)
       '@vueup/vue-quill':
         specifier: ^1.2.0
         version: 1.2.0(vue@3.2.44)
@@ -159,8 +159,8 @@ importers:
         specifier: 1.0.5
         version: 1.0.5
       vue-demi:
-        specifier: 0.13.11
-        version: 0.13.11(vue@3.2.44)
+        specifier: 0.14.6
+        version: 0.14.6(vue@3.2.44)
       vue-i18n:
         specifier: 9.2.2
         version: 9.2.2(vue@3.2.44)
@@ -182,9 +182,6 @@ importers:
       vuedraggable-es:
         specifier: 4.1.1
         version: 4.1.1(vue@3.2.44)
-      xgplayer:
-        specifier: ^3.0.22
-        version: 3.0.22(core-js@3.43.0)
     devDependencies:
       '@antfu/eslint-config':
         specifier: 0.29.4
@@ -1448,13 +1445,6 @@ packages:
   d3-timer@1.0.10:
     resolution: {integrity: sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==}
 
-  d@1.0.2:
-    resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
-    engines: {node: '>=0.12'}
-
-  danmu.js@1.1.13:
-    resolution: {integrity: sha512-knFd0/cB2HA4FFWiA7eB2suc5vCvoHdqio33FyyCSfP7C+1A+zQcTvnvwfxaZhrxsGj4qaQI2I8XiTqedRaVmg==}
-
   data-view-buffer@1.0.2:
     resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
     engines: {node: '>= 0.4'}
@@ -1581,9 +1571,6 @@ packages:
     resolution: {integrity: sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==}
     hasBin: true
 
-  downloadjs@1.4.7:
-    resolution: {integrity: sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==}
-
   dunder-proto@1.0.1:
     resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
     engines: {node: '>= 0.4'}
@@ -1645,17 +1632,6 @@ packages:
     resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
     engines: {node: '>= 0.4'}
 
-  es5-ext@0.10.64:
-    resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
-    engines: {node: '>=0.10'}
-
-  es6-iterator@2.0.3:
-    resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
-
-  es6-symbol@3.1.4:
-    resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
-    engines: {node: '>=0.12'}
-
   esbuild@0.17.19:
     resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
     engines: {node: '>=12'}
@@ -1863,10 +1839,6 @@ packages:
     deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
     hasBin: true
 
-  esniff@2.0.1:
-    resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
-    engines: {node: '>=0.10'}
-
   espree@10.4.0:
     resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1901,24 +1873,15 @@ packages:
     resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
     engines: {node: '>=0.10.0'}
 
-  event-emitter@0.3.5:
-    resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
-
   event-source-polyfill@1.0.31:
     resolution: {integrity: sha512-4IJSItgS/41IxN5UVAVuAyczwZF7ZIEsM1XAoUzIHA6A+xzusEZUutdXz2Nr+MQPLxfTiCvqE79/C8HT8fKFvA==}
 
   eventemitter3@2.0.3:
     resolution: {integrity: sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==}
 
-  eventemitter3@4.0.7:
-    resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
-
   exsolve@1.0.5:
     resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==}
 
-  ext@1.7.0:
-    resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
-
   extend@3.0.2:
     resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
 
@@ -2592,9 +2555,6 @@ packages:
     engines: {node: '>= 4.4.x'}
     hasBin: true
 
-  next-tick@1.1.0:
-    resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
-
   node-releases@2.0.19:
     resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
 
@@ -3281,9 +3241,6 @@ packages:
     resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
     engines: {node: '>=8'}
 
-  type@2.7.3:
-    resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
-
   typed-array-buffer@1.0.3:
     resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
     engines: {node: '>= 0.4'}
@@ -3444,6 +3401,17 @@ packages:
       '@vue/composition-api':
         optional: true
 
+  vue-demi@0.14.6:
+    resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
+    engines: {node: '>=12'}
+    hasBin: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
   vue-eslint-parser@9.1.0:
     resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}
     engines: {node: ^14.17.0 || >=16.0.0}
@@ -3576,16 +3544,6 @@ packages:
   wrappy@1.0.2:
     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
 
-  xgplayer-subtitles@3.0.22:
-    resolution: {integrity: sha512-2XjamtZnWS/r4QjesOC34JmuGD3QPbgeqkI4t5Gq19dN1CWNBP7nJ8pbGLuAeHswKjGg8LFRpnsic7xjc/XSyA==}
-    peerDependencies:
-      core-js: '>=3.12.1'
-
-  xgplayer@3.0.22:
-    resolution: {integrity: sha512-uVKffa02NxWnWMVzgnrU0HGwZFH0ymPHsD3zGxtV6oPPplA6EBLyh9N5q3b++J7jRs2usvKR2+WslT+je1RuwA==}
-    peerDependencies:
-      core-js: '>=3.12.1'
-
   xml-name-validator@4.0.0:
     resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
     engines: {node: '>=12'}
@@ -4567,20 +4525,20 @@ snapshots:
       vite: 4.2.1(less@4.1.3)(terser@5.42.0)
       vue: 3.2.44
 
-  '@vue-office/docx@1.2.0(vue-demi@0.13.11(vue@3.2.44))(vue@3.2.44)':
+  '@vue-office/docx@1.2.0(vue-demi@0.14.6(vue@3.2.44))(vue@3.2.44)':
     dependencies:
       vue: 3.2.44
-      vue-demi: 0.13.11(vue@3.2.44)
+      vue-demi: 0.14.6(vue@3.2.44)
 
-  '@vue-office/excel@1.2.0(vue-demi@0.13.11(vue@3.2.44))(vue@3.2.44)':
+  '@vue-office/excel@1.2.0(vue-demi@0.14.6(vue@3.2.44))(vue@3.2.44)':
     dependencies:
       vue: 3.2.44
-      vue-demi: 0.13.11(vue@3.2.44)
+      vue-demi: 0.14.6(vue@3.2.44)
 
-  '@vue-office/pdf@1.2.0(vue-demi@0.13.11(vue@3.2.44))(vue@3.2.44)':
+  '@vue-office/pdf@1.2.0(vue-demi@0.14.6(vue@3.2.44))(vue@3.2.44)':
     dependencies:
       vue: 3.2.44
-      vue-demi: 0.13.11(vue@3.2.44)
+      vue-demi: 0.14.6(vue@3.2.44)
 
   '@vue/babel-helper-vue-transform-on@1.4.0': {}
 
@@ -5166,15 +5124,6 @@ snapshots:
 
   d3-timer@1.0.10: {}
 
-  d@1.0.2:
-    dependencies:
-      es5-ext: 0.10.64
-      type: 2.7.3
-
-  danmu.js@1.1.13:
-    dependencies:
-      event-emitter: 0.3.5
-
   data-view-buffer@1.0.2:
     dependencies:
       call-bound: 1.0.4
@@ -5294,8 +5243,6 @@ snapshots:
     dependencies:
       minimatch: 3.1.2
 
-  downloadjs@1.4.7: {}
-
   dunder-proto@1.0.1:
     dependencies:
       call-bind-apply-helpers: 1.0.2
@@ -5410,24 +5357,6 @@ snapshots:
       is-date-object: 1.1.0
       is-symbol: 1.1.1
 
-  es5-ext@0.10.64:
-    dependencies:
-      es6-iterator: 2.0.3
-      es6-symbol: 3.1.4
-      esniff: 2.0.1
-      next-tick: 1.1.0
-
-  es6-iterator@2.0.3:
-    dependencies:
-      d: 1.0.2
-      es5-ext: 0.10.64
-      es6-symbol: 3.1.4
-
-  es6-symbol@3.1.4:
-    dependencies:
-      d: 1.0.2
-      ext: 1.7.0
-
   esbuild@0.17.19:
     optionalDependencies:
       '@esbuild/android-arm': 0.17.19
@@ -5720,13 +5649,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  esniff@2.0.1:
-    dependencies:
-      d: 1.0.2
-      es5-ext: 0.10.64
-      event-emitter: 0.3.5
-      type: 2.7.3
-
   espree@10.4.0:
     dependencies:
       acorn: 8.15.0
@@ -5759,23 +5681,12 @@ snapshots:
 
   esutils@2.0.3: {}
 
-  event-emitter@0.3.5:
-    dependencies:
-      d: 1.0.2
-      es5-ext: 0.10.64
-
   event-source-polyfill@1.0.31: {}
 
   eventemitter3@2.0.3: {}
 
-  eventemitter3@4.0.7: {}
-
   exsolve@1.0.5: {}
 
-  ext@1.7.0:
-    dependencies:
-      type: 2.7.3
-
   extend@3.0.2: {}
 
   fast-deep-equal@3.1.3: {}
@@ -6446,8 +6357,6 @@ snapshots:
       sax: 1.4.1
     optional: true
 
-  next-tick@1.1.0: {}
-
   node-releases@2.0.19: {}
 
   normalize-package-data@2.5.0:
@@ -6607,7 +6516,7 @@ snapshots:
     dependencies:
       '@vue/devtools-api': 6.6.4
       vue: 3.2.44
-      vue-demi: 0.13.11(vue@3.2.44)
+      vue-demi: 0.14.6(vue@3.2.44)
     optionalDependencies:
       typescript: 4.9.5
 
@@ -7186,8 +7095,6 @@ snapshots:
 
   type-fest@0.8.1: {}
 
-  type@2.7.3: {}
-
   typed-array-buffer@1.0.3:
     dependencies:
       call-bound: 1.0.4
@@ -7389,6 +7296,10 @@ snapshots:
     dependencies:
       vue: 3.2.44
 
+  vue-demi@0.14.6(vue@3.2.44):
+    dependencies:
+      vue: 3.2.44
+
   vue-eslint-parser@9.1.0(eslint@8.26.0):
     dependencies:
       debug: 4.4.1
@@ -7552,20 +7463,6 @@ snapshots:
 
   wrappy@1.0.2: {}
 
-  xgplayer-subtitles@3.0.22(core-js@3.43.0):
-    dependencies:
-      core-js: 3.43.0
-      eventemitter3: 4.0.7
-
-  xgplayer@3.0.22(core-js@3.43.0):
-    dependencies:
-      core-js: 3.43.0
-      danmu.js: 1.1.13
-      delegate: 3.2.0
-      downloadjs: 1.4.7
-      eventemitter3: 4.0.7
-      xgplayer-subtitles: 3.0.22(core-js@3.43.0)
-
   xml-name-validator@4.0.0: {}
 
   xss@1.0.15:

+ 22 - 6
src/api/student/classCentre.js

@@ -2,6 +2,10 @@ import { baseRequest } from '@/utils/request'
 
 const request = (url, ...arg) => baseRequest(`/api/webapp/disk/${url}`, ...arg)
 export default {
+	//课程中心-课程-详情(增加点击次数)
+	addViewCount(data) {
+		return request('coursecentry/addViewCount', data)
+	},
 	//课程中心-课程-详情(学生端)
 	courseDetail(data) {
 		return request('coursecentry/detail', data, 'get')
@@ -15,19 +19,31 @@ export default {
 		return request('coursecentry/hourDetail', data, 'get')
 	},
 	//课程中心-笔记/笔记本-添加
-	notesAdd(data) {
-		return request('courseNotes/add', data)
+	notesSubmitForm(data, edit = false) {
+		return request(`courseNotes/${edit ? 'edit' : 'add'}`, data)
 	},
 	//课程中心-笔记-分页列表
 	notesList(data) {
 		return request('courseNotes/page', data, 'get')
 	},
-	//课程中心-笔记-修改
-	notesEdit(data) {
-		return request('courseNotes/edit', data)
-	},
 	//课程中心-笔记-删除
 	notesEdit(data) {
 		return request('courseNotes/delete', data)
 	},
+	//课程中心-问答-添加/编辑
+	askSubmitForm(data, edit = false) {
+		return request(`answer/${edit ? 'edit' : 'add'}`, data)
+	},
+	//课程中心-问答-删除
+	askDel(data) {
+		return request('answer/delete', data)
+	},
+	//课程中心-问答-列表
+	askList(data) {
+		return request('answer/page', data, 'get')
+	},
+	//课程中心-问答-点赞/取消赞
+	askLike(data, like = false) {
+		return request(`answer/${edit ? 'giveCancel' : 'give'}`, data, 'get')
+	},
 }

+ 4 - 1
src/utils/request.js

@@ -120,7 +120,10 @@ service.interceptors.response.use(
 				'saveDraft'
 			]
 			apiNameArray.forEach((apiName) => {
-				if (responseUrl.includes(apiName)) {
+				// if (responseUrl.includes(apiName)) {
+				// 	message.success(data.msg)
+				// }
+				if (responseUrl.substring(responseUrl.lastIndexOf('/') + 1) == apiName) {
 					message.success(data.msg)
 				}
 			})

+ 65 - 12
src/views/portal/components/Header.vue

@@ -110,16 +110,12 @@
 					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/resourceCenter">资源中心</a-menu-item>
 					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseCenter">课程中心</a-menu-item>
 					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/resourceManagement">课程详情</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/personalResources">我的考试</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">我的作业</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/resourceCenter">调查问卷</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">个人中心</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">论坛</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">站内信</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">课程公告</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/personalResources">学习足迹</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">登录</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">密码找回</a-menu-item>
+					<a-sub-menu key="myList">
+						<template #title>我的</template>
+						<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/personalResources">我的考试</a-menu-item>
+						<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">我的作业</a-menu-item>
+						<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/resourceCenter">调查问卷</a-menu-item>
+					</a-sub-menu>
 				</a-menu>
 			</div>
 
@@ -132,7 +128,22 @@
 				</div>
 				<div style="width: 20px"></div> -->
 				<div style="display: flex">
-					<UserOutlined :style="{ fontSize: '16px', color: '#00000083' }" />
+					
+					<a-dropdown>
+						<UserOutlined :style="{ fontSize: '16px', color: '#00000083' }" />
+						<template #overlay>
+							<a-menu>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">个人中心</a-menu-item>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">论坛</a-menu-item>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">站内信</a-menu-item>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">课程公告</a-menu-item>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/personalResources">学习足迹</a-menu-item>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">登录</a-menu-item>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/courseManagement">密码找回</a-menu-item>
+								<a-menu-item style="margin-left: 10px; margin-right: 10px" key="outLogin" @click="handleUser('outLogin')">退出登陆</a-menu-item>
+							</a-menu>
+						</template>
+					</a-dropdown>
 					<div style="width: 5px"></div>
 					<span style="font-size: 12px; color: #00000083">登录</span>
 				</div>
@@ -142,6 +153,8 @@
 				</div>
 				<!-- <a-button type="primary">登录</a-button>
 				<a-button>注册</a-button> -->
+
+				
 			</div>
 		</div>
 		<div class="line" style=""></div>
@@ -149,6 +162,11 @@
 </template>
 
 <script setup>
+	import { createVNode } from 'vue'
+	import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
+	import { Modal } from 'ant-design-vue'
+	import loginApi from '@/api/auth/loginApi'
+	import { message } from 'ant-design-vue'
 	import { ref } from 'vue'
 	import { useRouter, useRoute } from 'vue-router'
 	const router = useRouter()
@@ -169,7 +187,42 @@
 			}
 		}
 	)
-
+	const handleUser = (key) => {
+		
+		if (key === 'outLogin') {
+			Modal.confirm({
+				title: '提示',
+				content: '确认退出当前用户?',
+				icon: createVNode(ExclamationCircleOutlined),
+				maskClosable: false,
+				onOk() {
+					// 取得缓存中的token
+					const token = tool.data.get('TOKEN')
+					const param = {
+						token: token
+					}
+					message.loading('退出中...', 1)
+					loginApi
+						.logout(param)
+						.then(() => {
+							// 清理掉个人的一些信息
+							tool.data.remove('TOKEN')
+							tool.data.remove('USER_INFO')
+							tool.data.remove('MENU')
+							tool.data.remove('PERMISSIONS')
+							tool.cookie.remove('Token')
+							router.replace({ path: '/slogin' })
+						})
+						.catch(() => {
+							tool.data.clear()
+							router.replace({ path: '/slogin' })
+							location.reload()
+						})
+				},
+				onCancel() {}
+			})
+		}
+	}
 
 </script>
 

+ 135 - 0
src/views/student/classCentre/ask.vue

@@ -0,0 +1,135 @@
+<template>
+	<a-list
+		class="demo-loadmore-list"
+		:loading="initLoading"
+		item-layout="horizontal"
+		:data-source="listData"
+		:pagination="pagination"
+	>
+		<template #renderItem="{ item }">
+			<a-list-item>
+				<a-skeleton avatar :title="false" :loading="!!item.loading" active>
+					<div style="width: 100%">
+						<a-list-item-meta>
+							<template #title>{{ item.name }}</template>
+							<template #avatar v-if="item.avatar">
+								<a-avatar :src="item.avatar" />
+							</template>
+						</a-list-item-meta>
+						{{ item.remark }}
+						<div class="flc">
+							<div @click="editNote(item)">
+								<a-tooltip title="编辑" :getPopupContainer="(trigger) => trigger.parentElement">
+									<edit-outlined />
+								</a-tooltip>
+							</div>
+							<div class="ml-2" @click="delNote(item)">
+								<a-tooltip title="删除" :getPopupContainer="(trigger) => trigger.parentElement">
+									<delete-outlined />
+								</a-tooltip>
+							</div>
+							<div class="ml-2" @click="giveFun(item)">
+								<a-tooltip title="点赞" :getPopupContainer="(trigger) => trigger.parentElement">
+									<like-outlined :style="{ color: item.isLike == 1 ? '#fa6c8d' : '' }" />
+								</a-tooltip>
+							</div>
+						</div>
+					</div>
+				</a-skeleton>
+			</a-list-item>
+		</template>
+	</a-list>
+</template>
+
+<script setup>
+	import classCentre from '@/api/student/classCentre'
+	import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
+	import { createVNode } from 'vue'
+	import { Modal } from 'ant-design-vue'
+	const props = defineProps({
+		idsObj: {
+			type: [Array, Object],
+			required: () => {}
+		}
+	})
+	const count = 3
+	const emit = defineEmits({ edit: null })
+	const initLoading = ref(true)
+	const loading = ref(false)
+	const data = ref([])
+	const listData = ref([])
+	const itemNote = ref({})
+	onMounted(() => {
+		loading.value = false
+		initLoading.value = false
+		getList()
+	})
+	const pagination = ref({
+		onChange: (page) => {
+			pagination.value.current = page
+			getList()
+		},
+		pageSize: 10
+	})
+	const getList = () => {
+		classCentre
+			.askList(
+				{
+					size: pagination.value.pageSize,
+					...props.idsObj
+				},
+				itemNote.value.noteId
+			)
+			.then((data) => {
+				data.records = data.records.map((r) => {
+					return {
+						...r,
+						loading: false
+					}
+				})
+				listData.value = data.records
+				pagination.value.total = data.total
+				loading.value = false
+				initLoading.value = false
+			})
+	}
+
+	const editNote = (e) => {
+		itemNote.value = e.noteId
+		emit('edit', e)
+	}
+	const delNote = (e) => {
+		Modal.confirm({
+			title: '确定要删除笔记',
+			icon: createVNode(ExclamationCircleOutlined),
+			onOk() {
+				classCentre.askDel([{ noteId: e.noteId }]).then((data) => {
+					getList()
+				})
+			},
+			onCancel() {
+				console.log('Cancel')
+			}
+		})
+	}
+	const giveFun = (e) => {
+		classCentre.askLike({ giveId: e.id }, e.giveNumSelf).then(() => {
+			getList()
+		})
+	}
+	// 调用这个函数将子组件的一些数据和方法暴露出去
+	defineExpose({
+		getList
+	})
+</script>
+<style scoped lang="less">
+	.flc {
+		display: flex;
+		align-items: center;
+	}
+	.fcbc {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+	}
+</style>

+ 46 - 29
src/views/student/classCentre/form.vue

@@ -7,31 +7,35 @@
 		@close="onClose"
 		:mask="false"
 	>
-		<div v-if="itemObj.type == 1" style="height: 100%;">
-			<a-image width="100%" :src="sysConfig.FILE_URL + itemObj.url" v-if="fileType(itemObj.url)" />
-			<iframe
-				v-else
-				:src="`https://view.officeapps.live.com/op/view.aspx?src=${sysConfig.FILE_URL + itemObj.url}`"
-				frameborder="0"
-				width="100%"
-				height="100%"
-			></iframe>
+		<div v-if="itemObj.key == 2" style="height: 100%">
+			<vue-office-pdf :src="itemObj.url" style="width: 100%;height: 100%;"  />
 		</div>
-		<div v-if="itemObj.type == 2">
+		<div v-if="itemObj.type == 2 || itemObj.type == 4">
 			<a-card :bordered="false">
 				<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
 					<a-row :gutter="16">
 						<a-col :span="24">
-							<a-form-item name="postTitle">
-								<a-textarea v-model:value="formData.postTitle" placeholder="请输入" :rows="4" />
+							<a-form-item name="noteContent" v-if="itemObj.type == 2">
+								<a-textarea v-model:value="formData.noteContent" placeholder="请输入内容" :rows="4" />
 							</a-form-item>
+							<div v-if="itemObj.type == 4">
+								<a-form-item name="name" label="问题">
+									<a-input v-model:value="formData.name" placeholder="请输入问题" allow-clear />
+								</a-form-item>
+								<a-form-item name="remark" label="备注">
+									<a-textarea v-model:value="formData.remark" placeholder="请输入备注" :rows="4" />
+								</a-form-item>
+							</div>
 						</a-col>
 					</a-row>
 				</a-form>
 				<div class="frc">
 					<a-button type="primary" :loading="submitLoading" @click="onSubmit">保存</a-button>
 				</div>
-				<note></note>
+				<div class="noteBox">
+					<note v-if="itemObj.type == 2" :idsObj="idsObj" ref="noteRef" @edit="editForm"></note>
+					<askDiv v-if="itemObj.type == 4" :idsObj="idsObj" ref="noteRef" @edit="editForm"></askDiv>
+				</div>
 			</a-card>
 		</div>
 	</xn-form-container>
@@ -40,15 +44,21 @@
 <script setup>
 	import classCentre from '@/api/student/classCentre'
 	import { required } from '@/utils/formRules'
-	import sysConfig from '@/config/index'
 	import note from './note.vue'
+	import askDiv from './ask.vue'
+	import VueOfficePdf from '@vue-office/pdf';
 	const props = defineProps({
 		rightItem: {
 			type: [Array, Object],
 			required: () => {}
+		},
+		idsObj: {
+			type: [Array, Object],
+			required: () => {}
 		}
 	})
 	const itemObj = computed(() => props.rightItem)
+	const noteRef = ref()
 	const submitLoading = ref(false)
 	// 表单数据,也就是默认给一些数据
 	const formData = ref({})
@@ -58,20 +68,21 @@
 	// 默认是关闭状态
 	const visible = ref(false)
 	const emit = defineEmits({ successful: null })
-	// 模块ID
-	const moduleId = ref('')
 	// 打开抽屉
-	const onOpen = (record, module) => {
-		moduleId.value = module
+	const onOpen = (edit) => {
 		visible.value = true
+		if(edit){
+			formData.value = edit
+		}
 	}
 	// 关闭抽屉
 	const onClose = () => {
+		formRef.value?.resetFields()
 		visible.value = false
 	}
 	// 默认要校验的
 	const formRules = {
-		postTitle: [required('请输入标题')]
+		noteContent: [required('请输入内容')]
 	}
 	// 提交数据
 	const onSubmit = () => {
@@ -79,23 +90,25 @@
 			.validate()
 			.then(() => {
 				submitLoading.value = true
-				forumApi.submitForm(formData.value).then(() => {
-					onClose()
+				classCentre[itemObj.value.type == 2 ? 'notesSubmitForm' : 'askSubmitForm'](
+					{
+						...props.idsObj,
+						...formData.value
+					},
+					formData.value.noteId
+				).then(() => {
 					emit('successful')
+					formRef.value.resetFields()
+					noteRef.value.getList()
 				})
 			})
 			.finally(() => {
 				submitLoading.value = false
 			})
 	}
-	const fileType = (str) => {
-		let index = str.lastIndexOf('.')
-		let ext = str.substr(index)
-		if(ext == '.xls' || ext == '.doc'){
-			return false
-		}else{
-			return true
-		}
+	const editForm = (e) => {
+		onOpen(e)
+		formData.value = e
 	}
 	// 调用这个函数将子组件的一些数据和方法暴露出去
 	defineExpose({
@@ -108,4 +121,8 @@
 		justify-content: flex-end;
 		align-items: center;
 	}
+	.noteBox {
+		height: 750px;
+		overflow-y: auto;
+	}
 </style>

+ 79 - 37
src/views/student/classCentre/index.vue

@@ -49,12 +49,36 @@
 					</div>
 				</div>
 			</a-layout-header>
-			<a-layout-content>
+			<a-layout-content style="overflow-y: auto">
 				<a-card :bordered="false">
-					<div id="player" style="height: 900px; width: 100%"></div>
-					<rightMenu :dataList="classTimeData" @callback="editVideo"></rightMenu>
+					<video
+						style="height: 900px; width: 100%; background-color: #000"
+						ref="videoRef"
+						controls
+						Controlslist="nodownload noplaybackrate"
+					>
+						<source :src="videoUrl" type="video/mp4" />
+						<source :src="videoUrl" type="video/ogg" />
+						您的浏览器不支持 HTML5 video 标签。
+					</video>
+					<rightMenu :idsObj="idsObj" :dataList="classTimeData" ref="rightNenuRef"></rightMenu>
+				</a-card>
+				<a-card :bordered="false" class="mt-2">
+					<a-tabs v-model:activeKey="tabsActiveKey">
+						<a-tab-pane key="1" tab="讲义">
+							<div style="height: 500px">
+								<vue-office-pdf :src="itemObj.url" style="width: 100%; height: 100%" />
+							</div>
+						</a-tab-pane>
+						<a-tab-pane key="2" tab="字幕">字幕</a-tab-pane>
+						<a-tab-pane key="3" tab="笔记">
+							<note :idsObj="idsObj" ref="noteRef" @edit="noteEdit"></note>
+						</a-tab-pane>
+						<a-tab-pane key="4" tab="问答">
+							<askDiv :idsObj="idsObj" ref="askDivRef" @edit="askEdit"></askDiv>
+						</a-tab-pane>
+					</a-tabs>
 				</a-card>
-				<a-card :bordered="false" class="mt-2"></a-card>
 			</a-layout-content>
 		</a-layout>
 	</a-layout>
@@ -65,58 +89,76 @@
 	import rightMenu from './rightMenu.vue'
 	import { useRoute, useRouter } from 'vue-router'
 	import sysConfig from '@/config/index'
-	import XGPlayer from 'xgplayer'
-	import 'xgplayer/dist/index.min.css'
-	import TextTrack from 'xgplayer/es/plugins/track'
+	import note from './note.vue'
+	import askDiv from './ask.vue'
+	import VueOfficePdf from '@vue-office/pdf'
 
 	const route = useRoute()
 	const router = useRouter()
 	const classDetail = ref({})
 	const classTimeList = ref([])
-	const classTimeData = ref({})
+	const classTimeData = ref([])
 	const openKeys = ref(['1'])
 	const selectedKeys = ref([])
 	const collapsed = ref(false)
-
+	const videoRef = ref()
+	const idsObj = computed(() => {
+		let item = findNodeByKey(classTimeList.value, selectedKeys.value[0])
+		return {
+			courseId: route.query.id,
+			chapterId: item?.chapterId,
+			hourId: selectedKeys.value[0]
+		}
+	})
+	function findNodeByKey(list, id) {
+		for (const item of list) {
+			if (item.id === id) {
+				return item
+			}
+			if (item.classHours && Array.isArray(item.classHours)) {
+				const found = findNodeByKey(item.classHours, id)
+				if (found) return found
+			}
+		}
+		return null
+	}
 	const getClassData = () => {
+		classCentre.addViewCount({ courseId: route.query.id })
 		classCentre.courseDetail({ courseId: route.query.id }).then((data) => {
 			classDetail.value = data
 			classCentre.coursechapterList({ courseId: data.courseId }).then((data) => {
 				classTimeList.value = data
-				selectedKeys.value = [data[0].classHours[0].id]
-				classCentre.courseTimeDetail({ id: selectedKeys.value[0] }).then((data) => {
-					classTimeData.value = data.courseRelates
-					videoStart();
-				})
+				selectedKeys.value = [data[0]?.classHours[0].id]
+				if (selectedKeys.value[0]) {
+					classCentre.courseTimeDetail({ id: selectedKeys.value[0] }).then((data) => {
+						classTimeData.value = data.courseRelates.map((r) => {
+							return {
+								...r,
+								url: sysConfig.FILE_URL + r.url
+							}
+						})
+						videoRef.value.src = classTimeData.value.filter((r) => r.funcType == 1)[0]?.url
+					})
+				}
 			})
 		})
 	}
 	getClassData()
 
-	const player = ref()
-
-	const videoStart = () => {
-		player.value = new XGPlayer({
-			lang: 'zh',
-			id: 'player',
-			url: sysConfig.FILE_URL + classTimeData.value.filter((r) => r.funcType == 1)[0].url, // 视频文件路径
-			width: '100%',
-			height: 900,
-			plugins: [TextTrack],
-			texttrack: {
-				list: [
-					{
-						id: 'vtt1',
-						url: sysConfig.FILE_URL + classTimeData.value.filter((r) => r.funcType == 3)[0].url,
-						language: 'zh',
-						text: '中文字幕'
-					}
-				]
-			}
-		})
+	const tabsActiveKey = ref('1')
+	const noteRef = ref()
+	const askDivRef = ref()
+	const itemObj = computed(() => {
+		let item = classTimeData.value.length > 0 ? classTimeData.value.filter((r) => r.funcType == 2)[0] : { url: '' }
+		return item
+	})
+	const videoUrl = ''
+	const rightNenuRef = ref()
+	const noteEdit = (e) => {
+		rightNenuRef.value.selectBtn({ key: 6, type: 2 }, e)
 	}
-	const editVideo = (e) => {
-		// player.value.src = e.url
+	const askEdit = (e) => {
+		rightNenuRef.value.selectBtn({ key: 7, type: 4 }, e)
 	}
 </script>
 <style scoped lang="less">

+ 78 - 54
src/views/student/classCentre/note.vue

@@ -1,30 +1,32 @@
 <template>
-	<a-list class="demo-loadmore-list" :loading="initLoading" item-layout="horizontal" :data-source="listData">
-		<template #loadMore>
-			<div
-				v-if="!initLoading && !loading"
-				:style="{ textAlign: 'center', marginTop: '12px', height: '32px', lineHeight: '32px' }"
-			>
-				<a-button @click="onLoadMore">loading more</a-button>
-			</div>
-		</template>
+	<a-list
+		class="demo-loadmore-list"
+		:loading="initLoading"
+		item-layout="horizontal"
+		:data-source="listData"
+		:pagination="pagination"
+	>
 		<template #renderItem="{ item }">
 			<a-list-item>
 				<a-skeleton avatar :title="false" :loading="!!item.loading" active>
-					<div>
+					<div style="width: 100%">
 						<a-list-item-meta>
-							<template #title>
-								<a href="https://www.antdv.com/">{{ item.title }}</a>
-							</template>
-							<template #avatar>
+							<template #title>{{ item.courseName }}</template>
+							<template #avatar v-if="item.avatar">
 								<a-avatar :src="item.avatar" />
 							</template>
 						</a-list-item-meta>
-						{{ item.content }}
+						{{ item.noteContent }}
 						<div class="flc">
-							<div v-for="{ icon, text } in actions" :key="icon">
-								<component :is="icon" style="margin-right: 8px" />
-								{{ text }}
+							<div @click="editNote(item)">
+								<a-tooltip title="编辑" :getPopupContainer="(trigger) => trigger.parentElement">
+									<edit-outlined />
+								</a-tooltip>
+							</div>
+							<div class="ml-2" @click="delNote(item)">
+								<a-tooltip title="删除" :getPopupContainer="(trigger) => trigger.parentElement">
+									<delete-outlined />
+								</a-tooltip>
 							</div>
 						</div>
 					</div>
@@ -36,58 +38,80 @@
 
 <script setup>
 	import classCentre from '@/api/student/classCentre'
-	import { StarOutlined, LikeOutlined, MessageOutlined } from '@ant-design/icons-vue'
+	import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
+	import { createVNode } from 'vue'
+	import { Modal } from 'ant-design-vue'
 	const props = defineProps({
-		noteData: {
+		idsObj: {
 			type: [Array, Object],
-			default: () => {}
+			required: () => {}
 		}
 	})
 	const count = 3
-
+	const emit = defineEmits({ edit: null })
 	const initLoading = ref(true)
 	const loading = ref(false)
 	const data = ref([])
 	const listData = ref([])
-	const actions = [
-		{ icon: StarOutlined, text: '156' },
-		{ icon: LikeOutlined, text: '156' },
-		{ icon: MessageOutlined, text: '2' }
-	]
+	const itemNote = ref({})
 	onMounted(() => {
-		for (let i = 0; i < 23; i++) {
-			listData.value.push({
-				href: 'https://www.antdv.com/',
-				title: `ant design vue part ${i}`,
-				avatar: 'https://joeschmoe.io/api/v1/random',
-				loading: false,
-				description: 'Ant Design, a design language for background applications, is refined by Ant UED Team.',
-				content:
-					'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.'
-			})
-		}
 		loading.value = false
 		initLoading.value = false
+		getList()
 	})
-
-	const onLoadMore = () => {
-		loading.value = true
-		for (let i = 0; i < 23; i++) {
-			listData.value.push({
-				href: 'https://www.antdv.com/',
-				title: `ant design vue part ${i}`,
-				avatar: 'https://joeschmoe.io/api/v1/random',
-				loading: false,
-				description: 'Ant Design, a design language for background applications, is refined by Ant UED Team.',
-				content:
-					'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.'
+	const pagination = ref({
+		current: 1,
+		onChange: (page) => {
+			pagination.value.current = page
+			getList()
+		},
+		pageSize: 10
+	})
+	const getList = () => {
+		classCentre
+			.notesList(
+				{
+					current: pagination.value.current,
+					size: pagination.value.pageSize,
+					...props.idsObj
+				},
+				itemNote.value.noteId
+			)
+			.then((data) => {
+				data.records = data.records.map((r) => {
+					return {
+						...r,
+						loading: false
+					}
+				})
+				listData.value = data.records
+				pagination.value.total = data.total
+				loading.value = false
+				initLoading.value = false
 			})
-		}
-		loading.value = false
-		initLoading.value = false
+	}
+	const editNote = (e) => {
+		itemNote.value = e.noteId
+		emit('edit', e)
+	}
+	const delNote = (e) => {
+		Modal.confirm({
+			title: '确定要删除笔记',
+			icon: createVNode(ExclamationCircleOutlined),
+			onOk() {
+				classCentre.notesEdit([{ noteId: e.noteId }]).then((data) => {
+					getList()
+				})
+			},
+			onCancel() {
+				console.log('Cancel')
+			}
+		})
 	}
 	// 调用这个函数将子组件的一些数据和方法暴露出去
-	defineExpose({})
+	defineExpose({
+		getList
+	})
 </script>
 <style scoped lang="less">
 	.flc {

+ 35 - 26
src/views/student/classCentre/rightMenu.vue

@@ -8,16 +8,28 @@
 				<div class="fcc">{{ item.title }}</div>
 			</a-menu-item>
 		</a-menu>
-		<rightContent ref="formRef" :rightItem="rightItem"></rightContent>
+		<rightContent ref="formRef" :idsObj="props.idsObj" :rightItem="rightItem"></rightContent>
 	</div>
 </template>
 
 <script setup name="rightMenu">
 	import classCentre from '@/api/student/classCentre'
 	import rightContent from './form.vue'
-	import sysConfig from '@/config/index'
 	import axios from 'axios'
+	import { useRoute, useRouter } from 'vue-router'
+	const route = useRoute()
+	const router = useRouter()
 	const emit = defineEmits({ callback: null })
+	const props = defineProps({
+		dataList: {
+			type: [Array, Object],
+			default: () => []
+		},
+		idsObj: {
+			type: [Array, Object],
+			required: () => {}
+		}
+	})
 	import {
 		PlaySquareOutlined,
 		FileTextOutlined,
@@ -31,12 +43,12 @@
 	const rightItem = ref({})
 	const selectedKeys = ref([''])
 	const btnList = ref([
-		{
-			title: '视频',
-			key: '1',
-			icon: PlaySquareOutlined,
-			type: 0
-		},
+		// {
+		// 	title: '视频',
+		// 	key: '1',
+		// 	icon: PlaySquareOutlined,
+		// 	type: 1
+		// },
 		{
 			title: '讲义',
 			key: '2',
@@ -53,13 +65,15 @@
 			title: '作业',
 			key: '4',
 			icon: SnippetsOutlined,
-			type: 3
+			type: 3,
+			routerUrl: ''
 		},
 		{
 			title: '测验',
 			key: '5',
 			icon: CopyOutlined,
-			type: 3
+			type: 3,
+			routerUrl: ''
 		},
 		{
 			title: '笔记',
@@ -71,31 +85,23 @@
 			title: '问答',
 			key: '7',
 			icon: QuestionCircleOutlined,
-			type: 3
+			type: 4
 		}
 	])
-	const selectBtn = (event) => {
-		event.url = sysConfig.FILE_URL + event.url
+	const selectBtn = (event, edit) => {
 		if (event.key == 3) {
 			// GetSrtInfo(event.url)
 		}
 		if (event.type == 3) {
-			
+			router.push({
+				path: event.routerUrl,
+				query: {}
+			})
 		} else {
-			if (event.key == 1) {
-				emit('callback', event)
-			} else {
-				rightItem.value = event
-				formRef.value.onOpen()
-			}
+			rightItem.value = event
+			formRef.value.onOpen(edit ? edit : '')
 		}
 	}
-	const props = defineProps({
-		dataList: {
-			type: [Array, Object],
-			default: () => []
-		}
-	})
 	const listBtn = computed(() => {
 		return btnList.value.map((r) => {
 			const match = props.dataList.length && props.dataList.find((e) => r.key == e.funcType)
@@ -140,6 +146,9 @@
 		}
 		return s
 	}
+	defineExpose({
+		selectBtn
+	})
 </script>
 <style scoped lang="less">
 	.rightBtn {