mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-14 22:53:47 +08:00
vue3的js和ts代码上传
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
<!--
|
||||
* 目录表单
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" :title="formState.helpDocCatalogId ? '编辑目录' : '添加目录'" @ok="handleOk" destroyOnClose>
|
||||
<a-form ref="formRef" :model="formState" :rules="rules" layout="vertical">
|
||||
<a-form-item label="上级目录" name="parentId" v-if="formState.parentId != 0">
|
||||
<HelpDocCatalogTreeSelect ref="helpDocCatalogTreeSelect" v-model:value="formState.parentId" :defaultValueFlag="false" width="100%" />
|
||||
</a-form-item>
|
||||
<a-form-item label="目录名称" name="name">
|
||||
<a-input v-model:value.trim="formState.name" placeholder="请输入目录名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="目录排序 (值越小越靠前!)" name="sort">
|
||||
<a-input-number style="width: 100%" v-model:value="formState.sort" :min="0" placeholder="请输入目录名称" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import message from 'ant-design-vue/lib/message';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { helpDocCatalogApi } from '/@/api/support/help-doc/help-doc-catalog-api';
|
||||
import HelpDocCatalogTreeSelect from './help-doc-catalog-tree-select.vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
// ----------------------- 对外暴漏 ---------------------
|
||||
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
|
||||
// ----------------------- modal 的显示与隐藏 ---------------------
|
||||
const emits = defineEmits(['refresh']);
|
||||
|
||||
const visible = ref(false);
|
||||
function showModal(data) {
|
||||
visible.value = true;
|
||||
updateFormData(data);
|
||||
}
|
||||
function closeModal() {
|
||||
visible.value = false;
|
||||
resetFormData();
|
||||
}
|
||||
|
||||
// ----------------------- form 表单操作 ---------------------
|
||||
const formRef = ref();
|
||||
const helpDocCatalogTreeSelect = ref();
|
||||
const defaultHelpDocCatalogForm = {
|
||||
helpDocCatalogId: undefined,
|
||||
name: undefined,
|
||||
parentId: undefined,
|
||||
sort: 0,
|
||||
};
|
||||
const employeeSelect = ref();
|
||||
|
||||
let formState = reactive({
|
||||
...defaultHelpDocCatalogForm,
|
||||
});
|
||||
// 表单校验规则
|
||||
const rules = {
|
||||
parentId: [{ required: true, message: '上级目录不能为空' }],
|
||||
name: [
|
||||
{ required: true, message: '目录名称不能为空' },
|
||||
{ max: 50, message: '目录名称不能大于20个字符', trigger: 'blur' },
|
||||
],
|
||||
};
|
||||
// 更新表单数据
|
||||
function updateFormData(data) {
|
||||
Object.assign(formState, defaultHelpDocCatalogForm);
|
||||
if (data) {
|
||||
Object.assign(formState, data);
|
||||
}
|
||||
visible.value = true;
|
||||
}
|
||||
// 重置表单数据
|
||||
function resetFormData() {
|
||||
Object.assign(formState, defaultHelpDocCatalogForm);
|
||||
}
|
||||
|
||||
async function handleOk() {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
if (formState.helpDocCatalogId) {
|
||||
updateHelpDocCatalog();
|
||||
} else {
|
||||
addHelpDocCatalog();
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- form 表单 ajax 操作 ---------------------
|
||||
//添加目录ajax请求
|
||||
async function addHelpDocCatalog() {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
await helpDocCatalogApi.add(formState);
|
||||
emits('refresh');
|
||||
closeModal();
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
//更新目录ajax请求
|
||||
async function updateHelpDocCatalog() {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
if (formState.parentId == formState.helpDocCatalogId) {
|
||||
message.warning('上级菜单不能为自己');
|
||||
return;
|
||||
}
|
||||
await helpDocCatalogApi.update(formState);
|
||||
emits('refresh');
|
||||
closeModal();
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,89 @@
|
||||
<!--
|
||||
* 目录下拉框
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-tree-select
|
||||
:value="props.value"
|
||||
:treeData="treeData"
|
||||
:fieldNames="{ label: 'name', key: 'helpDocCatalogId', value: 'helpDocCatalogId' }"
|
||||
show-search
|
||||
style="width: 100%"
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
placeholder="请选择目录"
|
||||
allow-clear
|
||||
tree-default-expand-all
|
||||
:multiple="props.multiple"
|
||||
@change="treeSelectChange"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import _ from 'lodash';
|
||||
import { helpDocCatalogApi } from '/@/api/support/help-doc/help-doc-catalog-api';
|
||||
|
||||
const props = defineProps({
|
||||
// 绑定值
|
||||
value: Number,
|
||||
// 单选多选
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:value']);
|
||||
|
||||
let treeData = ref([]);
|
||||
onMounted(queryCatalogTree);
|
||||
// 外部调用初始化
|
||||
async function queryCatalogTree() {
|
||||
let res = await helpDocCatalogApi.getAll();
|
||||
let children = buildHelpDocCatalogTree(res.data, 0);
|
||||
treeData.value = children;
|
||||
}
|
||||
|
||||
// 构建目录树
|
||||
function buildHelpDocCatalogTree(data, parentId) {
|
||||
let children = data.filter((e) => e.parentId === parentId) || [];
|
||||
children = _.sortBy(children, (e) => e.sort);
|
||||
children.forEach((e) => {
|
||||
e.children = buildHelpDocCatalogTree(data, e.helpDocCatalogId);
|
||||
});
|
||||
updateHelpDocCatalogPreIdAndNextId(children);
|
||||
return children;
|
||||
}
|
||||
|
||||
// 更新树的前置id和后置id
|
||||
function updateHelpDocCatalogPreIdAndNextId(data) {
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
if (index === 0) {
|
||||
data[index].nextId = data.length > 1 ? data[1].helpDocCatalogId : undefined;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index === data.length - 1) {
|
||||
data[index].preId = data[index - 1].helpDocCatalogId;
|
||||
data[index].nextId = undefined;
|
||||
continue;
|
||||
}
|
||||
|
||||
data[index].preId = data[index - 1].helpDocCatalogId;
|
||||
data[index].nextId = data[index + 1].helpDocCatalogId;
|
||||
}
|
||||
}
|
||||
|
||||
function treeSelectChange(e) {
|
||||
emit('update:value', e);
|
||||
}
|
||||
|
||||
// ----------------------- 以下是暴露的方法内容 ------------------------
|
||||
defineExpose({
|
||||
queryCatalogTree,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,354 @@
|
||||
<!--
|
||||
* 目录树
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-card class="tree-container" size="small">
|
||||
<a-row>
|
||||
<a-input v-model:value.trim="keywords" placeholder="请输入目录名称" />
|
||||
</a-row>
|
||||
<a-row class="sort-flag-row" v-if="props.showMenu">
|
||||
<span>
|
||||
排序
|
||||
<template v-if="showSortFlag"> (越小越靠前) </template>
|
||||
:<a-switch v-model:checked="showSortFlag" />
|
||||
</span>
|
||||
<a-button type="primary" @click="addTop" size="small" v-privilege="'helpDocCatalog:addCategory'">新建</a-button>
|
||||
</a-row>
|
||||
<a-tree
|
||||
v-if="!_.isEmpty(helpDocCatalogTreeData)"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
v-model:checkedKeys="checkedKeys"
|
||||
class="tree"
|
||||
:treeData="helpDocCatalogTreeData"
|
||||
:fieldNames="{ title: 'name', key: 'helpDocCatalogId', value: 'helpDocCatalogId' }"
|
||||
style="width: 100%; overflow-x: auto"
|
||||
:style="[!height ? '' : { height: `${height}px`, overflowY: 'auto' }]"
|
||||
:showLine="!props.checkable"
|
||||
:checkable="props.checkable"
|
||||
:checkStrictly="props.checkStrictly"
|
||||
:selectable="!props.checkable"
|
||||
:defaultExpandAll="true"
|
||||
@select="treeSelectChange"
|
||||
>
|
||||
<template #title="item">
|
||||
<a-popover placement="right" v-if="props.showMenu">
|
||||
<template #content>
|
||||
<div style="display: flex; flex-direction: column">
|
||||
<a-button type="text" @click="addHelpDocCatalog(item.dataRef)" v-privilege="'helpDocCatalog:addCategory'">添加下级</a-button>
|
||||
<a-button type="text" @click="updateHelpDocCatalog(item.dataRef)" v-privilege="'helpDocCatalog:edit'">修改</a-button>
|
||||
<a-button
|
||||
type="text"
|
||||
v-if="item.helpDocCatalogId != topHelpDocCatalogId"
|
||||
@click="deleteHelpDocCatalog(item.helpDocCatalogId)"
|
||||
v-privilege="'helpDocCatalog:delete'"
|
||||
>删除</a-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
{{ item.name }}
|
||||
<!--显示排序字段-->
|
||||
<template v-if="showSortFlag">
|
||||
<span class="sort-span">({{ item.sort }})</span>
|
||||
</template>
|
||||
</a-popover>
|
||||
<div v-else>{{ item.name }}</div>
|
||||
</template>
|
||||
</a-tree>
|
||||
<div class="no-data" v-else>暂无结果</div>
|
||||
<!-- 添加编辑目录弹窗 -->
|
||||
<HelpDocCatalogFormModal ref="helpDocCatalogFormModal" @refresh="refresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { ref } from 'vue';
|
||||
import { onUnmounted, watch } from 'vue';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { createVNode, onMounted } from 'vue';
|
||||
import HelpDocCatalogFormModal from './help-doc-catalog-form-modal.vue';
|
||||
import { helpDocCatalogApi } from '/@/api/support/help-doc/help-doc-catalog-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import helpDocCatalogEmitter from '../help-doc-mitt';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const HELP_DOC_CATALOG_PARENT_ID = 0;
|
||||
|
||||
// ----------------------- 组件参数 ---------------------
|
||||
|
||||
const props = defineProps({
|
||||
// 是否可以选中
|
||||
checkable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 父子节点选中状态不再关联
|
||||
checkStrictly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 树高度 超出出滚动条
|
||||
height: Number,
|
||||
// 显示菜单
|
||||
showMenu: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
// ----------------------- 目录树的展示 ---------------------
|
||||
const topHelpDocCatalogId = ref();
|
||||
// 所有目录列表
|
||||
const helpDocCatalogList = ref([]);
|
||||
// 目录树形数据
|
||||
const helpDocCatalogTreeData = ref([]);
|
||||
// 存放目录id和目录,用于查找
|
||||
const idInfoMap = ref(new Map());
|
||||
// 是否显示排序字段
|
||||
const showSortFlag = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
queryHelpDocCatalogTree();
|
||||
});
|
||||
|
||||
// 刷新
|
||||
async function refresh() {
|
||||
await queryHelpDocCatalogTree();
|
||||
if (currentSelectedHelpDocCatalogId.value) {
|
||||
selectTree(currentSelectedHelpDocCatalogId.value);
|
||||
}
|
||||
}
|
||||
|
||||
// 查询目录列表并构建 目录树
|
||||
async function queryHelpDocCatalogTree() {
|
||||
let res = await helpDocCatalogApi.getAll();
|
||||
let data = res.data;
|
||||
helpDocCatalogList.value = data;
|
||||
helpDocCatalogTreeData.value = buildHelpDocCatalogTree(data, HELP_DOC_CATALOG_PARENT_ID);
|
||||
|
||||
data.forEach((e) => {
|
||||
idInfoMap.value.set(e.helpDocCatalogId, e);
|
||||
});
|
||||
|
||||
// 默认显示 最顶级ID为列表中返回的第一条数据的ID
|
||||
if (!_.isEmpty(helpDocCatalogTreeData.value) && helpDocCatalogTreeData.value.length > 0) {
|
||||
topHelpDocCatalogId.value = helpDocCatalogTreeData.value[0].helpDocCatalogId;
|
||||
selectTree(helpDocCatalogTreeData.value[0].helpDocCatalogId);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建目录树
|
||||
function buildHelpDocCatalogTree(data, parentId) {
|
||||
let children = data.filter((e) => e.parentId === parentId) || [];
|
||||
children = _.sortBy(children, (e) => e.sort);
|
||||
children.forEach((e) => {
|
||||
e.children = buildHelpDocCatalogTree(data, e.helpDocCatalogId);
|
||||
});
|
||||
updateHelpDocCatalogPreIdAndNextId(children);
|
||||
return children;
|
||||
}
|
||||
|
||||
// 更新树的前置id和后置id
|
||||
function updateHelpDocCatalogPreIdAndNextId(data) {
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
if (index === 0) {
|
||||
data[index].nextId = data.length > 1 ? data[1].helpDocCatalogId : undefined;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index === data.length - 1) {
|
||||
data[index].preId = data[index - 1].helpDocCatalogId;
|
||||
data[index].nextId = undefined;
|
||||
continue;
|
||||
}
|
||||
|
||||
data[index].preId = data[index - 1].helpDocCatalogId;
|
||||
data[index].nextId = data[index + 1].helpDocCatalogId;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- 树的选中 ---------------------
|
||||
const selectedKeys = ref([]);
|
||||
const checkedKeys = ref([]);
|
||||
const breadcrumb = ref([]);
|
||||
const currentSelectedHelpDocCatalogId = ref();
|
||||
const selectedHelpDocCatalogChildren = ref([]);
|
||||
|
||||
helpDocCatalogEmitter.on('selectTree', selectTree);
|
||||
|
||||
function selectTree(id) {
|
||||
selectedKeys.value = [id];
|
||||
treeSelectChange(selectedKeys.value);
|
||||
}
|
||||
|
||||
function treeSelectChange(idList) {
|
||||
if (_.isEmpty(idList)) {
|
||||
breadcrumb.value = [];
|
||||
selectedHelpDocCatalogChildren.value = [];
|
||||
return;
|
||||
}
|
||||
let id = idList[0];
|
||||
selectedHelpDocCatalogChildren.value = helpDocCatalogList.value.filter((e) => e.parentId == id);
|
||||
let filterHelpDocCatalogList = [];
|
||||
recursionFilterHelpDocCatalog(filterHelpDocCatalogList, id, true);
|
||||
breadcrumb.value = filterHelpDocCatalogList.map((e) => e.name);
|
||||
}
|
||||
|
||||
// ----------------------- 筛选 ---------------------
|
||||
const keywords = ref('');
|
||||
watch(
|
||||
() => keywords.value,
|
||||
() => {
|
||||
onSearch();
|
||||
}
|
||||
);
|
||||
|
||||
// 筛选
|
||||
function onSearch() {
|
||||
if (!keywords.value) {
|
||||
helpDocCatalogTreeData.value = buildHelpDocCatalogTree(helpDocCatalogList.value, HELP_DOC_CATALOG_PARENT_ID);
|
||||
return;
|
||||
}
|
||||
let originData = helpDocCatalogList.value.concat();
|
||||
if (!originData) {
|
||||
return;
|
||||
}
|
||||
// 筛选出名称符合的目录
|
||||
let filterDepartmenet = originData.filter((e) => e.name.indexOf(keywords.value) > -1);
|
||||
let filterHelpDocCatalogList = [];
|
||||
// 循环筛选出的目录 构建目录树
|
||||
filterDepartmenet.forEach((e) => {
|
||||
recursionFilterHelpDocCatalog(filterHelpDocCatalogList, e.helpDocCatalogId, false);
|
||||
});
|
||||
|
||||
helpDocCatalogTreeData.value = buildHelpDocCatalogTree(filterHelpDocCatalogList, HELP_DOC_CATALOG_PARENT_ID);
|
||||
}
|
||||
|
||||
// 根据ID递归筛选目录
|
||||
function recursionFilterHelpDocCatalog(resList, id, unshift) {
|
||||
let info = idInfoMap.value.get(id);
|
||||
if (!info || resList.some((e) => e.helpDocCatalogId == id)) {
|
||||
return;
|
||||
}
|
||||
if (unshift) {
|
||||
resList.unshift(info);
|
||||
} else {
|
||||
resList.push(info);
|
||||
}
|
||||
if (info.parentId && info.parentId != 0) {
|
||||
recursionFilterHelpDocCatalog(resList, info.parentId, unshift);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- 表单操作:添加目录/修改目录/删除目录/上下移动 ---------------------
|
||||
const helpDocCatalogFormModal = ref();
|
||||
|
||||
// 添加
|
||||
function addHelpDocCatalog(e) {
|
||||
let data = {
|
||||
helpDocCatalogId: 0,
|
||||
name: '',
|
||||
parentId: e.helpDocCatalogId,
|
||||
};
|
||||
currentSelectedHelpDocCatalogId.value = e.helpDocCatalogId;
|
||||
helpDocCatalogFormModal.value.showModal(data);
|
||||
}
|
||||
// 添加
|
||||
function addTop() {
|
||||
let data = {
|
||||
helpDocCatalogId: 0,
|
||||
name: '',
|
||||
parentId: 0,
|
||||
};
|
||||
helpDocCatalogFormModal.value.showModal(data);
|
||||
}
|
||||
// 编辑
|
||||
function updateHelpDocCatalog(e) {
|
||||
currentSelectedHelpDocCatalogId.value = e.helpDocCatalogId;
|
||||
helpDocCatalogFormModal.value.showModal(e);
|
||||
}
|
||||
|
||||
// 删除
|
||||
function deleteHelpDocCatalog(id) {
|
||||
Modal.confirm({
|
||||
title: '提醒',
|
||||
icon: createVNode(ExclamationCircleOutlined),
|
||||
content: '确定要删除该目录吗?',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
async onOk() {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
// 若删除的是当前的目录 先找到上级目录
|
||||
let selectedKey = null;
|
||||
if (!_.isEmpty(selectedKeys.value)) {
|
||||
selectedKey = selectedKeys.value[0];
|
||||
if (selectedKey == id) {
|
||||
let selectInfo = helpDocCatalogList.value.find((e) => e.helpDocCatalogId == id);
|
||||
if (selectInfo && selectInfo.parentId) {
|
||||
selectedKey = selectInfo.parentId;
|
||||
}
|
||||
}
|
||||
}
|
||||
await helpDocCatalogApi.delete(id);
|
||||
await queryHelpDocCatalogTree();
|
||||
// 刷新选中目录
|
||||
if (selectedKey) {
|
||||
selectTree(selectedKey);
|
||||
}
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
helpDocCatalogEmitter.all.clear();
|
||||
});
|
||||
|
||||
// ----------------------- 以下是暴露的方法内容 ----------------------------
|
||||
defineExpose({
|
||||
queryHelpDocCatalogTree,
|
||||
selectedHelpDocCatalogChildren,
|
||||
breadcrumb,
|
||||
selectedKeys,
|
||||
checkedKeys,
|
||||
keywords,
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.tree-container {
|
||||
height: 100%;
|
||||
.tree {
|
||||
height: 618px;
|
||||
margin-top: 10px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.sort-flag-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.sort-span {
|
||||
margin-left: 5px;
|
||||
color: @success-color;
|
||||
}
|
||||
.no-data {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,204 @@
|
||||
<!--
|
||||
* 帮助文档表单
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-drawer
|
||||
:title="formData.helpDocId ? '编辑' : '新建'"
|
||||
:visible="visibleFlag"
|
||||
:width="1000"
|
||||
:footerStyle="{ textAlign: 'right' }"
|
||||
@close="onClose"
|
||||
:destroyOnClose="true"
|
||||
>
|
||||
<a-form ref="formRef" :model="formData" :rules="formRules" :label-col="{ span: 3 }" :wrapper-col="{ span: 20 }">
|
||||
<a-form-item label="标题" name="title">
|
||||
<a-input v-model:value="formData.title" placeholder="请输入标题" />
|
||||
</a-form-item>
|
||||
<a-form-item label="目录" name="helpDocCatalogId">
|
||||
<HelpDocCatalogTreeSelect v-model:value="formData.helpDocCatalogId" style="width: 100%" />
|
||||
</a-form-item>
|
||||
<a-form-item label="作者" name="author">
|
||||
<a-input v-model:value="formData.author" placeholder="请输入作者" />
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" name="sort">
|
||||
<a-input-number v-model:value="formData.sort" placeholder="值越小越靠前" />(值越小越靠前)
|
||||
</a-form-item>
|
||||
<a-form-item label="关联菜单">
|
||||
<MenuTreeSelect v-model:value="formData.relationIdList" ref="menuTreeSelect" />
|
||||
</a-form-item>
|
||||
<a-form-item label="公告内容" name="contentHtml">
|
||||
<Wangeditor ref="contentRef" :modelValue="formData.contentHtml" :height="300" />
|
||||
</a-form-item>
|
||||
<a-form-item label="附件">
|
||||
<Upload
|
||||
:defaultFileList="defaultFileList"
|
||||
:maxUploadSize="10"
|
||||
:folder="FILE_FOLDER_TYPE_ENUM.HELP_DOC.value"
|
||||
buttonText="上传附件"
|
||||
listType="text"
|
||||
extraMsg="最多上传10个附件"
|
||||
@change="changeAttachment"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<template #footer>
|
||||
<a-space>
|
||||
<a-button @click="onClose">取消</a-button>
|
||||
<a-button type="primary" @click="onSubmit">保存</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import lodash from 'lodash';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { FILE_FOLDER_TYPE_ENUM } from '/@/constants/support/file-const';
|
||||
import { helpDocApi } from '/@/api/support/help-doc/help-doc-api';
|
||||
import Wangeditor from '/@/components/framework/wangeditor/index.vue';
|
||||
import Upload from '/@/components/support/file-upload/index.vue';
|
||||
import HelpDocCatalogTreeSelect from './help-doc-catalog-tree-select.vue';
|
||||
import MenuTreeSelect from '/@/components/system/menu-tree-select/index.vue';
|
||||
import _ from 'lodash';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const emits = defineEmits(['reloadList']);
|
||||
|
||||
// ------------------ 显示,关闭 ------------------
|
||||
// 显示
|
||||
const visibleFlag = ref(false);
|
||||
function showModal(helpDocId) {
|
||||
Object.assign(formData, defaultFormData);
|
||||
defaultFileList.value = [];
|
||||
if (helpDocId) {
|
||||
getDetail(helpDocId);
|
||||
}
|
||||
|
||||
visibleFlag.value = true;
|
||||
nextTick(() => {
|
||||
formRef.value.clearValidate();
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭
|
||||
function onClose() {
|
||||
visibleFlag.value = false;
|
||||
}
|
||||
|
||||
// ------------------ 表单 ------------------
|
||||
|
||||
const formRef = ref();
|
||||
const contentRef = ref();
|
||||
const noticeFormVisibleModal = ref();
|
||||
|
||||
const defaultFormData = {
|
||||
helpDocId: undefined,
|
||||
helpDocCatalogId: undefined,
|
||||
title: undefined, // 标题
|
||||
author: undefined, // 作者
|
||||
sort: 0, // 排序
|
||||
attachment: [], // 附件
|
||||
relationIdList: [], //关联id集合
|
||||
contentHtml: '', // html内容
|
||||
contentText: '', // 纯文本内容
|
||||
};
|
||||
|
||||
const formData = reactive({ ...defaultFormData });
|
||||
|
||||
const formRules = {
|
||||
title: [{ required: true, message: '请输入' }],
|
||||
helpDocCatalogId: [{ required: true, message: '请选择目录' }],
|
||||
author: [{ required: true, message: '请输入作者' }],
|
||||
sort: [{ required: true, message: '请输入排序' }],
|
||||
contentHtml: [{ required: true, message: '请输入内容' }],
|
||||
};
|
||||
|
||||
// 查询详情
|
||||
async function getDetail(helpDocId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
const result = await helpDocApi.getDetail(helpDocId);
|
||||
const attachment = result.data.attachment;
|
||||
if (!lodash.isEmpty(attachment)) {
|
||||
defaultFileList.value = attachment;
|
||||
} else {
|
||||
defaultFileList.value = [];
|
||||
}
|
||||
Object.assign(formData, result.data);
|
||||
formData.relationIdList = result.data.relationList ? result.data.relationList.map((e) => e.relationId) : [];
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// 点击确定,验证表单
|
||||
async function onSubmit() {
|
||||
try {
|
||||
formData.contentHtml = contentRef.value.getHtml();
|
||||
formData.contentText = contentRef.value.getText();
|
||||
await formRef.value.validateFields();
|
||||
save();
|
||||
} catch (err) {
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
}
|
||||
}
|
||||
|
||||
// 新建、编辑API
|
||||
const menuTreeSelect = ref();
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
let param = _.cloneDeep(formData);
|
||||
let relationList = menuTreeSelect.value.getMenuListByIdList(formData.relationIdList);
|
||||
param.relationList = relationList.map((e) => Object.assign({}, { relationId: e.menuId, relationName: e.menuName }));
|
||||
|
||||
if (param.helpDocId) {
|
||||
await helpDocApi.update(param);
|
||||
} else {
|
||||
await helpDocApi.add(param);
|
||||
}
|
||||
message.success('保存成功');
|
||||
emits('reloadList');
|
||||
onClose();
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- 上传附件 ----------------------------
|
||||
// 已上传的附件列表
|
||||
const defaultFileList = ref([]);
|
||||
function changeAttachment(fileList) {
|
||||
defaultFileList.value = fileList;
|
||||
formData.attachment = lodash.isEmpty(fileList) ? [] : fileList;
|
||||
}
|
||||
|
||||
// ----------------------- 以下是暴露的方法内容 ------------------------
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.visible-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.visible-item {
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,267 @@
|
||||
<!--
|
||||
* 帮助文档 列表
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-form class="smart-query-form" v-privilege="'helpDoc:query'">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 300px" v-model:value="queryForm.keywords" placeholder="标题、作者" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="创建时间" class="smart-query-form-item">
|
||||
<a-range-picker v-model:value="createDate" @change="createDateChange" style="width: 220px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button-group>
|
||||
<a-button type="primary" @click="onSearch">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="onReload">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false">
|
||||
<a-row class="smart-table-btn-block">
|
||||
<div class="smart-table-operate-block">
|
||||
<a-button type="primary" size="small" @click="addOrUpdate()" v-privilege="'helpDoc:add'">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新建
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="smart-table-setting-block">
|
||||
<TableOperator v-model="tableColumns" :tableId="TABLE_ID_CONST.SUPPORT.HELP_DOC" :refresh="queryHelpDocList" />
|
||||
</div>
|
||||
</a-row>
|
||||
|
||||
<a-table
|
||||
rowKey="helpDocId"
|
||||
:columns="tableColumns"
|
||||
:scroll="{ x: 1000 }"
|
||||
:dataSource="tableData"
|
||||
:pagination="false"
|
||||
:loading="tableLoading"
|
||||
size="small"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'title'">
|
||||
<router-link tag="a" target="_blank" :to="{ path: '/help-doc/detail', query: { helpDocId: record.helpDocId } }">{{
|
||||
record.title
|
||||
}}</router-link>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button type="link" @click="addOrUpdate(record.helpDocId)" v-privilege="'helpDoc:update'">编辑</a-button>
|
||||
<a-button type="link" danger @click="onDelete(record.helpDocId)" v-privilege="'helpDoc:delete'">删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryHelpDocList"
|
||||
@showSizeChange="queryHelpDocList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<HelpDocFormDrawer ref="helpDocFormDrawerRef" @reloadList="queryHelpDocList" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { onMounted, reactive, ref, watch } from 'vue';
|
||||
import HelpDocFormDrawer from './help-doc-form-drawer.vue';
|
||||
import { helpDocApi } from '/@/api/support/help-doc/help-doc-api';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||||
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||||
|
||||
const props = defineProps({
|
||||
// 目录id
|
||||
helpDocCatalogId: Number,
|
||||
});
|
||||
|
||||
const queryFormState = {
|
||||
helpDocCatalogId: props.helpDocCatalogId, //目录
|
||||
keywords: '', //标题、作者
|
||||
createTimeBegin: null, //创建-开始时间
|
||||
createTimeEnd: null, //创建-截止时间
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
};
|
||||
const queryForm = reactive({ ...queryFormState });
|
||||
|
||||
const tableColumns = ref([
|
||||
{
|
||||
title: `标题`,
|
||||
dataIndex: 'title',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '目录',
|
||||
dataIndex: 'helpDocCatalogName',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: `作者`,
|
||||
dataIndex: 'author',
|
||||
width: 110,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
title: '页面浏览量',
|
||||
dataIndex: 'pageViewCount',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
title: '用户浏览量',
|
||||
dataIndex: 'userViewCount',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 90,
|
||||
},
|
||||
]);
|
||||
|
||||
// ------------------ 查询相关 ------------------
|
||||
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
const tableLoading = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
queryHelpDocList();
|
||||
});
|
||||
|
||||
// 查询列表
|
||||
async function queryHelpDocList() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
const result = await helpDocApi.query(queryForm);
|
||||
tableData.value = result.data.list;
|
||||
total.value = result.data.total;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 点击查询
|
||||
function onSearch() {
|
||||
queryForm.pageNum = 1;
|
||||
queryHelpDocList();
|
||||
}
|
||||
|
||||
// 点击重置
|
||||
function onReload() {
|
||||
Object.assign(queryForm, queryFormState);
|
||||
publishDate.value = [];
|
||||
createDate.value = [];
|
||||
queryHelpDocList();
|
||||
}
|
||||
|
||||
// 发布日期选择
|
||||
const publishDate = ref([]);
|
||||
function publishDateChange(dates, dateStrings) {
|
||||
queryForm.publishTimeBegin = dateStrings[0];
|
||||
queryForm.publishTimeEnd = dateStrings[1];
|
||||
}
|
||||
// 创建日期选择
|
||||
const createDate = ref([]);
|
||||
function createDateChange(dates, dateStrings) {
|
||||
queryForm.createTimeBegin = dateStrings[0];
|
||||
queryForm.createTimeEnd = dateStrings[1];
|
||||
}
|
||||
|
||||
// ------------------ 新建、编辑 ------------------
|
||||
|
||||
// 新建、编辑
|
||||
const helpDocFormDrawerRef = ref();
|
||||
function addOrUpdate(helpDocId) {
|
||||
helpDocFormDrawerRef.value.showModal(helpDocId);
|
||||
}
|
||||
|
||||
// ------------------ 删除 ------------------
|
||||
|
||||
// 删除
|
||||
function onDelete(helpDocId) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确认删除此数据吗?',
|
||||
onOk() {
|
||||
deleteHelpDoc(helpDocId);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 删除API
|
||||
async function deleteHelpDoc(helpDocId) {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
await helpDocApi.delete(helpDocId);
|
||||
message.success('删除成功');
|
||||
queryHelpDocList();
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.helpDocCatalogId,
|
||||
() => {
|
||||
queryForm.helpDocCatalogId = props.helpDocCatalogId;
|
||||
onSearch();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -0,0 +1,55 @@
|
||||
<!--
|
||||
* 帮助文档 管理
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<div class="height100">
|
||||
<a-row :gutter="16" class="height100">
|
||||
<a-col :span="6">
|
||||
<HelpDocCatalogTree ref="helpDocCatalogTreeRef" />
|
||||
</a-col>
|
||||
|
||||
<a-col :span="18" class="height100">
|
||||
<div class="help-doc-box height100">
|
||||
<HelpDocList :helpDocCatalogId="selectedHelpDocCatalogId" />
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import _ from 'lodash';
|
||||
import { computed, ref } from 'vue';
|
||||
import HelpDocCatalogTree from './components/help-doc-catalog-tree.vue';
|
||||
import HelpDocList from './components/help-doc-list.vue';
|
||||
|
||||
const helpDocCatalogTreeRef = ref();
|
||||
|
||||
// 当前选中的目录id
|
||||
const selectedHelpDocCatalogId = computed(() => {
|
||||
if (helpDocCatalogTreeRef.value) {
|
||||
let selectedKeys = helpDocCatalogTreeRef.value.selectedKeys;
|
||||
return _.isEmpty(selectedKeys) ? null : selectedKeys[0];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.height100 {
|
||||
height: 100%;
|
||||
}
|
||||
.help-doc-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.employee {
|
||||
flex-grow: 2;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 帮助文档 event bus
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-09-12 18:06:41
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
*/
|
||||
import mitt from 'mitt';
|
||||
export default mitt();
|
||||
@@ -0,0 +1,168 @@
|
||||
<!--
|
||||
* 查看记录
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<a-form class="smart-query-form">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="关键字" class="smart-query-form-item" style="width: 280px">
|
||||
<a-input v-model:value="queryForm.keywords" placeholder="姓名/IP/设备" />
|
||||
</a-form-item>
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button-group>
|
||||
<a-button type="primary" @click="onSearch">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="resetQuery">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<a-table rowKey="employeeId" :columns="tableColumns" :dataSource="tableData" :pagination="false" :loading="tableLoading" size="small" bordered>
|
||||
<template #bodyCell="{ column, record, text }">
|
||||
<template v-if="column.dataIndex === 'firstIp'"> {{ text }} ({{ record.firstDevice }}) </template>
|
||||
<template v-if="column.dataIndex === 'lastIp'"> {{ text }} ({{ record.lastDevice }}) </template>
|
||||
</template>
|
||||
</a-table>
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryViewRecord"
|
||||
@showSizeChange="queryViewRecord"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { helpDocApi } from '/@/api/support/help-doc/help-doc-api';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import uaparser from 'ua-parser-js';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const props = defineProps({
|
||||
helpDocId: {
|
||||
type: [Number, String],
|
||||
},
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
onSearch,
|
||||
});
|
||||
|
||||
const tableColumns = [
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'userName',
|
||||
},
|
||||
{
|
||||
title: '查看次数',
|
||||
dataIndex: 'pageViewCount',
|
||||
with: 100,
|
||||
},
|
||||
{
|
||||
title: '首次查看设备',
|
||||
dataIndex: 'firstIp',
|
||||
},
|
||||
{
|
||||
title: '首次查看时间',
|
||||
dataIndex: 'createTime',
|
||||
with: 120,
|
||||
},
|
||||
{
|
||||
title: '最后一次查看设备',
|
||||
dataIndex: 'lastIp',
|
||||
},
|
||||
{
|
||||
title: '最后一次查看时间',
|
||||
dataIndex: 'updateTime',
|
||||
with: 120,
|
||||
},
|
||||
];
|
||||
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
const tableLoading = ref(false);
|
||||
|
||||
const defaultQueryForm = {
|
||||
helpDocId: props.helpDocId,
|
||||
keywords: '',
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
};
|
||||
|
||||
const queryForm = reactive({ ...defaultQueryForm });
|
||||
|
||||
function buildDeviceInfo(userAgent) {
|
||||
if (!userAgent) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let ua = uaparser(userAgent);
|
||||
let browser = ua.browser.name;
|
||||
let os = ua.os.name;
|
||||
return browser + '/' + os + '/' + (ua.device.vendor ? ua.device.vendor + ua.device.model : '');
|
||||
}
|
||||
|
||||
async function queryViewRecord() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
const result = await helpDocApi.queryViewRecord(queryForm);
|
||||
|
||||
for (const e of result.data.list) {
|
||||
e.firstDevice = buildDeviceInfo(e.firstUserAgent);
|
||||
e.lastDevice = buildDeviceInfo(e.lastUserAgent);
|
||||
}
|
||||
|
||||
tableData.value = result.data.list;
|
||||
total.value = result.data.total;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
// 点击查询
|
||||
function onSearch() {
|
||||
queryForm.pageNum = 1;
|
||||
queryViewRecord();
|
||||
}
|
||||
|
||||
// 点击重置
|
||||
function resetQuery() {
|
||||
Object.assign(queryForm, defaultQueryForm);
|
||||
queryViewRecord();
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-table.ant-table-small .ant-table-title,
|
||||
.ant-table.ant-table-small .ant-table-footer,
|
||||
.ant-table.ant-table-small .ant-table-tbody > tr > td,
|
||||
.ant-table.ant-table-small tfoot > tr > th,
|
||||
.ant-table.ant-table-small tfoot > tr > td {
|
||||
padding: 0px 3px !important;
|
||||
line-height: 28px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,150 @@
|
||||
<!--
|
||||
* 帮助文档详情
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-card size="small" :bordered="false">
|
||||
<div v-if="helpDocDetail">
|
||||
<div class="content-header">
|
||||
<!--startprint-->
|
||||
<div class="content-header-title">
|
||||
{{ helpDocDetail.title }}
|
||||
</div>
|
||||
<div class="content-header-info">
|
||||
<span>阅读量:{{ helpDocDetail.pageViewCount }}</span>
|
||||
<span v-show="helpDocDetail.author">作者:{{ helpDocDetail.author }}</span>
|
||||
<span>发布于:{{ helpDocDetail.createTime }}</span>
|
||||
<span>修改于:{{ helpDocDetail.updateTime }}</span>
|
||||
<span @click="print">【打印本页】</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-html" v-html="helpDocDetail.contentHtml"></div>
|
||||
<!--endprint-->
|
||||
</div>
|
||||
<a-divider v-if="helpDocDetail.attachment && helpDocDetail.attachment.length > 0" />
|
||||
<div v-if="helpDocDetail.attachment && helpDocDetail.attachment.length > 0">附件:<FilePreview :fileList="helpDocDetail.attachment" /></div>
|
||||
</a-card>
|
||||
|
||||
<a-card title="阅读记录" size="small" class="smart-margin-top10" :bordered="false">
|
||||
<HelpDocViewRecordList ref="helpDocViewRecordListRef" :helpDocId="route.query.helpDocId" />
|
||||
</a-card>
|
||||
|
||||
<!-- 预览附件 -->
|
||||
<FilePreview ref="filePreviewRef" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import HelpDocViewRecordList from './components/help-doc-view-record-list.vue';
|
||||
import { helpDocApi } from '/@/api/support/help-doc/help-doc-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import FilePreview from '/@/components/support/file-preview/index.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const activeKey = ref(1);
|
||||
|
||||
const helpDocDetail = ref({});
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.helpDocId) {
|
||||
queryHelpDocDetail();
|
||||
}
|
||||
});
|
||||
|
||||
const helpDocViewRecordListRef = ref();
|
||||
|
||||
// 查询详情
|
||||
async function queryHelpDocDetail() {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
const result = await helpDocApi.view(route.query.helpDocId);
|
||||
helpDocDetail.value = result.data;
|
||||
|
||||
helpDocViewRecordListRef.value.onSearch();
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// 预览附件
|
||||
const filePreviewRef = ref();
|
||||
function onPrevFile(fileItem) {
|
||||
filePreviewRef.value.showPreview(fileItem);
|
||||
}
|
||||
|
||||
// 打印
|
||||
function print() {
|
||||
let bdhtml = window.document.body.innerHTML;
|
||||
let sprnstr = '<!--startprint-->'; //必须在页面添加<!--startprint-->和<!--endprint-->而且需要打印的内容必须在它们之间
|
||||
let eprnstr = '<!--endprint-->';
|
||||
let prnhtml = bdhtml.substr(bdhtml.indexOf(sprnstr));
|
||||
prnhtml = prnhtml.substring(0, prnhtml.indexOf(eprnstr));
|
||||
let newWin = window.open(''); //新打开一个空窗口
|
||||
newWin.document.body.innerHTML = prnhtml;
|
||||
newWin.document.close(); //在IE浏览器中使用必须添加这一句
|
||||
newWin.focus(); //在IE浏览器中使用必须添加这一句
|
||||
newWin.print(); //打印
|
||||
newWin.close(); //关闭窗口
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ant-descriptions-item-content) {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.file-list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.file-item {
|
||||
display: block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.visible-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.visible-item {
|
||||
margin-right: 10px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
.content-header {
|
||||
.content-header-title {
|
||||
margin: 10px 0px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
.content-header-info {
|
||||
margin: 10px 0px;
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
span {
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-html {
|
||||
margin-top: 30px;
|
||||
padding: 0 8px;
|
||||
line-height: 28px;
|
||||
font-size: 14px;
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user