Initial commit
This commit is contained in:
184
src/views/cms/docs-md-bak/components/docs-edit.vue
Normal file
184
src/views/cms/docs-md-bak/components/docs-edit.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<!-- 文档编辑弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
:width="400"
|
||||
:visible="visible"
|
||||
:confirm-loading="loading"
|
||||
:title="isUpdate ? '修改文档' : '添加文档'"
|
||||
:body-style="{ paddingBottom: '8px' }"
|
||||
@update:visible="updateVisible"
|
||||
@ok="save"
|
||||
>
|
||||
<a-form
|
||||
:label-col="{ md: { span: 24 }, sm: { span: 24 } }"
|
||||
:wrapper-col="{ md: { span: 24 }, sm: { span: 24 } }"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-item label="上级目录" v-bind="validateInfos.parentId">
|
||||
<docs-select
|
||||
:data="docs"
|
||||
placeholder="请选择上级目录"
|
||||
v-model:value="form.parentId"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="文档标题" v-bind="validateInfos.title">
|
||||
<a-input
|
||||
allow-clear
|
||||
:maxlength="20"
|
||||
placeholder="请输入文档标题"
|
||||
v-model:value="form.title"
|
||||
@pressEnter="save"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序号" v-bind="validateInfos.sortNumber">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:max="99999"
|
||||
class="ele-fluid"
|
||||
placeholder="请输入排序号"
|
||||
v-model:value="form.sortNumber"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<!-- <a-alert-->
|
||||
<!-- message="文档内容应该放在最后一级"-->
|
||||
<!-- banner-->
|
||||
<!-- style="margin-bottom: 12px"-->
|
||||
<!-- />-->
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { Form, message } from 'ant-design-vue';
|
||||
import { assignObject } from 'ele-admin-pro';
|
||||
import DocsSelect from './docs-select.vue';
|
||||
import { addDocs, updateDocs } from '@/api/cms/docs';
|
||||
import type { Docs } from '@/api/cms/docs/model';
|
||||
|
||||
const useForm = Form.useForm;
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done'): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
visible: boolean;
|
||||
// 修改回显的数据
|
||||
data?: Docs | null;
|
||||
// 文档id
|
||||
docsId?: number;
|
||||
// 全部文档
|
||||
docs: Docs[];
|
||||
}>();
|
||||
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
|
||||
// 提交状态
|
||||
const loading = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const form = reactive<Docs>({
|
||||
// 文档id
|
||||
docsId: 0,
|
||||
// 文档标题
|
||||
title: '',
|
||||
// 文档类型 0目录 1文档
|
||||
type: 0,
|
||||
// 上级文档
|
||||
parentId: 0,
|
||||
// 封面图
|
||||
avatar: '',
|
||||
// 用户ID
|
||||
userId: '',
|
||||
// 所属门店ID
|
||||
shopId: '',
|
||||
// 排序
|
||||
sortNumber: 100,
|
||||
// 备注
|
||||
comments: '',
|
||||
// 内容
|
||||
content: ''
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
title: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入文档标题',
|
||||
type: 'string',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
sortNumber: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入排序号',
|
||||
type: 'number',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
/* type选择改变 */
|
||||
const onTypeChange = (e) => {
|
||||
if (e.target.value === 1) {
|
||||
form.type = 0;
|
||||
} else {
|
||||
form.type = 1;
|
||||
}
|
||||
};
|
||||
|
||||
const { resetFields, validate, validateInfos } = useForm(form, rules);
|
||||
|
||||
/* 保存编辑 */
|
||||
const save = () => {
|
||||
validate()
|
||||
.then(() => {
|
||||
loading.value = true;
|
||||
const docsData = {
|
||||
...form,
|
||||
parentId: form.parentId || 0
|
||||
};
|
||||
const saveOrUpdate = isUpdate.value ? updateDocs : addDocs;
|
||||
saveOrUpdate(docsData)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
message.success(msg);
|
||||
updateVisible(false);
|
||||
emit('done');
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
/* 更新visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
if (props.data) {
|
||||
assignObject(form, props.data);
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
form.parentId = props.docsId;
|
||||
isUpdate.value = false;
|
||||
}
|
||||
} else {
|
||||
resetFields();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
39
src/views/cms/docs-md-bak/components/docs-select.vue
Normal file
39
src/views/cms/docs-md-bak/components/docs-select.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<!-- 目录选择下拉框 -->
|
||||
<template>
|
||||
<a-tree-select
|
||||
allow-clear
|
||||
tree-default-expand-all
|
||||
:placeholder="placeholder"
|
||||
:value="value || undefined"
|
||||
:tree-data="data"
|
||||
:dropdown-style="{ maxHeight: '360px', overflow: 'auto' }"
|
||||
@update:value="updateValue"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Docs } from '@/api/cms/docs/model';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', value?: number): void;
|
||||
}>();
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
// 选中的数据(v-modal)
|
||||
value?: number;
|
||||
// 提示信息
|
||||
placeholder?: string;
|
||||
// 目录数据
|
||||
data: Docs[];
|
||||
}>(),
|
||||
{
|
||||
placeholder: '请选择目录'
|
||||
}
|
||||
);
|
||||
|
||||
/* 更新选中数据 */
|
||||
const updateValue = (value?: number) => {
|
||||
emit('update:value', value);
|
||||
};
|
||||
</script>
|
||||
169
src/views/cms/docs-md-bak/content.vue
Normal file
169
src/views/cms/docs-md-bak/content.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<a-card v-if="current" :bordered="false" :title="`${current.title}`">
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a @click="onEdit">{{ isUpdate ? '预览' : '编辑' }}</a>
|
||||
<a-divider v-if="isUpdate" type="vertical" />
|
||||
<a v-if="isUpdate" type="primary" @click="save">保存</a>
|
||||
</a-space>
|
||||
</template>
|
||||
<div class="content">
|
||||
<!-- 编辑器 -->
|
||||
<byte-md-editor
|
||||
v-if="isUpdate"
|
||||
v-model:value="content"
|
||||
placeholder="请输入您的内容,图片请直接粘贴"
|
||||
:locale="zh_Hans"
|
||||
mode="split"
|
||||
:plugins="plugins"
|
||||
:editorConfig="{ lineNumbers: true }"
|
||||
@paste="onPaste"
|
||||
/>
|
||||
<byte-md-viewer v-else :value="content" :plugins="plugins" />
|
||||
</div>
|
||||
</a-card>
|
||||
<div class="docs-sumbit" v-if="isUpdate">
|
||||
<a-button type="primary" @click="save">保存</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import 'bytemd/dist/index.min.css';
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import 'github-markdown-css/github-markdown-light.css';
|
||||
import type { Docs } from '@/api/cms/docs/model';
|
||||
import { message } from 'ant-design-vue';
|
||||
import ByteMdEditor from '@/components/ByteMdEditor/index.vue';
|
||||
import highlight from '@bytemd/plugin-highlight';
|
||||
// 中文语言文件
|
||||
import zh_Hans from 'bytemd/locales/zh_Hans.json';
|
||||
// // 链接、删除线、复选框、表格等的插件
|
||||
import gfm from '@bytemd/plugin-gfm';
|
||||
// // 插件的中文语言文件
|
||||
import zh_HansGfm from '@bytemd/plugin-gfm/locales/zh_Hans.json';
|
||||
// // 预览界面的样式,这里用的 github 的 markdown 主题
|
||||
import 'github-markdown-css/github-markdown-light.css';
|
||||
import { addDocs, updateDocs } from '@/api/cms/docs';
|
||||
import {ItemType} from "ele-admin-pro/es/ele-image-upload/types";
|
||||
import {uploadFile} from "@/api/system/file";
|
||||
|
||||
const props = defineProps<{
|
||||
// 文档 id
|
||||
current?: Docs | null;
|
||||
}>();
|
||||
|
||||
// 插件
|
||||
const plugins = ref([
|
||||
gfm({
|
||||
locale: zh_HansGfm
|
||||
}),
|
||||
highlight()
|
||||
]);
|
||||
|
||||
// 提交状态
|
||||
const loading = ref(false);
|
||||
// 编辑器内容,双向绑定
|
||||
const content = ref('');
|
||||
const editStatus = ref(false);
|
||||
// const disabled = ref(false);
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
// const docsContentId = ref(0);
|
||||
|
||||
const form = reactive<Docs>({
|
||||
docsId: 0,
|
||||
content: ''
|
||||
});
|
||||
|
||||
const onEdit = () => {
|
||||
isUpdate.value = !isUpdate.value;
|
||||
}
|
||||
|
||||
|
||||
/* 粘贴图片上传服务器并插入编辑器 */
|
||||
const onPaste = (e) => {
|
||||
console.log(e);
|
||||
const items = (e.clipboardData || e.originalEvent.clipboardData).items;
|
||||
console.log(items);
|
||||
let hasFile = false;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf('image') !== -1) {
|
||||
let file = items[i].getAsFile();
|
||||
const item: ItemType = {
|
||||
file,
|
||||
uid: (file as any).lastModified,
|
||||
name: file.name
|
||||
};
|
||||
uploadFile(<File>item.file)
|
||||
.then((result) => {
|
||||
const addPath = '\n\r';
|
||||
content.value = content.value + addPath
|
||||
})
|
||||
.catch((e) => {
|
||||
message.error(e.message);
|
||||
});
|
||||
hasFile = true;
|
||||
}
|
||||
}
|
||||
if (hasFile) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// 保存文档
|
||||
const save = () => {
|
||||
loading.value = true;
|
||||
const docsData = {
|
||||
...form,
|
||||
docsId: props.current?.docsId,
|
||||
content: content.value
|
||||
};
|
||||
const saveOrUpdate = isUpdate.value ? updateDocs : addDocs;
|
||||
saveOrUpdate(docsData)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
isUpdate.value = false;
|
||||
message.success(msg);
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
// 监听文档 id 变化
|
||||
watch(
|
||||
() => props.current?.docsId,
|
||||
() => {
|
||||
content.value = props.current?.content + '';
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Markdown'
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
/deep/.markdown-body{
|
||||
background-color: transparent; /* 设置背景透明 */
|
||||
}
|
||||
.sys-category-table :deep(.ant-table-body) {
|
||||
overflow: auto !important;
|
||||
overflow: overlay !important;
|
||||
}
|
||||
|
||||
.sys-category-table :deep(.ant-table-pagination.ant-pagination) {
|
||||
padding: 0 4px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.content *{
|
||||
max-width: 80%;
|
||||
}
|
||||
.docs-sumbit {
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
258
src/views/cms/docs-md-bak/index.vue
Normal file
258
src/views/cms/docs-md-bak/index.vue
Normal file
@@ -0,0 +1,258 @@
|
||||
<template>
|
||||
<div class="ele-body">
|
||||
<a-card
|
||||
:bordered="false"
|
||||
class="transparent-bg"
|
||||
:body-style="{ padding: '16px' }"
|
||||
>
|
||||
<ele-split-layout
|
||||
width="266px"
|
||||
allow-collapse
|
||||
:right-style="{ overflow: 'hidden' }"
|
||||
:style="{ minHeight: 'calc(100vh - 152px)' }"
|
||||
>
|
||||
<a-card :body-style="{ padding: '0' }">
|
||||
<ele-toolbar theme="default">
|
||||
<a-space :size="10">
|
||||
<span>目录</span>
|
||||
<a-button
|
||||
v-permission="'cms:docs:save'"
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
class="ele-btn-icon"
|
||||
@click="openEdit()"
|
||||
>
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
v-permission="'cms:docs:update'"
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
:disabled="!current"
|
||||
class="ele-btn-icon"
|
||||
@click="openEdit(current)"
|
||||
>
|
||||
<template #icon>
|
||||
<edit-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
v-permission="'cms:docs:remove'"
|
||||
danger
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
:disabled="!current"
|
||||
class="ele-btn-icon"
|
||||
@click="remove"
|
||||
>
|
||||
<template #icon>
|
||||
<delete-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-space>
|
||||
</ele-toolbar>
|
||||
<div class="ele-border-split sys-docs-list">
|
||||
<a-tree
|
||||
:tree-data="data"
|
||||
v-model:expanded-keys="expandedRowKeys"
|
||||
v-model:selected-keys="selectedRowKeys"
|
||||
@select="onTreeSelect"
|
||||
>
|
||||
<template #title="{ key: treeKey, title }">
|
||||
<a-dropdown :trigger="['contextmenu']">
|
||||
<span>{{ title }}</span>
|
||||
<template #overlay>
|
||||
<a-menu
|
||||
@click="
|
||||
({ key: menuKey }) =>
|
||||
onContextMenuClick(treeKey, menuKey)
|
||||
"
|
||||
>
|
||||
<a-menu-item key="1">添加</a-menu-item>
|
||||
<a-menu-item key="2">修改</a-menu-item>
|
||||
<a-menu-item key="3">删除</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
</a-card>
|
||||
<template #content>
|
||||
<content :data="data" :current="current" @done="query"></content>
|
||||
</template>
|
||||
</ele-split-layout>
|
||||
</a-card>
|
||||
<!-- 编辑弹窗 -->
|
||||
<docs-edit
|
||||
v-model:visible="showEdit"
|
||||
:data="editData"
|
||||
:docs="data"
|
||||
:docs-id="current?.docsId"
|
||||
@done="query"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import {
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
ExclamationCircleOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
import { toTreeData, eachTreeData } from 'ele-admin-pro';
|
||||
import Content from './content.vue';
|
||||
import DocsEdit from './components/docs-edit.vue';
|
||||
import { listDocs, getDocs, removeDocs } from '@/api/cms/docs';
|
||||
import type { Docs, DocsParam } from '@/api/cms/docs/model';
|
||||
import useSearch from '@/utils/use-search';
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(true);
|
||||
|
||||
// 树形数据
|
||||
const data = ref<any[]>([]);
|
||||
|
||||
// 树展开的key
|
||||
const expandedRowKeys = ref<number[]>([]);
|
||||
|
||||
// 树选中的key
|
||||
const selectedRowKeys = ref<number[]>([]);
|
||||
|
||||
// 选中数据
|
||||
const current = ref<Docs | null>();
|
||||
|
||||
// 是否显示表单弹窗
|
||||
const showEdit = ref(false);
|
||||
|
||||
// 编辑回显数据
|
||||
const editData = ref<Docs | null>(null);
|
||||
|
||||
// 表单数据
|
||||
const { where } = useSearch<DocsParam>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
/* 查询 */
|
||||
const query = () => {
|
||||
loading.value = true;
|
||||
listDocs()
|
||||
.then((list) => {
|
||||
loading.value = false;
|
||||
const eks: number[] = [];
|
||||
list.forEach((d, i) => {
|
||||
d.key = d.docsId;
|
||||
d.value = d.docsId;
|
||||
if (typeof d.docsId === 'number') {
|
||||
eks.push(d.docsId);
|
||||
}
|
||||
});
|
||||
expandedRowKeys.value = eks;
|
||||
data.value = toTreeData({
|
||||
data: list,
|
||||
idField: 'docsId',
|
||||
parentIdField: 'parentId'
|
||||
});
|
||||
if (list.length) {
|
||||
if (typeof list[0].docsId === 'number') {
|
||||
selectedRowKeys.value = [list[0].docsId];
|
||||
}
|
||||
queryDocs(list[0].docsId);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
/* 选择数据 */
|
||||
const onTreeSelect = () => {
|
||||
eachTreeData(data.value, (d) => {
|
||||
if (
|
||||
typeof d.docsId === 'number' &&
|
||||
selectedRowKeys.value.includes(d.docsId)
|
||||
) {
|
||||
queryDocs(d.docsId);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 查询文档
|
||||
const queryDocs = (docsId) => {
|
||||
getDocs(docsId).then((detail) => {
|
||||
current.value = detail;
|
||||
});
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (item?: Docs | null) => {
|
||||
editData.value = item ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
/* 删除 */
|
||||
const remove = () => {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除选中的文档吗?',
|
||||
icon: createVNode(ExclamationCircleOutlined),
|
||||
maskClosable: true,
|
||||
onOk: () => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removeDocs(current.value?.docsId)
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
query();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onContextMenuClick = (treeKey: string, menuKey: string | number) => {
|
||||
// 添加操作
|
||||
if (menuKey == 1) {
|
||||
openEdit();
|
||||
}
|
||||
// 编辑操作
|
||||
if (menuKey == 2) {
|
||||
openEdit(current.value);
|
||||
}
|
||||
// 删除操作
|
||||
if (menuKey == 3) {
|
||||
remove();
|
||||
}
|
||||
console.log(`treeKey: ${treeKey}, menuKey: ${menuKey}`);
|
||||
};
|
||||
|
||||
query();
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Docs'
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.transparent-bg {
|
||||
background-color: transparent; /* 设置背景透明 */
|
||||
}
|
||||
.sys-docs-list {
|
||||
padding: 12px 6px;
|
||||
height: calc(100vh - 242px);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
162
src/views/cms/docs-md-bak/markdown.vue
Normal file
162
src/views/cms/docs-md-bak/markdown.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<a-card v-if="current" :bordered="false" :title="`${current.title}`">
|
||||
<!-- 编辑器 -->
|
||||
<tinymce-editor
|
||||
v-model:value="content"
|
||||
:disabled="disabled"
|
||||
:init="config"
|
||||
/>
|
||||
<div class="ele-text-info" style="margin-top: 10px">
|
||||
<a-space :size="100">
|
||||
<div>文档ID: {{ current.docsId }}</div>
|
||||
<div>预览地址: {{ `/docs?id=${current.docsId}` }}</div>
|
||||
<div>发布时间: {{ current.createTime }}</div>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="docs-sumbit" v-permission="'cms:docs:update'">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="save">保存</a-button>
|
||||
<!-- <router-link :to="'/content/docs?id=' + current.docsId" @click.stop="">-->
|
||||
<!-- <a-button>预览</a-button>-->
|
||||
<!-- </router-link>-->
|
||||
</a-space>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import 'github-markdown-css/github-markdown-light.css';
|
||||
import type { Docs } from '@/api/cms/docs/model';
|
||||
import { message } from 'ant-design-vue';
|
||||
import TinymceEditor from '@/components/TinymceEditor/index.vue';
|
||||
import {
|
||||
addDocsContent,
|
||||
getDocsContent,
|
||||
updateDocsContent
|
||||
} from '@/api/cms/docs-content';
|
||||
import { DocsContent } from '@/api/cms/docs-content/model';
|
||||
|
||||
const props = defineProps<{
|
||||
// 文档 id
|
||||
current?: Docs | null;
|
||||
}>();
|
||||
|
||||
// 提交状态
|
||||
const loading = ref(false);
|
||||
// 编辑器内容,双向绑定
|
||||
const content = ref('');
|
||||
const disabled = ref(false);
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
const docsContentId = ref(0);
|
||||
|
||||
const form = reactive<DocsContent>({
|
||||
docsContentId: 0,
|
||||
docsId: 0,
|
||||
content: ''
|
||||
});
|
||||
|
||||
const editorRef = ref<InstanceType<typeof TinymceEditor> | null>(null);
|
||||
const config = ref({
|
||||
height: 690,
|
||||
// 自定义文件上传(这里使用把选择的文件转成 blob 演示)
|
||||
file_picker_callback: (callback: any, _value: any, meta: any) => {
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'file');
|
||||
// 设定文件可选类型
|
||||
if (meta.filetype === 'image') {
|
||||
input.setAttribute('accept', 'image/*');
|
||||
} else if (meta.filetype === 'media') {
|
||||
input.setAttribute('accept', 'video/*');
|
||||
}
|
||||
input.onchange = () => {
|
||||
const file = input.files?.[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
if (meta.filetype === 'media') {
|
||||
if (!file.type.startsWith('video/')) {
|
||||
editorRef.value?.alert({ content: '只能选择视频文件' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (file.size / 1024 / 1024 > 20) {
|
||||
editorRef.value?.alert({ content: '大小不能超过 20MB' });
|
||||
return;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
if (e.target?.result != null) {
|
||||
const blob = new Blob([e.target.result], { type: file.type });
|
||||
callback(URL.createObjectURL(blob));
|
||||
}
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
};
|
||||
input.click();
|
||||
}
|
||||
});
|
||||
|
||||
/* 搜索 */
|
||||
const reload = () => {
|
||||
getDocsContent(Number(props.current?.docsId))
|
||||
.then((res) => {
|
||||
content.value = String(res.content);
|
||||
docsContentId.value = Number(res.docsContentId);
|
||||
isUpdate.value = true;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
content.value = '';
|
||||
isUpdate.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 保存文档
|
||||
const save = () => {
|
||||
loading.value = true;
|
||||
const docsData = {
|
||||
...form,
|
||||
docsContentId: docsContentId.value,
|
||||
docsId: props.current?.docsId,
|
||||
content: content.value
|
||||
};
|
||||
const saveOrUpdate = isUpdate.value ? updateDocsContent : addDocsContent;
|
||||
saveOrUpdate(docsData)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
message.success(msg);
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
// 监听文档 id 变化
|
||||
watch(
|
||||
() => props.current?.docsId,
|
||||
() => {
|
||||
reload();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sys-category-table :deep(.ant-table-body) {
|
||||
overflow: auto !important;
|
||||
overflow: overlay !important;
|
||||
}
|
||||
|
||||
.sys-category-table :deep(.ant-table-pagination.ant-pagination) {
|
||||
padding: 0 4px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.docs-sumbit {
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
162
src/views/cms/docs-md-bak/tinymce.vue
Normal file
162
src/views/cms/docs-md-bak/tinymce.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<a-card v-if="current" :bordered="false" :title="`${current.title}`">
|
||||
<!-- 编辑器 -->
|
||||
<tinymce-editor
|
||||
v-model:value="content"
|
||||
:disabled="disabled"
|
||||
:init="config"
|
||||
/>
|
||||
<div class="ele-text-info" style="margin-top: 10px">
|
||||
<a-space :size="100">
|
||||
<div>文档ID: {{ current.docsId }}</div>
|
||||
<div>预览地址: {{ `/docs?id=${current.docsId}` }}</div>
|
||||
<div>发布时间: {{ current.createTime }}</div>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="docs-sumbit" v-permission="'cms:docs:update'">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="save">保存</a-button>
|
||||
<!-- <router-link :to="'/content/docs?id=' + current.docsId" @click.stop="">-->
|
||||
<!-- <a-button>预览</a-button>-->
|
||||
<!-- </router-link>-->
|
||||
</a-space>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import 'github-markdown-css/github-markdown-light.css';
|
||||
import type { Docs } from '@/api/cms/docs/model';
|
||||
import { message } from 'ant-design-vue';
|
||||
import TinymceEditor from '@/components/TinymceEditor/index.vue';
|
||||
import {
|
||||
addDocsContent,
|
||||
getDocsContent,
|
||||
updateDocsContent
|
||||
} from '@/api/cms/docs-content';
|
||||
import { DocsContent } from '@/api/cms/docs-content/model';
|
||||
|
||||
const props = defineProps<{
|
||||
// 文档 id
|
||||
current?: Docs | null;
|
||||
}>();
|
||||
|
||||
// 提交状态
|
||||
const loading = ref(false);
|
||||
// 编辑器内容,双向绑定
|
||||
const content = ref('');
|
||||
const disabled = ref(false);
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
const docsContentId = ref(0);
|
||||
|
||||
const form = reactive<DocsContent>({
|
||||
docsContentId: 0,
|
||||
docsId: 0,
|
||||
content: ''
|
||||
});
|
||||
|
||||
const editorRef = ref<InstanceType<typeof TinymceEditor> | null>(null);
|
||||
const config = ref({
|
||||
height: 690,
|
||||
// 自定义文件上传(这里使用把选择的文件转成 blob 演示)
|
||||
file_picker_callback: (callback: any, _value: any, meta: any) => {
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'file');
|
||||
// 设定文件可选类型
|
||||
if (meta.filetype === 'image') {
|
||||
input.setAttribute('accept', 'image/*');
|
||||
} else if (meta.filetype === 'media') {
|
||||
input.setAttribute('accept', 'video/*');
|
||||
}
|
||||
input.onchange = () => {
|
||||
const file = input.files?.[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
if (meta.filetype === 'media') {
|
||||
if (!file.type.startsWith('video/')) {
|
||||
editorRef.value?.alert({ content: '只能选择视频文件' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (file.size / 1024 / 1024 > 20) {
|
||||
editorRef.value?.alert({ content: '大小不能超过 20MB' });
|
||||
return;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
if (e.target?.result != null) {
|
||||
const blob = new Blob([e.target.result], { type: file.type });
|
||||
callback(URL.createObjectURL(blob));
|
||||
}
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
};
|
||||
input.click();
|
||||
}
|
||||
});
|
||||
|
||||
/* 搜索 */
|
||||
const reload = () => {
|
||||
getDocsContent(Number(props.current?.docsId))
|
||||
.then((res) => {
|
||||
content.value = String(res.content);
|
||||
docsContentId.value = Number(res.docsContentId);
|
||||
isUpdate.value = true;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
content.value = '';
|
||||
isUpdate.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 保存文档
|
||||
const save = () => {
|
||||
loading.value = true;
|
||||
const docsData = {
|
||||
...form,
|
||||
docsContentId: docsContentId.value,
|
||||
docsId: props.current?.docsId,
|
||||
content: content.value
|
||||
};
|
||||
const saveOrUpdate = isUpdate.value ? updateDocsContent : addDocsContent;
|
||||
saveOrUpdate(docsData)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
message.success(msg);
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
// 监听文档 id 变化
|
||||
watch(
|
||||
() => props.current?.docsId,
|
||||
() => {
|
||||
reload();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sys-category-table :deep(.ant-table-body) {
|
||||
overflow: auto !important;
|
||||
overflow: overlay !important;
|
||||
}
|
||||
|
||||
.sys-category-table :deep(.ant-table-pagination.ant-pagination) {
|
||||
padding: 0 4px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.docs-sumbit {
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user