---初始化后台管理web页面项目

This commit is contained in:
2025-08-20 14:39:30 +08:00
parent ad49711a7e
commit 87545a8baf
2057 changed files with 282864 additions and 213 deletions

View File

@ -0,0 +1,406 @@
import { LocationType } from '/@/enums/desktop';
import { DesktopInfoItem } from '/@/model/mobileDesign/designer';
/**
* 构建app数据设计页代码
* @param model
* @param _tableInfo
* @returns
*/
export function buildAppDataCode(model: Array<DesktopInfoItem>): string {
const compMap: any[] = [];
let importCode = '';
let configCode = '';
let code = `<template>
<view class="data-display">
`;
if (model.length) {
model.forEach((o, i) => {
const key = o.type;
if (!compMap.includes(key)) compMap.push(key);
const config: any = o.config;
const apiConfig = config.apiConfig
? `apiConfig: {
name: "${config.apiConfig.name}",
method: "${config.apiConfig.method}",
path: "${config.apiConfig.path}",
requestParamsConfigs: ${JSON.stringify(config.apiConfig.requestParamsConfigs) || []},
requestHeaderConfigs: ${JSON.stringify(config.apiConfig.requestHeaderConfigs) || []},
requestBodyConfigs:${JSON.stringify(config.apiConfig.requestBodyConfigs) || []}
},`
: '';
const idx = i > 0 ? `_${i}` : '';
switch (key) {
case 'Dashboard':
code += `<Dashboard :config="dashboardConfig${idx}"></Dashboard>
`;
configCode += `const dashboardConfig${idx} = ref({
${apiConfig}
numColor: "${config.numColor}",
labelColor: "${config.labelColor}",
dashboard: ${JSON.stringify(config.dashboard) || []}
});
`;
break;
case 'Banner':
code += `<view style="margin: 0 -10px 10px;">
<Banner :config="bannerConfig${idx}"></Banner>
</view>
`;
const imgs: string[] = config.imgs.map((k) => {
return k.url;
});
configCode += `const bannerConfig${idx} = ref({
height: ${o.h},
imgs: ${JSON.stringify(imgs)},
});
`;
break;
case 'ChartLine':
code += `<LineChart :config="lineConfig${idx}"></LineChart>
`;
const Llegend = getLegend(config.legend);
const dataList: any[] = [];
config.dataList.forEach((k) => {
const yAxis: any[] = [];
config.yAxis.forEach((j, i) => {
yAxis.push({
type: 'value', //value数值,categories类别
position: j.position,
title: j.name,
titleFontColor: j.nameTextStyle.color,
titleFontSize: j.nameTextStyle.fontSize,
// min: j.min,
// max: j.max,
format: i === 0 ? 'lineYAxis' : 'lineYAxisTwo',
axisFormat: j.axisLabel.formatter,
fontColor: j.axisLabel.color,
axisLine: j.axisLine.show,
axisLineColor: j.axisLine.lineStyle.color,
});
});
dataList.push({
title: k.title,
valueKey: k.valueKey,
apiConfig: k.apiConfig,
indicator: k.indicator,
options: {
extra: {
mix: {
column: {
seriesGap: 120,
},
area: {
gradient: true,
opacity: 6,
},
},
},
yAxis: {
data: yAxis,
},
xAxis: {
title: config.xAxis[0].name,
titleFontColor: config.xAxis[0].nameTextStyle.color,
titleFontSize: config.xAxis[0].nameTextStyle.fontSize,
fontColor: config.xAxis[0].axisLabel.color,
axisLine: config.xAxis[0].axisLine.show,
axisLineColor: config.xAxis[0].axisLine.lineStyle.color,
format: 'lineXAxis',
axisFormat: config.xAxis[0].axisLabel.formatter,
},
dataLabel: config.label.show,
legend: Llegend,
},
});
});
configCode += `const lineConfig${idx} = ref({
height: ${o.h},
title: "${config.title}",
condition: ${JSON.stringify(config.condition)},
count: ${JSON.stringify(config.count)},
dataList:${JSON.stringify(dataList)},
line: ${JSON.stringify(config.line)},
fontSize:${config.label.fontSize},
fontColor:"${config.label.color}",
});
`;
break;
case 'Pie':
code += `<PieChart :config="pieConfig${idx}"></PieChart>
`;
const Plegend = getLegend(config.echarts.legend);
const type =
config.echarts.series[0].radius[0] &&
config.echarts.series[0].radius[0].split('%')[0] > 0
? 'ring'
: config.echarts.series[0].roseType
? 'rose'
: 'pie';
let opts = '';
if (type == 'pie') {
opts = `pie: {
"customRadius": ${config.echarts.series[0].radius[1].split('%')[0]},
"labelWidth": 10,
"border": false
}`;
} else if (type == 'ring') {
opts = `ring: {
ringWidth: ${config.echarts.series[0].radius[0].split('%')[0]}, //内圈大小
labelWidth: 10,
border: false,
customRadius:${config.echarts.series[0].radius[1].split('%')[0]} //外圈大小
}`;
} else {
opts = `rose: {
type: "${config.echarts.series[0].roseType}",
minRadius: ${config.echarts.series[0].radius[0].split('%')[0]},
labelWidth: 10,
border: false,
}`;
}
configCode += `const pieConfig${idx} = ref({
${apiConfig}
labelKey: "${config.labelKey}",
valueKey: "${config.valueKey}",
title: "${config.title}",
height: ${o.h},
fontSize:${config.echarts.series[0].label.fontSize},
fontColor:"${config.echarts.series[0].label.color}",
pieType:"${type}", //rose玫瑰图pie饼图ring环形图
options:{
dataLabel: ${config.echarts.series[0].label.show},
labelFormat:"${config.echarts.series[0].label.formatter}",
legend: ${JSON.stringify(Plegend)},
color: ${JSON.stringify(config.colors)},
extra: {${opts}}
}
});
`;
break;
case 'Radar':
code += `<RadarChart :config="radarConfig${idx}"></RadarChart>
`;
const Rlegend = getLegend(config.echarts.legend);
configCode += `const radarConfig${idx} = ref({
${apiConfig}
labelKey: "${config.labelKey}",
title: "${config.title}",
height: ${o.h},
indicator:${JSON.stringify(config.echarts.radar.indicator) || []},
pointShape:"${config.echarts.series[0].symbol}",
options:{
dataLabel: ${config.echarts.series[0].label.show},
legend: ${JSON.stringify(Rlegend)},
color: ${JSON.stringify(config.colors)},
extra: {
"radar": {
radius:${config.echarts.radar.radius},
"gridType": "circle",
"gridColor": "#CCCCCC",
border:true,
"opacity": ${config.echarts.showAreaStyle},
},
}
}
});
`;
break;
case 'Gauge':
code += `<GaugeChart :config="gaugeConfig${idx}"></GaugeChart>
`;
configCode += `const gaugeConfig${idx} = ref({
${apiConfig}
labelKey: "${config.labelKey}",
title: "${config.title}",
height: ${o.h},
valueKey: "${config.valueKey}",
});
`;
break;
case 'Funnel':
code += `<FunnelChart :config="funnelConfig${idx}"></FunnelChart>
`;
const Flegend = getLegend(config.echarts.legend);
configCode += `const funnelConfig${idx} = ref({
${apiConfig}
fontSize:${config.echarts.series[0].label.fontSize},
fontColor:"${config.echarts.series[0].label.color}",
options:{
labelFormat:"${config.echarts.series[0].label.formatter}",
dataLabel:${config.echarts.series[0].label.show},
color: ${JSON.stringify(config.colors)},
padding: [${config.echarts.series[0].top || 0},${
config.echarts.series[0].right || 0
},${config.echarts.series[0].bottom || 0},${config.echarts.series[0].left || 0}],
legend:${JSON.stringify(Flegend)},
extra: {
funnel: {
activeOpacity: 0.3,
activeWidth: 10,
border: true,
borderWidth: ${config.echarts.series[0].gap},
borderColor: "#FFFFFF",
fillOpacity: 1,
labelAlign: "${
config.echarts.series[0].label.show
? config.echarts.series[0].label.position
: 'left'
}",
type: "${
config.echarts.series[0].sort == 'descending' ? 'triangle' : 'pyramid'
}" //triangle倒三角pyramid金字塔
}
}
},
labelKey: "${config.labelKey}",
title: "${config.title}",
height: ${o.h},
valueKey: "${config.valueKey}",
});
`;
break;
case 'ChartBar':
code += `<BarChart :config="barConfig${idx}"></BarChart>
`;
configCode += `const barConfig${idx} = ref({
${apiConfig}
labelKey: "${config.labelKey}",
targetKey:"${config.targetKey}",
title: "${config.title}",
height: ${o.h},
unit: "${config.unit}",
valueKey: "${config.valueKey}"
});
`;
break;
case 'MyTask':
code += `<MyTask :config="taskConfig${idx}"></MyTask>
`;
configCode += `const taskConfig${idx} = ref({
title: "${config.title}",
});
`;
break;
case 'TodoList':
code += `<TodoList :config="todoConfig${idx}"></TodoList>
`;
configCode += `const todoConfig${idx} = ref({
title: "${config.title}",
maxRows: ${config.maxRows},
});
`;
break;
case 'Modules':
code += `<Modules :config="modulesConfig${idx}"></Modules>
`;
configCode += `const modulesConfig${idx} = ref({
title: "${config.title}",
functions: ${JSON.stringify(config.functions)},
});
`;
break;
default:
break;
}
});
compMap.forEach((o) => {
switch (o) {
case 'Dashboard':
importCode += `import Dashboard from '@/components/dataDisplay/Dashboard.vue';
`;
break;
case 'Banner':
importCode += `import Banner from '@/components/dataDisplay/Banner.vue';
`;
break;
case 'ChartLine':
importCode += `import LineChart from '@/components/dataDisplay/LineChart.vue';
`;
break;
case 'Pie':
importCode += `import PieChart from '@/components/dataDisplay/PieChart.vue';
`;
break;
case 'Radar':
importCode += `import RadarChart from '@/components/dataDisplay/RadarChart.vue';
`;
break;
case 'Gauge':
importCode += `import GaugeChart from '@/components/dataDisplay/GaugeChart.vue';
`;
break;
case 'Funnel':
importCode += `import FunnelChart from '@/components/dataDisplay/FunnelChart.vue';
`;
break;
case 'ChartBar':
importCode += `import BarChart from '@/components/dataDisplay/BarChart.vue';
`;
break;
case 'MyTask':
importCode += `import MyTask from '@/components/dataDisplay/MyTask.vue';
`;
break;
case 'TodoList':
importCode += `import TodoList from '@/components/dataDisplay/TodoList.vue';
`;
break;
case 'Modules':
importCode += `import Modules from '@/components/dataDisplay/Modules.vue';
`;
break;
default:
break;
}
});
}
code += `</view>
</template>
<script setup>
import { ref } from 'vue';
${importCode}
${configCode}
</script>
<style></style>`;
return code;
}
function getLegend(config) {
let left = 'left';
let top = 'bottom';
if (config.position == LocationType.LEFT_TOP) {
left = config.orient == 'horizontal' ? 'left' : 'top';
top = config.orient == 'horizontal' ? 'top' : 'left';
} else if (config.position == LocationType.RIGHT_TOP) {
left = config.orient == 'horizontal' ? 'right' : 'top';
top = config.orient == 'horizontal' ? 'top' : 'right';
} else if (config.position == LocationType.LEFT_BOTTOM) {
left = config.orient == 'horizontal' ? 'left' : 'bottom';
top = config.orient == 'horizontal' ? 'bottom' : 'left';
} else if (config.position == LocationType.RIGHT_BOTTOM) {
left = config.orient == 'horizontal' ? 'right' : 'bottom';
top = config.orient == 'horizontal' ? 'bottom' : 'right';
} else if (config.position == LocationType.TOP_CENTER) {
left = 'center';
top = config.orient == 'horizontal' ? 'top' : 'left';
} else if (config.position == LocationType.BOTTOM_CENTER) {
left = 'center';
top = config.orient == 'horizontal' ? 'bottom' : 'left';
}
const legend = {
show: config.show,
position: top,
float: left,
margin: config.padding,
legendShape: config.icon,
fontColor: config.textStyle.color,
};
return legend;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,530 @@
import { camelCaseString } from '/@/utils/event/design';
//查询为inputNumber的组件
const iptNumComponents = ['number', 'slider', 'rate', 'computational', 'money-chinese'];
const remoteComponents = [
'select',
'associate-select',
'associate-popup',
'multiple-popup',
'checkbox',
'radio',
];
export const handleSearchForm = (option, schema, item, isNeedTrans, convertCamel = true) => {
if (!isNeedTrans) {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'Input',
},`
: {
field: item.fieldName,
label: schema!.label,
component: 'Input',
};
}
if (iptNumComponents.includes(schema.type)) {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'InputNumber',
componentProps:{
style:{ width:'100%' }
},
},`
: {
field: item.fieldName,
label: schema!.label,
component: 'InputNumber',
componentProps: {
style: { width: '100%' },
},
};
}
if (remoteComponents.includes(schema.type)) {
if (option && option?.datasourceType === 'staticData') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'XjrSelect',
componentProps: {
datasourceType:'staticData',
staticOptions: ${JSON.stringify(option.staticOptions)},
labelField: '${option.labelField}',
valueField: '${option.valueField}',
${
schema.type === 'checkbox' || schema.type === 'multiple-popup' ? "mode:'multiple'," : ''
}
getPopupContainer: () => document.body,
},
},`
: {
field: item.fieldName,
label: schema!.label,
component: 'XjrSelect',
componentProps: {
datasourceType: 'staticData',
staticOptions: option.staticOptions,
labelField: option.labelField,
valueField: option.valueField,
mode:
schema.type === 'checkbox' || schema.type === 'multiple-popup' ? 'multiple' : '',
getPopupContainer: () => document.body,
},
};
} else if (option && option?.datasourceType === 'dic') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'XjrSelect',
componentProps: {
datasourceType:'dic',
params: ${JSON.stringify(option.params)},
labelField: '${option.labelField}',
valueField: '${option.valueField}',
${
schema.type === 'checkbox' || schema.type === 'multiple-popup' ? "mode:'multiple'," : ''
}
getPopupContainer: () => document.body,
},
},`
: {
field: item.fieldName,
label: schema!.label,
component: 'XjrSelect',
componentProps: {
datasourceType: 'dic',
params: option.params,
labelField: option.labelField,
valueField: option.valueField,
mode:
schema.type === 'checkbox' || schema.type === 'multiple-popup' ? 'multiple' : '',
getPopupContainer: () => document.body,
},
};
} else if (option && option?.datasourceType === 'api') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'XjrSelect',
componentProps: {
datasourceType:'api',
apiConfig: ${JSON.stringify(option.apiConfig)},
labelField: '${option.labelField}',
valueField: '${option.valueField}',
${schema.type === 'checkbox' || schema.type === 'multiple-popup' ? "mode:'multiple'," : ''}
getPopupContainer: () => document.body,
},
},`
: {
field: item.fieldName,
label: schema!.label,
component: 'XjrSelect',
componentProps: {
datasourceType: 'api',
apiConfig: option.apiConfig,
labelField: option.labelField,
valueField: option.valueField,
mode:
schema.type === 'checkbox' || schema.type === 'multiple-popup' ? 'multiple' : '',
getPopupContainer: () => document.body,
},
};
}
}
if (schema.type === 'switch') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'Select',
componentProps:{
getPopupContainer: () => document.body,
options:[
{
label:'开',
value: 1
},{
label:'关',
value: 0
}
]
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: 'Select',
componentProps: {
options: [
{
label: '开',
value: 1,
},
{
label: '关',
value: 0,
},
],
},
};
}
if (schema.type === 'time') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'TimeRangePicker',
componentProps:{
format:'${option.format}',
style: { width: '100%' },
getPopupContainer: () => document.body,
},
},`
: {
field: item.fieldName,
label: schema!.label,
component: 'TimeRangePicker',
componentProps: {
format: option.format,
style: { width: '100%' },
getPopupContainer: () => document.body,
},
};
}
if (schema.type === 'date') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'RangePicker',
componentProps:{
format:'${option.format}',
style: { width: '100%' },
getPopupContainer: () => document.body,
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: 'RangePicker',
componentProps: {
format: option.format,
style: { width: '100%' },
getPopupContainer: () => document.body,
},
};
}
if (schema.type === 'user') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'User',
componentProps:{
suffix:'ant-design:setting-outlined',
placeholder:'请选择'
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: 'User',
componentProps: {
suffix: 'ant-design:setting-outlined',
placeholder: '请选择',
},
};
}
if (schema.type === 'area') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'Area',
componentProps:{
suffix:'ant-design:setting-outlined',
placeholder:'请选择',
getPopupContainer: () => document.body,
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: 'Area',
componentProps: {
suffix: 'ant-design:setting-outlined',
placeholder: '请选择',
getPopupContainer: () => document.body,
},
};
}
if (schema.type === 'organization') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: '${schema!.component}',
componentProps:{
placeholder:'请选择',
getPopupContainer: () => document.body,
},
},`
: {
field: item.fieldName,
label: schema!.label,
component: schema!.component,
componentProps: {
placeholder: '请选择',
getPopupContainer: () => document.body,
},
};
}
if (schema.type === 'cascader') {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: '${schema!.component}',
componentProps: {
apiConfig: ${JSON.stringify(option.apiConfig)},
showFormat: '${option.showFormat}',
separator: '${option.separator}',
selectedConfig: 'any',
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: schema!.component,
componentProps: {
apiConfig: option.apiConfig,
showFormat: option.showFormat,
separator: option.separator,
selectedConfig: 'any',
},
};
}
if (schema.type === 'info') {
if (option && option.infoType === 0) {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'User',
componentProps:{
suffix:'ant-design:setting-outlined',
placeholder:'请选择'
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: 'User',
componentProps: {
suffix: 'ant-design:setting-outlined',
placeholder: '请选择',
},
};
} else if (option && option.infoType === 1) {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'Dept',
componentProps:{
placeholder:'请选择',
getPopupContainer: () => document.body,
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: 'Dept',
componentProps: {
placeholder: '请选择',
getPopupContainer: () => document.body,
},
};
} else if (option && option.infoType === 2) {
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: 'RangePicker',
componentProps: {
showTime: true,
style: { width: '100%' },
getPopupContainer: () => document.body,
},
},
`
: {
field: item.fieldName,
label: schema!.label,
component: 'RangePicker',
componentProps: {
showTime: true,
style: { width: '100%' },
getPopupContainer: () => document.body,
},
};
}
}
return convertCamel
? `{
field: '${camelCaseString(item.fieldName)}',
label: '${schema!.label}',
component: '${schema!.component}',
},
`
: {
field: item.fieldName,
label: schema!.label,
component: schema!.component,
};
};
export const handleAppSearchForm = (option, schema, item, isNeedTrans, convertCamel = true) => {
if (!schema) return;
const fieldName = convertCamel ? camelCaseString(item.fieldName) : item.fieldName;
const field = `field: '${fieldName}',`;
const params = `key: '${schema.key}',
name: '${schema!.label}',
label: '${schema!.label}',`;
if (isNeedTrans) {
if (schema.component == 'TimeRange') {
return `{
${params}
field: '${fieldName + 'Start,' + fieldName + 'End'}',
component: componentType.timeRange, //组件类型
startTimeField:'${fieldName + 'Start'}',
endTimeField:'${fieldName + 'End'}',
componentProps: {
startTimePlaceholder: '开始时间',
endTimePlaceholder: '结束时间',
isRange: true,
}, //组件的所有配置信息
},`;
} else if (schema.component == 'DateTime') {
return `{
${params}
field: '${fieldName + 'Start,' + fieldName + 'End'}',
component: componentType.dateRange, //组件类型
startTimeField:'${fieldName + 'Start'}',
endTimeField:'${fieldName + 'End'}',
componentProps: {
formatType:'${
option.format == 'YYYY-MM'
? 'month'
: option.format == 'YYYY'
? 'year'
: option.format == 'YYYY-MM-DD HH:mm:ss'
? 'datetime'
: 'date'
}',
type: "datetimerange", //日期时间范围选择器
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
}, //组件的所有配置信息
},`;
} else if (schema.component == 'Switch') {
return `{
${params}
${field}
component: componentType.select, //组件类型
componentProps: {
localdata:[{text:'开',value:1},{text:'关',value:0}],
},
},`;
} else if (
schema.component == 'Checkbox' ||
schema.component == 'Radio' ||
schema.component == 'Select'
) {
return `{
${params}
${field}
component: componentType.select, //组件类型
componentProps: ${JSON.stringify(schema.componentProps)},
},`;
} else if (schema.component == 'colorPicker') {
return `{
${params}
${field}
component: componentType.color, //组件类型
defaultValue:null,
componentProps: {},
},`;
} else if (schema.component == 'InputNumber') {
return `{
${params}
${field}
component: componentType.input, //组件类型
componentProps: {
type: 'number',
},
},`;
} else if (schema.component == 'Info') {
if (schema.componentProps.infoType === 0) {
return `{
${params}
${field}
component: componentType.user, //组件类型
componentProps: {
placeholder: '请选择人员',
suffixIcon: 'ant-design:setting-outlined',
},
},`;
} else if (schema.componentProps.infoType === 1) {
return `{
${params}
${field}
component: componentType.organization, //组件类型
componentProps: {
placeholder: '请选择组织架构',
},
},`;
} else if (schema.componentProps.infoType === 2) {
return `{
${params}
field: '${fieldName + 'Start,' + fieldName + 'End'}',
component: componentType.dateRange, //组件类型
startTimeField:'${fieldName + 'Start'}',
endTimeField:'${fieldName + 'End'}',
componentProps: {
formatType: 'datetime',
type: 'datetimerange', //日期时间范围选择器
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
},
},`;
}
} else {
return JSON.stringify(schema) + ',';
}
} else {
return `{
${params}
${field}
component: componentType.input, //组件类型
componentProps: {
placeholder: '请输入${schema.label}',
}
},`;
}
};

