Commit ea5ad978 authored by 白舜's avatar 白舜 🎱

Merge branch 'dev-lp0602' into 'dev0602'

Dev lp0602

See merge request apaas/apaas-system-ui!1
parents d6dfaaeb 72fc342d
......@@ -115,7 +115,7 @@ export default {
// this.initMsg()
},
mounted() {
this.getSysOptions();
// this.getSysOptions();
},
methods: {
/**
......@@ -123,54 +123,54 @@ export default {
* limit:用户无操作时常限制(分钟)
*/
exitSystemAfterLimit(limit) {
window.lastOperateTime = new Date();
window.onload = this.addOperateListener;
this.setTimer(limit);
},
// exitSystemAfterLimit(limit) {
// window.lastOperateTime = new Date();
// window.onload = this.addOperateListener;
// this.setTimer(limit);
// },
//绑定用户操作事件
addOperateListener() {
document.addEventListener("mousemove", this.resetStartTime);
document.addEventListener("keydown", this.resetStartTime);
document.addEventListener("scroll", this.resetStartTime);
document.addEventListener("touchstart", this.resetStartTime);
},
// addOperateListener() {
// document.addEventListener("mousemove", this.resetStartTime);
// document.addEventListener("keydown", this.resetStartTime);
// document.addEventListener("scroll", this.resetStartTime);
// document.addEventListener("touchstart", this.resetStartTime);
// },
//重置起始时间
resetStartTime() {
window.lastOperateTime = new Date();
},
// resetStartTime() {
// window.lastOperateTime = new Date();
// },
//设置定时器
setTimer(limit) {
window.logTimer = setInterval(() => {
var currentTime = new Date();
var timeDiff = currentTime.getTime() - lastOperateTime.getTime();
if (timeDiff > limit * 60 * 1000) {
clearInterval(window.logTimer);
this.$axios.post(`/apaas/system/v5/user/logout`).then((res) => {
if (res.data.code == "200") {
window.location.href = `/apaas/manage/ui/#/login`;
this.$store.commit("setUserInfo", null);
clearCookie("bgToken");
this.$message.success("退出成功");
resetRouter();
} else {
this.$message.error("退出失败");
}
});
}
}, 1000);
},
// setTimer(limit) {
// window.logTimer = setInterval(() => {
// var currentTime = new Date();
// var timeDiff = currentTime.getTime() - lastOperateTime.getTime();
// if (timeDiff > limit * 60 * 1000) {
// clearInterval(window.logTimer);
// this.$axios.post(`/apaas/system/v5/user/logout`).then((res) => {
// if (res.data.code == "200") {
// window.location.href = `/apaas/manage/ui/#/login`;
// this.$store.commit("setUserInfo", null);
// clearCookie("bgToken");
// this.$message.success("退出成功");
// resetRouter();
// } else {
// this.$message.error("退出失败");
// }
// });
// }
// }, 1000);
// },
getSysOptions() {
this.$axios.get(`/apaas/system/v5/sysOptions`).then((res) => {
if (res.data.code == 200) {
const result = res.data.data || {};
if (result.session_validity) this.exitSystemAfterLimit(result.session_validity);
} else {
this.$message.error(res.data.data);
}
});
},
// getSysOptions() {
// this.$axios.get(`/apaas/system/v5/sysOptions`).then((res) => {
// if (res.data.code == 200) {
// const result = res.data.data || {};
// if (result.session_validity) this.exitSystemAfterLimit(result.session_validity);
// } else {
// this.$message.error(res.data.data);
// }
// });
// },
openMsg(data) {
this.readFlag = !this.readFlag;
......
......@@ -2,6 +2,9 @@ import { createApp } from "vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import mavonEditor from "mavon-editor";
import "mavon-editor/dist/css/index.css";
import locale from "element-plus/lib/locale/lang/zh-cn";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
......@@ -101,7 +104,13 @@ Promise.all([getUser(), getMenu("dadb2d3f-e263-48d1-9389-42acb9ea49f8")])
console.error(e);
})
.finally(() => {
createVue.use(ElementPlus, { locale }).use(store).use(router).use(i18n).use(bgui);
createVue
.use(ElementPlus, { locale })
.use(store)
.use(router)
.use(i18n)
.use(bgui)
.use(mavonEditor);
createVue.mount("#app");
});
......
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="flex_row">
<div class="flex_left bgc_white">
<div class="tree_header">文档类型</div>
<div class="tree_content">
<div class="search">
<el-input v-model="filterTree" placeholder="请输入文档类型名称" :prefix-icon="Search" />
</div>
<div class="tree">
<el-tree
ref="treeRef"
:data="typeData"
:props="defaultProps"
@node-click="handleNodeClick"
node-key="classify_id"
:highlight-current="true"
:filter-node-method="filterNode"
:default-expand-all="true">
<template #default="{ node, data }">
<div class="custom_tree_node">
<span class="label-text" :title="node.label">{{ node.label }} </span>
</div>
</template>
</el-tree>
</div>
</div>
</div>
<div class="flex_right bgc_white">
<div class="main_container">
<bg-filter-group
@search="changeSearch"
v-model="filter.search"
placeholder="请输入文档类型名称">
<template v-if="treeLevel === 0" v-slot:left_action>
<div class="apaas_button">
<el-button type="primary" @click="addDocType">
<bg-icon
style="font-size: 12px; color: #fff; margin-right: 8px"
icon="#bg-ic-add"></bg-icon>
新增
</el-button>
</div>
</template>
<template v-slot:filter_group>
<div class="left-filter filter_list">
<div class="filter_item">
<span class="filter_title">状态</span>
<el-select v-model="filter.is_active" placeholder="请选择" style="width: 300px">
<el-option label="全部" value=""></el-option>
<el-option label="已启用" :value="1"> </el-option>
<el-option label="已停用" :value="0"> </el-option>
</el-select>
</div>
</div>
<div class="right-action apaas_button">
<el-button type="primary" @click="filterAction"> 查询 </el-button>
<el-button type="default" @click="filterClear"> 重置 </el-button>
</div>
</template>
</bg-filter-group>
<div class="table_container apaas_scroll">
<bg-table
ref="dataTable"
:headers="headers"
:rows="tableRows"
:isIndex="true"
:stripe="true">
<template v-slot:is_active="{ row }">
<el-switch
style="
--el-switch-on-color: #2b4695;
--el-switch-off-color: #cbced7;
height: 20px;
"
v-model="row.is_active"
inline-prompt
:active-value="1"
:inactive-value="0"
active-text="是"
inactive-text="否"
:before-change="() => beforeSwitchStatus(row)" />
</template>
<template v-slot:action="{ row }">
<bg-table-btn @click="editCurType(row)"> 编辑 </bg-table-btn>
<bg-table-btn @click="deleteCurType(row)"> 删除 </bg-table-btn>
</template>
</bg-table>
<div class="pagination_box">
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</div>
</div>
<el-dialog
v-model="secondTipsDialogConfig.visible"
:title="secondTipsDialogConfig.title"
width="520px">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
{{ secondTipsDialogConfig.content }}
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseSecondTipsDialog">取消</el-button>
<el-button type="primary" @click="secondConfirm(secondTipsDialogConfig.type)"
>确定</el-button
>
</span>
</template>
</el-dialog>
<el-dialog
v-model="formDialogConfig.visible"
:title="formDialogConfig.title"
width="600px"
:before-close="handleCloseForm">
<el-form label-width="80px" :model="formData" :rules="rules" ref="ruleForm">
<el-form-item required label="上级类型" prop="parent_id">
<el-tree-select
v-model="formData.parent_id"
:data="parentTypeData"
:props="defaultProps"
node-key="classify_id"
:highlight-current="true"
:filter-node-method="filterNode"
check-strictly
filterable
:render-after-expand="false" />
</el-form-item>
<el-form-item label="类型名称" prop="classify_name">
<el-input v-model="formData.classify_name" placeholder="请输入"> </el-input>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input v-model.number.trim="formData.sort" placeholder="请输入"> </el-input>
</el-form-item>
<el-form-item label="备注" prop="describe">
<el-input v-model="formData.describe" :rows="3" type="textarea" placeholder="请输入">
</el-input>
</el-form-item>
<el-form-item label="是否启用" prop="is_active">
<el-switch
style="--el-switch-on-color: #2b4695; --el-switch-off-color: #cbced7; height: 20px"
v-model="formData.is_active"
inline-prompt
:active-value="1"
:inactive-value="0"
active-text="是"
inactive-text="否" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseForm">取消</el-button>
<el-button type="primary" @click="confirmForm">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { Search } from "@element-plus/icons-vue";
import { watch, nextTick, reactive, toRefs, ref, computed, onBeforeMount } from "vue";
import { useRoute, useRouter } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const dataTable = ref(null);
const ruleForm = ref(null);
const selectNode = ref(null);
const selectNodeObj = ref(null);
const filterTree = ref("");
const treeRef = ref(null);
//校验上级类型
const state = reactive({
filter: {
search: "",
is_active: "",
page: 1,
limit: 10,
},
headers: [
{
label: "类型名称",
prop: "classify_name",
minWidth: 160,
},
{
label: "上级类型名称",
prop: "parent_classify_name",
minWidth: 160,
},
{
label: "启用状态",
prop: "is_active",
},
{
label: "操作",
prop: "action",
width: 220,
fixed: "right",
},
],
tableRows: [],
tableTotal: 0,
formDialogConfig: {
visible: false,
title: "新增",
type: "add",
},
formData: {
parent_id: "",
classify_name: "",
sort: "",
describe: "",
is_active: 0,
},
rules: {
parent_id: [
{
required: true,
message: "请选择",
trigger: "change",
},
],
classify_name: [
{
required: true,
message: "请输入",
trigger: "blur",
},
],
},
//左侧类型树层级
treeLevel: 0,
//删除确认弹框
secondTipsDialogConfig: {
visible: false,
title: "",
type: "",
content: "",
},
selectedRow: null,
});
const {
filter,
headers,
tableRows,
tableTotal,
formDialogConfig,
formData,
rules,
treeLevel,
secondTipsDialogConfig,
} = toRefs(state);
onBeforeMount(() => {
getTypeTree();
});
watch(filterTree, (val) => {
treeRef.value.filter(val);
});
watch(selectNode, (val) => {
state.formData.parent_id = val;
});
const filterAction = () => {
changePage(1);
};
const filterClear = () => {
state.filter = {
search: "",
is_active: "",
page: 1,
limit: 10,
};
changePage(1);
};
const router = useRouter();
const getTableRows = () => {
let params = {
...state.filter,
classify_id: selectNodeObj.value.id ? selectNodeObj.value.id : undefined,
};
axios
.get(`/apaas/knowledge/v5/documentmgr/classify/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
state.tableRows = res.data.data || [];
state.tableTotal = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
//新增文档类型
const addDocType = () => {
state.formDialogConfig = {
visible: true,
title: "新增",
type: "add",
};
};
const handleNodeClick = (data) => {
selectNode.value = data.classify_id;
selectNodeObj.value = data;
state.treeLevel = data.level;
changePage(1);
};
const typeData = ref([]);
const parentTypeData = ref([]);
const defaultProps = {
label: "classify_name",
children: "children",
value: "classify_id",
};
const getTypeTree = () => {
axios.get(`/apaas/knowledge/v5/documentmgr/classify/tree`).then((res) => {
if (res.data.code == 200) {
const result = res.data.data || [];
result.length ? (result[0].classify_id = "topLevel") : null;
typeData.value = result;
parentTypeData.value = getParentTree(typeData.value);
selectNode.value = typeData.value.length > 0 ? typeData.value[0].classify_id : "";
selectNodeObj.value = typeData.value.length > 0 ? typeData.value[0] : null;
nextTick(() => {
treeRef.value.setCurrentNode(selectNodeObj.value);
});
changePage(1);
} else {
ElMessage.error(res.data.data);
}
});
};
//过滤掉level不为0的层级
const getParentTree = (data) => {
let arr = [];
data.forEach((item) => {
if (item.level === 0) {
let obj = { classify_id: item.classify_id, classify_name: item.classify_name };
if (item.children) obj.children = getParentTree(item.children);
arr.push(obj);
}
});
return arr;
};
const filterNode = (value, data) => {
if (!value) return true;
return data.classify_name.includes(value);
};
const changeSize = (size) => {
state.filter.limit = size;
state.filter.page = 1;
changePage(1);
};
const changePage = (page) => {
state.filter.page = page;
getTableRows();
};
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 表格关键字筛选
const handleCloseForm = () => {
state.formData = {
parent_id: selectNode.value,
classify_name: "",
sort: "",
describe: "",
is_active: 0,
};
state.formDialogConfig.visible = false;
};
const editCurType = async (row) => {
const res = await axios.get(`/apaas/knowledge/v5/documentmgr/classify/detail/${row.id}`);
if (res.data.code == 200) {
const data = res.data.data || {};
state.formData = {
parent_id: data.parent_id,
classify_name: data.classify_name,
sort: data.sort,
describe: data.describe,
is_active: data.is_active,
};
state.selectedRow = row;
state.formDialogConfig = {
visible: true,
title: "编辑",
type: "update",
};
} else {
ElMessage.error(res.data.data);
}
};
const confirmForm = () => {
ruleForm.value.validate((valid, fields) => {
let params = {
...state.formData,
parent_id: state.formData.parent_id !== "topLevel" ? state.formData.parent_id : "",
};
if (state.formDialogConfig.type === "update") {
params = { ...params, id: state.selectedRow.id };
}
if (valid) {
axios
.post(`/apaas/knowledge/v5/documentmgr/classify/${state.formDialogConfig.type}`, params)
.then((res) => {
if (res.data.code == 200) {
getTypeTree();
ElMessage.success(res.data.msg);
} else {
ElMessage.error(res.data.data);
}
handleCloseForm();
});
}
});
};
const handleCloseSecondTipsDialog = () => {
state.secondTipsDialogConfig.visible = false;
};
const deleteCurType = (row) => {
if (row.is_active === 1) return ElMessage.warning("该文档类型已启用,请先停用后再删除!");
state.selectedRow = row;
state.secondTipsDialogConfig = {
visible: true,
title: "删除",
type: "delete",
content: "确定删除该文档类型吗?",
};
};
const beforeSwitchStatus = async (row) => {
const res = await axios.get(`/apaas/knowledge/v5/documentmgr/classify/quote/${row.id}`);
if (!res.data.data) {
ElMessage.warning("请将该文档类型下所挂载的文档删除或转移至其他文档类型下再停用!");
return false;
}
const text = row.is_active ? "停用" : "启用";
state.selectedRow = row;
state.secondTipsDialogConfig = {
visible: true,
title: text,
type: "switchStatus",
content: `确定${text}该文档类型吗?`,
};
return false;
};
const secondConfirm = () => {
if (state.secondTipsDialogConfig.type === "delete") {
axios.delete(`/apaas/knowledge/v5/documentmgr/classify/${state.selectedRow.id}`).then((res) => {
if (res.data.code == 200) {
getTypeTree();
ElMessage.success(res.data.msg);
} else {
ElMessage.error(res.data.data);
}
handleCloseSecondTipsDialog();
});
return;
}
if (state.secondTipsDialogConfig.type === "switchStatus") {
axios
.get(`/apaas/knowledge/v5/documentmgr/classify/active/${state.selectedRow.id}`)
.then((res) => {
if (res.data.code == 200) {
getTypeTree();
ElMessage.success(res.data.msg);
} else {
ElMessage.error(res.data.data);
}
handleCloseSecondTipsDialog();
});
return;
}
};
</script>
<style lang="scss" scoped>
.tree_header {
height: 40px;
line-height: 40px;
background-color: #f7f7f9;
border-radius: 6px 6px 0px 0px;
font-size: 16px;
letter-spacing: 0px;
color: #202531;
padding-left: 16px;
}
.tree_content {
overflow: hidden;
height: calc(100% - 45px);
}
.search {
padding: 16px;
}
.tree {
overflow: auto;
height: calc(100% - 65px);
}
.tree :deep() .el-tree-node > .el-tree-node__children {
overflow: unset;
}
.tree :deep().noFocus:focus > .el-tree-node__content {
background-color: #fff;
}
.custom_tree_node {
width: 100%;
font-size: 14px;
color: #202531;
padding-right: 16px;
}
.label-text:hover {
padding: 3px 0;
background-color: var(--el-tree-node-hover-bg-color);
}
.main_container {
height: 100%;
}
.table_container {
height: calc(100% - 30px);
overflow: auto;
padding: 0 16px;
}
:deep() .el-switch__core {
min-width: 44px;
}
.el-form {
margin-top: 24px;
:deep() .el-select {
width: 100%;
.el-input .el-select__caret {
color: #b9b9b9;
}
}
}
.pagination_box {
position: sticky;
position: -webkit-sticky;
margin-top: 16px;
bottom: 25px;
background-color: #fff;
z-index: 1024;
height: 40px;
line-height: 40px;
padding-top: 5px;
}
.bg-pagination {
bottom: unset;
margin-top: 0px;
}
</style>
<!-- 角色管理 -->
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="form_content apaas_scroll_nor">
<el-form label-width="80px" :model="formData" :rules="rules" ref="ruleForm">
<el-form-item label="文档类型">
<el-input disabled v-model="docTypeName"> </el-input>
</el-form-item>
<el-form-item label="文档名称" prop="title">
<el-input v-model="formData.title" placeholder="请输入"> </el-input>
</el-form-item>
<el-form-item class="editor" label="文档内容" prop="content">
<mavon-editor
class="mark-down-edit"
ref="editorRef"
v-model="formData.content"
:box-shadow="false"
:autofocus="false"
placeholder="请输入正文"
@img-add="(...arg) => $imgAdd(arg, editorRef)" />
</el-form-item>
</el-form>
</div>
<div class="operate_btns">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="publish">发布</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, computed, ref, onBeforeMount, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { $imgAdd } from "../helper";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute();
const router = useRouter();
const ruleForm = ref(null);
const editorRef = ref();
const state = reactive({
//表单数据
formData: {
classify_id: route.query.classify_id,
title: "",
content: "",
},
//表单校验规则
rules: {
title: [
{
required: true,
message: "请输入",
trigger: "blur",
},
],
},
docTypeNameArr: ["平台公开"],
});
const { formData, rules } = toRefs(state);
const docTypeName = computed(() => {
return state.docTypeNameArr.join("/");
});
onBeforeMount(() => {
getTypeTree();
});
const getTypeTree = () => {
axios.get(`/apaas/knowledge/v5/documentmgr/classify/tree`).then((res) => {
if (res.data.code == 200) {
const result = res.data.data || [];
getDocTypeName(result[0].children, route.query.classify_id);
} else {
ElMessage.error(res.data.data);
}
});
};
const getDocTypeName = (data, classifyId) => {
const findItem = data.find((item) => item.classify_id === classifyId);
if (findItem) {
state.docTypeNameArr.push(findItem.classify_name);
return true;
}
data.find((item) => {
if (item.children && item.children.length) {
const res = getDocTypeName(item.children, classifyId);
if (res) {
state.docTypeNameArr.splice(state.docTypeNameArr.length - 2, 0, item.classify_name);
}
return res;
}
});
};
//取消
const cancel = () => {
router.push("/support/document");
};
//发布
const publish = () => {
ruleForm.value.validate((valid, fields) => {
let params = {
...state.formData,
};
if (valid) {
axios.post(`/apaas/knowledge/v5/documentmgr/document/add`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
router.push("/support/document");
} else {
ElMessage.error(res.data.data);
}
});
}
});
};
</script>
<style lang="scss" scoped>
.page_container {
.main_container {
position: relative;
margin: 0 0 16px;
width: 100%;
height: calc(100% - 62px);
padding: 24px 0 70px;
overflow: auto;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
.form_content {
overflow: auto;
width: 60%;
min-width: 972px;
height: 100%;
padding-left: 35px;
}
.mark-down-edit {
height: 525px;
border: solid 1px #dadee7;
}
.operate_btns {
position: absolute;
bottom: 0;
width: 100%;
height: 70px;
text-align: right;
line-height: 68px;
border-top: solid 1px #e6e9ef;
.el-button {
width: 92px;
margin-right: 16px;
}
}
}
}
</style>
<!-- 角色管理 -->
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="form_content apaas_scroll_nor">
<el-form label-width="80px" :model="formData" :rules="rules" ref="ruleForm">
<el-form-item label="文档类型">
<el-input disabled v-model="docTypeName"> </el-input>
</el-form-item>
<el-form-item label="文档名称" prop="title">
<el-input v-model="formData.title" disabled placeholder="请输入"> </el-input>
</el-form-item>
<el-form-item class="editor" label="文档内容" prop="content">
<mavon-editor
class="mark-down-edit"
ref="editorRef"
v-model="formData.content"
:box-shadow="false"
:autofocus="false"
placeholder="请输入正文"
@img-add="(...arg) => $imgAdd(arg, editorRef)" />
</el-form-item>
</el-form>
</div>
<div class="operate_btns">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="publish">发布</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, computed, ref, onBeforeMount, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { $imgAdd } from "../helper";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute();
const router = useRouter();
const ruleForm = ref(null);
const editorRef = ref();
const state = reactive({
//表单数据
formData: {
classify_id: route.query.classify_id,
title: "",
content: "",
},
//表单校验规则
rules: {
title: [
{
required: true,
message: "请输入",
trigger: "blur",
},
],
},
docTypeNameArr: ["平台公开"],
});
const { formData, rules } = toRefs(state);
const docTypeName = computed(() => {
return state.docTypeNameArr.join("/");
});
onBeforeMount(() => {
getTypeTree();
getEditInfo();
});
const getTypeTree = () => {
axios.get(`/apaas/knowledge/v5/documentmgr/classify/tree`).then((res) => {
if (res.data.code == 200) {
const result = res.data.data || [];
getDocTypeName(result[0].children, route.query.classify_id);
} else {
ElMessage.error(res.data.data);
}
});
};
const getDocTypeName = (data, classifyId) => {
const findItem = data.find((item) => item.classify_id === classifyId);
if (findItem) {
state.docTypeNameArr.push(findItem.classify_name);
return true;
}
data.find((item) => {
if (item.children && item.children.length) {
const res = getDocTypeName(item.children, classifyId);
if (res) {
state.docTypeNameArr.splice(state.docTypeNameArr.length - 2, 0, item.classify_name);
}
return res;
}
});
};
const getEditInfo = () => {
axios.get(`/apaas/knowledge/v5/documentmgr/document/detail/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
const result = res.data.data || {};
Object.keys(state.formData).forEach((key) => {
state.formData[key] = result[key];
});
} else {
ElMessage.error(res.data.data);
}
});
};
//取消
const cancel = () => {
router.push("/support/document");
};
//发布
const publish = () => {
ruleForm.value.validate((valid, fields) => {
let params = {
id: +route.query.id,
content: state.formData.content,
};
if (valid) {
axios.post(`/apaas/knowledge/v5/documentmgr/document/update`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
router.push("/support/document");
} else {
ElMessage.error(res.data.data);
}
});
}
});
};
</script>
<style lang="scss" scoped>
.page_container {
.main_container {
position: relative;
margin: 0 0 16px;
width: 100%;
height: calc(100% - 62px);
padding: 24px 0 70px;
overflow: auto;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
.form_content {
overflow: auto;
width: 60%;
min-width: 972px;
height: 100%;
padding-left: 35px;
}
.mark-down-edit {
height: 525px;
border: solid 1px #dadee7;
}
.operate_btns {
position: absolute;
bottom: 0;
width: 100%;
height: 70px;
text-align: right;
line-height: 68px;
border-top: solid 1px #e6e9ef;
.el-button {
width: 92px;
margin-right: 16px;
}
}
}
}
</style>
import $axios from "@/request/http";
export const $imgAdd = function (args, editorRef) {
const [pos, $file] = args;
const formdata = new FormData();
formdata.append("file", $file);
formdata.append("directory", "image");
$axios
.post("/apaas/common/image/upload", formdata, {
headers: { "Content-Type": "multipart/form-data" },
})
.then(({ data }) => {
editorRef.$img2Url(pos, data.data);
});
};
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="flex_row">
<div class="flex_left bgc_white">
<div class="tree_header">文档类型</div>
<div class="tree_content">
<div class="search">
<el-input v-model="filterTree" placeholder="请输入文档名称" :prefix-icon="Search" />
</div>
<div class="tree">
<el-tree
ref="treeRef"
:data="typeData"
:props="defaultProps"
@node-click="handleNodeClick"
node-key="classify_id"
:highlight-current="true"
:filter-node-method="filterNode"
:default-expand-all="true">
<template #default="{ node, data }">
<div class="custom_tree_node">
<span class="label-text" :title="node.label">{{ node.label }} </span>
</div>
</template>
</el-tree>
</div>
</div>
</div>
<div class="flex_right bgc_white">
<div class="main_container">
<bg-filter-group
@search="changeSearch"
v-model="filter.search"
placeholder="请输入文档类型名称">
<template v-if="showAdd" v-slot:left_action>
<div class="apaas_button">
<el-button type="primary" @click="addDoc">
<bg-icon
style="font-size: 12px; color: #fff; margin-right: 8px"
icon="#bg-ic-add"></bg-icon>
新增
</el-button>
</div>
</template>
<template v-slot:filter_group>
<div class="left-filter filter_list">
<div class="filter_item">
<span class="filter_title">更新时间</span>
<el-date-picker
v-model="filter.time"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 300px; flex: 0 0 auto" />
</div>
</div>
<div class="right-action apaas_button">
<el-button type="primary" @click="filterAction"> 查询 </el-button>
<el-button type="default" @click="filterClear"> 重置 </el-button>
</div>
</template>
</bg-filter-group>
<div class="table_container apaas_scroll">
<bg-table
ref="dataTable"
:headers="headers"
:rows="tableRows"
:isIndex="true"
:stripe="true">
<template v-slot:action="{ row }">
<bg-table-btn @click="editCurDoc(row)"> 编辑 </bg-table-btn>
<bg-table-btn @click="deleteCurDoc(row)"> 删除 </bg-table-btn>
</template>
</bg-table>
<div class="pagination_box">
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</div>
</div>
<el-dialog v-model="deleteDialogVisible" title="删除" width="520px">
<div class="warning_info delete_tips">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
<span
>删除后,该文档将不再{{ selectedRow.classify_name }}里展示且<span style="color: red"
>删除后无法撤销</span
>,确定要删除吗?</span
>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseDeleteDialog">取消</el-button>
<el-button type="primary" @click="confirmDelete">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { Search } from "@element-plus/icons-vue";
import { watch, nextTick, reactive, toRefs, ref, computed, onBeforeMount } from "vue";
import { useRouter } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const dataTable = ref(null);
const ruleForm = ref(null);
const selectNodeObj = ref({});
const filterTree = ref("");
const treeRef = ref(null);
const typeData = ref([]);
const defaultProps = {
label: "classify_name",
children: "children",
value: "classify_id",
};
//校验上级类型
const state = reactive({
filter: {
search: "",
time: [],
page: 1,
limit: 10,
},
headers: [
{
label: "文档名称",
prop: "title",
minWidth: 160,
},
{
label: "文档类型",
prop: "classify_name",
minWidth: 160,
},
{
label: "操作人",
prop: "updated_by",
},
{
label: "最后更新时间",
prop: "updated_time",
},
{
label: "操作",
prop: "action",
width: 220,
fixed: "right",
},
],
tableRows: [],
tableTotal: 0,
//是否展示新增按钮,只有当选择没有子节点的叶子节点才展示
showAdd: false,
//删除确认弹框
deleteDialogVisible: false,
selectedRow: null,
});
const { filter, headers, tableRows, tableTotal, showAdd, deleteDialogVisible, selectedRow } =
toRefs(state);
onBeforeMount(() => {
getTypeTree();
});
watch(filterTree, (val) => {
treeRef.value.filter(val);
});
const filterAction = () => {
changePage(1);
};
const filterClear = () => {
state.filter = {
search: "",
time: [],
page: 1,
limit: 10,
};
changePage(1);
};
const router = useRouter();
const getTableRows = () => {
let params = {
...state.filter,
start_at: state.filter.time ? state.filter.time[0] : undefined,
end_at: state.filter.time ? state.filter.time[1] : undefined,
classify_id: selectNodeObj.value.id ? selectNodeObj.value.id : undefined,
};
delete params.time;
axios
.get(`/apaas/knowledge/v5/documentmgr/document/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
state.tableRows = res.data.data || [];
state.tableTotal = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
//新增文档
const addDoc = () => {
router.push({
path: "/support/document/add",
query: {
classify_id: selectNodeObj.value.classify_id,
},
});
};
const handleNodeClick = (data) => {
selectNodeObj.value = data;
state.showAdd = !(data.children && data.children.length);
changePage(1);
};
const getTypeTree = () => {
axios.get(`/apaas/knowledge/v5/documentmgr/classify/tree`).then((res) => {
if (res.data.code == 200) {
const result = res.data.data || [];
typeData.value = result;
selectNodeObj.value = typeData.value.length > 0 ? typeData.value[0] : {};
nextTick(() => {
treeRef.value.setCurrentNode(selectNodeObj.value);
});
changePage(1);
} else {
ElMessage.error(res.data.data);
}
});
};
const filterNode = (value, data) => {
if (!value) return true;
return data.classify_name.includes(value);
};
const changeSize = (size) => {
state.filter.limit = size;
state.filter.page = 1;
changePage(1);
};
const changePage = (page) => {
state.filter.page = page;
getTableRows();
};
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 表格关键字筛选
const editCurDoc = async (row) => {
router.push({
path: "/support/document/edit",
query: {
id: row.id,
classify_id: row.classify_id,
},
});
};
const handleCloseDeleteDialog = () => {
state.deleteDialogVisible = false;
};
const deleteCurDoc = (row) => {
state.selectedRow = row;
state.deleteDialogVisible = true;
};
const confirmDelete = () => {
axios.delete(`/apaas/knowledge/v5/documentmgr/classify/${state.selectedRow.id}`).then((res) => {
if (res.data.code == 200) {
changePage(1);
ElMessage.success(res.data.msg);
} else {
ElMessage.error(res.data.data);
}
handleCloseDeleteDialog();
});
};
</script>
<style lang="scss" scoped>
.tree_header {
height: 40px;
line-height: 40px;
background-color: #f7f7f9;
border-radius: 6px 6px 0px 0px;
font-size: 16px;
letter-spacing: 0px;
color: #202531;
padding-left: 16px;
}
.tree_content {
overflow: hidden;
height: calc(100% - 45px);
}
.search {
padding: 16px;
}
.tree {
overflow: auto;
height: calc(100% - 65px);
}
.tree :deep() .el-tree-node > .el-tree-node__children {
overflow: unset;
}
.tree :deep().noFocus:focus > .el-tree-node__content {
background-color: #fff;
}
.custom_tree_node {
width: 100%;
font-size: 14px;
color: #202531;
padding-right: 16px;
}
.label-text:hover {
padding: 3px 0;
background-color: var(--el-tree-node-hover-bg-color);
}
.main_container {
height: 100%;
}
.table_container {
height: calc(100% - 30px);
overflow: auto;
padding: 0 16px;
}
.delete_tips {
display: flex;
align-items: baseline;
line-height: 20px;
}
.pagination_box {
position: sticky;
position: -webkit-sticky;
margin-top: 16px;
bottom: 25px;
background-color: #fff;
z-index: 1024;
height: 40px;
line-height: 40px;
padding-top: 5px;
}
.bg-pagination {
bottom: unset;
margin-top: 0px;
}
</style>
......@@ -56,6 +56,15 @@ export default {
changeOrigin: true,
secure: false,
},
"/apaas/knowledge/v5": {
target: "https://apaas5.wodcloud.com/apaas/knowledge/v5", // 所要代理的目标地址
rewrite: (path) => {
console.log("path", path);
return path.replace(/^\/apaas\/knowledge\/v5/, "");
}, // 重写传过来的path路径,比如 `/api/index/1?id=10&name=zs`(注意:path路径最前面有斜杠(/),因此,正则匹配的时候不要忘了是斜杠(/)开头的;选项的 key 也是斜杠(/)开头的)
changeOrigin: true, // true/false, Default: false - changes the origin of the host header to the target URL
secure: false, //解决证书缺失问题
},
},
},
build: {
......
......@@ -438,6 +438,11 @@ clipboard@^2.0.11:
select "^1.1.2"
tiny-emitter "^2.0.0"
commander@^2.20.3:
version "2.20.3"
resolved "https://mirrors.cloud.tencent.com/npm/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
compute-scroll-into-view@^1.0.20:
version "1.0.20"
resolved "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz"
......@@ -455,6 +460,11 @@ css-line-break@^2.1.0:
dependencies:
utrie "^1.0.2"
cssfilter@0.0.10:
version "0.0.10"
resolved "https://mirrors.cloud.tencent.com/npm/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=
csstype@^2.6.8:
version "2.6.20"
resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.20.tgz"
......@@ -744,6 +754,16 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
highlight.js-async-webpack@^1.0.4:
version "1.0.4"
resolved "https://mirrors.cloud.tencent.com/npm/highlight.js-async-webpack/-/highlight.js-async-webpack-1.0.4.tgz#c06b67bf99f049045d62b756e5855b0912ec616c"
integrity sha1-wGtnv5nwSQRdYrdW5YVbCRLsYWw=
highlight.js@^9.11.0:
version "9.18.5"
resolved "https://mirrors.cloud.tencent.com/npm/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825"
integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==
html-void-elements@^2.0.0:
version "2.0.1"
resolved "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz"
......@@ -895,6 +915,15 @@ markdown-it@^13.0.1:
mdurl "^1.0.1"
uc.micro "^1.0.5"
mavon-editor@^3.0.0:
version "3.0.0"
resolved "https://mirrors.cloud.tencent.com/npm/mavon-editor/-/mavon-editor-3.0.0.tgz#232a34a8ceb2d9d1dfc7822103d09d1ffcf779ba"
integrity sha512-7TrZz4Z8+UUbQmVyQ688m50A9XBs2gZrOw8QaeWCvuo2stifyKukb0rPpmrBIMEeA1FCLPkR5dMf7BEMAc04uw==
dependencies:
highlight.js "^9.11.0"
highlight.js-async-webpack "^1.0.4"
xss "^1.0.6"
mdurl@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz"
......@@ -1193,6 +1222,14 @@ wildcard@^1.1.0:
resolved "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz"
integrity sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==
xss@^1.0.6:
version "1.0.14"
resolved "https://mirrors.cloud.tencent.com/npm/xss/-/xss-1.0.14.tgz#4f3efbde75ad0d82e9921cc3c95e6590dd336694"
integrity sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==
dependencies:
commander "^2.20.3"
cssfilter "0.0.10"
zrender@5.3.2:
version "5.3.2"
resolved "https://registry.npmmirror.com/zrender/-/zrender-5.3.2.tgz"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment