ソースを参照

Merge branch 'dev' of http://192.168.1.245:11111/shanming/onlineEducation-front into dev

zhangsq 7 ヶ月 前
コミット
b382387985
35 ファイル変更1604 行追加874 行削除
  1. 1 0
      package.json
  2. 47 0
      pnpm-lock.yaml
  3. 0 3
      public/tinymce/plugins/kityformula-editor/kityFormula.html
  4. 66 68
      public/tinymce/plugins/kityformula-editor/plugin.js
  5. 66 69
      public/tinymce/plugins/kityformula-editor/plugin.min.js
  6. 14 2
      src/api/forum/forumApi.js
  7. 2 2
      src/api/forum/forumPostInfoApi.js
  8. 1 1
      src/api/forum/forumPostTypeApi.js
  9. 1 1
      src/api/forum/forumReportInfoApi.js
  10. 1 1
      src/api/forum/forumSensitivityApi.js
  11. 1 1
      src/api/forum/forumSensitivityRecordApi.js
  12. 1 0
      src/components/Comment/index.vue
  13. 4 3
      src/components/Editor/index.vue
  14. 42 40
      src/components/UpLoadImg/index.vue
  15. 5 5
      src/store/exam.js
  16. 7 7
      src/views/exm/exampaper/index.vue
  17. 1 1
      src/views/exm/question/edit/gap-filling.vue
  18. 1 1
      src/views/exm/question/edit/multiple-choice.vue
  19. 1 1
      src/views/exm/question/edit/short-answer.vue
  20. 1 1
      src/views/exm/question/edit/single-choice.vue
  21. 1 1
      src/views/exm/question/edit/true-false.vue
  22. 17 5
      src/views/exm/question/index.vue
  23. 1 1
      src/views/exm/task/index.vue
  24. 189 0
      src/views/forum/addForum.vue
  25. 9 6
      src/views/forum/detail.vue
  26. 6 2
      src/views/forum/form.vue
  27. 1 0
      src/views/forum/index.vue
  28. 185 97
      src/views/forum/postinfo/form.vue
  29. 258 145
      src/views/forum/postinfo/index.vue
  30. 110 105
      src/views/forum/posttype/index.vue
  31. 227 80
      src/views/forum/reportinfo/form.vue
  32. 58 38
      src/views/forum/reportinfo/index.vue
  33. 5 0
      src/views/forum/sensitivity/index.vue
  34. 136 74
      src/views/forum/sensitivityrecord/form.vue
  35. 138 113
      src/views/forum/sensitivityrecord/index.vue

+ 1 - 0
package.json

@@ -37,6 +37,7 @@
 		"@vueup/vue-quill": "^1.2.0",
 		"ant-design-vue": "3.2.14",
 		"axios": "1.1.3",
+		"bowser": "^2.11.0",
 		"codemirror": "^6.0.2",
 		"cropperjs": "1.5.12",
 		"dayjs": "1.11.7",

+ 47 - 0
pnpm-lock.yaml

@@ -56,12 +56,18 @@ importers:
       '@vue-office/pdf':
         specifier: 1.2.0
         version: 1.2.0(vue-demi@0.13.11(vue@3.2.44))(vue@3.2.44)
+      '@vueup/vue-quill':
+        specifier: ^1.2.0
+        version: 1.2.0(vue@3.2.44)
       ant-design-vue:
         specifier: 3.2.14
         version: 3.2.14(vue@3.2.44)
       axios:
         specifier: 1.1.3
         version: 1.1.3
+      bowser:
+        specifier: ^2.11.0
+        version: 2.11.0
       codemirror:
         specifier: ^6.0.2
         version: 6.0.2
@@ -1064,6 +1070,11 @@ packages:
     peerDependencies:
       vue: ^3.0.10
 
+  '@vueup/vue-quill@1.2.0':
+    resolution: {integrity: sha512-kd5QPSHMDpycklojPXno2Kw2JSiKMYduKYQckTm1RJoVDA557MnyUXgcuuDpry4HY/Rny9nGNcK+m3AHk94wag==}
+    peerDependencies:
+      vue: ^3.2.41
+
   '@vueuse/core@6.9.2':
     resolution: {integrity: sha512-FRwl4ccSFuHZBHLGgS9TMv/+Dd6XFaL4o9nph2qtgQIV+z29RBFokw08XjHfykiENRzB01MjYHJ7iRUnsIFQXg==}
     peerDependencies:
@@ -1229,6 +1240,9 @@ packages:
   boolbase@1.0.0:
     resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
 
+  bowser@2.11.0:
+    resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
+
   brace-expansion@1.1.11:
     resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
 
@@ -1877,6 +1891,9 @@ packages:
   fast-diff@1.1.2:
     resolution: {integrity: sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==}
 
+  fast-diff@1.2.0:
+    resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
+
   fast-diff@1.3.0:
     resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
 
@@ -2405,6 +2422,13 @@ packages:
   lodash-es@4.17.21:
     resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
 
+  lodash.clonedeep@4.5.0:
+    resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
+
+  lodash.isequal@4.5.0:
+    resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+    deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
+
   lodash.merge@4.6.2:
     resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
 
@@ -2815,6 +2839,9 @@ packages:
     resolution: {integrity: sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==}
     engines: {node: '>=0.10'}
 
+  quill-delta@4.2.2:
+    resolution: {integrity: sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==}
+
   quill@1.3.7:
     resolution: {integrity: sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==}
 
@@ -4687,6 +4714,12 @@ snapshots:
       quill: 1.3.7
       vue: 3.2.44
 
+  '@vueup/vue-quill@1.2.0(vue@3.2.44)':
+    dependencies:
+      quill: 1.3.7
+      quill-delta: 4.2.2
+      vue: 3.2.44
+
   '@vueuse/core@6.9.2(vue@3.2.44)':
     dependencies:
       '@vueuse/shared': 6.9.2(vue@3.2.44)
@@ -4875,6 +4908,8 @@ snapshots:
 
   boolbase@1.0.0: {}
 
+  bowser@2.11.0: {}
+
   brace-expansion@1.1.11:
     dependencies:
       balanced-match: 1.0.2
@@ -5647,6 +5682,8 @@ snapshots:
 
   fast-diff@1.1.2: {}
 
+  fast-diff@1.2.0: {}
+
   fast-diff@1.3.0: {}
 
   fast-glob@3.3.3:
@@ -6166,6 +6203,10 @@ snapshots:
 
   lodash-es@4.17.21: {}
 
+  lodash.clonedeep@4.5.0: {}
+
+  lodash.isequal@4.5.0: {}
+
   lodash.merge@4.6.2: {}
 
   lodash@4.17.21: {}
@@ -6573,6 +6614,12 @@ snapshots:
       extend: 3.0.2
       fast-diff: 1.1.2
 
+  quill-delta@4.2.2:
+    dependencies:
+      fast-diff: 1.2.0
+      lodash.clonedeep: 4.5.0
+      lodash.isequal: 4.5.0
+
   quill@1.3.7:
     dependencies:
       clone: 2.1.2

+ 0 - 3
public/tinymce/plugins/kityformula-editor/kityFormula.html

@@ -54,7 +54,6 @@
 <script>
 //获取url地址栏传参
 function getQueryVariable(variable){
-    console.log('window.location=', window.location)
     var query = window.location.search.substring(1);
     var vars = query.split("&");
     for (var i=0;i<vars.length;i++) {
@@ -66,7 +65,6 @@ function getQueryVariable(variable){
 //处理TinyMCE编辑器的事件
 window.addEventListener('message', function (event) {
   var data = event.data;
-  console.log('调试回显-message:', data)
   kfe.execCommand('get.image.data', function(data){
         var latex = kfe.execCommand('get.source');
         window.parent.postMessage({
@@ -91,7 +89,6 @@ jQuery( function ($) {
             }
         } );
         factory.ready( function ( KFEditor ) {
-            console.log('调试回显:', KFEditor)
             $( "#tips").remove();
             //处理地址栏的参数并加载到编辑器中
             var c=getQueryVariable("c")

+ 66 - 68
public/tinymce/plugins/kityformula-editor/plugin.js

@@ -1,72 +1,70 @@
-tinymce.PluginManager.add('kityformula-editor', function(editor, url) {
+tinymce.PluginManager.add('kityformula-editor', function (editor, url) {
+	var baseURL = tinymce.baseURL + '/plugins/kityformula-editor/kityFormula.html'
 
-    var baseURL = tinymce.baseURL+'/plugins/kityformula-editor/kityFormula.html';
+	editor.on('dblclick', function () {
+		var sel = editor.selection.getContent()
+		var path = /\<img(.*?)src="data:image\/png;base64,[A-Za-z0-9+/=]*"(.*?)data-latex="(.*?)" \/>/g
+		var path2 = /data-latex="(.*?)"/g
 
-    editor.on('dblclick',function(){
-        var sel=editor.selection.getContent();
-        var path=/\<img(.*?)src="data:image\/png;base64,[A-Za-z0-9+/=]*"(.*?)data-latex="(.*?)" \/>/g;
-        var path2=/data-latex="(.*?)"/g;
+		if (sel.search(path) == 0) {
+			sel.replace(path2, function ($0, $1) {
+				var param = encodeURIComponent($1)
+				openDialog(param)
+				return $0
+			})
+		}
+	})
 
-        if(sel.search(path)==0){
-            sel.replace(path2,function($0,$1){
-                var param=encodeURIComponent($1);
-                openDialog(param);
-                return $0;
-            });
-        };
-    });
+	var openDialog = function (param) {
+		return editor.windowManager.openUrl({
+			title: '插入公式',
+			size: 'large',
+			width: 785,
+			height: 475,
+			url: param ? baseURL + '?c=' + param : baseURL,
+			buttons: [
+				{
+					type: 'cancel',
+					text: 'Close'
+				},
+				{
+					type: 'custom',
+					text: 'Save',
+					name: 'save',
+					primary: true
+				}
+			],
+			onAction: function (api, details) {
+				switch (details.name) {
+					case 'save':
+						api.sendMessage('save')
+						break
+					default:
+						break
+				}
+			}
+		})
+	}
 
-    var openDialog = function(param) {
-        return editor.windowManager.openUrl({
-            title: '插入公式',
-            size: 'large',
-            width: 785,
-            height: 475,
-            url:param?baseURL+"?c="+param:baseURL,
-            buttons: [
-                {
-                    type: 'cancel',
-                    text: 'Close'
-                },
-                {
-                    type: 'custom',
-                    text: 'Save',
-                    name: 'save',
-                    primary: true
-                },
-            ],
-            onAction: function (api, details) {
-                switch (details.name) {
-                    case 'save':
-                        api.sendMessage("save");
-                        break;
-                    default:
-                        break;
-                };
-            }
-        });
-    };
-
-    
-    editor.ui.registry.addButton('kityformula-editor', {
-        text: '公式',
-        tooltip: '插入公式',
-        onAction: function() {
-            openDialog();
-        }
-    });
-    editor.ui.registry.addMenuItem('kityformula-editor', {
-        text: '公式',
-        onAction: function() {
-            openDialog();
-        }
-    });
-    return {
-        getMetadata: function() {
-            return  {
-                name: "公式",
-                url: "http://hgcserver.gitee.io",
-            };
-        }
-    };
-});
+	editor.ui.registry.addButton('kityformula-editor', {
+		text: '公式',
+		tooltip: '插入公式',
+		onAction: function () {
+			openDialog()
+		}
+	})
+	editor.ui.registry.addMenuItem('kityformula-editor', {
+		text: '公式',
+		onAction: function () {
+			openDialog()
+		}
+	})
+	return {
+		getMetadata: function () {
+			return {
+				name: '公式',
+				url: ''
+			}
+		}
+	}
+})

+ 66 - 69
public/tinymce/plugins/kityformula-editor/plugin.min.js

@@ -1,73 +1,70 @@
-tinymce.PluginManager.add('kityformula-editor', function(editor, url) {
+tinymce.PluginManager.add('kityformula-editor', function (editor, url) {
+	var baseURL = '/tinymce/plugins/kityformula-editor/kityFormula.html'
 
-    var baseURL = '/tinymce/plugins/kityformula-editor/kityFormula.html';
+	editor.on('dblclick', function () {
+		var sel = editor.selection.getContent()
+		var path = /^<img\s+[^>]*src="data:image\/png;base64,[A-Za-z0-9+\/=]*"[^>]*data-latex="([^"]+)"[^>]*>$/
+		var path2 = /data-latex="(.*?)"/g
 
-    editor.on('dblclick',function(){
-        var sel=editor.selection.getContent();
-        console.log('双击sel=', sel)
-        var path=/\<img(.*?)src="data:image\/png;base64,[A-Za-z0-9+/=]*"(.*?)data-latex="(.*?)" \/>/g;
-        var path2=/data-latex="(.*?)"/g;
+		if (sel.search(path) == 0) {
+			sel.replace(path2, function ($0, $1) {
+				var param = encodeURIComponent($1)
+				openDialog(param)
+				return $0
+			})
+		}
+	})
 
-        if(sel.search(path)==0){
-            sel.replace(path2,function($0,$1){
-                var param=encodeURIComponent($1);
-                openDialog(param);
-                return $0;
-            });
-        };
-    });
+	var openDialog = function (param) {
+		return editor.windowManager.openUrl({
+			title: '插入公式',
+			size: 'large',
+			width: 785,
+			height: 475,
+			url: param ? baseURL + '?c=' + param : baseURL,
+			buttons: [
+				{
+					type: 'cancel',
+					text: 'Close'
+				},
+				{
+					type: 'custom',
+					text: 'Save',
+					name: 'save',
+					primary: true
+				}
+			],
+			onAction: function (api, details) {
+				switch (details.name) {
+					case 'save':
+						api.sendMessage('save')
+						break
+					default:
+						break
+				}
+			}
+		})
+	}
 
-    var openDialog = function(param) {
-        return editor.windowManager.openUrl({
-            title: '插入公式',
-            size: 'large',
-            width: 785,
-            height: 475,
-            url:param?baseURL+"?c="+param:baseURL,
-            buttons: [
-                {
-                    type: 'cancel',
-                    text: 'Close'
-                },
-                {
-                    type: 'custom',
-                    text: 'Save',
-                    name: 'save',
-                    primary: true
-                },
-            ],
-            onAction: function (api, details) {
-                switch (details.name) {
-                    case 'save':
-                        api.sendMessage("save");
-                        break;
-                    default:
-                        break;
-                };
-            }
-        });
-    };
-
-    
-    editor.ui.registry.addButton('kityformula-editor', {
-        text: '公式',
-        tooltip: '插入公式',
-        onAction: function() {
-            openDialog();
-        }
-    });
-    editor.ui.registry.addMenuItem('kityformula-editor', {
-        text: '公式',
-        onAction: function() {
-            openDialog();
-        }
-    });
-    return {
-        getMetadata: function() {
-            return  {
-                name: "公式",
-                url: "http://hgcserver.gitee.io",
-            };
-        }
-    };
-});
+	editor.ui.registry.addButton('kityformula-editor', {
+		text: '公式',
+		tooltip: '插入公式',
+		onAction: function () {
+			openDialog()
+		}
+	})
+	editor.ui.registry.addMenuItem('kityformula-editor', {
+		text: '公式',
+		onAction: function () {
+			openDialog()
+		}
+	})
+	return {
+		getMetadata: function () {
+			return {
+				name: '公式',
+				url: ''
+			}
+		}
+	}
+})

+ 14 - 2
src/api/forum/forumApi.js

@@ -44,8 +44,20 @@ export default {
 	moreList(data) {
 		return request('forum/postinfo/moreList', data, 'get')
 	},
-	// 扩展帖子列表,1.查询我发布的 2.查询我回复的 3.查询关于我的 4.查询我点赞的
+	// 所有用户
 	allUserList(data) {
 		return request('sys/user/allList', data, 'get')
-	}
+	},
+	// 后台-管理员是否关闭帖子接口
+	postinfoStatus(data) {
+		return request('forum/postinfo/status', data)
+	},
+	// 后台-管理员置顶帖子接口
+	postinfoTop(data) {
+		return request('forum/postinfo/top', data)
+	},
+	// 后台-管理员处理举报接口
+	reportinfoAudit(data) {
+		return request('forum/reportinfo/adminHandle', data)
+	},
 }

+ 2 - 2
src/api/forum/forumPostInfoApi.js

@@ -1,6 +1,6 @@
 import { baseRequest } from '@/utils/request'
 
-const request = (url, ...arg) => baseRequest(`/api/forumapp/forum/postinfo/` + url, ...arg)
+const request = (url, ...arg) => baseRequest(`/api/webapp/forum/postinfo/` + url, ...arg)
 
 /**
  * 帖子信息表Api接口管理器
@@ -11,7 +11,7 @@ const request = (url, ...arg) => baseRequest(`/api/forumapp/forum/postinfo/` + u
 export default {
 	// 获取帖子信息表分页
 	forumPostInfoPage(data) {
-		return request('page', data, 'get')
+		return request('adminPage', data, 'get')
 	},
 	// 提交帖子信息表表单 edit为true时为编辑,默认为新增
 	forumPostInfoSubmitForm(data, edit = false) {

+ 1 - 1
src/api/forum/forumPostTypeApi.js

@@ -1,6 +1,6 @@
 import { baseRequest } from '@/utils/request'
 
-const request = (url, ...arg) => baseRequest(`/api/forumapp/forum/posttype/` + url, ...arg)
+const request = (url, ...arg) => baseRequest(`/api/webapp/forum/posttype/` + url, ...arg)
 
 /**
  * 帖子分类表Api接口管理器

+ 1 - 1
src/api/forum/forumReportInfoApi.js

@@ -1,6 +1,6 @@
 import { baseRequest } from '@/utils/request'
 
-const request = (url, ...arg) => baseRequest(`/api/forumapp/forum/reportinfo/` + url, ...arg)
+const request = (url, ...arg) => baseRequest(`/api/webapp/forum/reportinfo/` + url, ...arg)
 
 /**
  * 论坛-帖子举报信息表Api接口管理器

+ 1 - 1
src/api/forum/forumSensitivityApi.js

@@ -1,6 +1,6 @@
 import { baseRequest } from '@/utils/request'
 
-const request = (url, ...arg) => baseRequest(`/api/forumapp/forum/sensitivity/` + url, ...arg)
+const request = (url, ...arg) => baseRequest(`/api/webapp/forum/sensitivity/` + url, ...arg)
 
 /**
  * 论坛-敏感词Api接口管理器

+ 1 - 1
src/api/forum/forumSensitivityRecordApi.js

@@ -1,6 +1,6 @@
 import { baseRequest } from '@/utils/request'
 
-const request = (url, ...arg) => baseRequest(`/api/forumapp/forum/sensitivityrecord/` + url, ...arg)
+const request = (url, ...arg) => baseRequest(`/api/webapp/forum/sensitivityrecord/` + url, ...arg)
 
 /**
  * 敏感词过滤记录Api接口管理器

+ 1 - 0
src/components/Comment/index.vue

@@ -103,6 +103,7 @@
 			)
 			.then((data) => {
 				item.isLike = l
+				emit('successful')
 			})
 	}
 	const showDeleteConfirm = (item) => {

+ 4 - 3
src/components/Editor/index.vue

@@ -67,13 +67,14 @@
 		resize: true,
 		elementpath: true,
 		content_style: '',
+		toolbar_mode: 'wrap',
 		external_plugins: {
-			'kityformula-editor': '/public/tinymce/plugins/kityformula-editor/plugin.min.js',
+			'kityformula-editor': '/public/tinymce/plugins/kityformula-editor/plugin.min.js'
 		},
-		draggable: true,
 		automatic_uploads: false,
 		images_upload_handler(blobInfo, progress) {
 			return new Promise((resolve, reject) => {
+				console.log('调用上传文件回显:', blobInfo.blob)
 				const param = new FormData()
 				param.append('file', blobInfo.blob(), blobInfo.filename())
 				props
@@ -91,7 +92,7 @@
 				// getBody().style.fontSize = '14px'
 			})
 			editor.ui.registry.addButton('numberedline', {
-				text: '横杠数字',
+				text: '填空',
 				onAction: function () {
 					const count = editor.getBody().querySelectorAll('.gapfilling-span').length
 					const lineNumber = count + 1

+ 42 - 40
src/components/UpLoadImg/index.vue

@@ -26,7 +26,8 @@ import {message} from 'ant-design-vue'
 import {PictureOutlined, CloudUploadOutlined} from '@ant-design/icons-vue'
 import tool from "@/utils/tool";
 
-const action = ref(sysConfig.API_URL +'/api/webapp/dev/file/uploadMinioReturnId')
+const action = ref(sysConfig.API_URL +'/api/webapp/dev/file/uploadMinioReturnUrl')
+// const action = ref(sysConfig.API_URL +'/api/webapp/dev/file/uploadMinioReturnId')
 const headers = ref({
 	token: tool.data.get('TOKEN')
 })
@@ -162,58 +163,59 @@ defineExpose({
 		display: flex;
 		align-items: center;
 	}
+	
+}
+
+.cover-upload-row {
+	// display: flex;
+	// align-items: center;
 
-	.cover-upload-row {
+	.cover-upload-box {
+		width: 120px;
+		height: 120px;
+		background: #f7f8fa;
+		border-radius: 8px;
 		display: flex;
 		align-items: center;
-
-		.cover-upload-box {
-			width: 120px;
-			height: 120px;
-			background: #f7f8fa;
+		justify-content: center;
+		margin-right: 24px;
+		border: 1px dashed #d9d9d9;
+		cursor: pointer;
+
+		.cover-img {
+			width: 100%;
+			height: 100%;
+			object-fit: cover;
 			border-radius: 8px;
+		}
+
+		.cover-placeholder {
 			display: flex;
 			align-items: center;
 			justify-content: center;
-			margin-right: 24px;
-			border: 1px dashed #d9d9d9;
-			cursor: pointer;
-
-			.cover-img {
-				width: 100%;
-				height: 100%;
-				object-fit: cover;
-				border-radius: 8px;
-			}
-
-			.cover-placeholder {
-				display: flex;
-				align-items: center;
-				justify-content: center;
-				width: 100%;
-				height: 100%;
-				color: #bbb;
-				font-size: 32px;
-			}
-		}
-
-		.cover-tip {
-			color: #888;
-			font-size: 13px;
+			width: 100%;
+			height: 100%;
+			color: #bbb;
+			font-size: 32px;
 		}
 	}
 
-	.upload-tip {
+	.cover-tip {
 		color: #888;
 		font-size: 13px;
-		margin-left: 12px;
 	}
+}
 
-	.footer-btns {
-		display: flex;
-		justify-content: flex-end;
-		gap: 16px;
-		margin-top: 24px;
-	}
+.upload-tip {
+	color: #888;
+	font-size: 13px;
+	margin-left: 12px;
+}
+
+.footer-btns {
+	display: flex;
+	justify-content: flex-end;
+	gap: 16px;
+	margin-top: 24px;
 }
 </style>

+ 5 - 5
src/store/exam.js

@@ -94,11 +94,11 @@ export const useExamStore = defineStore('exam', {
 					{ key: 5, value: '简答题' }
 				],
 				editUrlEnum: [
-					{ key: 1, value: '/src/views/exm/question/edit/single-choice.vue', name: '单选题' },
-					{ key: 2, value: '/src/views/exm/question/edit/multiple-choice.vue', name: '多选题' },
-					{ key: 3, value: '/src/views/exm/question/edit/true-false.vue', name: '判断题' },
-					{ key: 4, value: '/src/views/exm/question/edit/gap-filling.vue', name: '填空题' },
-					{ key: 5, value: '/src/views/exm/question/edit/short-answer.vue', name: '简答题' }
+					{ key: 1, value: 'single-choice', name: '单选题' },
+					{ key: 2, value: 'multiple-choice', name: '多选题' },
+					{ key: 3, value: 'true-false', name: '判断题' },
+					{ key: 4, value: 'gap-filling', name: '填空题' },
+					{ key: 5, value: 'short-answer', name: '简答题' }
 				],
 				answer: {
 					doRightTag: [

+ 7 - 7
src/views/exm/exampaper/index.vue

@@ -134,13 +134,13 @@
 			key: 'id',
 			width: 90
 		},
-		{
-			title: '学科',
-			dataIndex: 'subjectId',
-			key: 'subjectId',
-			width: 200,
-			customRender: ({ text }) => examStore.subjectEnumFormat(text)
-		},
+		// {
+		// 	title: '学科',
+		// 	dataIndex: 'subjectId',
+		// 	key: 'subjectId',
+		// 	width: 200,
+		// 	customRender: ({ text }) => examStore.subjectEnumFormat(text)
+		// },
 		{
 			title: '名称',
 			dataIndex: 'name',

+ 1 - 1
src/views/exm/question/edit/gap-filling.vue

@@ -55,7 +55,7 @@
 		</a-form>
 		<a-modal
 			v-model:visible="richEditor.dialogVisible"
-			width="800px"
+			width="70%"
 			:footer="null"
 			:closable="false"
 			centered

+ 1 - 1
src/views/exm/question/edit/multiple-choice.vue

@@ -61,7 +61,7 @@
 		</a-form>
 		<a-modal
 			v-model:visible="richEditor.dialogVisible"
-			width="800px"
+			width="70%"
 			:footer="null"
 			:closable="false"
 			centered

+ 1 - 1
src/views/exm/question/edit/short-answer.vue

@@ -45,7 +45,7 @@
 		</a-form>
 		<a-modal
 			v-model:visible="richEditor.dialogVisible"
-			width="800px"
+			width="70%"
 			:footer="null"
 			:closable="false"
 			centered

+ 1 - 1
src/views/exm/question/edit/single-choice.vue

@@ -61,7 +61,7 @@
 		</a-form>
 		<a-modal
 			v-model:visible="richEditor.dialogVisible"
-			width="800px"
+			width="70%"
 			:footer="null"
 			:closable="false"
 			centered

+ 1 - 1
src/views/exm/question/edit/true-false.vue

@@ -59,7 +59,7 @@
 		</a-form>
 		<a-modal
 			v-model:visible="richEditor.dialogVisible"
-			width="800px"
+			width="70%"
 			:footer="null"
 			:closable="false"
 			centered

+ 17 - 5
src/views/exm/question/index.vue

@@ -153,7 +153,12 @@
 </template>
 
 <script setup>
-	import { ref, reactive, computed, onMounted, defineAsyncComponent, shallowRef } from 'vue'
+	import { ref, reactive, computed, onMounted, shallowRef } from 'vue'
+	import SingleChoice from './edit/single-choice.vue'
+	import MultipleChoice from './edit/multiple-choice.vue'
+	import TrueFalse from './edit/true-false.vue'
+	import GapFilling from './edit/gap-filling.vue'
+	import ShortAnswer from './edit/short-answer.vue'
 	import { useExamStore } from '@/store/exam'
 	import tQuestionApi from '@/api/exam/question/tQuestionApi'
 	import customPagination from '@/components/customPagination.vue'
@@ -194,9 +199,16 @@
 	// 动态抽屉相关
 	const drawerOpen = ref(false)
 	const currentComponent = shallowRef(null)
-	const openDrawer = (componentPath) => {
+	const componentMap = {
+		'single-choice': SingleChoice,
+		'multiple-choice': MultipleChoice,
+		'true-false': TrueFalse,
+		'gap-filling': GapFilling,
+		'short-answer': ShortAnswer
+	}
+	const openDrawer = (componentName) => {
 		currentComponentId.value = 0
-		currentComponent.value = defineAsyncComponent(() => import(/* @vite-ignore */ componentPath))
+		currentComponent.value = componentMap[componentName]
 		drawerOpen.value = true
 	}
 	const closeDrawer = () => {
@@ -262,8 +274,8 @@
 	}
 
 	const editQuestion = (row) => {
-		const url = enumFormat(editUrlEnum.value, row.questionType)
-		currentComponent.value = defineAsyncComponent(() => import(/* @vite-ignore */ url))
+		const componentName = enumFormat(editUrlEnum.value, row.questionType)
+		currentComponent.value = componentMap[componentName]
 		drawerOpen.value = true
 		currentComponentId.value = row.id
 	}

+ 1 - 1
src/views/exm/task/index.vue

@@ -24,7 +24,7 @@
 		>
 			<a-table-column title="Id" dataIndex="id" key="id" width="100" />
 			<a-table-column title="标题" dataIndex="title" key="title" />
-			<a-table-column title="学级" dataIndex="gradeLevel" key="gradeLevel" :customRender="levelFormatter" />
+			<!-- <a-table-column title="学级" dataIndex="gradeLevel" key="gradeLevel" :customRender="levelFormatter" /> -->
 			<a-table-column title="发送人" dataIndex="createUserName" key="createUserName" width="100" />
 			<a-table-column title="创建时间" dataIndex="createTime" key="createTime" width="160">
 				<template #default="{ record }">

+ 189 - 0
src/views/forum/addForum.vue

@@ -0,0 +1,189 @@
+<template>
+	<a-card :bordered="false">
+		<a-alert
+			class="mb-3"
+			message="欢迎来到论坛 — 衷心感谢你参与讨论!
+			标题是否清晰明了地描述了主题?看
+			起来有意思么?
+			谁会感兴趣?
+			它为什么重要?
+			你期望从社区中获得什么样的回应?
+			选择常用的词句以便别人能找到你的主题。若想要给主题和类似主题分组,选择一个分类。"
+			type="warning"
+		/>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-row :gutter="16">
+				<a-col :span="12">
+					<a-form-item label="标题:" name="postTitle">
+						<a-input v-model:value="formData.postTitle" placeholder="请输入标题" allow-clear />
+					</a-form-item>
+				</a-col>
+				<a-col :span="12">
+					<a-form-item label="分类:" name="typeId">
+						<a-select
+							v-model:value="formData.typeId"
+							show-search
+							placeholder="请选择分类"
+							style="width: 200px"
+							:options="typeOptions"
+							:filter-option="filterOption"
+						></a-select>
+					</a-form-item>
+				</a-col>
+				<a-col :span="12">
+					<a-form-item label="指向:" name="appointUserArr">
+						<a-select
+							v-model:value="formData.appointUserArr"
+							mode="multiple"
+							show-search
+							placeholder="请选择"
+							style="width: 200px"
+							:options="usertypeOptions"
+							:filter-option="filterOption"
+						></a-select>
+					</a-form-item>
+				</a-col>
+				<a-col :span="24">
+					<a-form-item label="内容:" name="postContent">
+						<xn-editor v-model="formData.postContent" placeholder="请输入内容" :height="400"></xn-editor>
+					</a-form-item>
+				</a-col>
+			</a-row>
+		</a-form>
+		<div>
+			<!-- <a-button style="margin-right: 8px" @click="onClose">关闭</a-button> -->
+			<a-button type="primary" :loading="submitLoading" @click="onSubmit">保存</a-button>
+		</div>
+	</a-card>
+</template>
+
+<script setup name="addForum">
+	import { required } from '@/utils/formRules'
+	import SnowflakeId from 'snowflake-id'
+	import tool from '@/utils/tool'
+	import forumApi from '@/api/forum/forumApi'
+	import XnEditor from '@/components/Editor/index.vue'
+	import Bowser from 'bowser'
+	import { useRoute, useRouter } from 'vue-router'
+	const route = useRoute()
+	const router = useRouter()
+	const { proxy } = getCurrentInstance()
+	const userInfo = tool.data.get('USER_INFO')
+	const typeOptions = ref([])
+	// 默认是关闭状态
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	const treeData = ref([])
+	// 表单数据,也就是默认给一些数据
+	const formData = ref({})
+	// 默认展开的节点(顶级)
+	const defaultExpandedKeys = ref([0])
+	const submitLoading = ref(false)
+	// 模块ID
+	const moduleId = ref('')
+	const usertypeOptions = ref([])
+	const filterOption = (input, option) => {
+		return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+	}
+
+	// 打开抽屉
+	const onOpen = () => {
+		forumApi.forumTypeList().then((data) => {
+			typeOptions.value = data.map((r) => {
+				return {
+					label: r.typeName,
+					value: r.typeId,
+					...r
+				}
+			})
+		})
+		forumApi.allUserList().then((data) => {
+			usertypeOptions.value = data.map((r) => {
+				return {
+					label: r.name,
+					value: r.id,
+					...r
+				}
+			})
+		})
+		if (route.query.postType == 1) {
+			getBower()
+		}
+		if (route.query.postType == 2) {
+			errorCorrection()
+		}
+	}
+	setTimeout(() => {
+		onOpen()
+	}, 0)
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+	}
+
+	// 默认要校验的
+	const formRules = {
+		postTitle: [required('请输入标题')],
+		typeId: [required('请选择分类')],
+		postContent: [required('请输入内容')]
+	}
+
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+				submitLoading.value = true
+				if (formData.value.appointUserArr && formData.value.appointUserArr.length > 1) {
+					formData.value.appointUser = formData.value.appointUserArr.join(',')
+				}
+				let params = formData.value
+				if (route.query.postType == 1) {
+					params = {
+						...formData.value,
+						...browserObj.value,
+						postType:route.query.postType
+					}
+				}
+				if (route.query.postType == 2) {
+					params = {
+						...formData.value,
+						...errorVal.value,
+						postType:route.query.postType
+					}
+				}
+				forumApi.submitForm(params).then(() => {
+					onClose()
+					emit('successful')
+				})
+			})
+			.finally(() => {
+				submitLoading.value = false
+			})
+	}
+	//获取操作系统/浏览器等信息
+	const browserObj = ref({})
+	function getBower() {
+		const browser = Bowser.getParser(window.navigator.userAgent)
+		let obj = browser.parsedResult
+		browserObj.value = {
+			forumSupportEnvParam: {
+				browserType: obj.browser.name,
+				browserVersion: obj.browser.version,
+				osType: obj.os.name,
+				osVersion: obj.os.version,
+				deviceType: 0
+			}
+		}
+	}
+	//纠错
+	const errorVal = ref({})
+	function errorCorrection() {
+		errorVal.value = {
+			contentCorrectionParam: {
+				resourceType: route.query.type,
+				resourceId: route.query.id
+			}
+		}
+	}
+</script>

