@@ -1,5 +1,8 @@ | |||
module.exports = { | |||
presets: [ | |||
'@vue/cli-plugin-babel/preset' | |||
] | |||
presets: [ | |||
'@vue/cli-plugin-babel/preset' | |||
], | |||
plugins: [ | |||
'@vue/babel-plugin-jsx' | |||
] | |||
} |
@@ -66,6 +66,24 @@ | |||
</template> | |||
<script> | |||
import FingerprintJS from '@fingerprintjs/fingerprintjs' | |||
const fpPromise = FingerprintJS.load() | |||
// 获取访客标识 | |||
fpPromise | |||
.then(fp => fp.get()) | |||
.then(result => { | |||
// 唯一标识符 | |||
const visitorId = result.visitorId | |||
// console.log(visitorId, 'FingerprintJS') | |||
// 其他设备信息 | |||
// console.log(result.components, 'FingerprintJS') // 包含屏幕分辨率、浏览器插件等信息 | |||
}) | |||
.catch(error => { | |||
console.error('FingerprintJS 失败:', error) | |||
}) | |||
export default { | |||
data () { | |||
@@ -101,7 +119,7 @@ export default { | |||
} | |||
} | |||
this.carouselKey++ // 及时刷新图片 | |||
console.log(this.imgIdArr, 'imgIdArr') | |||
// console.log(this.imgIdArr, 'imgIdArr') | |||
}, | |||
async getCategories () { | |||
@@ -1,7 +1,7 @@ | |||
<template> | |||
<div class="center"> | |||
<div>这是Center.vue组件</div> | |||
<!-- <div>这是Center.vue组件</div>--> | |||
<slot>center组件默认插槽</slot> | |||
<div></div> | |||
<!-- <slot name="footer" :val="'插槽传参'">center组件具名插槽</slot>--> | |||
@@ -23,8 +23,8 @@ setTimeout(() => { | |||
<style scoped lang="less"> | |||
.center{ | |||
height: 500px; | |||
border: 1px solid rebeccapurple; | |||
//height: 500px; | |||
//border: 1px solid rebeccapurple; | |||
} | |||
</style> |
@@ -4,13 +4,13 @@ | |||
<template> | |||
<div class="footer"> | |||
这是footer组件 | |||
<!-- 这是footer组件--> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
.footer{ | |||
border: 1px solid skyblue; | |||
//border: 1px solid skyblue; | |||
height: 200px; | |||
} | |||
</style> |
@@ -1,17 +1,20 @@ | |||
<script setup lang="ts"> | |||
import { ref, defineProps } from 'vue' | |||
const props = defineProps({}) | |||
</script> | |||
<template> | |||
<div class="header"> | |||
这是Header.vue组件 | |||
<div></div> | |||
<slot></slot> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
.header{ | |||
//width: 100%; | |||
height: 300px; | |||
border: 1px solid salmon; | |||
//height: 300px; | |||
//border: 1px solid salmon; | |||
} | |||
</style> |
@@ -1,28 +1,25 @@ | |||
<template> | |||
<div> | |||
<!-- <div>123</div>--> | |||
<!-- <component :is="Comp"></component>--> | |||
<!-- 直接以函数的形式渲染组件--> | |||
<!-- <Comp :count="'展示props传参'">--> | |||
<!-- <div>使用函数组件插槽</div>--> | |||
<!-- <template #header>--> | |||
<!-- <div>具名插槽</div>--> | |||
<!-- </template>--> | |||
<!-- </Comp>--> | |||
<!-- <Comp2>--> | |||
<!-- <div>使用center组件的插槽</div>--> | |||
<!-- </Comp2>--> | |||
<!-- <center @onFoo="(val)=>{console.log(val)}"></center>--> | |||
<Comp3></Comp3> | |||
<!-- <component :is="Comp3"></component>--> | |||
<div> | |||
动态渲染组件 | |||
<component | |||
:is="dynamicComponent" | |||
v-bind="jsonConfig.template.props" | |||
></component> | |||
<!-- <div>123</div>--> | |||
<!-- <component :is="Comp"></component>--> | |||
<!-- 直接以函数的形式渲染组件--> | |||
<!-- <Comp :count="'展示props传参'">--> | |||
<!-- <div>使用函数组件插槽</div>--> | |||
<!-- <template #header>--> | |||
<!-- <div>具名插槽</div>--> | |||
<!-- </template>--> | |||
<!-- </Comp>--> | |||
<!-- <Comp2>--> | |||
<!-- <div>使用center组件的插槽</div>--> | |||
<!-- </Comp2>--> | |||
<!-- <center @onFoo="(val)=>{console.log(val)}"></center>--> | |||
<Comp3></Comp3> | |||
<!-- <component :is="Comp3"></component>--> | |||
<div> | |||
动态渲染组件 | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script setup lang="ts"> | |||
@@ -35,258 +32,82 @@ import Layout from './Layout.vue' | |||
import Header from './Header.vue' | |||
import Panel from './Panel.vue' | |||
import Footer from './Footer.vue' | |||
// 模拟 JSON 数据 | |||
const jsonConfig = { | |||
template: { | |||
type: 'custom', | |||
name: 'CustomComponent', | |||
code: `<div> | |||
<el-button>这是一个json传入的按钮</el-button> | |||
<h1>{{ title }}</h1> | |||
<p>{{ description }}</p> | |||
</div>`, | |||
props: { | |||
title: '动态标题', | |||
description: '这是通过 JSON 动态渲染的 Vue 代码' | |||
} | |||
} | |||
} | |||
// 编译 JSON 中的 Vue 模板为渲染函数 | |||
const createDynamicComponent = (template: string) => { | |||
const { code } = compile(template, { mode: 'function' }) | |||
// eslint-disable-next-line no-new-func | |||
const renderFunction = new Function('Vue', code)(Vue) | |||
// 返回一个动态组件 | |||
return defineComponent({ | |||
props: ['title', 'description'], | |||
render: renderFunction | |||
}) | |||
} | |||
// 解析 JSON 并生成动态组件 | |||
const dynamicComponent = ref() | |||
if (jsonConfig.template?.code) { | |||
dynamicComponent.value = createDynamicComponent(jsonConfig.template.code) | |||
} | |||
// h函数基础使用 | |||
// const comp = h('div', { style: 'color: red' }, 'Hello World') | |||
const components = { Layout, PageOrDialog, Header, Panel, Center, Footer } | |||
// 使用响应式变量 和 使用 子节点的嵌套,事件,属性,插槽的使用 | |||
const msg = ref('使用变量') | |||
// 注意这里是一个函数 FunctionalComponent:方法组件类型声明 | |||
// 这里是声明了一个函数组件,然后被使用 | |||
const Comp = ((props, { slots }) => { | |||
return h('div', { style: 'color: red', onClick () { msg.value = '点击了' } }, | |||
[ | |||
h('span', {}, msg.value), | |||
h('h1', {}, props.count), | |||
h('h1', {}, [slots?.header?.(), slots?.default?.()]) | |||
]) | |||
}) as FunctionalComponent<{ count:string }> | |||
// 这里是声明了一个函数组件,但是是使用的已经定义好的组件 | |||
const Comp2 = ((props, { slots }) => { | |||
return h(Center, { | |||
msg: '我是参数', | |||
// 事件传参 | |||
onFoo (val:any) { | |||
console.log(123123) | |||
console.log('点击了' + val) | |||
} | |||
}, { | |||
default: slots.default, | |||
// 这里在footer插槽里面又嵌套了Center组件继续使用插槽,递归组件 | |||
footer: () => h(Center, null, { | |||
default: () => h('div', {}, '我是footer插槽'), | |||
footer: ({ val }) => h('div', {}, val + '使用插槽传参数') | |||
}) | |||
}) | |||
}) as FunctionalComponent | |||
import json2 from './jsonData2.js' | |||
import fxTitle from './component/fxTitle/FxTitle.vue' | |||
import FxButton from './component/fxButton/FxButton.vue' | |||
import FxSelect from './component/fxSelect/FxSelect.vue' | |||
import FxText from './component/fxText/FxText.vue' | |||
import FxDivider from './component/fxDivider/FxDivider.vue' | |||
import FxForm from './component/FxForm/FxForm.vue' | |||
import fxForm from './component/FxForm/FxFormCard.vue' | |||
import FxInput from './component/FxInput/FxInput.vue' | |||
import FxTable from './component/FxTable/FxTable.vue' | |||
import FxTableColumn from './component/FxTable/FxTableColumn/FxTableColumn.vue' | |||
import FxTableCard from './component/FxTable/FxTableCard.vue' | |||
import FxHeaderCard from './component/FxHeader/FxHeaderCard.vue' | |||
import toolbar from './component/toolbar/toobar.vue' | |||
import grid from './component/FxTable/FxTableCard.vue' | |||
import panel from './Panel.vue' | |||
const json3 = ref(json2) | |||
const components = { | |||
Layout, | |||
PageOrDialog, | |||
Header, | |||
Panel, | |||
Center, | |||
Footer, | |||
fxTitle, | |||
FxSelect, | |||
FxButton, | |||
FxText, | |||
FxDivider, | |||
FxForm, | |||
FxInput, | |||
FxTable, | |||
FxTableColumn, | |||
fxForm, | |||
FxTableCard, | |||
FxHeaderCard, | |||
toolbar, | |||
grid, | |||
panel | |||
} // 手动注册组件,因为自动注册的不知道为什么识别不了 | |||
// 递归解析模板的函数 | |||
const parseTemplate = (template: any, model: Record<string, any>) => { | |||
if (!template) return null | |||
if (!template) return null | |||
const componentName = | |||
const componentName = | |||
template.type in components | |||
? components[template.type] | |||
: resolveComponent(template.type || 'div') | |||
// 查找 model 数据并传递给组件 | |||
const modelData = model[template.name] || {} | |||
console.log(modelData, 'modelData') | |||
console.log(template.type, 'modelData') | |||
const children = (template.children || []).map((child: any) => | |||
parseTemplate(child, model) | |||
) | |||
return h( | |||
componentName, | |||
{ | |||
style: { margin: '20px', padding: '20px' }, | |||
...template.props, // 组件自带的 props | |||
data: modelData // 绑定的 model 数据 | |||
}, | |||
() => children | |||
) | |||
? components[template.type] | |||
: resolveComponent(template.type || 'div') // resolveComponent 如果在已注册的组件中找到了template.type的值(例如el-button),则返回对应的组件,否则返回一个空字符串。 | |||
// 查找 model 数据并传递给组件 | |||
const modelData = model[template.name] || {} | |||
console.log(modelData, 'modelData') | |||
console.log(template.type, 'modelData') | |||
const children = (template.children || []).map((child: any) => | |||
parseTemplate(child, model) | |||
) | |||
return h( | |||
componentName, | |||
{ | |||
style: {}, | |||
...template.props, // 组件自带的 props | |||
data: modelData // 绑定的 model 数据 | |||
}, | |||
() => children | |||
) | |||
} | |||
console.log(json3.value, 'json3.value') | |||
// const PageRenderer = defineComponent({ | |||
// props: ['config'], | |||
// setup (props) { | |||
// return () => parseTemplate(template) | |||
// } | |||
// }) | |||
// function bindModel (modelConfig, data) { | |||
// const model = {} | |||
// for (const [key, value] of Object.entries(modelConfig)) { | |||
// model[key] = value.fields.map((field) => ({ | |||
// ...field, | |||
// value: data[field.field.split('.')[0]][field.field.split('.')[1]] | |||
// })) | |||
// } | |||
// return model | |||
// } | |||
const Comp3 = () => parseTemplate(json.form[0].template, json.form[0].model) | |||
const Comp3 = () => parseTemplate(json3.value.form[0].template, json3.value.form[0].model) | |||
onMounted(() => { | |||
// console.log(Comp2) | |||
// console.log(Comp3()) | |||
// console.log(parseTemplate(json.form[0].template)) | |||
// console.log(Comp2) | |||
// console.log(Comp3()) | |||
// console.log(parseTemplate(json.form[0].template)) | |||
}) | |||
const json = { | |||
form: [ | |||
{ | |||
page: { | |||
name: '', | |||
type: 'page/dialog', | |||
title: '中文标题', | |||
template: '模板文件,为空则读自定义模板' | |||
}, | |||
template: { | |||
type: 'Layout', | |||
name: 'l1', | |||
children: [ | |||
{ | |||
type: 'Header', | |||
name: 'h1', | |||
props: { | |||
title: '标题', | |||
subTitle: '副标题', | |||
icon: 'icon' | |||
} | |||
}, | |||
{ | |||
type: 'Center', | |||
name: 'c1', | |||
children: [ | |||
{ | |||
type: 'Panel', | |||
name: 'p1' | |||
} | |||
] | |||
}, | |||
{ | |||
type: 'Footer', | |||
name: 'Footer', | |||
props: { | |||
title: '标题', | |||
subTitle: '副标题', | |||
icon: 'icon' | |||
} | |||
} | |||
] | |||
}, | |||
model: { | |||
p1: { | |||
vueComponent: { | |||
vueTemplate: ` | |||
<div style="background-color: #42b883;height: 180px;line-height: 30px;color: #fff;width: 400px;border-radius: 4px;padding:10px;margin: 0 auto"> | |||
<el-button type="primary" @click="log123">点击事件测试</el-button> | |||
<h1>{{ title }}</h1> | |||
<p >{{ description }}</p> | |||
<p>点击次数:{{ clickCount }}</p> | |||
<p>计算属性{{capitalizedTitle}}</p> | |||
</div>`, | |||
props: { | |||
title: '动态标题', | |||
description: '这是通过 JSON 动态渲染的 Vue 代码块' | |||
}, | |||
methods: { | |||
log123 () { | |||
console.log('按钮点击事件触发!') | |||
this.clickCount++ | |||
} | |||
}, | |||
data: { | |||
clickCount: 0 | |||
}, | |||
computed: { | |||
capitalizedTitle () { | |||
return this.clickCount + '00' | |||
} | |||
}, | |||
watch: { | |||
clickCount (newValue) { | |||
console.log('点击次数发生变化:', newValue) | |||
} | |||
} | |||
}, | |||
dataset: [ | |||
{ | |||
d1: { f1: '我是数据集数据' } | |||
}, | |||
{ | |||
d2: { f2: '我是f2' } | |||
} | |||
], | |||
fields: [ | |||
{ | |||
name: 'f1', | |||
field: 'd1.f1', | |||
type: 'combo', | |||
readonly: true | |||
}, | |||
{ | |||
name: 'f1', | |||
field: 'd1.f1', | |||
type: 'vue', | |||
content: { string: '自定义vue放这里' } | |||
} | |||
] | |||
} | |||
} | |||
} | |||
] | |||
} | |||
const template = { | |||
type: 'div', | |||
props: { class: 'container' }, | |||
children: [ | |||
{ | |||
type: 'span', | |||
props: { class: 'text' }, | |||
children: ['Hello'] | |||
}, | |||
{ | |||
type: 'button', | |||
props: { onClick: () => alert('Clicked!') }, | |||
children: ['Click me'] | |||
} | |||
] | |||
} | |||
// const vNode = parseTemplate(template) | |||
// console.log(PageRenderer) | |||
@@ -20,7 +20,7 @@ console.log(attrs, 'attrs') // 打印未定义的属性 | |||
<template> | |||
<div v-bind="$attrs" class="layout"> | |||
这是Layout.vue组件 | |||
<!-- 这是Layout.vue组件--> | |||
<slot></slot> | |||
</div> | |||
@@ -28,7 +28,8 @@ console.log(attrs, 'attrs') // 打印未定义的属性 | |||
<style scoped lang="less"> | |||
.layout{ | |||
text-align: center; | |||
//text-align: center; | |||
color: #333; | |||
border: 1px solid seagreen; | |||
} | |||
</style> |
@@ -1,22 +1,23 @@ | |||
<template> | |||
<div class="panel"> | |||
<p style="background-color: #fff;" >这是 Panel 组件</p> | |||
<!-- 渲染 JSON 动态组件 --> | |||
<div>{{data.dataset}}</div> | |||
<div class="panel" :class="[{flex:props.direction=='row'}, {grid:props.colnum}]"> | |||
<!-- <fxTitle v-if="props.data.title" :title="props.data.title"></fxTitle>--> | |||
<component v-for="(item,index) in props.data.content" :is="components[item.type]" :key="index" :label="item.label" :opts="item.opts"></component> | |||
<!-- 用于渲染用户写的vue代码片段--> | |||
<component | |||
v-if="dynamicComponent" | |||
:is="dynamicComponent" | |||
v-bind="data?.vueComponent.props" | |||
></component> | |||
<slot></slot> | |||
<!-- 自定义渲染函数 --> | |||
<!-- <div v-else-if="renderedContent">--> | |||
<!-- <div v-html="renderedContent"></div>--> | |||
<!-- </div>--> | |||
<!-- 默认内容 --> | |||
<div v-else> | |||
<p>没有动态组件或渲染函数</p> | |||
</div> | |||
</div> | |||
</template> | |||
@@ -24,49 +25,38 @@ | |||
import { compile } from '@vue/compiler-dom' | |||
import { defineComponent, h, ref, shallowRef, reactive, computed, defineProps, useAttrs, watch, toRefs } from 'vue' | |||
import * as Vue from 'vue' | |||
import fxTitle from '@/views/ddmDemo/component/fxTitle/FxTitle.vue' | |||
import select from '@/views/ddmDemo/component/fxSelect/FxSelect.vue' | |||
import label from '@/views/ddmDemo/component/fxText/FxText.vue' | |||
const components = shallowRef({select, fxTitle,label}) | |||
const attrs = useAttrs() | |||
const props = defineProps({ | |||
// title: String, | |||
// description: String, | |||
// vueComponent: Object, | |||
data: Object | |||
data: Object, | |||
direction:{ | |||
type: String, | |||
default: 'col' | |||
}, | |||
colnum:{ | |||
type: Number, | |||
} | |||
}) | |||
console.log(props, 'awdasdas') | |||
// 解构 props | |||
// const { customContent, render1 } = toRefs(props) | |||
// 模拟 JSON 配置数据 | |||
const jsonConfig = { | |||
template: { | |||
type: 'custom', | |||
name: 'CustomComponent', | |||
code: `<div> | |||
<el-button type="primary" @click="log123">这是一个json传入的按钮</el-button> | |||
<h1>{{ title }}</h1> | |||
<p>{{ description }}</p> | |||
</div>`, | |||
props: { | |||
title: '动态标题', | |||
description: '这是通过 JSON 动态渲染的 Vue 代码' | |||
}, | |||
methods: { | |||
log123 () { | |||
console.log('按钮点击事件触发!') | |||
} | |||
} | |||
} | |||
} | |||
// 动态组件解析器 | |||
// 动态组件解析器(解析vue代码块) | |||
const createDynamicComponent = ( | |||
template: string, | |||
options:{ | |||
props?: Record<string, any> // 动态 props | |||
methods?: Record<string, Function> // 动态方法 | |||
methods?: Record<string, (...args: any[]) => any > // 动态方法 | |||
data?: Record<string, any> // 动态 data | |||
computed?: Record<string, Function> // 动态计算属性 | |||
watch?: Record<string, Function> // 动态 watch | |||
computed?: Record<string, () => any> // 动态计算属性 | |||
watch?: Record<string, (newValue: any, oldValue: any) => void> // 动态 watch | |||
} = {} | |||
) => { | |||
try { | |||
@@ -74,7 +64,13 @@ const createDynamicComponent = ( | |||
const { code } = compile(template, { mode: 'function' }) | |||
// eslint-disable-next-line no-new-func | |||
const renderFunction = new Function('Vue', code)(Vue) | |||
const renderFunction = new Function('Vue', code)(Vue) // 这里的(Vue)是把vue作为形参传给新生成的函数,code作为函数的函数体,code函数体里面有很多需要调用vueApi的地方,所以需要把vue作为形参传进去, | |||
// 等价于(举例) | |||
// function anonymous (Vue) { | |||
// return function render (_ctx, _cache) { | |||
// return (_openBlock(), _createElementBlock('div', null, _toDisplayString(_ctx.message), 1)) | |||
// } | |||
// } | |||
// 返回动态组件定义 | |||
return defineComponent({ | |||
@@ -127,7 +123,7 @@ const createDynamicComponent = ( | |||
} | |||
// 动态组件引用shallowRef | |||
const dynamicComponent = ref<ReturnType<typeof defineComponent> | null>(null) | |||
const dynamicComponent = shallowRef<ReturnType<typeof defineComponent> | null>(null) | |||
// data.vueComponent.vueTemplate | |||
// 初始化动态组件 | |||
if (props?.data?.vueComponent?.vueTemplate) { | |||
@@ -150,6 +146,19 @@ if (props?.data?.vueComponent?.vueTemplate) { | |||
<style scoped lang="less"> | |||
.panel{ | |||
//height: 200px; | |||
border: 1px solid gold; | |||
//padding: 20px; | |||
//border: 1px solid gold; | |||
} | |||
.pad20{ | |||
//padding: 20px; | |||
} | |||
.flex{ | |||
display: flex; | |||
align-items: center; | |||
} | |||
.grid{ | |||
display: grid; | |||
//background-color: pink; | |||
} | |||
</style> |
@@ -0,0 +1,29 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent, defineProps } from 'vue' | |||
defineOptions({ | |||
name: 'FxForm', // 设置组件的名称 | |||
}); | |||
const props = defineProps({ | |||
style:{ | |||
type:Object, | |||
default:{} | |||
} | |||
}) | |||
</script> | |||
<template> | |||
<div> | |||
<el-form label-width="auto" > | |||
<div :style="style"> | |||
<slot></slot> | |||
</div> | |||
</el-form> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
</style> |
@@ -0,0 +1,76 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent, defineProps, ref } from 'vue' | |||
import FxTitle from '@/views/ddmDemo/component/fxTitle/FxTitle.vue' | |||
import FxDivider from '@/views/ddmDemo/component/fxDivider/FxDivider.vue' | |||
defineOptions({ | |||
name: 'FxFormCard', // 设置组件的名称 | |||
}); | |||
const props = defineProps({ | |||
data:{ | |||
type:Object, | |||
default:{} | |||
}, | |||
divider:{ | |||
type:Boolean, | |||
default:false | |||
}, | |||
colnum:{ | |||
type:Number, | |||
default:1 | |||
} | |||
}) | |||
console.log(props,'propsprops') | |||
// const form = ref({ | |||
// name: '', | |||
// region: '', | |||
// date1: '', | |||
// date2: '', | |||
// delivery: false, | |||
// type: [], | |||
// resource: '', | |||
// desc: '', | |||
// }) | |||
</script> | |||
<template> | |||
<div class="FxFormCard"> | |||
<fx-title :title="data.title"></fx-title> | |||
<el-form label-width="auto" style="margin-top: 20px"> | |||
<div class="form"> | |||
<div v-for="(item,index) in data.content" :key="index" class="form-item"> | |||
<!-- {{item.name}}--> | |||
<!-- {{ data.dataset.formData.fields[item.name] }}--> | |||
<el-form-item :label="item.label" :required="item.required" > | |||
<el-input :readonly="item.readonly" :disabled="item.readonly" /> | |||
</el-form-item> | |||
</div> | |||
</div> | |||
</el-form> | |||
<fx-divider size="small" v-if="props.divider" ></fx-divider> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
.FxFormCard{ | |||
padding: 20px 20px 0px; | |||
.form{ | |||
//width:800px; | |||
display: grid; /* 启用 grid 布局 */ | |||
grid-template-columns: 400px 400px; /* 定义两列等宽 */ | |||
gap: 0px 50px; /* 定义网格之间的间距 */ | |||
padding: 16px; /* 可选:为容器添加内边距 */ | |||
.form-item{ | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,73 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent } from 'vue' | |||
import FxTitle from '@/views/ddmDemo/component/fxTitle/FxTitle.vue' | |||
defineOptions({ | |||
name: 'FxHeaderCard' | |||
}) | |||
const props = defineProps({ | |||
data:{ | |||
type:Object, | |||
required:true | |||
} | |||
}) | |||
console.log(props.data,'123123765') | |||
const dataset = props.data.dataset | |||
const fields = props.data.fields | |||
</script> | |||
<template> | |||
<div class="FxHeaderCard"> | |||
<div class="title"> | |||
<fx-title title="单据编辑"></fx-title> | |||
<div style="width: 200px;margin-left: 20px"> | |||
<el-select | |||
v-for="(item,index) in fields" | |||
v-show="item.type == 'select'" | |||
v-model="item.field" | |||
placeholder="Select" | |||
size="large" | |||
style="width: 240px" | |||
> | |||
<el-option | |||
v-for="item in dataset.headerData.selectOption" | |||
:key="item.value" | |||
:label="item.label" | |||
:value="item.value" | |||
/> | |||
</el-select> | |||
</div> | |||
<div class="btn"> | |||
<el-button v-for="(item,index) in dataset.headerData.button" :type="item.type">{{item.name}}</el-button> | |||
</div> | |||
</div> | |||
<div class="text"> | |||
<div v-show="item.type=='string'" v-for="(item,index) in fields">{{ item.label }}: {{ dataset.headerData.fields[item.field] }}</div> | |||
</div> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
.FxHeaderCard{ | |||
padding: 20px; | |||
.title{ | |||
display: flex; | |||
align-items: center; | |||
} | |||
.btn{ | |||
margin-left: auto; | |||
} | |||
.text{ | |||
font-size: 14px; | |||
margin-top: 30px; | |||
display: flex; | |||
gap: 50px; | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,42 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent, defineProps, ref } from 'vue' | |||
defineOptions({ | |||
name: 'FxInpout', // 设置组件的名称 | |||
}); | |||
const props = defineProps({ | |||
label:{ | |||
type:String, | |||
default:'' | |||
}, | |||
placeholder:{ | |||
type:String, | |||
default:'请输入内容' | |||
}, | |||
required:{ | |||
} | |||
}) | |||
const form = ref({ | |||
name: '', | |||
region: '', | |||
date1: '', | |||
date2: '', | |||
delivery: false, | |||
type: [], | |||
resource: '', | |||
desc: '', | |||
}) | |||
</script> | |||
<template> | |||
<div> | |||
<el-form-item :label="label" :required="required"> | |||
<el-input v-model="form.name" :placeholder="placeholder" /> | |||
</el-form-item> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
</style> |
@@ -0,0 +1,45 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent , defineProps} from 'vue' | |||
defineOptions({ | |||
name: 'FxTable', // 设置组件的名称 | |||
}); | |||
const props = defineProps({ | |||
}) | |||
const tableData = [ | |||
{ | |||
date: '2016-05-03', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
{ | |||
date: '2016-05-02', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
{ | |||
date: '2016-05-04', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
{ | |||
date: '2016-05-01', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
] | |||
</script> | |||
<template> | |||
<div> | |||
<el-table :data="tableData" style="width: 100%" border> | |||
<slot></slot> | |||
</el-table> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
</style> |
@@ -0,0 +1,75 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent, defineProps, ref } from 'vue' | |||
import FxTitle from '@/views/ddmDemo/component/fxTitle/FxTitle.vue' | |||
import FxDivider from '@/views/ddmDemo/component/fxDivider/FxDivider.vue' | |||
defineOptions({ | |||
name: 'FxTableCard' | |||
}) | |||
const props = defineProps({ | |||
data:{ //data后续同一个改为model | |||
type:Object, | |||
default:{} | |||
}, | |||
}) | |||
// const tableData1 = ref(props.data.dataset.tableData) | |||
const fields = ref(props.data.fields) | |||
console.log(props.data,'123123125') | |||
const model = ref(props.data) | |||
const tableData = [ | |||
{ | |||
date: '2016-05-03', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
{ | |||
date: '2016-05-02', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
{ | |||
date: '2016-05-04', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
{ | |||
date: '2016-05-01', | |||
name: 'Tom', | |||
address: 'No. 189, Grove St, Los Angeles', | |||
}, | |||
] | |||
</script> | |||
<template> | |||
<div class='FxTableCard'> | |||
<div class="title"> | |||
<fx-title :title="model.title"></fx-title> | |||
<div> | |||
<el-button v-for="(item,index) in model.toolbar" :key="index" :type="item.btn_type">{{item.label}}</el-button> | |||
</div> | |||
</div> | |||
<el-table :data="tableData.fields" style="width: 100%;margin-top: 20px"> | |||
<el-table-column type="index" v-if="model.rownumbers" /> | |||
<el-table-column type="selection" v-if="model.checkbox" /> | |||
<el-table-column v-for="(item,index) in model.cols" :type="item.type" :prop="item.field" :label="item.label" :width="item.width" /> | |||
</el-table> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
.FxTableCard{ | |||
padding: 20px; | |||
.title{ | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,28 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent , defineProps} from 'vue' | |||
defineOptions({ | |||
name: 'FxTableColumn', // 设置组件的名称 | |||
}); | |||
const props = defineProps({ | |||
type:{ | |||
type:String, | |||
default:'' | |||
}, | |||
fixed:{ | |||
type:String, | |||
default:'' | |||
} | |||
}) | |||
</script> | |||
<template> | |||
<el-table-column :fixed="fixed" :type="type" prop="date" label="Date" width="180" > | |||
<!-- <slot></slot>--> | |||
</el-table-column> | |||
</template> | |||
<style scoped lang="less"> | |||
</style> |
@@ -0,0 +1,42 @@ | |||
<script lang="jsx"> | |||
import { defineComponent, ref, defineProps } from 'vue' | |||
import { ElButton } from 'element-plus' | |||
// import { ElButton } from 'element-plus' | |||
export default defineComponent({ | |||
name: 'FxButton', | |||
props: { | |||
text: { | |||
type: String, | |||
required: true, | |||
default: '按钮' | |||
}, | |||
type:{ | |||
type: String, | |||
required: false, | |||
default: 'primary' | |||
} | |||
}, | |||
setup (props, { slots }) { | |||
const count = ref(0) | |||
const increment = () => { | |||
count.value++ | |||
} | |||
return () => ( | |||
<div> | |||
<ElButton type={props.type}> | |||
{props.text} | |||
</ElButton> | |||
{/* 渲染默认插槽 */} | |||
{slots.default ? slots.default() : null} | |||
{/* <button onClick={increment}>Increment</button> */} | |||
</div> | |||
) | |||
} | |||
}) | |||
</script> |
@@ -0,0 +1,38 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent , defineProps} from 'vue' | |||
defineOptions({ | |||
name: 'FxDivider', // 设置组件的名称 | |||
}); | |||
const props = defineProps({ | |||
// style:{ | |||
// type:Object, | |||
// default:{} | |||
// } | |||
size:{ | |||
type:String, | |||
default:'default' | |||
} | |||
}) | |||
</script> | |||
<template> | |||
<div class="fx-divider" :style="size=='large'? {height:'8px'} : {height:'1px'} "> | |||
<!-- <el-divider></el-divider>--> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
.fx-divider{ | |||
background-color: #f0f2f5; | |||
} | |||
.large{ | |||
height: 8px; | |||
} | |||
.small{ | |||
height: 1px; | |||
} | |||
</style> |
@@ -0,0 +1,68 @@ | |||
<script lang="jsx"> | |||
import { defineComponent, ref, defineProps } from 'vue' | |||
import { ElOption, ElSelect } from 'element-plus' | |||
export default defineComponent({ | |||
name: 'FxSelect', | |||
props: { | |||
title: { | |||
type: String, | |||
default: 'hello' | |||
}, | |||
opts:{ | |||
type: Array, | |||
} | |||
}, | |||
setup (props) { | |||
console.log(props, '1312321355') | |||
const value = ref('') | |||
const options = [ | |||
{ | |||
value: 'Option1', | |||
label: 'Option1', | |||
}, | |||
{ | |||
value: 'Option2', | |||
label: 'Option2', | |||
}, | |||
{ | |||
value: 'Option3', | |||
label: 'Option3', | |||
}, | |||
{ | |||
value: 'Option4', | |||
label: 'Option4', | |||
}, | |||
{ | |||
value: 'Option5', | |||
label: 'Option5', | |||
}, | |||
] | |||
return () => ( | |||
<div> | |||
<ElSelect | |||
v-model={value.value} // 等效于 v-model | |||
placeholder="请选择" | |||
size="default" | |||
style={{ width: '240px' }} | |||
> | |||
{props.opts.map((item) => ( | |||
<ElOption | |||
key={item.value} | |||
label={item.label} | |||
value={item.value} | |||
/> | |||
))} | |||
</ElSelect> | |||
<slot></slot> | |||
{/* <button onClick={increment}>Increment</button> */} | |||
</div> | |||
) | |||
} | |||
}) | |||
</script> |
@@ -0,0 +1,33 @@ | |||
<script lang="jsx"> | |||
import { defineComponent } from 'vue' | |||
export default defineComponent({ | |||
name: 'FxText', | |||
props: { | |||
label: { | |||
type: String, | |||
required: true, | |||
default: 'text' | |||
}, | |||
value:{ | |||
type: String, | |||
required: false, | |||
default: 'value' | |||
} | |||
}, | |||
setup(props,{}){ | |||
return () => ( | |||
<div class="fx-text"> | |||
<span>{props.label}:</span> | |||
<span>{props.value}</span> | |||
</div> | |||
) | |||
} | |||
}) | |||
</script> | |||
<style> | |||
.fx-text{ | |||
font-size: 14px; | |||
display: flex; | |||
gap: 20px; | |||
} | |||
</style> |
@@ -0,0 +1,17 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent } from 'vue' | |||
defineOptions({ | |||
name: 'FxTextCard' | |||
}) | |||
</script> | |||
<template> | |||
</template> | |||
<style scoped lang="less"> | |||
</style> |
@@ -0,0 +1,3 @@ | |||
h1{ | |||
font-size: 30px; | |||
} |
@@ -0,0 +1,59 @@ | |||
<script lang="jsx"> | |||
import { defineComponent, ref, defineProps } from 'vue' | |||
export default defineComponent({ | |||
name: 'fxTitle', | |||
props: { | |||
title: { | |||
type: String, | |||
default: 'hello' | |||
}, | |||
data:{ | |||
type: Object, | |||
} | |||
}, | |||
setup (props, { slots }) { | |||
const title = ref(props.title||props.data.title) | |||
console.log(props,'13123213') | |||
return () => ( | |||
<div> | |||
<div class="title"> | |||
<span class="decoration" ></span> | |||
<h1>{title.value}</h1> | |||
</div> | |||
{/* 渲染默认插槽 */} | |||
{slots.default ? slots.default() : null} | |||
{/* <button onClick={increment}>Increment</button> */} | |||
</div> | |||
) | |||
} | |||
}) | |||
</script> | |||
<style lang="less"> | |||
.title{ | |||
margin-right: 30px; | |||
display: flex; | |||
gap: 5px; | |||
.decoration{ | |||
height: 18px; | |||
width: 3px; | |||
background-color: #4362e6; | |||
border-radius: 2px; | |||
} | |||
h1{ | |||
font-weight: 600; | |||
font-size: 18px; | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,35 @@ | |||
<script lang="ts" setup> | |||
import { defineComponent } from 'vue' | |||
defineOptions({ | |||
name: 'toobar' | |||
}) | |||
const props = defineProps({ | |||
align:{ | |||
type:String, | |||
default:'' | |||
}, | |||
data:{ | |||
type:Object | |||
} | |||
}) | |||
console.log(props,'541332231') | |||
</script> | |||
<template> | |||
<div class="toobar" :class="{alignRight:props.align=='right'}"> | |||
<div> | |||
<el-button v-for="(item,index) in props.data.content" :type="item.btn_type">{{item.label}}</el-button> | |||
</div> | |||
</div> | |||
</template> | |||
<style scoped lang="less"> | |||
.toobar{ | |||
} | |||
.alignRight{ | |||
margin-left: auto; | |||
justify-self: end | |||
} | |||
</style> |
@@ -0,0 +1,342 @@ | |||
const json = { | |||
form: [ | |||
{ | |||
page: { | |||
// 页面整体的属性 | |||
name: '', | |||
type: 'page/dialog', | |||
title: '中文标题', | |||
template: '模板文件,为空则读自定义模板', | |||
class: '指定样式文件' | |||
}, | |||
template: { | |||
type: 'Layout', | |||
name: 'l1', | |||
children: [ | |||
{ | |||
type: 'Header', | |||
name: 'Header', | |||
props: { | |||
}, | |||
children:[ | |||
{ | |||
type:'FxHeaderCard', | |||
name:'FxHeaderCard1' //单据编辑 | |||
} | |||
] | |||
}, | |||
{ | |||
type: 'FxDivider', | |||
name: '分割线', | |||
props: { | |||
size:'large' | |||
} | |||
}, | |||
{ | |||
type: 'Center', | |||
name: 'c1', | |||
children: [ | |||
{ | |||
type: 'FxFormCard', | |||
name: 'FxFormCard1'//表单 | |||
}, | |||
{ | |||
type: 'FxDivider', | |||
name: '分割线', | |||
props: { | |||
} | |||
}, | |||
{ | |||
type: 'FxTableCard', | |||
name: 'FxTableCard1',//表格 | |||
}, | |||
] | |||
}, | |||
{ | |||
type: 'Footer', | |||
name: 'Footer', | |||
props: { | |||
title: '标题', | |||
subTitle: '副标题', | |||
icon: 'icon' | |||
} | |||
} | |||
] | |||
}, | |||
model: { | |||
FxHeaderCard1:{ | |||
dataset:{ | |||
headerData:{ | |||
name:'headerData', | |||
title:'单据编辑', | |||
button:[ | |||
{ | |||
name:'删除', | |||
type:'danger', | |||
}, | |||
{ | |||
name:'流程跟踪', | |||
type:'warning', | |||
},{ | |||
name:'返回', | |||
type:'', | |||
} | |||
], | |||
selectOption:[ | |||
{ | |||
label:'制单1', | |||
value:'zd' | |||
}, | |||
{ | |||
label:'制单2', | |||
value:'zd2' | |||
}, | |||
], | |||
fields:{ | |||
zd:'zd', | |||
djbh:'BC20230158', | |||
zdrq:'2023-10-19', | |||
bzdw:'重庆民政局', | |||
bzbm:'业务部门', | |||
} | |||
} | |||
}, | |||
fields:[ | |||
{ | |||
label: '', | |||
dataSetName:'headerData', | |||
field: 'zd', | |||
type: 'select', | |||
}, | |||
{ | |||
label: '单据编号', | |||
dataSetName:'headerData', | |||
field: 'djbh', | |||
type: 'string', | |||
}, | |||
{ | |||
label: '制单日期', | |||
dataSetName:'headerData', | |||
field: 'zdrq', | |||
type: 'string', | |||
}, | |||
{ | |||
label: '编制单位', | |||
dataSetName:'headerData', | |||
field: 'bzdw', | |||
type: 'string', | |||
}, | |||
{ | |||
label: '编制部门', | |||
dataSetName:'headerData', | |||
field: 'bzbm', | |||
type: 'string', | |||
}, | |||
] | |||
}, | |||
FxFormCard1: { | |||
dataset: { | |||
formData: { | |||
name: 'formData', | |||
title: '名册信息', | |||
fields: { | |||
recordNumber: 'BC20230158', // 单据编号 | |||
unit: '重庆市民政局', // 单位 | |||
fundItem: ['高龄津贴'], // 资金科目 | |||
businessType: '艾滋病孤儿', // 业务类型 | |||
businessMonth: '2023-11', // 业务月 | |||
creationDate: '2023-10-19 14:58:41', // 制单日期 | |||
totalItems: 0, // 合计条数 | |||
totalAmount: 0, // 合计金额 | |||
}, | |||
}, | |||
}, | |||
fields: [ | |||
{ | |||
name: 'recordNumber', | |||
field: 'formData.recordNumber', | |||
type: 'text', | |||
label: '单据编号', | |||
readonly: false, | |||
}, | |||
{ | |||
name: 'unit', | |||
field: 'formData.unit', | |||
type: 'text', | |||
label: '单位', | |||
readonly: false, | |||
}, | |||
{ | |||
name: 'fundItem', | |||
field: 'formData.fundItem', | |||
type: 'multi-select', | |||
label: '资金科目', | |||
required: true, | |||
}, | |||
{ | |||
name: 'businessType', | |||
field: 'formData.businessType', | |||
type: 'dropdown', | |||
label: '业务类型', | |||
required: true, | |||
}, | |||
{ | |||
name: 'businessMonth', | |||
field: 'formData.businessMonth', | |||
type: 'date', | |||
label: '业务月', | |||
required: true, | |||
}, | |||
{ | |||
name: 'creationDate', | |||
field: 'formData.creationDate', | |||
type: 'datetime', | |||
label: '制单日期', | |||
readonly: false, | |||
}, | |||
{ | |||
name: 'totalItems', | |||
field: 'formData.totalItems', | |||
type: 'number', | |||
label: '合计条数', | |||
readonly: false, | |||
}, | |||
{ | |||
name: 'totalAmount', | |||
field: 'formData.totalAmount', | |||
type: 'number', | |||
label: '合计金额', | |||
readonly: false, | |||
}, | |||
], | |||
}, | |||
FxTableCard1: { | |||
dataset: { | |||
tableData: { | |||
name: 'tableData', | |||
title: '统计信息', | |||
button:[ | |||
{ | |||
name:'导入', | |||
type:'warning', | |||
icon:'' | |||
}, | |||
{ | |||
name:'新增', | |||
type:'primary', | |||
icon:'' | |||
} | |||
], | |||
fields: [ | |||
{ | |||
unit: '单位1', | |||
name: '张三', | |||
idCode: '500101111111111111111', | |||
fundSubject:'科目1', | |||
totalAmount:'100', | |||
subsidyAmount:'100' | |||
}, | |||
{ | |||
unit: '单位2', | |||
name: '李斯', | |||
idCode: '5001022222222222', | |||
fundSubject:'科目2', | |||
totalAmount:'200', | |||
subsidyAmount:'200' | |||
} | |||
] | |||
} | |||
}, | |||
fields:[ | |||
{ | |||
label: '序号', | |||
type:'index' | |||
}, | |||
{ | |||
label: '单位', | |||
dataSetName:'tableData', | |||
field: 'unit', | |||
type: 'number', | |||
}, | |||
{ | |||
label: '姓名', | |||
dataSetName:'tableData', | |||
field: 'name', | |||
type: 'number', | |||
}, | |||
{ | |||
label: '证件号码', | |||
dataSetName:'tableData', | |||
field: 'idCode', | |||
type: 'idCode', | |||
}, | |||
{ | |||
label: '资金科目', | |||
dataSetName:'tableData', | |||
field: 'fundSubject', | |||
type: 'string', | |||
}, | |||
{ | |||
label: '合计金额', | |||
dataSetName:'tableData', | |||
field: 'totalAmount', | |||
type: 'found', | |||
}, | |||
{ | |||
label: '补发金额', | |||
dataSetName:'tableData', | |||
field: 'subsidyAmount', | |||
type: 'found', | |||
}, | |||
] | |||
} | |||
} | |||
} | |||
] | |||
} | |||
export default json |
@@ -0,0 +1,358 @@ | |||
const formData = { | |||
form: [ | |||
{ | |||
page: { | |||
name: "formMain", | |||
type: "page", | |||
title: "测试", | |||
template: "这里为空则" | |||
}, | |||
template: { | |||
type: "panel", | |||
name: "form", | |||
props: { | |||
direction: "col" | |||
}, | |||
children: [ | |||
//单据编辑 | |||
{ | |||
type: "panel", | |||
name: "header", //这里的header 无规律,样式不固定,由开发者自己布局,css样式必不可少,开发者写样式不建议写这里的话,该怎么写呢 | |||
props: { | |||
direction: "row", | |||
style:{ | |||
padding:'20px' //修改 增加样式, | |||
} | |||
}, | |||
children: [ | |||
{ | |||
type: "fxTitle", //修改 增加了title组件 | |||
name: "header_title", | |||
props: { | |||
title: "单据编辑", | |||
} | |||
}, | |||
{ | |||
type: "panel", // 这里的下拉框,由panel组件渲染,在这里直接放一个下拉框组件会不会好一点 | |||
name: "tool_left" | |||
}, | |||
{ | |||
type: "toolbar", | |||
name: "toolbar", | |||
props: { | |||
align:'right'// 修改,增加向右对齐 | |||
}, | |||
} | |||
] | |||
}, | |||
// 单据编号行 | |||
{ | |||
type: "panel", | |||
name: "panelHeader", | |||
props: { | |||
direction: "row", | |||
// colnum: 4, //修改 注释 | |||
style:{ | |||
padding:'20px', //修改 增加样式, | |||
gap:"50px" | |||
} | |||
} | |||
}, | |||
// 名册信息表单 | |||
{ | |||
type: "fxForm", //修改,把panel 改为 fxForm,表单单独做一个组件, 如果使用panel,model里的title属性,显示的位置,会不明确,想让panel只负责容器布局 | |||
name: "panelMain", | |||
props: { | |||
colnum: 2, | |||
divider:true | |||
} | |||
}, | |||
// 统计信息表格 | |||
{ | |||
type: "grid", | |||
name: "gridItem", | |||
props: { | |||
} | |||
} | |||
] | |||
}, | |||
model: { | |||
header_title:{ | |||
title: "单据编辑" | |||
}, | |||
//单据编辑下拉框 | |||
tool_left: { | |||
content: [ | |||
{ | |||
name: "f1", | |||
field: "d1.f1", | |||
type: "select", //修改 | |||
label: "", | |||
opts: [ | |||
{ | |||
label: "制单1", | |||
value: "zd1" | |||
}, | |||
{ | |||
label: "制单2", | |||
value: "zd2" | |||
} | |||
] | |||
} | |||
] | |||
}, | |||
//单据编辑按钮 | |||
toolbar: { | |||
content: [ | |||
{ | |||
name: "btnDel", | |||
label: "删除", | |||
type: "button", | |||
btn_type: "danger" | |||
}, | |||
{ | |||
name: "btnFlow", | |||
label: "流程跟踪", | |||
type: "button", | |||
btn_type: "warning" | |||
}, | |||
{ | |||
name: "btnList", | |||
label: "返回", | |||
type: "button" | |||
} | |||
] | |||
}, | |||
//单据编号 | |||
panelHeader: { | |||
content: [ | |||
{ | |||
name: "", | |||
type: "label", | |||
label: "单据编号", | |||
field: "masterTable.djbh" | |||
}, | |||
{ | |||
name: "", | |||
type: "label", | |||
label: "制单日期", | |||
field: "masterTable.djbh" | |||
}, | |||
{ | |||
name: "", | |||
type: "label", | |||
label: "编制单位", | |||
field: "masterTable.djbh" | |||
}, | |||
{ | |||
name: "", | |||
type: "label", | |||
label: "编制部门", | |||
field: "masterTable.djbh" | |||
} | |||
] | |||
}, | |||
// 名册信息 表单 | |||
panelMain: { | |||
title: "名册信息", | |||
content: [ | |||
{ | |||
name: "field1", | |||
type: "input", | |||
label: "单据编号", | |||
field: "masterTable.djbh", | |||
readonly: true | |||
}, | |||
{ | |||
name: "field2", | |||
type: "input", | |||
label: "单位", | |||
field: "masterTable.djbh", | |||
readonly: true | |||
}, | |||
{ | |||
name: "field3", | |||
type: "input", | |||
label: "资金科目", | |||
field: "masterTable.djbh" | |||
}, | |||
{ | |||
name: "field4", | |||
type: "input", | |||
label: "业务类型", | |||
field: "masterTable.djbh" | |||
}, | |||
{ | |||
name: "field4", | |||
type: "input", | |||
label: "业务月", | |||
field: "masterTable.djbh" | |||
}, | |||
{ | |||
name: "field4", | |||
type: "input", | |||
label: "制单日期", | |||
field: "masterTable.djbh" | |||
} | |||
] | |||
}, | |||
// 统计信息 表格 | |||
gridItem: { | |||
title: "统计信息", | |||
rownumbers: true, //序号,要不要叫index,element是叫index | |||
checkbox: true, //复选框 | |||
toolbar: [ | |||
{ | |||
name: "btnImp", | |||
label: "导入", | |||
type: "button", | |||
btn_type: "warning" | |||
}, | |||
{ | |||
name: "btnAddItem", | |||
label: "新增", | |||
type: "button", | |||
btn_type: "primary" | |||
} | |||
], | |||
optCol: [ | |||
{ | |||
name: "btnDetail", | |||
label: "详情", | |||
btn_type: "info" | |||
}, | |||
{ | |||
name: "btnDelItem", | |||
label: "删除", | |||
btn_type: "danger" | |||
} | |||
], | |||
filter: { | |||
}, | |||
fixedLeft: [ | |||
{} | |||
], | |||
fixedRight: [ | |||
{} | |||
], | |||
cols: [ | |||
{ | |||
name: "field1", | |||
label: "单位", | |||
field: "masterTable.djbh", | |||
width: 120, | |||
align: "left" | |||
}, | |||
{ | |||
name: "field1", | |||
label: "姓名", | |||
field: "masterTable.djbh", | |||
width: 80, | |||
align: "left" | |||
} | |||
] | |||
} | |||
} | |||
} | |||
], | |||
formCss: { | |||
header:{ | |||
className: "flex_left, div_width", //给组件添加类名,样式名在全局样式定义好,把定义好的样式名写文档给开发者 | |||
style: "width:80%;height:50px;", //开发者自定义样式 | |||
selfClass:[ | |||
{ | |||
name:'.div_width',//开发者自定义类名 | |||
content:'width:90%;border:1px;', | |||
} | |||
] | |||
} | |||
}, | |||
dataset: [ | |||
{ | |||
name: "masterTable", | |||
label: "主表", | |||
type: "表/视图/sql/json", | |||
rows: "单行/多行", | |||
opts: { | |||
表: { | |||
table: "表id" | |||
}, | |||
视图: { | |||
table: "视图id" | |||
}, | |||
sql: { | |||
sql: "查询sql" | |||
}, | |||
json: { | |||
type: "field/param/text", | |||
src: "table.field/param_name/XXX" | |||
} | |||
}, | |||
fields: [ | |||
{ | |||
name: "pt_id", | |||
field: "table.field", | |||
fieldType: "str/number/float" | |||
} | |||
], | |||
filter: { | |||
trigger: "click/change,默认为取值类型需要输入的click,其他为实时监控触发", | |||
fields: [ | |||
{ | |||
name: "pt_id", | |||
field: "table.field", | |||
fieldType: "str/number/float", | |||
sqlName: "ta.field1", | |||
valueType: "取值类型", | |||
trigger: "click/change,可不用,根据默认规则来" | |||
} | |||
], | |||
fixed: "固定条件,如:cpi_id=:id", | |||
dyn_动态条件树: { | |||
opt: "逻辑运算符:and/or", | |||
children: [ | |||
{ | |||
opt: "or", | |||
children: [ | |||
{ | |||
name: "对应filter的name", | |||
opt: "运算符:eq/gt/ge/lt/le/plike..." | |||
} | |||
] | |||
}, | |||
{ | |||
param: "fid182396b0dad", | |||
opt: "=" | |||
} | |||
] | |||
} | |||
}, | |||
sortFields: [ | |||
{ | |||
field: "pt_code", | |||
type: "asc" | |||
}, | |||
{ | |||
field: "pt_id", | |||
type: "asc" | |||
} | |||
] | |||
} | |||
], | |||
params: [ | |||
{ | |||
name: "参数名", | |||
type: "参数类型", | |||
value: "参数值" | |||
} | |||
] | |||
}; | |||
export default formData; | |||
// 示例:访问 form 数据 | |||
console.log(formData.form[0].page.title); // 输出: 测试 |
@@ -0,0 +1,69 @@ | |||
<template> | |||
<div> | |||
<!-- <div>123</div>--> | |||
<!-- <component :is="Comp"></component>--> | |||
<!-- 直接以函数的形式渲染组件--> | |||
<!-- <Comp :count="'展示props传参'">--> | |||
<!-- <div>使用函数组件插槽</div>--> | |||
<!-- <template #header>--> | |||
<!-- <div>具名插槽</div>--> | |||
<!-- </template>--> | |||
<!-- </Comp>--> | |||
<Comp2> | |||
<div>使用center组件的插槽</div> | |||
</Comp2> | |||
<!-- <center @onFoo="(val)=>{console.log(val)}"></center>--> | |||
<!-- <component :is="Comp3"></component>--> | |||
</div> | |||
</template> | |||
<script lang="ts" setup> | |||
import { compile } from '@vue/compiler-dom' | |||
import { defineComponent, resolveComponent, h, ref, type FunctionalComponent, onMounted } from 'vue' | |||
import * as Vue from 'vue' | |||
import Center from '../Center.vue' | |||
import PageOrDialog from '../PageOrDialog.vue' | |||
import Layout from '../Layout.vue' | |||
import Header from '../Header.vue' | |||
import Panel from '../Panel.vue' | |||
import Footer from '../Footer.vue' | |||
// h函数基础使用 | |||
// const comp = h('div', { style: 'color: red' }, 'Hello World') | |||
const components = { Layout, PageOrDialog, Header, Panel, Center, Footer } | |||
// 使用响应式变量 和 使用 子节点的嵌套,事件,属性,插槽的使用 | |||
const msg = ref('使用变量') | |||
// 注意这里是一个函数 FunctionalComponent:方法组件类型声明 | |||
// 这里是声明了一个函数组件,然后被使用 | |||
const Comp = ((props, { slots }) => { | |||
return h('div', { style: 'color: red', onClick () { msg.value = '点击了' } }, | |||
[ | |||
h('span', {}, msg.value), | |||
h('h1', {}, props.count), | |||
h('h1', {}, [slots?.header?.(), slots?.default?.()]) | |||
]) | |||
}) as FunctionalComponent<{ count:string }> | |||
// 这里是声明了一个函数组件,但是是使用的已经定义好的组件 | |||
const Comp2 = ((props, { slots }) => { | |||
return h(Center, { | |||
msg: '我是参数', | |||
// 事件传参 | |||
onFoo (val:any) { | |||
console.log(123123) | |||
console.log('点击了' + val) | |||
} | |||
}, { | |||
default: slots.default, | |||
// 这里在footer插槽里面又嵌套了Center组件继续使用插槽,递归组件 | |||
footer: () => h(Center, null, { | |||
default: () => h('div', {}, '我是footer插槽'), | |||
footer: ({ val }) => h('div', {}, val + '使用插槽传参数') | |||
}) | |||
}) | |||
}) as FunctionalComponent | |||
</script> | |||
<style scoped lang="less"> | |||
</style> |