Ver código fonte

低代码demo存档

main
张海 3 semanas atrás
pai
commit
7e6dd59b0c
27 arquivos alterados com 1604 adições e 317 exclusões
  1. +6
    -3
      babel.config.js
  2. +19
    -1
      src/views/HomeView.vue
  3. +3
    -3
      src/views/ddmDemo/Center.vue
  4. +2
    -2
      src/views/ddmDemo/Footer.vue
  5. +6
    -3
      src/views/ddmDemo/Header.vue
  6. +87
    -266
      src/views/ddmDemo/Index.vue
  7. +3
    -2
      src/views/ddmDemo/Layout.vue
  8. +46
    -37
      src/views/ddmDemo/Panel.vue
  9. +29
    -0
      src/views/ddmDemo/component/FxForm/FxForm.vue
  10. +76
    -0
      src/views/ddmDemo/component/FxForm/FxFormCard.vue
  11. +73
    -0
      src/views/ddmDemo/component/FxHeader/FxHeaderCard.vue
  12. +42
    -0
      src/views/ddmDemo/component/FxInput/FxInput.vue
  13. +45
    -0
      src/views/ddmDemo/component/FxTable/FxTable.vue
  14. +75
    -0
      src/views/ddmDemo/component/FxTable/FxTableCard.vue
  15. +28
    -0
      src/views/ddmDemo/component/FxTable/FxTableColumn/FxTableColumn.vue
  16. +42
    -0
      src/views/ddmDemo/component/fxButton/FxButton.vue
  17. +38
    -0
      src/views/ddmDemo/component/fxDivider/FxDivider.vue
  18. +68
    -0
      src/views/ddmDemo/component/fxSelect/FxSelect.vue
  19. +33
    -0
      src/views/ddmDemo/component/fxText/FxText.vue
  20. +17
    -0
      src/views/ddmDemo/component/fxText/FxTextCard.vue
  21. +3
    -0
      src/views/ddmDemo/component/fxTitle/FxTitle.css
  22. +59
    -0
      src/views/ddmDemo/component/fxTitle/FxTitle.vue
  23. +35
    -0
      src/views/ddmDemo/component/toolbar/toobar.vue
  24. +0
    -0
      src/views/ddmDemo/engine/pageEngine.ts
  25. +342
    -0
      src/views/ddmDemo/jsonData.js
  26. +358
    -0
      src/views/ddmDemo/jsonData2.js
  27. +69
    -0
      src/views/ddmDemo/study/hDemo.vue

+ 6
- 3
babel.config.js Ver arquivo

@@ -1,5 +1,8 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
'@vue/babel-plugin-jsx'
]
}

+ 19
- 1
src/views/HomeView.vue Ver arquivo

@@ -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 () {


+ 3
- 3
src/views/ddmDemo/Center.vue Ver arquivo

@@ -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>

+ 2
- 2
src/views/ddmDemo/Footer.vue Ver arquivo

@@ -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>

+ 6
- 3
src/views/ddmDemo/Header.vue Ver arquivo

@@ -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>

+ 87
- 266
src/views/ddmDemo/Index.vue Ver arquivo

@@ -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)


+ 3
- 2
src/views/ddmDemo/Layout.vue Ver arquivo

@@ -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>

+ 46
- 37
src/views/ddmDemo/Panel.vue Ver arquivo

@@ -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>

+ 29
- 0
src/views/ddmDemo/component/FxForm/FxForm.vue Ver arquivo

@@ -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>

+ 76
- 0
src/views/ddmDemo/component/FxForm/FxFormCard.vue Ver arquivo

@@ -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>

+ 73
- 0
src/views/ddmDemo/component/FxHeader/FxHeaderCard.vue Ver arquivo

@@ -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 }}: &nbsp; {{ 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>

+ 42
- 0
src/views/ddmDemo/component/FxInput/FxInput.vue Ver arquivo

@@ -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>

+ 45
- 0
src/views/ddmDemo/component/FxTable/FxTable.vue Ver arquivo

@@ -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>

+ 75
- 0
src/views/ddmDemo/component/FxTable/FxTableCard.vue Ver arquivo

@@ -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>

+ 28
- 0
src/views/ddmDemo/component/FxTable/FxTableColumn/FxTableColumn.vue Ver arquivo

@@ -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>

+ 42
- 0
src/views/ddmDemo/component/fxButton/FxButton.vue Ver arquivo

@@ -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>

+ 38
- 0
src/views/ddmDemo/component/fxDivider/FxDivider.vue Ver arquivo

@@ -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>

+ 68
- 0
src/views/ddmDemo/component/fxSelect/FxSelect.vue Ver arquivo

@@ -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>

+ 33
- 0
src/views/ddmDemo/component/fxText/FxText.vue Ver arquivo

@@ -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>

+ 17
- 0
src/views/ddmDemo/component/fxText/FxTextCard.vue Ver arquivo

@@ -0,0 +1,17 @@
<script lang="ts" setup>
import { defineComponent } from 'vue'

defineOptions({
name: 'FxTextCard'
})


</script>

<template>

</template>

<style scoped lang="less">

</style>

+ 3
- 0
src/views/ddmDemo/component/fxTitle/FxTitle.css Ver arquivo

@@ -0,0 +1,3 @@
h1{
font-size: 30px;
}

+ 59
- 0
src/views/ddmDemo/component/fxTitle/FxTitle.vue Ver arquivo

@@ -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>

+ 35
- 0
src/views/ddmDemo/component/toolbar/toobar.vue Ver arquivo

@@ -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
src/views/ddmDemo/engine/pageEngine.ts Ver arquivo


+ 342
- 0
src/views/ddmDemo/jsonData.js Ver arquivo

@@ -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

+ 358
- 0
src/views/ddmDemo/jsonData2.js Ver arquivo

@@ -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); // 输出: 测试

+ 69
- 0
src/views/ddmDemo/study/hDemo.vue Ver arquivo

@@ -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>

Carregando…
Cancelar
Salvar