| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- <template>
- <div class="app-container">
- <el-card shadow="never">
- <el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
- <el-form-item prop="keyword">
- <template slot="label">{{ tsT("queryKeyword") }}</template>
- <el-input
- v-model="queryParams.keyword"
- :placeholder="tsT('queryKeywordPh')"
- clearable
- style="width: 220px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item prop="knowledgeTopic">
- <template slot="label">{{ tsT("queryTopic") }}</template>
- <el-select v-model="queryParams.knowledgeTopic" :placeholder="tsCommon('pleaseSelect')" clearable style="width: 150px">
- <el-option v-for="item in topicOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- <el-form-item prop="kbSyncStatus">
- <template slot="label">{{ tsT("queryKbSync") }}</template>
- <el-select v-model="queryParams.kbSyncStatus" :placeholder="tsCommon('pleaseSelect')" clearable style="width: 130px">
- <el-option :label="$t('techService.status.kbNotIn')" :value="0" />
- <el-option :label="$t('techService.status.kbIn')" :value="1" />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ tsCommon("search") }}</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ tsCommon("reset") }}</el-button>
- <el-button
- v-hasPermi="['techService:knowledge:add']"
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- >{{ tsCommon("add") }}</el-button>
- </el-form-item>
- </el-form>
- </el-card>
- <br />
- <el-card shadow="never">
- <el-table v-loading="loading" :data="tableList" border>
- <el-table-column :label="tsT('colTitle')" prop="knowledgeTitle" align="center" min-width="120" :show-overflow-tooltip="true" />
- <el-table-column :label="tsT('colTopic')" align="center" width="110">
- <template slot-scope="scope">
- <span>{{ knowledgeTopicText(scope.row.knowledgeTopic) }}</span>
- </template>
- </el-table-column>
- <el-table-column :label="tsT('colIntro')" prop="introduction" align="center" min-width="140" :show-overflow-tooltip="true" />
- <el-table-column :label="tsCommon('colContentFile')" align="center" min-width="130" :show-overflow-tooltip="true">
- <template slot-scope="scope">
- <el-link
- v-if="scope.row.contentFileUrl"
- type="primary"
- :href="scope.row.contentFileUrl"
- target="_blank"
- >{{ scope.row.contentFileName }}</el-link>
- <span v-else>{{ $t('techService.status.dash') }}</span>
- </template>
- </el-table-column>
- <el-table-column :label="tsCommon('colKb')" align="center" width="100">
- <template slot-scope="scope">
- <span>{{ kbSyncStatusText(scope.row.kbSyncStatus) }}</span>
- </template>
- </el-table-column>
- <el-table-column :label="tsCommon('colCreate')" align="center" width="160">
- <template slot-scope="scope">
- <span>{{ scope.row.createTime ? parseTime(scope.row.createTime) : $t('techService.status.dash') }}</span>
- </template>
- </el-table-column>
- <el-table-column :label="tsCommon('colOp')" align="center" class-name="small-padding fixed-width" width="340" fixed="right">
- <template slot-scope="scope">
- <el-button v-hasPermi="['techService:knowledge:query']" type="text" size="mini" @click="handleView(scope.row)">{{ tsCommon("view") }}</el-button>
- <el-button
- v-hasPermi="['techService:knowledge:syncKb']"
- v-if="canSyncKb(scope.row)"
- type="text"
- size="mini"
- @click="handleSyncKb(scope.row)"
- >{{ tsCommon("syncKb") }}</el-button>
- <el-button
- v-hasPermi="['techService:knowledge:removeKb']"
- v-if="canRemoveKb(scope.row)"
- type="text"
- size="mini"
- @click="handleRemoveKb(scope.row)"
- >{{ tsCommon("removeKb") }}</el-button>
- <el-button
- v-hasPermi="['techService:knowledge:edit']"
- v-if="canEdit(scope.row)"
- type="text"
- size="mini"
- @click="handleEdit(scope.row)"
- >{{ tsCommon("edit") }}</el-button>
- <el-button
- v-hasPermi="['techService:knowledge:remove']"
- v-if="canDelete(scope.row)"
- type="text"
- size="mini"
- @click="handleDelete(scope.row)"
- >{{ tsCommon("delete") }}</el-button>
- </template>
- </el-table-column>
- </el-table>
- <pagination
- v-show="total > 0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
- </el-card>
- <el-dialog :title="dialogTitle" :visible.sync="open" width="580px" append-to-body @close="cancel">
- <el-form :key="formKey" ref="form" :model="form" label-width="110px">
- <el-form-item prop="knowledgeTitle" :rules="formRules.knowledgeTitle">
- <template slot="label">{{ tsT("formTitle") }}</template>
- <el-input v-model="form.knowledgeTitle" :placeholder="tsT('phTitle')" maxlength="20" show-word-limit />
- </el-form-item>
- <el-form-item prop="knowledgeTopic" :rules="formRules.knowledgeTopic">
- <template slot="label">{{ tsT("formTopic") }}</template>
- <el-select v-model="form.knowledgeTopic" :placeholder="tsCommon('pleaseSelect')" style="width: 100%">
- <el-option v-for="item in topicOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- <el-form-item prop="introduction" :rules="formRules.introduction">
- <template slot="label">{{ tsT("formIntro") }}</template>
- <el-input
- v-model="form.introduction"
- type="textarea"
- :rows="2"
- :placeholder="tsT('phIntroOptional')"
- maxlength="50"
- show-word-limit
- />
- </el-form-item>
- <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
- <template slot="label">{{ tsT("formContent") }}</template>
- <el-upload
- class="upload-file-uploader"
- :action="uploadAction"
- :headers="uploadHeaders"
- :before-upload="beforeContentUpload"
- :on-success="handleContentUploadSuccess"
- :on-error="handleUploadHttpError"
- :show-file-list="false"
- >
- <el-button size="mini" type="primary">{{ tsCommon("pickFile") }}</el-button>
- </el-upload>
- <div class="el-upload__tip">{{ tsCommon("tipBody") }}</div>
- <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
- <li class="el-upload-list__item ele-upload-list__item-content">
- <el-link :href="form.contentFileUrl || '#'" :underline="false" target="_blank">
- <span class="el-icon-document"> {{ form.contentFileName }} </span>
- </el-link>
- <div class="ele-upload-list__item-content-action">
- <el-link type="danger" :underline="false" @click="clearContentFile">{{ tsCommon("del") }}</el-link>
- </div>
- </li>
- </ul>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">{{ tsCommon("ok") }}</el-button>
- <el-button @click="cancel">{{ tsCommon("cancel") }}</el-button>
- </div>
- </el-dialog>
- <el-dialog :title="tsCommon('viewTitle')" :visible.sync="viewOpen" width="560px" append-to-body>
- <el-form label-width="110px" size="small">
- <el-form-item :label="tsT('formTitle')">
- <span>{{ viewRow.knowledgeTitle || $t('techService.status.dash') }}</span>
- </el-form-item>
- <el-form-item :label="tsT('formTopic')">
- <span>{{ knowledgeTopicText(viewRow.knowledgeTopic) }}</span>
- </el-form-item>
- <el-form-item :label="tsT('formIntro')">
- <span>{{ viewRow.introduction || $t('techService.status.dash') }}</span>
- </el-form-item>
- <el-form-item :label="tsT('formContent')">
- <el-link
- v-if="viewRow.contentFileUrl"
- type="primary"
- :href="viewRow.contentFileUrl"
- target="_blank"
- >{{ viewRow.contentFileName }}</el-link>
- <span v-else>{{ $t('techService.status.dash') }}</span>
- </el-form-item>
- <el-form-item :label="tsCommon('colKb')">
- <span>{{ kbSyncStatusText(viewRow.kbSyncStatus) }}</span>
- </el-form-item>
- <el-form-item :label="tsT('viewCreateBy')">
- <span>{{ viewRow.createBy || $t('techService.status.dash') }}</span>
- </el-form-item>
- <el-form-item :label="tsT('viewUpdateBy')">
- <span>{{ viewRow.updateBy || $t('techService.status.dash') }}</span>
- </el-form-item>
- <el-form-item :label="tsT('viewUpdateTime')">
- <span>{{ viewRow.updateTime ? parseTime(viewRow.updateTime) : $t('techService.status.dash') }}</span>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button v-if="canEdit(viewRow)" v-hasPermi="['techService:knowledge:edit']" type="primary" @click="handleEditFromView">{{ tsCommon("edit") }}</el-button>
- <el-button @click="viewOpen = false">{{ tsCommon("close") }}</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import { getToken } from "@/utils/auth"
- import techServiceLocaleMixin from "@/mixins/techServiceLocaleMixin"
- import {
- listKnowledge,
- getKnowledge,
- addKnowledge,
- updateKnowledge,
- delKnowledge,
- syncKbKnowledge,
- removeKbKnowledge
- } from "@/api/techService/knowledge"
- const KB_SYNC_STATUS = { NOT_IN: 0, IN: 1 }
- export default {
- name: "TechServiceKnowledge",
- mixins: [techServiceLocaleMixin],
- data() {
- return {
- tsNs: "knowledge",
- loading: false,
- open: false,
- viewOpen: false,
- viewRow: {},
- dialogEdit: false,
- formKey: 0,
- total: 0,
- tableList: [],
- queryParams: {
- pageNum: 1,
- pageSize: 20,
- keyword: undefined,
- knowledgeTopic: undefined,
- kbSyncStatus: undefined
- },
- form: {},
- contentFileExts: ["pdf", "doc", "docx", "xls", "xlsx", "pptx"]
- }
- },
- computed: {
- dialogTitle() {
- return this.dialogEdit ? this.tsT("dialogEdit") : this.tsT("dialogAdd")
- },
- topicOptions() {
- return [1, 2, 3, 4, 5].map((value) => ({ label: this.tsT("topic" + value), value }))
- },
- formRules() {
- return {
- knowledgeTitle: [
- { required: true, message: this.tsT("ruleTitleRequired"), trigger: "blur" },
- { min: 1, max: 20, message: this.tsT("ruleTitleLen"), trigger: "blur" }
- ],
- knowledgeTopic: [{ required: true, message: this.tsT("ruleTopicRequired"), trigger: "change" }],
- introduction: [{ max: 50, message: this.tsT("ruleIntroMax"), trigger: "blur" }],
- contentFilePath: [{ required: true, message: this.tsT("ruleContentRequired"), trigger: "change" }]
- }
- },
- uploadAction() {
- return process.env.VUE_APP_BASE_API + "/common/upload"
- },
- uploadHeaders() {
- return { Authorization: "Bearer " + getToken() }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- canEdit(row) {
- return row && row.kbSyncStatus === KB_SYNC_STATUS.NOT_IN
- },
- canDelete(row) {
- return row && row.kbSyncStatus === KB_SYNC_STATUS.NOT_IN
- },
- canSyncKb(row) {
- return row && row.kbSyncStatus === KB_SYNC_STATUS.NOT_IN
- },
- canRemoveKb(row) {
- return row && row.kbSyncStatus === KB_SYNC_STATUS.IN
- },
- getList() {
- this.loading = true
- listKnowledge(this.queryParams)
- .then((res) => {
- this.tableList = res.rows || []
- this.total = res.total != null ? res.total : 0
- })
- .finally(() => {
- this.loading = false
- })
- },
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- resetQuery() {
- this.queryParams.keyword = undefined
- this.queryParams.knowledgeTopic = undefined
- this.queryParams.kbSyncStatus = undefined
- this.resetForm("queryForm")
- this.handleQuery()
- },
- resetFormModel() {
- this.form = {
- id: undefined,
- knowledgeTitle: undefined,
- knowledgeTopic: undefined,
- introduction: undefined,
- contentFileUrl: undefined,
- contentFilePath: undefined,
- contentFileName: undefined
- }
- },
- handleAdd() {
- this.formKey += 1
- this.resetFormModel()
- this.dialogEdit = false
- this.open = true
- this.$nextTick(() => this.resetForm("form"))
- },
- fillFormFromApi(data) {
- this.form = {
- id: data.id,
- knowledgeTitle: data.knowledgeTitle,
- knowledgeTopic: data.knowledgeTopic,
- introduction: data.introduction,
- contentFileUrl: data.contentFileUrl,
- contentFilePath: data.contentFilePath,
- contentFileName: data.contentFileName
- }
- },
- handleEdit(row) {
- if (!this.canEdit(row)) {
- return
- }
- getKnowledge(row.id).then((res) => {
- const data = res.data || {}
- this.formKey += 1
- this.dialogEdit = true
- this.fillFormFromApi(data)
- this.open = true
- this.viewOpen = false
- this.$nextTick(() => {
- if (this.$refs.form) {
- this.$refs.form.clearValidate()
- }
- })
- })
- },
- handleEditFromView() {
- this.viewOpen = false
- this.handleEdit(this.viewRow)
- },
- handleView(row) {
- getKnowledge(row.id).then((res) => {
- this.viewRow = res.data || {}
- this.viewOpen = true
- })
- },
- handleSyncKb(row) {
- this.runSyncKbAfterConfirm(this.tsT("confirmSync"), () => syncKbKnowledge(row.id))
- .then(() => {
- this.$modal.msgSuccess(this.tsCommon("msgSyncOk"))
- this.getList()
- })
- .catch(() => {})
- },
- handleRemoveKb(row) {
- this.runRemoveKbAfterConfirm(this.tsT("confirmRemoveKb"), () => removeKbKnowledge(row.id))
- .then(() => {
- this.$modal.msgSuccess(this.tsCommon("msgRemoveKbOk"))
- this.getList()
- })
- .catch(() => {})
- },
- handleDelete(row) {
- this.$modal
- .confirm(this.tsT("confirmDelete", { title: row.knowledgeTitle }))
- .then(() => delKnowledge(row.id))
- .then(() => {
- this.$modal.msgSuccess(this.tsCommon("msgDelOk"))
- this.viewOpen = false
- this.getList()
- })
- .catch(() => {})
- },
- extOf(fileName) {
- if (!fileName || fileName.lastIndexOf(".") < 0) {
- return ""
- }
- return fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase()
- },
- beforeContentUpload(file) {
- const ext = this.extOf(file.name)
- if (!this.contentFileExts.includes(ext)) {
- this.$modal.msgError(this.tsCommon("errBodyFmt"))
- return false
- }
- if (file.name.includes(",")) {
- this.$modal.msgError(this.tsCommon("errComma"))
- return false
- }
- if (file.size / 1024 / 1024 >= 30) {
- this.$modal.msgError(this.tsCommon("errBodyMb"))
- return false
- }
- this.$modal.loading(this.tsCommon("uploadingFile"))
- return true
- },
- handleContentUploadSuccess(res, file) {
- this.$modal.closeLoading()
- if (res.code === 200) {
- this.form.contentFileUrl = res.url
- this.form.contentFilePath = res.fileName
- this.form.contentFileName = res.originalFilename || file.name
- this.$refs.form && this.$refs.form.validateField("contentFilePath")
- } else {
- this.$modal.msgError(res.msg || this.tsCommon("errUploadFail"))
- }
- },
- clearContentFile() {
- this.form.contentFileUrl = undefined
- this.form.contentFilePath = undefined
- this.form.contentFileName = undefined
- this.$refs.form && this.$refs.form.validateField("contentFilePath")
- },
- handleUploadHttpError() {
- this.$modal.closeLoading()
- this.$modal.msgError(this.tsCommon("errUploadRetry"))
- },
- buildSubmitPayload() {
- return {
- knowledgeTitle: (this.form.knowledgeTitle || "").trim(),
- knowledgeTopic: this.form.knowledgeTopic,
- introduction: this.form.introduction ? this.form.introduction.trim() : undefined,
- contentFileUrl: this.form.contentFileUrl,
- contentFilePath: this.form.contentFilePath,
- contentFileName: this.form.contentFileName
- }
- },
- submitForm() {
- this.$refs.form.validate((valid) => {
- if (!valid) {
- return
- }
- const payload = this.buildSubmitPayload()
- if (this.dialogEdit) {
- payload.id = this.form.id
- updateKnowledge(payload).then(() => {
- this.$modal.msgSuccess(this.tsCommon("msgModOk"))
- this.open = false
- this.getList()
- })
- } else {
- addKnowledge(payload).then(() => {
- this.$modal.msgSuccess(this.tsCommon("msgAddOk"))
- this.open = false
- this.getList()
- })
- }
- })
- },
- cancel() {
- this.open = false
- this.resetFormModel()
- }
- }
- }
- </script>
- <style scoped>
- .upload-file-uploader {
- margin-bottom: 8px;
- }
- .upload-file-list {
- list-style: none;
- padding: 0;
- margin: 8px 0 0;
- }
- .upload-file-list .el-upload-list__item {
- border: 1px solid #e4e7ed;
- line-height: 2;
- padding: 0 8px;
- }
- .ele-upload-list__item-content {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- </style>
|