浏览代码

feat: 添加知识库管理功能并更新相关配置

- 新增知识库管理页面,包含分类树和内容列表功能
- 更新微信小程序接口地址和订阅消息模板ID
- 添加tinymce和vue-tinymce-editor依赖
- 优化地图详情页图片存储逻辑
- 调整登录页面订阅消息模板配置
weieryang 1 月之前
父节点
当前提交
53fdbc4875

+ 2 - 0
web/package.json

@@ -60,6 +60,7 @@
60 60
     "quill": "^1.3.7",
61 61
     "screenfull": "4.2.0",
62 62
     "sortablejs": "1.8.4",
63
+    "tinymce": "^8.3.0",
63 64
     "v-viewer": "^1.4.2",
64 65
     "vue": "2.6.10",
65 66
     "vue-amap": "^0.5.10",
@@ -71,6 +72,7 @@
71 72
     "vue-quill-editor": "^3.0.6",
72 73
     "vue-router": "3.0.2",
73 74
     "vue-splitpane": "1.0.4",
75
+    "vue-tinymce-editor": "^1.6.2",
74 76
     "vuedraggable": "2.20.0",
75 77
     "vuex": "3.1.0",
76 78
     "wangeditor": "^3.1.1",

+ 874 - 0
web/src/views/knowledge/index.vue

