Signed-off-by: chy <chy@163.com>
This commit is contained in:
89
src/hooks/design/useAvueUpload.ts
Normal file
89
src/hooks/design/useAvueUpload.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { downloadByUrl } from '@/utils/filt';
|
||||
export default function (jsEnhanceObj?: Ref<any>) {
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
//文件大小格式化
|
||||
const fileSizeFormatter = (fileSize) => {
|
||||
const unitArr = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
fileSize = parseFloat(fileSize)
|
||||
const index = Math.floor(Math.log(fileSize) / Math.log(1024))
|
||||
fileSize = fileSize / Math.pow(1024, index)
|
||||
//保留的小数位数
|
||||
if (`${fileSize}`.indexOf('.') != -1) fileSize = fileSize.toFixed(2)
|
||||
return fileSize + ' ' + unitArr[index]
|
||||
}
|
||||
|
||||
//校验文件类型
|
||||
const verifyFileType = (fileName) => {
|
||||
const imgExp = /\.(gif|jpg|jpeg|png|webp|svg|GIF|JPG|JPEG|PNG|WEBP|SVG)/
|
||||
const videoExp = /\.(swf|avi|flv|mpg|rm|mov|wav|asf|3gp|mkv|rmvb|ogg|mp4)/
|
||||
const audioExp = /\.(mp3|wav|MP3|WAV)/
|
||||
if (imgExp.test(fileName)) return 'image/*'
|
||||
if (videoExp.test(fileName)) return 'video/*'
|
||||
if (audioExp.test(fileName)) return 'audio/*'
|
||||
return false
|
||||
}
|
||||
|
||||
const uploadBefore = async (file, done, loading, column) => {
|
||||
let bool = false
|
||||
if (column.controlType == 'image') {
|
||||
if (column.accept == 'image/*' && verifyFileType(file.name) == column.accept) bool = true
|
||||
else if (column.accept) {
|
||||
const accept = column.accept instanceof Array ? column.accept : column.accept.split(',')
|
||||
if (accept.includes(file.type)) bool = true
|
||||
} else bool = true
|
||||
}
|
||||
if (column.controlType == 'file') {
|
||||
if (column.accept) {
|
||||
const nameList = file.name.split('.')
|
||||
const suffix = `.${nameList[nameList.length - 1]}`
|
||||
const accept = column.accept instanceof Array ? column.accept : column.accept.split(',')
|
||||
|
||||
accept.forEach(type => {
|
||||
if (['image/*', 'video/*', 'audio/*'].includes(type) && verifyFileType(file.name) == type) bool = true
|
||||
})
|
||||
if (accept.includes(suffix) || accept.includes(file.type)) bool = true
|
||||
} else bool = true
|
||||
}
|
||||
try {
|
||||
if (column.verify) {
|
||||
bool = await column.verify(file).then(() => true).catch(() => false)
|
||||
}
|
||||
} catch (error) { }
|
||||
if (!bool) {
|
||||
message.info(`请上传正确的${column.label}格式`)
|
||||
loading()
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (jsEnhanceObj?.value.beforeUpload) {
|
||||
const isUpload = await jsEnhanceObj.value.beforeUpload(file)
|
||||
if (!isUpload) {
|
||||
loading()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`'js增强【beforeUpload】方法执行异常,请检查'
|
||||
${error}`)
|
||||
}
|
||||
done()
|
||||
}
|
||||
|
||||
const uploadExceed = (limit, files, fileList, column) => {
|
||||
message.info(`${column.label} 最大可上传 ${limit}${column.controlType == 'image' ? '张' : '件'}`)
|
||||
}
|
||||
const uploadSized = (fileSize, files, fileList, column) => {
|
||||
fileSize = fileSizeFormatter(fileSize)
|
||||
message.info(`${column.label} 上传大小不可超过 ${fileSize}`)
|
||||
}
|
||||
const uploadPreview = (file, column, done) => {
|
||||
if (column.controlType == 'image') return done()
|
||||
const bool = verifyFileType(file.url)
|
||||
if (bool) done()
|
||||
else downloadByUrl({ url: file.url })
|
||||
}
|
||||
|
||||
return { uploadBefore, uploadExceed, uploadSized, uploadPreview }
|
||||
}
|
||||
28
src/hooks/design/useCopyText.ts
Normal file
28
src/hooks/design/useCopyText.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
export default function () {
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
const copy = async (text: string) => {
|
||||
if (navigator.clipboard) {
|
||||
const { copy, copied, isSupported } = useClipboard({ source: text })
|
||||
if (!isSupported) {
|
||||
message.error(t('common.copyError'))
|
||||
return
|
||||
}
|
||||
await copy()
|
||||
if (unref(copied)) {
|
||||
message.success(t('common.copySuccess'))
|
||||
}
|
||||
} else {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
message.success(t('common.copySuccess'));
|
||||
}
|
||||
}
|
||||
return { copyText: copy }
|
||||
}
|
||||
26
src/hooks/design/useCrudHeight.ts
Normal file
26
src/hooks/design/useCrudHeight.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
|
||||
export const useCrudHeight = (crudRef) => {
|
||||
const windowSize = useWindowSize()
|
||||
const crudHeightTimer = ref<any>(null)
|
||||
|
||||
const initTableLayout = () => {
|
||||
if (crudHeightTimer.value) clearTimeout(crudHeightTimer.value)
|
||||
crudHeightTimer.value = setTimeout(() => {
|
||||
if (crudRef instanceof Array) {
|
||||
crudRef.forEach(itemRef => {
|
||||
if (itemRef.value) itemRef.value.getTableHeight()
|
||||
})
|
||||
} else if (crudRef.value) crudRef.value.getTableHeight()
|
||||
}, 100)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => windowSize.height.value,
|
||||
() => {
|
||||
initTableLayout()
|
||||
}
|
||||
)
|
||||
|
||||
return { initTableLayout, windowSize }
|
||||
}
|
||||
24
src/hooks/design/useCrudPermi.ts
Normal file
24
src/hooks/design/useCrudPermi.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
|
||||
|
||||
export const useCrudPermi = () => {
|
||||
const { wsCache } = useCache()
|
||||
const all_permission = '*:*'
|
||||
const permissions = wsCache.get(CACHE_KEY.USER).permissions
|
||||
const crudBtnObj = {
|
||||
query: 'viewBtn',
|
||||
create: 'addBtn',
|
||||
update: 'editBtn',
|
||||
delete: 'delBtn',
|
||||
}
|
||||
|
||||
const getCurrPermi = (permiArr: string[]) => {
|
||||
const crudPermission = {}
|
||||
permiArr.forEach(permiKey => {
|
||||
for (const key in crudBtnObj) {
|
||||
crudPermission[crudBtnObj[key]] = permiKey === all_permission || permissions[`${permiKey}:${key}`]
|
||||
}
|
||||
})
|
||||
return crudPermission
|
||||
}
|
||||
return { getCurrPermi }
|
||||
}
|
||||
83
src/hooks/design/useDrageed.ts
Normal file
83
src/hooks/design/useDrageed.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
export default function () {
|
||||
const onMove = (e) => {
|
||||
const type = e.draggedContext.element.type
|
||||
const toClassName = e.to.className.split(' ')
|
||||
// console.log(type, toClassName)
|
||||
if (
|
||||
type == 'layoutGroup' &&
|
||||
['layout-group__body', 'layout-table__body'].includes(toClassName[0])
|
||||
) {
|
||||
//禁止 group 拖拽进 group\table
|
||||
return false
|
||||
}
|
||||
if (type == 'layoutTable' && ['layout-table__body'].includes(toClassName[0])) {
|
||||
//禁止 table 拖拽进 table
|
||||
return false
|
||||
}
|
||||
if (
|
||||
type == 'layoutTabs' &&
|
||||
['layout-tabs__body', 'layout-table__body', 'layout-grid__body'].includes(toClassName[0])
|
||||
) {
|
||||
//禁止 tabs 拖拽进 tabs/table/grid
|
||||
return false
|
||||
}
|
||||
if (type == 'layoutGrid' && ['layout-grid__body', 'layout-table__body'].includes(toClassName[0])) {
|
||||
//禁止 grid 拖拽进 grid/table
|
||||
return false
|
||||
}
|
||||
if (['layoutTabs', 'layoutGrid'].includes(type) && ['tabs-layout-group__body', 'grid-layout-group__body'].includes(toClassName[3])) {
|
||||
//禁止 tabs|grid 拖拽进 tabs内的group grid内的group
|
||||
return false
|
||||
}
|
||||
|
||||
if (type == 'comboBox' && ['layout-table__body'].includes(toClassName[0])) {
|
||||
//禁止 comboBox 拖拽进 table
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
['ueditor', 'buttonList', 'title'].includes(type) &&
|
||||
['layout-table__body'].includes(toClassName[0])
|
||||
) {
|
||||
//禁止 富文本、按钮组、文本 拖拽进 table
|
||||
return false
|
||||
}
|
||||
|
||||
// 限制组合框可拖拽控件
|
||||
if (['combo-box__body'].includes(toClassName[0])) {
|
||||
if (['input', 'select', 'date', 'time'].includes(e.draggedContext.element.controlType)) {
|
||||
if (['textarea', 'radio', 'checkbox', 'switch'].includes(type)) return false
|
||||
} else {
|
||||
if (!['buttonList'].includes(type)) return false
|
||||
}
|
||||
if (type == 'comboBox') return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const handleDragPosition = (newIndex, columnData) => {
|
||||
let isGroup = false
|
||||
if (columnData[newIndex]) isGroup = columnData[newIndex].type == 'layoutGroup'
|
||||
let repIndex: number | undefined = undefined
|
||||
columnData.forEach((item, index) => {
|
||||
if (repIndex === undefined && item.type == 'layoutGroup') {
|
||||
if (isGroup && index > newIndex) repIndex = index != 0 ? index - 1 : index
|
||||
else if (!isGroup && index <= newIndex) repIndex = index
|
||||
}
|
||||
})
|
||||
if (isGroup && repIndex !== newIndex) {
|
||||
const column = columnData.splice(newIndex, 1)
|
||||
if (repIndex === undefined) repIndex = columnData.length
|
||||
if (column[0]) columnData.splice(repIndex, 0, column[0])
|
||||
} else if (!isGroup && repIndex !== undefined && repIndex < newIndex) {
|
||||
const column = columnData.splice(newIndex, 1)
|
||||
if (column[0]) columnData.splice(repIndex, 0, column[0])
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
onMove,
|
||||
handleDragPosition
|
||||
}
|
||||
}
|
||||
128
src/hooks/design/useGroup.ts
Normal file
128
src/hooks/design/useGroup.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { listToTree, findNode, treeMap } from '@/utils/tree'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
export const useGroup = (treeRef, DataApi, resetChange, isView?, isOneLevel?) => {
|
||||
const message = useMessage() // 消息弹窗
|
||||
const treeForm = ref<any>({})
|
||||
const treeOption = ref({
|
||||
nodeKey: 'id',
|
||||
defaultExpandAll: true,
|
||||
filterText: '输入名称进行过滤',
|
||||
props: { label: 'name', value: 'id' },
|
||||
formOption: {
|
||||
labelWidth: 100,
|
||||
column: {
|
||||
pid: { label: '上级分组', type: 'tree', value: 0, disabled: isOneLevel, dicData: [], filterable: true, defaultExpandAll: true, props: { label: 'name', value: 'id' } },
|
||||
name: { label: '分组名称', rules: [{ required: true, message: '请输入 分组名称', trigger: "blur" }] }
|
||||
}
|
||||
}
|
||||
})
|
||||
if (isOneLevel) treeOption.value.formOption['filterParams'] = ['pid']
|
||||
const treeData = ref<any>([])
|
||||
const groupValue = ref<string | number>(0)
|
||||
const currMenuNodeData = ref<any>({})
|
||||
|
||||
if (isView) {
|
||||
treeOption.value['addBtn'] = false
|
||||
treeOption.value['editBtn'] = false
|
||||
treeOption.value['delBtn'] = false
|
||||
treeOption.value['menu'] = false
|
||||
}
|
||||
|
||||
const treePermission = (key, data) => {
|
||||
if (key != 'addBtn' && data.id === 0) return false
|
||||
return true
|
||||
}
|
||||
|
||||
const treeNodeContextmenu = (data) => {
|
||||
currMenuNodeData.value = data
|
||||
}
|
||||
|
||||
const treeBeforeOpen = (done, type) => {
|
||||
setTimeout(() => {
|
||||
const treeList = cloneDeep(treeData.value)
|
||||
if (type == 'edit') {
|
||||
const disabledArr = [treeForm.value.id]
|
||||
treeMap(treeList, {
|
||||
children: 'children',
|
||||
conversion: (item) => {
|
||||
if (item.id == disabledArr[0]) item.disabled = true
|
||||
if (disabledArr.includes(item.pid)) {
|
||||
item.disabled = true
|
||||
disabledArr.push(item.id)
|
||||
}
|
||||
return item
|
||||
}
|
||||
})
|
||||
treeForm.value.oldPid = treeForm.value.pid
|
||||
} else {
|
||||
treeForm.value.pid = currMenuNodeData.value.id
|
||||
}
|
||||
treeOption.value.formOption.column.pid.dicData = treeList
|
||||
if (isOneLevel) treeForm.value.pid = 0
|
||||
}, 30)
|
||||
done()
|
||||
}
|
||||
|
||||
const treeNodeClick = (data) => {
|
||||
if (data.id == groupValue.value) {
|
||||
treeRef.value.setCurrentKey(null)
|
||||
groupValue.value = ''
|
||||
} else groupValue.value = data.id
|
||||
resetChange()
|
||||
}
|
||||
|
||||
const getTreeData = async () => {
|
||||
const data = await DataApi.getGroupData({})
|
||||
treeData.value = [{ name: '全部', id: 0, children: listToTree(data) }]
|
||||
}
|
||||
|
||||
const treeUpdate = (node, data, done, loading) => {
|
||||
DataApi.updateGroupData(data)
|
||||
.then(() => {
|
||||
if (data.oldPid != data.pid) {
|
||||
const oldPNode = findNode(treeData.value, (node) => node.id == data.oldPid)
|
||||
oldPNode.children = oldPNode.children.filter((item) => item.id != data.id)
|
||||
const pNode = findNode(treeData.value, (node) => node.id == data.pid)
|
||||
delete data.oldPid
|
||||
if (pNode.children) pNode.children.push(data)
|
||||
else pNode.children = [data]
|
||||
}
|
||||
done()
|
||||
})
|
||||
.catch(() => loading())
|
||||
}
|
||||
const treeSave = async (node, data, done, loading) => {
|
||||
treeForm.value['children'] = []
|
||||
await DataApi.saveGroupData(data)
|
||||
.then((res) => {
|
||||
treeForm.value.id = res
|
||||
done()
|
||||
setTimeout(() => {
|
||||
if (treeData.value.length > 1) {
|
||||
const currData = treeData.value.splice(1, 1)
|
||||
const pNode = findNode(treeData.value, (node) => node.id == currData[0].pid)
|
||||
if (pNode) pNode.children.push(currData[0])
|
||||
}
|
||||
if (isOneLevel && treeData.value[0]?.children.length) {
|
||||
for (const index in treeData.value[0].children) {
|
||||
const child = treeData.value[0].children[index]
|
||||
if (child.children?.length) {
|
||||
const addData = cloneDeep(child.children[0])
|
||||
treeRef.value.updateKeyChildren(child.id, [])
|
||||
treeRef.value.updateKeyChildren(treeData.value[0].id, [...treeData.value[0].children, addData])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0)
|
||||
})
|
||||
.catch(() => loading())
|
||||
}
|
||||
const treeDel = async (node, done) => {
|
||||
await message.delConfirm()
|
||||
await DataApi.deleteGroupData([node.data.id])
|
||||
done()
|
||||
}
|
||||
|
||||
return { treeForm, treeOption, treeData, groupValue, treePermission, treeNodeContextmenu, treeBeforeOpen, treeNodeClick, getTreeData, treeUpdate, treeSave, treeDel }
|
||||
}
|
||||
57
src/hooks/design/useMEDialog.ts
Normal file
57
src/hooks/design/useMEDialog.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
export default function () {
|
||||
interface MEDialog {
|
||||
value: boolean
|
||||
title?: string
|
||||
params?: object
|
||||
otherParams?: object
|
||||
handleClose?: any
|
||||
}
|
||||
interface MEData {
|
||||
value: string
|
||||
language?: string
|
||||
editorOption?: object
|
||||
params?: object
|
||||
setFormValue?: (value: string) => void
|
||||
}
|
||||
|
||||
const MEDialog = ref<MEDialog>({ value: false })
|
||||
const MEData = ref<MEData>({ value: '' })
|
||||
const openMEDialog = (column, tableForm) => {
|
||||
const { prop, label, params } = column
|
||||
const dialogParams = {}
|
||||
const meParams = {}
|
||||
let otherParams = {}
|
||||
if (typeof params == 'object') {
|
||||
for (const key in params) {
|
||||
if (['title', 'width', 'controlType', 'fullscreen', 'headerBtn', 'footerBtn', 'dialogParams'].includes(key)) dialogParams[key] = params[key]
|
||||
else if (['language', 'editorOption', 'providerType', 'oldValue'].includes(key)) meParams[key] = params[key]
|
||||
if (key == 'otherParams') otherParams = params[key]
|
||||
}
|
||||
}
|
||||
dialogParams['handleClose'] = (done) => {
|
||||
if (MEData.value.setFormValue) MEData.value.setFormValue(MEData.value.value)
|
||||
if (params && params.handleClose) params.handleClose(done)
|
||||
else done()
|
||||
}
|
||||
MEDialog.value = {
|
||||
value: true,
|
||||
params: {
|
||||
destroyOnClose: true,
|
||||
title: label,
|
||||
...dialogParams,
|
||||
},
|
||||
otherParams: Object.keys(otherParams).length ? otherParams : false
|
||||
}
|
||||
MEData.value = {
|
||||
value: prop ? tableForm[prop] : tableForm || '',
|
||||
params: meParams,
|
||||
setFormValue: (value: string) => {
|
||||
if (tableForm && prop) tableForm[prop] = value
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
MEDialog, MEData, openMEDialog
|
||||
}
|
||||
}
|
||||
389
src/hooks/design/useMonacoEditor.ts
Normal file
389
src/hooks/design/useMonacoEditor.ts
Normal file
@@ -0,0 +1,389 @@
|
||||
// import * as monaco from 'monaco-editor'
|
||||
import { ref, nextTick, onBeforeUnmount } from 'vue'
|
||||
//语言
|
||||
// import 'monaco-editor/esm/vs/basic-languages/scss/scss.contribution';
|
||||
// import 'monaco-editor/esm/vs/basic-languages/java/java.contribution';
|
||||
// import * as MySql from 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js';
|
||||
// import * as JavaScript from 'monaco-editor/esm/vs/basic-languages/javascript/javascript.js';
|
||||
// import * as Java from 'monaco-editor/esm/vs/basic-languages/java/java.js';
|
||||
// 查找控件
|
||||
import 'monaco-editor/esm/vs/editor/contrib/find/browser/findController';
|
||||
import enhanceTip from '@/components/LowDesign/src/utils/enhanceTip';
|
||||
|
||||
import * as sqlFormatter from 'sql-formatter'
|
||||
|
||||
interface completions {
|
||||
label: string
|
||||
insertText: string
|
||||
detail?: string
|
||||
kind?: any
|
||||
sortText?: string
|
||||
}
|
||||
|
||||
let MySql: any = null
|
||||
let JavaScript: any = null
|
||||
let Java: any = null
|
||||
let monaco: any = null
|
||||
|
||||
const monacoProviderRef = ref<any>({})
|
||||
const providerType = ref('')
|
||||
let disposeArr: any[] = []
|
||||
|
||||
// 动态加载 monaco-editor 和相关语言包
|
||||
async function initMonaco() {
|
||||
if (!monaco) {
|
||||
monaco = await import('monaco-editor')
|
||||
MySql = await import('monaco-editor/esm/vs/basic-languages/mysql/mysql.js')
|
||||
JavaScript = await import('monaco-editor/esm/vs/basic-languages/javascript/javascript.js')
|
||||
Java = await import('monaco-editor/esm/vs/basic-languages/java/java.js')
|
||||
}
|
||||
return monaco
|
||||
}
|
||||
|
||||
//清除提示
|
||||
function clearProvider() {
|
||||
for (const key in monacoProviderRef.value) monacoProviderRef.value[key]?.dispose()
|
||||
}
|
||||
|
||||
function initLanguageProvider() {
|
||||
if (!monaco) return
|
||||
|
||||
clearProvider()
|
||||
const sqlProvider: any = {
|
||||
provideCompletionItems: (model, position) => {
|
||||
const suggestions: completions[] = []
|
||||
const { lineNumber, column } = position
|
||||
const textBeforePointer = model.getValueInRange({
|
||||
startLineNumber: lineNumber,
|
||||
startColumn: 0,
|
||||
endLineNumber: lineNumber,
|
||||
endColumn: column,
|
||||
})
|
||||
const contents = textBeforePointer.trim().split(/\s+/)
|
||||
const lastContents = contents[contents?.length - 1] // 获取最后一段非空字符串
|
||||
if (lastContents) {
|
||||
const sqlConfigKey = ['builtinFunctions', 'keywords', 'operators']
|
||||
sqlConfigKey.forEach(key => {
|
||||
MySql.language[key].forEach(sql => suggestions.push({ label: sql, insertText: sql, kind: monaco.languages.CompletionItemKind.Value }))
|
||||
})
|
||||
}
|
||||
return { suggestions }
|
||||
}
|
||||
}
|
||||
const javaProvider: any = {
|
||||
provideCompletionItems: (model, position) => {
|
||||
const suggestions: completions[] = []
|
||||
const { lineNumber, column } = position
|
||||
const textBeforePointer = model.getValueInRange({
|
||||
startLineNumber: lineNumber,
|
||||
startColumn: 0,
|
||||
endLineNumber: lineNumber,
|
||||
endColumn: column,
|
||||
})
|
||||
const contents = textBeforePointer.trim().split(/\s+/)
|
||||
const lastContents = contents[contents?.length - 1] // 获取最后一段非空字符串
|
||||
if (lastContents) {
|
||||
const javaConfigKey = ['keywords', 'operators']
|
||||
javaConfigKey.forEach(key => {
|
||||
Java.language[key].forEach(java => suggestions.push({ label: java, insertText: java, kind: monaco.languages.CompletionItemKind.Value }))
|
||||
})
|
||||
}
|
||||
return { suggestions }
|
||||
}
|
||||
}
|
||||
|
||||
let javaScriptDesign: any = []
|
||||
const { tipList, triggerObj } = enhanceTip[providerType.value] || {}
|
||||
if (tipList) javaScriptDesign = tipList
|
||||
const javaScriptProvider: any = {
|
||||
provideCompletionItems: (model, position) => {
|
||||
if (!providerType.value) return { suggestions: [] }
|
||||
const suggestions: completions[] = []
|
||||
const { lineNumber, column } = position
|
||||
const textBeforePointer = model.getValueInRange({
|
||||
startLineNumber: lineNumber,
|
||||
startColumn: 0,
|
||||
endLineNumber: lineNumber,
|
||||
endColumn: column,
|
||||
})
|
||||
const contents = textBeforePointer.trim().split(/\s+/)
|
||||
const lastContents = contents[contents?.length - 1] // 获取最后一段非空字符串
|
||||
const setTipFun = (bool) => {
|
||||
javaScriptDesign.forEach((javaScript) => {
|
||||
const item = { ...javaScript, sortText: bool ? '100' : '' }
|
||||
suggestions.push(item)
|
||||
})
|
||||
}
|
||||
let triggerKey = ''
|
||||
if (triggerObj && lastContents) {
|
||||
const lastLeng = lastContents.length
|
||||
for (const key in triggerObj) {
|
||||
if (triggerKey) break
|
||||
const findIndex = lastContents.lastIndexOf(key)
|
||||
if (findIndex != -1) {
|
||||
const keyLeng = key.length
|
||||
if (lastLeng - keyLeng == findIndex) triggerKey = key
|
||||
}
|
||||
}
|
||||
}
|
||||
if (triggerKey) {
|
||||
javaScriptDesign = triggerObj[triggerKey]
|
||||
setTipFun(true)
|
||||
return { incomplete: false, suggestions }
|
||||
}
|
||||
javaScriptDesign = tipList || []
|
||||
if (lastContents) {
|
||||
const javaScriptConfigKey = ['operators']
|
||||
javaScriptConfigKey.forEach(key => {
|
||||
JavaScript.language[key].forEach(javaScript => suggestions.push({ label: javaScript, insertText: javaScript }))
|
||||
})
|
||||
setTipFun(false)
|
||||
}
|
||||
return { incomplete: false, suggestions }
|
||||
},
|
||||
triggerCharacters: ['.'],
|
||||
}
|
||||
|
||||
monacoProviderRef.value.mysql = monaco.languages.registerCompletionItemProvider('mysql', sqlProvider);
|
||||
monacoProviderRef.value.java = monaco.languages.registerCompletionItemProvider('java', javaProvider);
|
||||
monacoProviderRef.value.javascript = monaco.languages.registerCompletionItemProvider('javascript', javaScriptProvider);
|
||||
}
|
||||
|
||||
function addMySqlFormat() {
|
||||
if (!monaco) return
|
||||
|
||||
const sqlFormatDisposable = monaco.editor.addEditorAction({
|
||||
id: 'format-sql',
|
||||
label: '格式化 SQL',
|
||||
contextMenuGroupId: 'navigation',
|
||||
contextMenuOrder: 1.5,
|
||||
run: (ed) => {
|
||||
const original = ed.getValue();
|
||||
const formatted = sqlFormatter.format(original, {
|
||||
language: 'mysql',
|
||||
params: ['#\\{[^}]+\\}']
|
||||
});
|
||||
ed.setValue(formatted)
|
||||
}
|
||||
})
|
||||
const list = [...(sqlFormatDisposable['_toDispose'] || [])]
|
||||
disposeArr.push(...list)
|
||||
}
|
||||
|
||||
function emptyDispose() {
|
||||
if (disposeArr.length) {
|
||||
disposeArr.forEach(item => item.dispose && item.dispose())
|
||||
disposeArr = []
|
||||
}
|
||||
}
|
||||
|
||||
export function useMonacoEditor(language: string = 'javascript') {
|
||||
// 编辑器示例
|
||||
let monacoEditor: any = null
|
||||
// 目标元素
|
||||
const monacoEditorRef = ref<HTMLElement | null>(null)
|
||||
|
||||
// 创建实例
|
||||
async function createEditor(editorOption: any = {}, type = '') {
|
||||
providerType.value = type
|
||||
|
||||
// 动态加载 monaco
|
||||
await initMonaco()
|
||||
|
||||
if (!monacoEditorRef.value) return
|
||||
initLanguageProvider()
|
||||
if (language) {
|
||||
monacoEditor = monaco.editor.create(monacoEditorRef.value, {
|
||||
// 初始模型
|
||||
model: monaco.editor.createModel('', language),
|
||||
|
||||
minimap: { enabled: true },
|
||||
// 圆角
|
||||
roundedSelection: true,
|
||||
// 主题
|
||||
theme: 'vs-dark',
|
||||
multiCursorModifier: 'ctrlCmd',
|
||||
// 滚动条
|
||||
scrollbar: {
|
||||
verticalScrollbarSize: 8,
|
||||
horizontalScrollbarSize: 8
|
||||
},
|
||||
// 行号
|
||||
lineNumbers: 'on',
|
||||
// tab大小
|
||||
tabSize: 2,
|
||||
//字体大小
|
||||
fontSize: 14,
|
||||
// 控制编辑器在用户键入、粘贴、移动或缩进行时是否应自动调整缩进
|
||||
autoIndent: 'advanced',
|
||||
autoClosingBrackets: 'always',//补全括号
|
||||
autoClosingQuotes: 'always', //补全冒号
|
||||
// 自动布局
|
||||
automaticLayout: true,
|
||||
fixedOverflowWidgets: true,
|
||||
...editorOption,
|
||||
})
|
||||
}
|
||||
return monacoEditor
|
||||
}
|
||||
|
||||
emptyDispose()
|
||||
if (language == 'mysql') addMySqlFormat()
|
||||
|
||||
// 格式化
|
||||
async function formatDoc() {
|
||||
await monacoEditor?.getAction('editor.action.formatDocument')?.run()
|
||||
}
|
||||
|
||||
// 数据更新
|
||||
function updateVal(val: string) {
|
||||
nextTick(() => {
|
||||
monacoEditor?.setValue(val)
|
||||
setTimeout(async () => {
|
||||
await formatDoc()
|
||||
}, 10)
|
||||
})
|
||||
}
|
||||
|
||||
// 配置更新
|
||||
async function updateOptions(opt: any, type = '') {
|
||||
// 确保 monaco 已加载
|
||||
await initMonaco()
|
||||
|
||||
providerType.value = type
|
||||
initLanguageProvider()
|
||||
monacoEditor?.updateOptions(opt)
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
function getOption(name: any) {
|
||||
return monacoEditor?.getOption(name)
|
||||
}
|
||||
|
||||
// 获取实例
|
||||
function getEditor() {
|
||||
return monacoEditor
|
||||
}
|
||||
|
||||
// 设置语言
|
||||
async function setLanguage(language: string, type = '') {
|
||||
// 确保 monaco 已加载
|
||||
await initMonaco()
|
||||
|
||||
providerType.value = type
|
||||
const text = monacoEditor?.getModel()?.getValue() || ''
|
||||
const model = monaco.editor.createModel(text, language)
|
||||
monacoEditor?.setModel(model)
|
||||
emptyDispose()
|
||||
if (language == 'mysql') addMySqlFormat()
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (monacoEditor) {
|
||||
clearProvider()
|
||||
emptyDispose()
|
||||
monacoEditor.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
monacoEditorRef,
|
||||
createEditor,
|
||||
getEditor,
|
||||
setLanguage,
|
||||
updateVal,
|
||||
updateOptions,
|
||||
getOption,
|
||||
formatDoc,
|
||||
}
|
||||
}
|
||||
|
||||
export function useDiffEditor(language: string = 'javascript', newValue: string, oldValue: string) {
|
||||
// 编辑器示例
|
||||
let diffEditor: any = null
|
||||
let originalModel: any = null
|
||||
let modifiedModel: any = null
|
||||
// 目标元素
|
||||
const deffEditorRef = ref<HTMLElement | null>(null)
|
||||
|
||||
// 创建实例
|
||||
async function createDeffEditor(editorOption: any = {}, type = '') {
|
||||
// 动态加载 monaco
|
||||
await initMonaco()
|
||||
|
||||
providerType.value = type
|
||||
if (!deffEditorRef.value) return
|
||||
initLanguageProvider()
|
||||
diffEditor = monaco.editor.createDiffEditor(deffEditorRef.value, {
|
||||
fontSize: 14, // 字体大小
|
||||
theme: 'vs-dark', //主题
|
||||
readOnly: false, // 是否只读
|
||||
overviewRulerBorder: false, // 滚动是否有边框
|
||||
cursorSmoothCaretAnimation: 'off', // 控制光标平滑动画的开启与关闭。当开启时,光标移动会有平滑的动画效果。
|
||||
mouseWheelZoom: true, //设置是否开启鼠标滚轮缩放功能
|
||||
folding: true, //控制是否开启代码折叠功能
|
||||
automaticLayout: true, // 控制编辑器是否自动调整布局以适应容器大小的变化
|
||||
// 是否启用预览图
|
||||
minimap: { enabled: true },
|
||||
// 滚动条
|
||||
scrollbar: {
|
||||
verticalScrollbarSize: 8,
|
||||
horizontalScrollbarSize: 8
|
||||
},
|
||||
wordWrap: "off", // 关闭自动换行
|
||||
scrollBeyondLastLine: false,
|
||||
roundedSelection: true, // 右侧不显示编辑器预览框
|
||||
originalEditable: false, // 是否允许修改原始文本
|
||||
...editorOption,
|
||||
})
|
||||
originalModel = monaco.editor.createModel(oldValue, language);
|
||||
modifiedModel = monaco.editor.createModel(newValue, language);
|
||||
diffEditor.setModel({ original: originalModel, modified: modifiedModel });
|
||||
return { diffEditor, originalModel, modifiedModel }
|
||||
}
|
||||
|
||||
//获取实例
|
||||
function getEditor(type: string) {
|
||||
if (type == 'diff') return diffEditor
|
||||
if (type == 'original') return originalModel
|
||||
if (type == 'modified') return modifiedModel
|
||||
}
|
||||
|
||||
// 格式化
|
||||
async function formatDoc() {
|
||||
await originalModel?.getAction('editor.action.formatDocument')?.run()
|
||||
await modifiedModel?.getAction('editor.action.formatDocument')?.run()
|
||||
}
|
||||
|
||||
// 数据更新
|
||||
function updateVal(val: string, type: string) {
|
||||
nextTick(() => {
|
||||
if (type == 'original') return originalModel?.setValue(val)
|
||||
if (type == 'modified') return modifiedModel?.setValue(val)
|
||||
setTimeout(async () => {
|
||||
await formatDoc()
|
||||
}, 10)
|
||||
})
|
||||
}
|
||||
|
||||
// 设置语言
|
||||
async function setLanguage(language: string, type = '') {
|
||||
// 确保 monaco 已加载
|
||||
await initMonaco()
|
||||
|
||||
providerType.value = type
|
||||
const originalText = originalModel?.getValue() || ''
|
||||
const modifiedText = modifiedModel?.getValue() || ''
|
||||
originalModel = monaco.editor.createModel(originalText, language)
|
||||
modifiedModel = monaco.editor.createModel(modifiedText, language)
|
||||
diffEditor?.setModel({ original: originalModel, modified: modifiedModel })
|
||||
}
|
||||
|
||||
return {
|
||||
deffEditorRef,
|
||||
createDeffEditor,
|
||||
getEditor,
|
||||
updateVal,
|
||||
setLanguage
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user