feat: 批量动态表单业务组件&卡片组件&代码编辑器组件&其他组件调整
This commit is contained in:
parent
dfea1f83f9
commit
9dc0ca96f8
|
@ -7,6 +7,7 @@ import configArcoStyleImportPlugin from './plugin/arcoStyleImport';
|
|||
import configArcoResolverPlugin from './plugin/arcoResolver';
|
||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
|
||||
import vueSetupExtend from 'vite-plugin-vue-setup-extend';
|
||||
import monacoEditorPlugin from 'vite-plugin-monaco-editor';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
|
@ -22,6 +23,7 @@ export default defineConfig({
|
|||
// 指定symbolId格式
|
||||
symbolId: 'icon-[name]',
|
||||
}),
|
||||
monacoEditorPlugin({}),
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
<template>
|
||||
<a-form ref="formRef" :model="form" layout="vertical">
|
||||
<div class="mb-[16px] overflow-y-auto rounded-[4px] bg-[var(--color-fill-1)] p-[12px]">
|
||||
<a-scrollbar class="overflow-y-auto" :style="{ 'max-height': props.maxHeight }">
|
||||
<div class="flex flex-wrap items-start justify-between gap-[8px]">
|
||||
<template v-for="(order, i) of form.list" :key="`form-item-${order}`">
|
||||
<div class="flex w-full items-start justify-between gap-[8px]">
|
||||
<a-form-item
|
||||
v-for="item of props.models"
|
||||
:key="`${item.filed}${order}`"
|
||||
:field="`${item.filed}${order}`"
|
||||
:class="i > 0 ? 'hidden-item' : 'mb-0 flex-1'"
|
||||
:label="i === 0 && item.label ? t(item.label) : ''"
|
||||
:rules="item.rules"
|
||||
asterisk-position="end"
|
||||
>
|
||||
<a-input
|
||||
v-if="item.type === 'input'"
|
||||
v-model="form[`${item.filed}${order}`]"
|
||||
class="mb-[4px] flex-1"
|
||||
:placeholder="t(item.placeholder || '')"
|
||||
:max-length="item.maxLength || 250"
|
||||
allow-clear
|
||||
/>
|
||||
<a-input-number
|
||||
v-if="item.type === 'inputNumber'"
|
||||
v-model="form[`${item.filed}${order}`]"
|
||||
class="mb-[4px] flex-1"
|
||||
:placeholder="t(item.placeholder || '')"
|
||||
:min="item.min"
|
||||
:max="item.max || 9999999"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<div
|
||||
v-show="form.list.length > 1"
|
||||
:class="[
|
||||
'flex',
|
||||
'h-full',
|
||||
'w-[32px]',
|
||||
'cursor-pointer',
|
||||
'items-center',
|
||||
'justify-center',
|
||||
'text-[var(--color-text-brand)]',
|
||||
i === 0 ? 'mt-[36px]' : 'mt-[5px]',
|
||||
]"
|
||||
@click="removeField(order, i)"
|
||||
>
|
||||
<icon-minus-circle />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</a-scrollbar>
|
||||
<div v-if="props.formMode === 'create'" class="w-full">
|
||||
<a-button class="px-0" type="text" @click="addField">
|
||||
<template #icon>
|
||||
<icon-plus class="text-[14px]" />
|
||||
</template>
|
||||
{{ t(props.addText) }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watchEffect } from 'vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import type { ValidatedError, FormInstance } from '@arco-design/web-vue';
|
||||
import type { FormItemModel, FormMode, ValueType } from './types';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
models: FormItemModel[];
|
||||
formMode: FormMode;
|
||||
addText: string;
|
||||
maxHeight?: string;
|
||||
valueType?: ValueType;
|
||||
delimiter?: string; // 当valueType为 string 类型时的分隔符,默认为英文逗号,
|
||||
defaultVals?: Record<string, string | string[] | number[]>; // 当外层是编辑状态时,可传入已填充的数据
|
||||
}>(),
|
||||
{
|
||||
valueType: 'Array',
|
||||
delimiter: ',',
|
||||
maxHeight: '30vh',
|
||||
}
|
||||
);
|
||||
|
||||
const defaultForm = {
|
||||
list: [0],
|
||||
};
|
||||
const form = ref<Record<string, any>>({ ...defaultForm });
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
|
||||
/**
|
||||
* 监测defaultVals和models的变化
|
||||
* 初始化时通过models创建初始化表单
|
||||
* 若defaultVals变化,则说明当前是填充模式,将清空之前的表单项,填充传入的数据(一般是表单编辑的时候)
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props.models.forEach((e) => {
|
||||
form.value[`${e.filed}0`] = e.type === 'inputNumber' ? null : '';
|
||||
});
|
||||
if (props.defaultVals) {
|
||||
// 重置表单,因为组件初始化后可能输入过值或创建过表单项
|
||||
form.value = { list: [0] };
|
||||
// 取出defaultVals的表单 filed
|
||||
const arr = Object.keys(props.defaultVals);
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const filed = arr[i];
|
||||
// 取出当前 filed 的默认值
|
||||
const dVals = props.defaultVals[filed];
|
||||
// 判断默认值为数组还是字符串,字符串需要根据传入的分隔符delimiter分割
|
||||
const vals = Array.isArray(dVals) ? dVals : dVals.split(`${props.delimiter}`);
|
||||
// 遍历当前 filed 的默认值数组,填充至表单对象
|
||||
vals.forEach((val, order) => {
|
||||
form.value[`${filed}${order}`] = val;
|
||||
if (i === 0 && order > 0) {
|
||||
// 行数只需要遍历一次字段的值数组长度即可
|
||||
form.value.list.push(order);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function getFormResult() {
|
||||
const res: Record<string, any> = {};
|
||||
props.models.forEach((e) => {
|
||||
res[e.filed] = [];
|
||||
});
|
||||
form.value.list.forEach((e: number) => {
|
||||
props.models.forEach((m) => {
|
||||
res[m.filed].push(form.value[`${m.filed}${e}`]);
|
||||
});
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发表单校验
|
||||
* @param cb 校验通过后执行回调
|
||||
* @param isSubmit 是否需要将表单值拼接后传入回调函数
|
||||
*/
|
||||
function formValidate(cb: (res?: Record<string, string[] | string>) => void, isSubmit = true) {
|
||||
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||
if (errors) {
|
||||
return;
|
||||
}
|
||||
if (typeof cb === 'function') {
|
||||
if (isSubmit) {
|
||||
const res = getFormResult();
|
||||
cb(props.valueType === 'Array' ? res : res.join(','));
|
||||
return;
|
||||
}
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加表单项
|
||||
*/
|
||||
function addField() {
|
||||
formValidate(() => {
|
||||
const lastIndex = form.value.list.length - 1;
|
||||
const lastOrder = form.value.list[lastIndex] + 1;
|
||||
form.value.list.push(lastOrder); // 序号自增,不会因为删除而重复
|
||||
props.models.forEach((e) => {
|
||||
form.value[`${e.filed}${lastOrder}`] = e.type === 'inputNumber' ? null : '';
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除表单项
|
||||
* @param index 表单项的序号
|
||||
* @param i 表单项对应 list 的下标
|
||||
*/
|
||||
function removeField(index: number, i: number) {
|
||||
props.models.forEach((e) => {
|
||||
delete form.value[`${e.filed}${index}`];
|
||||
});
|
||||
form.value.list.splice(i, 1);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
formValidate,
|
||||
getFormResult,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -0,0 +1,36 @@
|
|||
import { FieldRule } from '@arco-design/web-vue';
|
||||
|
||||
export type FormItemType = 'input' | 'select' | 'inputNumber';
|
||||
export type FormMode = 'create' | 'edit';
|
||||
export type ValueType = 'Array' | 'string';
|
||||
|
||||
export interface FormItemModel {
|
||||
filed: string;
|
||||
type: FormItemType;
|
||||
rules?: FieldRule[];
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
maxLength?: number;
|
||||
}
|
||||
|
||||
declare const _default: import('vue').DefineComponent<
|
||||
{
|
||||
models: FormItemModel[];
|
||||
formMode: FormMode;
|
||||
addText: string;
|
||||
maxHeight?: string;
|
||||
valueType?: ValueType;
|
||||
delimiter?: string; // 当valueType为 string 类型时的分隔符,默认为英文逗号,
|
||||
defaultVals?: Record<string, string[] | string>; // 当外层是编辑状态时,可传入已填充的数据
|
||||
},
|
||||
unknown,
|
||||
import('vue').ComponentOptionsMixin,
|
||||
import('vue').ComponentOptionsMixin,
|
||||
{
|
||||
formValidate: (cb: (res?: Record<string, string[] | string>) => void, isSubmit = true) => void;
|
||||
}
|
||||
>;
|
||||
|
||||
export declare type MsBatchFormInstance = InstanceType<typeof _default>;
|
|
@ -4,19 +4,24 @@
|
|||
<div class="back-btn" @click="back"><icon-arrow-left /></div>
|
||||
<div class="text-[var(--color-text-000)]">{{ props.title }}</div>
|
||||
</div>
|
||||
<a-divider />
|
||||
<a-scrollbar class="mt-[16px]" style="overflow-y: auto; height: calc(100vh - 264px)">
|
||||
<a-divider class="my-[16px]" />
|
||||
<a-scrollbar class="mt-[16px]" style="overflow-y: auto; height: calc(100vh - 256px)">
|
||||
<slot></slot>
|
||||
</a-scrollbar>
|
||||
<div
|
||||
v-if="!hideFooter"
|
||||
class="m-[0_-24px_-24px] flex justify-end gap-[16px] p-[24px] shadow-[0_-1px_4px_rgba(2,2,2,0.1)]"
|
||||
class="relative z-10 m-[0_-24px_-24px] flex justify-end gap-[16px] p-[24px] shadow-[0_-1px_4px_rgba(2,2,2,0.1)]"
|
||||
>
|
||||
<a-button type="secondary" @click="back">{{ t('mscard.defaultCancelText') }}</a-button>
|
||||
<a-button v-if="!props.hideContinue" type="secondary" @click="emit('saveAndContinue')">
|
||||
{{ t('mscard.defaultSaveAndContinueText') }}
|
||||
</a-button>
|
||||
<a-button type="primary" @click="emit('save')">{{ t('mscard.defaultConfirm') }}</a-button>
|
||||
<div class="ml-0 mr-auto">
|
||||
<slot name="footerLeft"></slot>
|
||||
</div>
|
||||
<slot name="footerRight">
|
||||
<a-button type="secondary" @click="back">{{ t('mscard.defaultCancelText') }}</a-button>
|
||||
<a-button v-if="!props.hideContinue" type="secondary" @click="emit('saveAndContinue')">
|
||||
{{ t('mscard.defaultSaveAndContinueText') }}
|
||||
</a-button>
|
||||
<a-button type="primary" @click="emit('save')">{{ t('mscard.defaultConfirm') }}</a-button>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -64,7 +69,6 @@
|
|||
background: linear-gradient(90deg, rgb(var(--primary-9)) 3.36%, #ffffff 100%);
|
||||
box-shadow: 0 0 7px rgb(15 0 78 / 9%);
|
||||
.arco-icon {
|
||||
font-size: 20px !important;
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
<template>
|
||||
<div ref="fullRef" class="rounded-[4px] bg-[var(--color-fill-1)] p-[12px]">
|
||||
<div class="mb-[12px] flex justify-between pr-[12px]">
|
||||
<slot name="title">
|
||||
<span class="font-medium">{{ title }}</span>
|
||||
</slot>
|
||||
<div class="w-[96px] cursor-pointer text-right !text-[var(--color-text-4)]" @click="toggle">
|
||||
<MsIcon v-if="isFullscreen" type="icon-icon_minify_outlined" />
|
||||
<MsIcon v-else type="icon-icon_magnify_outlined" />
|
||||
{{ t('msCodeEditor.fullScreen') }}
|
||||
</div>
|
||||
</div>
|
||||
<div ref="codeEditBox" :class="['ms-code-editor', isFullscreen ? 'ms-code-editor-full-screen' : '']"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { editorProps, CustomeTheme } from './types';
|
||||
import './userWorker';
|
||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import MsCodeEditorTheme from './themes';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MonacoEditor',
|
||||
props: editorProps,
|
||||
emits: ['update:modelValue', 'change', 'editorMounted'],
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n();
|
||||
let editor: monaco.editor.IStandaloneCodeEditor;
|
||||
const codeEditBox = ref();
|
||||
const fullRef = ref<HTMLElement | null>();
|
||||
|
||||
const init = () => {
|
||||
// 注册自定义主题
|
||||
if (MsCodeEditorTheme[props.theme as CustomeTheme]) {
|
||||
monaco.editor.defineTheme(props.theme, MsCodeEditorTheme[props.theme as CustomeTheme]);
|
||||
}
|
||||
editor = monaco.editor.create(codeEditBox.value, {
|
||||
value: props.modelValue,
|
||||
automaticLayout: true,
|
||||
...props,
|
||||
});
|
||||
|
||||
// 监听值的变化
|
||||
editor.onDidBlurEditorText(() => {
|
||||
const value = editor.getValue(); // 给父组件实时返回最新文本
|
||||
emit('update:modelValue', value);
|
||||
emit('change', value);
|
||||
});
|
||||
|
||||
emit('editorMounted', editor);
|
||||
};
|
||||
|
||||
const setEditBoxBg = () => {
|
||||
const codeBgEl = document.querySelector('.monaco-editor-background');
|
||||
if (codeBgEl) {
|
||||
// 获取计算后的样式对象
|
||||
const computedStyle = window.getComputedStyle(codeBgEl);
|
||||
|
||||
// 获取背景颜色
|
||||
const { backgroundColor } = computedStyle;
|
||||
codeEditBox.value.style.backgroundColor = backgroundColor;
|
||||
}
|
||||
};
|
||||
|
||||
const { isFullscreen, toggle } = useFullscreen(fullRef);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (editor) {
|
||||
const value = editor.getValue();
|
||||
if (newValue !== value) {
|
||||
editor.setValue(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.options,
|
||||
(newValue) => {
|
||||
editor.updateOptions(newValue);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// watch(
|
||||
// () => props.language,
|
||||
// (newValue) => {
|
||||
// monaco.editor.setModelLanguage(editor.getModel()!, newValue);
|
||||
// }
|
||||
// );
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
editor.dispose();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
setEditBoxBg();
|
||||
});
|
||||
|
||||
return { codeEditBox, fullRef, isFullscreen, toggle, t };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ms-code-editor {
|
||||
@apply z-10;
|
||||
|
||||
padding: 16px 0;
|
||||
width: v-bind(width);
|
||||
height: v-bind(height);
|
||||
&[data-mode-id='plaintext'] {
|
||||
:deep(.mtk1) {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
}
|
||||
.ms-code-editor-full-screen {
|
||||
height: calc(100vh - 66px);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
'msCodeEditor.fullScreen': 'FullScreen',
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
'msCodeEditor.fullScreen': '全屏',
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
import { rgbToHex } from '@/utils';
|
||||
import { primaryVars } from '@/hooks/useThemeVars';
|
||||
|
||||
export default {
|
||||
base: 'vs',
|
||||
inherit: false,
|
||||
rules: [],
|
||||
colors: {
|
||||
'editorLineNumber.foreground': rgbToHex(primaryVars.P2),
|
||||
'editorLineNumber.activeForeground': rgbToHex(primaryVars.P4),
|
||||
'editorCursor.background': rgbToHex(primaryVars.P5),
|
||||
'editorCursor.foreground': rgbToHex(primaryVars.P5),
|
||||
'editor.wordHighlightBackground': rgbToHex(primaryVars.P1),
|
||||
'editor.selectionBackground': rgbToHex(primaryVars.P2),
|
||||
'editor.lineHighlightBorder': rgbToHex(primaryVars.P1),
|
||||
'editor.lineHighlightBackground': rgbToHex(primaryVars.P1),
|
||||
'editor.rangeHighlightBackground': rgbToHex(primaryVars.P1),
|
||||
'editor.findMatchBackground': rgbToHex(primaryVars.P2),
|
||||
'editor.findMatchHighlightBackground': rgbToHex(primaryVars.P9),
|
||||
'editor.findRangeHighlightBackground': rgbToHex(primaryVars.P5),
|
||||
'scrollbarSlider.activeBackground': rgbToHex(primaryVars.P4),
|
||||
'scrollbarSlider.background': rgbToHex(primaryVars.P2),
|
||||
'scrollbarSlider.hoverBackground': rgbToHex(primaryVars.P3),
|
||||
'scrollbar.shadow': rgbToHex(primaryVars.P2),
|
||||
},
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import MSText from './MS-text';
|
||||
|
||||
import type { CustomeTheme } from '../types';
|
||||
|
||||
const MsCodeEditorThemes: Record<CustomeTheme, any> = {
|
||||
'MS-text': MSText,
|
||||
};
|
||||
|
||||
export default MsCodeEditorThemes;
|
|
@ -0,0 +1,82 @@
|
|||
import { PropType } from 'vue';
|
||||
|
||||
export type CustomeTheme = 'MS-text';
|
||||
export type Theme = 'vs' | 'hc-black' | 'vs-dark' | CustomeTheme;
|
||||
export type FoldingStrategy = 'auto' | 'indentation';
|
||||
export type RenderLineHighlight = 'all' | 'line' | 'none' | 'gutter';
|
||||
export type Language =
|
||||
| 'plaintext'
|
||||
| 'javascript'
|
||||
| 'typescript'
|
||||
| 'css'
|
||||
| 'less'
|
||||
| 'sass'
|
||||
| 'html'
|
||||
| 'sql'
|
||||
| 'json'
|
||||
| 'java'
|
||||
| 'python'
|
||||
| 'xml'
|
||||
| 'yaml'
|
||||
| 'shell';
|
||||
export interface Options {
|
||||
automaticLayout: boolean; // 自适应布局
|
||||
foldingStrategy: FoldingStrategy; // 折叠方式 auto | indentation
|
||||
renderLineHighlight: RenderLineHighlight; // 行亮
|
||||
selectOnLineNumbers: boolean; // 显示行号
|
||||
minimap: {
|
||||
// 关闭小地图
|
||||
enabled: boolean;
|
||||
};
|
||||
readOnly: boolean; // 只读
|
||||
fontSize: number; // 字体大小
|
||||
scrollBeyondLastLine: boolean; // 取消代码后面一大段空白
|
||||
overviewRulerBorder: boolean; // 不要滚动条的边框
|
||||
}
|
||||
|
||||
export const editorProps = {
|
||||
modelValue: {
|
||||
type: String as PropType<string>,
|
||||
default: null,
|
||||
},
|
||||
width: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: '50vh',
|
||||
},
|
||||
language: {
|
||||
type: String as PropType<Language>,
|
||||
default: 'plaintext',
|
||||
},
|
||||
theme: {
|
||||
type: String as PropType<Theme>,
|
||||
validator(value: string): boolean {
|
||||
return ['vs', 'hc-black', 'vs-dark', 'MS-text'].includes(value);
|
||||
},
|
||||
default: 'vs-dark',
|
||||
},
|
||||
options: {
|
||||
type: Object as PropType<Options>,
|
||||
default() {
|
||||
return {
|
||||
automaticLayout: true,
|
||||
foldingStrategy: 'indentation',
|
||||
renderLineHighlight: 'all',
|
||||
selectOnLineNumbers: true,
|
||||
minimap: {
|
||||
enabled: true,
|
||||
},
|
||||
readOnly: false,
|
||||
fontSize: 16,
|
||||
scrollBeyondLastLine: false,
|
||||
overviewRulerBorder: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
title: {
|
||||
type: String as PropType<string>,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
import * as monaco from 'monaco-editor';
|
||||
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
|
||||
// import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
|
||||
// import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
|
||||
// import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
|
||||
// import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
|
||||
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
self.MonacoEnvironment = {
|
||||
async getWorker(_: any, label: string) {
|
||||
if (label === 'json') {
|
||||
const JsonWorker = ((await import('monaco-editor/esm/vs/language/json/json.worker?worker')) as any).default;
|
||||
return new JsonWorker();
|
||||
}
|
||||
if (label === 'css' || label === 'scss' || label === 'less') {
|
||||
const CssWorker = ((await import('monaco-editor/esm/vs/language/css/css.worker?worker')) as any).default;
|
||||
return new CssWorker();
|
||||
}
|
||||
if (label === 'html' || label === 'handlebars' || label === 'razor') {
|
||||
const HtmlWorker = ((await import('monaco-editor/esm/vs/language/html/html.worker?worker')) as any).default;
|
||||
return new HtmlWorker();
|
||||
}
|
||||
if (label === 'typescript' || label === 'javascript') {
|
||||
const TsWorker = ((await import('monaco-editor/esm/vs/language/typescript/ts.worker?worker')) as any).default;
|
||||
|
||||
return new TsWorker();
|
||||
}
|
||||
return new EditorWorker();
|
||||
},
|
||||
};
|
||||
|
||||
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);
|
|
@ -18,21 +18,24 @@
|
|||
</slot>
|
||||
</template>
|
||||
<slot>
|
||||
<MsDescription :descriptions="props.descriptions"></MsDescription>
|
||||
<MsDescription v-if="props.descriptions?.length > 0" :descriptions="props.descriptions"></MsDescription>
|
||||
</slot>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import MsDescription, { Description } from '@/components/pure/ms-description/index.vue';
|
||||
import { ref, watch, defineAsyncComponent } from 'vue';
|
||||
import type { Description } from '@/components/pure/ms-description/index.vue';
|
||||
|
||||
// 懒加载描述组件
|
||||
const MsDescription = defineAsyncComponent(() => import('@/components/pure/ms-description/index.vue'));
|
||||
|
||||
interface DrawerProps {
|
||||
visible: boolean;
|
||||
title: string | undefined;
|
||||
titleTag?: string;
|
||||
titleTagColor?: string;
|
||||
descriptions: Description[];
|
||||
descriptions?: Description[];
|
||||
footer?: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
@ -75,8 +78,6 @@
|
|||
}
|
||||
}
|
||||
.arco-drawer-footer {
|
||||
@apply text-left;
|
||||
|
||||
border-bottom: 1px solid var(--color-text-n8);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
<template>
|
||||
<icon-font
|
||||
:type="props.type"
|
||||
:size="props.size || 14"
|
||||
:class="props.color ? `text-[${props.color}]` : 'text-[var(--color-text-4)]'"
|
||||
/>
|
||||
<icon-font :type="props.type" :size="props.size || 14" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
@ -15,7 +11,6 @@
|
|||
size?: string | number;
|
||||
rotate?: number;
|
||||
spin?: boolean;
|
||||
color?: string;
|
||||
}>();
|
||||
|
||||
const IconFont = Icon.addFromIconFontCn({
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
type UploadProps = Partial<{
|
||||
mainText: string;
|
||||
subText: string;
|
||||
class: string;
|
||||
multiple: boolean;
|
||||
limit: number;
|
||||
imagePreview: boolean;
|
||||
showFileList: boolean;
|
||||
[key: string]: any;
|
||||
}> & {
|
||||
accept: UploadType;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue