This commit is contained in:
2025-12-18 16:37:33 +08:00
commit e974bf361d
4183 changed files with 497339 additions and 0 deletions

View File

@@ -0,0 +1,252 @@
<script setup lang="ts">
import { onMounted, onUnmounted, reactive, ref, nextTick, createVNode, render, watch,computed, readonly } from 'vue'
import { Page } from '@vben/common-ui';
import { ElSplitter,ElSplitterPanel,ElCard } from 'element-plus';
import { useElementSize } from '@vueuse/core'
import { DbTree } from '#/components/db-tree';
import { DbHst } from '#/components/db-hst';
import { handleRowOperation, codeRenderer } from '#/components/db-hst/tree'
// import { sourceDataObject } from '#/components/db-hst/mockData'
const containerRef = ref<HTMLElement | null>(null)
const { height: containerHeight } = useElementSize(containerRef)
const topContainerRef = ref<HTMLElement | null>(null)
const { height: topContainerHeight } = useElementSize(topContainerRef)
const bottomContainerRef = ref<HTMLElement | null>(null)
const { height: bottomContainerHeight } = useElementSize(bottomContainerRef)
type Tree = { id: string; label: string; children?: Tree[] }
const categoryTreeData = ref<Tree[]>([
{
id: '1',
label: '行业总类',
children: [
{
id: '2',
label: '广东',
children: [
{ id: '3', label: '行业1' },
{ id: '4', label: '行业2' },
{ id: '5', label: '行业3' }
]
}
]
},
{
id: '11',
label: '行业2',
children: [
{
id: '12',
label: '广西',
children: [
{ id: '13', label: '行业5' },
{ id: '14', label: '行业6' },
{ id: '15', label: '行业7' }
]
}
]
}
])
const tagRenderer = (instance: any, td: HTMLElement, row: number, col: number, prop: string, value: any, cellProperties: any) => {
// 清空单元格内容
td.innerHTML = ''
td.style.padding = '4px'
td.style.overflow = 'visible'
// 获取当前单元格的标签数据
const getCurrentTags = (): string[] => {
const currentValue = instance.getDataAtCell(row, col)
// console.log(currentValue)
if (typeof currentValue === 'string') {
return currentValue ? currentValue.split(',').map(t => t.trim()).filter(t => t) : []
} else if (Array.isArray(currentValue)) {
return [...currentValue]
}
return []
}
// 创建容器
const container = document.createElement('div')
container.style.cssText = 'display: flex; flex-wrap: wrap; gap: 4px; align-items: center; min-height: 24px;'
// 渲染标签
const renderTags = () => {
const tags = getCurrentTags()
container.innerHTML = ''
tags.forEach((tag, index) => {
const tagEl = document.createElement('span')
tagEl.style.cssText = `
display: inline-flex;
align-items: center;
padding: 2px 8px;
background: #f0f0f0;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 12px;
gap: 4px;
`
tagEl.textContent = tag
// 删除按钮
const closeBtn = document.createElement('span')
closeBtn.innerHTML = '×'
closeBtn.style.cssText = `
cursor: pointer;
font-size: 14px;
font-weight: bold;
color: #999;
margin-left: 2px;
`
closeBtn.onmouseover = () => closeBtn.style.color = '#333'
closeBtn.onmouseout = () => closeBtn.style.color = '#999'
closeBtn.onclick = (e) => {
e.stopPropagation()
const currentTags = getCurrentTags()
currentTags.splice(index, 1)
instance.setDataAtCell(row, col, currentTags.join(','))
renderTags()
}
tagEl.appendChild(closeBtn)
container.appendChild(tagEl)
})
// 添加输入框
const inputWrapper = document.createElement('span')
inputWrapper.style.cssText = 'display: inline-flex; align-items: center;'
const input = document.createElement('input')
input.type = 'text'
input.placeholder = '按Enter回车键添加'
//border: 1px solid #d9d9d9;
input.style.cssText = `
border-radius: 4px;
padding: 2px 8px;
font-size: 12px;
outline: none;
width: 100%;
`
input.onfocus = () => {
input.style.borderColor = '#409eff'
}
input.onblur = () => {
input.style.borderColor = '#d9d9d9'
// 失去焦点时添加标签
if (input.value.trim()) {
const newTag = input.value.trim()
const currentTags = getCurrentTags()
console.log('添加前的标签:', currentTags)
if (!currentTags.includes(newTag)) {
currentTags.push(newTag)
console.log('添加后的标签:', currentTags)
instance.setDataAtCell(row, col, currentTags.join(','))
input.value = ''
renderTags()
} else {
input.value = ''
}
}
}
input.onkeydown = (e) => {
// 保留 Enter 键功能,按 Enter 也可以添加
if (e.key === 'Enter' && input.value.trim()) {
e.preventDefault()
input.blur() // 触发失去焦点事件
}
}
inputWrapper.appendChild(input)
container.appendChild(inputWrapper)
}
renderTags()
td.appendChild(container)
return td
}
const bottomColumns = ref<any[]>([
{type:'text',data:'code',title:'序号'},
{type:'text',data:'name',title:'名称'},
{type:'text',data:'content',title:'内容',width: 300, renderer: tagRenderer, readOnly:true},
{type:'text',data:'spec',title:'代码'},
])
// const colHeaders = ref<string[]>(topColHeaders)
const bottomHstRef = ref<any>(null)
const bootomMock = ()=>{
// 生成模拟数据
const mockData = Array.from({ length: 30 }, (_, index) => ({
code: `DTL${String(index + 1).padStart(6, '0')}`,
name: `明细项目${index + 1}`,
content: ``,
spec: `规格${index + 1}`,
}))
return mockData;
}
let bottomDbSettings = {
columns: bottomColumns.value,
}
const categoryHandleSelect = (node: Tree) => {
console.log('categoryhandleSelect',node)
}
const detailHandleSelect = (node: Tree) => {
// if (topHstRef.value && typeof topHstRef.value.loadData === 'function') {
// // console.log('hstData.value',hstData.value)
// // topHstRef.value.loadData(topHstData.value)
// }
}
function onBottomHeight(height: number){
if (bottomHstRef.value?.hotInstance) {
bottomHstRef.value.hotInstance.updateSettings({
height: height-15
})
bottomHstRef.value.loadData(bootomMock())
bottomHstRef.value.hotInstance.render()
console.log('onResizeEnd-bottomHstRef',height);
}
}
onMounted(() => {
setTimeout(() => {
onBottomHeight(bottomContainerHeight.value)
}, 200);
})
onUnmounted(() => {
})
</script>
<template>
<Page auto-content-height>
<ElSplitter >
<ElSplitterPanel collapsible size="15%" :min="200">
<ElCard class="w-full h-full border-radius-0" body-class="!p-0 h-full" ref="containerRef">
<DbTree :height="containerHeight" :data="categoryTreeData" @select="categoryHandleSelect" :defaultExpandedKeys="2" :search="false" />
</ElCard>
</ElSplitterPanel>
<ElSplitterPanel collapsible :min="200">
<ElCard class="w-full h-full border-radius-0" body-class="!p-0 h-full">
<DbHst ref="bottomHstRef" :settings="bottomDbSettings"></DbHst>
</ElCard>
</ElSplitterPanel>
</ElSplitter>
</Page>
</template>
<style lang="css">
</style>

View File

@@ -0,0 +1,129 @@
<script setup lang="ts">
import { onMounted, onUnmounted, reactive, ref, nextTick, createVNode, render, watch,computed, readonly } from 'vue'
import { Page } from '@vben/common-ui';
import { ElSplitter,ElSplitterPanel,ElCard,ElTabs,ElTabPane } from 'element-plus';
import { useElementSize } from '@vueuse/core'
import { DbTree } from '#/components/db-tree';
import { DbHst } from '#/components/db-hst';
import { handleRowOperation, codeRenderer } from '#/components/db-hst/tree'
// import { sourceDataObject } from '#/components/db-hst/mockData'
// 导入子组件
import FieldName from './unit/FieldName.vue'
import SubItem from './unit/SubItem.vue'
import MeasureItem from './unit/MeasureItem.vue'
import OtherItem from './unit/OtherItem.vue'
import UnitSummary from './unit/UnitSummary.vue'
import VariableSettings from './unit/VariableSettings.vue'
import MaterialField from './unit/MaterialField.vue'
const containerRef = ref<HTMLElement | null>(null)
const { height: containerHeight } = useElementSize(containerRef)
// const topContainerRef = ref<HTMLElement | null>(null)
// const { height: topContainerHeight } = useElementSize(topContainerRef)
// const bottomContainerRef = ref<HTMLElement | null>(null)
// const { height: bottomContainerHeight } = useElementSize(bottomContainerRef)
// const bottomPanelHeight = ref<number>(0)
type Tree = { id: string; label: string; children?: Tree[] }
const categoryTreeData = ref<Tree[]>([
{
id: '1',
label: '行业总类',
children: [
{
id: '2',
label: '广东',
children: [
{ id: '3', label: '行业1' },
{ id: '4', label: '行业2' },
{ id: '5', label: '行业3' }
]
}
]
},
{
id: '11',
label: '行业2',
children: [
{
id: '12',
label: '广西',
children: [
{ id: '13', label: '行业5' },
{ id: '14', label: '行业6' },
{ id: '15', label: '行业7' }
]
}
]
}
])
// const colHeaders = ref<string[]>(topColHeaders)
const activeTab = ref('fieldName')
const categoryHandleSelect = (node: Tree) => {
console.log('categoryhandleSelect',node)
}
const detailHandleSelect = (node: Tree) => {
// if (topHstRef.value && typeof topHstRef.value.loadData === 'function') {
// // console.log('hstData.value',hstData.value)
// // topHstRef.value.loadData(topHstData.value)
// }
}
onMounted(() => {
})
onUnmounted(() => {
})
</script>
<template>
<Page auto-content-height>
<!-- <DbHst ref="bottomHstRef" :settings="bottomDbSettings"></DbHst> -->
<ElSplitter >
<ElSplitterPanel collapsible size="15%" :min="200">
<ElCard class="w-full h-full border-radius-0" body-class="!p-0 h-full" ref="containerRef">
<DbTree :height="containerHeight" :data="categoryTreeData" @select="categoryHandleSelect" :defaultExpandedKeys="2" :search="false" />
</ElCard>
</ElSplitterPanel>
<ElSplitterPanel collapsible :min="200">
<ElCard class="w-full h-full border-radius-0" body-class="!p-0 h-full">
<ElTabs v-model="activeTab" type="border-card" class="h-full">
<ElTabPane label="字段名称" name="fieldName" lazy>
<FieldName :height="containerHeight"/>
</ElTabPane>
<ElTabPane label="分部分项" name="subItem" lazy>
<!-- <SubItem /> -->
<FieldName :height="containerHeight"/>
</ElTabPane>
<ElTabPane label="措施项目" name="measureItem" lazy>
<!-- <MeasureItem /> -->
<FieldName :height="containerHeight"/>
</ElTabPane>
<ElTabPane label="其他项目" name="otherItem" lazy>
<!-- <OtherItem /> -->
<FieldName :height="containerHeight"/>
</ElTabPane>
<ElTabPane label="单位汇总" name="unitSummary" lazy>
<!-- <UnitSummary /> -->
<FieldName :height="containerHeight"/>
</ElTabPane>
<ElTabPane label="变量设置" name="variableSettings" lazy>
<VariableSettings />
</ElTabPane>
<ElTabPane label="工料机字段" name="materialField" lazy>
<MaterialField />
</ElTabPane>
</ElTabs>
</ElCard>
</ElSplitterPanel>
</ElSplitter>
</Page>
</template>
<style lang="css">
.el-tabs--border-card>.el-tabs__content {
padding: 5px 0;
}
</style>

View File

@@ -0,0 +1,150 @@
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'
import { DbHst } from '#/components/db-hst'
import { handleRowOperation, codeRenderer } from '#/components/db-hst/tree'
const props = defineProps<{
height?: number
}>()
const hstRef = ref<any>(null)
const columns = ref<any[]>([
{ type: 'text', data: 'seq', title: '序', width: 40 },
{ type: 'text', data: 'code', title: '编码', renderer: codeRenderer },
{ type: 'text', data: 'category', title: '类别' },
{ type: 'text', data: 'name', title: '名称' },
{ type: 'text', data: 'feature', title: '项目特征' },
{ type: 'text', data: 'locked', title: '锁定' },
{ type: 'text', data: 'unitPrice', title: '综合单价' },
{ type: 'text', data: 'unit', title: '单位' },
{ type: 'text', data: 'quantity', title: '工程量' },
{ type: 'text', data: 'comprehensivePrice', title: '综合单价' },
{ type: 'text', data: 'totalPrice', title: '综合合价' },
{ type: 'text', data: 'remark', title: '备注' },
])
let rowSchema: any = {}
// 根据 columns 的 data 字段生成对象结构
columns.value.forEach((col: any) => {
if (col.data ) {
rowSchema[col.data] = null
}
})
const mockData = (() => {
const data: any[] = []
// 生成5个父级数据
for (let i = 1; i <= 5; i++) {
const parent = {
seq: `${i}`,
code: `CODE${String(i).padStart(6, '0')}`,
category: i % 3 === 0 ? '分部分项' : i % 3 === 1 ? '措施项目' : '其他项目',
name: `项目名称${i}`,
feature: `特征描述${i}`,
locked: i % 2 === 0 ? '是' : '否',
unitPrice: `${i * 100}`,
unit: 'm²',
quantity: `${i * 10}`,
comprehensivePrice: `${i * 100}`,
totalPrice: `${i * 1000}`,
remark: `备注${i}`,
level: String(i - 1),
__children: [] as any[]
}
// 为每个父级生成3-5个子级
const childCount = Math.floor(Math.random() * 3) + 3
for (let j = 1; j <= childCount; j++) {
const child = {
seq: `${i}.${j}`,
code: `CODE${String(i).padStart(6, '0')}-${String(j).padStart(3, '0')}`,
category: '子项',
name: `子项目${i}-${j}`,
feature: `子特征${j}`,
locked: '否',
unitPrice: `${j * 50}`,
unit: 'm²',
quantity: `${j * 5}`,
comprehensivePrice: `${j * 50}`,
totalPrice: `${j * 250}`,
remark: `子备注${j}`,
level: `${i - 1}.${j - 1}`,
__children: []
}
parent.__children.push(child)
}
data.push(parent)
}
return data
})()
const settings = {
data: mockData,
dataSchema: rowSchema,
colWidths: 120,
columns: columns.value,
rowHeaders: false,
nestedRows: true,
bindRowsWithHeaders: true,
contextMenu: {
items: {
custom_row_above: {
name: '在上方插入行',
callback: function() {
handleRowOperation(this, 'above')
}
},
custom_row_below: {
name: '在下方插入行',
callback: function() {
handleRowOperation(this, 'below')
}
},
separator1: '---------',
custom_add_child: {
name: '添加子行',
callback: function() {
handleRowOperation(this, 'child')
}
},
separator2: '---------',
remove_row: {
name: '删除行',
callback: function() {
handleRowOperation(this, 'delete')
}
},
// separator3: '---------',
// undo: {},
// redo: {}
}
},
}
watch(
() => props.height,
(newHeight) => {
console.log('MarketMaterials newHeight', newHeight)
if (newHeight && hstRef.value?.hotInstance) {
hstRef.value.hotInstance.updateSettings({
height: newHeight - 50 - 15// 减去 tabs 头部和 padding 的高度,滚动条
})
hstRef.value.hotInstance.render()
}
},
{ immediate: true }
)
onMounted(() => {
setTimeout(() => {
// if (hstRef.value) {
// hstRef.value.loadData(mockData)
// }
}, 100)
})
</script>
<template>
<div class="h-full">
<DbHst ref="hstRef" :settings="settings" />
</div>
</template>

