mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-04-30 13:48:47 +00:00
Compare commits
No commits in common. "master" and "v1.7.10" have entirely different histories.
37
CHANGELOG.md
37
CHANGELOG.md
@ -1,40 +1,3 @@
|
||||
## [1.7.13](https://github.com/Tencent/tmagic-editor/compare/v1.7.12...v1.7.13) (2026-04-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** getTransform 支持 string 类型并适配 hippy ([96801e2](https://github.com/Tencent/tmagic-editor/commit/96801e2ccba1fb400007e988aebbda7195e8ff15))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **editor:** update 支持 selectedAfterUpdate 参数控制是否更新 nodes ([26efa75](https://github.com/Tencent/tmagic-editor/commit/26efa75ff2cf03d4e27e3e77592d0304d343e44a))
|
||||
|
||||
|
||||
|
||||
## [1.7.12](https://github.com/Tencent/tmagic-editor/compare/v1.7.11...v1.7.12) (2026-04-24)
|
||||
|
||||
|
||||
|
||||
## [1.7.11](https://github.com/Tencent/tmagic-editor/compare/v1.7.10...v1.7.11) (2026-04-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **form:** group-list lastValues 为空时兼容取值报错 ([7249b51](https://github.com/Tencent/tmagic-editor/commit/7249b5106eee06a4e22cc325e83fac4e09e146ba))
|
||||
* **form:** table 全屏每次进入重新获取 z-index ([9ba12e9](https://github.com/Tencent/tmagic-editor/commit/9ba12e97afccbca6bafcacc1b5e79f4d7fed3341)), closes [#672](https://github.com/Tencent/tmagic-editor/issues/672)
|
||||
* **vue-runtime-help:** 删除所有页面后,新增页面出错 ([6a4a4ed](https://github.com/Tencent/tmagic-editor/commit/6a4a4ed122ce19ece81d816cb9b7dfb473dc351a)), closes [#668](https://github.com/Tencent/tmagic-editor/issues/668)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **editor:** 样式面板布局分组新增透明度配置 ([e106c08](https://github.com/Tencent/tmagic-editor/commit/e106c081c8fd6e0e8db9160605190e21ffccc1f7)), closes [#675](https://github.com/Tencent/tmagic-editor/issues/675)
|
||||
* **editor:** 没有参考线时不显示参考线切换按钮 ([b46b571](https://github.com/Tencent/tmagic-editor/commit/b46b5712142c85fc18533f68d52ae0958c2835e0))
|
||||
* **form:** group-list 支持 max 限制和 beforeAddRow 前置校验 ([ac755ac](https://github.com/Tencent/tmagic-editor/commit/ac755ac3d0328a2ca8e77d6f8b117b8b349e1bd0))
|
||||
* **table:** 支持列排序配置 ([4cd54d1](https://github.com/Tencent/tmagic-editor/commit/4cd54d13979da5189ecbd19ec732a4653a4f7d0a))
|
||||
|
||||
|
||||
|
||||
## [1.7.10](https://github.com/Tencent/tmagic-editor/compare/v1.7.9...v1.7.10) (2026-04-13)
|
||||
|
||||
|
||||
|
||||
@ -16,9 +16,9 @@ https://tencent.github.io/tmagic-editor/playground/index.html
|
||||
|
||||
## 环境准备
|
||||
|
||||
node.js ^20.19.0 || >=22.12.0
|
||||
node.js >= 18
|
||||
|
||||
pnpm >= 10
|
||||
pnpm >= 9
|
||||
|
||||
先安装 pnpm
|
||||
|
||||
|
||||
18
package.json
18
package.json
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "tmagic",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@ -44,8 +44,8 @@
|
||||
"@commitlint/config-conventional": "^20.0.0",
|
||||
"@tmagic/eslint-config": "workspace:*",
|
||||
"@types/node": "24.0.10",
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"@vitest/coverage-v8": "^4.1.5",
|
||||
"@vitejs/plugin-vue": "^6.0.5",
|
||||
"@vitest/coverage-v8": "^4.1.0",
|
||||
"@vue/compiler-sfc": "catalog:",
|
||||
"c8": "^10.1.3",
|
||||
"commitizen": "^4.3.1",
|
||||
@ -54,7 +54,7 @@
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"element-plus": "^2.11.8",
|
||||
"enquirer": "^2.4.1",
|
||||
"eslint": "^10.2.1",
|
||||
"eslint": "^10.0.3",
|
||||
"execa": "^9.6.0",
|
||||
"highlight.js": "^11.11.1",
|
||||
"husky": "^9.1.7",
|
||||
@ -62,12 +62,12 @@
|
||||
"lint-staged": "^16.2.7",
|
||||
"minimist": "^1.2.8",
|
||||
"picocolors": "^1.1.1",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier": "^3.8.1",
|
||||
"recast": "^0.23.11",
|
||||
"rimraf": "^3.0.2",
|
||||
"rolldown": "^1.0.0-rc.17",
|
||||
"rolldown-plugin-dts": "^0.23.2",
|
||||
"sass-embedded": "^1.99.0",
|
||||
"rolldown": "^1.0.0-rc.9",
|
||||
"rolldown-plugin-dts": "^0.22.5",
|
||||
"sass-embedded": "^1.93.3",
|
||||
"semver": "^7.7.3",
|
||||
"serialize-javascript": "^7.0.0",
|
||||
"shx": "^0.3.4",
|
||||
@ -76,7 +76,7 @@
|
||||
"vitepress": "^1.6.4",
|
||||
"vitest": "^4.1.0",
|
||||
"vue": "catalog:",
|
||||
"vue-tsc": "^3.2.7"
|
||||
"vue-tsc": "^3.2.6"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/cli",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/core",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -56,22 +56,8 @@ export const fillBackgroundImage = (value: string) => {
|
||||
return value;
|
||||
};
|
||||
|
||||
export const getTransform = (value: Record<string, string> | string, jsEngine: JsEngine) => {
|
||||
const isHippy = jsEngine === 'hippy';
|
||||
|
||||
if (!value) return isHippy ? [] : '';
|
||||
|
||||
if (typeof value === 'string') {
|
||||
if (!isHippy) return value;
|
||||
|
||||
// Hippy 不支持 css transform 字符串,需要将 "rotate(90deg) scale(1.5)" 解析成 [{ rotate: '90deg' }, { scale: '1.5' }]
|
||||
const transformArr: Record<string, string>[] = [];
|
||||
value.replace(/(\w+)\(([^)]+)\)/g, (_, key, val) => {
|
||||
transformArr.push({ [key]: val.trim() });
|
||||
return '';
|
||||
});
|
||||
return transformArr;
|
||||
}
|
||||
export const getTransform = (value: Record<string, string>, jsEngine: JsEngine) => {
|
||||
if (!value) return [];
|
||||
|
||||
const transform = Object.entries(value).map(([transformKey, transformValue]) => {
|
||||
if (!transformValue.trim()) return '';
|
||||
@ -79,14 +65,14 @@ export const getTransform = (value: Record<string, string> | string, jsEngine: J
|
||||
transformValue = `${transformValue}deg`;
|
||||
}
|
||||
|
||||
return isHippy ? { [transformKey]: transformValue } : `${transformKey}(${transformValue})`;
|
||||
return jsEngine !== 'hippy' ? `${transformKey}(${transformValue})` : { [transformKey]: transformValue };
|
||||
});
|
||||
|
||||
if (isHippy) {
|
||||
if (jsEngine === 'hippy') {
|
||||
return transform;
|
||||
}
|
||||
const values = transform.join(' ');
|
||||
return values.trim();
|
||||
return !values.trim() ? 'none' : values;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -116,11 +102,8 @@ export const transformStyle = (style: Record<string, any> | string, jsEngine: Js
|
||||
results.transform = [{ scale: value }];
|
||||
} else if (key === 'backgroundImage' && !isHippy) {
|
||||
value && (results[key] = fillBackgroundImage(value));
|
||||
} else if (key === 'transform') {
|
||||
const transform = getTransform(value, jsEngine);
|
||||
if (transform) {
|
||||
results[key] = transform;
|
||||
}
|
||||
} else if (key === 'transform' && typeof value !== 'string') {
|
||||
results[key] = getTransform(value, jsEngine);
|
||||
} else if (!whiteList.includes(key) && value && /^[-]?[0-9]*[.]?[0-9]*$/.test(value)) {
|
||||
results[key] = isHippy ? value : `${value / 100}rem`;
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/data-source",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/dep",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/design",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
|
||||
@ -342,7 +342,7 @@ export interface TableColumnOptions<T = any> {
|
||||
prop?: string;
|
||||
align?: string;
|
||||
headerAlign?: string;
|
||||
sortable?: boolean | string;
|
||||
sortable?: boolean;
|
||||
sortOrders?: Array<'ascending' | 'descending'>;
|
||||
selectable?: (row: T, index: number) => boolean;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/editor",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
|
||||
@ -67,7 +67,6 @@ const config = computed<GroupListConfig>(() => ({
|
||||
name: props.name,
|
||||
titlePrefix: props.config.titlePrefix,
|
||||
expandAll: true,
|
||||
enableToggleMode: false,
|
||||
items: [
|
||||
{
|
||||
type: 'table',
|
||||
|
||||
@ -59,12 +59,10 @@ export const useStage = (stageOptions: StageOptions) => {
|
||||
},
|
||||
);
|
||||
|
||||
const hGuidesCache = getGuideLineFromCache(getGuideLineKey(H_GUIDE_LINE_STORAGE_KEY));
|
||||
const vGuidesCache = getGuideLineFromCache(getGuideLineKey(V_GUIDE_LINE_STORAGE_KEY));
|
||||
|
||||
stage.mask?.setGuides([hGuidesCache, vGuidesCache]);
|
||||
|
||||
uiService.set('hasGuides', hGuidesCache.length > 0 || vGuidesCache.length > 0);
|
||||
stage.mask?.setGuides([
|
||||
getGuideLineFromCache(getGuideLineKey(H_GUIDE_LINE_STORAGE_KEY)),
|
||||
getGuideLineFromCache(getGuideLineKey(V_GUIDE_LINE_STORAGE_KEY)),
|
||||
]);
|
||||
|
||||
stage.on('page-el-update', () => {
|
||||
editorService.set('stageLoading', false);
|
||||
@ -126,11 +124,6 @@ export const useStage = (stageOptions: StageOptions) => {
|
||||
stage.on('change-guides', (e) => {
|
||||
uiService.set('showGuides', true);
|
||||
|
||||
uiService.set(
|
||||
'hasGuides',
|
||||
(stage.mask?.horizontalGuidelines.length ?? 0) > 0 || (stage.mask?.verticalGuidelines.length ?? 0) > 0,
|
||||
);
|
||||
|
||||
if (!root.value || !page.value) return;
|
||||
|
||||
const storageKey = getGuideLineKey(
|
||||
|
||||
@ -37,7 +37,6 @@ const columnWidth = computed(() => uiService.get('columnWidth'));
|
||||
const keys = Object.values(ColumnLayout);
|
||||
|
||||
const showGuides = computed((): boolean => uiService.get('showGuides'));
|
||||
const hasGuides = computed((): boolean => uiService.get('hasGuides'));
|
||||
const showRule = computed((): boolean => uiService.get('showRule'));
|
||||
const zoom = computed((): number => uiService.get('zoom'));
|
||||
|
||||
@ -144,7 +143,6 @@ const getConfig = (item: MenuItem): (MenuButton | MenuComponent)[] => {
|
||||
});
|
||||
break;
|
||||
case 'guides':
|
||||
if (!hasGuides.value) break;
|
||||
config.push({
|
||||
type: 'button',
|
||||
className: 'guides',
|
||||
|
||||
@ -509,10 +509,7 @@ class Editor extends BaseService {
|
||||
|
||||
public async doUpdate(
|
||||
config: MNode,
|
||||
{
|
||||
changeRecords = [],
|
||||
selectedAfterUpdate = true,
|
||||
}: { changeRecords?: ChangeRecord[]; selectedAfterUpdate?: boolean } = {},
|
||||
{ changeRecords = [] }: { changeRecords?: ChangeRecord[] } = {},
|
||||
): Promise<{ newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }> {
|
||||
const root = this.get('root');
|
||||
if (!root) throw new Error('root为空');
|
||||
@ -557,12 +554,10 @@ class Editor extends BaseService {
|
||||
parentNodeItems[index] = newConfig;
|
||||
|
||||
// 将update后的配置更新到nodes中
|
||||
if (selectedAfterUpdate) {
|
||||
const nodes = this.get('nodes');
|
||||
const targetIndex = nodes.findIndex((nodeItem: MNode) => `${nodeItem.id}` === `${newConfig.id}`);
|
||||
nodes.splice(targetIndex, 1, newConfig);
|
||||
this.set('nodes', [...nodes]);
|
||||
}
|
||||
const nodes = this.get('nodes');
|
||||
const targetIndex = nodes.findIndex((nodeItem: MNode) => `${nodeItem.id}` === `${newConfig.id}`);
|
||||
nodes.splice(targetIndex, 1, newConfig);
|
||||
this.set('nodes', [...nodes]);
|
||||
|
||||
if (isPage(newConfig) || isPageFragment(newConfig)) {
|
||||
this.set('page', newConfig as MPage | MPageFragment);
|
||||
@ -585,7 +580,7 @@ class Editor extends BaseService {
|
||||
*/
|
||||
public async update(
|
||||
config: MNode | MNode[],
|
||||
data: { changeRecords?: ChangeRecord[]; selectedAfterUpdate?: boolean } = {},
|
||||
data: { changeRecords?: ChangeRecord[] } = {},
|
||||
): Promise<MNode | MNode[]> {
|
||||
this.captureSelectionBeforeOp();
|
||||
|
||||
|
||||
@ -55,7 +55,6 @@ const state = shallowReactive<UiState>({
|
||||
DEFAULT_RIGHT_COLUMN_WIDTH,
|
||||
},
|
||||
showGuides: true,
|
||||
hasGuides: false,
|
||||
showRule: true,
|
||||
propsPanelSize: 'small',
|
||||
showAddPageButton: true,
|
||||
|
||||
@ -253,8 +253,6 @@ export interface UiState {
|
||||
columnWidth: GetColumnWidth;
|
||||
/** 是否显示画布参考线,true: 显示,false: 不显示,默认为true */
|
||||
showGuides: boolean;
|
||||
/** 画布上是否存在参考线 */
|
||||
hasGuides: boolean;
|
||||
/** 是否显示标尺,true: 显示,false: 不显示,默认为true */
|
||||
showRule: boolean;
|
||||
/** 用于控制该属性配置表单内组件的尺寸 */
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import type { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/core';
|
||||
import { type CascaderOption, type FormConfig, type TabConfig } from '@tmagic/form';
|
||||
import { type CascaderOption, defineFormItem, type FormConfig } from '@tmagic/form';
|
||||
import { dataSourceTemplateRegExp, getKeysArray, isNumber } from '@tmagic/utils';
|
||||
|
||||
import BaseFormConfig from './formConfigs/base';
|
||||
import HttpFormConfig from './formConfigs/http';
|
||||
|
||||
const dataSourceFormConfig: TabConfig = {
|
||||
const dataSourceFormConfig = defineFormItem({
|
||||
type: 'tab',
|
||||
items: [
|
||||
{
|
||||
@ -73,13 +73,9 @@ const dataSourceFormConfig: TabConfig = {
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
const fillConfig = <T = never>(config: FormConfig<T>): FormConfig<T> => [
|
||||
...BaseFormConfig(),
|
||||
...config,
|
||||
dataSourceFormConfig,
|
||||
];
|
||||
const fillConfig = (config: FormConfig): FormConfig => [...BaseFormConfig(), ...config, dataSourceFormConfig];
|
||||
|
||||
export const getFormConfig = (type: string, configs: Record<string, FormConfig>): FormConfig => {
|
||||
switch (type) {
|
||||
|
||||
@ -106,7 +106,6 @@ export const styleTabConfig: TabPaneConfig = {
|
||||
'borderWidth',
|
||||
'borderStyle',
|
||||
'borderColor',
|
||||
'opacity',
|
||||
],
|
||||
} as unknown as ChildConfig,
|
||||
{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/element-plus-adapter",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/form-schema",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -701,43 +701,28 @@ export interface PanelConfig<T = never> extends FormItem, ContainerCommonConfig<
|
||||
schematic?: string;
|
||||
}
|
||||
|
||||
export interface TableGroupListCommonConfig extends FormItem {
|
||||
type: 'table' | 'groupList' | 'group-list';
|
||||
enableToggleMode?: boolean;
|
||||
/** 最大行数 */
|
||||
max?: number;
|
||||
enum?: any[];
|
||||
/** 是否显示添加按钮 */
|
||||
addable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
|
||||
/** 新增的默认行,可以是函数动态生成或静态对象 */
|
||||
defaultAdd?: ((mForm: FormState | undefined, data: any) => any) | Record<string, any>;
|
||||
/** table 新增行时前置回调 */
|
||||
beforeAddRow?: (mForm: FormState | undefined, data: any) => boolean | Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface TableColumnConfig<T = never> extends FormItem {
|
||||
export interface TableColumnConfig extends FormItem {
|
||||
name?: string;
|
||||
label?: string;
|
||||
text?: string;
|
||||
label: string;
|
||||
width?: string | number;
|
||||
sortable?: boolean;
|
||||
items?: FormConfig<T>;
|
||||
itemsFunction?: (row: any) => FormConfig<T>;
|
||||
items?: FormConfig;
|
||||
itemsFunction?: (row: any) => FormConfig;
|
||||
titleTip?: FilterFunction<string>;
|
||||
type?: string;
|
||||
addButtonConfig?: {
|
||||
props?: Record<string, any>;
|
||||
text?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格容器
|
||||
*/
|
||||
export interface TableConfig<T = never> extends TableGroupListCommonConfig {
|
||||
items: TableColumnConfig<T>[];
|
||||
tableItems?: TableColumnConfig<T>[];
|
||||
groupItems?: TableColumnConfig<T>[];
|
||||
export interface TableConfig extends FormItem {
|
||||
type: 'table' | 'groupList' | 'group-list';
|
||||
items: TableColumnConfig[];
|
||||
tableItems?: TableColumnConfig[];
|
||||
groupItems?: TableColumnConfig[];
|
||||
enableToggleMode?: boolean;
|
||||
/** 最大行数 */
|
||||
max?: number;
|
||||
/** 最大高度 */
|
||||
maxHeight?: number | string;
|
||||
border?: boolean;
|
||||
@ -746,6 +731,9 @@ export interface TableConfig<T = never> extends TableGroupListCommonConfig {
|
||||
/** 操作栏宽度 */
|
||||
operateColWidth?: number | string;
|
||||
pagination?: boolean;
|
||||
enum?: any[];
|
||||
/** 是否显示添加按钮 */
|
||||
addable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
|
||||
/** 是否显示删除按钮 */
|
||||
delete?: (model: any, index: number, values: any) => boolean | boolean;
|
||||
copyable?: (model: any, data: any) => boolean | boolean;
|
||||
@ -753,6 +741,8 @@ export interface TableConfig<T = never> extends TableGroupListCommonConfig {
|
||||
importable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
|
||||
/** 是否显示checkbox */
|
||||
selection?: (mForm: FormState | undefined, data: any) => boolean | boolean | 'single';
|
||||
/** 新增的默认行,可以是函数动态生成或静态对象 */
|
||||
defaultAdd?: ((mForm: FormState | undefined, data: any) => any) | Record<string, any>;
|
||||
copyHandler?: (mForm: FormState | undefined, data: any) => any;
|
||||
onSelect?: (mForm: FormState | undefined, data: any) => any;
|
||||
/** @deprecated 请使用 defaultSort */
|
||||
@ -770,12 +760,20 @@ export interface TableConfig<T = never> extends TableGroupListCommonConfig {
|
||||
itemExtra?: string | FilterFunction<string>;
|
||||
titleTip?: FilterFunction<string>;
|
||||
rowKey?: string;
|
||||
/** table 新增行时前置回调 */
|
||||
beforeAddRow?: (mForm: FormState | undefined, data: any) => boolean;
|
||||
addButtonConfig?: {
|
||||
props?: Record<string, any>;
|
||||
text?: string;
|
||||
};
|
||||
sort?: boolean;
|
||||
sortKey?: string;
|
||||
}
|
||||
|
||||
export interface GroupListConfig<T = never> extends TableGroupListCommonConfig {
|
||||
export interface GroupListConfig<T = never> extends FormItem {
|
||||
type: 'table' | 'groupList' | 'group-list';
|
||||
span?: number;
|
||||
enableToggleMode?: boolean;
|
||||
items: FormConfig<T>;
|
||||
groupItems?: FormConfig<T>;
|
||||
tableItems?: FormConfig<T>;
|
||||
@ -790,6 +788,9 @@ export interface GroupListConfig<T = never> extends TableGroupListCommonConfig {
|
||||
* 当未设置时,默认展开第一项
|
||||
*/
|
||||
defaultExpandQuantity?: number;
|
||||
addable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
|
||||
/** 新增的默认值,可以是函数动态生成或静态对象 */
|
||||
defaultAdd?: ((mForm: FormState | undefined, data: any) => any) | Record<string, any>;
|
||||
delete?: (model: any, index: number | string | symbol, values: any) => boolean | boolean;
|
||||
copyable?: FilterFunction<boolean>;
|
||||
movable?: (
|
||||
@ -799,6 +800,10 @@ export interface GroupListConfig<T = never> extends TableGroupListCommonConfig {
|
||||
groupModel: any,
|
||||
) => boolean | boolean;
|
||||
moveSpecifyLocation?: boolean;
|
||||
addButtonConfig?: {
|
||||
props?: Record<string, any>;
|
||||
text?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface StepItemConfig<T = never> extends FormItem, ContainerCommonConfig<T> {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/form",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
v-for="(item, index) in model[name]"
|
||||
:key="index"
|
||||
:model="item"
|
||||
:lastValues="getLastValues(lastValues?.[name], Number(index))"
|
||||
:lastValues="getLastValues(lastValues[name], Number(index))"
|
||||
:is-compare="isCompare"
|
||||
:config="config"
|
||||
:prop="prop"
|
||||
@ -27,18 +27,33 @@
|
||||
></MFieldsGroupListItem>
|
||||
|
||||
<div class="m-fields-group-list-footer">
|
||||
<slot name="toggle-button"></slot>
|
||||
<TMagicButton v-if="config.enableToggleMode" :icon="Grid" size="small" @click="toggleMode"
|
||||
>切换为表格</TMagicButton
|
||||
>
|
||||
<div style="display: flex; justify-content: flex-end; flex: 1">
|
||||
<slot name="add-button"></slot>
|
||||
<TMagicButton
|
||||
v-if="addable"
|
||||
:size="config.enableToggleMode ? 'small' : 'default'"
|
||||
:icon="Plus"
|
||||
v-bind="config.addButtonConfig?.props || { type: 'primary' }"
|
||||
:disabled="disabled"
|
||||
@click="addHandler"
|
||||
>{{ config.addButtonConfig?.text || '新增' }}</TMagicButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, inject } from 'vue';
|
||||
import { Grid, Plus } from '@element-plus/icons-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import type { ContainerChangeEventData, GroupListConfig } from '../schema';
|
||||
import { TMagicButton } from '@tmagic/design';
|
||||
|
||||
import type { ContainerChangeEventData, FormState, GroupListConfig } from '../schema';
|
||||
import { initValue } from '../utils/form';
|
||||
|
||||
import MFieldsGroupListItem from './GroupListItem.vue';
|
||||
|
||||
@ -56,7 +71,6 @@ const props = defineProps<{
|
||||
prop?: string;
|
||||
size?: string;
|
||||
disabled?: boolean;
|
||||
showIndex?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -64,10 +78,60 @@ const emit = defineEmits<{
|
||||
addDiffCount: [];
|
||||
}>();
|
||||
|
||||
const mForm = inject<FormState | undefined>('mForm');
|
||||
|
||||
const addable = computed(() => {
|
||||
if (!props.name) return false;
|
||||
|
||||
if (typeof props.config.addable === 'function') {
|
||||
return props.config.addable(mForm, {
|
||||
model: props.model[props.name],
|
||||
formValue: mForm?.values,
|
||||
prop: props.prop,
|
||||
config: props.config,
|
||||
});
|
||||
}
|
||||
|
||||
return typeof props.config.addable === 'undefined' ? true : props.config.addable;
|
||||
});
|
||||
|
||||
const changeHandler = (v: any, eventData: ContainerChangeEventData) => {
|
||||
emit('change', props.model, eventData);
|
||||
};
|
||||
|
||||
const addHandler = async () => {
|
||||
if (!props.name) return false;
|
||||
|
||||
let initValues = {};
|
||||
|
||||
if (typeof props.config.defaultAdd === 'function') {
|
||||
initValues = await props.config.defaultAdd(mForm, {
|
||||
model: props.model[props.name],
|
||||
formValue: mForm?.values,
|
||||
prop: props.prop,
|
||||
config: props.config,
|
||||
});
|
||||
} else if (props.config.defaultAdd) {
|
||||
initValues = props.config.defaultAdd;
|
||||
}
|
||||
|
||||
const groupValue = await initValue(mForm, {
|
||||
config: props.config.items,
|
||||
initValues,
|
||||
});
|
||||
|
||||
props.model[props.name].push(groupValue);
|
||||
|
||||
emit('change', props.model[props.name], {
|
||||
changeRecords: [
|
||||
{
|
||||
propPath: `${props.prop}.${props.model[props.name].length - 1}`,
|
||||
value: groupValue,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const removeHandler = (index: number) => {
|
||||
if (!props.name) return false;
|
||||
|
||||
@ -89,6 +153,17 @@ const swapHandler = (idx1: number, idx2: number) => {
|
||||
emit('change', props.model[props.name]);
|
||||
};
|
||||
|
||||
const toggleMode = () => {
|
||||
props.config.type = 'table';
|
||||
props.config.groupItems = props.config.items;
|
||||
props.config.items = (props.config.tableItems ||
|
||||
props.config.items.map((item: any) => ({
|
||||
...item,
|
||||
label: item.label || item.text,
|
||||
text: null,
|
||||
}))) as any;
|
||||
};
|
||||
|
||||
const onAddDiffCount = () => emit('addDiffCount');
|
||||
|
||||
const getLastValues = (item: any, index: number) => item?.[index] || {};
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
<template>
|
||||
<component
|
||||
:is="displayMode === 'table' ? MFormTable : MFormGroupList"
|
||||
ref="tableGroupList"
|
||||
v-bind="$attrs"
|
||||
:model="model"
|
||||
:name="`${name}`"
|
||||
:config="currentConfig"
|
||||
:disabled="disabled"
|
||||
:size="size"
|
||||
:is-compare="isCompare"
|
||||
:last-values="lastValues"
|
||||
:prop="prop"
|
||||
:label-width="labelWidth"
|
||||
:show-index="showIndex"
|
||||
:sort-key="sortKey"
|
||||
:sort="sort"
|
||||
@change="onChange"
|
||||
@select="onSelect"
|
||||
@addDiffCount="onAddDiffCount"
|
||||
@add="onAdd"
|
||||
>
|
||||
<template #toggle-button>
|
||||
<TMagicButton
|
||||
v-if="config.enableToggleMode || enableToggleMode"
|
||||
:icon="Grid"
|
||||
size="small"
|
||||
@click="toggleDisplayMode"
|
||||
>
|
||||
{{ displayMode === 'table' ? '展开配置' : '切换为表格' }}
|
||||
</TMagicButton>
|
||||
</template>
|
||||
|
||||
<template #add-button v-if="addable">
|
||||
<TMagicButton
|
||||
:class="displayMode === 'table' ? 'm-form-table-add-button' : ''"
|
||||
:size="addButtonSize"
|
||||
:plain="displayMode === 'table'"
|
||||
:icon="Plus"
|
||||
:disabled="disabled"
|
||||
v-bind="currentConfig.addButtonConfig?.props || { type: 'primary' }"
|
||||
@click="newHandler"
|
||||
>
|
||||
{{ currentConfig.addButtonConfig?.text || (displayMode === 'table' ? '新增一行' : '新增') }}
|
||||
</TMagicButton>
|
||||
</template>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, useTemplateRef } from 'vue';
|
||||
import { Grid, Plus } from '@element-plus/icons-vue';
|
||||
|
||||
import { TMagicButton } from '@tmagic/design';
|
||||
import type { GroupListConfig, TableConfig } from '@tmagic/form-schema';
|
||||
|
||||
import type { ContainerChangeEventData } from '../../schema';
|
||||
import MFormGroupList from '../GroupList.vue';
|
||||
import MFormTable from '../table/Table.vue';
|
||||
|
||||
import { useAdd } from './useAdd';
|
||||
|
||||
defineOptions({
|
||||
name: 'MFormTableGroupList',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
model: any;
|
||||
lastValues?: any;
|
||||
isCompare?: boolean;
|
||||
config: TableConfig | GroupListConfig;
|
||||
name: string;
|
||||
prop?: string;
|
||||
labelWidth?: string;
|
||||
disabled?: boolean;
|
||||
size?: string;
|
||||
enableToggleMode?: true;
|
||||
showIndex?: boolean;
|
||||
sortKey?: string;
|
||||
sort?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['change', 'select', 'addDiffCount']);
|
||||
|
||||
const { addable, newHandler } = useAdd(props, emit);
|
||||
|
||||
const isGroupListType = (type: string | undefined) => type === 'groupList' || type === 'group-list';
|
||||
|
||||
const displayMode = ref<'table' | 'groupList'>(isGroupListType(props.config.type) ? 'groupList' : 'table');
|
||||
|
||||
const calcLabelWidth = (label: string) => {
|
||||
if (!label) return '0px';
|
||||
const zhLength = label.match(/[^\x00-\xff]/g)?.length || 0;
|
||||
const chLength = label.length - zhLength;
|
||||
return `${Math.max(chLength * 8 + zhLength * 20, 80)}px`;
|
||||
};
|
||||
|
||||
// 当原始 config 是 table 形态时,table 模式直接透传;
|
||||
// 若原始是 groupList,则基于它派生出 table 所需的 config
|
||||
const tableConfig = computed<TableConfig>(() => {
|
||||
if (!isGroupListType(props.config.type)) {
|
||||
return props.config as TableConfig;
|
||||
}
|
||||
|
||||
const source = props.config as GroupListConfig;
|
||||
return {
|
||||
...props.config,
|
||||
type: 'table',
|
||||
groupItems: source.items,
|
||||
items:
|
||||
source.tableItems ||
|
||||
(source.items as any[]).map((item: any) => ({
|
||||
...item,
|
||||
label: item.label || item.text,
|
||||
text: null,
|
||||
})),
|
||||
} as any as TableConfig;
|
||||
});
|
||||
|
||||
// 反向派生 groupList 所需的 config
|
||||
const groupListConfig = computed<GroupListConfig>(() => {
|
||||
if (isGroupListType(props.config.type)) {
|
||||
return props.config as GroupListConfig;
|
||||
}
|
||||
|
||||
const source = props.config as TableConfig;
|
||||
return {
|
||||
...props.config,
|
||||
type: 'groupList',
|
||||
tableItems: source.items,
|
||||
items:
|
||||
source.groupItems ||
|
||||
(source.items as any[]).map((item: any) => {
|
||||
const text = item.text || item.label;
|
||||
return {
|
||||
...item,
|
||||
text,
|
||||
labelWidth: calcLabelWidth(text),
|
||||
span: item.span || 12,
|
||||
};
|
||||
}),
|
||||
} as any as GroupListConfig;
|
||||
});
|
||||
|
||||
// 运行时类型由 displayMode 决定,`<component :is>` 无法做联合类型收窄,统一转 any 交给子组件处理
|
||||
const currentConfig = computed<any>(() => (displayMode.value === 'table' ? tableConfig.value : groupListConfig.value));
|
||||
|
||||
// 保持原 Table/GroupList 模式下新增按钮的不同尺寸策略
|
||||
const addButtonSize = computed(() => {
|
||||
if (displayMode.value === 'table') return 'small';
|
||||
return props.config.enableToggleMode !== false ? 'small' : 'default';
|
||||
});
|
||||
|
||||
const toggleDisplayMode = () => {
|
||||
displayMode.value = displayMode.value === 'table' ? 'groupList' : 'table';
|
||||
};
|
||||
|
||||
const onChange = (v: any, eventData?: ContainerChangeEventData) => emit('change', v, eventData);
|
||||
const onSelect = (...args: any[]) => emit('select', ...args);
|
||||
const onAddDiffCount = () => emit('addDiffCount');
|
||||
const onAdd = (rows: any[]) => {
|
||||
rows.forEach((row: any) => {
|
||||
newHandler(row);
|
||||
});
|
||||
};
|
||||
|
||||
const tableGroupListRef = useTemplateRef<InstanceType<typeof MFormTable>>('tableGroupList');
|
||||
|
||||
defineExpose({
|
||||
toggleRowSelection: (row: any, selected: boolean) => tableGroupListRef.value?.toggleRowSelection?.(row, selected),
|
||||
});
|
||||
</script>
|
||||
@ -1,31 +0,0 @@
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { useZIndex } from '@tmagic/design';
|
||||
|
||||
export const useFullscreen = () => {
|
||||
const { nextZIndex } = useZIndex();
|
||||
|
||||
const fullscreenZIndex = ref(nextZIndex());
|
||||
|
||||
const isFullscreen = ref(false);
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
if (isFullscreen.value) {
|
||||
isFullscreen.value = false;
|
||||
} else {
|
||||
isFullscreen.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
watch(isFullscreen, (value) => {
|
||||
if (value) {
|
||||
fullscreenZIndex.value = nextZIndex();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
isFullscreen,
|
||||
fullscreenZIndex,
|
||||
toggleFullscreen,
|
||||
};
|
||||
};
|
||||
@ -32,9 +32,8 @@ export { default as MFlexLayout } from './containers/FlexLayout.vue';
|
||||
export { default as MPanel } from './containers/Panel.vue';
|
||||
export { default as MRow } from './containers/Row.vue';
|
||||
export { default as MTabs } from './containers/Tabs.vue';
|
||||
export { default as MTable } from './containers/table-group-list/TableGroupList.vue';
|
||||
export { default as MGroupList } from './containers/table-group-list/TableGroupList.vue';
|
||||
export { default as MTableGroupList } from './containers/table-group-list/TableGroupList.vue';
|
||||
export { default as MTable } from './table/Table.vue';
|
||||
export { default as MGroupList } from './containers/GroupList.vue';
|
||||
export { default as MText } from './fields/Text.vue';
|
||||
export { default as MNumber } from './fields/Number.vue';
|
||||
export { default as MNumberRange } from './fields/NumberRange.vue';
|
||||
|
||||
@ -21,10 +21,10 @@ import { type App } from 'vue';
|
||||
import Container from './containers/Container.vue';
|
||||
import Fieldset from './containers/Fieldset.vue';
|
||||
import FlexLayout from './containers/FlexLayout.vue';
|
||||
import GroupList from './containers/GroupList.vue';
|
||||
import Panel from './containers/Panel.vue';
|
||||
import Row from './containers/Row.vue';
|
||||
import MStep from './containers/Step.vue';
|
||||
import TableGroupList from './containers/table-group-list/TableGroupList.vue';
|
||||
import Tabs from './containers/Tabs.vue';
|
||||
import Cascader from './fields/Cascader.vue';
|
||||
import Checkbox from './fields/Checkbox.vue';
|
||||
@ -46,6 +46,7 @@ import Text from './fields/Text.vue';
|
||||
import Textarea from './fields/Textarea.vue';
|
||||
import Time from './fields/Time.vue';
|
||||
import Timerange from './fields/Timerange.vue';
|
||||
import Table from './table/Table.vue';
|
||||
import { setConfig } from './utils/config';
|
||||
import Form from './Form.vue';
|
||||
import FormDialog from './FormDialog.vue';
|
||||
@ -69,11 +70,11 @@ export default {
|
||||
app.component('m-form-dialog', FormDialog);
|
||||
app.component('m-form-container', Container);
|
||||
app.component('m-form-fieldset', Fieldset);
|
||||
app.component('m-form-group-list', TableGroupList);
|
||||
app.component('m-form-group-list', GroupList);
|
||||
app.component('m-form-panel', Panel);
|
||||
app.component('m-form-row', Row);
|
||||
app.component('m-form-step', MStep);
|
||||
app.component('m-form-table', TableGroupList);
|
||||
app.component('m-form-table', Table);
|
||||
app.component('m-form-tab', Tabs);
|
||||
app.component('m-form-flex-layout', FlexLayout);
|
||||
app.component('m-fields-text', Text);
|
||||
|
||||
@ -38,7 +38,7 @@ import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import { TMagicButton, TMagicTooltip } from '@tmagic/design';
|
||||
|
||||
import type { FormState, TableConfig } from '../../schema';
|
||||
import type { FormState, TableConfig } from '../schema';
|
||||
|
||||
const emit = defineEmits(['change']);
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
v-bind="$attrs"
|
||||
class="m-fields-table-wrap"
|
||||
:class="{ fixed: isFullscreen }"
|
||||
:style="isFullscreen ? `z-index: ${fullscreenZIndex}` : ''"
|
||||
:style="isFullscreen ? `z-index: ${nextZIndex()}` : ''"
|
||||
>
|
||||
<div class="m-fields-table" :class="{ 'm-fields-table-item-extra': config.itemExtra }">
|
||||
<span v-if="config.extra" style="color: rgba(0, 0, 0, 0.45)" v-html="config.extra"></span>
|
||||
@ -34,7 +34,13 @@
|
||||
|
||||
<div style="display: flex; justify-content: space-between; margin: 10px 0">
|
||||
<div style="display: flex">
|
||||
<slot name="toggle-button" v-if="!isFullscreen"></slot>
|
||||
<TMagicButton
|
||||
:icon="Grid"
|
||||
size="small"
|
||||
@click="toggleMode"
|
||||
v-if="enableToggleMode && config.enableToggleMode !== false && !isFullscreen"
|
||||
>展开配置</TMagicButton
|
||||
>
|
||||
<TMagicButton
|
||||
:icon="FullScreen"
|
||||
size="small"
|
||||
@ -58,7 +64,17 @@
|
||||
>清空</TMagicButton
|
||||
>
|
||||
</div>
|
||||
<slot name="add-button"></slot>
|
||||
<TMagicButton
|
||||
v-if="addable"
|
||||
class="m-form-table-add-button"
|
||||
size="small"
|
||||
plain
|
||||
:icon="Plus"
|
||||
v-bind="config.addButtonConfig?.props || { type: 'primary' }"
|
||||
:disabled="disabled"
|
||||
@click="newHandler()"
|
||||
>{{ config.addButtonConfig?.text || '新增一行' }}</TMagicButton
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="bottom" style="text-align: right" v-if="config.pagination">
|
||||
@ -81,14 +97,15 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, useTemplateRef } from 'vue';
|
||||
import { FullScreen } from '@element-plus/icons-vue';
|
||||
import { FullScreen, Grid, Plus } from '@element-plus/icons-vue';
|
||||
|
||||
import { TMagicButton, TMagicPagination, TMagicTable, TMagicTooltip, TMagicUpload } from '@tmagic/design';
|
||||
import { TMagicButton, TMagicPagination, TMagicTable, TMagicTooltip, TMagicUpload, useZIndex } from '@tmagic/design';
|
||||
|
||||
import type { SortProp } from '../../schema';
|
||||
import { sortChange } from '../../utils/form';
|
||||
import type { SortProp } from '../schema';
|
||||
import { sortChange } from '../utils/form';
|
||||
|
||||
import type { TableProps } from './type';
|
||||
import { useAdd } from './useAdd';
|
||||
import { useFullscreen } from './useFullscreen';
|
||||
import { useImport } from './useImport';
|
||||
import { usePagination } from './usePagination';
|
||||
@ -103,12 +120,13 @@ defineOptions({
|
||||
const props = withDefaults(defineProps<TableProps>(), {
|
||||
prop: '',
|
||||
sortKey: '',
|
||||
enableToggleMode: true,
|
||||
showIndex: true,
|
||||
lastValues: () => ({}),
|
||||
isCompare: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['change', 'select', 'addDiffCount', 'add']);
|
||||
const emit = defineEmits(['change', 'select', 'addDiffCount']);
|
||||
|
||||
const modelName = computed(() => props.name || props.config.name || '');
|
||||
const tMagicTableRef = useTemplateRef<InstanceType<typeof TMagicTable>>('tMagicTable');
|
||||
@ -118,17 +136,44 @@ const { pageSize, currentPage, paginationData, handleSizeChange, handleCurrentCh
|
||||
modelName,
|
||||
);
|
||||
|
||||
const { nextZIndex } = useZIndex();
|
||||
const updateKey = ref(1);
|
||||
|
||||
const { addable, newHandler } = useAdd(props, emit);
|
||||
const { columns } = useTableColumns(props, emit, currentPage, pageSize, modelName);
|
||||
useSortable(props, emit, tMagicTableRef, modelName, updateKey);
|
||||
const { isFullscreen, fullscreenZIndex, toggleFullscreen } = useFullscreen();
|
||||
|
||||
const { importable, excelHandler, clearHandler } = useImport(props, emit);
|
||||
const { isFullscreen, toggleFullscreen } = useFullscreen();
|
||||
const { importable, excelHandler, clearHandler } = useImport(props, emit, newHandler);
|
||||
const { selectHandle, toggleRowSelection } = useSelection(props, emit, tMagicTableRef);
|
||||
|
||||
const data = computed(() => (props.config.pagination ? paginationData.value : props.model[modelName.value]));
|
||||
|
||||
const toggleMode = () => {
|
||||
const calcLabelWidth = (label: string) => {
|
||||
if (!label) return '0px';
|
||||
const zhLength = label.match(/[^\x00-\xff]/g)?.length || 0;
|
||||
const chLength = label.length - zhLength;
|
||||
return `${Math.max(chLength * 8 + zhLength * 20, 80)}px`;
|
||||
};
|
||||
|
||||
// 切换为groupList的形式
|
||||
props.config.type = 'groupList';
|
||||
props.config.enableToggleMode = true;
|
||||
props.config.tableItems = props.config.items;
|
||||
props.config.items =
|
||||
props.config.groupItems ||
|
||||
props.config.items.map((item: any) => {
|
||||
const text = item.text || item.label;
|
||||
const labelWidth = calcLabelWidth(text);
|
||||
return {
|
||||
...item,
|
||||
text,
|
||||
labelWidth,
|
||||
span: item.span || 12,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const sortChangeHandler = (sortOptions: SortProp) => {
|
||||
const modelName = props.name || props.config.name || '';
|
||||
sortChange(props.model[modelName], sortOptions);
|
||||
@ -13,5 +13,6 @@ export interface TableProps {
|
||||
sortKey?: string;
|
||||
text?: string;
|
||||
size?: string;
|
||||
enableToggleMode?: boolean;
|
||||
showIndex?: boolean;
|
||||
}
|
||||
@ -1,40 +1,30 @@
|
||||
import { computed, inject } from 'vue';
|
||||
|
||||
import { tMagicMessage } from '@tmagic/design';
|
||||
import type { FormConfig, FormState, TableConfig, TableGroupListCommonConfig } from '@tmagic/form-schema';
|
||||
import type { FormConfig, FormState } from '@tmagic/form-schema';
|
||||
|
||||
import { initValue } from '../../utils/form';
|
||||
import type { TableProps } from '../table/type';
|
||||
import { initValue } from '../utils/form';
|
||||
|
||||
import type { TableProps } from './type';
|
||||
|
||||
export const useAdd = (
|
||||
props: Pick<TableProps, 'name' | 'model' | 'prop' | 'sortKey'> & {
|
||||
config: Pick<TableGroupListCommonConfig, 'addable' | 'max' | 'beforeAddRow' | 'defaultAdd' | 'enum'> &
|
||||
Pick<TableConfig, 'key' | 'name'> & {
|
||||
items: { name?: string | number }[];
|
||||
};
|
||||
},
|
||||
emit: (event: 'change', ...args: any[]) => void,
|
||||
props: TableProps,
|
||||
emit: (event: 'select' | 'change' | 'addDiffCount', ...args: any[]) => void,
|
||||
) => {
|
||||
const mForm = inject<FormState | undefined>('mForm');
|
||||
|
||||
const addable = computed(() => {
|
||||
const modelName = props.name || props.config.name || '';
|
||||
|
||||
if (!modelName) return false;
|
||||
|
||||
if (!props.model[modelName].length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof props.config.addable === 'function') {
|
||||
return props.config.addable(mForm, {
|
||||
model: props.model[modelName],
|
||||
formValue: mForm?.values,
|
||||
prop: props.prop,
|
||||
config: props.config,
|
||||
});
|
||||
}
|
||||
|
||||
return typeof props.config.addable === 'undefined' ? true : props.config.addable;
|
||||
});
|
||||
|
||||
@ -47,7 +37,7 @@ export const useAdd = (
|
||||
}
|
||||
|
||||
if (typeof props.config.beforeAddRow === 'function') {
|
||||
const beforeCheckRes = await props.config.beforeAddRow(mForm, {
|
||||
const beforeCheckRes = props.config.beforeAddRow(mForm, {
|
||||
model: props.model[modelName],
|
||||
formValue: mForm?.values,
|
||||
prop: props.prop,
|
||||
18
packages/form/src/table/useFullscreen.ts
Normal file
18
packages/form/src/table/useFullscreen.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
export const useFullscreen = () => {
|
||||
const isFullscreen = ref(false);
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
if (isFullscreen.value) {
|
||||
isFullscreen.value = false;
|
||||
} else {
|
||||
isFullscreen.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isFullscreen,
|
||||
toggleFullscreen,
|
||||
};
|
||||
};
|
||||
@ -8,7 +8,8 @@ import type { TableProps } from './type';
|
||||
|
||||
export const useImport = (
|
||||
props: TableProps,
|
||||
emit: (event: 'select' | 'change' | 'addDiffCount' | 'add', ...args: any[]) => void,
|
||||
emit: (event: 'select' | 'change' | 'addDiffCount', ...args: any[]) => void,
|
||||
newHandler: (row: any) => void,
|
||||
) => {
|
||||
const mForm = inject<FormState | undefined>('mForm');
|
||||
const modelName = computed(() => props.name || props.config.name || '');
|
||||
@ -40,7 +41,9 @@ export const useImport = (
|
||||
pdata.SheetNames.forEach((sheetName: string) => {
|
||||
const arr = (globalThis as any).XLSX.utils.sheet_to_json(pdata.Sheets[sheetName], { header: 1 });
|
||||
if (arr?.[0]) {
|
||||
emit('add', arr);
|
||||
arr.forEach((row: any) => {
|
||||
newHandler(row);
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
excelBtn.value?.clearFiles();
|
||||
@ -1,6 +1,6 @@
|
||||
import { computed, type Ref, ref } from 'vue';
|
||||
|
||||
import { getDataByPage } from '../../utils/form';
|
||||
import { getDataByPage } from '../utils/form';
|
||||
|
||||
import type { TableProps } from './type';
|
||||
|
||||
@ -4,7 +4,7 @@ import type { default as SortableType, SortableEvent } from 'sortablejs';
|
||||
import { type TMagicTable } from '@tmagic/design';
|
||||
import type { FormState } from '@tmagic/form-schema';
|
||||
|
||||
import { sortArray } from '../../utils/form';
|
||||
import { sortArray } from '../utils/form';
|
||||
|
||||
import type { TableProps } from './type';
|
||||
|
||||
@ -5,9 +5,9 @@ import { cloneDeep } from 'lodash-es';
|
||||
import { type TableColumnOptions, TMagicIcon, TMagicTooltip } from '@tmagic/design';
|
||||
import type { FormItemConfig, FormState, TableColumnConfig } from '@tmagic/form-schema';
|
||||
|
||||
import type { ContainerChangeEventData } from '../../schema';
|
||||
import { display as displayFunc, getDataByPage, sortArray } from '../../utils/form';
|
||||
import Container from '../Container.vue';
|
||||
import Container from '../containers/Container.vue';
|
||||
import type { ContainerChangeEventData } from '../schema';
|
||||
import { display as displayFunc, getDataByPage, sortArray } from '../utils/form';
|
||||
|
||||
import ActionsColumn from './ActionsColumn.vue';
|
||||
import SortColumn from './SortColumn.vue';
|
||||
@ -187,7 +187,7 @@ export const useTableColumns = (
|
||||
columns.push({
|
||||
props: {
|
||||
prop: column.name,
|
||||
label: column.label || column.text,
|
||||
label: column.label,
|
||||
width: column.width,
|
||||
sortable: column.sortable,
|
||||
sortOrders: ['ascending', 'descending'],
|
||||
@ -223,10 +223,7 @@ export const useTableColumns = (
|
||||
gap: '5px',
|
||||
},
|
||||
},
|
||||
[
|
||||
h('span', column.label || column.text),
|
||||
h(TMagicIcon, {}, { default: () => h(WarningFilled) }),
|
||||
],
|
||||
[h('span', column.label), h(TMagicIcon, {}, { default: () => h(WarningFilled) })],
|
||||
),
|
||||
content: () =>
|
||||
h('div', {
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/schema",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/stage",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/table",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
|
||||
@ -139,7 +139,6 @@ const tableColumns = computed(() =>
|
||||
prop: item.prop,
|
||||
type,
|
||||
selectable: item.selectable,
|
||||
sortable: item.sortable,
|
||||
},
|
||||
cell: type === 'selection' ? undefined : ({ row, $index }: any) => cellRender(item, { row, $index }),
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/tdesign-vue-next-adapter",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"name": "@tmagic/utils",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tmagic-playground",
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@ -12,11 +12,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@tmagic/core": "1.7.13",
|
||||
"@tmagic/design": "1.7.13",
|
||||
"@tmagic/editor": "1.7.13",
|
||||
"@tmagic/element-plus-adapter": "1.7.13",
|
||||
"@tmagic/tdesign-vue-next-adapter": "1.7.13",
|
||||
"@tmagic/core": "1.7.10",
|
||||
"@tmagic/design": "1.7.10",
|
||||
"@tmagic/editor": "1.7.10",
|
||||
"@tmagic/element-plus-adapter": "1.7.10",
|
||||
"@tmagic/tdesign-vue-next-adapter": "1.7.10",
|
||||
"@tmagic/tmagic-form-runtime": "1.1.3",
|
||||
"element-plus": "^2.11.8",
|
||||
"lodash-es": "^4.17.21",
|
||||
@ -30,8 +30,8 @@
|
||||
"@types/lodash-es": "^4.17.4",
|
||||
"@types/node": "^24.0.10",
|
||||
"@types/serialize-javascript": "^5.0.4",
|
||||
"@vitejs/plugin-legacy": "^8.0.1",
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"@vitejs/plugin-legacy": "^8.0.0",
|
||||
"@vitejs/plugin-vue": "^6.0.5",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
||||
"@vue/compiler-sfc": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
|
||||
1941
pnpm-lock.yaml
generated
1941
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,14 @@
|
||||
packages:
|
||||
- "packages/*"
|
||||
- "playground"
|
||||
- "runtime/*"
|
||||
- "vue-components/*"
|
||||
- "react-components/*"
|
||||
- "eslint-config"
|
||||
- 'packages/*'
|
||||
- 'playground'
|
||||
- 'runtime/*'
|
||||
- 'vue-components/*'
|
||||
- 'react-components/*'
|
||||
- 'eslint-config'
|
||||
|
||||
catalog:
|
||||
vue: ^3.5.33
|
||||
"@vue/compiler-sfc": ^3.5.33
|
||||
vite: ^8.0.10
|
||||
typescript: "^6.0.3"
|
||||
vue: ^3.5.24
|
||||
'@vue/compiler-sfc': ^3.5.24
|
||||
vite: ^8.0.3
|
||||
typescript: "^6.0.2"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "runtime-react",
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"engines": {
|
||||
@ -16,16 +16,16 @@
|
||||
"build:playground": "node scripts/build.mjs --type=playground"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/core": "1.7.13",
|
||||
"@tmagic/core": "1.7.10",
|
||||
"@tmagic/react-runtime-help": "0.2.2",
|
||||
"@tmagic/stage": "1.7.13",
|
||||
"@tmagic/stage": "1.7.10",
|
||||
"axios": "^1.13.2",
|
||||
"qrcode": "^1.5.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tmagic/cli": "1.7.13",
|
||||
"@tmagic/cli": "1.7.10",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.1",
|
||||
"name": "@tmagic/vue-runtime-help",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { computed, inject, nextTick, reactive, ref, watch } from 'vue';
|
||||
|
||||
import type TMagicApp from '@tmagic/core';
|
||||
import type { Id, MApp, MNode, MPage, MPageFragment } from '@tmagic/core';
|
||||
import { asyncLoadCss, getElById, getNodePath, replaceChildNode } from '@tmagic/core';
|
||||
import type { Magic, RemoveData, Runtime, UpdateData } from '@tmagic/stage';
|
||||
import type { Id, MApp, MNode } from '@tmagic/core';
|
||||
import { getElById, getNodePath, replaceChildNode } from '@tmagic/core';
|
||||
import type { Magic, RemoveData, UpdateData } from '@tmagic/stage';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -11,22 +11,7 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
let styleEl: HTMLStyleElement | null = null;
|
||||
|
||||
const createCss = async (config: MPage | MPageFragment) => {
|
||||
if (config.cssFile) {
|
||||
await asyncLoadCss(config.cssFile, window.document);
|
||||
}
|
||||
if (config.css) {
|
||||
if (!styleEl) {
|
||||
styleEl = window.document.createElement('style');
|
||||
window.document.head.appendChild(styleEl);
|
||||
}
|
||||
styleEl.innerHTML = config.css;
|
||||
}
|
||||
};
|
||||
|
||||
export const useEditorDsl = (app = inject<TMagicApp>('app'), runtimeApi: Runtime = {}, win = window) => {
|
||||
export const useEditorDsl = (app = inject<TMagicApp>('app'), win = window) => {
|
||||
const root = ref<MApp>();
|
||||
const curPageId = ref<Id>();
|
||||
const selectedId = ref<Id>();
|
||||
@ -35,37 +20,31 @@ export const useEditorDsl = (app = inject<TMagicApp>('app'), runtimeApi: Runtime
|
||||
() => root.value?.items?.find((item: MNode) => item.id === curPageId.value) || root.value?.items?.[0],
|
||||
);
|
||||
|
||||
watch(pageConfig, (config) => {
|
||||
if (!config) return;
|
||||
|
||||
setTimeout(() => {
|
||||
const page =
|
||||
document.querySelector<HTMLElement>('.magic-ui-page') ||
|
||||
document.querySelector<HTMLElement>('.magic-ui-page-fragment');
|
||||
page && win.magic?.onPageElUpdate(page);
|
||||
});
|
||||
|
||||
createCss(config);
|
||||
watch(pageConfig, async () => {
|
||||
await nextTick();
|
||||
const page =
|
||||
document.querySelector<HTMLElement>('.magic-ui-page') ||
|
||||
document.querySelector<HTMLElement>('.magic-ui-page-fragment');
|
||||
page && win.magic?.onPageElUpdate(page);
|
||||
});
|
||||
|
||||
const updateRoot = (config: MApp) => {
|
||||
root.value = config;
|
||||
if (typeof curPageId.value === 'undefined') {
|
||||
curPageId.value = config.items?.[0]?.id;
|
||||
}
|
||||
win.magic?.onRuntimeReady({
|
||||
getApp() {
|
||||
return app;
|
||||
},
|
||||
|
||||
if (typeof selectedId.value === 'undefined') {
|
||||
selectedId.value = curPageId.value;
|
||||
}
|
||||
updateRootConfig(config: MApp) {
|
||||
root.value = config;
|
||||
|
||||
app?.setConfig(config, curPageId.value);
|
||||
};
|
||||
if (typeof curPageId.value === 'undefined') {
|
||||
curPageId.value = config.items?.[0]?.id;
|
||||
}
|
||||
|
||||
window.magic?.onRuntimeReady({
|
||||
getApp: () => app,
|
||||
if (typeof selectedId.value === 'undefined') {
|
||||
selectedId.value = curPageId.value;
|
||||
}
|
||||
|
||||
updateRootConfig: (config: MApp) => {
|
||||
updateRoot(config);
|
||||
app?.setConfig(config, curPageId.value);
|
||||
},
|
||||
|
||||
updatePageId(id: Id) {
|
||||
@ -86,14 +65,8 @@ export const useEditorDsl = (app = inject<TMagicApp>('app'), runtimeApi: Runtime
|
||||
return nextTick().then(() => getElById()(document, `${id}`));
|
||||
},
|
||||
|
||||
add: ({ config, parentId, root: appConfig }: UpdateData) => {
|
||||
if (!root.value) {
|
||||
if (appConfig) {
|
||||
updateRoot(appConfig);
|
||||
return;
|
||||
}
|
||||
throw new Error('error');
|
||||
}
|
||||
add({ config, parentId }: UpdateData) {
|
||||
if (!root.value) throw new Error('error');
|
||||
if (!selectedId.value) throw new Error('error');
|
||||
if (!parentId) throw new Error('error');
|
||||
|
||||
@ -114,15 +87,13 @@ export const useEditorDsl = (app = inject<TMagicApp>('app'), runtimeApi: Runtime
|
||||
}
|
||||
},
|
||||
|
||||
update: ({ config, parentId, root: appConfig }: UpdateData) => {
|
||||
if (!root.value) {
|
||||
if (appConfig) {
|
||||
updateRoot(appConfig);
|
||||
return;
|
||||
}
|
||||
throw new Error('error');
|
||||
update({ config, parentId }: UpdateData) {
|
||||
if (!root.value || !app) throw new Error('error');
|
||||
|
||||
if (config.type === 'app') {
|
||||
this.updateRootConfig?.(config as MApp);
|
||||
return;
|
||||
}
|
||||
if (!app) throw new Error('error');
|
||||
|
||||
const newNode = app.dataSourceManager?.compiledNode(config, undefined, true) || config;
|
||||
|
||||
@ -138,7 +109,7 @@ export const useEditorDsl = (app = inject<TMagicApp>('app'), runtimeApi: Runtime
|
||||
}
|
||||
},
|
||||
|
||||
remove: ({ id, parentId }: RemoveData) => {
|
||||
remove({ id, parentId }: RemoveData) {
|
||||
if (!root.value) throw new Error('error');
|
||||
|
||||
const node = getNodePath(id, [root.value]).pop();
|
||||
@ -156,12 +127,9 @@ export const useEditorDsl = (app = inject<TMagicApp>('app'), runtimeApi: Runtime
|
||||
const index = parent.items?.findIndex((child: MNode) => child.id === node.id);
|
||||
parent.items.splice(index, 1);
|
||||
},
|
||||
|
||||
...runtimeApi,
|
||||
});
|
||||
|
||||
return {
|
||||
root,
|
||||
pageConfig,
|
||||
app,
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "runtime-vue",
|
||||
"version": "1.7.13",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"engines": {
|
||||
@ -16,18 +16,18 @@
|
||||
"build:playground": "node scripts/build.mjs --type=playground"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/core": "1.7.13",
|
||||
"@tmagic/stage": "1.7.13",
|
||||
"@tmagic/vue-runtime-help": "^2.0.1",
|
||||
"@tmagic/core": "1.7.10",
|
||||
"@tmagic/stage": "1.7.10",
|
||||
"@tmagic/vue-runtime-help": "^2.0.0",
|
||||
"axios": "^1.13.2",
|
||||
"vue": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tmagic/cli": "1.7.13",
|
||||
"@tmagic/cli": "1.7.10",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/node": "^24.0.10",
|
||||
"@vitejs/plugin-legacy": "^8.0.1",
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"@vitejs/plugin-legacy": "^8.0.0",
|
||||
"@vitejs/plugin-vue": "^6.0.5",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
||||
"@vue/compiler-sfc": "catalog:",
|
||||
"fs-extra": "^11.3.1",
|
||||
|
||||
@ -20,10 +20,9 @@ if (args.package) {
|
||||
const pkgRoot = path.resolve(packagesDir, args.package);
|
||||
if (fs.statSync(pkgRoot).isDirectory()) {
|
||||
rimraf.sync(path.resolve(packagesDir, `./${args.package}/dist`));
|
||||
const pkg = createRequire(import.meta.url)(`../packages/${args.package}/package.json`);
|
||||
|
||||
build({ packageName: args.package, format: 'es', pkg, packagesDir });
|
||||
build({ packageName: args.package, format: 'umd', pkg, packagesDir });
|
||||
build({ packageName: args.package, format: 'es' });
|
||||
build({ packageName: args.package, format: 'umd' });
|
||||
}
|
||||
} else {
|
||||
const packages = getPackageNames(packagesDir);
|
||||
@ -46,30 +45,6 @@ if (args.package) {
|
||||
}
|
||||
}
|
||||
|
||||
// rolldown 在 UMD 输出顶部会注入
|
||||
// Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
||||
// 当内联的依赖(如 lodash-es 的 _Symbol.js)声明 `var Symbol = root.Symbol;`
|
||||
// 时,由于 var hoisting,该局部 `Symbol` 会把上面一行引用到的全局 `Symbol`
|
||||
// 遮蔽掉(此时局部变量还未赋值),运行时抛出
|
||||
// TypeError: Cannot read properties of undefined (reading 'toStringTag')
|
||||
// 这里通过后处理把该引用改为 `globalThis.Symbol.toStringTag`,绕开被 hoist
|
||||
// 的局部绑定。rolldown 修好前先用此 workaround。
|
||||
function fixUmdSymbolShadow() {
|
||||
return {
|
||||
name: 'tmagic:fix-umd-symbol-shadow',
|
||||
generateBundle(outputOptions, bundle) {
|
||||
if (outputOptions.format !== 'umd') return;
|
||||
for (const file of Object.values(bundle)) {
|
||||
if (file.type !== 'chunk' || typeof file.code !== 'string') continue;
|
||||
file.code = file.code.replace(
|
||||
/Object\.defineProperty\(exports,\s*Symbol\.toStringTag,/g,
|
||||
'Object.defineProperty(exports, globalThis.Symbol.toStringTag,',
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function build({ packageName, format, pkg, packagesDir }) {
|
||||
await buildVite({
|
||||
root: path.resolve(packagesDir, `./${packageName}`),
|
||||
@ -94,7 +69,6 @@ async function build({ packageName, format, pkg, packagesDir }) {
|
||||
},
|
||||
|
||||
rolldownOptions: {
|
||||
plugins: [fixUmdSymbolShadow()],
|
||||
// 确保外部化处理那些你不想打包进库的依赖
|
||||
external(id) {
|
||||
if (format === 'umd' && id === 'lodash-es') {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user