+ 9 - 6
src/views/forum/detail.vue

@@ -9,22 +9,22 @@
 				/>
 				<div class="snowy-index-card-left-one-username">
 					<span style="font-weight: 600; margin: 2px; font-size: 18px">{{ detailObj.userNickName }}</span>
-					<span style="color: #6d737b; margin: 2px"
-						>{{ detailObj.typeName }} | {{ formatDateTime(detailObj.lastReplyTime) }}</span
-					>
+					<span style="color: #6d737b; margin: 2px">
+						{{ detailObj.typeName }} | {{ formatDateTime(detailObj.lastReplyTime) }}
+					</span>
 				</div>
 			</div>
 		</div>
 		<div class="forum-list-title">{{ detailObj.postTitle }}</div>
-		<div v-html="detailObj.postContent"></div>
+		<div class="htmlContent" v-html="detailObj.postContent"></div>
 		<div>
 			<span>
 				<a-tooltip title="点赞">
 					<template v-if="detailObj.isLike == 1">
-						<HeartOutlined :style="{ color: '#fa6c8d' }" @click="like(item, 0)" />
+						<HeartOutlined :style="{ color: '#fa6c8d' }" @click="like(detailObj, 0)" />
 					</template>
 					<template v-else>
-						<HeartOutlined @click="like(item, 1)" />
+						<HeartOutlined @click="like(detailObj, 1)" />
 					</template>
 				</a-tooltip>
 				<span style="padding-left: 8px">
