CN-938 feat: 知识库编辑功能

This commit is contained in:
chenjinsong
2023-03-23 16:13:55 +08:00
parent 8da7dc5e58
commit 45d6475243
4 changed files with 171 additions and 67 deletions

View File

@@ -1,7 +1,9 @@
<template> <template>
<div class="cn-home"> <div class="cn-home">
<cn-header @refresh="refresh"></cn-header> <cn-header @refresh="refresh"></cn-header>
<cn-container v-if="containerShow" ref="container"></cn-container> <suspense>
<cn-container v-if="containerShow" ref="container"></cn-container>
</suspense>
</div> </div>
</template> </template>

View File

@@ -44,7 +44,11 @@ const routes = [
component: () => import('@/views/setting/KnowledgeBase') component: () => import('@/views/setting/KnowledgeBase')
}, },
{ {
path: '/knowledgeBase/form', path: '/knowledgeBase/create',
component: () => import('@/views/setting/KnowledgeBaseForm')
},
{
path: '/knowledgeBase/edit',
component: () => import('@/views/setting/KnowledgeBaseForm') component: () => import('@/views/setting/KnowledgeBaseForm')
}, },
{ {

View File

@@ -18,13 +18,11 @@
<i class="cn-icon-xinjian cn-icon"></i> <i class="cn-icon-xinjian cn-icon"></i>
<span>{{$t('overall.create')}}</span> <span>{{$t('overall.create')}}</span>
</button> </button>
<!--
<button id="knowledge-base-edit" :title="$t('knowledgeBase.editKnowledgeBase')" class="top-tool-btn margin-r-10" :disabled="disableEdit" <button id="knowledge-base-edit" :title="$t('knowledgeBase.editKnowledgeBase')" class="top-tool-btn margin-r-10" :disabled="disableEdit"
@click="edit"> @click="editSelectRecord">
<i class="cn-icon-edit cn-icon" ></i> <i class="cn-icon-edit cn-icon" ></i>
<span>{{$t('overall.edit')}}</span> <span>{{$t('overall.edit')}}</span>
</button> </button>
-->
<button id="knowledge-base-delete" :title="$t('knowledgeBase.deleteKnowledgeBase')" class="top-tool-btn margin-r-10" <button id="knowledge-base-delete" :title="$t('knowledgeBase.deleteKnowledgeBase')" class="top-tool-btn margin-r-10"
@click="delBatch"> @click="delBatch">
<i class="cn-icon-delete cn-icon"></i> <i class="cn-icon-delete cn-icon"></i>
@@ -75,9 +73,10 @@ export default {
}, },
methods: { methods: {
edit (u) { edit (u) {
axios.get(`${this.url}`, { params: { ids: u.id } }).then(response => { axios.get(`${this.url}/${u.id}`).then(response => {
if (response.data.code === 200) { if (response.data.code === 200) {
this.object = response.data.data.list[0] this.object = response.data.data.list[0]
console.info(this.object)
} }
}).catch(e => { }).catch(e => {
console.error(e) console.error(e)
@@ -88,6 +87,16 @@ export default {
} }
}) })
}, },
editSelectRecord () {
if (this.batchDeleteObjs.length === 0) {
this.$alert(this.$t('tip.pleaseSelectForEdit'), {
confirmButtonText: this.$t('tip.yes'),
type: 'warning'
})
} else {
this.jumpToEditPage(this.batchDeleteObjs[0].id)
}
},
del (row) { del (row) {
this.$confirm(this.$t('tip.confirmDelete'), { this.$confirm(this.$t('tip.confirmDelete'), {
confirmButtonText: this.$t('tip.yes'), confirmButtonText: this.$t('tip.yes'),
@@ -115,9 +124,18 @@ export default {
}) })
}) })
}, },
jumpToEditPage (id) {
this.$router.push({
path: '/knowledgeBase/edit',
query: {
t: +new Date(),
id: id
}
})
},
jumpToCreatePage () { jumpToCreatePage () {
this.$router.push({ this.$router.push({
path: '/knowledgeBase/form', path: '/knowledgeBase/create',
query: { query: {
t: +new Date() t: +new Date()
} }

View File

@@ -1,6 +1,7 @@
<template> <template>
<div class="edit-knowledge-base"> <div class="edit-knowledge-base">
<div class="edit-knowledge-base__header">{{$t('overall.create')}}</div> <loading :loading="initLoading"></loading>
<div class="edit-knowledge-base__header">{{editObject.id ? $t('overall.edit') : $t('overall.create')}}</div>
<div class="edit-knowledge-base__body"> <div class="edit-knowledge-base__body">
<el-steps direction="vertical" :active="activeStep"> <el-steps direction="vertical" :active="activeStep">
<el-step v-for="(height, index) in stepHeights" :style="`flex-basis: ${height}px; flex-shrink: 0;`" :key="index"></el-step> <el-step v-for="(height, index) in stepHeights" :style="`flex-basis: ${height}px; flex-shrink: 0;`" :key="index"></el-step>
@@ -62,7 +63,7 @@
</el-collapse-item> </el-collapse-item>
<el-collapse-item name="2"> <el-collapse-item name="2">
<template #title><div class="form-sub-title">{{$t('overall.preview')}}</div></template> <template #title><div class="form-sub-title">{{$t('overall.preview')}}</div></template>
<div class="skeleton-border" v-if="!uploaded"> <div class="skeleton-border" v-if="!uploaded && !editObject.id">
<el-skeleton> <el-skeleton>
<template #template> <template #template>
<div v-for="item of 6" :key="item" class="skeleton-item-row"> <div v-for="item of 6" :key="item" class="skeleton-item-row">
@@ -74,7 +75,7 @@
</el-skeleton> </el-skeleton>
<div class="skeleton-tip">{{$t('knowledgeBase.skeletonTip')}}</div> <div class="skeleton-tip">{{$t('knowledgeBase.skeletonTip')}}</div>
</div> </div>
<div v-else> <template v-else>
<div class="imported-tip"><i class="cn-icon cn-icon-baocuo"/> <div class="imported-tip"><i class="cn-icon cn-icon-baocuo"/>
&nbsp;&nbsp;{{$t('knowledgeBase.importTip', { total: originalImportInfo.total, succeeded: originalImportInfo.succeeded, failed: originalImportInfo.failed })}} &nbsp;&nbsp;{{$t('knowledgeBase.importTip', { total: originalImportInfo.total, succeeded: originalImportInfo.succeeded, failed: originalImportInfo.failed })}}
</div> </div>
@@ -107,7 +108,7 @@
<transition name="el-zoom-in-top"> <transition name="el-zoom-in-top">
<div class="preview-error-tip" v-if="previewErrorTip">{{previewErrorTip}}</div> <div class="preview-error-tip" v-if="previewErrorTip">{{previewErrorTip}}</div>
</transition> </transition>
</div> </template>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
</div> </div>
@@ -124,7 +125,7 @@
</template> </template>
<script> <script>
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { ref } from 'vue' import { ref, nextTick } from 'vue'
import _ from 'lodash' import _ from 'lodash'
import { knowledgeBaseType, storageKey, unitTypes } from '@/utils/constants' import { knowledgeBaseType, storageKey, unitTypes } from '@/utils/constants'
import Pagination from '@/components/common/Pagination' import Pagination from '@/components/common/Pagination'
@@ -133,6 +134,7 @@ import axios from 'axios'
import { api } from '@/utils/api' import { api } from '@/utils/api'
import unitConvert from '@/utils/unit-convert' import unitConvert from '@/utils/unit-convert'
import Loading from '@/components/common/Loading' import Loading from '@/components/common/Loading'
export default { export default {
name: 'CreateKnowledgeBase', name: 'CreateKnowledgeBase',
components: { components: {
@@ -149,27 +151,31 @@ export default {
return validate return validate
} }
const nameAndTypeValidator = async (rule, value, callback) => { const nameAndTypeValidator = async (rule, value, callback) => {
this.$refs.form.clearValidate('tagType')
let validate = true let validate = true
const response = await this.getKnowledgeBaseList() if (!this.editObject.id) {
if (response.data.code === 200) { this.$refs.form.clearValidate('tagType')
const find = response.data.data.list.find(d => d.tagName === value && d.tagType === this.editObject.tagType) const response = await this.getKnowledgeBaseList()
if (find) { if (response.data.code === 200) {
validate = false const find = response.data.data.list.find(d => d.tagName === value && d.tagType === this.editObject.tagType)
callback(new Error()) if (find) {
validate = false
callback(new Error())
}
} }
} }
return validate return validate
} }
const typeAndNameValidator = async (rule, value, callback) => { const typeAndNameValidator = async (rule, value, callback) => {
this.$refs.form.clearValidate('tagName')
let validate = true let validate = true
const response = await this.getKnowledgeBaseList() if (!this.editObject.id) {
if (response.data.code === 200) { this.$refs.form.clearValidate('tagName')
const find = response.data.data.list.find(d => d.tagName === this.editObject.tagName && d.tagType === value) const response = await this.getKnowledgeBaseList()
if (find) { if (response.data.code === 200) {
validate = false const find = response.data.data.list.find(d => d.tagName === this.editObject.tagName && d.tagType === value)
callback(new Error()) if (find) {
validate = false
callback(new Error())
}
} }
} }
return validate return validate
@@ -216,6 +222,7 @@ export default {
this.previewErrorTip = '' this.previewErrorTip = ''
this.importedType = this.editObject.tagType this.importedType = this.editObject.tagType
const originalImportedData = _.cloneDeep(response.data.data) const originalImportedData = _.cloneDeep(response.data.data)
this.importedDataNoData = originalImportedData.length === 0 this.importedDataNoData = originalImportedData.length === 0
this.originalImportInfo = { this.originalImportInfo = {
@@ -225,6 +232,7 @@ export default {
} }
originalImportedData.sort((a, b) => b.status - a.status) originalImportedData.sort((a, b) => b.status - a.status)
this.importedData = originalImportedData this.importedData = originalImportedData
this.handleShowImportedData() this.handleShowImportedData()
} else { } else {
this.uploadLoading = false this.uploadLoading = false
@@ -261,14 +269,6 @@ export default {
this.uploadLoading = true this.uploadLoading = true
this.typeSelectDisable = true this.typeSelectDisable = true
}, },
handleShowImportedData () {
const startIndex = (this.importedPageObj.pageNo - 1) * this.importedPageObj.pageSize
const endIndex = this.importedPageObj.pageNo * this.importedPageObj.pageSize
this.showImportedData = this.importedData.slice(startIndex, endIndex)
this.$nextTick(() => {
this.uploadLoading = false
})
},
pageNo (val) { pageNo (val) {
this.importedPageObj.pageNo = val this.importedPageObj.pageNo = val
}, },
@@ -309,7 +309,7 @@ export default {
// 校验form + upload + preview // 校验form + upload + preview
this.$refs.form.validate(valid => { this.$refs.form.validate(valid => {
this.$refs.form.validateField('tagName') this.$refs.form.validateField('tagName')
if (!this.uploaded) { if (!this.uploaded && !this.editObject.id) {
this.uploadErrorTip = this.$t('validate.required') this.uploadErrorTip = this.$t('validate.required')
} else { } else {
this.uploadErrorTip = '' this.uploadErrorTip = ''
@@ -347,26 +347,50 @@ export default {
d.itemList = [...d.itemList] d.itemList = [...d.itemList]
}) })
postData.remark = this.editObject.remark postData.remark = this.editObject.remark
axios.post(this.url, postData).then(response => { if (!this.editObject.id) {
if (response.data.code === 200) { axios.post(this.url, postData).then(response => {
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') }) if (response.data.code === 200) {
this.$router.push({ this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
path: '/knowledgeBase', this.$router.push({
t: +new Date() path: '/knowledgeBase',
}) t: +new Date()
} else { })
this.$message.error(response.data.message) } else {
} this.$message.error(response.data.message)
}).catch(e => { }
console.error(e) }).catch(e => {
if (e.response.data && e.response.data.message) { console.error(e)
this.$message.error(e.response.data.message) if (e.response.data && e.response.data.message) {
} else { this.$message.error(e.response.data.message)
this.$message.error('Something went wrong...') } else {
} this.$message.error('Something went wrong...')
}).finally(() => { }
this.blockOperation.save = false }).finally(() => {
}) this.blockOperation.save = false
})
} else {
postData.id = this.editObject.id
axios.put(this.url, postData).then(response => {
if (response.data.code === 200) {
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
this.$router.push({
path: '/knowledgeBase',
t: +new Date()
})
} else {
this.$message.error(response.data.message)
}
}).catch(e => {
console.error(e)
if (e.response.data && e.response.data.message) {
this.$message.error(e.response.data.message)
} else {
this.$message.error('Something went wrong...')
}
}).finally(() => {
this.blockOperation.save = false
})
}
} else { } else {
this.blockOperation.save = false this.blockOperation.save = false
} }
@@ -393,13 +417,41 @@ export default {
return t ? t.name : '' return t ? t.name : ''
}, },
activeStep () { activeStep () {
if (this.tagNameFirstBlur) { if (this.editObject.id) {
return 2
} else if (this.tagNameFirstBlur) {
return this.uploaded ? 2 : 1 return this.uploaded ? 2 : 1
} else { } else {
return 0 return 0
} }
} }
}, },
mounted () {
if (this.knowledgeBaseId) {
axios.get(`${api.knowledgeBase}/${this.knowledgeBaseId}`).then(response => {
if (response.data.code === 200) {
this.editObject = response.data.data
this.importedData = this.revertImportedData(this.editObject.data)
this.handleShowImportedData()
this.originalImportInfo = {
total: this.importedData.length,
succeeded: this.importedData.length,
failed: 0
}
this.importedPageObj.total = this.importedData.length
this.importedType = this.editObject.tagType
this.initLoading = false
}
}).catch(e => {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
this.$router.push({
path: '/knowledgeBase',
t: +new Date()
})
})
}
},
watch: { watch: {
activeCollapses (n) { activeCollapses (n) {
const index0 = n.indexOf('0') const index0 = n.indexOf('0')
@@ -434,7 +486,7 @@ export default {
}, },
setup () { setup () {
const { query } = useRoute() const { query } = useRoute()
const knowledgeBaseId = ref(query.id || '') const knowledgeBaseId = query.id || ''
const url = api.knowledgeBase const url = api.knowledgeBase
// 空白对象 // 空白对象
const blankObject = { const blankObject = {
@@ -445,17 +497,22 @@ export default {
remark: '', remark: '',
updateTime: '' updateTime: ''
} }
/* 将组织后的数据还原拉平 */
const revertImportedData = (data) => {
const importedData = []
data.forEach(d => {
d.itemList.forEach(item => {
importedData.push({
tagItem: item,
tagValue: d.tagValue,
status: 1
})
})
})
return importedData
}
// form绑定的对象 // form绑定的对象
const editObject = ref(_.cloneDeep(blankObject)) const editObject = ref(_.cloneDeep(blankObject))
// 折叠组件控制
const activeCollapses = ref(['0', '1', '2'])
// 步骤条控制
const stepHeightConstant = {
collapse: 58,
first: 333,
second: 284
}
const stepHeights = ref([stepHeightConstant.first, stepHeightConstant.second, stepHeightConstant.collapse])
// 所有导入的数据 // 所有导入的数据
const importedData = ref([]) const importedData = ref([])
// 导入数据的原始数量信息 // 导入数据的原始数量信息
@@ -466,12 +523,32 @@ export default {
}) })
// table中显示的导入的数据 // table中显示的导入的数据
const showImportedData = ref([]) const showImportedData = ref([])
// table分页对象
const importedPageObj = ref({ const importedPageObj = ref({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
total: null total: null
}) })
const importedType = ref('') const importedType = ref('')
const uploadLoading = ref(false)
const initLoading = ref(!!knowledgeBaseId)
const handleShowImportedData = async () => {
const startIndex = (importedPageObj.value.pageNo - 1) * importedPageObj.value.pageSize
const endIndex = importedPageObj.value.pageNo * importedPageObj.value.pageSize
showImportedData.value = importedData.value.slice(startIndex, endIndex)
await nextTick()
uploadLoading.value = false
}
// 折叠组件控制
const activeCollapses = ref(['0', '1', '2'])
// 步骤条控制
const stepHeightConstant = {
collapse: 58,
first: 333,
second: 284
}
const stepHeights = ref([stepHeightConstant.first, stepHeightConstant.second, stepHeightConstant.collapse])
// 没上传过文件的提示 // 没上传过文件的提示
const uploadErrorTip = ref('') const uploadErrorTip = ref('')
// 预览区无内容的提示 // 预览区无内容的提示
@@ -489,6 +566,8 @@ export default {
showImportedData, showImportedData,
importedPageObj, importedPageObj,
importedType, importedType,
revertImportedData,
handleShowImportedData,
baseUrl: BASE_CONFIG.baseUrl, baseUrl: BASE_CONFIG.baseUrl,
fileList: ref([]), fileList: ref([]),
uploadHeaders: { uploadHeaders: {
@@ -502,7 +581,8 @@ export default {
previewErrorTip, previewErrorTip,
typeSelectDisable: ref(false), typeSelectDisable: ref(false),
uploadFileSizeLimit: 100 * 1024 * 1024, uploadFileSizeLimit: 100 * 1024 * 1024,
uploadLoading: ref(false), uploadLoading,
initLoading,
fileTypeLimit: '.csv' fileTypeLimit: '.csv'
} }
} }