提交 43bde8c6 authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 cdcb443e
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.0.6", "@element-plus/icons-vue": "^2.0.6",
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"@vueuse/core": "^9.1.0",
"axios": "^0.27.2", "axios": "^0.27.2",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"element-plus": "^2.2.12", "element-plus": "^2.2.12",
...@@ -371,9 +372,9 @@ ...@@ -371,9 +372,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/web-bluetooth": { "node_modules/@types/web-bluetooth": {
"version": "0.0.14", "version": "0.0.15",
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz", "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==" "integrity": "sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA=="
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.33.0", "version": "5.33.0",
...@@ -747,52 +748,55 @@ ...@@ -747,52 +748,55 @@
} }
}, },
"node_modules/@vueuse/core": { "node_modules/@vueuse/core": {
"version": "8.9.4", "version": "9.1.0",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-8.9.4.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.1.0.tgz",
"integrity": "sha512-B/Mdj9TK1peFyWaPof+Zf/mP9XuGAngaJZBwPaXBvU3aCTZlx3ltlrFFFyMV4iGBwsjSCeUCgZrtkEj9dS2Y3Q==", "integrity": "sha512-BIroqvXEqt826aE9r3K5cox1zobuPuAzdYJ36kouC2TVhlXvFKIILgFVWrpp9HZPwB3aLzasmG3K87q7TSyXZg==",
"dependencies": { "dependencies": {
"@types/web-bluetooth": "^0.0.14", "@types/web-bluetooth": "^0.0.15",
"@vueuse/metadata": "8.9.4", "@vueuse/metadata": "9.1.0",
"@vueuse/shared": "8.9.4", "@vueuse/shared": "9.1.0",
"vue-demi": "*" "vue-demi": "*"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.13.8",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.8.tgz",
"integrity": "sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
}, },
"peerDependencies": { "peerDependencies": {
"@vue/composition-api": "^1.1.0", "@vue/composition-api": "^1.0.0-rc.1",
"vue": "^2.6.0 || ^3.2.0" "vue": "^3.0.0-0 || ^2.6.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@vue/composition-api": { "@vue/composition-api": {
"optional": true "optional": true
},
"vue": {
"optional": true
} }
} }
}, },
"node_modules/@vueuse/core/node_modules/@vueuse/shared": { "node_modules/@vueuse/metadata": {
"version": "8.9.4", "version": "9.1.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.9.4.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.1.0.tgz",
"integrity": "sha512-wt+T30c4K6dGRMVqPddexEVLa28YwxW5OFIPmzUHICjphfAuBFTTdDoyqREZNDOFJZ44ARH1WWQNCUK8koJ+Ag==", "integrity": "sha512-8OEhlog1iaAGTD3LICZ8oBGQdYeMwByvXetOtAOZCJOzyCRSwqwdggTsmVZZ1rkgYIEqgUBk942AsAPwM21s6A=="
},
"node_modules/@vueuse/shared": {
"version": "9.1.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.1.0.tgz",
"integrity": "sha512-pB/3njQu4tfJJ78ajELNda0yMG6lKfpToQW7Soe09CprF1k3QuyoNi1tBNvo75wBDJWD+LOnr+c4B5HZ39jY/Q==",
"dependencies": { "dependencies": {
"vue-demi": "*" "vue-demi": "*"
},
"peerDependencies": {
"@vue/composition-api": "^1.1.0",
"vue": "^2.6.0 || ^3.2.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"vue": {
"optional": true
}
} }
}, },
"node_modules/@vueuse/core/node_modules/vue-demi": { "node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.13.6", "version": "0.13.8",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.6.tgz", "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.8.tgz",
"integrity": "sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==", "integrity": "sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==",
"hasInstallScript": true, "hasInstallScript": true,
"bin": { "bin": {
"vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-fix": "bin/vue-demi-fix.js",
...@@ -811,11 +815,6 @@ ...@@ -811,11 +815,6 @@
} }
} }
}, },
"node_modules/@vueuse/metadata": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.9.4.tgz",
"integrity": "sha512-IwSfzH80bnJMzqhaapqJl9JRIiyQU0zsRGEgnxN6jhq7992cPUJIRfV+JHRIZXjYqbwt07E1gTEp0R0zPJ1aqw=="
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.8.0", "version": "8.8.0",
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.0.tgz", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.0.tgz",
...@@ -1458,6 +1457,81 @@ ...@@ -1458,6 +1457,81 @@
"vue": "^3.2.0" "vue": "^3.2.0"
} }
}, },
"node_modules/element-plus/node_modules/@types/web-bluetooth": {
"version": "0.0.14",
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
},
"node_modules/element-plus/node_modules/@vueuse/core": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-8.9.4.tgz",
"integrity": "sha512-B/Mdj9TK1peFyWaPof+Zf/mP9XuGAngaJZBwPaXBvU3aCTZlx3ltlrFFFyMV4iGBwsjSCeUCgZrtkEj9dS2Y3Q==",
"dependencies": {
"@types/web-bluetooth": "^0.0.14",
"@vueuse/metadata": "8.9.4",
"@vueuse/shared": "8.9.4",
"vue-demi": "*"
},
"peerDependencies": {
"@vue/composition-api": "^1.1.0",
"vue": "^2.6.0 || ^3.2.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"vue": {
"optional": true
}
}
},
"node_modules/element-plus/node_modules/@vueuse/core/node_modules/@vueuse/shared": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.9.4.tgz",
"integrity": "sha512-wt+T30c4K6dGRMVqPddexEVLa28YwxW5OFIPmzUHICjphfAuBFTTdDoyqREZNDOFJZ44ARH1WWQNCUK8koJ+Ag==",
"dependencies": {
"vue-demi": "*"
},
"peerDependencies": {
"@vue/composition-api": "^1.1.0",
"vue": "^2.6.0 || ^3.2.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"vue": {
"optional": true
}
}
},
"node_modules/element-plus/node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.13.8",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.8.tgz",
"integrity": "sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/element-plus/node_modules/@vueuse/metadata": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.9.4.tgz",
"integrity": "sha512-IwSfzH80bnJMzqhaapqJl9JRIiyQU0zsRGEgnxN6jhq7992cPUJIRfV+JHRIZXjYqbwt07E1gTEp0R0zPJ1aqw=="
},
"node_modules/end-of-stream": { "node_modules/end-of-stream": {
"version": "1.4.4", "version": "1.4.4",
"resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz", "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz",
...@@ -4936,9 +5010,9 @@ ...@@ -4936,9 +5010,9 @@
"dev": true "dev": true
}, },
"@types/web-bluetooth": { "@types/web-bluetooth": {
"version": "0.0.14", "version": "0.0.15",
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz", "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==" "integrity": "sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA=="
}, },
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "5.33.0", "version": "5.33.0",
...@@ -5226,37 +5300,45 @@ ...@@ -5226,37 +5300,45 @@
"requires": {} "requires": {}
}, },
"@vueuse/core": { "@vueuse/core": {
"version": "8.9.4", "version": "9.1.0",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-8.9.4.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.1.0.tgz",
"integrity": "sha512-B/Mdj9TK1peFyWaPof+Zf/mP9XuGAngaJZBwPaXBvU3aCTZlx3ltlrFFFyMV4iGBwsjSCeUCgZrtkEj9dS2Y3Q==", "integrity": "sha512-BIroqvXEqt826aE9r3K5cox1zobuPuAzdYJ36kouC2TVhlXvFKIILgFVWrpp9HZPwB3aLzasmG3K87q7TSyXZg==",
"requires": { "requires": {
"@types/web-bluetooth": "^0.0.14", "@types/web-bluetooth": "^0.0.15",
"@vueuse/metadata": "8.9.4", "@vueuse/metadata": "9.1.0",
"@vueuse/shared": "8.9.4", "@vueuse/shared": "9.1.0",
"vue-demi": "*" "vue-demi": "*"
}, },
"dependencies": { "dependencies": {
"vue-demi": {
"version": "0.13.8",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.8.tgz",
"integrity": "sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==",
"requires": {}
}
}
},
"@vueuse/metadata": {
"version": "9.1.0",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.1.0.tgz",
"integrity": "sha512-8OEhlog1iaAGTD3LICZ8oBGQdYeMwByvXetOtAOZCJOzyCRSwqwdggTsmVZZ1rkgYIEqgUBk942AsAPwM21s6A=="
},
"@vueuse/shared": { "@vueuse/shared": {
"version": "8.9.4", "version": "9.1.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.9.4.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.1.0.tgz",
"integrity": "sha512-wt+T30c4K6dGRMVqPddexEVLa28YwxW5OFIPmzUHICjphfAuBFTTdDoyqREZNDOFJZ44ARH1WWQNCUK8koJ+Ag==", "integrity": "sha512-pB/3njQu4tfJJ78ajELNda0yMG6lKfpToQW7Soe09CprF1k3QuyoNi1tBNvo75wBDJWD+LOnr+c4B5HZ39jY/Q==",
"requires": { "requires": {
"vue-demi": "*" "vue-demi": "*"
}
}, },
"dependencies": {
"vue-demi": { "vue-demi": {
"version": "0.13.6", "version": "0.13.8",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.6.tgz", "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.8.tgz",
"integrity": "sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==", "integrity": "sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==",
"requires": {} "requires": {}
} }
} }
}, },
"@vueuse/metadata": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.9.4.tgz",
"integrity": "sha512-IwSfzH80bnJMzqhaapqJl9JRIiyQU0zsRGEgnxN6jhq7992cPUJIRfV+JHRIZXjYqbwt07E1gTEp0R0zPJ1aqw=="
},
"acorn": { "acorn": {
"version": "8.8.0", "version": "8.8.0",
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.0.tgz", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.0.tgz",
...@@ -5774,6 +5856,45 @@ ...@@ -5774,6 +5856,45 @@
"lodash-unified": "^1.0.2", "lodash-unified": "^1.0.2",
"memoize-one": "^6.0.0", "memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0" "normalize-wheel-es": "^1.2.0"
},
"dependencies": {
"@types/web-bluetooth": {
"version": "0.0.14",
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
},
"@vueuse/core": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-8.9.4.tgz",
"integrity": "sha512-B/Mdj9TK1peFyWaPof+Zf/mP9XuGAngaJZBwPaXBvU3aCTZlx3ltlrFFFyMV4iGBwsjSCeUCgZrtkEj9dS2Y3Q==",
"requires": {
"@types/web-bluetooth": "^0.0.14",
"@vueuse/metadata": "8.9.4",
"@vueuse/shared": "8.9.4",
"vue-demi": "*"
},
"dependencies": {
"@vueuse/shared": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.9.4.tgz",
"integrity": "sha512-wt+T30c4K6dGRMVqPddexEVLa28YwxW5OFIPmzUHICjphfAuBFTTdDoyqREZNDOFJZ44ARH1WWQNCUK8koJ+Ag==",
"requires": {
"vue-demi": "*"
}
},
"vue-demi": {
"version": "0.13.8",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.8.tgz",
"integrity": "sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==",
"requires": {}
}
}
},
"@vueuse/metadata": {
"version": "8.9.4",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.9.4.tgz",
"integrity": "sha512-IwSfzH80bnJMzqhaapqJl9JRIiyQU0zsRGEgnxN6jhq7992cPUJIRfV+JHRIZXjYqbwt07E1gTEp0R0zPJ1aqw=="
}
} }
}, },
"end-of-stream": { "end-of-stream": {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.0.6", "@element-plus/icons-vue": "^2.0.6",
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"@vueuse/core": "^9.1.0",
"axios": "^0.27.2", "axios": "^0.27.2",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"element-plus": "^2.2.12", "element-plus": "^2.2.12",
......
...@@ -24,13 +24,11 @@ withDefaults(defineProps<{ sidebar?: boolean; hasTitle?: boolean }>(), { ...@@ -24,13 +24,11 @@ withDefaults(defineProps<{ sidebar?: boolean; hasTitle?: boolean }>(), {
<style lang="scss"> <style lang="scss">
.app-layout { .app-layout {
display: flex;
flex-direction: column;
min-height: 100vh; min-height: 100vh;
background-color: #f8f8f8; background-color: #f8f8f8;
} }
.app-layout-container { .app-layout-container {
flex: 1; height: calc(100vh - 70px);
display: flex; display: flex;
} }
</style> </style>
...@@ -22,7 +22,7 @@ export function getExperimentVideoPlayInfo(params: { source_id: string }) { ...@@ -22,7 +22,7 @@ export function getExperimentVideoPlayInfo(params: { source_id: string }) {
// 获取实验讨论交流 // 获取实验讨论交流
export function getExperimentDiscussList(params: { export function getExperimentDiscussList(params: {
experiment_id: string experiment_id: string
tag: string tag: number
page?: number page?: number
'per-page'?: number 'per-page'?: number
}) { }) {
......
<script setup lang="ts"> <script setup lang="ts">
import type { ExperimentDiscussType } from '../types' import type { ExperimentDiscussType } from '../types'
import { getExperimentDiscussList } from '../api' import { Loading } from '@element-plus/icons-vue'
import { useInfiniteScroll } from '@vueuse/core'
import DiscussItem from './DiscussItem.vue' import DiscussItem from './DiscussItem.vue'
import { getExperimentDiscussList } from '../api'
const DiscussAddDialog = defineAsyncComponent(() => import('./DiscussAddDialog.vue')) const DiscussAddDialog = defineAsyncComponent(() => import('./DiscussAddDialog.vue'))
interface Props { interface Props {
experiment_id?: string experiment_id?: string
} }
const props = defineProps<Props>() const props = defineProps<Props>()
const discussTag = $ref('1') const params = reactive({ tag: 3, page: 0, 'per-page': 10 })
let list = $ref<ExperimentDiscussType[]>([]) let list = $ref<ExperimentDiscussType[]>([])
let hasMore = $ref(false)
let isLoading = $ref(false)
function fetchInfo() { function fetchInfo() {
if (!props.experiment_id) return if (!props.experiment_id) return
getExperimentDiscussList({ experiment_id: props.experiment_id, tag: discussTag }).then(res => { isLoading = true
list = res.data.list getExperimentDiscussList({ ...params, experiment_id: props.experiment_id })
.then(res => {
list = params.page ? [...list, ...res.data.list] : res.data.list
hasMore = !!res.data.list.length
})
.finally(() => {
isLoading = false
}) })
} }
watchEffect(() => { onMounted(() => {
fetchInfo() fetchInfo()
}) })
...@@ -25,10 +35,29 @@ const isEmpty = $computed(() => { ...@@ -25,10 +35,29 @@ const isEmpty = $computed(() => {
}) })
const dialogVisible = $ref(false) const dialogVisible = $ref(false)
// 刷新
function handleRefetch() {
params.page = 0
fetchInfo()
}
// 滚动加载
const scrollRef = ref<HTMLElement>()
useInfiniteScroll(
scrollRef,
() => {
if (!hasMore) return
params.page++
fetchInfo()
},
{ distance: 10 }
)
</script> </script>
<template> <template>
<el-radio-group v-model="discussTag"> <div class="discuss">
<el-radio-group v-model="params.tag" @change="handleRefetch">
<el-radio :label="1">我发起的</el-radio> <el-radio :label="1">我发起的</el-radio>
<el-radio :label="2">我回复的</el-radio> <el-radio :label="2">我回复的</el-radio>
<el-radio :label="3">我的小组</el-radio> <el-radio :label="3">我的小组</el-radio>
...@@ -39,11 +68,45 @@ const dialogVisible = $ref(false) ...@@ -39,11 +68,45 @@ const dialogVisible = $ref(false)
</el-row> </el-row>
<el-empty description="暂无数据" v-if="isEmpty" /> <el-empty description="暂无数据" v-if="isEmpty" />
<template v-else> <template v-else>
<DiscussItem v-for="item in list" :key="item.id" :data="item"></DiscussItem> <div class="discuss-scroll" ref="scrollRef">
<DiscussItem v-for="item in list" :key="item.id" :data="item" @update="handleRefetch"></DiscussItem>
<div class="tips" v-if="isLoading">
<el-icon class="is-loading">
<Loading />
</el-icon>
加载中...
</div>
</div>
</template> </template>
</div>
<!-- 发表新话题 --> <!-- 发表新话题 -->
<DiscussAddDialog v-model="dialogVisible" v-if="dialogVisible"></DiscussAddDialog> <DiscussAddDialog
v-model="dialogVisible"
:experiment_id="experiment_id"
@update="handleRefetch"
v-if="dialogVisible && experiment_id"
></DiscussAddDialog>
</template> </template>
<style lang="scss" scoped></style> <style lang="scss" scoped>
.discuss {
display: flex;
height: 100%;
flex-direction: column;
.el-radio {
margin-right: 12px;
}
}
.discuss-scroll {
flex: 1;
overflow-y: auto;
}
.tips {
padding: 40px;
color: #555;
text-align: center;
}
.el-icon.is-loading {
animation: rotating 2s linear infinite;
}
</style>
<script setup lang="ts"> <script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
// import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { addExperimentDiscuss } from '../api'
interface Props { interface Props {
data?: any experiment_id: string
} }
const props = defineProps<Props>() const props = defineProps<Props>()
defineEmits<{ const emit = defineEmits<{
(e: 'update'): void (e: 'update'): void
(e: 'update:modelValue', visible: boolean): void (e: 'update:modelValue', visible: boolean): void
}>() }>()
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
const form = reactive({ title: '', content: '' }) const form = reactive({ title: '', content: '' })
watchEffect(() => {
Object.assign(form, props.data)
})
const rules = ref<FormRules>({ const rules = ref<FormRules>({
title: [{ required: true, message: '请输入话题标题', trigger: 'blur' }], title: [{ required: true, message: '请输入话题标题', trigger: 'blur' }],
content: [{ required: true, message: '请输入话题描述', trigger: 'blur' }] content: [{ required: true, message: '请输入话题描述', trigger: 'blur' }]
}) })
// 提交 // 提交
function handleSubmit() { function handleSubmit() {
formRef?.validate().then(update) formRef?.validate().then(handleAdd)
} }
// 修改 // 创建话题
const update = () => { function handleAdd() {
// submitSuggestion(form).then(() => { const params = { ...form, experiment_id: props.experiment_id }
// ElMessage({ message: '提交成功', type: 'success' }) addExperimentDiscuss(params).then(() => {
// emit('update') ElMessage({ message: '发表成功', type: 'success' })
// formRef?.resetFields() emit('update')
// }) emit('update:modelValue', false)
})
} }
</script> </script>
<template> <template>
<el-dialog title="发表新话题" :close-on-click-modal="false" width="600px"> <el-dialog
title="发表新话题"
:close-on-click-modal="false"
width="600px"
@update:modelValue="$emit('update:modelValue')"
>
<el-form ref="formRef" :model="form" :rules="rules"> <el-form ref="formRef" :model="form" :rules="rules">
<el-form-item label="话题标题" prop="title"> <el-form-item label="话题标题" prop="title">
<el-input v-model="form.title"></el-input> <el-input v-model="form.title"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="话题描述" prop="content"> <el-form-item label="话题描述" prop="content">
<el-input type="textarea" v-model="form.content" /> <el-input type="textarea" v-model="form.content" :autosize="{ minRows: 4, maxRows: 6 }" />
</el-form-item> </el-form-item>
<el-row justify="center"> <el-row justify="center">
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button> <el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button>
......
<script setup lang="ts"> <script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
// import { ElMessage } from 'element-plus' import type { ExperimentDiscussType } from '../types'
import { ElMessage } from 'element-plus'
import { addExperimentDiscussComment } from '../api'
interface Props { interface Props {
data?: any data: ExperimentDiscussType
} }
const props = defineProps<Props>() const props = defineProps<Props>()
defineEmits<{ const emit = defineEmits<{
(e: 'update'): void (e: 'update'): void
(e: 'update:modelValue', visible: boolean): void (e: 'update:modelValue', visible: boolean): void
}>() }>()
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
const form = reactive({ content: '' }) const form = reactive({ content: '' })
watchEffect(() => {
Object.assign(form, props.data)
})
const rules = ref<FormRules>({ const rules = ref<FormRules>({
content: [{ required: true, message: '请输入话题评论内容', trigger: 'blur' }] content: [{ required: true, message: '请输入话题评论内容', trigger: 'blur' }]
}) })
// 提交 // 提交
function handleSubmit() { function handleSubmit() {
formRef?.validate().then(update) formRef?.validate().then(handleAdd)
} }
// 修改 // 发布评论
const update = () => { function handleAdd() {
// submitSuggestion(form).then(() => { const params = { ...form, discussion_id: props.data.id }
// ElMessage({ message: '提交成功', type: 'success' }) addExperimentDiscussComment(params).then(() => {
// emit('update') ElMessage({ message: '评论成功', type: 'success' })
// formRef?.resetFields() emit('update')
// }) emit('update:modelValue', false)
})
} }
</script> </script>
<template> <template>
<el-dialog title="话题评论" :close-on-click-modal="false" width="600px"> <el-dialog
title="话题评论"
:close-on-click-modal="false"
width="600px"
@update:modelValue="$emit('update:modelValue')"
>
<el-form ref="formRef" :model="form" :rules="rules"> <el-form ref="formRef" :model="form" :rules="rules">
<el-form-item prop="content"> <el-form-item prop="content">
<el-input type="textarea" v-model="form.content" /> <el-input type="textarea" v-model="form.content" :autosize="{ minRows: 4, maxRows: 6 }" />
</el-form-item> </el-form-item>
<el-row justify="center"> <el-row justify="center">
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button> <el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button>
......
<script setup lang="ts"> <script setup lang="ts">
import type { ExperimentDiscussType } from '../types' import type { ExperimentDiscussType } from '../types'
import { ChatLineRound } from '@element-plus/icons-vue'
const DiscussCommentAddDialog = defineAsyncComponent(() => import('./DiscussCommentAddDialog.vue')) const DiscussCommentAddDialog = defineAsyncComponent(() => import('./DiscussCommentAddDialog.vue'))
...@@ -8,35 +9,117 @@ interface Props { ...@@ -8,35 +9,117 @@ interface Props {
} }
defineProps<Props>() defineProps<Props>()
defineEmits<{
(e: 'update'): void
}>()
const commentDialogVisible = $ref(false) const commentDialogVisible = $ref(false)
const commentVisible = $ref(false)
const commentButtonText = $computed(() => (commentVisible ? '收起' : '展开'))
</script> </script>
<template> <template>
<div class="discuss-item"> <div class="discuss-item">
<div class="discuss-item-user"> <div class="discuss-box">
<img src="" /> <div class="discuss-box-user">
<p></p> <img :src="data.sso_user.avatar" />
<p>{{ data.sso_user.real_name || data.sso_user.nickname || data.sso_user.username }}</p>
</div>
<div class="discuss-box-main">
<div class="discuss-box-header">
<p class="discuss-box-time">{{ data.created_time }}</p>
<div class="tools">
<el-button size="small" type="primary" plain round @click="commentVisible = !commentVisible">
{{ commentButtonText }}
</el-button>
<el-icon><ChatLineRound></ChatLineRound></el-icon>{{ data.reply_count }}
</div>
</div>
<h3>{{ data.title }}</h3>
<div class="discuss-box-content" v-html="data.content"></div>
</div>
</div>
<template v-if="commentVisible">
<div class="discuss-box discuss-comment" v-for="item in data.replies" :key="item.id">
<div class="discuss-box-user">
<img :src="item.sso_user.avatar" />
<p>{{ item.sso_user.real_name || item.sso_user.nickname || item.sso_user.username }}</p>
</div> </div>
<div class="discuss-item-main"></div> <div class="discuss-box-main">
<p class="discuss-box-time">{{ item.created_time }}</p>
<div class="discuss-box-content" v-html="item.content"></div>
</div> </div>
<el-row justify="end"> </div>
<el-button round type="primary" @click="commentDialogVisible = true">我要评论</el-button> </template>
<el-row justify="end" style="margin-top: 10px">
<el-button round type="primary" size="small" @click="commentDialogVisible = true">我要评论</el-button>
</el-row> </el-row>
</div>
<!-- 我要评论 --> <!-- 我要评论 -->
<DiscussCommentAddDialog v-model="commentDialogVisible" v-if="commentDialogVisible"></DiscussCommentAddDialog> <DiscussCommentAddDialog
:data="data"
v-model="commentDialogVisible"
@update="$emit('update')"
v-if="commentDialogVisible"
></DiscussCommentAddDialog>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.video-item { .discuss-item {
h2 { margin-top: 10px;
font-size: 16px; padding: 10px 0;
color: #333; border-top: 1px dashed #ccc;
margin-bottom: 10px; }
text-align: center; .discuss-box {
display: flex;
margin: 10px 0;
padding: 10px;
font-size: 12px;
color: var(--main-color);
border-radius: 10px;
border: 1px solid var(--main-color);
&.discuss-comment {
margin-left: 40px;
color: #016fa0;
border: 1px solid #016fa0;
} }
}
.discuss-box-user {
img { img {
width: 100%; width: 50px;
height: 200px; height: 50px;
border-radius: 50%;
overflow: hidden;
object-fit: cover; object-fit: cover;
} }
p {
text-align: center;
}
}
.discuss-box-main {
flex: 1;
padding-left: 10px;
h3 {
font-size: 14px;
font-weight: 500;
}
}
.discuss-box-content {
padding: 5px 0;
color: #555;
}
.discuss-box-header {
display: flex;
align-items: center;
justify-content: space-between;
.tools {
display: flex;
align-items: center;
.el-icon {
font-size: 16px;
margin-left: 10px;
margin-right: 5px;
color: #333333;
}
}
} }
</style> </style>
...@@ -137,8 +137,10 @@ onUnmounted(() => { ...@@ -137,8 +137,10 @@ onUnmounted(() => {
padding: 20px; padding: 20px;
background-color: rgba(45, 48, 55, 1); background-color: rgba(45, 48, 55, 1);
border-radius: 6px; border-radius: 6px;
box-sizing: border-box;
.el-tabs { .el-tabs {
flex: 1; flex: 1;
overflow: hidden;
} }
:deep(.el-tabs__content) { :deep(.el-tabs__content) {
height: calc(100% - 40px); height: calc(100% - 40px);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论