@@ -121,6 +121,9 @@
 </script>
 
 <style scoped>
+	:deep(.htmlContent img) {
+		max-width: 100% !important;
+	}
 	.snowy-index-card-left-one-username {
 		margin-left: 8px;
 		display: flex;

+ 6 - 2
src/views/forum/form.vue

@@ -113,7 +113,9 @@
 			})
 		})
 		if (module) {
-			record.appointUserArr = record.appointUser.split(',')
+			if(record.appointUser){
+				record.appointUserArr = record.appointUser.split(',')
+			}
 			formData.value = Object.assign(formData.value, record)
 		}
 	}
@@ -138,7 +140,9 @@
 			.validate()
 			.then(() => {
 				submitLoading.value = true
-				formData.value.appointUser = formData.value.appointUserArr.join(',')
+				if(formData.value.appointUserArr && formData.value.appointUserArr.length > 1){
+					formData.value.appointUser = formData.value.appointUserArr.join(',')
+				}
 				forumApi.submitForm(formData.value, formData.value.postId).then(() => {
 					onClose()
 					emit('successful')

+ 1 - 0
src/views/forum/index.vue

@@ -219,6 +219,7 @@
 		searchFormState.sortOrder = value
 		table.value.refresh(true)
 	}
+	
 </script>
 <style scoped>
 	.forum-list-title {

+ 185 - 97
src/views/forum/postinfo/form.vue

@@ -1,103 +1,191 @@
 <template>
-    <xn-form-container
-        :title="formData.postId ? '编辑帖子信息表' : '增加帖子信息表'"
-        :width="700"
-        :visible="visible"
-        :destroy-on-close="true"
-        @close="onClose"
-    >
-        <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
-            <a-form-item label="分类id:" name="typeId">
-                <a-input v-model:value="formData.typeId" placeholder="请输入分类id" allow-clear />
-            </a-form-item>
-            <a-form-item label="用户id:" name="userId">
-                <a-input v-model:value="formData.userId" placeholder="请输入用户id" allow-clear />
-            </a-form-item>
-            <a-form-item label="帖子标题:" name="postTitle">
-                <a-input v-model:value="formData.postTitle" placeholder="请输入帖子标题" allow-clear />
-            </a-form-item>
-            <a-form-item label="帖子内容:" name="postContent">
-                <a-input v-model:value="formData.postContent" placeholder="请输入帖子内容" allow-clear />
-            </a-form-item>
-            <a-form-item label="是否置顶 0普通 1置顶:" name="isTop">
-                <a-input v-model:value="formData.isTop" placeholder="请输入是否置顶 0普通 1置顶" allow-clear />
-            </a-form-item>
-            <a-form-item label="浏览次数:" name="viewCount">
-                <a-input v-model:value="formData.viewCount" placeholder="请输入浏览次数" allow-clear />
-            </a-form-item>
-            <a-form-item label="回复次数:" name="replyCount">
-                <a-input v-model:value="formData.replyCount" placeholder="请输入回复次数" allow-clear />
-            </a-form-item>
-            <a-form-item label="点赞次数:" name="likeCount">
-                <a-input v-model:value="formData.likeCount" placeholder="请输入点赞次数" allow-clear />
-            </a-form-item>
-            <a-form-item label="最后回复用户id:" name="lastReplyUserId">
-                <a-input v-model:value="formData.lastReplyUserId" placeholder="请输入最后回复用户id" allow-clear />
-            </a-form-item>
-            <a-form-item label="最后回复时间:" name="lastReplyTime">
-                <a-date-picker v-model:value="formData.lastReplyTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择最后回复时间" style="width: 100%" />
-            </a-form-item>
-            <a-form-item label="帖子类型 0普通帖子 1技术支持 2内容纠错:" name="postType">
-                <a-input v-model:value="formData.postType" placeholder="请输入帖子类型 0普通帖子 1技术支持 2内容纠错" allow-clear />
-            </a-form-item>
-            <a-form-item label="定向用户:" name="appointUser">
-                <a-input v-model:value="formData.appointUser" placeholder="请输入定向用户" allow-clear />
-            </a-form-item>
-        </a-form>
-        <template #footer>
-            <a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
-            <a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
-        </template>
-    </xn-form-container>
+	<xn-form-container
+		:title="formData.postId ? '编辑帖子信息表' : '增加帖子信息表'"
+		:width="700"
+		:visible="visible"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-form-item label="分类:" name="typeId">
+				<a-select
+					v-model:value="formData.typeId"
+					show-search
+					placeholder="请选择分类"
+					style="width: 100%"
+					:options="typeOptions"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="用户" name="userId">
+				<a-select
+					v-model:value="formData.userId"
+					show-search
+					placeholder="请选择用户"
+					style="width: 100%"
+					:options="usertypeOptions"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="帖子标题:" name="postTitle">
+				<a-input v-model:value="formData.postTitle" placeholder="请输入帖子标题" allow-clear />
+			</a-form-item>
+			<a-form-item label="帖子内容:" name="postContent">
+				<xn-editor v-model="formData.postContent" placeholder="请输入内容" :height="400"></xn-editor>
+			</a-form-item>
+			<a-form-item label="是否置顶:" name="isTop">
+				<a-select
+					v-model:value="formData.isTop"
+					placeholder="请选择是否置顶"
+					style="width: 100%"
+					:options="topOptions"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<!-- <a-form-item label="浏览次数:" name="viewCount">
+				<a-input v-model:value="formData.viewCount" placeholder="请输入浏览次数" allow-clear />
+			</a-form-item>
+			<a-form-item label="回复次数:" name="replyCount">
+				<a-input v-model:value="formData.replyCount" placeholder="请输入回复次数" allow-clear />
+			</a-form-item>
+			<a-form-item label="点赞次数:" name="likeCount">
+				<a-input v-model:value="formData.likeCount" placeholder="请输入点赞次数" allow-clear />
+			</a-form-item> -->
+
+			<a-form-item label="帖子类型:" name="postType">
+				<a-select
+					v-model:value="formData.postType"
+					show-search
+					placeholder="请选择类型"
+					style="width: 100%"
+					:options="invitationOptions"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="定向用户:" name="appointUserArr">
+				<a-select
+					v-model:value="formData.appointUserArr"
+					show-search
+					mode="multiple"
+					placeholder="请选择用户"
+					style="width: 100%"
+					:options="usertypeOptions"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
 </template>
 
 <script setup name="forumPostInfoForm">
-    import { cloneDeep } from 'lodash-es'
-    import { required } from '@/utils/formRules'
-    import forumPostInfoApi from '@/api/forum/forumPostInfoApi'
-    // 抽屉状态
-    const visible = ref(false)
-    const emit = defineEmits({ successful: null })
-    const formRef = ref()
-    // 表单数据
-    const formData = ref({})
-    const submitLoading = ref(false)
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import forumPostInfoApi from '@/api/forum/forumPostInfoApi'
+	import forumApi from '@/api/forum/forumApi'
+	import XnEditor from '@/components/Editor/index.vue'
+	// 抽屉状态
+	const visible = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+	//分类
+	const typeOptions = ref([])
+	//用户
+	const usertypeOptions = ref([])
+	//置顶
+	const topOptions = ref([
+		{
+			label: '普通',
+			value: 0
+		},
+		{
+			label: '置顶',
+			value: 1
+		}
+	])
+	//帖子类型
+	const invitationOptions = ref([
+		{
+			label: '普通帖子',
+			value: 0
+		},
+		{
+			label: '技术支持',
+			value: 1
+		},
+		{
+			label: '内容纠错',
+			value: 2
+		}
+	])
+	// 打开抽屉
+	const onOpen = (record) => {
+		visible.value = true
+		forumApi.forumTypeList().then((data) => {
+			typeOptions.value = data.map((r) => {
+				return {
+					label: r.typeName,
+					value: r.typeId,
+					...r
+				}
+			})
+		})
+		forumApi.allUserList().then((data) => {
+			usertypeOptions.value = data.map((r) => {
+				return {
+					label: r.name,
+					value: r.id,
+					...r
+				}
+			})
+		})
 
-    // 打开抽屉
-    const onOpen = (record) => {
-        visible.value = true
-        if (record) {
-            let recordData = cloneDeep(record)
-            formData.value = Object.assign({}, recordData)
-        }
-    }
-    // 关闭抽屉
-    const onClose = () => {
-        formRef.value.resetFields()
-        formData.value = {}
-        visible.value = false
-    }
-    // 默认要校验的
-    const formRules = {
-    }
-    // 验证并提交数据
-    const onSubmit = () => {
-        formRef.value.validate().then(() => {
-            submitLoading.value = true
-            const formDataParam = cloneDeep(formData.value)
-            forumPostInfoApi
-                .forumPostInfoSubmitForm(formDataParam, formDataParam.postId)
-                .then(() => {
-                    onClose()
-                    emit('successful')
-                })
-                .finally(() => {
-                    submitLoading.value = false
-                })
-        })
-    }
-    // 抛出函数
-    defineExpose({
-        onOpen
-    })
+		if (record) {
+			if (record.appointUser) {
+				record.appointUserArr = record.appointUser.split(',')
+			}
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		visible.value = false
+	}
+	const filterOption = (input, option) => {
+		return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+	}
+	// 默认要校验的
+	const formRules = {}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value.validate().then(() => {
+			submitLoading.value = true
+			const formDataParam = cloneDeep(formData.value)
+			forumPostInfoApi
+				.forumPostInfoSubmitForm(formDataParam, formDataParam.postId)
+				.then(() => {
+					if (formData.value.appointUserArr && formData.value.appointUserArr.length > 1) {
+						formData.value.appointUser = formData.value.appointUserArr.join(',')
+					}
+					onClose()
+					emit('successful')
+				})
+				.finally(() => {
+					submitLoading.value = false
+				})
+		})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
 </script>

+ 258 - 145
src/views/forum/postinfo/index.vue

@@ -1,150 +1,263 @@
 <template>
-    <a-card :bordered="false">
-        <s-table
-            ref="table"
-            :columns="columns"
-            :data="loadData"
-            :alert="options.alert.show"
-            bordered
-            :row-key="(record) => record.postId"
-            :tool-config="toolConfig"
-            :row-selection="options.rowSelection"
-        >
-            <template #operator class="table-operator">
-                <a-space>
-                    <a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('forumPostInfoAdd')">
-                        <template #icon><plus-outlined /></template>
-                        新增
-                    </a-button>
-                    <xn-batch-delete
-                        v-if="hasPerm('forumPostInfoBatchDelete')"
-                        :selectedRowKeys="selectedRowKeys"
-                        @batchDelete="deleteBatchForumPostInfo"
-                    />
-                </a-space>
-            </template>
-            <template #bodyCell="{ column, record }">
-                <template v-if="column.dataIndex === 'action'">
-                    <a-space>
-                        <a @click="formRef.onOpen(record)" v-if="hasPerm('forumPostInfoEdit')">编辑</a>
-                        <a-divider type="vertical" v-if="hasPerm(['forumPostInfoEdit', 'forumPostInfoDelete'], 'and')" />
-                        <a-popconfirm title="确定要删除吗?" @confirm="deleteForumPostInfo(record)">
-                            <a-button type="link" danger size="small" v-if="hasPerm('forumPostInfoDelete')">删除</a-button>
-                        </a-popconfirm>
-                    </a-space>
-                </template>
-            </template>
-        </s-table>
-    </a-card>
-    <Form ref="formRef" @successful="table.refresh(true)" />
+	<a-card :bordered="false">
+		<s-table
+			ref="table"
+			:columns="columns"
+			:data="loadData"
+			:alert="options.alert.show"
+			bordered
+			:row-key="(record) => record.postId"
+			:tool-config="toolConfig"
+			:row-selection="options.rowSelection"
+		>
+			<template #operator class="table-operator">
+				<a-space>
+					<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('forumPostInfoAdd')">
+						<template #icon><plus-outlined /></template>
+						新增
+					</a-button>
+					<xn-batch-delete
+						v-if="hasPerm('forumPostInfoBatchDelete')"
+						:selectedRowKeys="selectedRowKeys"
+						@batchDelete="deleteBatchForumPostInfo"
+					/>
+				</a-space>
+			</template>
+			<template #bodyCell="{ column, record }">
+				<template v-if="column.dataIndex === 'action'">
+					<a-space>
+						<a @click="formRef.onOpen(record)" v-if="hasPerm('forumPostInfoEdit')">编辑</a>
+						<a-divider type="vertical" v-if="hasPerm(['forumPostInfoEdit', 'forumPostInfoDelete'], 'and')" />
+						<a-popconfirm title="确定要删除吗?" @confirm="deleteForumPostInfo(record)">
+							<a-button type="link" danger size="small" v-if="hasPerm('forumPostInfoDelete')">删除</a-button>
+						</a-popconfirm>
+					</a-space>
+				</template>
+				<template v-if="column.dataIndex === 'postContent'">
+					<a-tooltip>
+						<template #title>
+							<div class="htmlContent" v-html="record.postContent"></div>
+						</template>
+						<div class="one-line" v-html="record.postContent"></div>
+					</a-tooltip>
+				</template>
+				<template v-if="column.dataIndex === 'lastReplyTime'">
+					<div>{{ formatDateTime(record.lastReplyTime) }}</div>
+				</template>
+				<template v-if="column.dataIndex === 'postType'">
+					<div v-if="record.postType == 0">普通帖子</div>
+					<div v-if="record.postType == 1">技术支持</div>
+					<div v-if="record.postType == 2">内容纠错</div>
+				</template>
+				<template v-if="column.dataIndex === 'postStatus'">
+					<a-switch
+						v-model:checked="record.postStatus"
+						:checkedValue="0"
+						:unCheckedValue="1"
+						checked-children="开"
+						un-checked-children="关"
+						@change="closeItem($event, record)"
+					/>
+				</template>
+				<template v-if="column.dataIndex === 'isTop'">
+					<a-switch
+						v-model:checked="record.isTop"
+						:checkedValue="1"
+						:unCheckedValue="0"
+						checked-children="是"
+						un-checked-children="否"
+						@change="topItem($event, record)"
+					/>
+				</template>
+				<template v-if="column.dataIndex === 'appointUser'">
+					<span v-for="(item, idx) in seltUserList(record.appointUser)">{{ item.name }},</span>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="table.refresh(true)" />
 </template>
 
 <script setup name="postinfo">
-    import Form from './form.vue'
-    import forumPostInfoApi from '@/api/forum/forumPostInfoApi'
-    const table = ref()
-    const formRef = ref()
-    const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
-    const columns = [
-        {
-            title: '分类id',
-            dataIndex: 'typeId'
-        },
-        {
-            title: '用户id',
-            dataIndex: 'userId'
-        },
-        {
-            title: '帖子标题',
-            dataIndex: 'postTitle'
-        },
-        {
-            title: '帖子内容',
-            dataIndex: 'postContent'
-        },
-        {
-            title: '是否置顶 0普通 1置顶',
-            dataIndex: 'isTop'
-        },
-        {
-            title: '浏览次数',
-            dataIndex: 'viewCount'
-        },
-        {
-            title: '回复次数',
-            dataIndex: 'replyCount'
-        },
-        {
-            title: '点赞次数',
-            dataIndex: 'likeCount'
-        },
-        {
-            title: '最后回复用户id',
-            dataIndex: 'lastReplyUserId'
-        },
-        {
-            title: '最后回复时间',
-            dataIndex: 'lastReplyTime'
-        },
-        {
-            title: '帖子类型 0普通帖子 1技术支持 2内容纠错',
-            dataIndex: 'postType'
-        },
-        {
-            title: '定向用户',
-            dataIndex: 'appointUser'
-        },
-    ]
-    // 操作栏通过权限判断是否显示
-    if (hasPerm(['forumPostInfoEdit', 'forumPostInfoDelete'])) {
-        columns.push({
-            title: '操作',
-            dataIndex: 'action',
-            align: 'center',
-            width: '150px'
-        })
-    }
-    const selectedRowKeys = ref([])
-    // 列表选择配置
-    const options = {
-        // columns数字类型字段加入 needTotal: true 可以勾选自动算账
-        alert: {
-            show: true,
-            clear: () => {
-                selectedRowKeys.value = ref([])
-            }
-        },
-        rowSelection: {
-            onChange: (selectedRowKey, selectedRows) => {
-                selectedRowKeys.value = selectedRowKey
-            }
-        }
-    }
-    const loadData = (parameter) => {
-        return forumPostInfoApi.forumPostInfoPage(parameter).then((data) => {
-            return data
-        })
-    }
-    // 重置
-    const reset = () => {
-        searchFormRef.value.resetFields()
-        table.value.refresh(true)
-    }
-    // 删除
-    const deleteForumPostInfo = (record) => {
-        let params = [
-            {
-                postId: record.postId
-            }
-        ]
-        forumPostInfoApi.forumPostInfoDelete(params).then(() => {
-            table.value.refresh(true)
-        })
-    }
-    // 批量删除
-    const deleteBatchForumPostInfo = (params) => {
-        forumPostInfoApi.forumPostInfoDelete(params).then(() => {
-            table.value.clearRefreshSelected()
-        })
-    }
+	import Form from './form.vue'
+	import forumPostInfoApi from '@/api/forum/forumPostInfoApi'
+	import forumApi from '@/api/forum/forumApi'
+	import { parseTime } from '@/utils/exam'
+	const table = ref()
+	const formRef = ref()
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+	const columns = [
+		{
+			title: '用户',
+			dataIndex: 'userNickName'
+		},
+		{
+			title: '帖子标题',
+			dataIndex: 'postTitle',
+			width: 120
+		},
+		{
+			title: '帖子内容',
+			dataIndex: 'postContent',
+			width: 300,
+			ellipsis: true
+		},
+		{
+			title: '状态',
+			dataIndex: 'postStatus'
+		},
+		{
+			title: '是否置顶',
+			dataIndex: 'isTop'
+		},
+		{
+			title: '浏览次数',
+			dataIndex: 'viewCount'
+		},
+		{
+			title: '回复次数',
+			dataIndex: 'replyCount'
+		},
+		{
+			title: '点赞次数',
+			dataIndex: 'likeCount'
+		},
+		{
+			title: '最后回复用户',
+			dataIndex: 'lastReplyUserNickName',
+			width: 120
+		},
+		{
+			title: '最后回复时间',
+			dataIndex: 'lastReplyTime',
+			width: 120
+		},
+		{
+			title: '帖子类型',
+			dataIndex: 'postType'
+		},
+		{
+			title: '定向用户',
+			dataIndex: 'appointUser'
+		}
+	]
+
+	function formatDateTime(val) {
+		if (!val) return ''
+		return parseTime(val, '{y}-{m}-{d} {h}:{i}:{s}')
+	}
+	//用户
+	const usertypeOptions = ref([])
+	// 操作栏通过权限判断是否显示
+	if (hasPerm(['forumPostInfoEdit', 'forumPostInfoDelete'])) {
+		columns.push({
+			title: '操作',
+			dataIndex: 'action',
+			align: 'center',
+			width: '150px'
+		})
+	}
+	const selectedRowKeys = ref([])
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+			}
+		}
+	}
+	const loadData = (parameter) => {
+		return forumPostInfoApi.forumPostInfoPage(parameter).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		table.value.refresh(true)
+	}
+	// 删除
+	const deleteForumPostInfo = (record) => {
+		let params = [
+			{
+				postId: record.postId
+			}
+		]
+		forumPostInfoApi.forumPostInfoDelete(params).then(() => {
+			table.value.refresh(true)
+		})
+	}
+	// 批量删除
+	const deleteBatchForumPostInfo = (params) => {
+		params = params.map((r) => {
+			return {
+				postId: r.id
+			}
+		})
+		forumPostInfoApi.forumPostInfoDelete(params).then(() => {
+			table.value.clearRefreshSelected()
+		})
+	}
+	const closeItem = (event, params) => {
+		forumApi
+			.postinfoStatus({
+				postId: params.postId,
+				postStatus: event
+			})
+			.then((data) => {
+				table.value.refresh(true)
+			})
+	}
+	const topItem = (event, params) => {
+		forumApi
+			.postinfoTop({
+				postId: params.postId,
+				postStatus: event
+			})
+			.then((data) => {
+				table.value.refresh(true)
+			})
+	}
+	const getUserList = () => {
+		forumApi.allUserList().then((data) => {
+			usertypeOptions.value = data.map((r) => {
+				return {
+					label: r.name,
+					value: r.id,
+					...r
+				}
+			})
+		})
+	}
+	getUserList()
+	const seltUserList = (str) => {
+		return usertypeOptions.value.filter((r) => {
+			if (str && str.includes(r.id)) {
+				return r
+			}
+		})
+	}
 </script>
+<style scoped lang="less">
+	.htmlContent {
+		max-height: 400px;
+		overflow-x: auto;
+		:deep(img) {
+			max-width: 100% !important;
+		}
+	}
+
+	.one-line {
+		display: -webkit-box;
+		-webkit-box-orient: vertical;
+		-webkit-line-clamp: 1;
+		overflow: hidden;
+	}
+</style>

+ 110 - 105
src/views/forum/posttype/index.vue

@@ -1,110 +1,115 @@
 <template>
-    <a-card :bordered="false">
-        <s-table
-            ref="table"
-            :columns="columns"
-            :data="loadData"
-            :alert="options.alert.show"
-            bordered
-            :row-key="(record) => record.typeId"
-            :tool-config="toolConfig"
-            :row-selection="options.rowSelection"
-        >
-            <template #operator class="table-operator">
-                <a-space>
-                    <a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('forumPostTypeAdd')">
-                        <template #icon><plus-outlined /></template>
-                        新增
-                    </a-button>
-                    <xn-batch-delete
-                        v-if="hasPerm('forumPostTypeBatchDelete')"
-                        :selectedRowKeys="selectedRowKeys"
-                        @batchDelete="deleteBatchForumPostType"
-                    />
-                </a-space>
-            </template>
-            <template #bodyCell="{ column, record }">
-                <template v-if="column.dataIndex === 'action'">
-                    <a-space>
-                        <a @click="formRef.onOpen(record)" v-if="hasPerm('forumPostTypeEdit')">编辑</a>
-                        <a-divider type="vertical" v-if="hasPerm(['forumPostTypeEdit', 'forumPostTypeDelete'], 'and')" />
-                        <a-popconfirm title="确定要删除吗?" @confirm="deleteForumPostType(record)">
-                            <a-button type="link" danger size="small" v-if="hasPerm('forumPostTypeDelete')">删除</a-button>
-                        </a-popconfirm>
-                    </a-space>
-                </template>
-            </template>
-        </s-table>
-    </a-card>
-    <Form ref="formRef" @successful="table.refresh(true)" />
+	<a-card :bordered="false">
+		<s-table
+			ref="table"
+			:columns="columns"
+			:data="loadData"
+			:alert="options.alert.show"
+			bordered
+			:row-key="(record) => record.typeId"
+			:tool-config="toolConfig"
+			:row-selection="options.rowSelection"
+		>
+			<template #operator class="table-operator">
+				<a-space>
+					<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('forumPostTypeAdd')">
+						<template #icon><plus-outlined /></template>
+						新增
+					</a-button>
+					<xn-batch-delete
+						v-if="hasPerm('forumPostTypeBatchDelete')"
+						:selectedRowKeys="selectedRowKeys"
+						@batchDelete="deleteBatchForumPostType"
+					/>
+				</a-space>
+			</template>
+			<template #bodyCell="{ column, record }">
+				<template v-if="column.dataIndex === 'action'">
+					<a-space>
+						<a @click="formRef.onOpen(record)" v-if="hasPerm('forumPostTypeEdit')">编辑</a>
+						<a-divider type="vertical" v-if="hasPerm(['forumPostTypeEdit', 'forumPostTypeDelete'], 'and')" />
+						<a-popconfirm title="确定要删除吗?" @confirm="deleteForumPostType(record)">
+							<a-button type="link" danger size="small" v-if="hasPerm('forumPostTypeDelete')">删除</a-button>
+						</a-popconfirm>
+					</a-space>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="table.refresh(true)" />
 </template>
 
 <script setup name="posttype">
-    import Form from './form.vue'
-    import forumPostTypeApi from '@/api/forum/forumPostTypeApi'
-    const table = ref()
-    const formRef = ref()
-    const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
-    const columns = [
-        {
-            title: '分类名称',
-            dataIndex: 'typeName'
-        },
-        {
-            title: '分类描述',
-            dataIndex: 'typeDesc'
-        },
-    ]
-    // 操作栏通过权限判断是否显示
-    if (hasPerm(['forumPostTypeEdit', 'forumPostTypeDelete'])) {
-        columns.push({
-            title: '操作',
-            dataIndex: 'action',
-            align: 'center',
-            width: '150px'
-        })
-    }
-    const selectedRowKeys = ref([])
-    // 列表选择配置
-    const options = {
-        // columns数字类型字段加入 needTotal: true 可以勾选自动算账
-        alert: {
-            show: true,
-            clear: () => {
-                selectedRowKeys.value = ref([])
-            }
-        },
-        rowSelection: {
-            onChange: (selectedRowKey, selectedRows) => {
-                selectedRowKeys.value = selectedRowKey
-            }
-        }
-    }
-    const loadData = (parameter) => {
-        return forumPostTypeApi.forumPostTypePage(parameter).then((data) => {
-            return data
-        })
-    }
-    // 重置
-    const reset = () => {
-        searchFormRef.value.resetFields()
-        table.value.refresh(true)
-    }
-    // 删除
-    const deleteForumPostType = (record) => {
-        let params = [
-            {
-                typeId: record.typeId
-            }
-        ]
-        forumPostTypeApi.forumPostTypeDelete(params).then(() => {
-            table.value.refresh(true)
-        })
-    }
-    // 批量删除
-    const deleteBatchForumPostType = (params) => {
-        forumPostTypeApi.forumPostTypeDelete(params).then(() => {
-            table.value.clearRefreshSelected()
-        })
-    }
+	import Form from './form.vue'
+	import forumPostTypeApi from '@/api/forum/forumPostTypeApi'
+	const table = ref()
+	const formRef = ref()
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+	const columns = [
+		{
+			title: '分类名称',
+			dataIndex: 'typeName'
+		},
+		{
+			title: '分类描述',
+			dataIndex: 'typeDesc'
+		}
+	]
+	// 操作栏通过权限判断是否显示
+	if (hasPerm(['forumPostTypeEdit', 'forumPostTypeDelete'])) {
+		columns.push({
+			title: '操作',
+			dataIndex: 'action',
+			align: 'center',
+			width: '150px'
+		})
+	}
+	const selectedRowKeys = ref([])
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+			}
+		}
+	}
+	const loadData = (parameter) => {
+		return forumPostTypeApi.forumPostTypePage(parameter).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		table.value.refresh(true)
+	}
+	// 删除
+	const deleteForumPostType = (record) => {
+		let params = [
+			{
+				typeId: record.typeId
+			}
+		]
+		forumPostTypeApi.forumPostTypeDelete(params).then(() => {
+			table.value.refresh(true)
+		})
+	}
+	// 批量删除
+	const deleteBatchForumPostType = (params) => {
+		params = params.map((r) => {
+			return {
+				typeId: r.id
+			}
+		})
+		forumPostTypeApi.forumPostTypeDelete(params).then(() => {
+			table.value.clearRefreshSelected()
+		})
+	}
 </script>