@@ -0,0 +1,874 @@
1
+<template>
2
+  <div class="app-container" style="height:100%;">
3
+    <el-row :gutter="24">
4
+      <!-- 左侧分类树 -->
5
+      <el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="padding-right: 3px;">
6
+        <el-card class="box-card box-cardh" shadow="never" style="padding: 8px;">
7
+          <div class="tree-header">
8
+            <span class="tree-title">知识库分类</span>
9
+            <div class="tree-actions">
10
+              <el-button size="mini" type="primary" icon="el-icon-plus" @click="addCategory">添加</el-button>
11
+            </div>
12
+          </div>
13
+          <el-scrollbar style="height: calc(100% - 50px);">
14
+            <el-tree
15
+              ref="categoryTreeRef"
16
+              v-loading="loading1"
17
+              element-loading-text="数据加载中"
18
+              element-loading-spinner="el-icon-loading"
19
+              class="filter-tree"
20
+              :data="categoryTree"
21
+              :props="defaultProps"
22
+              default-expand-all
23
+              highlight-current
24
+              node-key="id"
25
+              @node-click="handleCategoryClick"
26
+            >
27
+              <span slot-scope="{ node, data }" class="custom-tree-node">
28
+                <span>{{ node.label }}</span>
29
+                <span>
30
+                  <el-button type="text" size="mini" icon="el-icon-edit" @click.stop="editCategory(data)" />
31
+                  <el-button type="text" size="mini" icon="el-icon-delete" @click.stop="deleteCategory(data)" />
32
+                </span>
33
+              </span>
34
+            </el-tree>
35
+          </el-scrollbar>
36
+        </el-card>
37
+      </el-col>
38
+      <!-- 右侧内容列表 -->
39
+      <el-col :xs="24" :sm="24" :md="18" :lg="18" :xl="18" style="padding-left: 3px;">
40
+        <el-card class="box-card box-cardh map-container" shadow="never" style="overflow:auto;">
41
+          <!-- 工具栏 -->
42
+          <div class="toolbar">
43
+            <el-input
44
+              v-model="searchKeyword"
45
+              placeholder="请输入关键词搜索"
46
+              prefix-icon="el-icon-search"
47
+              style="width: 300px; margin-right: 10px;"
48
+            />
49
+            <el-button type="primary" icon="el-icon-search" @click="searchContent">搜索</el-button>
50
+            <el-button type="primary" icon="el-icon-plus" @click="addContent">新增知识</el-button>
51
+          </div>
52
+          <!-- 表格渲染 -->
53
+          <el-table
54
+            v-loading="loading2"
55
+            element-loading-text="数据加载中"
56
+            element-loading-spinner="el-icon-loading"
57
+            :data="contentList"
58
+            style="width: 100%;"
59
+          >
60
+            <el-table-column type="selection" width="55" />
61
+            <el-table-column prop="title" label="标题" show-overflow-tooltip min-width="200" />
62
+            <el-table-column prop="categoryName" label="分类" width="150" />
63
+            <el-table-column prop="createdAt" label="创建时间" width="180" />
64
+            <el-table-column prop="updatedAt" label="更新时间" width="180" />
65
+            <el-table-column label="操作" width="200" align="center" fixed="right">
66
+              <template slot-scope="scope">
67
+                <el-button-group>
68
+                  <el-button size="mini" type="primary" icon="el-icon-view" @click="viewContent(scope.row)">查看</el-button>
69
+                  <el-button size="mini" type="success" icon="el-icon-edit" @click="editContent(scope.row)">编辑</el-button>
70
+                  <el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteContent(scope.row)">删除</el-button>
71
+                </el-button-group>
72
+              </template>
73
+            </el-table-column>
74
+          </el-table>
75
+          <!-- 分页组件 -->
76
+          <div class="pagination-container">
77
+            <el-pagination
78
+              :current-page="page.current"
79
+              :page-sizes="[10, 20, 50, 100]"
80
+              :page-size="page.size"
81
+              layout="total, sizes, prev, pager, next, jumper"
82
+              :total="total"
83
+              @size-change="handleSizeChange"
84
+              @current-change="handleCurrentChange"
85
+            />
86
+          </div>
87
+        </el-card>
88
+      </el-col>
89
+    </el-row>
90
+
91
+    <!-- 分类编辑对话框 -->
92
+    <el-dialog
93
+      append-to-body
94
+      :close-on-click-modal="false"
95
+      :destroy-on-close="true"
96
+      :title="categoryDialog.title"
97
+      :visible.sync="categoryDialog.visible"
98
+      width="40%"
99
+    >
100
+      <el-form
101
+        ref="categoryFormRef"
102
+        :model="categoryForm"
103
+        label-width="80px"
104
+        class="demo-ruleForm"
105
+      >
106
+        <el-form-item label="分类名称" prop="categoryName" :rules="[{ required: true, message: '请输入分类名称', trigger: 'blur' }]">
107
+          <el-input v-model="categoryForm.categoryName" placeholder="请输入分类名称" />
108
+        </el-form-item>
109
+        <el-form-item label="上级分类">
110
+          <el-select v-model="categoryForm.parentId" placeholder="请选择上级分类">
111
+            <el-option label="根分类" :value="0" />
112
+            <el-option
113
+              v-for="item in categoryOptions"
114
+              :key="item.id"
115
+              :label="item.label"
116
+              :value="item.id"
117
+            />
118
+          </el-select>
119
+        </el-form-item>
120
+        <el-form-item label="分类描述">
121
+          <el-input v-model="categoryForm.description" type="textarea" placeholder="请输入分类描述" :rows="3" />
122
+        </el-form-item>
123
+        <el-form-item label="是否启用">
124
+          <el-switch v-model="categoryForm.isActive" :active-value="true" :inactive-value="false" active-color="#13ce66" inactive-color="#ff4949" />
125
+        </el-form-item>
126
+        <el-form-item label="排序号">
127
+          <el-input-number v-model="categoryForm.sortOrder" :min="0" :step="1" placeholder="请输入排序号" />
128
+        </el-form-item>
129
+
130
+      </el-form>
131
+      <div slot="footer" class="dialog-footer">
132
+        <el-button @click="categoryDialog.visible = false">取消</el-button>
133
+        <el-button type="primary" @click="saveCategory">确定</el-button>
134
+      </div>
135
+    </el-dialog>
136
+
137
+    <!-- 内容编辑对话框 -->
138
+    <el-dialog
139
+      append-to-body
140
+      :close-on-click-modal="false"
141
+      :destroy-on-close="true"
142
+      :title="contentDialog.title"
143
+      :visible.sync="contentDialog.visible"
144
+      width="70%"
145
+    >
146
+      <el-scrollbar class="editbox-cardh" style="height: 600px;">
147
+        <el-form
148
+          ref="contentFormRef"
149
+          :model="contentForm"
150
+          label-width="80px"
151
+          class="demo-ruleForm"
152
+        >
153
+          <el-form-item label="所属分类" prop="categoryId" :rules="[{ required: true, message: '请选择所属分类', trigger: 'change' }]">
154
+            <el-select v-model="contentForm.categoryId" placeholder="请选择所属分类">
155
+              <el-option
156
+                v-for="item in categoryOptions"
157
+                :key="item.id"
158
+                :label="item.label"
159
+                :value="item.id"
160
+              />
161
+            </el-select>
162
+          </el-form-item>
163
+          <el-form-item label="标题" prop="title" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]">
164
+            <el-input v-model="contentForm.title" placeholder="请输入标题" maxlength="200" />
165
+          </el-form-item>
166
+          <el-form-item label="内容" prop="content" :rules="[{ required: true, message: '请输入内容', trigger: 'blur' }]">
167
+            <div ref="editorRef" class="editor-container" />
168
+          </el-form-item>
169
+        </el-form>
170
+      </el-scrollbar>
171
+      <div slot="footer" class="dialog-footer">
172
+        <el-button @click="closeContentDialog">取消</el-button>
173
+        <el-button type="primary" @click="saveContent">确定</el-button>
174
+      </div>
175
+    </el-dialog>
176
+
177
+    <!-- 内容查看对话框 -->
178
+    <el-dialog
179
+      append-to-body
180
+      :title="'查看知识 - ' + viewContentForm.title"
181
+      :visible.sync="viewContentDialogVisible"
182
+      width="70%"
183
+    >
184
+      <el-scrollbar class="editbox-cardh" style="height: 600px;">
185
+        <div class="view-content">
186
+          <div class="view-title">{{ viewContentForm.title }}</div>
187
+          <div class="view-meta">
188
+            <span class="meta-item">所属分类:{{ viewContentForm.categoryName }}</span>
189
+            <span class="meta-item">创建时间:{{ viewContentForm.createTime }}</span>
190
+            <span class="meta-item">更新时间:{{ viewContentForm.updateTime }}</span>
191
+          </div>
192
+          <div class="view-body" v-html="viewContentForm.content" />
193
+          <div v-if="viewContentForm.remark" class="view-remark">
194
+            <strong>备注:</strong>{{ viewContentForm.remark }}
195
+          </div>
196
+        </div>
197
+      </el-scrollbar>
198
+      <div slot="footer" class="dialog-footer">
199
+        <el-button @click="viewContentDialogVisible = false">关闭</el-button>
200
+      </div>
201
+    </el-dialog>
202
+  </div>
203
+</template>
204
+
205
+<script>
206
+import { mapGetters } from 'vuex'
207
+import { upload } from '@/utils/upload'
208
+import E from 'wangeditor'
209
+import request from '@/utils/request'
210
+
211
+export default {
212
+  name: 'KnowledgeBase',
213
+  data() {
214
+    return {
215
+      // 分类树相关
216
+      categoryTree: [],
217
+      defaultProps: {
218
+        children: 'children',
219
+        label: 'categoryName'
220
+      },
221
+      categoryOptions: [],
222
+      loading1: false,
223
+      currentCategoryId: 0,
224
+
225
+      // 内容列表相关
226
+      contentList: [],
227
+      loading2: false,
228
+      searchKeyword: '',
229
+      page: {
230
+        current: 1,
231
+        size: 10
232
+      },
233
+      total: 0,
234
+
235
+      // 分类对话框
236
+      categoryDialog: {
237
+        visible: false,
238
+        title: '添加分类'
239
+      },
240
+      categoryForm: {
241
+        id: '',
242
+        name: '',
243
+        parentId: '0',
244
+        remark: ''
245
+      },
246
+
247
+      // 内容对话框
248
+      contentDialog: {
249
+        visible: false,
250
+        title: '添加知识'
251
+      },
252
+      contentForm: {
253
+        id: '',
254
+        categoryId: '',
255
+        title: '',
256
+        content: '',
257
+        remark: ''
258
+      },
259
+
260
+      // 查看对话框
261
+      viewContentDialogVisible: false,
262
+      viewContentForm: {
263
+        id: '',
264
+        title: '',
265
+        categoryName: '',
266
+        content: '',
267
+        createTime: '',
268
+        updateTime: '',
269
+        remark: ''
270
+      },
271
+
272
+      // 富文本编辑器
273
+      editor: null
274
+    }
275
+  },
276
+  computed: {
277
+    ...mapGetters([
278
+      'imagesUploadApi',
279
+      'baseApi'
280
+    ])
281
+  },
282
+  created() {
283
+    this.loadCategoryTree()
284
+    this.loadContentList()
285
+  },
286
+  mounted() {
287
+    // 初始化编辑器
288
+    this.$nextTick(() => {
289
+      this.initEditor()
290
+    })
291
+  },
292
+  beforeDestroy() {
293
+    if (this.editor) {
294
+      this.editor.destroy()
295
+    }
296
+  },
297
+  methods: {
298
+    // 初始化富文本编辑器
299
+    initEditor() {
300
+      if (this.$refs.editorRef) {
301
+        const _this = this
302
+        this.editor = new E(this.$refs.editorRef)
303
+        // 自定义菜单配置
304
+        this.editor.customConfig.zIndex = 10
305
+        // 文件上传
306
+        this.editor.customConfig.customUploadImg = function(files, insert) {
307
+          files.forEach(image => {
308
+            upload(_this.imagesUploadApi, image).then(res => {
309
+              const data = res.data
310
+              const url = _this.baseApi + '/file/' + data.type + '/' + data.realName
311
+              insert(url)
312
+            })
313
+          })
314
+        }
315
+        this.editor.customConfig.onchange = (html) => {
316
+          _this.contentForm.content = html
317
+        }
318
+        this.editor.create()
319
+        // 初始化数据 - 直接使用contentForm.content,因为接口返回的就是HTML格式
320
+        this.editor.txt.html(this.contentForm.content || '')
321
+      }
322
+    },
323
+
324
+    // 加载分类树
325
+    loadCategoryTree() {
326
+      this.loading1 = true
327
+      // 调用真实接口获取分类列表
328
+      request({
329
+        url: '/knowledge-category/selectKnowledgeCategoryList',
330
+        method: 'get'
331
+      })
332
+        .then(res => {
333
+          this.loading1 = false
334
+          if (res.status === 200 && res.data) {
335
+            // 将扁平数据转换为树形结构
336
+            this.categoryTree = this.buildCategoryTree(res.data)
337
+            this.generateCategoryOptions()
338
+          } else {
339
+            this.$message.error(res.message || '加载分类失败')
340
+          }
341
+        })
342
+        .catch(err => {
343
+          this.loading1 = false
344
+          this.$message.error(err || '加载分类失败')
345
+        })
346
+    },
347
+
348
+    // 将扁平数据转换为树形结构
349
+    buildCategoryTree(data) {
350
+      const tree = []
351
+      const map = {}
352
+
353
+      // 构建ID映射
354
+      data.forEach(item => {
355
+        map[item.id] = {
356
+          ...item,
357
+          children: []
358
+        }
359
+      })
360
+
361
+      // 构建树形结构
362
+      data.forEach(item => {
363
+        const parentId = item.parentId || 0
364
+        if (parentId === 0) {
365
+          // 顶级分类
366
+          tree.push(map[item.id])
367
+        } else {
368
+          // 子分类
369
+          if (map[parentId]) {
370
+            map[parentId].children.push(map[item.id])
371
+          }
372
+        }
373
+      })
374
+
375
+      return tree
376
+    },
377
+
378
+    // 生成分类选项(用于下拉选择)
379
+    generateCategoryOptions() {
380
+      const options = []
381
+      const generateOptions = (tree, level = 0, prefix = '') => {
382
+        tree.forEach(node => {
383
+          const label = level > 0 ? prefix + node.categoryName : node.categoryName
384
+          options.push({ id: node.id, label })
385
+          if (node.children && node.children.length > 0) {
386
+            generateOptions(node.children, level + 1, prefix + '└─')
387
+          }
388
+        })
389
+      }
390
+      generateOptions(this.categoryTree)
391
+      this.categoryOptions = options
392
+    },
393
+
394
+    // 加载内容列表
395
+    loadContentList() {
396
+      this.loading2 = true
397
+      // 调用真实接口获取知识库内容列表 - 使用POST请求,参数放到body中
398
+      request({
399
+        url: '/knowledge-base/selectKnowledgeBaseList',
400
+        method: 'post',
401
+        data: {
402
+          current: this.page.current,
403
+          size: this.page.size,
404
+          categoryId: this.currentCategoryId || undefined,
405
+          title: this.searchKeyword || undefined
406
+        }
407
+      })
408
+        .then(res => {
409
+          this.loading2 = false
410
+          if (res.status === 200 && res.data && res.data.data) {
411
+            // 获取原始数据
412
+            const rawData = res.data.data || []
413
+            // 为每条数据添加分类名称并解码HTML内容
414
+            this.contentList = rawData.map(item => ({
415
+              ...item,
416
+              // 根据categoryId获取分类名称
417
+              categoryName: this.getCategoryNameById(item.categoryId),
418
+              // 解码HTML内容
419
+              content: item.content ? this.decodeHtml(item.content) : ''
420
+            }))
421
+            this.total = res.data.total || 0
422
+          } else {
423
+            this.$message.error(res.message || '加载内容失败')
424
+          }
425
+        })
426
+        .catch(err => {
427
+          this.loading2 = false
428
+          this.$message.error(err || '加载内容失败')
429
+        })
430
+    },
431
+
432
+    // 根据分类ID获取分类名称
433
+    getCategoryNameById(categoryId) {
434
+      if (!categoryId) return ''
435
+
436
+      // 递归查找分类名称
437
+      const findCategory = (tree) => {
438
+        for (const node of tree) {
439
+          if (node.id === categoryId) {
440
+            return node.categoryName
441
+          }
442
+          if (node.children && node.children.length > 0) {
443
+            const result = findCategory(node.children)
444
+            if (result) {
445
+              return result
446
+            }
447
+          }
448
+        }
449
+        return ''
450
+      }
451
+
452
+      return findCategory(this.categoryTree)
453
+    },
454
+
455
+    // HTML实体解码
456
+    decodeHtml(html) {
457
+      if (!html) return ''
458
+      // 使用更可靠的HTML实体解码方式
459
+      const entities = {
460
+        '&amp;': '&',
461
+        '&lt;': '<',
462
+        '&gt;': '>',
463
+        '&quot;': '"',
464
+        '&#39;': "'",
465
+        '&#x2F;': '/',
466
+        '&#x60;': '`',
467
+        '&#x3D;': '='
468
+      }
469
+      return html.replace(/&[#\w]+;/g, match => entities[match] || match)
470
+    },
471
+
472
+    // 分类点击事件
473
+    handleCategoryClick(data) {
474
+      this.currentCategoryId = data.id
475
+      this.page.current = 1
476
+      this.loadContentList()
477
+    },
478
+
479
+    // 添加分类
480
+    addCategory() {
481
+      this.categoryDialog.title = '添加分类'
482
+      this.categoryForm = {
483
+        id: '',
484
+        categoryName: '',
485
+        parentId: this.currentCategoryId || 0,
486
+        description: '',
487
+        isActive: true,
488
+        sortOrder: 0
489
+      }
490
+      this.categoryDialog.visible = true
491
+    },
492
+
493
+    // 编辑分类
494
+    editCategory(data) {
495
+      this.categoryDialog.title = '编辑分类'
496
+      this.categoryForm = {
497
+        id: data.id,
498
+        categoryName: data.categoryName,
499
+        parentId: data.parentId || 0,
500
+        description: data.description || '',
501
+        isActive: data.isActive || true,
502
+        sortOrder: data.sortOrder || 0
503
+      }
504
+      this.categoryDialog.visible = true
505
+    },
506
+
507
+    // 删除分类
508
+    deleteCategory(data) {
509
+      this.$confirm('确定要删除该分类吗?', '提示', {
510
+        confirmButtonText: '确定',
511
+        cancelButtonText: '取消',
512
+        type: 'warning'
513
+      }).then(() => {
514
+        request({
515
+          url: `/knowledge-category/deleteKnowledgeCategory/${data.id}`,
516
+          method: 'delete'
517
+        })
518
+          .then(res => {
519
+            if (res.status === 200) {
520
+              this.$message.success('删除成功')
521
+              this.loadCategoryTree()
522
+            } else {
523
+              this.$message.error(res.message || '删除失败')
524
+            }
525
+          })
526
+          .catch(err => {
527
+            this.$message.error(err || '删除失败')
528
+          })
529
+      }).catch(() => {
530
+        // 取消删除
531
+      })
532
+    },
533
+
534
+    // 保存分类
535
+    saveCategory() {
536
+      this.$refs.categoryFormRef.validate((valid) => {
537
+        if (valid) {
538
+          const formData = { ...this.categoryForm }
539
+
540
+          // 根据是否有ID判断是添加还是修改
541
+          if (formData.id) {
542
+            // 修改分类 - 使用POST请求
543
+            request({
544
+              url: '/knowledge-category/updateKnowledgeCategory',
545
+              method: 'post',
546
+              data: formData
547
+            })
548
+              .then(res => {
549
+                if (res.status === 200) {
550
+                  this.$message.success('修改成功')
551
+                  this.categoryDialog.visible = false
552
+                  this.loadCategoryTree()
553
+                } else {
554
+                  this.$message.error(res.message || '修改失败')
555
+                }
556
+              })
557
+              .catch(err => {
558
+                this.$message.error(err || '修改失败')
559
+              })
560
+          } else {
561
+            // 添加分类 - 使用POST请求,参数放到body中
562
+            request({
563
+              url: '/knowledge-category/addKnowledgeCategory',
564
+              method: 'post',
565
+              data: formData
566
+            })
567
+              .then(res => {
568
+                if (res.status === 200) {
569
+                  this.$message.success('添加成功')
570
+                  this.categoryDialog.visible = false
571
+                  this.loadCategoryTree()
572
+                } else {
573
+                  this.$message.error(res.message || '添加失败')
574
+                }
575
+              })
576
+              .catch(err => {
577
+                this.$message.error(err || '添加失败')
578
+              })
579
+          }
580
+        }
581
+      })
582
+    },
583
+
584
+    // 添加知识
585
+    addContent() {
586
+      this.contentDialog.title = '添加知识'
587
+      this.contentForm = {
588
+        id: '',
589
+        categoryId: this.currentCategoryId || 0,
590
+        title: '',
591
+        content: ''
592
+      }
593
+      this.contentDialog.visible = true
594
+      this.$nextTick(() => {
595
+        this.initEditor()
596
+      })
597
+    },
598
+
599
+    // 编辑知识
600
+    editContent(row) {
601
+      this.contentDialog.title = '编辑知识'
602
+      // 调用详情接口获取完整数据
603
+      request({
604
+        url: `/knowledge-base/selectKnowledgeBaseDetail/${row.id}`,
605
+        method: 'get'
606
+      })
607
+        .then(res => {
608
+          if (res.status === 200) {
609
+            // 处理接口返回的内容字段,需要解码HTML实体
610
+            const rawContent = res.data && res.data.content ? res.data.content : ''
611
+            const decodedContent = this.decodeHtml(rawContent)
612
+
613
+            this.contentForm = {
614
+              id: res.data && res.data.id ? res.data.id : '',
615
+              categoryId: res.data && res.data.categoryId ? res.data.categoryId : 0,
616
+              title: res.data && res.data.title ? res.data.title : '',
617
+              content: decodedContent
618
+            }
619
+            this.contentDialog.visible = true
620
+            this.$nextTick(() => {
621
+              this.initEditor()
622
+            })
623
+          } else {
624
+            this.$message.error(res.message || '获取详情失败')
625
+          }
626
+        })
627
+        .catch(err => {
628
+          this.$message.error(err || '获取详情失败')
629
+        })
630
+    },
631
+
632
+    // 查看知识
633
+    viewContent(row) {
634
+      // 调用详情接口获取完整数据
635
+      request({
636
+        url: `/knowledge-base/selectKnowledgeBaseDetail/${row.id}`,
637
+        method: 'get'
638
+      })
639
+        .then(res => {
640
+          if (res.status === 200) {
641
+            // 处理接口返回的内容字段,需要解码HTML实体
642
+            const rawContent = res.data && res.data.content ? res.data.content : ''
643
+            const decodedContent = this.decodeHtml(rawContent)
644
+            const categoryId = res.data && res.data.categoryId ? res.data.categoryId : 0
645
+
646
+            this.viewContentForm = {
647
+              id: res.data && res.data.id ? res.data.id : '',
648
+              title: res.data && res.data.title ? res.data.title : '',
649
+              categoryName: this.getCategoryNameById(categoryId) || '', // 从分类树中查找分类名称
650
+              content: decodedContent,
651
+              createTime: res.data && res.data.createdAt ? res.data.createdAt : '',
652
+              updateTime: res.data && res.data.updatedAt ? res.data.updatedAt : '',
653
+              remark: '' // 接口中没有remark字段
654
+            }
655
+            this.viewContentDialogVisible = true
656
+          } else {
657
+            this.$message.error(res.message || '获取详情失败')
658
+          }
659
+        })
660
+        .catch(err => {
661
+          this.$message.error(err || '获取详情失败')
662
+        })
663
+    },
664
+
665
+    // 删除知识
666
+    deleteContent(row) {
667
+      this.$confirm('确定要删除该知识吗?', '提示', {
668
+        confirmButtonText: '确定',
669
+        cancelButtonText: '取消',
670
+        type: 'warning'
671
+      }).then(() => {
672
+        // 调用真实删除接口
673
+        request({
674
+          url: `/knowledge-base/deleteKnowledgeBase/${row.id}`,
675
+          method: 'delete'
676
+        })
677
+          .then(res => {
678
+            if (res.status === 200) {
679
+              this.$message.success('删除成功')
680
+              this.loadContentList()
681
+            } else {
682
+              this.$message.error(res.message || '删除失败')
683
+            }
684
+          })
685
+          .catch(err => {
686
+            this.$message.error(err || '删除失败')
687
+          })
688
+      }).catch(() => {
689
+        // 取消删除
690
+      })
691
+    },
692
+
693
+    // 关闭内容对话框
694
+    closeContentDialog() {
695
+      this.contentDialog.visible = false
696
+    },
697
+
698
+    // 保存知识
699
+    saveContent() {
700
+      // 先获取编辑器内容
701
+      if (this.editor) {
702
+        this.contentForm.content = this.editor.txt.html()
703
+      }
704
+
705
+      this.$refs.contentFormRef.validate((valid) => {
706
+        if (valid) {
707
+          const formData = { ...this.contentForm }
708
+
709
+          // 根据是否有ID判断是添加还是修改
710
+          if (formData.id) {
711
+            // 修改知识 - 使用POST请求
712
+            request({
713
+              url: '/knowledge-base/updateKnowledgeBase',
714
+              method: 'post',
715
+              data: formData
716
+            })
717
+              .then(res => {
718
+                if (res.status === 200) {
719
+                  this.$message.success('修改成功')
720
+                  this.contentDialog.visible = false
721
+                  this.loadContentList()
722
+                } else {
723
+                  this.$message.error(res.message || '修改失败')
724
+                }
725
+              })
726
+              .catch(err => {
727
+                this.$message.error(err || '修改失败')
728
+              })
729
+          } else {
730
+            // 添加知识 - 使用POST请求
731
+            request({
732
+              url: '/knowledge-base/addKnowledgeBase',
733
+              method: 'post',
734
+              data: formData
735
+            })
736
+              .then(res => {
737
+                if (res.status === 200) {
738
+                  this.$message.success('添加成功')
739
+                  this.contentDialog.visible = false
740
+                  this.loadContentList()
741
+                } else {
742
+                  this.$message.error(res.message || '添加失败')
743
+                }
744
+              })
745
+              .catch(err => {
746
+                this.$message.error(err || '添加失败')
747
+              })
748
+          }
749
+        }
750
+      })
751
+    },
752
+
753
+    // 搜索内容
754
+    searchContent() {
755
+      this.page.current = 1
756
+      this.loadContentList()
757
+    },
758
+
759
+    // 分页大小变化
760
+    handleSizeChange(val) {
761
+      this.page.size = val
762
+      this.loadContentList()
763
+    },
764
+
765
+    // 分页当前页变化
766
+    handleCurrentChange(val) {
767
+      this.page.current = val
768
+      this.loadContentList()
769
+    }
770
+  }
771
+}
772
+</script>
773
+
774
+<style scoped lang="scss">
775
+.tree-header {
776
+  display: flex;
777
+  justify-content: space-between;
778
+  align-items: center;
779
+  padding: 0 10px 10px;
780
+  border-bottom: 1px solid #eee;
781
+  margin-bottom: 10px;
782
+
783
+  .tree-title {
784
+    font-size: 16px;
785
+    font-weight: bold;
786
+  }
787
+}
788
+
789
+.toolbar {
790
+  display: flex;
791
+  align-items: center;
792
+  padding: 10px 0;
793
+  margin-bottom: 10px;
794
+}
795
+
796
+.pagination-container {
797
+  display: flex;
798
+  justify-content: flex-end;
799
+  align-items: center;
800
+  padding: 15px 0;
801
+}
802
+
803
+.view-content {
804
+  padding: 10px;
805
+
806
+  .view-title {
807
+    font-size: 20px;
808
+    font-weight: bold;
809
+    margin-bottom: 15px;
810
+    padding-bottom: 10px;
811
+    border-bottom: 1px solid #eee;
812
+  }
813
+
814
+  .view-meta {
815
+    margin-bottom: 20px;
816
+    color: #666;
817
+    font-size: 14px;
818
+
819
+    .meta-item {
820
+      margin-right: 20px;
821
+    }
822
+  }
823
+
824
+  .view-body {
825
+    margin-bottom: 20px;
826
+    line-height: 1.8;
827
+  }
828
+
829
+  .view-remark {
830
+    padding: 10px;
831
+    background-color: #f5f7fa;
832
+    border-radius: 4px;
833
+    color: #666;
834
+  }
835
+}
836
+
837
+.editor-container {
838
+  min-height: 400px;
839
+}
840
+
841
+::v-deep .w-e-text-container {
842
+  height: 400px !important;
843
+}
844
+
845
+.el-card__body {
846
+  padding: 0px;
847
+  height: 100%;
848
+}
849
+
850
+.box-cardh {
851
+  height: calc(100vh - 170px);
852
+}
853
+
854
+.editbox-cardh {
855
+  height: calc(100vh - 250px);
856
+}
857
+
858
+.el-scrollbar__wrap {
859
+  overflow-x: hidden;
860
+}
861
+
862
+.custom-tree-node {
863
+  flex: 1;
864
+  display: flex;
865
+  align-items: center;
866
+  justify-content: space-between;
867
+  font-size: 14px;
868
+  padding-right: 8px;
869
+}
870
+
871
+.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {
872
+  background-color: #e7faf0;
873
+}
874
+</style>

+ 2 - 2
wxproject/app.js

@@ -5,8 +5,8 @@ App({
5 5
   globalData: {
6 6
     userInfo: null,
7 7
     httpsUrl: 'https://cgdl.yutingcn.com/',
8
-    // httpsUrlServer: 'http://39.164.159.226:9090', //个人接口地址
9
-    httpsUrlServer:'http://zhyh.hnyulin.com/api/',
8
+    httpsUrlServer: 'http://39.164.159.226:9090', //个人接口地址
9
+    // httpsUrlServer:'http://zhyh.hnyulin.com/api/',
10 10
     zdzUrlServer:'http://58.246.189.90:30000', //市指导站推送测试接口地址
11 11
     openId: '',
12 12
     token: '',

+ 5 - 0
wxproject/greenland/pages/inspectionDetail/inspectionDetail.js

@@ -173,7 +173,12 @@ Page({
173 173
     ////console.log("跳转路径",e)
174 174
     let url = e.currentTarget.dataset.url;
175 175
     let remark = e.currentTarget.dataset.remark;
176
+    console.log(e.currentTarget.dataset.images, 'e.currentTarget.dataset.images');
176 177
     let images = JSON.stringify(e.currentTarget.dataset.images);
178
+
179
+    const key = 'detailMapInfo';
180
+    wx.setStorageSync(key, images)
181
+
177 182
     wx.navigateTo({
178 183
       url:
179 184
         // "/packageA/pages/historicalTrackDetailMap/historicalTrackDetailMap?url=" +

+ 5 - 1
wxproject/greenland/pages/inspectionDetailMap/inspectionDetailMap.js

@@ -43,8 +43,12 @@ Page({
43 43
       that.marksDots1()
44 44
     } else {
45 45
       console.log("2")
46
+      console.log(options.images, 'options.images');
46 47
 
47
-      let images = JSON.parse(options.images)
48
+      const key = 'detailMapInfo';
49
+    
50
+
51
+      let images = wx.getStorageInfo(key)
48 52
       let arr = options.url.split(",")
49 53
       let LineArr = options.dates.split(";")
50 54
       let arr1 = []

+ 1 - 1
wxproject/pages/login/login.js

@@ -267,7 +267,7 @@ Page({
267 267
                 },
268 268
               })
269 269
               wx.requestSubscribeMessage({
270
-                tmplIds: ["dnyWG_8ZFgueG1ioYJd8-PLT2LGVqYPVatlVs3OLVGI"],
270
+                tmplIds: ["9k7_suAIzYn4zbC7hdOegpeNoWFpmOisq57Coh_ISrs", "zlr8Ce3V9yB3S--v6kNnp8W66a2fQO7uG-LTbPRwgdE"],
271 271
                 success(res) {
272 272
                   console.log(res, '订阅消息成功')
273 273
                   if (res.errMsg == "requestSubscribeMessage:ok") {