Assessment.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <template>
  2. <div class="assessment-admin admin-page">
  3. <el-card class="config-card">
  4. <div slot="header" class="admin-page-header">
  5. <span class="admin-page-title">💰 积分配置</span>
  6. </div>
  7. <el-form :model="pointsConfig" label-width="120px">
  8. <el-form-item label="完成获得积分">
  9. <el-input-number v-model="pointsConfig.pointsValue" :min="1" :max="1000" />
  10. <span class="form-tip">分</span>
  11. </el-form-item>
  12. <el-form-item label="1积分等于">
  13. <el-input-number v-model="pointsConfig.pointsValueYuan" :min="0.01" :max="10" :precision="2" />
  14. <span class="form-tip">元</span>
  15. </el-form-item>
  16. <el-form-item>
  17. <el-button type="primary" @click="savePointsConfig">保存配置</el-button>
  18. </el-form-item>
  19. </el-form>
  20. </el-card>
  21. <el-card class="materials-card">
  22. <div slot="header" class="admin-page-header">
  23. <span class="admin-page-title">📚 测评资料</span>
  24. <el-input v-model="keyword" placeholder="搜索测评资料..." prefix-icon="el-icon-search" style="width:200px" clearable @keyup.enter.native="handleSearch" @clear="handleSearch" />
  25. <div class="admin-page-actions">
  26. <el-button type="primary" size="small" @click="showCreateDialog">添加资料</el-button>
  27. </div>
  28. </div>
  29. <div class="table-scroll-wrap-sm">
  30. <el-table :max-height="tableHeight" :data="filteredData" border stripe>
  31. <el-table-column prop="id" label="ID" width="60" />
  32. <el-table-column prop="title" label="标题" />
  33. <el-table-column prop="content" label="内容" show-overflow-tooltip />
  34. <el-table-column prop="status" label="状态" width="80">
  35. <template slot-scope="scope">
  36. <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'" size="small">
  37. {{ scope.row.status === 'active' ? '启用' : '停用' }}
  38. </el-tag>
  39. </template>
  40. </el-table-column>
  41. <el-table-column prop="createdAt" label="创建时间" width="160" />
  42. <el-table-column label="操作" width="180" fixed="right">
  43. <template slot-scope="{ row }">
  44. <el-button size="mini" type="primary" @click="editMaterial(row)">编辑</el-button>
  45. <el-dropdown trigger="hover" @command="(cmd) => handleActionCmd(row, cmd)">
  46. <el-button size="mini">
  47. 更多<i class="el-icon-arrow-down el-icon--right"></i>
  48. </el-button>
  49. <el-dropdown-menu slot="dropdown">
  50. <el-dropdown-item command="toggle" :icon="row.status === 'active' ? 'el-icon-circle-close' : 'el-icon-circle-check'">
  51. {{ row.status === 'active' ? '停用' : '启用' }}
  52. </el-dropdown-item>
  53. </el-dropdown-menu>
  54. </el-dropdown>
  55. </template>
  56. </el-table-column>
  57. </el-table>
  58. </div>
  59. </el-card>
  60. <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="600px">
  61. <el-form :model="materialForm" label-width="100px">
  62. <el-form-item label="标题">
  63. <el-input v-model="materialForm.title" placeholder="请输入测评资料标题" />
  64. </el-form-item>
  65. <el-form-item label="内容介绍">
  66. <el-input type="textarea" v-model="materialForm.content" :rows="6" placeholder="请输入测评详细介绍" />
  67. </el-form-item>
  68. <el-form-item label="封面图片(可选)">
  69. <el-input v-model="materialForm.coverImage" placeholder="图片URL地址" />
  70. </el-form-item>
  71. </el-form>
  72. <div slot="footer">
  73. <el-button @click="dialogVisible = false">取消</el-button>
  74. <el-button type="primary" @click="saveMaterial">保存</el-button>
  75. </div>
  76. </el-dialog>
  77. </div>
  78. </template>
  79. <script>
  80. import { getAssessmentMaterials, createAssessmentMaterial, updateAssessmentMaterial, getAssessmentConfig, updateAssessmentConfig } from '@/api/assessment'
  81. export default {
  82. name: 'AssessmentAdmin',
  83. data() {
  84. return {
  85. pointsConfig: {
  86. pointsValue: 100,
  87. pointsValueYuan: 0.01
  88. },
  89. materials: [],
  90. dialogVisible: false,
  91. dialogTitle: '添加测评资料',
  92. materialForm: {
  93. id: null,
  94. title: '',
  95. content: '',
  96. coverImage: ''
  97. },
  98. keyword: ''
  99. }
  100. },
  101. computed: {
  102. tableHeight() {
  103. return window.innerHeight - 300
  104. },
  105. filteredData() {
  106. if (!this.keyword) return this.materials
  107. const kw = this.keyword.toLowerCase()
  108. return this.materials.filter(item =>
  109. [item.title, item.content].some(v => (v||'').toLowerCase().includes(kw))
  110. )
  111. }
  112. },
  113. mounted() {
  114. this.loadConfig()
  115. this.loadMaterials()
  116. },
  117. methods: {
  118. handleSearch() {},
  119. async loadConfig() {
  120. try {
  121. const res = await getAssessmentConfig()
  122. if (res.data) {
  123. this.pointsConfig = {
  124. pointsValue: res.data.pointsValue || 100,
  125. pointsValueYuan: res.data.pointsValueYuan || 0.01
  126. }
  127. }
  128. } catch (e) {
  129. console.error('加载配置失败', e)
  130. }
  131. },
  132. async loadMaterials() {
  133. try {
  134. const res = await getAssessmentMaterials()
  135. this.materials = res.data || []
  136. } catch (e) {
  137. console.error('加载资料失败', e)
  138. }
  139. },
  140. async savePointsConfig() {
  141. try {
  142. await updateAssessmentConfig(this.pointsConfig)
  143. this.$message.success('配置保存成功')
  144. } catch (e) {
  145. this.$message.error('保存失败')
  146. }
  147. },
  148. showCreateDialog() {
  149. this.dialogTitle = '添加测评资料'
  150. this.materialForm = { id: null, title: '', content: '', coverImage: '' }
  151. this.dialogVisible = true
  152. },
  153. editMaterial(row) {
  154. this.dialogTitle = '编辑测评资料'
  155. this.materialForm = { ...row }
  156. this.dialogVisible = true
  157. },
  158. async saveMaterial() {
  159. if (!this.materialForm.title) {
  160. this.$message.warning('请输入标题')
  161. return
  162. }
  163. try {
  164. if (this.materialForm.id) {
  165. await updateAssessmentMaterial(this.materialForm.id, this.materialForm)
  166. } else {
  167. await createAssessmentMaterial(this.materialForm)
  168. }
  169. this.dialogVisible = false
  170. this.loadMaterials()
  171. this.$message.success('保存成功')
  172. } catch (e) {
  173. this.$message.error('保存失败')
  174. }
  175. },
  176. async toggleStatus(row) {
  177. const newStatus = row.status === 'active' ? 'inactive' : 'active'
  178. try {
  179. await updateAssessmentMaterial(row.id, { status: newStatus })
  180. this.loadMaterials()
  181. this.$message.success('状态更新成功')
  182. } catch (e) {
  183. this.$message.error('更新失败')
  184. }
  185. },
  186. handleActionCmd(row, cmd) {
  187. switch (cmd) {
  188. case 'toggle':
  189. this.toggleStatus(row)
  190. break
  191. }
  192. }
  193. }
  194. }
  195. </script>
  196. <style scoped>
  197. .assessment-admin {
  198. padding: 20px;
  199. }
  200. .config-card {
  201. margin-bottom: 20px;
  202. }
  203. .card-title {
  204. font-size: 16px;
  205. font-weight: 600;
  206. color: #303133;
  207. }
  208. .form-tip {
  209. margin-left: 10px;
  210. color: #909399;
  211. }
  212. .materials-card ::v-deep .el-card__body {
  213. padding: 0;
  214. }
  215. </style>