样式优化

This commit is contained in:
xiaozzzi 2023-10-08 14:56:24 +08:00
parent d4ca45956f
commit 247e33500e
7 changed files with 195 additions and 187 deletions

View File

@ -1,10 +1,5 @@
# 单引号
singleQuote: true singleQuote: true
# 不以分号结尾
semi: false semi: false
# 每行 150
printWidth: 150 printWidth: 150
# 不以逗号结尾
trailingComma: none trailingComma: none
# 标签末尾在同一行
bracketSameLine: true bracketSameLine: true

View File

@ -156,7 +156,7 @@ html.dark {
/* background color */ /* background color */
--bl-bg-color: #333434; --bl-bg-color: #333434;
/* ================================= text styles =================================*/ /* ================================= text styles =================================*/
--bl-text-doctree-color: #a8a8a8; --bl-text-doctree-color: #d0d0d0;
/* primary color */ /* primary color */
--bl-text-color: #a8a8a8; --bl-text-color: #a8a8a8;
/* lighter than primary color */ /* lighter than primary color */

View File

@ -1,17 +1,17 @@
<template> <template>
<!-- 文件夹操作 --> <!-- 文件夹操作 -->
<div class="doc-workbench"> <div class="doc-workbench">
<ArticleTreeWorkbench @refresh-doc-tree="getDocTree" @show-sort="handleShowSort" ref="ArticleTreeWorkbenchRef"> <ArticleTreeWorkbench @refresh-doc-tree="getDocTree" @show-sort="handleShowSort" ref="ArticleTreeWorkbenchRef"> </ArticleTreeWorkbench>
</ArticleTreeWorkbench>
</div> </div>
<div class="doc-trees-container" v-loading="docTreeLoading" element-loading-text="正在读取文档..." <div
class="doc-trees-container"
v-loading="docTreeLoading"
element-loading-text="正在读取文档..."
:style="{ fontSize: configStore.viewStyle.treeDocsFontSize }"> :style="{ fontSize: configStore.viewStyle.treeDocsFontSize }">
<el-menu v-if="!isEmpty(docTreeData)" class="doc-trees" :unique-opened="true" :default-active="docTreeDefaultActive"> <el-menu v-if="!isEmpty(docTreeData)" class="doc-trees" :unique-opened="true" :default-active="docTreeDefaultActive">
<!-- ================================================ L1 ================================================ --> <!-- ================================================ L1 ================================================ -->
<div v-for="L1 in docTreeData" :key="L1.i"> <div v-for="L1 in docTreeData" :key="L1.i">
<!-- L1无下级 --> <!-- L1无下级 -->
<el-menu-item v-if="isEmpty(L1.children)" :index="L1.i"> <el-menu-item v-if="isEmpty(L1.children)" :index="L1.i">
<template #title> <template #title>
@ -53,8 +53,7 @@
<!-- L3无下级 --> <!-- L3无下级 -->
<el-menu-item v-if="isEmpty(L3.children)" :index="L3.i"> <el-menu-item v-if="isEmpty(L3.children)" :index="L3.i">
<template #title> <template #title>
<div class="menu-item-wrapper" @click="clickCurDoc(L3)" <div class="menu-item-wrapper" @click="clickCurDoc(L3)" @click.right="handleClickRightMenu(L3, $event)">
@click.right="handleClickRightMenu(L3, $event)">
<ArticleTreeTitle :trees="L3" :level="3" /> <ArticleTreeTitle :trees="L3" :level="3" />
</div> </div>
</template> </template>
@ -73,8 +72,7 @@
<!-- L4 不允许有下级, 只允许4级 --> <!-- L4 不允许有下级, 只允许4级 -->
<el-menu-item v-if="isEmpty(L4.children)" :index="L4.i"> <el-menu-item v-if="isEmpty(L4.children)" :index="L4.i">
<template #title> <template #title>
<div class="menu-item-wrapper" @click="clickCurDoc(L4)" style="width: 100%;" <div class="menu-item-wrapper" @click="clickCurDoc(L4)" style="width: 100%" @click.right="handleClickRightMenu(L4, $event)">
@click.right="handleClickRightMenu(L4, $event)">
<ArticleTreeTitle :trees="L4" :level="4" /> <ArticleTreeTitle :trees="L4" :level="4" />
</div> </div>
</template> </template>
@ -87,70 +85,43 @@
</el-sub-menu> </el-sub-menu>
</div> </div>
</el-menu> </el-menu>
<div v-else class="doc-trees-empty-placeholder"> <div v-else class="doc-trees-empty-placeholder">暂无文档可点击上方 添加</div>
暂无文档可点击上方 添加
</div>
</div> </div>
<!-- 右键菜单, 添加到 body --> <!-- 右键菜单, 添加到 body -->
<Teleport to="body"> <Teleport to="body">
<div v-show="rMenu.show" class="doc-tree-right-menu" <div
:style="{ left: rMenu.clientX + 'px', top: rMenu.clientY + 'px' }" ref="ArticleDocTreeRightMenuRef"> v-show="rMenu.show"
class="doc-tree-right-menu"
:style="{ left: rMenu.clientX + 'px', top: rMenu.clientY + 'px' }"
ref="ArticleDocTreeRightMenuRef">
<div class="doc-name">{{ curDoc.n }}</div> <div class="doc-name">{{ curDoc.n }}</div>
<div class="menu-content"> <div class="menu-content">
<div @click="handleShowDocInfoDialog('upd')"> <div @click="handleShowDocInfoDialog('upd')"><span class="iconbl bl-a-fileedit-line"></span>编辑文档</div>
<span class="iconbl bl-a-fileedit-line"></span>编辑文档 <div @click="syncDoc()"><span class="iconbl bl-a-cloudrefresh-line"></span>同步文档</div>
</div> <div @click="handleShowDocInfoDialog('add', curDoc.p)"><span class="iconbl bl-a-fileadd-line"></span>新增同级文档</div>
<div @click="syncDoc()"> <div v-if="curDoc.ty != 3" @click="handleShowDocInfoDialog('add', curDoc.i)"><span class="iconbl bl-a-fileadd-fill"></span>新增子级文档</div>
<span class="iconbl bl-a-cloudrefresh-line"></span>同步文档 <div @click="delDoc()"><span class="iconbl bl-a-fileprohibit-line"></span>删除文档</div>
</div> <div v-if="curDoc.ty === 3" @click="createUrl('link')"><span class="iconbl bl-correlation-line"></span>复制引用</div>
<div @click="handleShowDocInfoDialog('add', curDoc.p)"> <div v-if="curDoc.ty != 3" @click="handleShowArticleImportDialog()"><span class="iconbl bl-file-upload-line"></span>导入文章</div>
<span class="iconbl bl-a-fileadd-line"></span>新增同级文档
</div>
<div v-if="curDoc.ty != 3" @click="handleShowDocInfoDialog('add', curDoc.i)">
<span class="iconbl bl-a-fileadd-fill"></span>新增子级文档
</div>
<div @click="delDoc()">
<span class="iconbl bl-a-fileprohibit-line"></span>删除文档
</div>
<div v-if="curDoc.ty === 3" @click="createUrl('link')">
<span class="iconbl bl-correlation-line"></span>复制引用
</div>
<div v-if="curDoc.ty != 3" @click="handleShowArticleImportDialog()">
<span class="iconbl bl-file-upload-line"></span>导入文章
</div>
<div class="menu-item-divider" v-if="curDoc.ty === 3"></div> <div class="menu-item-divider" v-if="curDoc.ty === 3"></div>
<div v-if="curDoc.ty === 3" @click="openArticleWindow"> <div v-if="curDoc.ty === 3" @click="openArticleWindow"><span class="iconbl bl-a-computerend-line"></span>新窗口打开</div>
<span class="iconbl bl-a-computerend-line"></span>新窗口打开
</div>
<div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="createUrl('open')"> <div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="createUrl('open')"><span class="iconbl bl-planet-line"></span>浏览器打开</div>
<span class="iconbl bl-planet-line"></span>浏览器打开
</div>
<div v-if="curDoc.ty === 3" @mouseenter="handleHoverRightMenuLevel2($event, 4)"> <div v-if="curDoc.ty === 3" @mouseenter="handleHoverRightMenuLevel2($event, 4)">
<span class="iconbl bl-a-rightsmallline-line"></span> <span class="iconbl bl-a-rightsmallline-line"></span>
<span class="iconbl bl-file-download-line"></span>导出文章 <span class="iconbl bl-file-download-line"></span>导出文章
<div class="menu-content-level2" :style="rMenuLevel2"> <div class="menu-content-level2" :style="rMenuLevel2">
<div @click="articleDownload"> <div @click="articleDownload"><span class="iconbl bl-file-markdown"></span>导出为 MD</div>
<span class="iconbl bl-file-markdown"></span>导出为 MD <div @click="articleBackup('MARKDOWN')"><span class="iconbl bl-file-markdown"></span>导出为本地 MD</div>
</div> <div @click="articleDownloadHtml"><span class="iconbl bl-HTML"></span>导出为 HTML</div>
<div @click="articleBackup('MARKDOWN')"> <div @click="articleBackup('HTML')"><span class="iconbl bl-HTML"></span>导出为本地 HTML</div>
<span class="iconbl bl-file-markdown"></span>导出为本地 MD
</div>
<div @click="articleDownloadHtml">
<span class="iconbl bl-HTML"></span>导出为 HTML
</div>
<div @click="articleBackup('HTML')">
<span class="iconbl bl-HTML"></span>导出为本地 HTML
</div>
</div> </div>
</div> </div>
<div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="createUrl('copy')"> <div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="createUrl('copy')"><span class="iconbl bl-a-linkspread-line"></span>复制链接</div>
<span class="iconbl bl-a-linkspread-line"></span>复制链接
</div>
<div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="handleArticleQrCodeDialog()"> <div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="handleArticleQrCodeDialog()">
<span class="iconbl bl-qr-code-line"></span>查看二维码 <span class="iconbl bl-qr-code-line"></span>查看二维码
</div> </div>
@ -158,22 +129,40 @@
</div> </div>
</Teleport> </Teleport>
<!-- 详情 --> <!-- 详情 -->
<el-dialog v-model="isShowDocInfoDialog" width="535" top="100px" style="margin-left: 320px;" :append-to-body="true" <el-dialog
:destroy-on-close="true" :close-on-click-modal="false" draggable> v-model="isShowDocInfoDialog"
width="535"
top="100px"
style="margin-left: 320px"
:append-to-body="true"
:destroy-on-close="true"
:close-on-click-modal="false"
draggable>
<ArticleInfo ref="ArticleInfoRef" @saved="savedCallback"></ArticleInfo> <ArticleInfo ref="ArticleInfoRef" @saved="savedCallback"></ArticleInfo>
</el-dialog> </el-dialog>
<!-- 二维码 --> <!-- 二维码 -->
<el-dialog v-model="isShowQrCodeDialog" width="335" top="100px" :append-to-body="true" :destroy-on-close="true" <el-dialog
:close-on-click-modal="false" draggable> v-model="isShowQrCodeDialog"
width="335"
top="100px"
:append-to-body="true"
:destroy-on-close="true"
:close-on-click-modal="false"
draggable>
<ArticleQrCode ref="ArticleQrCodeRef"></ArticleQrCode> <ArticleQrCode ref="ArticleQrCodeRef"></ArticleQrCode>
</el-dialog> </el-dialog>
<!-- 导入 --> <!-- 导入 -->
<el-dialog v-model="isShowArticleImportDialog" width="335" top="80px" :append-to-body="true" :destroy-on-close="true" <el-dialog
:close-on-click-modal="false" draggable> v-model="isShowArticleImportDialog"
width="335"
top="80px"
:append-to-body="true"
:destroy-on-close="true"
:close-on-click-modal="false"
draggable>
<ArticleImport ref="ArticleImportRef" :doc="curDoc"></ArticleImport> <ArticleImport ref="ArticleImportRef" :doc="curDoc"></ArticleImport>
</el-dialog> </el-dialog>
</template> </template>
@ -182,11 +171,11 @@
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { useUserStore } from '@renderer/stores/user' import { useUserStore } from '@renderer/stores/user'
import { useConfigStore } from '@renderer/stores/config' import { useConfigStore } from '@renderer/stores/config'
import { ref, onActivated, provide, onBeforeUnmount, nextTick, onMounted } from "vue" import { ref, onActivated, provide, onBeforeUnmount, nextTick, onMounted } from 'vue'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { ArrowDownBold, ArrowRightBold } from '@element-plus/icons-vue' import { ArrowDownBold, ArrowRightBold } from '@element-plus/icons-vue'
import { articleDownloadHtmlApi, docTreeApi } from '@renderer/api/blossom' import { articleDownloadHtmlApi, docTreeApi } from '@renderer/api/blossom'
import { isNotNull } from "@renderer/assets/utils/obj" import { isNotNull } from '@renderer/assets/utils/obj'
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { provideKeyDocTree } from '@renderer/views/doc/doc' import { provideKeyDocTree } from '@renderer/views/doc/doc'
import { grammar } from './scripts/markedjs' import { grammar } from './scripts/markedjs'
@ -196,7 +185,7 @@ import Notify from '@renderer/scripts/notify'
// components // components
import ArticleTreeTitle from './ArticleTreeTitle.vue' import ArticleTreeTitle from './ArticleTreeTitle.vue'
import ArticleTreeWorkbench from "./ArticleTreeWorkbench.vue" import ArticleTreeWorkbench from './ArticleTreeWorkbench.vue'
import ArticleQrCode from './ArticleQrCode.vue' import ArticleQrCode from './ArticleQrCode.vue'
import ArticleInfo from './ArticleInfo.vue' import ArticleInfo from './ArticleInfo.vue'
import ArticleImport from './ArticleImport.vue' import ArticleImport from './ArticleImport.vue'
@ -222,10 +211,10 @@ onBeforeUnmount(() => {
//#region ----------------------------------------< >-------------------------------------- //#region ----------------------------------------< >--------------------------------------
const docTreeLoading = ref(true) // const docTreeLoading = ref(true) //
const showSort = ref(false) // const showSort = ref(false) //
const docTreeDefaultActive = ref('') // , const docTreeDefaultActive = ref('') // ,
const docTreeData = ref<DocTree[]>([]) // const docTreeData = ref<DocTree[]>([]) //
// //
provide(provideKeyDocTree, docTreeData) provide(provideKeyDocTree, docTreeData)
@ -248,12 +237,14 @@ const getRouteQueryParams = () => {
*/ */
const getDocTree = (isOnlyOpen: boolean, isOnlySubject: boolean, isOnlyStar: boolean) => { const getDocTree = (isOnlyOpen: boolean, isOnlySubject: boolean, isOnlyStar: boolean) => {
docTreeLoading.value = true docTreeLoading.value = true
docTreeApi({ onlyPicture: false, onlyOpen: isOnlyOpen, onlySubject: isOnlySubject, onlyStar: isOnlyStar }).then(resp => { docTreeApi({ onlyPicture: false, onlyOpen: isOnlyOpen, onlySubject: isOnlySubject, onlyStar: isOnlyStar })
docTreeData.value = resp.data .then((resp) => {
concatSort(docTreeData.value) docTreeData.value = resp.data
}).finally(() => { concatSort(docTreeData.value)
docTreeLoading.value = false })
}) .finally(() => {
docTreeLoading.value = false
})
} }
/** /**
@ -327,7 +318,7 @@ const removeListenerTreeDocsRightMenu = () => {
const handleHoverRightMenuLevel2 = (event: MouseEvent, childMenuCount: number = 1) => { const handleHoverRightMenuLevel2 = (event: MouseEvent, childMenuCount: number = 1) => {
const domHeight = 25 * childMenuCount + 10 const domHeight = 25 * childMenuCount + 10
if (document.body.clientHeight - event.clientY <= domHeight) { if (document.body.clientHeight - event.clientY <= domHeight) {
rMenuLevel2.value.top = (domHeight * -1 + 20) + 'px' rMenuLevel2.value.top = domHeight * -1 + 20 + 'px'
} else { } else {
rMenuLevel2.value.top = '0px' rMenuLevel2.value.top = '0px'
} }
@ -337,16 +328,15 @@ const handleHoverRightMenuLevel2 = (event: MouseEvent, childMenuCount: number =
* 打开新页面, 文件夹(curDoc.value.ty == 1)无法使用新页面打开 * 打开新页面, 文件夹(curDoc.value.ty == 1)无法使用新页面打开
*/ */
const openArticleWindow = () => { const openArticleWindow = () => {
if (curDoc.value.ty === 1) if (curDoc.value.ty === 1) return
return openNewArticleWindow(curDoc.value.n, curDoc.value.i)
openNewArticleWindow(curDoc.value.n, curDoc.value.i);
} }
/** /**
* 使用浏览器打开公开链接, 或复制公开链接 * 使用浏览器打开公开链接, 或复制公开链接
*/ */
const createUrl = (type: 'open' | 'copy' | 'link') => { const createUrl = (type: 'open' | 'copy' | 'link') => {
let url: string = userStore.userinfo.params.WEB_ARTICLE_URL + curDoc.value.i; let url: string = userStore.userinfo.params.WEB_ARTICLE_URL + curDoc.value.i
if (type == 'open') { if (type == 'open') {
openExtenal(url) openExtenal(url)
} else if (type == 'copy') { } else if (type == 'copy') {
@ -361,18 +351,18 @@ const createUrl = (type: 'open' | 'copy' | 'link') => {
* 下载文章 * 下载文章
*/ */
const articleDownload = () => { const articleDownload = () => {
articleDownloadApi({ id: curDoc.value.i }).then(resp => { articleDownloadApi({ id: curDoc.value.i }).then((resp) => {
let filename: string = resp.headers.get('content-disposition') let filename: string = resp.headers.get('content-disposition')
let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
let matches = filenameRegex.exec(filename); let matches = filenameRegex.exec(filename)
if (matches != null && matches[1]) { if (matches != null && matches[1]) {
filename = decodeURI(matches[1].replace(/['"]/g, '')); filename = decodeURI(matches[1].replace(/['"]/g, ''))
} }
let a = document.createElement('a') let a = document.createElement('a')
let blob = new Blob([resp.data], { type: "text/plain" }) let blob = new Blob([resp.data], { type: 'text/plain' })
let objectUrl = URL.createObjectURL(blob) let objectUrl = URL.createObjectURL(blob)
a.setAttribute("href", objectUrl) a.setAttribute('href', objectUrl)
a.setAttribute("download", filename) a.setAttribute('download', filename)
a.click() a.click()
URL.revokeObjectURL(a.href) URL.revokeObjectURL(a.href)
a.remove() a.remove()
@ -383,18 +373,18 @@ const articleDownload = () => {
* 下载HTML文章 * 下载HTML文章
*/ */
const articleDownloadHtml = () => { const articleDownloadHtml = () => {
articleDownloadHtmlApi({ id: curDoc.value.i }).then(resp => { articleDownloadHtmlApi({ id: curDoc.value.i }).then((resp) => {
let filename: string = resp.headers.get('content-disposition') let filename: string = resp.headers.get('content-disposition')
let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
let matches = filenameRegex.exec(filename); let matches = filenameRegex.exec(filename)
if (matches != null && matches[1]) { if (matches != null && matches[1]) {
filename = decodeURI(matches[1].replace(/['"]/g, '')); filename = decodeURI(matches[1].replace(/['"]/g, ''))
} }
let a = document.createElement('a') let a = document.createElement('a')
let blob = new Blob([resp.data], { type: "text/plain" }) let blob = new Blob([resp.data], { type: 'text/plain' })
let objectUrl = URL.createObjectURL(blob) let objectUrl = URL.createObjectURL(blob)
a.setAttribute("href", objectUrl) a.setAttribute('href', objectUrl)
a.setAttribute("download", filename) a.setAttribute('download', filename)
a.click() a.click()
URL.revokeObjectURL(a.href) URL.revokeObjectURL(a.href)
a.remove() a.remove()
@ -406,17 +396,18 @@ const articleDownloadHtml = () => {
* @param type 导出类型 * @param type 导出类型
*/ */
const articleBackup = (type: 'MARKDOWN' | 'HTML') => { const articleBackup = (type: 'MARKDOWN' | 'HTML') => {
articleBackupApi({ type: type, articleId: curDoc.value.i, toLocal: 'YES' }).then(resp => { articleBackupApi({ type: type, articleId: curDoc.value.i, toLocal: 'YES' }).then((resp) => {
ElMessageBox.confirm( ElMessageBox.confirm(
`由于导出为本地文章时需要导出图片等信息,所以文章将会以 `由于导出为本地文章时需要导出图片等信息,所以文章将会以
<span style="color:#C02B2B;text-decoration: underline;">备份压缩包</span> <span style="color:#C02B2B;text-decoration: underline;">备份压缩包</span>
的形式存储在服务器上文件名为${resp.data.filename}你可以前往备份页面查看导出进度和导出文件压缩包`, { 的形式存储在服务器上文件名为${resp.data.filename}你可以前往备份页面查看导出进度和导出文件压缩包`,
confirmButtonText: '立即查看', {
cancelButtonText: '稍后再说', confirmButtonText: '立即查看',
type: 'info', cancelButtonText: '稍后再说',
draggable: true, type: 'info',
dangerouslyUseHTMLString: true, draggable: true,
} dangerouslyUseHTMLString: true
}
).then(() => { ).then(() => {
ArticleTreeWorkbenchRef.value.handleShowBackupDialog() ArticleTreeWorkbenchRef.value.handleShowBackupDialog()
}) })
@ -438,18 +429,20 @@ const syncDoc = () => {
*/ */
const delDoc = () => { const delDoc = () => {
let type = curDoc.value.ty === 3 ? '文章' : '文件夹' let type = curDoc.value.ty === 3 ? '文章' : '文件夹'
ElMessageBox.confirm( ElMessageBox.confirm(`是否确定删除${type}: <span style="color:#C02B2B;text-decoration: underline;">${curDoc.value.n}</span>?删除后将不可恢复!`, {
`是否确定删除${type}: <span style="color:#C02B2B;text-decoration: underline;">${curDoc.value.n}</span>?删除后将不可恢复!`, { confirmButtonText: '确定删除',
confirmButtonText: '确定删除', cancelButtonText: '我再想想', type: 'info', draggable: true, dangerouslyUseHTMLString: true, cancelButtonText: '我再想想',
} type: 'info',
).then(() => { draggable: true,
dangerouslyUseHTMLString: true
}).then(() => {
if (curDoc.value.ty === 3) { if (curDoc.value.ty === 3) {
articleDelApi({ id: curDoc.value.i }).then(_resp => { articleDelApi({ id: curDoc.value.i }).then((_resp) => {
Notify.success(`删除文章成功`) Notify.success(`删除文章成功`)
getDocTree(false, false, false) getDocTree(false, false, false)
}) })
} else { } else {
folderDelApi({ id: curDoc.value.i }).then(_resp => { folderDelApi({ id: curDoc.value.i }).then((_resp) => {
Notify.success(`删除文件夹成功`) Notify.success(`删除文件夹成功`)
getDocTree(false, false, false) getDocTree(false, false, false)
}) })
@ -461,7 +454,7 @@ const delDoc = () => {
//#region ----------------------------------------< >-------------------------------------- //#region ----------------------------------------< >--------------------------------------
const isShowQrCodeDialog = ref<boolean>(false); const isShowQrCodeDialog = ref<boolean>(false)
const ArticleQrCodeRef = ref() const ArticleQrCodeRef = ref()
const handleArticleQrCodeDialog = () => { const handleArticleQrCodeDialog = () => {
@ -494,7 +487,9 @@ const handleShowDocInfoDialog = (dialogType: DocDialogType, pid?: number) => {
} }
isShowDocInfoDialog.value = true isShowDocInfoDialog.value = true
if (dialogType === 'add') { if (dialogType === 'add') {
nextTick(() => { ArticleInfoRef.value.reload(dialogType, undefined, undefined, pid) }) nextTick(() => {
ArticleInfoRef.value.reload(dialogType, undefined, undefined, pid)
})
} }
if (dialogType === 'upd') { if (dialogType === 'upd') {
nextTick(() => { nextTick(() => {
@ -503,11 +498,13 @@ const handleShowDocInfoDialog = (dialogType: DocDialogType, pid?: number) => {
} }
} }
const savedCallback = (dialogType: DocDialogType) => { /**
* 保存后回调
* @param dialogType
*/
const savedCallback = (_dialogType: DocDialogType) => {
getDocTree(false, false, false) getDocTree(false, false, false)
if (dialogType === 'upd') { isShowDocInfoDialog.value = false
isShowDocInfoDialog.value = false
}
} }
//#endregion //#endregion
@ -530,7 +527,6 @@ const clickCurDoc = (tree: DocTree) => {
const emits = defineEmits(['clickDoc']) const emits = defineEmits(['clickDoc'])
defineExpose({ getDocTreeData }) defineExpose({ getDocTreeData })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="doc-workbench-root"> <div class="doc-workbench-root">
<bl-row just="flex-end" align="flex-end"> <bl-row just="flex-end" align="flex-end">
<div v-show="curDoc !== undefined" style="font-size: 12px; text-align: right; color: var(--bl-text-color-light)"> <div v-show="curDoc !== undefined" style="font-size: 12px; text-align: right; color: var(--bl-text-color)">
<span>{{ curDoc?.name }}</span> <span>{{ curDoc?.name }}</span>
<br /> <br />
<span style="font-size: 9px; padding-right: 5px">{{ curDoc?.id }}</span> <span style="font-size: 9px; padding-right: 5px">{{ curDoc?.id }}</span>
@ -177,17 +177,20 @@ const openArticleReferenceWindow = () => {
openNewArticleReferenceWindow() openNewArticleReferenceWindow()
} }
/**
* 控制台刷新文档列表
*/
const refreshDocTree = () => { const refreshDocTree = () => {
emits('refreshDocTree', onlyOpen.value, onlySubject.value, onlyStars.value) emits('refreshDocTree', onlyOpen.value, onlySubject.value, onlyStars.value)
} }
/** /**
* 保存后的回调 * 保存后的回调
* 1. [暂无] 刷新菜单列表 * 1. 刷新菜单列表
* 2. 关闭 dialog 页面 * 2. 关闭 dialog 页面
*/ */
const savedCallback = () => { const savedCallback = () => {
// isShowDocInfoDialog.value = false isShowDocInfoDialog.value = false
emits('refreshDocTree', onlyOpen.value, onlySubject.value, onlyStars.value) emits('refreshDocTree', onlyOpen.value, onlySubject.value, onlyStars.value)
} }

View File

@ -126,19 +126,21 @@ export const cwTheme: any = {
} }
const zhCNPhrases = { const zhCNPhrases = {
"Go to line": "前往行", 'Fold line': '折叠',
"go": "前往", 'Unfold line': '展开',
"Find": "查找内容", 'Go to line': '前往行',
"Replace": "替换内容", go: '前往',
"next": "下一个", Find: '查找内容',
"previous": "上一个", Replace: '替换内容',
"all": "全部", next: '下一个',
"match case": "区分大小写", previous: '上一个',
"by word": "全字匹配", all: '全部',
"replace": "替换", 'match case': '区分大小写',
"replace all": "替换全部", 'by word': '全字匹配',
"close": "schließen", replace: '替换',
"regexp": "使用正则表达式" 'replace all': '替换全部',
close: 'schließen',
regexp: '使用正则表达式'
} }
/** /**

View File

@ -30,7 +30,7 @@
} }
.iconbl { .iconbl {
@include themeColor(#909399, #717171); @include themeColor(#909399, #969696);
text-shadow: var(--bl-iconbl-text-shadow); text-shadow: var(--bl-iconbl-text-shadow);
font-size: 25px; font-size: 25px;
padding: 3px 2px; padding: 3px 2px;

View File

@ -1,38 +1,36 @@
<template> <template>
<div class="article-info-root"> <div class="article-info-root">
<!-- 标题 --> <!-- 标题 -->
<div class="info-title"> <div class="info-title">
<div class="iconbl bl-a-labellist-line"></div>{{ taskSaveFormTitle }} <div class="iconbl bl-a-labellist-line"></div>
{{ taskSaveFormTitle }}
</div> </div>
<div v-loading="formLoading" class="info-form"> <div v-loading="formLoading" class="info-form">
<el-form :inline="true" :model="taskSaveForm" :rules="taskSaveFormRule" label-width="52px" ref="TaskSaveFormRef"> <el-form :inline="true" :model="taskSaveForm" :rules="taskSaveFormRule" label-width="52px" ref="TaskSaveFormRef">
<!-- <el-form-item label="todoId">
<el-input v-model="taskSaveForm.todoId" style="width: 90px;" disabled></el-input>
<el-input v-model="taskSaveForm.todoName" style="width: 90px;" disabled></el-input>
<el-input v-model="taskSaveForm.todoType" style="width: 30px;" disabled></el-input>
</el-form-item> -->
<el-form-item label="标题" prop="taskName"> <el-form-item label="标题" prop="taskName">
<el-input v-model="taskSaveForm.taskName"> <el-input v-model="taskSaveForm.taskName">
<template #append> <template #append>
<el-tooltip content="查看 Emoji" effect="blossomt" placement="top" :hide-after="0"> <el-tooltip content="查看 Emoji" effect="blossomt" placement="top" :hide-after="0">
<div class="emoji-link" @click="openExtenal('https://www.emojiall.com/zh-hans')">😉</div> <div class="emoji-link" @click="openExtenal('https://www.emojiall.com/zh-hans')">😉</div>
</el-tooltip> </el-tooltip>
</template></el-input> </template></el-input
>
</el-form-item> </el-form-item>
<el-form-item label="内容"> <el-form-item label="内容">
<el-input type="textarea" :rows="4" v-model="taskSaveForm.taskContent"></el-input> <el-input type="textarea" :rows="4" v-model="taskSaveForm.taskContent"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="标签"> <el-form-item label="标签">
<div class="info-tags-container"> <div class="info-tags-container">
<el-input v-if="isShowTagInput" ref="TagInputRef" style="width: 75px;" v-model="tagInputValue" <el-input
@keyup.enter="blurTagInput" @blur="blurTagInput" /> v-if="isShowTagInput"
<el-button v-else style="width: 75px;" @click="showInput"> ref="TagInputRef"
+ 标签 style="width: 75px"
</el-button> v-model="tagInputValue"
<el-tag v-for="tag in taskSaveForm?.taskTags" :key="tag" :disable-transitions="false" @keyup.enter="blurTagInput"
@close="handleTagClose(tag)" closable> @blur="blurTagInput" />
<el-button v-else style="width: 75px" @click="showInput"> + 标签 </el-button>
<el-tag v-for="tag in taskSaveForm?.taskTags" :key="tag" :disable-transitions="false" @close="handleTagClose(tag)" closable>
{{ tag }} {{ tag }}
</el-tag> </el-tag>
</div> </div>
@ -41,32 +39,45 @@
<el-input v-model="taskSaveForm.deadLine" placeholder="如下午3点会议之间"></el-input> <el-input v-model="taskSaveForm.deadLine" placeholder="如下午3点会议之间"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="开始于" v-if="infoType == 'upd'"> <el-form-item label="开始于" v-if="infoType == 'upd'">
<el-date-picker v-model="taskSaveForm.startTime" type="datetime" format="YYYY-MM-DD HH:mm:ss" <el-date-picker
value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" /> v-model="taskSaveForm.startTime"
type="datetime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%" />
</el-form-item> </el-form-item>
<el-form-item label="结束于" v-if="infoType == 'upd'"> <el-form-item label="结束于" v-if="infoType == 'upd'">
<el-date-picker v-model="taskSaveForm.endTime" type="datetime" format="YYYY-MM-DD HH:mm:ss" <el-date-picker
value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" /> v-model="taskSaveForm.endTime"
type="datetime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%" />
</el-form-item> </el-form-item>
<el-form-item label="颜色" style="width: auto;"> <el-form-item label="颜色" style="width: auto">
<el-input v-model="taskSaveForm.color" style="width:200px;margin-right: 5px;" <el-input v-model="taskSaveForm.color" style="width: 200px; margin-right: 5px" placeholder="推荐半透明色,更兼容暗黑模式"></el-input>
placeholder="推荐半透明色,更兼容暗黑模式"></el-input> <el-color-picker
<el-color-picker show-alpha v-model="taskSaveForm.color" :predefine="[ show-alpha
'rgba(68, 173, 56, 0.7)', v-model="taskSaveForm.color"
'rgba(186, 196, 44, 0.7)', :predefine="[
'rgba(235, 205, 72, 0.7)', 'rgba(68, 173, 56, 0.7)',
'rgba(232, 144, 144, 0.7)', 'rgba(186, 196, 44, 0.7)',
'rgba(112, 145, 188, 0.7)', 'rgba(235, 205, 72, 0.7)',
'rgba(157, 129, 216, 0.7)', 'rgba(232, 144, 144, 0.7)',
'rgba(0, 0, 0, 0.65)', 'rgba(112, 145, 188, 0.7)',
]" /> 'rgba(157, 129, 216, 0.7)',
'rgba(0, 0, 0, 0.65)'
]" />
<el-tooltip content="颜色搭配参考" effect="blossomt" placement="top" :hide-after="0"> <el-tooltip content="颜色搭配参考" effect="blossomt" placement="top" :hide-after="0">
<a href="https://colorhunt.co/" target="_blank" class="color-hunt iconbl bl-a-colorpalette-line" <a
href="https://colorhunt.co/"
target="_blank"
class="color-hunt iconbl bl-a-colorpalette-line"
:style="{ color: taskSaveForm.color }"></a> :style="{ color: taskSaveForm.color }"></a>
</el-tooltip> </el-tooltip>
</el-form-item> </el-form-item>
<el-form-item label="进度" v-if="infoType == 'upd'" style="width: auto;"> <el-form-item label="进度" v-if="infoType == 'upd'" style="width: auto">
<el-input-number v-model="taskSaveForm.process" :min="0" :max="100" :step="5"></el-input-number> <el-input-number v-model="taskSaveForm.process" :min="0" :max="100" :step="5"></el-input-number>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -123,7 +134,7 @@ const taskSaveFormRule = ref<FormRules<TaskInfo>>({
/** /**
* 保存表单,内部决定是否存还是新增 * 保存表单,内部决定是否存还是新增
* @param formEl * @param formEl
*/ */
const save = async (formEl: FormInstance | undefined) => { const save = async (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
@ -134,11 +145,11 @@ const save = async (formEl: FormInstance | undefined) => {
if (valid) { if (valid) {
if (isNotBlank(taskSaveForm.value.id)) { if (isNotBlank(taskSaveForm.value.id)) {
let datas = { ...taskSaveForm.value, ...{ returnTasks: true } } let datas = { ...taskSaveForm.value, ...{ returnTasks: true } }
updTaskApi(datas).then(resp => { updTaskApi(datas).then((resp) => {
emits('saved', resp.data) emits('saved', resp.data)
}) })
} else { } else {
addTaskApi(taskSaveForm.value).then(resp => { addTaskApi(taskSaveForm.value).then((resp) => {
emits('saved', resp.data) emits('saved', resp.data)
}) })
} }
@ -151,10 +162,13 @@ const save = async (formEl: FormInstance | undefined) => {
*/ */
const delTaskBefore = () => { const delTaskBefore = () => {
if (taskSaveForm.value.todoType === 20) { if (taskSaveForm.value.todoType === 20) {
countTaskApi({ todoId: taskSaveForm.value.todoId }).then(resp => { countTaskApi({ todoId: taskSaveForm.value.todoId }).then((resp) => {
if (resp.data == 1) { if (resp.data == 1) {
ElMessageBox.confirm(`当删除阶段性事项的最后一个任务时, 该事项也将一并删除, 是否确定删除?`, { ElMessageBox.confirm(`当删除阶段性事项的最后一个任务时, 该事项也将一并删除, 是否确定删除?`, {
confirmButtonText: '确定删除', cancelButtonText: '我再想想', type: 'info', draggable: true, confirmButtonText: '确定删除',
cancelButtonText: '我再想想',
type: 'info',
draggable: true
}).then(() => { }).then(() => {
delTask() delTask()
}) })
@ -162,26 +176,25 @@ const delTaskBefore = () => {
delTask() delTask()
} }
}) })
} } else {
else {
delTask() delTask()
} }
} }
const delTask = () => { const delTask = () => {
delTaskApi(taskSaveForm.value).then(resp => emits('saved', resp.data)) delTaskApi(taskSaveForm.value).then((resp) => emits('saved', resp.data))
} }
/** /**
* 回显数据 * 回显数据
* @param dialogType * @param dialogType
* @param taskId * @param taskId
*/ */
const reload = (dialogType: 'upd' | 'add', taskId?: string, todoId?: string, todoType?: TodoType) => { const reload = (dialogType: 'upd' | 'add', taskId?: string, todoId?: string, todoType?: TodoType) => {
infoType.value = dialogType infoType.value = dialogType
if (dialogType == 'upd') { if (dialogType == 'upd') {
taskSaveFormTitle.value = '修改任务' taskSaveFormTitle.value = '修改任务'
taskInfoApi({ id: taskId }).then(resp => { taskInfoApi({ id: taskId }).then((resp) => {
taskSaveForm.value = resp.data taskSaveForm.value = resp.data
}) })
} else { } else {
@ -248,12 +261,11 @@ const emits = defineEmits(['saved'])
} }
} }
.info-tags-container { .info-tags-container {
text-align: left; text-align: left;
overflow-y: scroll; overflow-y: scroll;
&>span, & > span,
button { button {
margin: 3px 3px; margin: 3px 3px;
} }
@ -262,4 +274,4 @@ const emits = defineEmits(['saved'])
margin: 3px 3px; margin: 3px 3px;
} }
} }
</style> </style>