View File

@ -0,0 +1,153 @@
import { camelCaseString } from '../event/design';
import { buildAppFormProps } from './designHelper';
import { ComponentOptionModel, FormJson } from '/@/model/generator/codeGenerator';
export const buildAppSchemeStrBySchema = (json: FormJson, convertCamel = true) => {
const props = buildAppFormProps(json, convertCamel);
return props;
};
export const buildAppSchemeStr = (list: ComponentOptionModel[], convertCamel: boolean): string => {
const code = `${list.map((item) => {
if (item.type === 'divider') {
return `{
key: '${item.key}',
field: ${convertCamel ? camelCaseString(item.bindField) : item.bindField}
name: '${item.label}',
component: componentType.divider,
componentProps: {
text: '${item.options!.defaultValue}',
align: '${item.options!.orientation}',
},
}`;
}
//如果是栅格布局组件 手机端没有 必须要扁平化
else if (item.type === 'grid') {
let gridStr = ``;
item.layout?.map((el) => {
gridStr += buildAppSchemeStr(el.list, convertCamel);
});
return gridStr;
} //如果是tab组件 转换为手机端配置
else if (item.type === 'tab') {
return `{
key: '${item.key}',
name: '${item.label}',
component: componentType.segmented,
layout: [${item.layout?.map((el, index) => {
return `{
name: '${el.name}',
value: '${index}',
children: [${buildAppSchemeStr(el.list, convertCamel)}],
}`;
})}],
}`;
} else if (item.type === 'card') {
return `{
key: '${item.key}',
name: '${item.label}',
component: componentType.collapse,
layout: [${item.layout?.map((el, index) => {
return `{
name: '${el.name}',
value: '${index}',
children: [${buildAppSchemeStr(el.list, convertCamel)}],
}`;
})}],
}`;
} else if (item.type === 'subForm') {
return `{
field: '${item.bindField}', //字段
key: '${item.key}',
name: '${item.label}',
component: componentType.subForm,
columns: [${buildAppSchemeStr(item.children!, convertCamel)}],
}`;
} else {
return buildAppDefaultSchema(item, convertCamel);
}
})}`;
return code;
};
export function buildAppDefaultSchema(model: ComponentOptionModel, convertCamel: boolean): string {
const compType = buildAppComponentTypeStr(model.type);
const schema = `{
key: '${model.key}',
field: '${(convertCamel ? camelCaseString(model.bindField)! : model.bindField) || ''}',
label: '${model.label}',
component: '${compType}',
defaultValue: '${model.options?.defaultValue}',
componentProps: {
placeholder: '请输入${model.label}',
},
name: '${model.label}',
}`;
return schema;
}
export function buildAppComponentTypeStr(type: string): string {
switch (type) {
case 'input':
return 'componentType.input';
case 'password':
return 'componentType.input';
case 'textarea':
return 'componentType.input';
case 'number':
return 'componentType.inputNumber';
case 'radio':
return 'componentType.radio';
case 'checkbox':
return 'componentType.checkbox';
case 'select':
return 'componentType.select';
case 'cascader':
return 'componentType.select';
case 'time':
return 'componentType.dateTime';
case 'date':
return 'componentType.dateTime';
case 'time-range':
return 'componentType.dateRange';
case 'date-range':
return 'componentType.dateRange';
case 'rate':
return 'componentType.inputNumber';
case 'switch':
return 'componentType.switch';
case 'slider':
return 'componentType.inputNumber';
case 'divider':
return 'componentType.divider';
case 'upload':
return 'componentType.input';
case 'richtext-editor':
return 'componentType.input';
case 'form':
return 'componentType.subForm';
case 'one-for-one':
return 'componentType.subForm';
default:
return 'componentType.input';
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,204 @@
interface TreeHelperConfig {
id: string;
children: string;
pid: string;
}
const DEFAULT_CONFIG: TreeHelperConfig = {
id: 'id',
children: 'children',
pid: 'pid',
};
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config);
// tree from list
export function listToTree<T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] {
const conf = getConfig(config) as TreeHelperConfig;
const nodeMap = new Map();
const result: T[] = [];
const { id, children, pid } = conf;
for (const node of list) {
node[children] = node[children] || [];
nodeMap.set(node[id], node);
}
for (const node of list) {
const parent = nodeMap.get(node[pid]);
(parent ? parent[children] : result).push(node);
}
return result;
}
export function treeToList<T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T {
config = getConfig(config);
const { children } = config;
const result: any = [...tree];
for (let i = 0; i < result.length; i++) {
if (!result[i][children!]) continue;
result.splice(i + 1, 0, ...result[i][children!]);
}
return result;
}
export function findNode<T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {},
): T | null {
config = getConfig(config);
const { children } = config;
const list = [...tree];
for (const node of list) {
if (func(node)) return node;
node[children!] && list.push(...node[children!]);
}
return null;
}
export function findNodeAll<T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {},
): T[] {
config = getConfig(config);
const { children } = config;
const list = [...tree];
const result: T[] = [];
for (const node of list) {
func(node) && result.push(node);
node[children!] && list.push(...node[children!]);
}
return result;
}
export function findPath<T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {},
): T | T[] | null {
config = getConfig(config);
const path: T[] = [];
const list = [...tree];
const visitedSet = new Set();
const { children } = config;
while (list.length) {
const node = list[0];
if (visitedSet.has(node)) {
path.pop();
list.shift();
} else {
visitedSet.add(node);
node[children!] && list.unshift(...node[children!]);
path.push(node);
if (func(node)) {
return path;
}
}
}
return null;
}
export function findPathAll(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) {
config = getConfig(config);
const path: any[] = [];
const list = [...tree];
const result: any[] = [];
const visitedSet = new Set(),
{ children } = config;
while (list.length) {
const node = list[0];
if (visitedSet.has(node)) {
path.pop();
list.shift();
} else {
visitedSet.add(node);
node[children!] && list.unshift(...node[children!]);
path.push(node);
func(node) && result.push([...path]);
}
}
return result;
}
export function filter<T = any>(
tree: T[],
func: (n: T) => boolean,
config: Partial<TreeHelperConfig> = {},
): T[] {
config = getConfig(config);
const children = config.children as string;
function listFilter(list: T[]) {
return list
.map((node: any) => ({ ...node }))
.filter((node) => {
node[children] = node[children] && listFilter(node[children]);
return func(node) || (node[children] && node[children].length);
});
}
return listFilter(tree);
}
export function forEach<T = any>(
tree: T[],
func: (n: T) => any,
config: Partial<TreeHelperConfig> = {},
): void {
config = getConfig(config);
const list: any[] = [...tree];
const { children } = config;
for (let i = 0; i < list.length; i++) {
//func 返回true就终止遍历避免大量节点场景下无意义循环引起浏览器卡顿
if (func(list[i])) {
return;
}
children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]);
}
}
/**
* @description: Extract tree specified structure
*/
export function treeMap<T = any>(treeData: T[], opt: { children?: string; conversion: Fn }): T[] {
return treeData.map((item) => treeMapEach(item, opt));
}
/**
* @description: Extract tree specified structure
*/
export function treeMapEach(
data: any,
{ children = 'children', conversion }: { children?: string; conversion: Fn },
) {
const haveChildren = Array.isArray(data[children]) && data[children].length > 0;
const conversionData = conversion(data) || {};
if (haveChildren) {
return {
...conversionData,
[children]: data[children].map((i: number) =>
treeMapEach(i, {
children,
conversion,
}),
),
};
} else {
return {
...conversionData,
};
}
}
/**
* 递归遍历树结构
* @param treeDatas 树
* @param callBack 回调
* @param parentNode 父节点
*/
export function eachTree(treeDatas: any[], callBack: Fn, parentNode = {}) {
treeDatas.forEach((element) => {
const newNode = callBack(element, parentNode) || element;
if (element.children) {
eachTree(element.children, callBack, newNode);
}
});
}

View File

@ -0,0 +1,35 @@
import { Slots } from 'vue';
import { isFunction } from '/@/utils/is';
/**
* @description: Get slot to prevent empty error
*/
export function getSlot(slots: Slots, slot = 'default', data?: any) {
if (!slots || !Reflect.has(slots, slot)) {
return null;
}
if (!isFunction(slots[slot])) {
console.error(`${slot} is not a function!`);
return null;
}
const slotFn = slots[slot];
if (!slotFn) return null;
return slotFn(data);
}
/**
* extends slots
* @param slots
* @param excludeKeys
*/
export function extendSlots(slots: Slots, excludeKeys: string[] = []) {
const slotKeys = Object.keys(slots);
const ret: any = {};
slotKeys.map((key) => {
if (excludeKeys.includes(key)) {
return null;
}
ret[key] = () => getSlot(slots, key);
});
return ret;
}