View File

@@ -0,0 +1,36 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { DbHst } from '#/components/db-hst'
const hstRef = ref<any>(null)
const columns = ref<any[]>([
{ type: 'text', data: 'code', title: '序号' },
{ type: 'text', data: 'name', title: '字段名称' },
{ type: 'checkbox', data: 'unit', title: '分部分项隐藏' },
{ type: 'checkbox', data: 'price', title: '措施项目隐藏' },
])
const settings = {
columns: columns.value,
}
const mockData = Array.from({ length: 20 }, (_, index) => ({
code: `MAT${String(index + 1).padStart(6, '0')}`,
name: `工料机${index + 1}`,
unit: false,
price: false,
}))
onMounted(() => {
setTimeout(() => {
if (hstRef.value) {
hstRef.value.loadData(mockData)
}
}, 100)
})
</script>
<template>
<div class="h-full">
<DbHst ref="hstRef" :settings="settings" />
</div>
</template>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { DbHst } from '#/components/db-hst'
const hstRef = ref<any>(null)
const columns = ref<any[]>([
{ type: 'text', data: 'code', title: '编码' },
{ type: 'text', data: 'name', title: '措施项目名称' },
{ type: 'text', data: 'unit', title: '单位' },
{ type: 'text', data: 'amount', title: '金额' },
])
const settings = {
columns: columns.value,
}
const mockData = Array.from({ length: 20 }, (_, index) => ({
code: `MSR${String(index + 1).padStart(6, '0')}`,
name: `措施项目${index + 1}`,
unit: '项',
amount: `${(index + 1) * 1000}`,
}))
onMounted(() => {
setTimeout(() => {
if (hstRef.value) {
hstRef.value.loadData(mockData)
}
}, 100)
})
</script>
<template>
<div class="h-full">
<DbHst ref="hstRef" :settings="settings" />
</div>
</template>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { DbHst } from '#/components/db-hst'
const hstRef = ref<any>(null)
const columns = ref<any[]>([
{ type: 'text', data: 'code', title: '编码' },
{ type: 'text', data: 'name', title: '其他项目名称' },
{ type: 'text', data: 'type', title: '类型' },
{ type: 'text', data: 'amount', title: '金额' },
])
const settings = {
columns: columns.value,
}
const mockData = Array.from({ length: 20 }, (_, index) => ({
code: `OTH${String(index + 1).padStart(6, '0')}`,
name: `其他项目${index + 1}`,
type: '其他',
amount: `${(index + 1) * 500}`,
}))
onMounted(() => {
setTimeout(() => {
if (hstRef.value) {
hstRef.value.loadData(mockData)
}
}, 100)
})
</script>
<template>
<div class="h-full">
<DbHst ref="hstRef" :settings="settings" />
</div>
</template>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { DbHst } from '#/components/db-hst'
const hstRef = ref<any>(null)
const columns = ref<any[]>([
{ type: 'text', data: 'code', title: '编码' },
{ type: 'text', data: 'name', title: '项目名称' },
{ type: 'text', data: 'unit', title: '单位' },
{ type: 'text', data: 'quantity', title: '工程量' },
])
const settings = {
columns: columns.value,
}
const mockData = Array.from({ length: 20 }, (_, index) => ({
code: `SUB${String(index + 1).padStart(6, '0')}`,
name: `分部分项${index + 1}`,
unit: 'm²',
quantity: `${(index + 1) * 10}`,
}))
onMounted(() => {
setTimeout(() => {
if (hstRef.value) {
hstRef.value.loadData(mockData)
}
}, 100)
})
</script>
<template>
<div class="h-full">
<DbHst ref="hstRef" :settings="settings" />
</div>
</template>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { DbHst } from '#/components/db-hst'
const hstRef = ref<any>(null)
const columns = ref<any[]>([
{ type: 'text', data: 'category', title: '类别' },
{ type: 'text', data: 'count', title: '数量' },
{ type: 'text', data: 'totalAmount', title: '合计金额' },
{ type: 'text', data: 'remark', title: '备注' },
])
const settings = {
columns: columns.value,
}
const mockData = [
{ category: '分部分项', count: '50', totalAmount: '500000', remark: '' },
{ category: '措施项目', count: '20', totalAmount: '100000', remark: '' },
{ category: '其他项目', count: '10', totalAmount: '50000', remark: '' },
{ category: '合计', count: '80', totalAmount: '650000', remark: '' },
]
onMounted(() => {
setTimeout(() => {
if (hstRef.value) {
hstRef.value.loadData(mockData)
}
}, 100)
})
</script>
<template>
<div class="h-full">
<DbHst ref="hstRef" :settings="settings" />
</div>
</template>

