diff --git a/src/components/DataStandard/WorkForm/Design/config/view.tsx b/src/components/DataStandard/WorkForm/Design/config/view.tsx index e3df59c370da7d3d5cbf6069109d8e37ae141532..865eeeae5dfb3f92001f23d87f043923351bcd8c 100644 --- a/src/components/DataStandard/WorkForm/Design/config/view.tsx +++ b/src/components/DataStandard/WorkForm/Design/config/view.tsx @@ -10,10 +10,29 @@ import Classify from './formRule/builder/classify'; import { fieldConvert, tryParseJson } from '@/utils/tools'; import { FullEntityColumns } from '@/config/column'; import { FieldModel } from '@/ts/base/model'; +import { IOpenModeValue } from '@/ts/base/schema'; interface IAttributeProps { current: IForm; notifyEmitter: Emitter; } +interface IOpenMode { + id: string; + text: string; + value: IOpenModeValue; +} + +const OPENMODE: IOpenMode[] = [ + { + id: 'general', + text: '通用', + value: 'general', + }, + { + id: 'ledger', + text: '总账', + value: 'ledger', + }, +]; const ViewConfig: React.FC = ({ notifyEmitter, current }) => { const isGroupView = current.directory.target.typeName == TargetType.Group; @@ -124,6 +143,18 @@ const ViewConfig: React.FC = ({ notifyEmitter, current }) => { showSpinButtons: true, }} /> + void; } const Index: React.FC = ({ form, directory, finished }) => { + const renderFormView = () => { + switch (form.options?.openMode) { + case 'ledger': + return ( + + ); + default: + return ; + } + }; const opentType = form.viewType ?? '表单'; switch (opentType) { case '表单': - return ; + return renderFormView(); case '图表': default: return
暂不支持视图类型: {opentType}
; diff --git a/src/executor/open/view/ledger/LedgerForm.tsx b/src/executor/open/view/ledger/LedgerForm.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1aa4bbc3943eb18ea70f67687eacabd8c7fac3fb --- /dev/null +++ b/src/executor/open/view/ledger/LedgerForm.tsx @@ -0,0 +1,778 @@ +import React, { memo, useMemo, useRef, useState, useEffect, useCallback } from 'react'; +import { command, schema, model } from '@/ts/base'; +import { IDirectory } from '@/ts/core'; +import FullScreenModal from '@/components/Common/fullScreen'; +import EntityIcon from '@/components/Common/GlobalComps/entityIcon'; +import { + Spin, + Empty, + Tabs, + Select, + Form as FormAntd, + DatePicker, + Space, + Button, + message, + Cascader, + Popover, + InputNumber, + Checkbox, + Table, +} from 'antd'; +import type { IForm } from '@/ts/core'; +import { Form } from '@/ts/core/thing/standard/form'; +import useAsyncLoad from '@/hooks/useAsyncLoad'; +import cls from './index.module.less'; +import { UploadOutlined, PrinterOutlined, UpOutlined } from '@ant-design/icons'; +import { CheckboxChangeEvent } from 'antd/es/checkbox'; +import saveAs from 'file-saver'; +import { Workbook } from 'exceljs'; + +interface IProps { + form: schema.XForm; + directory: IDirectory; + finished: () => void; +} +type ITabs = 'ledger' | 'detail' | 'sum'; + +interface IContents { + type: ITabs; +} +interface IOperate { + editData: schema.XThing[]; +} +interface IFilter { + onOk: (val: IFilterValue) => void; +} +interface IFilterValue { + subjectLevel: (number | null)[]; + show: boolean[]; +} + +const CHECKBOX = ['显示辅助核算', '余额为0 不显示', '无发生额且余额未 0 不显示']; +const options = [ + { + label: 'Light', + value: 'light', + children: new Array(20) + .fill(null) + .map((_, index) => ({ label: `Number ${index}`, value: index })), + }, + { + label: 'Bamboo', + value: 'bamboo', + children: [ + { + label: 'Little', + value: 'little', + children: [ + { + label: 'Toy Fish', + value: 'fish', + }, + { + label: 'Toy Cards', + value: 'cards', + }, + { + label: 'Toy Bird', + value: 'bird', + }, + ], + }, + ], + }, +]; + +const ledgerData = [ + { + key: 1, + name: '银行存款', + code: '余额宝', + period: '202406', + digest: '期间余额', + }, + { + key: 2, + name: '银行存款', + code: '支付宝', + period: '202406', + digest: '期间余额', + }, + { + key: 8, + name: '银行存款', + code: '余额宝', + period: '202406', + digest: '期间余额', + }, + { + key: 3, + name: '银行存款', + code: '余额宝', + period: '202406', + digest: '期间余额', + }, + { + key: 4, + name: '银行存款', + code: '余额宝', + period: '202406', + digest: '期间余额', + }, + { + key: 5, + name: '银行存款', + code: '支付宝', + period: '202406', + digest: '期间余额', + }, + { + key: 9, + name: '银行存款', + code: '1003', + period: '202406', + digest: '期间余额1', + }, + { + key: 6, + name: '银行存款', + code: '支付宝', + period: '202406', + digest: '期间余额', + }, + { + key: 7, + name: '银行存款', + code: '支付宝', + period: '202406', + digest: '期间余额', + }, +]; +const detailData = [ + { + key: 1, + year: 2024, + month: 4, + day: 5, + period: '上年结转', + debtor: '15,930.00', + }, + { + key: 2, + year: 2024, + month: 4, + day: 5, + period: '上年结转', + debtor: '15,930.00', + }, + { + key: 3, + year: 2024, + month: 4, + day: 5, + period: '上年结转', + debtor: '15,930.00', + }, + { + key: 4, + year: 2024, + month: 4, + day: 5, + period: '上年结转', + debtor: '15,930.00', + }, + { + key: 5, + year: 2024, + month: 4, + day: 5, + period: '上年结转', + debtor: '15,930.00', + }, + { + key: 6, + year: 2024, + month: 4, + day: 5, + period: '上年结转', + debtor: '15,930.00', + }, + { + key: 8, + year: 2024, + month: 4, + day: 5, + period: '上年结转', + debtor: '15,930.00', + }, +]; +const sumData = [ + { + key: 1, + code: '1002', + name: '银行存款', + debtor: '28,731,119.50', + credit: '0.00', + children: [ + { + code: '1001', + name: '科目一', + debtor: '1111', + credit: '0.00', + }, + { + code: '1002', + name: '科目二', + debtor: '1111', + credit: '0.00', + }, + ], + }, + { + key: 2, + code: '1002', + name: '银行存款', + debtor: '28,731,119.50', + credit: '0.00', + children: [ + { + code: '1001', + name: '科目一', + debtor: '1111', + credit: '0.00', + }, + { + code: '1002', + name: '科目二', + debtor: '1111', + credit: '0.00', + }, + ], + }, + { + key: 3, + code: '1002', + name: '银行存款', + debtor: '28,731,119.50', + credit: '0.00', + children: [ + { + code: '1001', + name: '科目一', + debtor: '1111', + credit: '0.00', + }, + { + code: '1002', + name: '科目二', + debtor: '1111', + credit: '0.00', + }, + ], + }, + { + key: 4, + code: '1002', + name: '银行存款', + debtor: '28,731,119.50', + credit: '0.00', + children: [ + { + code: '1001', + name: '科目一', + debtor: '1111', + credit: '0.00', + }, + { + code: '1002', + name: '科目二', + debtor: '1111', + credit: '0.00', + }, + ], + }, +]; +const LedgerForm = ({ finished, form, directory }: IProps) => { + const metaForm: IForm = new Form(form, directory); + const [fields, setFields] = useState([]); + const [loaded] = useAsyncLoad(async () => { + setFields(await metaForm.loadFields()); + }); + metaForm.fields = fields; + + const Filter: React.FC = ({ onOk }) => { + const defaultFilterValue = { + date: [], + subject: [], + subjectLevel: [], + show: [], + }; + const [filterValue, setFilterValue] = useState(defaultFilterValue); + const PopoverTitle: React.FC = () => { + const onSubjectChange = (idx: number, val: number | null) => { + const subjectLevel = [...filterValue.subjectLevel]; + subjectLevel[idx] = val; + setFilterValue({ + ...filterValue, + subjectLevel, + }); + }; + + const onCheckboxChange = (idx: number, e: CheckboxChangeEvent) => { + const show = [...filterValue.show]; + show[idx] = e.target.checked; + }; + + return ( +
+
+ 科目层次: + +  至  + +
+ + {CHECKBOX.map((val, idx) => { + return ( + + {val} + + ); + })} + +
+ ); + }; + const PopoverContent: React.FC = ({}) => { + const onReset = () => { + setFilterValue(defaultFilterValue); + }; + const onExtend = () => {}; + return ( +
+ + 收起筛选  + + +
+ + + + +
+
+ ); + }; + + const onValuesChange = (val) => { + onOk(val); + setFilterValue({ + ...filterValue, + ...val, + }); + }; + return ( + + + + + + + + + + } + content={} + trigger="click"> + + + + ); + }; + + const Operate: React.FC = ({ editData, form, mockField, mockData }) => { + const lock = useRef(false); + const colNumberToSeq = (n) => { + let seq = ''; + while (n > 1) { + const mod = (n - 1) % 26; + seq = String.fromCharCode(mod + 65) + seq; + n = (n - mod) / 26; + } + return seq; + }; + const onExport = async () => { + if (lock.current) { + message.error('正在导出数据,请稍后再试!'); + return; + } + lock.current = true; + try { + // e.component.beginCustomLoading('正在导出数据...'); + const workbook = new Workbook(); + const worksheet = workbook.addWorksheet(form?.name); + let cols = []; + const headerRow = []; + mockField.forEach((column, index) => { + if (column.children) { + headerRow.push({ + start: cols.length + 1, + value: column.title, + span: column.children.length, + }); + column.children.forEach((i) => { + cols.push({ header: i.title, key: i.dataIndex }); + }); + } else { + cols.push({ header: column.title, key: column.dataIndex }); + } + }); + worksheet.columns = cols; + const insertRow = []; + headerRow.forEach((i) => { + insertRow[i.start] = i.value; + }); + worksheet.insertRow(1, insertRow); + headerRow.forEach((i) => { + worksheet.mergeCells( + `${colNumberToSeq(i.start)}1:${colNumberToSeq(i.start + i.span - 1)}1`, + ); + }); + mockData.forEach((item: any) => { + if (item.children) { + worksheet.addRow(item); + item.children.forEach((i) => { + worksheet.addRow(i); + }); + } + }); + + workbook.xlsx.writeBuffer().then((buffer) => { + saveAs( + new Blob([buffer], { type: 'application/octet-stream' }), + (form?.name ?? '表单') + '.xlsx', + ); + }); + + // let skip = 0; + // let take = 500; + // let pass = true; + // while (pass) { + // let result: model.LoadResult = { + // data: [], + // groupCount: 0, + // summary: [], + // totalCount: 0, + // msg: '', + // success: true, + // code: 0, + // }; + // result = (await e.component + // .getDataSource() + // .store() + // .load({ skip, take, ...options, filter })) as any; + // if (result.data.length == 0 || !Array.isArray(result?.data)) { + // pass = false; + // break; + // } else { + // let data = result.data; + // data.forEach((item: any) => { + // for (const column of form.fields) { + // const valueMap = (column.lookup as any)?.valueMap; + // if (valueMap && column.dataField) { + // item[column.dataField] = valueMap[item[column.dataField]]; + // } + // } + // worksheet.addRow(item); + // }); + // skip += result.data.length; + // } + // workbook.xlsx.writeBuffer().then((buffer) => { + // saveAs( + // new Blob([buffer], { type: 'application/octet-stream' }), + // (form?.name ?? '表单') + '.xlsx', + // ); + // }); + // } + } finally { + lock.current = false; + } + }; + + const onPrint = () => { + if (!metaForm.metadata.print) return message.error('请先配置打印模板'); + if (editData.length === 0) return message.error('请选择需要打印的数据'); + command.emitter('executor', 'printEntity', metaForm, 'multiple', editData); + }; + return ( + + + + + ); + }; + + const Contents: React.FC = memo(({ type }) => { + const mergeCell = useCallback((dataIndex: string, values, index: number) => { + const value = values[dataIndex]; + const obj = { + rowSpan: 0, + }; + if (index > 0 && ledgerData[index - 1][dataIndex] === value) { + obj.rowSpan = 0; + } else { + let occurCount = 1; + let count = index; + while (true) { + if ( + count < ledgerData.length - 1 && + ledgerData[count + 1][dataIndex] === value + ) { + occurCount++; + count++; + } else { + break; + } + } + obj.rowSpan = occurCount; + } + return obj; + }, []); + + const columns = useMemo(() => { + const ledgerField = [ + { + title: '科目编码', + dataIndex: 'code', + onCell: mergeCell.bind(this, 'code'), + }, + { + title: '科目名称', + dataIndex: 'name', + onCell: mergeCell.bind(this, 'name'), + }, + { + title: '期间', + dataIndex: 'period', + }, + { + title: '摘要', + dataIndex: 'digest', + }, + ]; + const detailField = [ + { + title: '日期', + dataIndex: 'date', + children: [ + { + title: '年', + dataIndex: 'year', + key: 'year', + width: 150, + }, + { + title: '月', + dataIndex: 'month', + key: 'month', + width: 150, + }, + { + title: '日', + dataIndex: 'day', + key: 'day', + width: 150, + }, + ], + }, + { + title: '摘要', + dataIndex: 'period', + }, + { + title: '借方资金', + dataIndex: 'debtor', + }, + ]; + const sumField = [ + { + title: '科目编码', + dataIndex: 'code', + }, + { + title: '科目名称', + dataIndex: 'name', + }, + { + title: '期初金额', + dataIndex: 'sum', + children: [ + { + title: '借方', + dataIndex: 'debtor', + }, + { + title: '贷方', + dataIndex: 'credit', + }, + ], + }, + ]; + let column; + switch (type) { + case 'ledger': + column = ledgerField; + break; + case 'detail': + column = detailField; + break; + case 'sum': + column = sumField; + break; + default: + break; + } + return column; + }, []); + + const data = useMemo(() => { + let data; + switch (type) { + case 'ledger': + data = ledgerData; + break; + case 'detail': + data = detailData; + break; + case 'sum': + data = sumData; + break; + default: + break; + } + return data; + }, []); + + const editData: schema.XThing[] = []; + const onOk = (val: IFilterValue) => { + console.log(val, 'onOk'); + }; + return ( +
+
+ + +
+
+ { + return { + onMouseEnter: (event) => {}, + }; + }}>
+
+
+ ); + }); + + const FormBrower: React.FC = () => { + if (directory.spaceId !== directory.target.belongId) { + return ( + + ); + } + const selectOptions = useMemo(() => { + return directory.target.user.companys.map((company) => { + return { + id: company.belongId, + value: company.belongId, + label: company.name, + }; + }); + }, [directory.target.user.companys]); + return ( +
+