+ 227 - 80
src/views/forum/reportinfo/form.vue

@@ -1,85 +1,232 @@
 <template>
-    <xn-form-container
-        :title="formData.reportId ? '编辑论坛-帖子举报信息表' : '增加论坛-帖子举报信息表'"
-        :width="700"
-        :visible="visible"
-        :destroy-on-close="true"
-        @close="onClose"
-    >
-        <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
-            <a-form-item label="帖子主键id:" name="postId">
-                <a-input v-model:value="formData.postId" placeholder="请输入帖子主键id" allow-clear />
-            </a-form-item>
-            <a-form-item label="举报人用户id:" name="userId">
-                <a-input v-model:value="formData.userId" placeholder="请输入举报人用户id" allow-clear />
-            </a-form-item>
-            <a-form-item label="举报原因类型 0垃圾广告 1色情内容 2人身攻击 3政治敏感 4其他:" name="reportReasonType">
-                <a-input v-model:value="formData.reportReasonType" placeholder="请输入举报原因类型 0垃圾广告 1色情内容 2人身攻击 3政治敏感 4其他" allow-clear />
-            </a-form-item>
-            <a-form-item label="举报信息描述:" name="reportDetail">
-                <a-input v-model:value="formData.reportDetail" placeholder="请输入举报信息描述" allow-clear />
-            </a-form-item>
-            <a-form-item label="证据图片:" name="evidenceScreenshot">
-                <a-input v-model:value="formData.evidenceScreenshot" placeholder="请输入证据图片" allow-clear />
-            </a-form-item>
-            <a-form-item label="举报处理状态 0待处理 1已关闭帖子 2已驳回:" name="reportStatus">
-                <a-input v-model:value="formData.reportStatus" placeholder="请输入举报处理状态 0待处理 1已关闭帖子 2已驳回" allow-clear />
-            </a-form-item>
-        </a-form>
-        <template #footer>
-            <a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
-            <a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
-        </template>
-    </xn-form-container>
+	<xn-form-container
+		:title="formData.reportId ? '编辑论坛-帖子举报信息表' : '增加论坛-帖子举报信息表'"
+		:width="700"
+		:visible="visible"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-form-item label="帖子:" name="postId">
+				<a-select
+					v-model:value="formData.postId"
+					show-search
+					placeholder="请选择帖子"
+					style="width: 100%"
+					:options="invitationList"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<!-- <a-form-item label="帖子类型:" name="postType">
+				<a-select
+					v-model:value="formData.postType"
+					show-search
+					placeholder="请选择帖子类型"
+					style="width: 100%"
+					:options="invitationType"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="帖子状态:" name="postStatus">
+				<a-select
+					v-model:value="formData.postStatus"
+					show-search
+					placeholder="请选择帖子状态"
+					style="width: 100%"
+					:options="invitationStatus"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item> -->
+			<a-form-item label="举报人:" name="userId">
+				<a-select
+					v-model:value="formData.userId"
+					show-search
+					placeholder="请选择用户"
+					style="width: 100%"
+					:options="usertypeOptions"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="举报原因类型:" name="reportReasonType">
+				<a-select
+					v-model:value="formData.reportReasonType"
+					show-search
+					placeholder="请选择类型"
+					style="width: 100%"
+					:options="reportType"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="举报信息描述:" name="reportDetail">
+				<a-input v-model:value="formData.reportDetail" placeholder="请输入举报信息描述" allow-clear />
+			</a-form-item>
+			<a-form-item label="证据图片:" name="evidenceScreenshot">
+				<UpLoadImg ref="upLoadImgRef" @handlerUpImage="handlerUpImage"></UpLoadImg>
+			</a-form-item>
+			<a-form-item label="举报处理状态:" name="reportStatus">
+				<a-select
+					v-model:value="formData.reportStatus"
+					show-search
+					placeholder="请选择分类"
+					style="width: 100%"
+					:options="statusType"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
 </template>
 
 <script setup name="forumReportInfoForm">