View File

@@ -0,0 +1,267 @@
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'
import { ElDialog, ElTable, ElTableColumn, ElButton, ElTabs, ElTabPane, ElInput, ElSegmented } from 'element-plus'
import { DbHst } from '#/components/db-hst'
import { handleRowOperation, codeRenderer } from '#/components/db-hst/tree'
const props = defineProps<{
height?: number
}>()
const hstRef = ref<any>(null)
const dialogVisible = ref(false)
const activeTab = ref('global')
const currentRowData = ref<any>(null)
const formulaInput = ref('')
// 各个 Tab 的表格数据
const tabTableData = ref({
global: [
{ seq: '1', code: 'GF001', name: '全局费用1', value: '100' },
{ seq: '2', code: 'GF002', name: '全局费用2', value: '200' },
],
division: [
{ seq: '1', code: 'FB001', name: '分部分项1', value: '150' },
{ seq: '2', code: 'FB002', name: '分部分项2', value: '250' },
],
measure: [
{ seq: '1', code: 'CS001', name: '措施项目1', value: '180' },
{ seq: '2', code: 'CS002', name: '措施项目2', value: '280' },
],
other: [
{ seq: '1', code: 'QT001', name: '其他项目1', value: '120' },
{ seq: '2', code: 'QT002', name: '其他项目2', value: '220' },
],
supplement: [
{ seq: '1', code: 'BC001', name: '补充费用1', value: '160' },
{ seq: '2', code: 'BC002', name: '补充费用2', value: '260' },
],
})
const dialogRenderer = (instance: any, td: HTMLElement, row: number, col: number, prop: string, value: any, cellProperties: any) => {
td.innerHTML = ''
td.style.position = 'relative'
td.style.padding = '0 8px'
// 创建文本容器
const textSpan = document.createElement('span')
textSpan.textContent = value || ''
textSpan.style.display = 'inline-block'
textSpan.style.verticalAlign = 'middle'
textSpan.style.maxWidth = 'calc(100% - 24px)'
textSpan.style.overflow = 'hidden'
textSpan.style.textOverflow = 'ellipsis'
textSpan.style.whiteSpace = 'nowrap'
// 创建图标按钮
const iconBtn = document.createElement('span')
iconBtn.innerHTML = '⚙️'
iconBtn.style.cursor = 'pointer'
iconBtn.style.marginLeft = '4px'
iconBtn.style.fontSize = '14px'
iconBtn.style.verticalAlign = 'middle'
iconBtn.style.float = 'right'
iconBtn.addEventListener('click', (e) => {
e.stopPropagation()
const rowData = instance.getSourceDataAtRow(instance.toPhysicalRow(row))
currentRowData.value = rowData
dialogVisible.value = true
})
td.appendChild(textSpan)
td.appendChild(iconBtn)
return td
}
const columns = ref<any[]>([
{ type: 'text', data: 'seq', title: '序', width: 40 },
{ type: 'text', data: 'name', title: '费用名称', renderer: codeRenderer },
{ type: 'text', data: 'spec', title: '费用代码', width: 300,renderer: dialogRenderer },
{ type: 'text', data: 'cardinal', title: '计算基数(用户端不显示)', width: 200 },
])
let rowSchema: any = {}
// 根据 columns 的 data 字段生成对象结构
columns.value.forEach((col: any) => {
if (col.data ) {
rowSchema[col.data] = null
}
})
const mockData = (() => {
const data: any[] = []
// 生成5个父级数据
for (let i = 1; i <= 5; i++) {
const parent: any = {
seq: `${i}`,
name: `费用名称${i}`,
spec: `SPEC${String(i).padStart(3, '0')}`,
cardinal: `基数${i}`,
__children: [] as any[]
}
// 为每个父级生成3-5个子级
const childCount = Math.floor(Math.random() * 3) + 3
for (let j = 1; j <= childCount; j++) {
const child: any = {
seq: `${i}.${j}`,
name: `子费用${i}-${j}`,
spec: `SPEC${String(i).padStart(3, '0')}-${String(j).padStart(2, '0')}`,
cardinal: `子基数${i}-${j}`,
__children: []
}
parent.__children.push(child)
}
data.push(parent)
}
return data
})()
const settings = {
data: mockData,
dataSchema: rowSchema,
colWidths: 120,
columns: columns.value,
rowHeaders: false,
nestedRows: true,
bindRowsWithHeaders: true,
contextMenu: {
items: {
custom_row_above: {
name: '在上方插入行',
callback: function() {
handleRowOperation(this, 'above')
}
},
custom_row_below: {
name: '在下方插入行',
callback: function() {
handleRowOperation(this, 'below')
}
},
separator1: '---------',
custom_add_child: {
name: '添加子行',
callback: function() {
handleRowOperation(this, 'child')
}
},
separator2: '---------',
remove_row: {
name: '删除行',
callback: function() {
handleRowOperation(this, 'delete')
}
},
// separator3: '---------',
// undo: {},
// redo: {}
}
},
}
watch(
() => props.height,
(newHeight) => {
console.log('MarketMaterials newHeight', newHeight)
if (newHeight && hstRef.value?.hotInstance) {
hstRef.value.hotInstance.updateSettings({
height: newHeight - 50 - 15// 减去 tabs 头部和 padding 的高度,滚动条
})
hstRef.value.hotInstance.render()
}
},
{ immediate: true }
)
const value = ref('分部分项???')
const options = ['分部分项???', '措施项目???', '其他项目???', '单位汇总???']
onMounted(() => {
setTimeout(() => {
// if (hstRef.value) {
// hstRef.value.loadData(mockData)
// }
}, 100)
})
</script>
<template>
<div class="w-full h-full">
<div class="flex flex-col items-start gap-4">
<ElSegmented v-model="value" :options="options" size="large" />
</div>
<DbHst ref="hstRef" :settings="settings" />
<!-- 弹窗 -->
<ElDialog v-model="dialogVisible" title="费用代码设置" width="60%" :close-on-click-modal="false">
<div style="margin-bottom: 16px;">
<div style="color: #909399; font-size: 13px; margin-bottom: 8px;">
提示: 现在书写的公式只能调用在当前项目以前的取费和系统参数
</div>
<ElInput
v-model="formulaInput"
placeholder="请输入公式"
clearable
/>
</div>
<ElTabs v-model="activeTab">
<ElTabPane label="全局费用" name="global">
<ElTable :data="tabTableData.global" border style="width: 100%" max-height="400">
<ElTableColumn prop="seq" label="序号" width="80" />
<ElTableColumn prop="code" label="费用代号" width="150" />
<ElTableColumn prop="name" label="费用名称" min-width="200" />
<ElTableColumn prop="value" label="值" width="120" />
</ElTable>
</ElTabPane>
<ElTabPane label="分部分项" name="division">
<ElTable :data="tabTableData.division" border style="width: 100%" max-height="400">
<ElTableColumn prop="seq" label="序号" width="80" />
<ElTableColumn prop="code" label="费用代号" width="150" />
<ElTableColumn prop="name" label="费用名称" min-width="200" />
<ElTableColumn prop="value" label="值" width="120" />
</ElTable>
</ElTabPane>
<ElTabPane label="措施项目" name="measure">
<ElTable :data="tabTableData.measure" border style="width: 100%" max-height="400">
<ElTableColumn prop="seq" label="序号" width="80" />
<ElTableColumn prop="code" label="费用代号" width="150" />
<ElTableColumn prop="name" label="费用名称" min-width="200" />
<ElTableColumn prop="value" label="值" width="120" />
</ElTable>
</ElTabPane>
<ElTabPane label="其他项目" name="other">
<ElTable :data="tabTableData.other" border style="width: 100%" max-height="400">
<ElTableColumn prop="seq" label="序号" width="80" />
<ElTableColumn prop="code" label="费用代号" width="150" />
<ElTableColumn prop="name" label="费用名称" min-width="200" />
<ElTableColumn prop="value" label="值" width="120" />
</ElTable>
</ElTabPane>
<ElTabPane label="补充费用" name="supplement">
<ElTable :data="tabTableData.supplement" border style="width: 100%" max-height="400">
<ElTableColumn prop="seq" label="序号" width="80" />
<ElTableColumn prop="code" label="费用代号" width="150" />
<ElTableColumn prop="name" label="费用名称" min-width="200" />
<ElTableColumn prop="value" label="值" width="120" />
</ElTable>
</ElTabPane>
</ElTabs>
<template #footer>
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="dialogVisible = false">确定</ElButton>
</template>
</ElDialog>
</div>
</template>