-    import { cloneDeep } from 'lodash-es'
-    import { required } from '@/utils/formRules'
-    import forumReportInfoApi from '@/api/forum/forumReportInfoApi'
-    // 抽屉状态
-    const visible = ref(false)
-    const emit = defineEmits({ successful: null })
-    const formRef = ref()
-    // 表单数据
-    const formData = ref({})
-    const submitLoading = ref(false)
-
-    // 打开抽屉
-    const onOpen = (record) => {
-        visible.value = true
-        if (record) {
-            let recordData = cloneDeep(record)
-            formData.value = Object.assign({}, recordData)
-        }
-    }
-    // 关闭抽屉
-    const onClose = () => {
-        formRef.value.resetFields()
-        formData.value = {}
-        visible.value = false
-    }
-    // 默认要校验的
-    const formRules = {
-    }
-    // 验证并提交数据
-    const onSubmit = () => {
-        formRef.value.validate().then(() => {
-            submitLoading.value = true
-            const formDataParam = cloneDeep(formData.value)
-            forumReportInfoApi
-                .forumReportInfoSubmitForm(formDataParam, formDataParam.reportId)
-                .then(() => {
-                    onClose()
-                    emit('successful')
-                })
-                .finally(() => {
-                    submitLoading.value = false
-                })
-        })
-    }
-    // 抛出函数
-    defineExpose({
-        onOpen
-    })
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import forumReportInfoApi from '@/api/forum/forumReportInfoApi'
+	import forumApi from '@/api/forum/forumApi'
+	// 抽屉状态
+	const visible = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+	//用户
+	const usertypeOptions = ref([])
+	//帖子
+	const invitationList = ref([])
+	//举报原因
+	const reportType = ref([
+		{
+			label: '垃圾广告',
+			value: 0
+		},
+		{
+			label: '色情内容',
+			value: 1
+		},
+		{
+			label: '人身攻击',
+			value: 2
+		},
+		{
+			label: '政治敏感',
+			value: 3
+		},
+		{
+			label: '其他',
+			value: 4
+		}
+	])
+	//状态
+	const statusType = ref([
+		{
+			label: '待处理',
+			value: 0
+		},
+		{
+			label: '已关闭帖子',
+			value: 1
+		},
+		{
+			label: '已驳回',
+			value: 2
+		}
+	])
+	//帖子类型
+	const invitationType = ref([
+		{
+			label:'普通帖子',
+			value:0
+		},
+		{
+			label:'技术支持',
+			value:1
+		},
+		{
+			label:'内容纠错',
+			value:2
+		},
+	])
+	//帖子状态
+	const invitationStatus = ref([
+		{
+			label:'正常',
+			value:0
+		},
+		{
+			label:'关闭',
+			value:1
+		}
+	])
+	//筛选
+	const filterOption = (input, option) => {
+		return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+	}
+	// 打开抽屉
+	const onOpen = (record) => {
+		visible.value = true
+		forumApi.allUserList().then((data) => {
+			usertypeOptions.value = data.map((r) => {
+				return {
+					label: r.name,
+					value: r.id,
+					...r
+				}
+			})
+		})
+		forumApi
+			.forumList({
+				current: 1,
+				size: 999999999,
+				sortOrder: 0
+			})
+			.then((data) => {
+				invitationList.value = data.records.map((r) => {
+					return {
+						label: r.postTitle,
+						value: r.postId,
+						...r
+					}
+				})
+			})
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		visible.value = false
+	}
+	// 默认要校验的
+	const formRules = {}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value.validate().then(() => {
+			submitLoading.value = true
+			const formDataParam = cloneDeep(formData.value)
+			forumReportInfoApi
+				.forumReportInfoSubmitForm(formDataParam, formDataParam.reportId)
+				.then(() => {
+					onClose()
+					emit('successful')
+				})
+				.finally(() => {
+					submitLoading.value = false
+				})
+		})
+	}
+	//选择图片
+	const handlerUpImage = (id) => {
+		formData.value.evidenceScreenshot = id
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
 </script>

ファイルの差分が大きいため隠しています
+ 58 - 38
src/views/forum/reportinfo/index.vue


+ 5 - 0
src/views/forum/sensitivity/index.vue

@@ -115,6 +115,11 @@
     }
     // 批量删除
     const deleteBatchForumSensitivity = (params) => {
+        params = params.map((r) => {
+			return {
+				sensitivityId: r.id
+			}
+		})
         forumSensitivityApi.forumSensitivityDelete(params).then(() => {
             table.value.clearRefreshSelected()
         })

+ 136 - 74
src/views/forum/sensitivityrecord/form.vue

@@ -1,79 +1,141 @@
 <template>
-    <xn-form-container
-        :title="formData.recordId ? '编辑敏感词过滤记录' : '增加敏感词过滤记录'"
-        :width="700"
-        :visible="visible"
-        :destroy-on-close="true"
-        @close="onClose"
-    >
-        <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
-            <a-form-item label="过滤词语:" name="sensitivityWord">
-                <a-input v-model:value="formData.sensitivityWord" placeholder="请输入过滤词语" allow-clear />
-            </a-form-item>
-            <a-form-item label="帖子id:" name="postId">
-                <a-input v-model:value="formData.postId" placeholder="请输入帖子id" allow-clear />
-            </a-form-item>
-            <a-form-item label="过滤类型 0发帖 1回复:" name="recordType">
-                <a-input v-model:value="formData.recordType" placeholder="请输入过滤类型 0发帖 1回复" allow-clear />
-            </a-form-item>
-            <a-form-item label="用户id:" name="userId">
-                <a-input v-model:value="formData.userId" placeholder="请输入用户id" allow-clear />
-            </a-form-item>
-        </a-form>
-        <template #footer>
-            <a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
-            <a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
-        </template>
-    </xn-form-container>
+	<xn-form-container
+		:title="formData.recordId ? '编辑敏感词过滤记录' : '增加敏感词过滤记录'"
+		:width="700"
+		:visible="visible"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-form-item label="过滤词语:" name="sensitivityWord">
+				<a-input v-model:value="formData.sensitivityWord" placeholder="请输入过滤词语" allow-clear />
+			</a-form-item>
+			<a-form-item label="帖子:" name="postId">
+				<a-select
+					v-model:value="formData.typeId"
+					show-search
+					placeholder="请选择帖子"
+					style="width: 100%"
+					:options="invitationList"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="过滤类型:" name="recordType">
+				<a-select
+					v-model:value="formData.recordType"
+					show-search
+					placeholder="请选择类型"
+					style="width: 100%"
+					:options="typeList"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+			<a-form-item label="用户:" name="userId">
+				<a-select
+					v-model:value="formData.userId"
+					show-search
+					placeholder="请选择用户"
+					style="width: 100%"
+					:options="usertypeOptions"
+					:filter-option="filterOption"
+				></a-select>
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
 </template>
 
 <script setup name="forumSensitivityRecordForm">
-    import { cloneDeep } from 'lodash-es'
-    import { required } from '@/utils/formRules'
-    import forumSensitivityRecordApi from '@/api/forum/forumSensitivityRecordApi'
-    // 抽屉状态
-    const visible = ref(false)
-    const emit = defineEmits({ successful: null })
-    const formRef = ref()
-    // 表单数据
-    const formData = ref({})
-    const submitLoading = ref(false)
-
-    // 打开抽屉
-    const onOpen = (record) => {
-        visible.value = true
-        if (record) {
-            let recordData = cloneDeep(record)
-            formData.value = Object.assign({}, recordData)
-        }
-    }
-    // 关闭抽屉
-    const onClose = () => {
-        formRef.value.resetFields()
-        formData.value = {}
-        visible.value = false
-    }
-    // 默认要校验的
-    const formRules = {
-    }
-    // 验证并提交数据
-    const onSubmit = () => {
-        formRef.value.validate().then(() => {
-            submitLoading.value = true
-            const formDataParam = cloneDeep(formData.value)
-            forumSensitivityRecordApi
-                .forumSensitivityRecordSubmitForm(formDataParam, formDataParam.recordId)
-                .then(() => {
-                    onClose()
-                    emit('successful')
-                })
-                .finally(() => {
-                    submitLoading.value = false
-                })
-        })
-    }
-    // 抛出函数
-    defineExpose({
-        onOpen
-    })
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import forumSensitivityRecordApi from '@/api/forum/forumSensitivityRecordApi'
+	import forumApi from '@/api/forum/forumApi'
+	// 抽屉状态
+	const visible = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+	//用户
+	const usertypeOptions = ref([])
+	//帖子
+	const invitationList = ref([])
+	// 打开抽屉
+	const onOpen = (record) => {
+		visible.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+		forumApi.allUserList().then((data) => {
+			usertypeOptions.value = data.map((r) => {
+				return {
+					label: r.name,
+					value: r.id,
+					...r
+				}
+			})
+		})
+		forumApi
+			.forumList({
+				current: 1,
+				size: 999999999,
+				sortOrder: 0
+			})
+			.then((data) => {
+				invitationList.value = data.records.map((r) => {
+					return {
+						label: r.postTitle,
+						value: r.postId,
+						...r
+					}
+				})
+			})
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		visible.value = false
+	}
+	//类型
+	const typeList = ref([
+		{
+			label: '发帖',
+			value: 0
+		},
+		{
+			label: '回复',
+			value: 1
+		}
+	])
+	const filterOption = (input, option) => {
+		return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+	}
+	// 默认要校验的
+	const formRules = {}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value.validate().then(() => {
+			submitLoading.value = true
+			const formDataParam = cloneDeep(formData.value)
+			forumSensitivityRecordApi
+				.forumSensitivityRecordSubmitForm(formDataParam, formDataParam.recordId)
+				.then(() => {
+					onClose()
+					emit('successful')
+				})
+				.finally(() => {
+					submitLoading.value = false
+				})
+		})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
 </script>

+ 138 - 113
src/views/forum/sensitivityrecord/index.vue

@@ -1,118 +1,143 @@
 <template>
-    <a-card :bordered="false">
-        <s-table
-            ref="table"
-            :columns="columns"
-            :data="loadData"
-            :alert="options.alert.show"
-            bordered
-            :row-key="(record) => record.recordId"
-            :tool-config="toolConfig"
-            :row-selection="options.rowSelection"
-        >
-            <template #operator class="table-operator">
-                <a-space>
-                    <a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('forumSensitivityRecordAdd')">
-                        <template #icon><plus-outlined /></template>
-                        新增
-                    </a-button>
-                    <xn-batch-delete
-                        v-if="hasPerm('forumSensitivityRecordBatchDelete')"
-                        :selectedRowKeys="selectedRowKeys"
-                        @batchDelete="deleteBatchForumSensitivityRecord"
-                    />
-                </a-space>
-            </template>
-            <template #bodyCell="{ column, record }">
-                <template v-if="column.dataIndex === 'action'">
-                    <a-space>
-                        <a @click="formRef.onOpen(record)" v-if="hasPerm('forumSensitivityRecordEdit')">编辑</a>
-                        <a-divider type="vertical" v-if="hasPerm(['forumSensitivityRecordEdit', 'forumSensitivityRecordDelete'], 'and')" />
-                        <a-popconfirm title="确定要删除吗?" @confirm="deleteForumSensitivityRecord(record)">
-                            <a-button type="link" danger size="small" v-if="hasPerm('forumSensitivityRecordDelete')">删除</a-button>
-                        </a-popconfirm>
-                    </a-space>
-                </template>
-            </template>
-        </s-table>
-    </a-card>
-    <Form ref="formRef" @successful="table.refresh(true)" />
+	<a-card :bordered="false">
+		<s-table
+			ref="table"
+			:columns="columns"
+			:data="loadData"
+			:alert="options.alert.show"
+			bordered
+			:row-key="(record) => record.recordId"
+			:tool-config="toolConfig"
+			:row-selection="options.rowSelection"
+		>
+			<template #operator class="table-operator">
+				<a-space>
+					<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('forumSensitivityRecordAdd')">
+						<template #icon><plus-outlined /></template>
+						新增
+					</a-button>
+					<xn-batch-delete
+						v-if="hasPerm('forumSensitivityRecordBatchDelete')"
+						:selectedRowKeys="selectedRowKeys"
+						@batchDelete="deleteBatchForumSensitivityRecord"
+					/>
+				</a-space>
+			</template>
+			<template #bodyCell="{ column, record }">
+				<template v-if="column.dataIndex === 'action'">
+					<a-space>
+						<a @click="formRef.onOpen(record)" v-if="hasPerm('forumSensitivityRecordEdit')">编辑</a>
+						<a-divider
+							type="vertical"
+							v-if="hasPerm(['forumSensitivityRecordEdit', 'forumSensitivityRecordDelete'], 'and')"
+						/>
+						<a-popconfirm title="确定要删除吗?" @confirm="deleteForumSensitivityRecord(record)">
+							<a-button type="link" danger size="small" v-if="hasPerm('forumSensitivityRecordDelete')">删除</a-button>
+						</a-popconfirm>
+					</a-space>
+				</template>
+				<template v-if="column.dataIndex === 'recordType'">
+					<div v-if="record.recordType == 0">发帖</div>
+					<div v-if="record.recordType == 1">回复</div>
+				</template>
+				<template v-if="column.dataIndex === 'postTitle'">
+					<a @click="jumpDetail(record)">{{ record.postTitle }}</a>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="table.refresh(true)" />
 </template>
 
 <script setup name="sensitivityrecord">
-    import Form from './form.vue'
-    import forumSensitivityRecordApi from '@/api/forum/forumSensitivityRecordApi'
-    const table = ref()
-    const formRef = ref()
-    const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
-    const columns = [
-        {
-            title: '过滤词语',
-            dataIndex: 'sensitivityWord'
-        },
-        {
-            title: '帖子id',
-            dataIndex: 'postId'
-        },
-        {
-            title: '过滤类型 0发帖 1回复',
-            dataIndex: 'recordType'
-        },
-        {
-            title: '用户id',
-            dataIndex: 'userId'
-        },
-    ]
-    // 操作栏通过权限判断是否显示
-    if (hasPerm(['forumSensitivityRecordEdit', 'forumSensitivityRecordDelete'])) {
-        columns.push({
-            title: '操作',
-            dataIndex: 'action',
-            align: 'center',
-            width: '150px'
-        })
-    }
-    const selectedRowKeys = ref([])
-    // 列表选择配置
-    const options = {
-        // columns数字类型字段加入 needTotal: true 可以勾选自动算账
-        alert: {
-            show: true,
-            clear: () => {
-                selectedRowKeys.value = ref([])
-            }
-        },
-        rowSelection: {
-            onChange: (selectedRowKey, selectedRows) => {
-                selectedRowKeys.value = selectedRowKey
-            }
-        }
-    }
-    const loadData = (parameter) => {
-        return forumSensitivityRecordApi.forumSensitivityRecordPage(parameter).then((data) => {
-            return data
-        })
-    }
-    // 重置
-    const reset = () => {
-        searchFormRef.value.resetFields()
-        table.value.refresh(true)
-    }
-    // 删除
-    const deleteForumSensitivityRecord = (record) => {
-        let params = [
-            {
-                recordId: record.recordId
-            }
-        ]
-        forumSensitivityRecordApi.forumSensitivityRecordDelete(params).then(() => {
-            table.value.refresh(true)
-        })
-    }
-    // 批量删除
-    const deleteBatchForumSensitivityRecord = (params) => {
-        forumSensitivityRecordApi.forumSensitivityRecordDelete(params).then(() => {
-            table.value.clearRefreshSelected()
-        })
-    }
+	import Form from './form.vue'
+	import forumSensitivityRecordApi from '@/api/forum/forumSensitivityRecordApi'
+	import { useRoute, useRouter } from 'vue-router'
+	const router = useRouter()
+	const table = ref()
+	const formRef = ref()
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+	const columns = [
+		{
+			title: '过滤词语',
+			dataIndex: 'sensitivityWord'
+		},
+		{
+			title: '帖子标题',
+			dataIndex: 'postTitle'
+		},
+		{
+			title: '过滤类型',
+			dataIndex: 'recordType'
+		},
+		{
+			title: '用户',
+			dataIndex: 'userNickname'
+		}
+	]
+	// 操作栏通过权限判断是否显示
+	if (hasPerm(['forumSensitivityRecordEdit', 'forumSensitivityRecordDelete'])) {
+		columns.push({
+			title: '操作',
+			dataIndex: 'action',
+			align: 'center',
+			width: '150px'
+		})
+	}
+	const selectedRowKeys = ref([])
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+			}
+		}
+	}
+	const loadData = (parameter) => {
+		return forumSensitivityRecordApi.forumSensitivityRecordPage(parameter).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		table.value.refresh(true)
+	}
+	// 删除
+	const deleteForumSensitivityRecord = (record) => {
+		let params = [
+			{
+				recordId: record.recordId
+			}
+		]
+		forumSensitivityRecordApi.forumSensitivityRecordDelete(params).then(() => {
+			table.value.refresh(true)
+		})
+	}
+	// 批量删除
+	const deleteBatchForumSensitivityRecord = (params) => {
+		params = params.map((r) => {
+			return {
+				recordId: r.id
+			}
+		})
+		forumSensitivityRecordApi.forumSensitivityRecordDelete(params).then(() => {
+			table.value.clearRefreshSelected()
+		})
+	}
+	const jumpDetail = (event) => {
+		router.push({
+			path: '/forum/detail',
+			query: {
+				postId: event.postId,
+			}
+		})
+	}
 </script>

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません