From 63514476d777bd6dd6136f96d6c7cf752b494ee2 Mon Sep 17 00:00:00 2001 From: oneao Date: Mon, 14 Sep 2026 22:30:13 +0800 Subject: [PATCH] 20260914223013 --- code/fms/FMS业务表设计.md | 440 ++++++- code/fms/FMS新系统核心表结构设计.md | 88 ++ .../tools/migration/FieldNameSync.java | 93 +- .../tools/migration/OtherDataMigrate.java | 362 ++++++ .../OtherDataMigration$OldBmflEntry.class | Bin 436 -> 0 bytes .../OtherDataMigration$TableMapping.class | Bin 442 -> 0 bytes .../tools/migration/OtherDataMigration.class | Bin 34308 -> 0 bytes .../tools/migration/OtherDataMigration.java | 1025 ----------------- .../tools/migration/OtherDataProbe.java | 367 ++++++ code/fms/fms-api/tools/migration/README.md | 38 +- .../fms-api/tools/migration/RunSqlFile.java | 93 ++ .../tools/migration/file-tables-out.txt | 2 + .../tools/migration/menu-probe-out.txt | 111 ++ .../tools/migration/module-tree-out.txt | 92 ++ .../tools/migration/otherdata-columns.txt | 261 +++++ .../tools/migration/otherdata-id-map.tsv | 556 +++++++++ .../tools/migration/otherdata-modules.txt | 81 ++ .../tools/migration/otherdata-probe-out.txt | 837 ++++++++++++++ .../fms-module-list/FmsQueryToolbar.vue | 9 +- .../src/components/fms-tree/FmsTree.vue | 2 + .../fms-vue/src/components/ui/demo/modal.vue | 21 +- .../fms-vue/src/components/ui/demo/space.vue | 158 +++ code/fms/fms-vue/src/components/ui/index.js | 4 + .../src/components/ui/modal/modal-confirm.js | 37 + .../src/components/ui/modal/modal-confirm.vue | 84 ++ .../fms-vue/src/components/ui/modal/modal.vue | 110 +- .../src/components/ui/space/index.scss | 45 + .../fms-vue/src/components/ui/space/space.vue | 128 ++ .../fms-vue/src/components/ui/tree/index.scss | 1 + .../src/components/ui/tree/tree-node.vue | 16 +- code/fms/fms-vue/src/router/routes.js | 44 +- .../fms-vue/src/views/base/contact/detail.vue | 22 + .../fms-vue/src/views/base/contact/index.vue | 118 +- .../base/othercompany/CategoryEditModal.vue | 147 --- .../base/othercompany/CategoryTreePanel.vue | 247 ---- .../src/views/base/othercompany/detail.vue | 5 +- .../src/views/base/othercompany/index.vue | 665 ++++++++--- .../src/views/base/othercompany/utils.js | 131 --- .../src/views/base/otherdata/index.vue | 479 +++++++- .../module/menu-management/MenuBasicPanel.vue | 78 +- .../module/menu-management/MenuTreePanel.vue | 23 +- .../menu-management/ModulePickerModal.vue | 81 ++ .../views/module/menu-management/index.vue | 133 ++- .../src/views/module/menu-management/utils.js | 1 - .../ModuleQueryConfigPanel.vue | 15 +- .../design-editor/FormDesignEditor.vue | 11 +- .../design-editor/TableDesignEditor.vue | 51 +- .../design-editor/common/FieldLibrary.vue | 10 +- .../common/useStructureEditing.js | 17 +- .../tests/components/modal-confirm.spec.js | 108 ++ .../fms-vue/tests/components/space.spec.js | 92 ++ .../tests/unit/module-list-components.spec.js | 33 + .../tests/unit/othercompany-utils.spec.js | 80 +- .../tests/views/menu-module-binding.spec.js | 195 ++++ .../fms-vue/tests/views/othercompany.spec.js | 52 +- code/fms/sql/fms_business_contact.sql | 127 ++ code/fms/sql/fms_business_othercompany.sql | 4 +- code/fms/sql/fms_business_otherdata.sql | 155 +++ code/fms/sql/fms_module_contact.sql | 82 ++ code/fms/sql/fms_module_otherdata.sql | 215 ++++ 60 files changed, 6478 insertions(+), 2004 deletions(-) create mode 100644 code/fms/fms-api/tools/migration/OtherDataMigrate.java delete mode 100644 code/fms/fms-api/tools/migration/OtherDataMigration$OldBmflEntry.class delete mode 100644 code/fms/fms-api/tools/migration/OtherDataMigration$TableMapping.class delete mode 100644 code/fms/fms-api/tools/migration/OtherDataMigration.class delete mode 100644 code/fms/fms-api/tools/migration/OtherDataMigration.java create mode 100644 code/fms/fms-api/tools/migration/OtherDataProbe.java create mode 100644 code/fms/fms-api/tools/migration/RunSqlFile.java create mode 100644 code/fms/fms-api/tools/migration/file-tables-out.txt create mode 100644 code/fms/fms-api/tools/migration/menu-probe-out.txt create mode 100644 code/fms/fms-api/tools/migration/module-tree-out.txt create mode 100644 code/fms/fms-api/tools/migration/otherdata-columns.txt create mode 100644 code/fms/fms-api/tools/migration/otherdata-id-map.tsv create mode 100644 code/fms/fms-api/tools/migration/otherdata-modules.txt create mode 100644 code/fms/fms-api/tools/migration/otherdata-probe-out.txt create mode 100644 code/fms/fms-vue/src/components/ui/demo/space.vue create mode 100644 code/fms/fms-vue/src/components/ui/modal/modal-confirm.js create mode 100644 code/fms/fms-vue/src/components/ui/modal/modal-confirm.vue create mode 100644 code/fms/fms-vue/src/components/ui/space/index.scss create mode 100644 code/fms/fms-vue/src/components/ui/space/space.vue create mode 100644 code/fms/fms-vue/src/views/base/contact/detail.vue delete mode 100644 code/fms/fms-vue/src/views/base/othercompany/CategoryEditModal.vue delete mode 100644 code/fms/fms-vue/src/views/base/othercompany/CategoryTreePanel.vue delete mode 100644 code/fms/fms-vue/src/views/base/othercompany/utils.js create mode 100644 code/fms/fms-vue/src/views/module/menu-management/ModulePickerModal.vue create mode 100644 code/fms/fms-vue/tests/components/modal-confirm.spec.js create mode 100644 code/fms/fms-vue/tests/components/space.spec.js create mode 100644 code/fms/fms-vue/tests/views/menu-module-binding.spec.js create mode 100644 code/fms/sql/fms_business_contact.sql create mode 100644 code/fms/sql/fms_business_otherdata.sql create mode 100644 code/fms/sql/fms_module_contact.sql create mode 100644 code/fms/sql/fms_module_otherdata.sql diff --git a/code/fms/FMS业务表设计.md b/code/fms/FMS业务表设计.md index 70915b1d..f0290fe7 100644 --- a/code/fms/FMS业务表设计.md +++ b/code/fms/FMS业务表设计.md @@ -93,9 +93,10 @@ create index ix_b_othercompany_bmfl_parent create index ix_b_othercompany_bmfl_path on dbo.b_othercompany_bmfl (b_path, b_canuse, b_id); +-- 注:b_grade 由「其他数据」迁移重建为雪花主键(原为级别编码) create table dbo.b_grade ( - b_id varchar(50) not null primary key, - b_name nvarchar(50) null, + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 级别名称 b_i18n varchar(150) null, b_canuse tinyint not null default 1, b_xh int not null default 0, @@ -106,9 +107,10 @@ create table dbo.b_grade ( b_updated_at datetime2 null ); +-- 注:b_from 由「其他数据」迁移重建为雪花主键(原为来源编码) create table dbo.b_from ( - b_id varchar(50) not null primary key, - b_name nvarchar(50) null, + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 来源名称 b_i18n varchar(150) null, b_canuse tinyint not null default 1, b_xh int not null default 0, @@ -152,3 +154,433 @@ select o.b_id, o.b_ywid, o.b_pycode, o.b_type, o.b_name, o.b_shortname, from dbo.b_othercompany o left join dbo.b_user u on u.b_id = o.b_owner_id; ``` + +## 联系人 + +```sql +create table dbo.b_contact ( + b_id bigint not null primary key, + b_ywid varchar(50) not null, + b_name_ch nvarchar(50) null, + b_name_en nvarchar(50) null, + b_sex nvarchar(50) null, + b_birthday date null, + b_duty nvarchar(50) null, + b_departmentname nvarchar(50) null, + b_phone nvarchar(50) null, + b_mobilephone nvarchar(50) null, + b_fax nvarchar(50) null, + b_email varchar(50) null, + b_homephone nvarchar(50) null, + b_homeaddr nvarchar(255) null, + b_taste nvarchar(50) null, + b_habit nvarchar(50) null, + b_homesituation nvarchar(50) null, + b_picture varchar(500) null, + b_cate_id varchar(50) null, + b_type1_id varchar(50) null, + b_customer_id bigint null, + b_owner_id varchar(50) null, + b_isdefault tinyint not null default 0, + b_showcolor int null, + b_htbegindate date null, + b_htenddate date null, + b_state varchar(50) null, + b_bz nvarchar(1000) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create unique index ux_b_contact_ywid on dbo.b_contact (b_ywid); +create index ix_b_contact_customer on dbo.b_contact (b_customer_id, b_id); +create index ix_b_contact_name on dbo.b_contact (b_name_ch, b_id); + +create table dbo.b_contact_type ( + b_id varchar(50) not null primary key, + b_name nvarchar(50) null, + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create or alter view dbo.v_b_contact as +select c.b_id, c.b_ywid, c.b_name_ch, c.b_name_en, c.b_sex, c.b_phone, + c.b_mobilephone, c.b_fax, c.b_email, + c.b_duty, c.b_homephone, c.b_cate_id, c.b_homeaddr, c.b_bz, + c.b_departmentname, c.b_picture, + c.b_customer_id, c.b_owner_id, c.b_isdefault, + c.b_taste, c.b_habit, c.b_homesituation, + u.b_name as v_ownername, + d.b_name as v_ownerdepartment, + c.b_showcolor, + o.b_name as v_customer_name, + c.b_birthday, + case when isnull(c.b_name_ch, '') = '' then c.b_name_en + when isnull(c.b_name_en, '') = '' then c.b_name_ch + else isnull(c.b_name_ch, '') + isnull(c.b_name_en, '') end as b_name, + c.b_type1_id, + c.b_htbegindate, c.b_htenddate, + c.b_created_by, c.b_created_at, c.b_updated_by, c.b_updated_at, + c.b_state +from dbo.b_contact c + left join dbo.b_othercompany o on o.b_id = c.b_customer_id + left join dbo.b_user u on u.b_id = c.b_owner_id + left join dbo.b_dept d on d.b_id = u.b_dept_id +where isnull(o.b_ywid, '') <> 'b_employee'; +``` + +## 其他数据(base_otherdata) + +> 数据来源:旧库 `b_other_bmfl`(65 条模块清单,每条对应一张数据表)。 +> 其中 3 张已在「往来单位」迁移中建过(`b_othercompany_partner_type`、`b_from`、`b_grade`): +> `b_from`、`b_grade` 随本次迁移**重建为纯雪花**(见下),`b_othercompany_partner_type` 保持编码主键 +> (树形分类,由 othercompany 页面自研维护)。 +> 本次待迁移 **62 张表**(启用 46 张)、数据合计 572 行;清单见 `fms-api/tools/migration/otherdata-modules.txt`。 +> 新版不建 `b_other_bmfl` 表;模块树为三层:`base_otherdata`(其他数据,根)→ 6 个分组 +> (常用 / 系统 / 仓库 / 物流 / 铁运 / 空运,`b_module_type = 'module'`)→ 62 个数据模块(`data`)。 +> 数据模块编码 = 表名(如 `b_port`),`b_view_table` / `b_save_table` 都指向表本身: +> 字典表直接查表,不建 `v_` 直通视图(只有需要 join / 计算列的模块才用视图,如 `v_b_othercompany`)。 +> 模块顺序 `b_xh` 按旧库「分组 + 组内序号」连续生成,保持原有排列(常用在前)。 +> +> **主键模式**:`b_id` 为雪花主键(新增行由前端 `nextIdApi` 生成,通用列表组件的主键列只读)。 +> 旧编号(`001`、`002` 等流水号)不保留 —— 它们没有业务含义,对外交换另有 `b_edicode` 等字段; +> 将来迁移引用这些字典的业务表时,按「旧编号 → 新雪花」映射替换字段值(映射由迁移脚本生成并留档)。 + +### `b_from` / `b_grade` 重建与引用转换 + +这两张表在「往来单位」迁移时按编码主键建好,随本次迁移改为纯雪花: + +1. 备份旧行(旧 `b_id` + `b_name`)→ 重建表(雪花主键)→ 重导数据(`IdGenerator` 生成雪花); +2. 引用它们的字段按「名称」映射转换为新雪花: + - `b_othercompany.b_from_id`(客户来源) + - `b_othercompany.b_type_id`(客户级别) +3. `b_othercompany_partner_type` 保持编码主键不动(树形分类,由 othercompany 页面自研维护)。 + +### 字段转换规则 + +| 旧字段 | 新字段 | 说明 | +| --- | --- | --- | +| `b_id` varchar(50) 主键 | —(不保留) | 旧编号是流水号,无业务含义;引用方迁移时按映射替换为雪花 | +| —(新生成) | `b_id` bigint 主键 | 雪花,前端新增时自动生成 | +| `b_name` / `b_name_c` | `b_name` nvarchar(50) | 名称统一为 `b_name` | +| `b_name_e` | `b_name_e` nvarchar(50) | 英文名保留 | +| `b_bz` varchar(n) | `b_bz` nvarchar(200) | 备注改 nvarchar | +| `b_default` / `b_tz` / `b_isconvert` 等 varchar(1) | tinyint not null default 0 | 布尔标志按 0/1 | +| `b_canuse` varchar(1) | `b_canuse` tinyint not null default 1 | 按规范 | +| `b_xh` int | `b_xh` int not null default 0 | 按规范 | +| `b_inputuser_id` / `b_inputdatetime` / `b_updateuser_id` / `b_updatedatetime` | `b_created_by` / `b_created_at` / `b_updated_by` / `b_updated_at` | 审计字段,datetime → datetime2 | +| 编码 / EDI 代码 / 状态类字段 | 类型保留 varchar | | +| — | `b_i18n` varchar(150) | 新增多语言资源键 | + +### 常用(旧分组「1.常用」,9 张) + +```sql +create table dbo.b_feetype ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_name_e nvarchar(50) null, -- 英文名 + b_default tinyint not null default 0, -- 默认类别(0/1) + b_amount decimal(18,2) null, -- 默认金额 + b_tax decimal(18,4) null, -- 税额/税率 + b_money_id varchar(50) null, -- 币种(b_money.b_id,雪花) + b_i18n varchar(150) null, -- 多语言资源键 + b_canuse tinyint not null default 1, -- 是否启用(0/1) + b_xh int not null default 0, -- 显示顺序 + b_bz nvarchar(200) null, -- 备注 + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_oceanline ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_edicode varchar(50) null, -- EDI 代码 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_goodssource ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_dailyfeetype ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_dailytype ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_ywtype ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_ysfs ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_port ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称(原 b_name_c) + b_name_e nvarchar(50) null, -- 英文名 + b_country nvarchar(50) null, -- 国家 + b_oceanline varchar(50) null, -- 所属航线(b_oceanline.b_id,雪花) + b_edicode varchar(50) null, -- EDI 代码 + b_tz tinyint not null default 0, -- 标志位(0/1,待确认含义) + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_money ( + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_edicode varchar(50) null, -- EDI 代码 + b_hl decimal(18,4) null, -- 汇率 + b_symbol nvarchar(50) null, -- 货币符号 + b_isconvert tinyint not null default 0, -- 是否参与折算(0/1) + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); +``` + +### 系统(旧分组「2.系统」,35 张) + +其中 29 张结构完全一致(`b_id` 雪花主键、`b_name`、`b_i18n`、`b_canuse`、`b_xh`、`b_bz`、审计四字段),按下面这个模板建(表名与注释替换即可): + +```sql +create table dbo.b_cargo_damage_status ( -- 货损状态 + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_i18n varchar(150) null, -- 多语言资源键 + b_canuse tinyint not null default 1, -- 是否启用(0/1) + b_xh int not null default 0, -- 显示顺序 + b_bz nvarchar(200) null, -- 备注 + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); +``` + +29 张同构表: + +| 表名 | 名称 | 表名 | 名称 | +| --- | --- | --- | --- | +| `b_cargo_damage_status` | 货损状态 | `b_sys_level` | 级别 | +| `b_bulkforkliftpersonname` | 散货铲车人员 | `b_sys_operator` | 条件设置操作符 | +| `b_bulktype` | 散货类型 | `b_blstate` | 提单方式 | +| `b_bulkpersonname` | 散货理货人员 | `b_sys_state` | 审核状态 | +| `b_bulkstevedorepersonname` | 散货装卸人员 | `b_sys_feesf` | 费用收付 | +| `b_charging_method` | 收费方式 | `bc_priceList_type` | 价目表类型 | +| `b_unloading_method` | 卸货方式 | `b_sys_yesno` | 是否 | +| `b_sys_b_lessfull` | 装箱 | `b_ystype` | 付款类型 | +| `b_sys_edittype` | 字段编辑选择 | `b_billtype` | 账单类型 | +| `b_freightpayment` | 运费条款 | `b_bgtype` | 报关方式 | +| `b_jsfs` | 结算方式 | `b_httype` | 合同类型 | +| `b_ivtype` | 发票类型 | `b_sys_hdtype` | 回单类型 | +| `b_sys_sex` | 性别 | `b_progress` | 进度情况 | +| `b_sys_copies` | 提单份数 | `b_zxstate` | 执行状态 | +| `b_cztype` | 称重方式 | | | + +另外 6 张有差异字段(完整写出): + +```sql +create table dbo.b_vessel ( -- 船名船次 + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(100) null, -- 船名(原 b_vessel_name) + b_edicode varchar(50) null, -- EDI 代码 + b_voy nvarchar(100) null, -- 船次 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_con_type ( -- 箱型管理 + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 箱型(40GP / 20GP / 45HQ) + b_edicode varchar(50) null, -- EDI 代码 + b_type nvarchar(50) null, -- 箱类(大箱/小箱) + b_linkcon nvarchar(50) null, -- 关联箱型 + b_default tinyint not null default 0, -- 默认箱型(0/1) + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_city ( -- 城市 + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 中文名(原 b_name_c) + b_name_e nvarchar(50) null, -- 英文名 + b_country_name_c nvarchar(50) null, -- 国家(中文) + b_country_name_e nvarchar(50) null, -- 国家(英文) + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_sys_pricelisttype ( -- 合作伙伴类型(委托单位/订舱单位/报关行…) + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 名称 + b_dw_id varchar(50) null, -- 关联单位字段名(如 b_customer_id) + b_dw_name varchar(50) null, -- 关联单位视图名(如 v_customer_company) + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_transway ( -- 运输条款(CY-CY / DOOR-DOOR / CFS-CFS) + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(100) null, -- 条款 + b_edicode varchar(50) null, -- EDI 代码 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); + +create table dbo.b_package ( -- 包装单位(BAGS / BALES / CASES…) + b_id bigint not null primary key, -- 主键(雪花) + b_name nvarchar(50) null, -- 包装代码 + b_edicode varchar(50) null, -- EDI 代码 + b_i18n varchar(150) null, + b_canuse tinyint not null default 1, + b_xh int not null default 0, + b_bz nvarchar(200) null, + b_created_by varchar(50) null, + b_created_at datetime2 null, + b_updated_by varchar(50) null, + b_updated_at datetime2 null +); +``` + +### 仓库、物流、铁运、空运(18 张) + +这 18 张全部是标准结构(同系统组模板,仅 `b_name` 即名称): + +| 分组 | 表名 | 名称 | +| --- | --- | --- | +| 3.仓库 | `b_depot` | 仓库 | +| 3.仓库 | `b_depotouttype` | 出库类型 | +| 3.仓库 | `b_depotintype` | 入库类型 | +| 5.物流 | `car_daily_feetype` | 费用报销-费用类型 | +| 5.物流 | `car_jiayou_jsfs` | 计算方式 | +| 5.物流 | `car_jiayou_type` | 加油类型 | +| 5.物流 | `car_jiayou_youliao` | 燃油种类 | +| 5.物流 | `b_cdtype` | 派车类型 | +| 5.物流 | `b_shfs` | 派送方式 | +| 5.物流 | `b_thfs` | 提货方式 | +| 5.物流 | `b_wangdian` | 网点 | +| 5.物流 | `b_ywfrom` | 业务来源 | +| 5.物流 | `b_ywtype_tc` | 业务类型(拖车) | +| 6.铁运 | `b_servicetype` | 服务内容 | +| 6.铁运 | `b_contype` | 箱属 | +| 6.铁运 | `b_ywtype_ht` | 业务类型(铁运) | +| 7.空运 | `b_dcterm` | 订舱条款 | +| 7.空运 | `b_ywtype_ky` | 业务类型(空运) | + +### 实施记录(2026-09-14) + +| 步骤 | 产物 | 状态 | +| --- | --- | --- | +| 建表 | `sql/fms_business_otherdata.sql`(62 张表;字典模块直接查表,不建视图) | 已执行 | +| 模块注册 | `sql/fms_module_otherdata.sql`(`base_otherdata` 根 + 6 个分组 + 64 个数据模块,编码 = 表名 + s_field) | 已执行 | +| 数据导入 | `fms-api/tools/migration/OtherDataMigrate.java`(555 行,雪花主键);映射留档 `otherdata-id-map.tsv` | 已执行 | +| `b_from` / `b_grade` 重建 | 工具内完成(雪花主键) | 已执行 | +| 引用转换 | `b_othercompany.b_from_id` / `b_type_id` | **待执行**:`b_othercompany` 目前是空表,数据迁入后重跑 `OtherDataMigrate` 即可(旧编号未匹配时脚本无副作用) | +| 字段中文名与界面配置 | `FieldNameSync --all-otherdata --force`:64 个模块全部同步(中文名 + view/edit 配置,含字段别名 `b_vessel_name`→`b_name`、`b_name_c`→`b_name`);通用字段名由注册脚本补齐(668 字段全部有中文名);旧库无配置的 44 个模块补默认列(名称 + 备注) | 已执行 | diff --git a/code/fms/FMS新系统核心表结构设计.md b/code/fms/FMS新系统核心表结构设计.md index 10fd05aa..2fb687c9 100644 --- a/code/fms/FMS新系统核心表结构设计.md +++ b/code/fms/FMS新系统核心表结构设计.md @@ -576,6 +576,13 @@ create index ix_s_menu_module_module 菜单树同样使用 `b_parent_id` 作为权威关系,并冗余维护 `b_depth`、`b_path`。菜单节点新增、移动和删除时,由业务层同步处理后代节点路径和层级;菜单编码创建后原则上不可修改。 +绑定规则: + +- `directory`(目录)和 `external`(外链)不绑定模块;`page` 可绑定一个或多个模块; +- 关系表只登记 `data` / `virtual` 模块:权限按 `data` 模块判定,`module` 类型只是模块树上的分类节点,不参与权限,也不进入关系表; +- 菜单管理界面按模块树勾选,勾中分类节点时自动展开为其下全部 `data` 模块逐条登记(界面级快捷操作,落库的始终是明确的模块清单,之后可单独增删); +- 菜单编码创建后原则上不可修改,绑定关系随菜单保存一并提交。 + 业务模块上下文可以根据所绑定数据模块的父级模块获得;暂不增加独立的菜单上下文字段。 菜单权限(`menu.*`)只控制页面入口;页面内各 `data`、`virtual` 模块的操作权限按模块编码独立判定,一个菜单绑定多个模块时不做权限合并。 @@ -968,3 +975,84 @@ b_condition_sql = 'b_salesman_id = {userId}' - `s_user_field_power.b_module_id`、`s_user_data_power.b_module_id` 指向 `s_module.b_id`,字段还需在 `s_field` 中存在; - 数据范围只作用于本表的 `b_user_id + b_module_id + b_operation`;是否向关联模块延伸(例如子表、明细模块)由权限引擎根据业务语义决定,不依赖 `s_relation` 自动传播; - 权限缓存、批量校验和 SQL 条件注入点由权限引擎实现,业务 SQL 生成时统一追加范围条件。 + +## 15. 文件 + +文件统一由文件服务托管:业务表不保存文件二进制,只通过 `bf_files.father` 关联宿主业务主键, +按 `father + mx_moduleid + mx_cate_id` 聚合出某个业务对象、某模块、某分类下的附件列表。 +存储方式由配置决定(本地磁盘 / 阿里云 OSS),两种模式共用同一张表:本地模式由后端写盘后落库, +OSS 模式由前端取号直传后回调落库。 + +```sql +-- 文件表 +create table dbo.bf_files ( + subid bigint not null primary key, -- 文件主键(雪花,应用层取号:本地由后端、OSS 直传由前端先取号) + father bigint null, -- 宿主业务主键(业务表 b_id),列表按它聚合 + mx_filename nvarchar(500) null, -- 原始文件名(含扩展名,展示与下载用) + mx_filesize varchar(50) null, -- 文件大小(字节,字符串存储) + mx_fileext varchar(50) null, -- 扩展名(小写、不含点) + mx_mapfilename nvarchar(500) null, -- 访问地址:本地为 {url-prefix}/{org}/{yyyy}/{MM}/{dd}/{uuid}.{ext},OSS 为完整 URL + mx_moduleid varchar(50) null, -- 业务模块编码(s_module.b_id) + mx_cate_id varchar(50) null, -- 文件分类(bf_files_cateid.b_id) + mx_xh int not null default 0, -- 排序号(保留;当前实现固定 0,列表按 subid 倒序) + mx_sh tinyint not null default 0, -- 审核标识(保留;当前实现固定 0) + mx_shuser_id varchar(50) null, -- 审核人(保留) + mx_shdatetime datetime2 null, -- 审核时间(保留) + mx_cutfilename nvarchar(500) null, -- 缩略图地址(保留) + mx_cutfilesize varchar(50) null, -- 缩略图大小(保留) + mx_orderid varchar(50) null, -- 排序组(保留) + mx_bz nvarchar(500) null, -- 备注(保留) + mx_inputuser_id varchar(50) null, -- 上传人(用户账号) + mx_inputdatetime datetime2 null, -- 上传时间 + mx_updateuser_id varchar(50) null, -- 最后修改人 + mx_updatedatetime datetime2 null -- 最后修改时间 +); + +create index ix_bf_files_host + on dbo.bf_files (father, mx_moduleid, mx_cate_id, mx_xh, subid); + +-- 文件分类表 +create table dbo.bf_files_cateid ( + b_id varchar(50) not null primary key, -- 分类编码 + b_name nvarchar(50) null, -- 分类名称 + b_files_type varchar(50) null, -- 允许的扩展名(逗号分隔,空 = 不限;保留) + b_xh int not null default 0, -- 显示顺序 + b_canuse tinyint not null default 1, -- 是否启用(0/1) + b_bz nvarchar(200) null, -- 备注 + b_inputuser_id varchar(50) null, -- 创建人 + b_inputdatetime datetime2 null, -- 创建时间 + b_updateuser_id varchar(50) null, -- 最后修改人 + b_updatedatetime datetime2 null -- 最后修改时间 +); +``` + +要点: + +- **主键**:`subid` 为应用层雪花 ID,不使用 `identity`。本地模式由后端在写盘前取号;OSS 模式由前端在上传前取号(`nextIdApi`),直传完成后回调 `/file/save-record` 落库 —— 两条链路都不能依赖数据库自增。 +- **宿主关联**:`father` 存宿主业务主键(业务表 `b_id`,bigint 雪花),不建外键;删除业务数据时由业务层级联清理附件(先删存储、后删行)。 +- **存储地址**:`mx_mapfilename` 即访问地址,前端预览 / 下载直接使用。本地模式写入 `{fms.file.local.url-prefix}/{orgId}/{yyyy}/{MM}/{dd}/{uuid}.{ext}`,物理文件落在 `{fms.file.local.storage-dir}` 下的同路径;OSS 模式写入 g3oss 返回的完整 URL。 +- **保留字段**:`mx_sh*`(审核)、`mx_cut*`(缩略图)、`mx_orderid`、`mx_bz`、`mx_xh` 沿用旧库结构,当前实现未使用(写 0 / 空值),保留以兼容历史数据迁移。 +- **旧库遗留**:`bf_files_type`(模块文件类型 / 数量配置)在旧库存在,但新旧系统均未使用,不迁移。 + +存储配置(`application.yaml`): + +```yaml +fms: + file: + storage-type: local # local / aliyun-oss + local: + storage-dir: ./data/files # 物理根目录 + url-prefix: /api/file/static # 访问前缀 + oss: + g3oss-url: http://g3oss.g3soft.cn:8082 +``` + +业务接入(前端 `FmsFile` 组件): + +```text + + ├── 列表:bf_files 按 father + mx_moduleid + mx_cate_id 过滤,mx_xh ASC, subid DESC 排序 + ├── 上传:local → POST /file/upload(后端写盘 + 落库) + │ aliyun-oss → 取号 → 凭证直传 → POST /file/save-record 落库 + └── 删除:POST /file/delete(删存储 → 删 DB 行) +``` diff --git a/code/fms/fms-api/tools/migration/FieldNameSync.java b/code/fms/fms-api/tools/migration/FieldNameSync.java index 3adf8a0f..1929ab8b 100644 --- a/code/fms/fms-api/tools/migration/FieldNameSync.java +++ b/code/fms/fms-api/tools/migration/FieldNameSync.java @@ -13,6 +13,7 @@ import java.util.*; * s_columnLib.col_TableName = s_module.b_view_table * s_columnLib.col_FieldName = s_field.b_field * 两侧用 Chinese_PRC_CI_AS 比较,兼容 v_b_OtherCompany 这类大小写差异。 + * 重命名字段走别名映射(b_vessel_name → b_name、b_name_c → b_name,见 FIELD_ALIAS)。 * * 列表/表单的成员资格沿用旧库语义:旧库标志为 '1' 的字段才进入对应配置, * 其余字段(标志为 '0'、空、无记录)**直接不写入 JSON**,不写 visible:false。 @@ -32,6 +33,7 @@ import java.util.*; * --dry-run 只报告不写库 * --skip-schema 只同步 s_field.b_name,不重建 s_module_schema * --force 允许覆盖已存在且非空的 s_module_schema 行 + * --all-otherdata 批量模式:同步 base_otherdata 下所有数据模块(不需要位置参数,失败跳过继续) */ public class FieldNameSync { @@ -43,6 +45,8 @@ public class FieldNameSync { boolean dryRun = false; boolean skipSchema = false; boolean force = false; + boolean allOtherData = false; + boolean batchMode = false; // 批量子任务:出错抛异常交给批量汇总,而不是 System.exit String moduleId; String oldTableOverride; @@ -70,6 +74,14 @@ public class FieldNameSync { Integer editPosition; // col_edit_position } + /** + * 旧库字段名 → 新系统字段名。 + * 表设计里做过重命名的字段:b_vessel_name → b_name(船名)、b_name_c → b_name(中文名)。 + */ + private static final Map FIELD_ALIAS = Map.of( + "b_vessel_name", "b_name", + "b_name_c", "b_name"); + // ------------------------------------------------------------------ SQL static final String QUERY_MODULE = """ SELECT b_id, b_view_table, b_name, b_module_type @@ -117,7 +129,45 @@ public class FieldNameSync { public static void main(String[] args) throws Exception { FieldNameSync tool = new FieldNameSync(); tool.parseArgs(args); - tool.run(); + if (tool.allOtherData) { + tool.runBatch(); + } else { + tool.run(); + } + } + + /** 批量:同步 base_otherdata 下所有数据模块;每个模块独立事务,失败跳过并继续 */ + void runBatch() throws SQLException { + List ids = new ArrayList<>(); + try (Connection c = DriverManager.getConnection(URL, USER, PASSWORD); + PreparedStatement ps = c.prepareStatement( + "SELECT b_id FROM dbo.s_module WHERE b_path LIKE '/base/base_otherdata/%' " + + "AND b_module_type = 'data' ORDER BY b_xh, b_id"); + ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + ids.add(rs.getString(1)); + } + } + System.out.println("批量同步 " + ids.size() + " 个模块(base_otherdata)" + (dryRun ? "[dry-run]" : "") + "\n"); + + int ok = 0; + int failed = 0; + for (String id : ids) { + FieldNameSync one = new FieldNameSync(); + one.dryRun = dryRun; + one.skipSchema = skipSchema; + one.force = force; + one.batchMode = true; + one.moduleId = id; + try { + one.run(); + ok++; + } catch (Exception e) { + failed++; + System.err.println("[失败] " + id + ": " + e.getMessage()); + } + } + System.out.println("\n批量完成:成功 " + ok + " 个,失败 " + failed + " 个"); } void parseArgs(String[] args) { @@ -128,6 +178,7 @@ public class FieldNameSync { case "--dry-run" -> dryRun = true; case "--skip-schema" -> skipSchema = true; case "--force" -> force = true; + case "--all-otherdata" -> allOtherData = true; default -> { if (arg.startsWith("--")) { System.err.println("未知选项: " + arg); @@ -139,8 +190,11 @@ public class FieldNameSync { } } if (positional.isEmpty()) { - usage(); - System.exit(1); + if (!allOtherData) { + usage(); + System.exit(1); + } + return; } moduleId = positional.get(0); if (positional.size() > 1) oldTableOverride = positional.get(1); @@ -153,6 +207,7 @@ public class FieldNameSync { static void usage() { System.err.println("用法: java FieldNameSync [oldTableName] [--dry-run] [--skip-schema] [--force]"); + System.err.println(" java FieldNameSync --all-otherdata [--dry-run] [--force] 批量同步 base_otherdata 下所有数据模块"); } void run() throws SQLException { @@ -203,6 +258,9 @@ public class FieldNameSync { } } catch (Exception e) { conn.rollback(); + if (batchMode) { + throw new SQLException(e.getMessage(), e); + } System.err.println("\n[错误] " + e.getMessage()); System.exit(1); } @@ -268,7 +326,8 @@ public class FieldNameSync { col.width = intOrNull(rs, "col_Width"); col.position = intOrNull(rs, "col_Position"); col.editPosition = intOrNull(rs, "col_edit_position"); - oldColumns.put(trim(rs.getString("col_FieldName")), col); + String fieldName = trim(rs.getString("col_FieldName")); + oldColumns.put(FIELD_ALIAS.getOrDefault(fieldName.toLowerCase(Locale.ROOT), fieldName), col); } } } @@ -349,10 +408,27 @@ public class FieldNameSync { return updated; } - /** view 配置:{"schemaVersion":1,"columns":[{"field":..,"width":..}]},只含旧库 col_Visible='1' 的字段 */ + /** 备注列统一排到最后(其他数据字典表的展示习惯) */ + private static void moveBzLast(List list) { + Field bz = null; + for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { + Field field = iterator.next(); + if ("b_bz".equalsIgnoreCase(field.name)) { + bz = field; + iterator.remove(); + break; + } + } + if (bz != null) { + list.add(bz); + } + } + + /** view 配置:{"schemaVersion":1,"columns":[{"field":..,"width":..}]},只含旧库 col_Visible='1' 的字段;备注列固定排最后 */ String buildViewJson() { StringBuilder sb = new StringBuilder("{\"schemaVersion\":1,\"columns\":["); - List list = includedFields("view"); + List list = new ArrayList<>(includedFields("view")); + moveBzLast(list); for (int i = 0; i < list.size(); i++) { Field f = list.get(i); if (i > 0) sb.append(','); @@ -364,10 +440,11 @@ public class FieldNameSync { return sb.append("]}").toString(); } - /** edit 配置:{"schemaVersion":1,"children":[{"field":..,"span":24}]},只含旧库 col_edit='1' 的字段 */ + /** edit 配置:{"schemaVersion":1,"children":[{"field":..,"span":24}]},只含旧库 col_edit='1' 的字段;备注列固定排最后 */ String buildEditJson() { StringBuilder sb = new StringBuilder("{\"schemaVersion\":1,\"children\":["); - List list = includedFields("edit"); + List list = new ArrayList<>(includedFields("edit")); + moveBzLast(list); for (int i = 0; i < list.size(); i++) { Field f = list.get(i); if (i > 0) sb.append(','); diff --git a/code/fms/fms-api/tools/migration/OtherDataMigrate.java b/code/fms/fms-api/tools/migration/OtherDataMigrate.java new file mode 100644 index 00000000..067a3393 --- /dev/null +++ b/code/fms/fms-api/tools/migration/OtherDataMigrate.java @@ -0,0 +1,362 @@ +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * 其他数据迁移:base_otherdata 下 64 个字典模块的数据导入 + b_from / b_grade 重建 + * + * 数据来源:旧库 G3HY2025;目标:新库 FMS(连接信息取 config/dbconfigs) + * + * 流程: + * 1. 从 s_module 读出 base_otherdata 下的数据模块(b_save_table); + * 2. 逐表导入:旧库读行 → 生成雪花 b_id → 按列映射写入新表; + * 列映射:同名对应;审计字段 b_inputuser_id→b_created_by 等;b_name_c / b_vessel_name → b_name; + * b_canuse 固定 1、b_xh 按旧编号顺序生成 10/20/…、b_i18n 留空; + * 3. b_from / b_grade:先读出旧行 → drop + create(雪花主键)→ 重导 → + * 转换 b_othercompany.b_from_id / b_type_id 的引用值为新雪花; + * 4. 输出映射文件 tools/migration/otherdata-id-map.tsv(表名、旧编号、新雪花)留档。 + * + * 用法(在 fms-api 下运行;整体一个事务,失败全部回滚): + * java -cp "tools/migration;tools/migration/mssql-jdbc-13.4.0.jre11.jar" OtherDataMigrate --dry-run + * java -cp "tools/migration;tools/migration/mssql-jdbc-13.4.0.jre11.jar" OtherDataMigrate + */ +public final class OtherDataMigrate { + + /** 与后端 IdGenerator 相同的时间基准和位布局;WorkerId 取 63(迁移专用,后端用 1,互不冲突) */ + private static final long BASE_TIME = 1582136402000L; + private static final long WORKER_ID = 63L; + private static final int SEQ_BITS = 6; + private static final int WORKER_BITS = 6; + + private static long lastMs = -1L; + private static int seq = 0; + + /** 审计字段映射(新列 → 旧列) */ + private static final Map COLUMN_ALIAS = Map.of( + "b_created_by", "b_inputuser_id", + "b_created_at", "b_inputdatetime", + "b_updated_by", "b_updateuser_id", + "b_updated_at", "b_updatedatetime"); + + /** 固定值列(不取旧数据) */ + private static final Set FIXED_COLUMNS = Set.of("b_i18n", "b_canuse", "b_xh"); + + /** 需要雪花化重建的表 → 建表 DDL(列名与旧结构一致,仅主键改雪花) */ + private static final Map REBUILD_DDL = Map.of( + "b_from", "create table dbo.b_from (" + + "b_id bigint not null primary key, b_name nvarchar(50) null, b_i18n varchar(150) null, " + + "b_canuse tinyint not null default 1, b_xh int not null default 0, b_bz nvarchar(50) null, " + + "b_created_by varchar(50) null, b_created_at datetime2 null, " + + "b_updated_by varchar(50) null, b_updated_at datetime2 null)", + "b_grade", "create table dbo.b_grade (" + + "b_id bigint not null primary key, b_name nvarchar(50) null, b_i18n varchar(150) null, " + + "b_canuse tinyint not null default 1, b_xh int not null default 0, b_bz nvarchar(50) null, " + + "b_created_by varchar(50) null, b_created_at datetime2 null, " + + "b_updated_by varchar(50) null, b_updated_at datetime2 null)"); + + public static void main(String[] args) throws Exception { + boolean dryRun = args.length > 0 && "--dry-run".equals(args[0]); + Path apiRoot = Path.of("").toAbsolutePath().normalize(); + Path mapFile = apiRoot.resolve("tools/migration/otherdata-id-map.tsv"); + + StringBuilder mapText = new StringBuilder("表名\t旧编号\t新ID\n"); + int totalRows = 0; + + try (Connection old = connect(apiRoot, "G3HY2025"); + Connection fms = connect(apiRoot, "G3HD")) { + fms.setAutoCommit(false); + try { + List tables = loadTables(fms); + System.out.println("模块数: " + tables.size() + (dryRun ? "(dry-run)" : "")); + + Map fromRefs = new LinkedHashMap<>(); + Map gradeRefs = new LinkedHashMap<>(); + + for (String table : tables) { + Map mapping = migrateTable(old, fms, table, mapText, dryRun); + totalRows += mapping.size(); + if ("b_from".equals(table)) { + fromRefs.putAll(mapping); + } + if ("b_grade".equals(table)) { + gradeRefs.putAll(mapping); + } + System.out.println(" " + pad(table, 28) + "旧库 " + mapping.size() + " 行"); + } + + if (!dryRun) { + int n1 = convertRefs(fms, "b_othercompany", "b_from_id", fromRefs); + int n2 = convertRefs(fms, "b_othercompany", "b_type_id", gradeRefs); + System.out.println("引用转换: b_othercompany.b_from_id " + n1 + " 行, b_type_id " + n2 + " 行"); + fms.commit(); + System.out.println("完成:共导入 " + totalRows + " 行"); + } else { + fms.rollback(); + System.out.println("[dry-run] 已回滚,共 " + totalRows + " 行待导入"); + } + } catch (Exception e) { + fms.rollback(); + throw e; + } + } + + if (!dryRun) { + Files.writeString(mapFile, mapText.toString(), StandardCharsets.UTF_8); + System.out.println("映射已写入: " + mapFile); + } + } + + // ---------------------------------------------------------------- 模块清单 + + private static List loadTables(Connection fms) throws Exception { + List tables = new ArrayList<>(); + try (Statement statement = fms.createStatement(); + ResultSet rows = statement.executeQuery( + "select b_save_table from dbo.s_module where b_path like '/base/base_otherdata/%' " + + "and b_module_type = 'data' order by b_xh, b_id")) { + while (rows.next()) { + tables.add(rows.getString(1)); + } + } + return tables; + } + + // ---------------------------------------------------------------- 单表迁移 + + /** 导入一张表,返回「旧编号 → 新雪花」映射 */ + private static Map migrateTable(Connection old, Connection fms, String table, + StringBuilder mapText, boolean dryRun) throws Exception { + // 新表列(跳过 b_id,它由雪花生成) + record Target(String name, String typeName, String source, Object fixed) {} + List targets = new ArrayList<>(); + try (Statement statement = fms.createStatement(); + ResultSet rows = statement.executeQuery( + "select c.name, ty.name from sys.columns c join sys.types ty on ty.user_type_id = c.user_type_id " + + "where c.object_id = object_id('dbo." + table + "') order by c.column_id")) { + while (rows.next()) { + String name = rows.getString(1); + String typeName = rows.getString(2); + if (!"b_id".equals(name)) { + targets.add(new Target(name, typeName, null, null)); + } + } + } + + // 旧表列 + Set oldColumns = new HashSet<>(); + try (Statement statement = old.createStatement(); + ResultSet rows = statement.executeQuery( + "select name from sys.columns where object_id = object_id('dbo." + table + "')")) { + while (rows.next()) { + oldColumns.add(rows.getString(1)); + } + } + if (oldColumns.isEmpty()) { + throw new IllegalStateException("旧库缺少表 dbo." + table); + } + + // 解析每个新列的取值来源 + List resolved = new ArrayList<>(); + for (Target target : targets) { + if (FIXED_COLUMNS.contains(target.name())) { + resolved.add(new Target(target.name(), target.typeName(), null, "@fixed")); + } else { + String source = resolveSource(target.name(), oldColumns); + resolved.add(new Target(target.name(), target.typeName(), source, null)); + } + } + + // 读取旧数据 + StringBuilder select = new StringBuilder("select b_id"); + for (Target target : resolved) { + if (target.source() != null) { + select.append(", [").append(target.source()).append("]"); + } + } + select.append(" from dbo.[").append(table).append("] order by b_id"); + + List rowsData = new ArrayList<>(); + List oldIds = new ArrayList<>(); + try (Statement statement = old.createStatement(); + ResultSet rows = statement.executeQuery(select.toString())) { + int columnCount = rows.getMetaData().getColumnCount(); + while (rows.next()) { + oldIds.add(String.valueOf(rows.getObject(1))); + Object[] values = new Object[columnCount - 1]; + for (int i = 2; i <= columnCount; i++) { + values[i - 2] = rows.getObject(i); + } + rowsData.add(values); + } + } + + if (dryRun) { + return toMap(oldIds, rowsData); + } + + // 重建表(b_from / b_grade)或清空目标表(其余) + try (Statement statement = fms.createStatement()) { + if (REBUILD_DDL.containsKey(table)) { + statement.execute("drop table if exists dbo." + table); + statement.execute(REBUILD_DDL.get(table)); + } else { + statement.execute("delete from dbo." + table); + } + } + + // 插入 + List names = new ArrayList<>(); + for (Target target : resolved) { + names.add("[" + target.name() + "]"); + } + String insert = "insert into dbo.[" + table + "] (b_id, " + String.join(", ", names) + ") values (?" + + ", ?".repeat(names.size()) + ")"; + Map mapping = new LinkedHashMap<>(); + try (PreparedStatement statement = fms.prepareStatement(insert)) { + int rowIndex = 0; + for (int row = 0; row < rowsData.size(); row++) { + rowIndex++; + long newId = nextId(); + String oldId = oldIds.get(row); + mapping.put(oldId, newId); + mapText.append(table).append('\t').append(oldId).append('\t').append(newId).append('\n'); + + statement.setLong(1, newId); + Object[] values = rowsData.get(row); + int parameter = 2; + int sourceIndex = 0; + for (Target target : resolved) { + if (target.source() != null) { + setValue(statement, parameter, target.typeName(), values[sourceIndex++]); + } else if ("b_xh".equals(target.name())) { + statement.setInt(parameter, rowIndex * 10); + } else if ("b_canuse".equals(target.name())) { + statement.setInt(parameter, 1); + } else { + statement.setObject(parameter, null); + } + parameter++; + } + statement.addBatch(); + } + statement.executeBatch(); + } + return mapping; + } + + /** 新列 → 旧列;返回 null 表示没有对应旧列 */ + private static String resolveSource(String newColumn, Set oldColumns) { + String alias = COLUMN_ALIAS.get(newColumn); + if (alias != null && oldColumns.contains(alias)) { + return alias; + } + if (oldColumns.contains(newColumn)) { + return newColumn; + } + if ("b_name".equals(newColumn)) { + if (oldColumns.contains("b_name_c")) { + return "b_name_c"; + } + if (oldColumns.contains("b_vessel_name")) { + return "b_vessel_name"; + } + } + return null; + } + + private static void setValue(PreparedStatement statement, int index, String typeName, Object value) throws Exception { + if ("tinyint".equals(typeName)) { + if (value == null) { + statement.setInt(index, 0); + return; + } + if (value instanceof Number number) { + statement.setInt(index, number.intValue() == 0 ? 0 : 1); + return; + } + String text = String.valueOf(value).trim(); + statement.setInt(index, "1".equals(text) || "true".equalsIgnoreCase(text) ? 1 : 0); + return; + } + statement.setObject(index, value); + } + + private static Map toMap(List oldIds, List rowsData) { + Map mapping = new LinkedHashMap<>(); + for (String oldId : oldIds) { + mapping.put(oldId, 0L); + } + return mapping; + } + + // ---------------------------------------------------------------- 引用转换 + + private static int convertRefs(Connection fms, String table, String column, Map mapping) throws Exception { + if (mapping.isEmpty()) { + return 0; + } + int count = 0; + try (PreparedStatement statement = fms.prepareStatement( + "update dbo." + table + " set " + column + " = ? where " + column + " = ?")) { + for (Map.Entry entry : mapping.entrySet()) { + statement.setString(1, String.valueOf(entry.getValue())); + statement.setString(2, entry.getKey()); + count += statement.executeUpdate(); + } + } + return count; + } + + // ---------------------------------------------------------------- 基础设施 + + private static Connection connect(Path apiRoot, String org) throws Exception { + Properties properties = new Properties(); + try (InputStream input = Files.newInputStream(apiRoot.resolve("config/dbconfigs/" + org + ".properties"))) { + properties.load(input); + } + return DriverManager.getConnection( + properties.getProperty("url"), + properties.getProperty("username"), + properties.getProperty("password")); + } + + /** 简易雪花:与后端同基准/位布局,同一毫秒内序列递增,回拨时沿用上次时间 */ + private static synchronized long nextId() { + long now = System.currentTimeMillis(); + if (now < lastMs) { + now = lastMs; + } + if (now == lastMs) { + seq++; + if (seq > 63) { + now++; + seq = 0; + } + } else { + seq = 0; + } + lastMs = now; + return ((now - BASE_TIME) << (WORKER_BITS + SEQ_BITS)) | (WORKER_ID << SEQ_BITS) | seq; + } + + private static String pad(String value, int width) { + StringBuilder text = new StringBuilder(value == null ? "" : value); + while (text.length() < width) { + text.append(' '); + } + return text.toString(); + } +} diff --git a/code/fms/fms-api/tools/migration/OtherDataMigration$OldBmflEntry.class b/code/fms/fms-api/tools/migration/OtherDataMigration$OldBmflEntry.class deleted file mode 100644 index 163b601e031cab56b57746460307f9e046187747..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 436 zcmZXQ%}&BV5Xb++M++4Nzd%il9!yXV@&JAuK#e2_2aNZHu4PHPHQTMx$MR(2!3Xf6 zjMIih6AnASnfcG`&d&GG=NEuW?0G1l=%Q3Z84jT_7cZg{3LSJtlewH)f^(s?vR8!S z@yVl$3gKX6XVP2?EACZbgjKOV8ijs0dJ1o}HE)D+9Qu8qurc_%Z)}ay!8xI%MI;GT zD<+{F=Dr)4IDPJNr!y5gO<1Nrq3}B6@?Pw7TpuVchiNpC<{@h&c;h%VQ+cbhptU^H zS@t%eGL(tEixcaj#S<;p5o&#{rRjwtNo2y||IgqMF7F6%_*CJs1y&ZUEx5Yi8tS>; u$Vu$;RzX;2Z=acGPCr2JoZw;DW-`!55u3~cwy>SEi5;fLs*5IeQTYWq7Fm%1 diff --git a/code/fms/fms-api/tools/migration/OtherDataMigration$TableMapping.class b/code/fms/fms-api/tools/migration/OtherDataMigration$TableMapping.class deleted file mode 100644 index 4f1d430bada8c1a6b419f8f61786076a0299e479..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmZXQO;5r=5Qg8ONTF6iR8SM62M_2$4j%ouV2l_F2aE@ATe^WI?Uu9){w_}@9{d6R zDC1D@BjK>~?CiYrvGe)${sG_`2M%(uY~)?6p+KmN#Y{9qp@+?$Kb8YSC|oJ6%niY6 zoIcqo5{`OiB$HcVgr|myFe=t3kHQb7Cngi6hlFAj2h&it0|Gq|oQ2zp14*cM{(AIH z!um@>X{O{$R^wOQ6%ngTBawPpF)sB?$S;bNJ4(y$H1cKglhu!>$w1zzkhAKm6Q0kz z@?>3^n)^64HtIafs*d2cwU$XM6lp3`cK?43$FO;0;B5gVIBbD+xEVK=++4DZ3cnK{ q-Ys*BZ->n6|i%z4SP(7qc&>TNAVld_g@zP diff --git a/code/fms/fms-api/tools/migration/OtherDataMigration.class b/code/fms/fms-api/tools/migration/OtherDataMigration.class deleted file mode 100644 index a78c390d8f68dd4b125579f021fccf2a626c5d0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34308 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 oF4WgWE*!a_(?H8_;e;y#Q*>R diff --git a/code/fms/fms-api/tools/migration/OtherDataMigration.java b/code/fms/fms-api/tools/migration/OtherDataMigration.java deleted file mode 100644 index f9f507b7..00000000 --- a/code/fms/fms-api/tools/migration/OtherDataMigration.java +++ /dev/null @@ -1,1025 +0,0 @@ -import java.sql.*; -import java.util.*; - -/** - * 其他数据子系统全量迁移工具 - * - * 从旧库 G3HY2025 迁移 b_other_bmfl 分类树 + 各基础字典表数据到新库 FMS。 - * 替代 FieldNameSync.java 的单表单字段同步,一次性完成整个"其他数据"子系统的迁移。 - * - * 注意:本工具面向 V1 表结构(s_module_field / s_module_field_list / s_module_field_edit), - * 与《FMS新系统核心表结构设计V2》的 s_field / s_module_schema 不兼容,仅作历史参考。 - * - * 4 个阶段: - * 1. 发现:读取旧 b_other_bmfl,列出分类和关联表 - * 2. 树迁移:创建 category/module 节点树 - * 3. 数据迁移:逐表复制数据(类型转换 + Snowflake ID) - * 4. 元数据同步:col_Caption/col_Visible/col_edit → s_module_field* - * - * 用法:java -cp ".;mssql-jdbc.jar" OtherDataMigration [options] - * - * 选项: - * --dry-run 仅发现并报告,不执行迁移 - * --clean-tree 清理新库中已有的 b_other_bmfl 树节点 - * --skip-data 跳过阶段 3(数据迁移),仅做树结构迁移 - * --skip-metadata 跳过阶段 4(字段元数据同步) - */ -public class OtherDataMigration { - - static final String URL = "jdbc:sqlserver://118.89.70.199:1433;databaseName=FMS;encrypt=true;trustServerCertificate=true"; - static final String USER = "sa"; - static final String PASSWORD = "zhang520.."; - - // ---- 选项 ---- - boolean dryRun = false; - boolean cleanTree = false; - boolean skipData = false; - boolean skipMetadata = false; - - Connection conn; - - // ---- 阶段 1 数据 ---- - static class OldBmflEntry { - String oldId; - String name; // mc_b - String tableName; // b_tablename - String groupBy; // b_groupby - int canuse; - int xh; - } - List oldEntries = new ArrayList<>(); - Map groupNameMap = new LinkedHashMap<>(); // groupBy -> 第一个 mc_b 作为分类名 - - // ---- 阶段 2 数据 ---- - static class TableMapping { - long moduleId; - String moduleCode; - String viewTable; - String moduleName; - boolean hasModule; - } - Map categoryIds = new LinkedHashMap<>(); // groupBy -> 新 category b_id - Map moduleNodeIds = new LinkedHashMap<>(); // moduleCode -> 新 module node b_id - Map tableMappings = new LinkedHashMap<>(); // tableName -> mapping info - - // ---- ID 缓存(避免反复查询 MAX)---- - Map nextIdCache = new HashMap<>(); - - // ====================================================================== - // main - // ====================================================================== - public static void main(String[] args) throws Exception { - OtherDataMigration tool = new OtherDataMigration(); - tool.parseArgs(args); - - tool.printHeader(); - tool.conn = DriverManager.getConnection(URL, USER, PASSWORD); - - try { - // ===== 阶段 1:发现 ===== - tool.phaseDiscovery(); - - // ===== 阶段 2:树迁移 ===== - tool.phaseTreeMigration(); - - // ===== 阶段 3:数据迁移 ===== - tool.phaseDataMigration(); - - // ===== 阶段 4:元数据同步 ===== - tool.phaseMetadataSync(); - - System.out.println("\n" + "=".repeat(60)); - System.out.println("所有阶段完成。"); - System.out.println("=".repeat(60)); - } catch (Exception e) { - System.err.println("\n[错误] " + e.getMessage()); - e.printStackTrace(); - if (tool.conn != null) { - try { tool.conn.rollback(); } catch (SQLException ignored) {} - } - } finally { - if (tool.conn != null) tool.conn.close(); - } - } - - // ====================================================================== - // 命令行参数解析 - // ====================================================================== - void parseArgs(String[] args) { - for (String arg : args) { - switch (arg.trim().toLowerCase(Locale.ROOT)) { - case "--dry-run" -> dryRun = true; - case "--clean-tree" -> cleanTree = true; - case "--skip-data" -> skipData = true; - case "--skip-metadata" -> skipMetadata = true; - default -> { - System.err.println("未知选项: " + arg); - System.err.println("用法: java OtherDataMigration [--dry-run] [--clean-tree] [--skip-data] [--skip-metadata]"); - System.exit(1); - } - } - } - } - - void printHeader() { - System.out.println("=".repeat(60)); - System.out.println(" 其他数据子系统全量迁移工具"); - System.out.println(" G3HY2025 → FMS"); - System.out.println("=".repeat(60)); - System.out.println(" dry-run: " + dryRun); - System.out.println(" clean-tree: " + cleanTree); - System.out.println(" skip-data: " + skipData); - System.out.println(" skip-metadata: " + skipMetadata); - System.out.println(); - } - - // ====================================================================== - // 阶段 1:发现 - // ====================================================================== - static final String DISCOVERY_SQL = """ - SELECT b_id, mc_b, b_tablename, - CASE WHEN b_canuse = '1' THEN 1 ELSE 0 END AS canuse, - CONVERT(int, ISNULL(NULLIF(b_xh,''), '0')) AS xh, - ISNULL(NULLIF(b_groupby,''), '(未分组)') AS groupby - FROM G3HY2025.dbo.b_other_bmfl - WHERE b_tablename IS NOT NULL AND LTRIM(RTRIM(b_tablename)) != '' - ORDER BY groupby, xh, mc_b - """; - - void phaseDiscovery() throws SQLException { - System.out.println("=".repeat(60)); - System.out.println("阶段 1:发现旧系统数据结构"); - System.out.println("=".repeat(60)); - - try (PreparedStatement ps = conn.prepareStatement(DISCOVERY_SQL); - ResultSet rs = ps.executeQuery()) { - Set seenGroups = new LinkedHashSet<>(); - while (rs.next()) { - OldBmflEntry entry = new OldBmflEntry(); - entry.oldId = rs.getString("b_id"); - entry.name = trim(rs.getString("mc_b")); - entry.tableName = trim(rs.getString("b_tablename")); - entry.canuse = rs.getInt("canuse"); - entry.xh = rs.getInt("xh"); - entry.groupBy = trim(rs.getString("groupby")); - oldEntries.add(entry); - - if (seenGroups.add(entry.groupBy)) { - groupNameMap.put(entry.groupBy, entry.name); - } - } - } - - // 打印分类 - System.out.println("\n发现 " + groupNameMap.size() + " 个分类:"); - for (Map.Entry e : groupNameMap.entrySet()) { - long count = oldEntries.stream().filter(oe -> oe.groupBy.equals(e.getKey())).count(); - System.out.println(" 【" + e.getKey() + "】" + (e.getValue() != null ? " (示例: " + e.getValue() + ")" : "") + " — " + count + " 个子项"); - } - - // 打印所有条目 - System.out.println("\n共 " + oldEntries.size() + " 条分类记录:"); - System.out.printf(" %-20s %-25s %-18s %-6s %s%n", "b_groupby", "mc_b", "b_tablename", "启用", "排序"); - System.out.println(" " + "-".repeat(80)); - for (OldBmflEntry e : oldEntries) { - System.out.printf(" %-20s %-25s %-18s %-6d %d%n", - e.groupBy, truncate(e.name, 24), e.tableName, e.canuse, e.xh); - } - - // 检查各表在新库中是否存在,以及是否有 s_module 条目 - System.out.println("\n检查表在新库中的状态:"); - System.out.printf(" %-20s %-10s %-20s %s%n", "表名", "表存在", "s_module_code", "模块名"); - System.out.println(" " + "-".repeat(75)); - Set processed = new LinkedHashSet<>(); - for (OldBmflEntry e : oldEntries) { - if (!processed.add(e.tableName)) continue; - - boolean tableExists = tableExistsInNew(e.tableName); - TableMapping mapping = findModuleByViewTable(e.tableName); - - String moduleCode = mapping != null && mapping.hasModule ? mapping.moduleCode : "(无)"; - String moduleName = mapping != null && mapping.hasModule ? mapping.moduleName : "(无)"; - - if (mapping != null && mapping.hasModule) { - tableMappings.put(e.tableName, mapping); - } - - System.out.printf(" %-20s %-10s %-20s %s%n", - e.tableName, - tableExists ? "存在" : "不存在", - moduleCode, - truncate(moduleName, 19)); - } - - if (!tableMappings.isEmpty()) { - System.out.println("\n以下 " + tableMappings.size() + " 个表已有 s_module 配置,可以直接迁移:"); - for (Map.Entry e : tableMappings.entrySet()) { - System.out.println(" " + e.getKey() + " → " + e.getValue().moduleCode + " (" + e.getValue().moduleName + ")"); - } - } - - Set missing = new LinkedHashSet<>(processed); - missing.removeAll(tableMappings.keySet()); - if (!missing.isEmpty()) { - System.out.println("\n以下 " + missing.size() + " 个表缺少 s_module 配置,将跳过:"); - for (String s : missing) { - System.out.println(" " + s); - } - } - } - - // ====================================================================== - // 阶段 2:树结构迁移 - // ====================================================================== - static final String CLEAN_TREE_SQL = """ - DELETE FROM dbo.b_other_bmfl - WHERE b_node_type IS NOT NULL - """; - - static final String INSERT_TREE_NODE = """ - INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse, - b_inputuser_id, b_inputdatetime, b_path, b_level) - VALUES (?, ?, ?, ?, ?, ?, 1, NULL, SYSDATETIME(), '', 1) - """; - - void phaseTreeMigration() throws SQLException { - System.out.println("\n" + "=".repeat(60)); - System.out.println("阶段 2:树结构迁移"); - System.out.println("=".repeat(60)); - - // 检查 b_other_bmfl 是否有 b_node_type 列,没有则自动添加 - if (!ensureColumn("b_other_bmfl", "b_node_type", "varchar(20) NULL")) { - System.out.println("无法添加 b_node_type 列,跳过树迁移。"); - return; - } - if (!ensureColumn("b_other_bmfl", "b_module_code", "varchar(100) NULL")) { - System.out.println("无法添加 b_module_code 列,跳过树迁移。"); - return; - } - - if (groupsWithModules().isEmpty()) { - System.out.println("没有可迁移的分类(所有表都缺少 s_module 配置),跳过树迁移。"); - return; - } - - conn.setAutoCommit(false); - - try { - // 可选:清理旧数据 - if (cleanTree) { - System.out.println("\n清理已有的 b_other_bmfl 树节点..."); - int deleted = 0; - try (PreparedStatement ps = conn.prepareStatement(CLEAN_TREE_SQL)) { - deleted = ps.executeUpdate(); - } - System.out.println(" 删除 " + deleted + " 条记录"); - } else { - System.out.println("\n保留已有树节点(使用 --clean-tree 可清理后重建)"); - } - - // Step 1: 创建顶层"其他数据"虚拟根节点(可选,用于组织) - long rootId = getNextId("b_other_bmfl"); - try (PreparedStatement ps = conn.prepareStatement(INSERT_TREE_NODE)) { - ps.setLong(1, rootId); - ps.setNull(2, Types.BIGINT); - ps.setString(3, "其他数据"); - ps.setString(4, "category"); - ps.setNull(5, Types.VARCHAR); - ps.setInt(6, 10); - ps.executeUpdate(); - } - System.out.println(" 根分类 " + rootId + ": 其他数据"); - - // Step 2: 创建各分类节点 - int catIndex = 10; - for (String groupBy : groupNameMap.keySet()) { - if (!groupsWithModules().contains(groupBy)) continue; - - long catId = getNextId("b_other_bmfl"); - categoryIds.put(groupBy, catId); - - try (PreparedStatement ps = conn.prepareStatement(INSERT_TREE_NODE)) { - ps.setLong(1, catId); - ps.setLong(2, rootId); - ps.setString(3, groupBy); - ps.setString(4, "category"); - ps.setNull(5, Types.VARCHAR); - ps.setInt(6, catIndex); - ps.executeUpdate(); - } - System.out.println(" 分类 " + catId + ": " + groupBy + " (parent=" + rootId + ")"); - catIndex += 10; - } - - // Step 3: 为每个旧条目创建模块节点 - int nodeXh = 10; - String currentGroup = null; - for (OldBmflEntry entry : oldEntries) { - // 跳过没有模块映射的表 - TableMapping mapping = tableMappings.get(entry.tableName); - if (mapping == null) continue; - // 跳过没有分类 ID 的组 - Long parentId = categoryIds.get(entry.groupBy); - if (parentId == null) continue; - - // 同一模块只创建一个节点 - if (moduleNodeIds.containsKey(mapping.moduleCode)) continue; - - long nodeId = getNextId("b_other_bmfl"); - moduleNodeIds.put(mapping.moduleCode, nodeId); - - if (!entry.groupBy.equals(currentGroup)) { - nodeXh = 10; - currentGroup = entry.groupBy; - } - - try (PreparedStatement ps = conn.prepareStatement(INSERT_TREE_NODE)) { - ps.setLong(1, nodeId); - ps.setLong(2, parentId); - ps.setString(3, mapping.moduleName); - ps.setString(4, "module"); - ps.setString(5, mapping.moduleCode); - ps.setInt(6, entry.xh > 0 ? entry.xh : nodeXh); - ps.executeUpdate(); - } - System.out.println(" 模块 " + nodeId + ": " - + mapping.moduleCode + " (" + mapping.moduleName + ") → parent=" + parentId); - nodeXh += 10; - } - - if (!dryRun) { - conn.commit(); - System.out.println("\n树结构迁移已提交。"); - } else { - System.out.println("\n[Dry-run] 树结构迁移已模拟完成,未实际提交。"); - conn.rollback(); - } - } catch (Exception e) { - conn.rollback(); - throw e; - } - } - - // ====================================================================== - // 阶段 3:数据迁移 - // ====================================================================== - static final String TABLE_EXISTS_SQL = """ - SELECT COUNT(*) FROM fms.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ? - """; - - static final String NEW_TABLE_COLUMNS = """ - SELECT COLUMN_NAME, ORDINAL_POSITION - FROM fms.INFORMATION_SCHEMA.COLUMNS - WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = ? - ORDER BY ORDINAL_POSITION - """; - - static final String OLD_TABLE_COLUMNS = """ - SELECT COLUMN_NAME, DATA_TYPE - FROM G3HY2025.INFORMATION_SCHEMA.COLUMNS - WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = ? - ORDER BY ORDINAL_POSITION - """; - - static final Set SKIP_COLUMNS = Set.of( - "b_inputuser_id", "b_updateuser_id", "b_inputdatetime", "b_updatedatetime", - "b_inputuserid", "b_updateuserid", "b_inputtime", "b_updatetime", - "mx_inputuser_id", "mx_updateuser_id", "mx_inputdatetime", "mx_updatedatetime" - ); - - static final Set BOOLEAN_COLUMNS = Set.of( - "b_canuse", "b_visible", "b_used", "b_default", "b_isdefault", - "b_black", "b_finish", "b_sh", "b_bill", "b_zx", "b_toall", - "b_visible_customer", "b_visible_supply", "b_levelvisible", - "b_fromcustomer", "b_othermachinelogin", "b_salesman", - "b_docman", "b_dealman", "b_logintime", "b_checkxy", - "b_loginfee", "b_reminder", "mx_finish", "mx_sh", - "b_isconvert" - ); - - static final Set KEY_COLUMNS = Set.of("b_code"); - - void phaseDataMigration() throws SQLException { - System.out.println("\n" + "=".repeat(60)); - System.out.println("阶段 3:数据迁移"); - System.out.println("=".repeat(60)); - - if (skipData) { - System.out.println("已跳过(--skip-data)"); - return; - } - - // 获取所有需要迁移的表(去重) - Set allTables = new LinkedHashSet<>(); - for (OldBmflEntry e : oldEntries) { - allTables.add(e.tableName); - } - - if (allTables.isEmpty()) { - System.out.println("没有需要迁移的表。"); - return; - } - - System.out.println("\n准备迁移 " + allTables.size() + " 个表的数据..."); - - conn.setAutoCommit(false); - try { - Set existingTables = new LinkedHashSet<>(); - Set missingTables = new LinkedHashSet<>(); - Set failedTables = new LinkedHashSet<>(); - int totalMigrated = 0; - - for (String tableName : allTables) { - // 检查新库中表是否存在 - if (!tableExistsInNew(tableName)) { - System.out.println(" 跳过 " + tableName + "(新库中不存在)"); - missingTables.add(tableName); - continue; - } - existingTables.add(tableName); - - TableMapping mapping = tableMappings.get(tableName); - String label = mapping != null ? mapping.moduleCode + " (" + mapping.moduleName + ")" : tableName; - - System.out.println("\n--- 迁移表 " + tableName + " → " + label + " ---"); - - try { - // 获取列信息 - List newColumns = getNewColumnNames(tableName); - Map oldColumnTypes = getOldColumnTypes(tableName); - - if (newColumns.isEmpty()) { - System.out.println(" 新表无列,跳过。"); - continue; - } - - // 找出新旧共有的列(仅用于显示) - List commonColumns = new ArrayList<>(); - for (String col : newColumns) { - if (oldColumnTypes.containsKey(col) || col.equals("b_id")) { - commonColumns.add(col); - } - } - - System.out.println(" 共有列: " + String.join(", ", commonColumns)); - - // 生成并执行迁移 SQL(传全部新表列,迁移方法内部处理旧表缺失的列) - int count = migrateTableData(tableName, newColumns, oldColumnTypes); - - if (dryRun) { - System.out.println(" [Dry-run] 共 " + count + " 条记录将被迁移"); - } else { - conn.commit(); - System.out.println(" 迁移 " + count + " 条记录"); - totalMigrated += count; - } - } catch (SQLException e) { - if (!dryRun) { - conn.rollback(); - } - System.err.println(" [失败] " + tableName + ": " + e.getMessage()); - failedTables.add(tableName); - } - } - - if (dryRun) { - System.out.println("\n[Dry-run] 数据迁移已模拟完成。"); - System.out.println("可迁移表: " + existingTables.size() + " 个"); - conn.rollback(); - } else { - System.out.println("\n数据迁移完成。共迁移 " + totalMigrated + " 条记录到 " + (existingTables.size() - failedTables.size()) + " 个表。"); - } - if (!missingTables.isEmpty()) { - System.out.println("跳过 " + missingTables.size() + " 个不存在的表: " + String.join(", ", missingTables)); - } - if (!failedTables.isEmpty()) { - System.out.println("失败 " + failedTables.size() + " 个表(已回滚,可重试): " + String.join(", ", failedTables)); - } - } catch (Exception e) { - conn.rollback(); - throw e; - } - } - - int migrateTableData(String tableName, - List newColumns, Map oldColumnTypes) throws SQLException { - // 直接查询 MAX(b_id) 作为 ID 基准(不使用 getNextId 缓存,因为批量插入会生成大量 ID) - long maxId = 0; - String maxSql = "SELECT ISNULL(MAX(b_id), 0) FROM dbo.[" + tableName.replace("]", "]]") + "]"; - try (Statement st = conn.createStatement(); - ResultSet rs = st.executeQuery(maxSql)) { - if (rs.next()) maxId = rs.getLong(1); - } - long baseId = maxId + 1; - - // 构建 INSERT 列列表(包含 b_inputdatetime) - List insertCols = new ArrayList<>(); - List selectExprs = new ArrayList<>(); - - for (String col : newColumns) { - if (SKIP_COLUMNS.contains(col.toLowerCase(Locale.ROOT))) { - // 审计用户字段设为 NULL - insertCols.add("[" + col + "]"); - selectExprs.add("NULL"); - continue; - } - - if (col.equalsIgnoreCase("b_id")) { - // b_id:使用 ROW_NUMBER 生成 - insertCols.add("[b_id]"); - selectExprs.add("(" + baseId + " + ROW_NUMBER() OVER (ORDER BY (SELECT NULL)))"); - continue; - } - - if (col.equalsIgnoreCase("b_inputdatetime")) { - insertCols.add("[b_inputdatetime]"); - selectExprs.add("SYSDATETIME()"); - continue; - } - - if (!oldColumnTypes.containsKey(col)) { - // 旧表没有此列,用特殊值填充 - insertCols.add("[" + col + "]"); - if (col.equalsIgnoreCase("b_code")) { - // b_code:使用旧的 b_id(保留旧 varchar ID 作为 code) - selectExprs.add("LTRIM(RTRIM(old.b_id))"); - } else if (col.equalsIgnoreCase("b_parent_id")) { - selectExprs.add("NULL"); - } else if (col.equalsIgnoreCase("b_canuse") || col.equalsIgnoreCase("b_visible") || col.equalsIgnoreCase("b_used")) { - selectExprs.add("1"); - } else { - // 设为 NULL(nullable 列应该 OK) - selectExprs.add("NULL"); - } - continue; - } - - String oldType = oldColumnTypes.get(col).toLowerCase(Locale.ROOT); - - insertCols.add("[" + col + "]"); - - if (BOOLEAN_COLUMNS.contains(col.toLowerCase(Locale.ROOT)) && isStringType(oldType)) { - // varchar(1) 布尔 → int - selectExprs.add("CASE WHEN LTRIM(RTRIM(old.[" + col + "])) = '1' THEN 1 ELSE 0 END"); - } else if (col.equalsIgnoreCase("b_code") && isStringType(oldType)) { - // b_code 可能为 NULL,回退到旧 b_id - selectExprs.add("CASE WHEN LTRIM(RTRIM(old.b_code)) != '' THEN LTRIM(RTRIM(old.b_code)) ELSE LTRIM(RTRIM(old.b_id)) END"); - } else if (col.toLowerCase(Locale.ROOT).endsWith("_id") && isStringType(oldType)) { - // varchar ID → bigint(尝试转换,失败则为 NULL) - selectExprs.add("TRY_CAST(LTRIM(RTRIM(old.[" + col + "])) AS bigint)"); - } else { - selectExprs.add("old.[" + col + "]"); - } - } - - // 确定唯一键用于去重 - String uniqueCheck = ""; - for (String keyCol : KEY_COLUMNS) { - if (oldColumnTypes.containsKey(keyCol) && newColumns.stream().anyMatch(c -> c.equalsIgnoreCase(keyCol))) { - uniqueCheck = keyCol; - break; - } - } - - // 构建 SQL - StringBuilder sql = new StringBuilder(); - sql.append("INSERT INTO fms.dbo.[").append(tableName).append("] ("); - sql.append(String.join(", ", insertCols)); - sql.append(")\nSELECT "); - sql.append(String.join(",\n ", selectExprs)); - - // 源表去重 + NOT EXISTS - boolean hasBcodeInOld = oldColumnTypes.containsKey("b_code"); - boolean hasBcodeInNew = newColumns.stream().anyMatch(c -> c.equalsIgnoreCase("b_code")); - String bcodeExpr = null; - // 实际存入新表 b_code 的表达式(用于 SELECT 列表中生成 b_code 值) - String bcodeValueExpr = null; - if (hasBcodeInOld && hasBcodeInNew) { - bcodeExpr = "COALESCE(NULLIF(LTRIM(RTRIM(old.b_code)),''), LTRIM(RTRIM(old.b_id)))"; - bcodeValueExpr = "COALESCE(NULLIF(LTRIM(RTRIM(b_code)),''), LTRIM(RTRIM(b_id)))"; - } else if (!hasBcodeInOld && hasBcodeInNew) { - bcodeExpr = "LTRIM(RTRIM(old.b_id))"; - bcodeValueExpr = "LTRIM(RTRIM(b_id))"; - } - - List whereClauses = new ArrayList<>(); - - if (bcodeExpr != null) { - // 源表去重(按实际 b_code 表达式分区,取第一条) - sql.append("\nFROM ("); - sql.append("\n SELECT *, ROW_NUMBER() OVER (PARTITION BY "); - sql.append(bcodeValueExpr); - sql.append(" ORDER BY b_id) AS _rn"); - sql.append("\n FROM G3HY2025.dbo.[").append(tableName).append("]"); - sql.append("\n) old"); - whereClauses.add("old._rn = 1"); - - // NOT EXISTS 去重新表中已有的数据(加 COLLATE 解决排序规则冲突) - whereClauses.add("NOT EXISTS (SELECT 1 FROM fms.dbo.[" + tableName + "] new WHERE new.b_code COLLATE Chinese_PRC_CI_AS = " + bcodeExpr + ")"); - } else { - sql.append("\nFROM G3HY2025.dbo.[").append(tableName).append("] old"); - } - - if (!whereClauses.isEmpty()) { - sql.append("\nWHERE ").append(String.join(" AND ", whereClauses)); - } - - String sqlStr = sql.toString(); - - if (dryRun) { - System.out.println(" SQL: " + sqlStr.substring(0, Math.min(200, sqlStr.length())) + "..."); - // Count rows that would be migrated - String countSql = "SELECT COUNT(*) FROM G3HY2025.dbo.[" + tableName + "]"; - try (Statement st = conn.createStatement(); - ResultSet rs = st.executeQuery(countSql)) { - rs.next(); - return rs.getInt(1); - } - } else { - int count; - try (Statement st = conn.createStatement()) { - count = st.executeUpdate(sqlStr); - } - return count; - } - } - - // ====================================================================== - // 阶段 4:字段元数据同步 - // ====================================================================== - void phaseMetadataSync() throws SQLException { - System.out.println("\n" + "=".repeat(60)); - System.out.println("阶段 4:字段元数据同步(col_Caption/col_Visible/col_edit)"); - System.out.println("=".repeat(60)); - - if (skipMetadata) { - System.out.println("已跳过(--skip-metadata)"); - return; - } - - List mappings = tableMappings.values().stream() - .filter(m -> m.hasModule) - .distinct() - .sorted(Comparator.comparing(m -> m.viewTable)) - .toList(); - - if (mappings.isEmpty()) { - System.out.println("没有可同步的表。"); - return; - } - - conn.setAutoCommit(false); - try { - // 初始化 ID 生成器 - long listNextId = getNextId("s_module_field_list"); - long editNextId = getNextId("s_module_field_edit"); - - for (TableMapping mapping : mappings) { - String viewTable = mapping.viewTable; - System.out.println("\n--- 同步 " + viewTable + " (" + mapping.moduleCode + ") ---"); - - // 1. 字段名称 - int nameUpdated = syncFieldNames(conn, viewTable); - System.out.println(" 字段名称: " + nameUpdated + " 条更新"); - - // 2. 列表显示 - int listUpdated = syncListVisibility(conn, viewTable); - int listInserted = insertMissingListRecords(conn, viewTable, listNextId); - listNextId += listInserted; - System.out.println(" 列表显示: " + listUpdated + " 条更新, " + listInserted + " 条新增"); - - // 3. 编辑显示 - int editUpdated = syncEditVisibility(conn, viewTable); - int editInserted = insertMissingEditRecords(conn, viewTable, editNextId); - editNextId += editInserted; - System.out.println(" 编辑显示: " + editUpdated + " 条更新, " + editInserted + " 条新增"); - } - - if (!dryRun) { - conn.commit(); - System.out.println("\n元数据同步已提交。"); - } else { - System.out.println("\n[Dry-run] 元数据同步已模拟完成,未实际提交。"); - conn.rollback(); - } - } catch (Exception e) { - conn.rollback(); - throw e; - } - } - - // ---- FieldNameSync 复用的 SQL ---- - static final String SYNC_NAME = """ - UPDATE sf - SET sf.b_name = LTRIM(RTRIM(sc.col_Caption)) - FROM dbo.s_module_field sf - JOIN dbo.s_module m ON m.b_id = sf.b_module_id - JOIN G3HY2025.dbo.s_columnLib sc - ON sc.col_TableName COLLATE Chinese_PRC_CI_AS = m.b_viewtable - AND sc.col_FieldName COLLATE Chinese_PRC_CI_AS = sf.b_field - WHERE m.b_viewtable = ? - AND sc.col_Caption IS NOT NULL - AND LTRIM(RTRIM(sc.col_Caption)) != '' - """; - - static final String SYNC_LIST_UPDATE = """ - UPDATE sfl - SET sfl.b_visible = CASE WHEN sc.col_Visible = '1' THEN 1 ELSE 0 END - FROM dbo.s_module_field_list sfl - JOIN dbo.s_module_field sf ON sf.b_id = sfl.b_field_id - JOIN dbo.s_module m ON m.b_id = sf.b_module_id - JOIN G3HY2025.dbo.s_columnLib sc - ON sc.col_TableName COLLATE Chinese_PRC_CI_AS = m.b_viewtable - AND sc.col_FieldName COLLATE Chinese_PRC_CI_AS = sf.b_field - WHERE m.b_viewtable = ? - AND sc.col_Visible IS NOT NULL - AND LTRIM(RTRIM(sc.col_Visible)) != '' - """; - - static final String LIST_INSERT_CANDIDATES = """ - SELECT sf.b_id AS field_id, m.b_id AS module_id, - CASE WHEN sc.col_Visible = '1' THEN 1 ELSE 0 END AS visible - FROM dbo.s_module_field sf - JOIN dbo.s_module m ON m.b_id = sf.b_module_id - JOIN G3HY2025.dbo.s_columnLib sc - ON sc.col_TableName COLLATE Chinese_PRC_CI_AS = m.b_viewtable - AND sc.col_FieldName COLLATE Chinese_PRC_CI_AS = sf.b_field - WHERE m.b_viewtable = ? - AND sc.col_Visible IS NOT NULL - AND LTRIM(RTRIM(sc.col_Visible)) != '' - AND NOT EXISTS ( - SELECT 1 FROM dbo.s_module_field_list sfl - WHERE sfl.b_field_id = sf.b_id - ) - """; - - static final String INSERT_LIST = """ - INSERT INTO dbo.s_module_field_list (b_id, b_module_id, b_field_id, b_visible, b_xh) - VALUES (?, ?, ?, ?, 0) - """; - - static final String SYNC_EDIT_UPDATE = """ - UPDATE sfe - SET sfe.b_visible = CASE WHEN sc.col_edit = '1' THEN 1 ELSE 0 END - FROM dbo.s_module_field_edit sfe - JOIN dbo.s_module_field sf ON sf.b_id = sfe.b_field_id - JOIN dbo.s_module m ON m.b_id = sf.b_module_id - JOIN G3HY2025.dbo.s_columnLib sc - ON sc.col_TableName COLLATE Chinese_PRC_CI_AS = m.b_viewtable - AND sc.col_FieldName COLLATE Chinese_PRC_CI_AS = sf.b_field - WHERE m.b_viewtable = ? - AND sc.col_edit IS NOT NULL - AND LTRIM(RTRIM(sc.col_edit)) != '' - """; - - static final String EDIT_INSERT_CANDIDATES = """ - SELECT sf.b_id AS field_id, m.b_id AS module_id, - CASE WHEN sc.col_edit = '1' THEN 1 ELSE 0 END AS visible - FROM dbo.s_module_field sf - JOIN dbo.s_module m ON m.b_id = sf.b_module_id - JOIN G3HY2025.dbo.s_columnLib sc - ON sc.col_TableName COLLATE Chinese_PRC_CI_AS = m.b_viewtable - AND sc.col_FieldName COLLATE Chinese_PRC_CI_AS = sf.b_field - WHERE m.b_viewtable = ? - AND sc.col_edit IS NOT NULL - AND LTRIM(RTRIM(sc.col_edit)) != '' - AND NOT EXISTS ( - SELECT 1 FROM dbo.s_module_field_edit sfe - WHERE sfe.b_field_id = sf.b_id - ) - """; - - static final String INSERT_EDIT = """ - INSERT INTO dbo.s_module_field_edit (b_id, b_module_id, b_field_id, b_visible, b_required, b_readonly, b_disabled, b_xh) - VALUES (?, ?, ?, ?, 0, 0, 0, 0) - """; - - int syncFieldNames(Connection conn, String viewTable) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement(SYNC_NAME)) { - ps.setString(1, viewTable); - return ps.executeUpdate(); - } - } - - int syncListVisibility(Connection conn, String viewTable) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement(SYNC_LIST_UPDATE)) { - ps.setString(1, viewTable); - return ps.executeUpdate(); - } - } - - int insertMissingListRecords(Connection conn, String viewTable, long startId) throws SQLException { - List candidates = new ArrayList<>(); - try (PreparedStatement ps = conn.prepareStatement(LIST_INSERT_CANDIDATES)) { - ps.setString(1, viewTable); - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - candidates.add(new long[]{rs.getLong("field_id"), rs.getLong("module_id"), rs.getLong("visible")}); - } - } - } - if (!candidates.isEmpty()) { - try (PreparedStatement ps = conn.prepareStatement(INSERT_LIST)) { - for (long[] row : candidates) { - ps.setLong(1, startId++); - ps.setLong(2, row[1]); - ps.setLong(3, row[0]); - ps.setInt(4, (int) row[2]); - ps.addBatch(); - } - ps.executeBatch(); - } - } - return candidates.size(); - } - - int syncEditVisibility(Connection conn, String viewTable) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement(SYNC_EDIT_UPDATE)) { - ps.setString(1, viewTable); - return ps.executeUpdate(); - } - } - - int insertMissingEditRecords(Connection conn, String viewTable, long startId) throws SQLException { - List candidates = new ArrayList<>(); - try (PreparedStatement ps = conn.prepareStatement(EDIT_INSERT_CANDIDATES)) { - ps.setString(1, viewTable); - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - candidates.add(new long[]{rs.getLong("field_id"), rs.getLong("module_id"), rs.getLong("visible")}); - } - } - } - if (!candidates.isEmpty()) { - try (PreparedStatement ps = conn.prepareStatement(INSERT_EDIT)) { - for (long[] row : candidates) { - ps.setLong(1, startId++); - ps.setLong(2, row[1]); - ps.setLong(3, row[0]); - ps.setInt(4, (int) row[2]); - ps.addBatch(); - } - ps.executeBatch(); - } - } - return candidates.size(); - } - - // ====================================================================== - // 辅助方法 - // ====================================================================== - List groupsWithModules() { - Set groups = new LinkedHashSet<>(); - for (OldBmflEntry e : oldEntries) { - if (tableMappings.containsKey(e.tableName)) { - groups.add(e.groupBy); - } - } - return new ArrayList<>(groups); - } - - boolean tableExistsInNew(String tableName) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement(TABLE_EXISTS_SQL)) { - ps.setString(1, tableName); - try (ResultSet rs = ps.executeQuery()) { - return rs.next() && rs.getInt(1) > 0; - } - } - } - - TableMapping findModuleByViewTable(String tableName) throws SQLException { - String sql = """ - SELECT m.b_id, m.b_code, m.b_name, m.b_viewtable - FROM dbo.s_module m - WHERE m.b_viewtable = ? - AND m.b_module_type = 'data' - AND m.b_canuse = 1 - """; - try (PreparedStatement ps = conn.prepareStatement(sql)) { - ps.setString(1, tableName); - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - TableMapping tm = new TableMapping(); - tm.moduleId = rs.getLong("b_id"); - tm.moduleCode = rs.getString("b_code"); - tm.moduleName = rs.getString("b_name"); - tm.viewTable = rs.getString("b_viewtable"); - tm.hasModule = true; - return tm; - } - } - } - - // 也尝试匹配视图(v_ 前缀) - String viewTable = "v_" + tableName; - try (PreparedStatement ps = conn.prepareStatement(sql)) { - ps.setString(1, viewTable); - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - TableMapping tm = new TableMapping(); - tm.moduleId = rs.getLong("b_id"); - tm.moduleCode = rs.getString("b_code"); - tm.moduleName = rs.getString("b_name"); - tm.viewTable = rs.getString("b_viewtable"); - tm.hasModule = true; - return tm; - } - } - } - return null; - } - - List getNewColumnNames(String tableName) throws SQLException { - List columns = new ArrayList<>(); - try (PreparedStatement ps = conn.prepareStatement(NEW_TABLE_COLUMNS)) { - ps.setString(1, tableName); - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - columns.add(rs.getString("COLUMN_NAME")); - } - } - } - return columns; - } - - Map getOldColumnTypes(String tableName) throws SQLException { - Map types = new LinkedHashMap<>(); - try (PreparedStatement ps = conn.prepareStatement(OLD_TABLE_COLUMNS)) { - ps.setString(1, tableName); - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - types.put(rs.getString("COLUMN_NAME"), rs.getString("DATA_TYPE")); - } - } - } - return types; - } - - boolean ensureColumn(String tableName, String columnName, String columnDef) throws SQLException { - String checkSql = """ - SELECT COUNT(*) FROM fms.INFORMATION_SCHEMA.COLUMNS - WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = ? AND COLUMN_NAME = ? - """; - try (PreparedStatement ps = conn.prepareStatement(checkSql)) { - ps.setString(1, tableName); - ps.setString(2, columnName); - try (ResultSet rs = ps.executeQuery()) { - if (rs.next() && rs.getInt(1) > 0) { - System.out.println(" b_other_bmfl 已有 " + columnName + " 列。"); - return true; - } - } - } - // 列不存在 - if (dryRun) { - System.out.println(" [Dry-run] 缺少列 " + columnName + "(需要 " + columnDef + "),将跳过树迁移。"); - System.out.println(" 请先运行: ALTER TABLE dbo." + tableName + " ADD " + columnName + " " + columnDef); - return false; - } - String alterSql = "ALTER TABLE dbo.[" + tableName + "] ADD " + columnName + " " + columnDef; - try (Statement st = conn.createStatement()) { - st.executeUpdate(alterSql); - System.out.println(" 自动添加列 " + columnName + " " + columnDef + " 到 " + tableName + "。"); - return true; - } catch (SQLException e) { - System.err.println(" 添加列 " + columnName + " 失败: " + e.getMessage()); - return false; - } - } - - long getNextId(String tableName) throws SQLException { - if (nextIdCache.containsKey(tableName)) { - long next = nextIdCache.get(tableName); - nextIdCache.put(tableName, next + 1); - return next; - } - - long maxId = 0; - String sql = "SELECT ISNULL(MAX(b_id), 0) FROM dbo.[" + tableName.replace("]", "]]") + "]"; - try (Statement st = conn.createStatement(); - ResultSet rs = st.executeQuery(sql)) { - if (rs.next()) maxId = rs.getLong(1); - } - - long next = maxId + 1; - nextIdCache.put(tableName, next + 1); - return next; - } - - static boolean isStringType(String type) { - String lower = type.toLowerCase(Locale.ROOT); - return lower.equals("varchar") || lower.equals("nvarchar") - || lower.equals("char") || lower.equals("nchar") - || lower.equals("text") || lower.equals("ntext"); - } - - static String trim(String s) { - return s == null ? null : s.trim(); - } - - static String truncate(String s, int maxLen) { - if (s == null) return "(null)"; - if (s.length() <= maxLen) return s; - return s.substring(0, maxLen - 3) + "..."; - } -} diff --git a/code/fms/fms-api/tools/migration/OtherDataProbe.java b/code/fms/fms-api/tools/migration/OtherDataProbe.java new file mode 100644 index 00000000..274637a4 --- /dev/null +++ b/code/fms/fms-api/tools/migration/OtherDataProbe.java @@ -0,0 +1,367 @@ +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * 只读探测工具,迁移期间使用: + * list 列出旧库 b_other_bmfl 全部分组与模块清单(启用、旧库行数、新库是否已建) + * tables <表名...> 输出指定表的三段信息:新库结构、旧库结构、旧库数据样例(前 3 行) + * + * 输出写入 tools/migration/ 下的文件(UTF-8 BOM,便于 Windows 记事本打开): + * list → otherdata-modules.txt + * tables → otherdata-probe-out.txt + * + * 用法(源码启动模式,不产生 .class 文件): + * cd fms-api + * java -cp "tools/migration/mssql-jdbc-13.4.0.jre11.jar" tools/migration/OtherDataProbe.java list + * java -cp "tools/migration/mssql-jdbc-13.4.0.jre11.jar" tools/migration/OtherDataProbe.java tables b_port b_money + */ +public final class OtherDataProbe { + + private static final Path MIGRATION_DIR = Path.of("").toAbsolutePath().normalize().resolve("tools/migration"); + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + usage(); + return; + } + switch (args[0]) { + case "list" -> listModules(); + case "columns" -> listColumns(); + case "tables" -> { + if (args.length < 2) { + usage(); + return; + } + probeTables(Arrays.copyOfRange(args, 1, args.length)); + } + default -> usage(); + } + } + + private static void usage() { + System.out.println("用法:"); + System.out.println(" list 列出旧库 b_other_bmfl 全部分组与模块清单"); + System.out.println(" columns 导出其他数据各字典在旧库 s_columnLib 的列配置"); + System.out.println(" tables b_port b_money 输出指定表的新库结构、旧库结构、旧库数据样例"); + } + + // ------------------------------------------------------------ list 模式 + + /** 旧库 b_other_bmfl 的一个模块(一条数据表登记) */ + private record Module(String table, String name, boolean enabled) {} + + private static void listModules() throws Exception { + Path output = MIGRATION_DIR.resolve("otherdata-modules.txt"); + try (PrintStream out = newBomPrintStream(output); + Connection old = connect("G3HY2025"); + Connection fms = connect("G3HD")) { + + Map> groups = new LinkedHashMap<>(); + try (Statement statement = old.createStatement(); + ResultSet rows = statement.executeQuery(""" + select isnull(nullif(b_groupby, ''), '(未分组)') as grp, + ltrim(rtrim(b_tablename)) as tbl, + isnull(mc_b, '') as mc, + isnull(b_canuse, '') as canuse + from G3HY2025.dbo.b_other_bmfl + where b_tablename is not null and ltrim(rtrim(b_tablename)) != '' + order by grp, b_xh, mc + """)) { + while (rows.next()) { + groups.computeIfAbsent(rows.getString("grp"), key -> new ArrayList<>()) + .add(new Module(rows.getString("tbl"), rows.getString("mc"), + "1".equals(rows.getString("canuse")))); + } + } + + Set fmsObjects = fmsObjectNames(fms); + + out.println("=== 旧库 b_other_bmfl 模块清单 ==="); + out.println(" 表名" + pad("", 22) + "名称" + pad("", 20) + "状态 旧库行数 新库"); + + int total = 0; + int totalEnabled = 0; + int totalWithData = 0; + int totalBuilt = 0; + int groupIndex = 0; + for (Map.Entry> entry : groups.entrySet()) { + groupIndex++; + int enabled = 0; + int withData = 0; + int built = 0; + StringBuilder body = new StringBuilder(); + for (Module module : entry.getValue()) { + long oldRows = countRows(old, module.table()); + boolean exists = existsInFms(fmsObjects, module.table()); + if (module.enabled()) { + enabled++; + } + if (oldRows > 0) { + withData++; + } + if (exists) { + built++; + } + body.append(" ") + .append(pad(module.table(), 26)) + .append(pad(module.name(), 24)) + .append(pad(module.enabled() ? "启用" : "停用", 6)) + .append(pad(oldRows < 0 ? "-" : String.valueOf(oldRows), 10)) + .append(exists ? "已建" : "-") + .append(System.lineSeparator()); + } + total += entry.getValue().size(); + totalEnabled += enabled; + totalWithData += withData; + totalBuilt += built; + out.println(); + out.println("[" + groupIndex + "] " + entry.getKey() + " —— " + entry.getValue().size() + + " 张(启用 " + enabled + "、有数据 " + withData + "、新库已建 " + built + ")"); + out.print(body); + } + + out.println(); + out.println("合计 " + total + " 张(启用 " + totalEnabled + "、有数据 " + totalWithData + + "、新库已建 " + totalBuilt + ")"); + } + System.out.println("输出已写入: " + output); + } + + private static long countRows(Connection old, String table) { + for (String name : List.of(table, "b_" + table, "v_" + table)) { + try (Statement statement = old.createStatement(); + ResultSet rows = statement.executeQuery( + "select count(*) from dbo.[" + name.replace("]", "]]") + "]")) { + rows.next(); + return rows.getLong(1); + } catch (Exception ignored) { + // 试下一个候选名 + } + } + return -1; + } + + private static Set fmsObjectNames(Connection fms) throws Exception { + Set names = new HashSet<>(); + try (Statement statement = fms.createStatement(); + ResultSet rows = statement.executeQuery( + "select name from sys.objects where type in ('U', 'V')")) { + while (rows.next()) { + names.add(rows.getString(1).toLowerCase(Locale.ROOT)); + } + } + return names; + } + + private static boolean existsInFms(Set fmsObjects, String table) { + return fmsObjects.contains(table.toLowerCase(Locale.ROOT)) + || fmsObjects.contains(("v_" + table).toLowerCase(Locale.ROOT)); + } + + // --------------------------------------------------------- columns 模式 + + /** 导出 base_otherdata 各字典表在旧库 s_columnLib 的列配置(列表列 / 表单字段) */ + private static void listColumns() throws Exception { + Path output = MIGRATION_DIR.resolve("otherdata-columns.txt"); + try (PrintStream out = newBomPrintStream(output); + Connection fms = connect("G3HD")) { + + List modules = new ArrayList<>(); + try (Statement statement = fms.createStatement(); + ResultSet rows = statement.executeQuery( + "select b_save_table, b_name from dbo.s_module " + + "where b_path like '/base/base_otherdata/%' and b_module_type = 'data' " + + "order by b_xh, b_id")) { + while (rows.next()) { + modules.add(new String[] {rows.getString(1), rows.getString(2)}); + } + } + + out.println("=== 旧库 s_columnLib 配置(base_otherdata 各字典) ==="); + out.println(" 列表=col_Visible(1 进列表) 表单=col_edit(1 进表单) 宽=col_Width 位置=col_Position 表单位置=col_edit_position"); + + int total = 0; + int inList = 0; + int inEdit = 0; + for (String[] module : modules) { + String table = module[0]; + out.println(); + out.println("--- " + table + "(" + module[1] + ")---"); + int count = 0; + try (PreparedStatement statement = fms.prepareStatement( + "select col_FieldName, col_Caption, col_Visible, col_edit, col_Width, col_Position, col_edit_position " + + "from G3HY2025.dbo.s_columnLib where col_TableName = ? " + + "order by isnull(col_Position, 9999), col_FieldName")) { + statement.setString(1, table); + try (ResultSet rows = statement.executeQuery()) { + while (rows.next()) { + count++; + String visible = text(rows.getString(3)); + String edit = text(rows.getString(4)); + Object width = rows.getObject(5); + Object position = rows.getObject(6); + Object editPosition = rows.getObject(7); + if ("1".equals(visible)) { + inList++; + } + if ("1".equals(edit)) { + inEdit++; + } + out.println(" " + pad(rows.getString(1), 24) + pad(rows.getString(2), 20) + + "列表=" + pad(visible, 5) + "表单=" + pad(edit, 5) + + "宽=" + pad(width == null ? "-" : String.valueOf(width), 7) + + "位置=" + pad(position == null ? "-" : String.valueOf(position), 7) + + "表单位置=" + (editPosition == null ? "-" : String.valueOf(editPosition))); + } + } + } + total += count; + if (count == 0) { + out.println(" (旧库无配置)"); + } + } + + out.println(); + out.println("合计: " + modules.size() + " 个模块、" + total + " 条字段配置(进列表 " + inList + + "、进表单 " + inEdit + ")"); + } + System.out.println("输出已写入: " + output); + } + + private static String text(String value) { + return value == null ? "" : value.trim(); + } + + // ---------------------------------------------------------- tables 模式 + + private static void probeTables(String[] tables) throws Exception { + Path output = MIGRATION_DIR.resolve("otherdata-probe-out.txt"); + try (PrintStream out = newBomPrintStream(output); + Connection old = connect("G3HY2025"); + Connection fms = connect("G3HD")) { + + out.println("=== 新库 FMS:表结构 ==="); + for (String table : tables) { + out.println(); + out.println("--- " + table + " ---"); + columns(fms, out, table); + } + + out.println(); + out.println("=== 旧库 G3HY2025:表结构 ==="); + for (String table : tables) { + out.println(); + out.println("--- " + table + " ---"); + columns(old, out, table); + } + + out.println(); + out.println("=== 旧库 G3HY2025:数据样例(每表前 3 行) ==="); + for (String table : tables) { + out.println(); + out.println("--- " + table + " ---"); + query(old, out, "select top 3 * from dbo.[" + table.replace("]", "]]") + "]"); + } + } + System.out.println("输出已写入: " + output); + } + + private static void columns(Connection connection, PrintStream out, String table) { + try (Statement statement = connection.createStatement(); + ResultSet rows = statement.executeQuery( + "select name, type_name(user_type_id) as t, max_length, is_nullable from sys.columns " + + "where object_id = object_id('dbo.[" + table.replace("]", "]]") + "]') order by column_id")) { + int count = 0; + while (rows.next()) { + count++; + out.println(" " + pad(rows.getString(1), 24) + pad(rows.getString(2), 14) + + pad(String.valueOf(rows.getInt(3)), 8) + (rows.getBoolean(4) ? "null" : "not null")); + } + if (count == 0) { + out.println(" (表不存在)"); + } + } catch (Exception e) { + out.println(" 读取失败: " + e.getMessage()); + } + } + + private static void query(Connection connection, PrintStream out, String sql) { + try (Statement statement = connection.createStatement(); + ResultSet rows = statement.executeQuery(sql)) { + ResultSetMetaData meta = rows.getMetaData(); + StringBuilder header = new StringBuilder(" "); + for (int i = 1; i <= meta.getColumnCount(); i++) { + header.append(pad(meta.getColumnLabel(i), 20)); + } + out.println(header.toString().stripTrailing()); + int count = 0; + while (rows.next()) { + count++; + StringBuilder line = new StringBuilder(" "); + for (int i = 1; i <= meta.getColumnCount(); i++) { + Object value = rows.getObject(i); + String text = value == null ? "(null)" : String.valueOf(value).replaceAll("\\s+", " "); + if (text.length() > 60) { + text = text.substring(0, 60) + "…"; + } + line.append(pad(text, 20)); + } + out.println(line.toString().stripTrailing()); + } + out.println(" (" + count + " 行)"); + } catch (Exception e) { + out.println(" 查询失败: " + e.getMessage()); + } + } + + // -------------------------------------------------------------- 基础设施 + + private static PrintStream newBomPrintStream(Path output) throws Exception { + FileOutputStream file = new FileOutputStream(output.toFile()); + file.write(0xEF); + file.write(0xBB); + file.write(0xBF); + return new PrintStream(file, true, StandardCharsets.UTF_8); + } + + private static Connection connect(String org) throws Exception { + Path apiRoot = Path.of("").toAbsolutePath().normalize(); + Properties properties = new Properties(); + try (InputStream input = Files.newInputStream(apiRoot.resolve("config/dbconfigs/" + org + ".properties"))) { + properties.load(input); + } + return DriverManager.getConnection( + properties.getProperty("url"), + properties.getProperty("username"), + properties.getProperty("password")); + } + + private static String pad(String value, int width) { + String text = value == null ? "" : value; + int display = text.length(); + while (display < width) { + text += " "; + display++; + } + return text; + } +} diff --git a/code/fms/fms-api/tools/migration/README.md b/code/fms/fms-api/tools/migration/README.md index 48a07b58..adbc04ac 100644 --- a/code/fms/fms-api/tools/migration/README.md +++ b/code/fms/fms-api/tools/migration/README.md @@ -9,7 +9,9 @@ | --- | --- | --- | | `FieldNameSync.java` | **V2 当前版本** | 从旧库 `s_columnLib` 同步字段名称与显示配置到 `s_field` / `s_module_schema` | | `SchemaDumpMarkdown.java` | 通用 | 导出该实例上任意库的表与视图结构为 Markdown | -| `OtherDataMigration.java` | **V1 历史工具,未改造,勿用于 V2** | 面向 V1 表结构(`s_module_field` / `s_module_field_list` / `s_module_field_edit`)与 `b_other_bmfl` 旧树结构,V2 下这些表已不存在,仅作历史参考 | +| `RunSqlFile.java` | 通用 | 在 FMS 库执行 `sql/` 下的建表 / 视图 / 索引脚本(按 GO 分批,单事务) | +| `OtherDataProbe.java` | 迁移辅助(只读) | `list` 列出旧库 `b_other_bmfl` 的 65 个字典模块(启用/旧库行数/新库已建),输出 `otherdata-modules.txt`;`tables <表名...>` 导出新旧结构 + 旧库数据样例 | +| `OtherDataMigrate.java` | **其他数据迁移** | 导入 `base_otherdata` 下 64 个字典模块的数据(雪花主键)、重建 `b_from`/`b_grade`、转换 `b_othercompany` 引用值,输出映射 `otherdata-id-map.tsv`;支持 `--dry-run` | --- @@ -50,7 +52,8 @@ view / edit 两份 `b_schema_json` 由旧库名单**完整重新生成**, 其余字段(标志为 `'0'`、空值、旧库无记录)**直接不写入 JSON**,不写 `visible:false`。 `s_field` 里有、旧库名单里没有的字段同样不进入配置(节点不存在 = 不显示、不参与表单)。 -顺序取旧库位置列:view 按 `col_Position`、edit 按 `col_edit_position`,位置缺失的排在最后。 +顺序取旧库位置列:view 按 `col_Position`、edit 按 `col_edit_position`,位置缺失的排在最后; +view 里备注列(`b_bz`)固定排到最后。 列表列宽取 `col_Width`,未配置时省略 `width` 键(前端按自身默认值渲染)。 生成的 JSON 结构与前端消费侧一致 @@ -110,6 +113,7 @@ del FieldNameSync*.class | `--dry-run` | 只报告不写库,结束时回滚 | | `--skip-schema` | 只同步 `s_field.b_name`,不重建 `s_module_schema` | | `--force` | 允许覆盖已存在且非空的 `s_module_schema` 行 | +| `--all-otherdata` | 批量模式:同步 `base_otherdata` 下所有数据模块(不需要 ``,失败跳过继续) | ### 输出示例 @@ -169,6 +173,34 @@ java -Dstdout.encoding=UTF-8 -cp ".;mssql-jdbc-13.4.0.jre11.jar" SchemaDumpMarkd 输出包含:对象清单(名称/类型/字段数/主键)、各表字段结构(含主键与外键)、视图字段结构。 字段「备注」列留空,供后续补充含义。 +--- + +## RunSqlFile — 执行 sql 脚本 + +执行 `sql/` 目录下的脚本。目标库固定取 `config/dbconfigs/G3HD.properties`,执行前校验 +catalog 必须是 `FMS`;按 `GO` 把脚本拆成批次,在单个事务中依次执行,任一批失败整体回滚。 + +```bash +cd fms-api + +# 先 dry-run 看批次划分 +java -Dstdout.encoding=UTF-8 -cp "tools/migration/mssql-jdbc-13.4.0.jre11.jar" \ + tools/migration/RunSqlFile.java ../sql/fms_business_contact.sql --dry-run + +# 确认后执行 +java -Dstdout.encoding=UTF-8 -cp "tools/migration/mssql-jdbc-13.4.0.jre11.jar" \ + tools/migration/RunSqlFile.java ../sql/fms_business_contact.sql +``` + +源码启动模式不产生 `.class` 文件;如需手动编译: + +```bash +cd fms-api/tools/migration +javac -encoding UTF-8 -cp "mssql-jdbc-13.4.0.jre11.jar" RunSqlFile.java +``` + +> 含「重建」段落(`drop ... if exists`)的脚本会删除同名表及其数据,执行前确认表中数据已不需要。 + ## 已有同步记录 | 模块 / 视图 | 同步日期 | 字段数 | 备注 | @@ -177,3 +209,5 @@ java -Dstdout.encoding=UTF-8 -cp ".;mssql-jdbc-13.4.0.jre11.jar" SchemaDumpMarkd | `v_b_contact` | 2026-07-30 | 36 | V1 时代(`s_module_field*`,已废弃) | | `b_port` | 2026-08-01 | 13 | V1 时代(`s_module_field*`,已废弃) | | `v_b_othercompany` | 2026-09-14 | 51 | V2:改名 43 条、保留原值 8 条;重建 view(15 列,含旧库列宽/顺序)与 edit(41 个字段),未进入配置的字段不写入 JSON | +| `v_b_contact` | 2026-09-14 | 36 | V2:改名 28 条、保留原值 8 条;重建 view(19 列)与 edit(19 个字段)。同批新增 `b_contact` / `b_contact_type` 表、`v_b_contact` 视图与模块注册 | +| 其他数据(`base_otherdata`) | 2026-09-14 | 668 | 62 张字典表(`sql/fms_business_otherdata.sql`,模块直接查表)、模块注册(`sql/fms_module_otherdata.sql`:根 + 6 个分组 + 64 个数据模块,编码 = 表名)、导入 555 行(`OtherDataMigrate.java`);`FieldNameSync --all-otherdata --force` 同步字段名与 view/edit 配置(含重命名字段别名 `b_vessel_name`→`b_name`、`b_name_c`→`b_name`),新增通用字段名由注册脚本补齐,旧库无配置的 44 个模块补默认列(名称 + 备注)。`b_from`/`b_grade` 已重建为雪花,其引用转换待 `b_othercompany` 数据迁入后重跑 | diff --git a/code/fms/fms-api/tools/migration/RunSqlFile.java b/code/fms/fms-api/tools/migration/RunSqlFile.java new file mode 100644 index 00000000..7d93b57d --- /dev/null +++ b/code/fms/fms-api/tools/migration/RunSqlFile.java @@ -0,0 +1,93 @@ +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.regex.Pattern; + +/** + * 执行 sql/ 目录下的脚本(按 GO 分批),用于建表 / 索引 / 视图。 + * + * 用法(在 fms-api 目录下运行): + * java -cp "tools/migration/mssql-jdbc-13.4.0.jre11.jar" tools/migration/RunSqlFile.java [--dry-run] + * + * 说明: + * - 目标库固定取 config/dbconfigs/G3HD.properties,执行前校验 catalog 必须是 FMS。 + * - 含「重建」段落(drop ... if exists)的脚本请确认表数据已不需要后再执行。 + * - DDL 在单个事务中执行,任一批次失败整体回滚。 + */ +public final class RunSqlFile { + private static final Pattern GO = Pattern.compile("(?im)^\\s*GO\\s*;?\\s*$"); + + public static void main(String[] args) throws Exception { + if (args.length < 1) { + System.out.println("用法: RunSqlFile [--dry-run]"); + return; + } + Path script = Path.of(args[0]).toAbsolutePath().normalize(); + boolean dryRun = args.length > 1 && "--dry-run".equalsIgnoreCase(args[1]); + + Path apiRoot = Path.of("").toAbsolutePath().normalize(); + Properties properties = new Properties(); + try (InputStream input = Files.newInputStream(apiRoot.resolve("config/dbconfigs/G3HD.properties"))) { + properties.load(input); + } + + List batches = new ArrayList<>(); + for (String batch : GO.split(Files.readString(script, StandardCharsets.UTF_8))) { + String trimmed = batch.trim(); + if (!trimmed.isEmpty()) { + batches.add(trimmed); + } + } + + System.out.println("脚本: " + script); + System.out.println("批次: " + batches.size() + (dryRun ? "(dry-run,不执行)" : "")); + for (String batch : batches) { + System.out.println(" - " + firstLine(batch)); + } + if (dryRun) { + return; + } + + try (Connection connection = DriverManager.getConnection( + properties.getProperty("url"), + properties.getProperty("username"), + properties.getProperty("password"))) { + if (!"FMS".equalsIgnoreCase(connection.getCatalog())) { + throw new IllegalStateException("Refusing to run on database: " + connection.getCatalog()); + } + connection.setAutoCommit(false); + int applied = 0; + try { + for (String batch : batches) { + try (Statement statement = connection.createStatement()) { + statement.execute(batch); + } + applied++; + System.out.println("APPLIED|" + firstLine(batch)); + } + connection.commit(); + } catch (Exception e) { + connection.rollback(); + throw new IllegalStateException("第 " + (applied + 1) + " 批失败,已回滚: " + e.getMessage(), e); + } + System.out.println("OK|batches=" + applied); + } + } + + private static String firstLine(String batch) { + for (String line : batch.split("\\R")) { + String trimmed = line.trim(); + if (!trimmed.isEmpty() && !trimmed.startsWith("--") && !trimmed.startsWith("/*")) { + return trimmed.length() > 90 ? trimmed.substring(0, 90) + "..." : trimmed; + } + } + return batch.split("\\R")[0].trim(); + } +} diff --git a/code/fms/fms-api/tools/migration/file-tables-out.txt b/code/fms/fms-api/tools/migration/file-tables-out.txt new file mode 100644 index 00000000..e0f63464 --- /dev/null +++ b/code/fms/fms-api/tools/migration/file-tables-out.txt @@ -0,0 +1,2 @@ +=== bf_files === +--- 行数 --- diff --git a/code/fms/fms-api/tools/migration/menu-probe-out.txt b/code/fms/fms-api/tools/migration/menu-probe-out.txt new file mode 100644 index 00000000..cb4f8401 --- /dev/null +++ b/code/fms/fms-api/tools/migration/menu-probe-out.txt @@ -0,0 +1,111 @@ +=== 1. s_menu 列 === +b_id varchar len=50 null=0 +b_parent_id varchar len=50 null=1 +b_depth int len=4 null=0 +b_path varchar len=1000 null=0 +b_name nvarchar len=400 null=0 +b_i18n varchar len=150 null=1 +b_menu_type varchar len=20 null=0 +b_route varchar len=500 null=1 +b_icon varchar len=50 null=1 +b_xh int len=4 null=0 +b_canuse tinyint len=1 null=0 + +=== 2. s_menu_module 列 === +b_menu_id varchar len=50 null=0 +b_module_id varchar len=50 null=0 +b_xh int len=4 null=0 +b_canuse tinyint len=1 null=0 + +=== 3. s_menu 数据(菜单树) === +b_id | b_parent_id | b_name | b_menu_type | b_route | b_canuse +base | null | 基础资料 | directory | null | 1 +contact | base | 联系人 | page | /base/contact | 1 +otherdata | base | 其他数据 | page | /base/otherdata | 1 +partner | base | 合作伙伴 | page | /base/othercompany | 1 +(共 4 行) + +=== 4. s_menu_module 数据(菜单-模块绑定) === +b_menu_id | b_module_id | b_xh | b_canuse +(共 0 行) + +=== 5. s_module 类型分布 === +b_module_type | total | enabled +data | 67 | 51 +module | 9 | 9 +(共 2 行) + +=== 6. base_otherdata 子树(其他数据页所用模块) === +b_id | b_parent_id | b_module_type | b_name | b_canuse +base_otherdata | base | module | 其他数据 | 1 +od_air | base_otherdata | module | 空运 | 1 +b_dcterm | od_air | data | 订舱条款 | 1 +b_ywtype_ky | od_air | data | 业务类型 | 1 +od_common | base_otherdata | module | 常用 | 1 +b_dailyfeetype | od_common | data | 日常费用 | 1 +b_dailytype | od_common | data | 收支类型 | 0 +b_feetype | od_common | data | 费用类别 | 1 +b_goodssource | od_common | data | 货物来源 | 1 +b_money | od_common | data | 币种 | 1 +b_oceanline | od_common | data | 航线 | 1 +b_port | od_common | data | 港口 | 1 +b_ysfs | od_common | data | 运输方式 | 1 +b_ywtype | od_common | data | 业务类型 | 1 +od_depot | base_otherdata | module | 仓库 | 1 +b_depot | od_depot | data | 仓库 | 1 +b_depotintype | od_depot | data | 入库类型 | 1 +b_depotouttype | od_depot | data | 出库类型 | 1 +od_logistics | base_otherdata | module | 物流 | 1 +b_cdtype | od_logistics | data | 派车类型 | 1 +b_shfs | od_logistics | data | 派送方式 | 1 +b_thfs | od_logistics | data | 提货方式 | 1 +b_wangdian | od_logistics | data | 网点 | 1 +b_ywfrom | od_logistics | data | 业务来源 | 1 +b_ywtype_tc | od_logistics | data | 业务类型 | 1 +car_daily_feetype | od_logistics | data | 费用报销-费用类型 | 1 +car_jiayou_jsfs | od_logistics | data | 计算方式 | 1 +car_jiayou_type | od_logistics | data | 加油类型 | 1 +car_jiayou_youliao | od_logistics | data | 燃油种类 | 1 +od_rail | base_otherdata | module | 铁运 | 1 +b_contype | od_rail | data | 箱属 | 1 +b_servicetype | od_rail | data | 服务内容 | 1 +b_ywtype_ht | od_rail | data | 业务类型 | 1 +od_system | base_otherdata | module | 系统 | 1 +b_bgtype | od_system | data | 报关方式 | 1 +b_billtype | od_system | data | 账单类型 | 1 +b_blstate | od_system | data | 提单方式 | 0 +b_bulkforkliftpersonname | od_system | data | 散货铲车人员 | 1 +b_bulkpersonname | od_system | data | 散货理货人员 | 1 +b_bulkstevedorepersonname | od_system | data | 散货装卸人员 | 1 +b_bulktype | od_system | data | 散货类型 | 1 +b_cargo_damage_status | od_system | data | 货损状态 | 1 +b_charging_method | od_system | data | 收费方式 | 1 +b_city | od_system | data | 城市 | 0 +b_con_type | od_system | data | 箱型管理 | 1 +b_cztype | od_system | data | 称重方式 | 1 +b_freightpayment | od_system | data | 运费条款 | 1 +b_from | od_system | data | 客户来源 | 1 +b_grade | od_system | data | 客户级别 | 1 +b_httype | od_system | data | 合同类型 | 0 +b_ivtype | od_system | data | 发票类型 | 1 +b_jsfs | od_system | data | 结算方式 | 0 +b_package | od_system | data | 包装单位 | 1 +b_progress | od_system | data | 进度情况 | 1 +b_sys_b_lessfull | od_system | data | 装箱 | 1 +b_sys_copies | od_system | data | 提单份数 | 0 +b_sys_edittype | od_system | data | 字段编辑选择 | 0 +b_sys_feesf | od_system | data | 费用收付 | 0 +b_sys_hdtype | od_system | data | 回单类型 | 1 +b_sys_level | od_system | data | 级别 | 0 +b_sys_operator | od_system | data | 条件设置操作符 | 0 +b_sys_pricelisttype | od_system | data | 合作伙伴类型 | 0 +b_sys_sex | od_system | data | 性别 | 0 +b_sys_state | od_system | data | 审核状态 | 0 +b_sys_yesno | od_system | data | 是否 | 0 +b_transway | od_system | data | 运输条款 | 1 +b_unloading_method | od_system | data | 卸货方式 | 1 +b_vessel | od_system | data | 船名船次 | 1 +b_ystype | od_system | data | 付款类型 | 1 +b_zxstate | od_system | data | 执行状态 | 0 +bc_priceList_type | od_system | data | 价目表类型 | 0 +(共 71 行) diff --git a/code/fms/fms-api/tools/migration/module-tree-out.txt b/code/fms/fms-api/tools/migration/module-tree-out.txt new file mode 100644 index 00000000..1f85e398 --- /dev/null +++ b/code/fms/fms-api/tools/migration/module-tree-out.txt @@ -0,0 +1,92 @@ +=== 1. s_module 全树(按 b_path 排序,含子树规模) === +b_id | b_depth | type | b_name | b_canuse | subtree | data_enabled +base | 0 | module | 基础资料 | 1 | 73 | 50 +base_otherdata | 1 | module | 其他数据 | 1 | 70 | 48 +od_air | 2 | module | 空运 | 1 | 2 | 2 +b_dcterm | 3 | data | 订舱条款 | 1 | 0 | 1 +b_ywtype_ky | 3 | data | 业务类型 | 1 | 0 | 1 +od_common | 2 | module | 常用 | 1 | 9 | 8 +b_dailyfeetype | 3 | data | 日常费用 | 1 | 0 | 1 +b_dailytype | 3 | data | 收支类型 | 0 | 0 | 0 +b_feetype | 3 | data | 费用类别 | 1 | 0 | 1 +b_goodssource | 3 | data | 货物来源 | 1 | 0 | 1 +b_money | 3 | data | 币种 | 1 | 0 | 1 +b_oceanline | 3 | data | 航线 | 1 | 0 | 1 +b_port | 3 | data | 港口 | 1 | 0 | 1 +b_ysfs | 3 | data | 运输方式 | 1 | 0 | 1 +b_ywtype | 3 | data | 业务类型 | 1 | 0 | 1 +od_depot | 2 | module | 仓库 | 1 | 3 | 3 +b_depot | 3 | data | 仓库 | 1 | 0 | 1 +b_depotintype | 3 | data | 入库类型 | 1 | 0 | 1 +b_depotouttype | 3 | data | 出库类型 | 1 | 0 | 1 +od_logistics | 2 | module | 物流 | 1 | 10 | 10 +b_cdtype | 3 | data | 派车类型 | 1 | 0 | 1 +b_shfs | 3 | data | 派送方式 | 1 | 0 | 1 +b_thfs | 3 | data | 提货方式 | 1 | 0 | 1 +b_wangdian | 3 | data | 网点 | 1 | 0 | 1 +b_ywfrom | 3 | data | 业务来源 | 1 | 0 | 1 +b_ywtype_tc | 3 | data | 业务类型 | 1 | 0 | 1 +car_daily_feetype | 3 | data | 费用报销-费用类型 | 1 | 0 | 1 +car_jiayou_jsfs | 3 | data | 计算方式 | 1 | 0 | 1 +car_jiayou_type | 3 | data | 加油类型 | 1 | 0 | 1 +car_jiayou_youliao | 3 | data | 燃油种类 | 1 | 0 | 1 +od_rail | 2 | module | 铁运 | 1 | 3 | 3 +b_contype | 3 | data | 箱属 | 1 | 0 | 1 +b_servicetype | 3 | data | 服务内容 | 1 | 0 | 1 +b_ywtype_ht | 3 | data | 业务类型 | 1 | 0 | 1 +od_system | 2 | module | 系统 | 1 | 37 | 22 +b_bgtype | 3 | data | 报关方式 | 1 | 0 | 1 +b_billtype | 3 | data | 账单类型 | 1 | 0 | 1 +b_blstate | 3 | data | 提单方式 | 0 | 0 | 0 +b_bulkforkliftpersonname | 3 | data | 散货铲车人员 | 1 | 0 | 1 +b_bulkpersonname | 3 | data | 散货理货人员 | 1 | 0 | 1 +b_bulkstevedorepersonname | 3 | data | 散货装卸人员 | 1 | 0 | 1 +b_bulktype | 3 | data | 散货类型 | 1 | 0 | 1 +b_cargo_damage_status | 3 | data | 货损状态 | 1 | 0 | 1 +b_charging_method | 3 | data | 收费方式 | 1 | 0 | 1 +b_city | 3 | data | 城市 | 0 | 0 | 0 +b_con_type | 3 | data | 箱型管理 | 1 | 0 | 1 +b_cztype | 3 | data | 称重方式 | 1 | 0 | 1 +b_freightpayment | 3 | data | 运费条款 | 1 | 0 | 1 +b_from | 3 | data | 客户来源 | 1 | 0 | 1 +b_grade | 3 | data | 客户级别 | 1 | 0 | 1 +b_httype | 3 | data | 合同类型 | 0 | 0 | 0 +b_ivtype | 3 | data | 发票类型 | 1 | 0 | 1 +b_jsfs | 3 | data | 结算方式 | 0 | 0 | 0 +b_package | 3 | data | 包装单位 | 1 | 0 | 1 +b_progress | 3 | data | 进度情况 | 1 | 0 | 1 +b_sys_b_lessfull | 3 | data | 装箱 | 1 | 0 | 1 +b_sys_copies | 3 | data | 提单份数 | 0 | 0 | 0 +b_sys_edittype | 3 | data | 字段编辑选择 | 0 | 0 | 0 +b_sys_feesf | 3 | data | 费用收付 | 0 | 0 | 0 +b_sys_hdtype | 3 | data | 回单类型 | 1 | 0 | 1 +b_sys_level | 3 | data | 级别 | 0 | 0 | 0 +b_sys_operator | 3 | data | 条件设置操作符 | 0 | 0 | 0 +b_sys_pricelisttype | 3 | data | 合作伙伴类型 | 0 | 0 | 0 +b_sys_sex | 3 | data | 性别 | 0 | 0 | 0 +b_sys_state | 3 | data | 审核状态 | 0 | 0 | 0 +b_sys_yesno | 3 | data | 是否 | 0 | 0 | 0 +b_transway | 3 | data | 运输条款 | 1 | 0 | 1 +b_unloading_method | 3 | data | 卸货方式 | 1 | 0 | 1 +b_vessel | 3 | data | 船名船次 | 1 | 0 | 1 +b_ystype | 3 | data | 付款类型 | 1 | 0 | 1 +b_zxstate | 3 | data | 执行状态 | 0 | 0 | 0 +bc_priceList_type | 3 | data | 价目表类型 | 0 | 0 | 0 +v_b_contact | 1 | data | 联系人 | 1 | 0 | 1 +v_b_othercompany | 1 | data | 合作伙伴 | 1 | 0 | 1 +module | 0 | module | 模块中心 | 1 | 1 | 1 +s_i18n_type | 1 | data | 多语言管理 | 1 | 0 | 1 +(共 76 行) + +=== 2. 顶层节点(b_parent_id is null 或不在表中) === +b_id | b_parent_id | b_module_type | b_name | b_canuse | b_path +base | null | module | 基础资料 | 1 | /base/ +module | null | module | 模块中心 | 1 | /module/ +(共 2 行) + +=== 3. base 直属子节点 === +b_id | b_module_type | b_name | b_canuse | b_xh +v_b_othercompany | data | 合作伙伴 | 1 | 10 +v_b_contact | data | 联系人 | 1 | 20 +base_otherdata | module | 其他数据 | 1 | 30 +(共 3 行) diff --git a/code/fms/fms-api/tools/migration/otherdata-columns.txt b/code/fms/fms-api/tools/migration/otherdata-columns.txt new file mode 100644 index 00000000..b9b83255 --- /dev/null +++ b/code/fms/fms-api/tools/migration/otherdata-columns.txt @@ -0,0 +1,261 @@ +=== 旧库 s_columnLib 配置(base_otherdata 各字典) === + 列表=col_Visible(1 进列表) 表单=col_edit(1 进表单) 宽=col_Width 位置=col_Position 表单位置=col_edit_position + +--- b_feetype(费用类别)--- + b_id 代码 列表=1 表单=0 宽=80 位置=1 表单位置=- + b_name 费用名称 列表=1 表单=1 宽=159 位置=2 表单位置=- + b_tax 税率 列表=1 表单=1 宽=60 位置=3 表单位置=- + b_default 默认 列表=0 表单=0 宽=31 位置=4 表单位置=- + b_money_id 默认币种 列表=1 表单=1 宽=71 位置=5 表单位置=- + b_bz 备注 列表=1 表单=1 宽=96 位置=6 表单位置=- + b_amount 默认金额 列表=0 表单=0 宽=60 位置=7 表单位置=- + +--- b_oceanline(航线)--- + b_id 航线代码 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 航线名称 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=86 位置=2 表单位置=- + +--- b_goodssource(货物来源)--- + b_id 编号 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 名称 列表=1 表单=1 宽=92 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=100 位置=2 表单位置=- + +--- b_dailyfeetype(日常费用)--- + b_id 编号 列表=1 表单=0 宽=80 位置=1 表单位置=- + b_name 费用类型 列表=1 表单=1 宽=159 位置=2 表单位置=- + b_bz 备注 列表=1 表单=1 宽=47 位置=3 表单位置=- + +--- b_dailytype(收支类型)--- + (旧库无配置) + +--- b_ywtype(业务类型)--- + (旧库无配置) + +--- b_ysfs(运输方式)--- + b_id 代码 列表=1 表单=0 宽=60 位置=0 表单位置=- + b_name 名称 列表=1 表单=1 宽=90 位置=0 表单位置=- + +--- b_port(港口)--- + b_id 港口代码 列表=1 表单=0 宽=80 位置=1 表单位置=- + b_name_c 中文名称 列表=1 表单=1 宽=120 位置=2 表单位置=- + b_name_e 英文名称 列表=1 表单=1 宽=80 位置=3 表单位置=- + b_country 所属国别 列表=1 表单=1 宽=99 位置=4 表单位置=- + b_edicode EDI代码 列表=1 表单=1 宽=70 位置=5 表单位置=- + b_oceanline 所属航线 列表=1 表单=1 宽=89 位置=6 表单位置=- + b_tz 还箱地 列表=1 表单=1 宽=49 位置=7 表单位置=- + b_bz 备注 列表=1 表单=1 宽=122 位置=8 表单位置=- + +--- b_money(币种)--- + b_id 编号 列表=1 表单=0 宽=80 位置=1 表单位置=- + b_name 币种 列表=1 表单=1 宽=82 位置=2 表单位置=- + b_hl 汇率 列表=1 表单=1 宽=60 位置=3 表单位置=- + b_symbol 符号 列表=1 表单=1 宽=59 位置=4 表单位置=- + b_bz 备注 列表=1 表单=1 宽=104 位置=5 表单位置=- + b_xh 统计次序 列表=1 表单=1 宽=56 位置=6 表单位置=- + b_canuse 统计显示 列表=1 表单=1 宽=53 位置=7 表单位置=- + b_edicode 列表=0 表单=0 宽=60 位置=8 表单位置=- + b_isconvert 折算币种 列表=1 表单=1 宽=60 位置=18 表单位置=- + +--- b_cargo_damage_status(货损状态)--- + (旧库无配置) + +--- b_bulkforkliftpersonname(散货铲车人员)--- + (旧库无配置) + +--- b_bulktype(散货类型)--- + (旧库无配置) + +--- b_bulkpersonname(散货理货人员)--- + (旧库无配置) + +--- b_bulkstevedorepersonname(散货装卸人员)--- + (旧库无配置) + +--- b_charging_method(收费方式)--- + (旧库无配置) + +--- b_unloading_method(卸货方式)--- + (旧库无配置) + +--- b_sys_b_lessfull(装箱)--- + (旧库无配置) + +--- b_sys_edittype(字段编辑选择)--- + (旧库无配置) + +--- b_vessel(船名船次)--- + b_id 编号 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_vessel_name 船名 列表=1 表单=1 宽=144 位置=1 表单位置=- + b_voy 船次 列表=1 表单=1 宽=60 位置=2 表单位置=- + b_bz 备注 列表=1 表单=1 宽=47 位置=3 表单位置=- + b_edicode 列表=0 表单=0 宽=60 位置=10 表单位置=- + +--- b_freightpayment(运费条款)--- + b_id 代码 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 描述 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=47 位置=2 表单位置=- + +--- b_con_type(箱型管理)--- + b_id 编号 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 箱型 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_type 大/小箱 列表=1 表单=1 宽=70 位置=2 表单位置=- + b_default 默认 列表=1 表单=1 宽=70 位置=10 表单位置=- + b_bz 备注 列表=1 表单=1 宽=60 位置=20 表单位置=- + b_edicode 列表=0 表单=0 宽=60 位置=30 表单位置=- + +--- b_jsfs(结算方式)--- + (旧库无配置) + +--- b_city(城市)--- + b_id 编号 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name_c 中文名 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_name_e 英文名 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=47 位置=2 表单位置=- + +--- b_ivtype(发票类型)--- + (旧库无配置) + +--- b_sys_sex(性别)--- + (旧库无配置) + +--- b_sys_copies(提单份数)--- + (旧库无配置) + +--- b_cztype(称重方式)--- + (旧库无配置) + +--- b_sys_level(级别)--- + (旧库无配置) + +--- b_sys_operator(条件设置操作符)--- + (旧库无配置) + +--- b_blstate(提单方式)--- + (旧库无配置) + +--- b_sys_state(审核状态)--- + (旧库无配置) + +--- b_sys_feesf(费用收付)--- + (旧库无配置) + +--- bc_priceList_type(价目表类型)--- + (旧库无配置) + +--- b_sys_yesno(是否)--- + (旧库无配置) + +--- b_sys_pricelisttype(合作伙伴类型)--- + b_id 代码 列表=1 表单= 宽=60 位置=10 表单位置=- + b_name 名称 列表=1 表单= 宽=110 位置=20 表单位置=- + b_dw_id 结算id 列表=1 表单= 宽=180 位置=30 表单位置=- + b_dw_name 结算单位 列表=1 表单= 宽=180 位置=40 表单位置=- + +--- b_ystype(付款类型)--- + (旧库无配置) + +--- b_billtype(账单类型)--- + (旧库无配置) + +--- b_bgtype(报关方式)--- + (旧库无配置) + +--- b_httype(合同类型)--- + (旧库无配置) + +--- b_transway(运输条款)--- + b_id 代码 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 描述 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=105 位置=2 表单位置=- + +--- b_from(客户来源)--- + (旧库无配置) + +--- b_grade(客户级别)--- + (旧库无配置) + +--- b_sys_hdtype(回单类型)--- + (旧库无配置) + +--- b_package(包装单位)--- + b_id 代码 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 包装单位 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=47 位置=2 表单位置=- + b_edicode EDI代码 列表=1 表单=1 宽=70 位置=12 表单位置=- + +--- b_progress(进度情况)--- + b_id 编号 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 进度 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=47 位置=2 表单位置=- + +--- b_zxstate(执行状态)--- + b_id 编号 列表=1 表单=0 宽=80 位置=0 表单位置=- + b_name 执行状态 列表=1 表单=1 宽=159 位置=1 表单位置=- + b_bz 备注 列表=1 表单=1 宽=47 位置=2 表单位置=- + +--- b_depot(仓库)--- + b_id 系统编号 列表=1 表单=0 宽=80 位置=10 表单位置=- + b_name 仓库 列表=1 表单=1 宽=159 位置=20 表单位置=- + b_linkman 仓库联系人 列表=1 表单=1 宽=90 位置=30 表单位置=- + b_linkmanphone 联系方式 列表=1 表单=1 宽=159 位置=40 表单位置=- + b_bz 备注 列表=1 表单=1 宽=200 位置=60 表单位置=- + +--- b_depotouttype(出库类型)--- + b_id 代码 列表=1 表单=0 宽=143 位置=0 表单位置=- + b_name 名称 列表=1 表单=1 宽=159 位置=10 表单位置=- + b_bz 备注 列表=1 表单=1 宽=141 位置=20 表单位置=- + +--- b_depotintype(入库类型)--- + b_id 代码 列表=1 表单=0 宽=112 位置=0 表单位置=- + b_name 名称 列表=1 表单=1 宽=159 位置=10 表单位置=- + b_bz 备注 列表=1 表单=1 宽=134 位置=20 表单位置=- + +--- car_daily_feetype(费用报销-费用类型)--- + (旧库无配置) + +--- car_jiayou_jsfs(计算方式)--- + (旧库无配置) + +--- car_jiayou_type(加油类型)--- + (旧库无配置) + +--- car_jiayou_youliao(燃油种类)--- + (旧库无配置) + +--- b_cdtype(派车类型)--- + (旧库无配置) + +--- b_shfs(派送方式)--- + (旧库无配置) + +--- b_thfs(提货方式)--- + (旧库无配置) + +--- b_wangdian(网点)--- + b_id 代码 列表=1 表单=0 宽=60 位置=1 表单位置=- + b_name 网点名称 列表=1 表单=1 宽=126 位置=2 表单位置=- + b_disport 属地 列表=1 表单=1 宽=67 位置=3 表单位置=- + b_bz 备注 列表=1 表单=1 宽=126 位置=4 表单位置=- + +--- b_ywfrom(业务来源)--- + (旧库无配置) + +--- b_ywtype_tc(业务类型)--- + (旧库无配置) + +--- b_servicetype(服务内容)--- + (旧库无配置) + +--- b_contype(箱属)--- + (旧库无配置) + +--- b_ywtype_ht(业务类型)--- + (旧库无配置) + +--- b_dcterm(订舱条款)--- + (旧库无配置) + +--- b_ywtype_ky(业务类型)--- + (旧库无配置) + +合计: 64 个模块、85 条字段配置(进列表 80、进表单 57) diff --git a/code/fms/fms-api/tools/migration/otherdata-id-map.tsv b/code/fms/fms-api/tools/migration/otherdata-id-map.tsv new file mode 100644 index 00000000..89de4c81 --- /dev/null +++ b/code/fms/fms-api/tools/migration/otherdata-id-map.tsv @@ -0,0 +1,556 @@ +表名 旧编号 新ID +b_feetype BC 848902778785728 +b_feetype BDFY 848902778798016 +b_feetype BG 848902778798017 +b_feetype BGb 848902778798018 +b_feetype BGF 848902778798019 +b_feetype BGTKF 848902778798020 +b_feetype BQF 848902778798021 +b_feetype BX 848902778798022 +b_feetype BXF 848902778798023 +b_feetype CCF 848902778798024 +b_feetype CD 848902778798025 +b_feetype CDF 848902778798026 +b_feetype CDLR 848902778798027 +b_feetype CDZ 848902778798028 +b_feetype CKF 848902778798029 +b_feetype CLF 848902778802112 +b_feetype CLWH 848902778802113 +b_feetype COA 848902778802114 +b_feetype CYF 848902778802115 +b_feetype CZ 848902778802116 +b_feetype CZF 848902778802117 +b_feetype CZFY 848902778802118 +b_feetype CZJGF 848902778802119 +b_feetype CZZX 848902778802120 +b_feetype DB 848902778802121 +b_feetype DBF 848902778802122 +b_feetype DC 848902778802123 +b_feetype DC1 848902778802124 +b_feetype DCF 848902778802125 +b_feetype DDF 848902778802126 +b_feetype DF 848902778802127 +b_feetype DHF 848902778802128 +b_feetype DJF 848902778802129 +b_feetype DL 848902778802130 +b_feetype DSDF 848902778802131 +b_feetype DTFT 848902778802132 +b_feetype DXF 848902778802133 +b_feetype DZF 848902778802134 +b_feetype DZW 848902778802135 +b_feetype EIR 848902778802136 +b_feetype FAF 848902778802137 +b_feetype FKKA费 848902778802138 +b_feetype FKTLF 848902778802139 +b_feetype FZBG 848902778802140 +b_feetype FZSD 848902778802141 +b_feetype FZTC 848902778802142 +b_feetype GBF 848902778802143 +b_feetype GDF 848902778802144 +b_feetype GJZCZ 848902778802145 +b_feetype GND 848902778802146 +b_feetype GPS 848902778802147 +b_feetype GSHDJF 848902778802148 +b_feetype GSXX 848902778802149 +b_feetype GWCYF 848902778802150 +b_feetype GWYF 848902778802151 +b_feetype GWZLF 848902778802152 +b_feetype GXTK 848902778802153 +b_feetype GZ 848902778802154 +b_feetype GZF 848902778802155 +b_feetype HDSY 848902778802156 +b_feetype HMP 848902778802157 +b_feetype HSKDZF 848902778802158 +b_feetype HSKMCY 848902778806208 +b_feetype HSXZ 848902778806209 +b_feetype HYF 848902778806210 +b_feetype JDF 848902778806211 +b_feetype JGF 848902778806212 +b_feetype JK 848902778806213 +b_feetype JSHZF 848902778806214 +b_feetype JTF 848902778806215 +b_feetype JWFK 848902778806216 +b_feetype JWYF 848902778806217 +b_feetype JWYSF 848902778806218 +b_feetype JXJ 848902778806219 +b_feetype JZXXK 848902778806220 +b_feetype KABGF 848902778806221 +b_feetype KACYF 848902778806222 +b_feetype KADLF 848902778806223 +b_feetype KAKXF 848902778806224 +b_feetype KAZLF 848902778806225 +b_feetype KDF 848902778806226 +b_feetype KSO 848902778806227 +b_feetype KXDDF 848902778806228 +b_feetype KZLY 848902778806229 +b_feetype LOCAL 848902778806230 +b_feetype LX 848902778806231 +b_feetype LYF 848902778806232 +b_feetype MXF 848902778806233 +b_feetype MXK 848902778806234 +b_feetype PZF 848902778806235 +b_feetype QB 848902778806236 +b_feetype QCDL 848902778806237 +b_feetype QGDLF 848902778806238 +b_feetype QGF 848902778806239 +b_feetype QT 848902778806240 +b_feetype QTF 848902778806241 +b_feetype QYFKF 848902778806242 +b_feetype SB 848902778806243 +b_feetype SCF 848902778806244 +b_feetype SEALFEE 848902778806245 +b_feetype SJF 848902778806246 +b_feetype SJHK 848902778806247 +b_feetype SJSJ 848902778806248 +b_feetype SK 848902778806249 +b_feetype STF 848902778806250 +b_feetype SX 848902778806251 +b_feetype SXF 848902778806252 +b_feetype TBF 848902778806253 +b_feetype TCF 848902778806254 +b_feetype THC 848902778806255 +b_feetype TJF 848902778806256 +b_feetype TK 848902778806257 +b_feetype TKF 848902778806258 +b_feetype TM 848902778806259 +b_feetype TSK 848902778806260 +b_feetype TX 848902778806261 +b_feetype TX1 848902778806262 +b_feetype TXF 848902778806263 +b_feetype WXXX 848902778806264 +b_feetype WYF 848902778806265 +b_feetype XHF 848902778806266 +b_feetype XTF 848902778806267 +b_feetype XTFY 848902778806268 +b_feetype XXF 848902778806269 +b_feetype YF 848902778806270 +b_feetype YG 848902778806271 +b_feetype YGBJSR 848902778810304 +b_feetype YSF 848902778810305 +b_feetype YXJ 848902778810306 +b_feetype YYF 848902778810307 +b_feetype ZC 848902778810308 +b_feetype ZDXFH 848902778810309 +b_feetype ZF 848902778810310 +b_feetype ZJF 848902778810311 +b_feetype ZLF 848902778810312 +b_feetype ZSF 848902778810313 +b_feetype ZXF 848902778810314 +b_feetype ZXF2 848902778810315 +b_feetype ZXF3 848902778810316 +b_oceanline 001 848902780678080 +b_oceanline 002 848902780678081 +b_oceanline 003 848902780678082 +b_oceanline 004 848902780678083 +b_oceanline 005 848902780678084 +b_oceanline 006 848902780678085 +b_oceanline 007 848902780678086 +b_oceanline 008 848902780678087 +b_oceanline 009 848902780678088 +b_goodssource 001 848902781091776 +b_goodssource 002 848902781091777 +b_dailyfeetype 001 848902781366208 +b_dailyfeetype 002 848902781366209 +b_dailyfeetype 003 848902781366210 +b_dailyfeetype 004 848902781366211 +b_dailyfeetype 005 848902781366212 +b_dailyfeetype 006 848902781366213 +b_dailyfeetype 007 848902781366214 +b_dailyfeetype 008 848902781366215 +b_dailyfeetype 010 848902781366216 +b_dailyfeetype 011 848902781366217 +b_dailyfeetype 012 848902781366218 +b_dailyfeetype 013 848902781370304 +b_dailytype 001 848902781702080 +b_dailytype 002 848902781702081 +b_ywtype 001 848902781976512 +b_ywtype 002 848902781976513 +b_ywtype 003 848902781976514 +b_ywtype 004 848902781976515 +b_ysfs 001 848902782304192 +b_ysfs 002 848902782304193 +b_port 000000 848902782595008 +b_port 000001 848902782599104 +b_port 0998 848902782599105 +b_port 181808 848902782599106 +b_port 183502 848902782599107 +b_port 302024 848902782599108 +b_port 524404 848902782599109 +b_port 625501 848902782599110 +b_port 630209 848902782599111 +b_port 661705 848902782599112 +b_port 663503 848902782599113 +b_port 665602 848902782599114 +b_port 666003 848902782599115 +b_port 667909 848902782599116 +b_port 673905 848902782599117 +b_port 684001 848902782599118 +b_port 690002 848902782599119 +b_port 690200 848902782599120 +b_port 696206 848902782599121 +b_port 698606 848902782599122 +b_port 700007 848902782599123 +b_port 700204 848902782599124 +b_port 701809 848902782599125 +b_port 706304 848902782599126 +b_port 709508 848902782599127 +b_port 713007 848902782599128 +b_port 716908 848902782599129 +b_port 720000 848902782599130 +b_port 721107 848902782599131 +b_port 722400 848902782599132 +b_port 722701 848902782599133 +b_port 723507 848902782599134 +b_port 725004 848902782599135 +b_port 726903 848902782599136 +b_port 727809 848902782599137 +b_port 727902 848902782599138 +b_port 730106 848902782599139 +b_port 731407 848902782599140 +b_port 733104 848902782599141 +b_port 737209 848902782599142 +b_port 738305 848902782599143 +b_port 740004 848902782599144 +b_port 742508 848902782599145 +b_port 745309 848902782599146 +b_port 747802 848902782599147 +b_port 752800 848902782599148 +b_port 753004 848902782599149 +b_port 754505 848902782599150 +b_port 890004 848902782599151 +b_port 890005 848902782599152 +b_port 890006 848902782599153 +b_port 890007 848902782599154 +b_port 890008 848902782599155 +b_port 890009 848902782599156 +b_port 890010 848902782599157 +b_port 890011 848902782599158 +b_port ABLK 848902782599159 +b_port AKTB 848902782599160 +b_port AKTG 848902782599161 +b_port ALMJ 848902782599162 +b_port ALMT 848902782599163 +b_port AS 848902782599164 +b_port ASHBD 848902782599165 +b_port ASHDOD 848902782599166 +b_port ASTN 848902782599167 +b_port ATL 848902782603200 +b_port BB 848902782603201 +b_port BD 848902782603202 +b_port BELAWAN 848902782603203 +b_port BEX 848902782603204 +b_port BFLDE 848902782603205 +b_port BK 848902782603206 +b_port BSKK 848902782603207 +b_port CHA 848902782603208 +b_port COLOMBO 848902782603209 +b_port CXZ 848902782603210 +b_port DB 848902782603211 +b_port DL 848902782603212 +b_port DLK 848902782603213 +b_port DSGZ 848902782603214 +b_port DSTK 848902782603215 +b_port FLP 848902782603216 +b_port GLJY 848902782603217 +b_port GY 848902782603218 +b_port GYZ 848902782603219 +b_port GZTUB 848902782603220 +b_port HB 848902782603221 +b_port HF 848902782603222 +b_port HH 848902782603223 +b_port JBL 848902782603224 +b_port JGLH 848902782603225 +b_port JN 848902782603226 +b_port JZK 848902782603227 +b_port KEX 848902782603228 +b_port KKST 848902782603229 +b_port KLGD 848902782603230 +b_port KLKE 848902782603231 +b_port KS 848902782603232 +b_port KSTN 848902782603233 +b_port KT 848902782603234 +b_port KWS 848902782603235 +b_port KZLAED 848902782603236 +b_port LAEM CHABNAG 848902782603237 +b_port LK 848902782603238 +b_port LR 848902782603239 +b_port MELBOURNE 848902782603240 +b_port MGSLK 848902782603241 +b_port MJW 848902782603242 +b_port ML 848902782603243 +b_port MZL 848902782603244 +b_port NC 848902782603245 +b_port NHAVA SHEVA 848902782603246 +b_port NKZ 848902782603247 +b_port NWY 848902782603248 +b_port NXQ 848902782603249 +b_port PHN 848902782603250 +b_port QINGDAO 848902782603251 +b_port QMKT 848902782603252 +b_port QZ 848902782603253 +b_port RLYW 848902782603254 +b_port RTS 848902782603255 +b_port SH 848902782603256 +b_port SHBJ 848902782603257 +b_port SHEKOU 848902782603258 +b_port SLAXY 848902782603259 +b_port SM 848902782603260 +b_port SQ 848902782603261 +b_port SURABAYA 848902782603262 +b_port SZ 848902782603263 +b_port TC 848902782607296 +b_port TLS 848902782607297 +b_port TS 848902782607298 +b_port TSG 848902782607299 +b_port WLMQ 848902782607300 +b_port WMJ 848902782607301 +b_port WX 848902782607302 +b_port WXDL 848902782607303 +b_port WXDLQ 848902782607304 +b_port WXLG 848902782607305 +b_port XGZ 848902782607306 +b_port YANTIAN 848902782607307 +b_port YEKST 848902782607308 +b_port YLDHL 848902782607309 +b_port YSQ 848902782607310 +b_port YX 848902782607311 +b_port ZDWLY 848902782607312 +b_port ZLFS 848902782607313 +b_port 阿克苏 848902782607314 +b_port 阿拉山口 848902782607315 +b_port 阿腾科里 848902782607316 +b_port 白银站 848902782607317 +b_port 保定 848902782607318 +b_port 长沙北 848902782607319 +b_port 常州 848902782607320 +b_port 东孚 848902782607321 +b_port 东莞 848902782607322 +b_port 二连浩特 848902782607323 +b_port 赣州 848902782607324 +b_port 广州江高镇 848902782607325 +b_port 河北石家庄 848902782607326 +b_port 河南 848902782607327 +b_port 霍尔果斯 848902782607328 +b_port 济南朱保站 848902782607329 +b_port 金华 848902782607330 +b_port 柯桥 848902782607331 +b_port 苦盏 848902782607332 +b_port 连云港 848902782607333 +b_port 莫斯科 848902782607334 +b_port 南京北站 848902782607335 +b_port 宁波北站 848902782607336 +b_port 七苏木站 848902782607337 +b_port 奇姆肯特 848902782607338 +b_port 青岛港 848902782607339 +b_port 衢州 848902782607340 +b_port 沈阳东 848902782607341 +b_port 石龙 848902782607342 +b_port 斯皮塔密 848902782607343 +b_port 苏州西 848902782607344 +b_port 塔拉兹 848902782607345 +b_port 天津 848902782607346 +b_port 铜山站 848902782607347 +b_port 温州西站 848902782607348 +b_port 乌兰巴托 848902782607349 +b_port 乌西站 848902782607350 +b_port 武威南站 848902782607351 +b_port 西安新筑 848902782607352 +b_port 新乡 848902782607353 +b_port 徐州 848902782607354 +b_port 扬州 848902782607355 +b_port 义乌西站 848902782607356 +b_port 银川南站 848902782607357 +b_port 中川北 848902782607358 +b_port 淄博 848902782607359 +b_money 001 848902783115200 +b_money 002 848902783115201 +b_money 003 848902783115202 +b_money 004 848902783115203 +b_money 005 848902783115204 +b_cargo_damage_status 001 848902783434688 +b_cargo_damage_status 002 848902783434689 +b_bulkforkliftpersonname 001 848902783700928 +b_bulktype 001 848902783918016 +b_bulkpersonname 001 848902784143296 +b_bulkpersonname 002 848902784143297 +b_bulkstevedorepersonname 001 848902784470976 +b_charging_method 001 848902784692160 +b_charging_method 002 848902784692161 +b_unloading_method 001 848902784954304 +b_unloading_method 002 848902784954305 +b_sys_b_lessfull 001 848902785216448 +b_sys_b_lessfull 002 848902785216449 +b_sys_edittype 001 848902785474496 +b_sys_edittype 002 848902785474497 +b_sys_edittype 003 848902785474498 +b_sys_edittype 004 848902785474499 +b_sys_edittype 005 848902785474500 +b_sys_edittype 006 848902785474501 +b_sys_edittype 007 848902785474502 +b_sys_edittype 009 848902785474503 +b_sys_edittype 010 848902785474504 +b_sys_edittype 011 848902785474505 +b_vessel 001 848902785814464 +b_vessel 002 848902785814465 +b_vessel 003 848902785814466 +b_vessel 004 848902785814467 +b_freightpayment 001 848902786113472 +b_freightpayment 002 848902786113473 +b_freightpayment 003 848902786113474 +b_con_type 001 848902786453440 +b_con_type 002 848902786453441 +b_con_type 003 848902786453442 +b_con_type 004 848902786453443 +b_con_type 006 848902786453444 +b_con_type 008 848902786453445 +b_con_type QY 848902786453446 +b_con_type SH 848902786453447 +b_jsfs 001 848902786772928 +b_jsfs 002 848902786772929 +b_city CNNGB 848902787071936 +b_city CS001 848902787071937 +b_city CS002 848902787071938 +b_city CS003 848902787071939 +b_city CS004 848902787071940 +b_city CS005 848902787071941 +b_city CS006 848902787071942 +b_city CS007 848902787071943 +b_city CS008 848902787071944 +b_city CS010 848902787071945 +b_city CS011 848902787071946 +b_city CS012 848902787071947 +b_city CS013 848902787071948 +b_city CS014 848902787071949 +b_city CS015 848902787071950 +b_city CS016 848902787071951 +b_city CS017 848902787071952 +b_ivtype 001 848902787403712 +b_ivtype 002 848902787403713 +b_sys_sex 001 848902787665856 +b_sys_sex 002 848902787665857 +b_sys_copies 001 848902787985344 +b_sys_copies 002 848902787985345 +b_sys_copies 003 848902787985346 +b_sys_copies 004 848902787985347 +b_sys_copies 005 848902787985348 +b_sys_copies 006 848902787985349 +b_sys_copies 007 848902787985350 +b_sys_copies 008 848902787985351 +b_sys_copies 009 848902787985352 +b_sys_copies 010 848902787985353 +b_sys_copies 011 848902787985354 +b_cztype 001 848902788288448 +b_cztype 002 848902788288449 +b_sys_level 001 848902788554688 +b_sys_level 002 848902788554689 +b_sys_level 003 848902788554690 +b_sys_level 004 848902788554691 +b_sys_level 005 848902788554692 +b_sys_level 006 848902788554693 +b_sys_level 007 848902788554694 +b_sys_level 008 848902788554695 +b_sys_operator 001 848902788861888 +b_sys_operator 002 848902788861889 +b_sys_operator 003 848902788861890 +b_sys_operator 004 848902788861891 +b_blstate 001 848902789169088 +b_blstate 002 848902789169089 +b_sys_state 001 848902789439424 +b_sys_state 002 848902789439425 +b_sys_state 003 848902789439426 +b_sys_state 004 848902789439427 +b_sys_state 005 848902789439428 +b_sys_feesf 001 848902789754816 +b_sys_feesf 002 848902789754817 +bc_priceList_type 001 848902790021056 +bc_priceList_type 002 848902790021057 +b_sys_yesno 001 848902790287296 +b_sys_yesno 002 848902790287297 +b_sys_pricelisttype 001 848902790553536 +b_sys_pricelisttype 002 848902790553537 +b_sys_pricelisttype 003 848902790553538 +b_sys_pricelisttype 004 848902790553539 +b_sys_pricelisttype 005 848902790553540 +b_ystype 001 848902790873024 +b_ystype 002 848902790873025 +b_ystype 003 848902790873026 +b_billtype 001 848902791258048 +b_billtype 002 848902791258049 +b_bgtype 001 848902791540672 +b_bgtype 002 848902791540673 +b_httype 001 848902791827392 +b_httype 002 848902791827393 +b_transway 001 848902792101824 +b_transway 002 848902792101825 +b_transway 003 848902792101826 +b_transway 004 848902792101827 +b_transway 005 848902792101828 +b_transway 006 848902792101829 +b_from 001 848902792478656 +b_from 002 848902792478657 +b_from 003 848902792478658 +b_from 004 848902792478659 +b_from 005 848902792478660 +b_grade 001 848902792839104 +b_grade 002 848902792839105 +b_grade 003 848902792839106 +b_grade 004 848902792839107 +b_sys_hdtype 001 848902793166784 +b_sys_hdtype 002 848902793166785 +b_package BAGS 848902793437120 +b_package BALES 848902793437121 +b_package CASES 848902793437122 +b_package CTNS 848902793437123 +b_package PCS 848902793437124 +b_package PKGS 848902793437125 +b_package PLATES 848902793437126 +b_package PLTS 848902793437127 +b_package PLYWOOD CASE 848902793437128 +b_package ROLLS 848902793441216 +b_package SETS 848902793441217 +b_progress 001 848902793920448 +b_progress 002 848902793920449 +b_progress 003 848902793920450 +b_zxstate 001 848902794219456 +b_zxstate 002 848902794219457 +b_zxstate 003 848902794219458 +b_zxstate 004 848902794219459 +b_zxstate 005 848902794219460 +b_depot 001 848902794526656 +b_depot 002 848902794526657 +b_depotouttype 001 848902794837952 +b_depotintype 001 848902795087808 +car_daily_feetype 001 848902795317184 +car_jiayou_jsfs 001 848902795542464 +car_jiayou_jsfs 002 848902795542465 +car_jiayou_jsfs 003 848902795542466 +car_jiayou_type 001 848902795853760 +car_jiayou_type 002 848902795853761 +car_jiayou_youliao 001 848902796132288 +car_jiayou_youliao 002 848902796132289 +b_cdtype 001 848902796402624 +b_cdtype 002 848902796402625 +b_shfs 001 848902796672960 +b_shfs 002 848902796672961 +b_thfs 001 848902796935104 +b_thfs 002 848902796935105 +b_wangdian 001 848902797197248 +b_wangdian 002 848902797201344 +b_wangdian 003 848902797201345 +b_wangdian 004 848902797201346 +b_ywfrom 001 848902797496256 +b_ywfrom 002 848902797496257 +b_ywtype_tc 001 848902797774784 +b_ywtype_tc 002 848902797774785 +b_ywtype_tc 003 848902797774786 +b_servicetype 1 848902798086080 +b_servicetype 2 848902798086081 +b_servicetype 3 848902798086082 +b_contype 1 848902798397376 +b_contype 2 848902798397377 +b_contype 3 848902798397378 +b_contype 4 848902798397379 +b_contype 5 848902798397380 +b_contype 6 848902798397381 +b_dcterm 001 848902798917568 +b_ywtype_ky 001 848902799138752 diff --git a/code/fms/fms-api/tools/migration/otherdata-modules.txt b/code/fms/fms-api/tools/migration/otherdata-modules.txt new file mode 100644 index 00000000..1e75674c --- /dev/null +++ b/code/fms/fms-api/tools/migration/otherdata-modules.txt @@ -0,0 +1,81 @@ +=== 旧库 b_other_bmfl 模块清单 === + 表名 名称 状态 旧库行数 新库 + +[1] 1.常用 —— 9 张(启用 8、有数据 9、新库已建 9) + b_feetype 费用类别 启用 139 已建 + b_oceanline 航线 启用 9 已建 + b_goodssource 货物来源 启用 2 已建 + b_dailyfeetype 日常费用 启用 12 已建 + b_dailytype 收支类型 停用 2 已建 + b_ywtype 业务类型 启用 4 已建 + b_ysfs 运输方式 启用 2 已建 + b_port 港口 启用 193 已建 + b_money 币种 启用 5 已建 + +[2] 2.系统 —— 38 张(启用 22、有数据 38、新库已建 38) + b_cargo_damage_status 货损状态 启用 2 已建 + b_bulkforkliftpersonname 散货铲车人员 启用 1 已建 + b_bulktype 散货类型 启用 1 已建 + b_bulkpersonname 散货理货人员 启用 2 已建 + b_bulkstevedorepersonname 散货装卸人员 启用 1 已建 + b_charging_method 收费方式 启用 2 已建 + b_unloading_method 卸货方式 启用 2 已建 + b_sys_b_lessfull 装箱 启用 2 已建 + b_sys_edittype 字段编辑选择 停用 10 已建 + b_vessel 船名船次 启用 4 已建 + b_freightpayment 运费条款 启用 3 已建 + b_con_type 箱型管理 启用 8 已建 + b_jsfs 结算方式 停用 2 已建 + b_city 城市 停用 17 已建 + b_ivtype 发票类型 启用 2 已建 + b_othercompany_partner_type合作伙伴类型 停用 17 已建 + b_sys_sex 性别 停用 2 已建 + b_sys_copies 提单份数 停用 11 已建 + b_cztype 称重方式 启用 2 已建 + b_sys_level 级别 停用 8 已建 + b_sys_operator 条件设置操作符 停用 4 已建 + b_blstate 提单方式 停用 2 已建 + b_sys_state 审核状态 停用 5 已建 + b_sys_feesf 费用收付 停用 2 已建 + bc_priceList_type 价目表类型 停用 2 已建 + b_sys_yesno 是否 停用 2 已建 + b_sys_pricelisttype 合作伙伴类型 停用 5 已建 + b_ystype 付款类型 启用 3 已建 + b_billtype 账单类型 启用 2 已建 + b_bgtype 报关方式 启用 2 已建 + b_httype 合同类型 停用 2 已建 + b_transway 运输条款 启用 6 已建 + b_from 客户来源 启用 5 已建 + b_grade 客户级别 启用 4 已建 + b_sys_hdtype 回单类型 启用 2 已建 + b_package 包装单位 启用 11 已建 + b_progress 进度情况 启用 3 已建 + b_zxstate 执行状态 停用 5 已建 + +[3] 3.仓库 —— 3 张(启用 3、有数据 3、新库已建 3) + b_depot 仓库 启用 2 已建 + b_depotouttype 出库类型 启用 1 已建 + b_depotintype 入库类型 启用 1 已建 + +[4] 5.物流 —— 10 张(启用 10、有数据 10、新库已建 10) + car_daily_feetype 费用报销-费用类型 启用 1 已建 + car_jiayou_jsfs 计算方式 启用 3 已建 + car_jiayou_type 加油类型 启用 2 已建 + b_cdtype 派车类型 启用 2 已建 + b_shfs 派送方式 启用 2 已建 + car_jiayou_youliao 燃油种类 启用 2 已建 + b_thfs 提货方式 启用 2 已建 + b_wangdian 网点 启用 4 已建 + b_ywfrom 业务来源 启用 2 已建 + b_ywtype_tc 业务类型 启用 3 已建 + +[5] 6.铁运 —— 3 张(启用 3、有数据 2、新库已建 3) + b_servicetype 服务内容 启用 3 已建 + b_contype 箱属 启用 6 已建 + b_ywtype_ht 业务类型 启用 0 已建 + +[6] 7.空运 —— 2 张(启用 2、有数据 2、新库已建 2) + b_dcterm 订舱条款 启用 1 已建 + b_ywtype_ky 业务类型 启用 1 已建 + +合计 65 张(启用 48、有数据 64、新库已建 65) diff --git a/code/fms/fms-api/tools/migration/otherdata-probe-out.txt b/code/fms/fms-api/tools/migration/otherdata-probe-out.txt new file mode 100644 index 00000000..cf236c0b --- /dev/null +++ b/code/fms/fms-api/tools/migration/otherdata-probe-out.txt @@ -0,0 +1,837 @@ +=== 新库 FMS:表结构 === + +--- b_cargo_damage_status --- + (表不存在) + +--- b_bulkforkliftpersonname --- + (表不存在) + +--- b_bulktype --- + (表不存在) + +--- b_bulkpersonname --- + (表不存在) + +--- b_bulkstevedorepersonname --- + (表不存在) + +--- b_charging_method --- + (表不存在) + +--- b_unloading_method --- + (表不存在) + +--- b_sys_b_lessfull --- + (表不存在) + +--- b_sys_edittype --- + (表不存在) + +--- b_vessel --- + (表不存在) + +--- b_freightpayment --- + (表不存在) + +--- b_con_type --- + (表不存在) + +--- b_jsfs --- + (表不存在) + +--- b_city --- + (表不存在) + +--- b_ivtype --- + (表不存在) + +--- b_sys_sex --- + (表不存在) + +--- b_sys_copies --- + (表不存在) + +--- b_cztype --- + (表不存在) + +--- b_sys_level --- + (表不存在) + +--- b_sys_operator --- + (表不存在) + +--- b_blstate --- + (表不存在) + +--- b_sys_state --- + (表不存在) + +--- b_sys_feesf --- + (表不存在) + +--- bc_priceList_type --- + (表不存在) + +--- b_sys_yesno --- + (表不存在) + +--- b_sys_pricelisttype --- + (表不存在) + +--- b_ystype --- + (表不存在) + +--- b_billtype --- + (表不存在) + +--- b_bgtype --- + (表不存在) + +--- b_httype --- + (表不存在) + +--- b_transway --- + (表不存在) + +--- b_sys_hdtype --- + (表不存在) + +--- b_package --- + (表不存在) + +--- b_progress --- + (表不存在) + +--- b_zxstate --- + (表不存在) + +--- b_depot --- + (表不存在) + +--- b_depotouttype --- + (表不存在) + +--- b_depotintype --- + (表不存在) + +--- car_daily_feetype --- + (表不存在) + +--- car_jiayou_jsfs --- + (表不存在) + +--- car_jiayou_type --- + (表不存在) + +--- b_cdtype --- + (表不存在) + +--- b_shfs --- + (表不存在) + +--- car_jiayou_youliao --- + (表不存在) + +--- b_thfs --- + (表不存在) + +--- b_wangdian --- + (表不存在) + +--- b_ywfrom --- + (表不存在) + +--- b_ywtype_tc --- + (表不存在) + +--- b_servicetype --- + (表不存在) + +--- b_contype --- + (表不存在) + +--- b_ywtype_ht --- + (表不存在) + +--- b_dcterm --- + (表不存在) + +--- b_ywtype_ky --- + (表不存在) + +=== 旧库 G3HY2025:表结构 === + +--- b_cargo_damage_status --- + b_id varchar 50 not null + b_name varchar 50 null + +--- b_bulkforkliftpersonname --- + b_id varchar 50 not null + b_name varchar 50 null + +--- b_bulktype --- + b_id varchar 50 not null + b_name varchar 50 null + +--- b_bulkpersonname --- + b_id varchar 50 not null + b_name varchar 50 null + +--- b_bulkstevedorepersonname --- + b_id varchar 50 not null + b_name varchar 50 null + +--- b_charging_method --- + b_id varchar 50 not null + b_name varchar 50 null + +--- b_unloading_method --- + b_id varchar 50 not null + b_name varchar 50 null + +--- b_sys_b_lessfull --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_sys_edittype --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + +--- b_vessel --- + b_id varchar 50 not null + b_vessel_name varchar 100 null + b_edicode varchar 50 null + b_voy varchar 100 null + b_bz varchar 200 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_freightpayment --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_con_type --- + b_id varchar 50 not null + b_name varchar 50 null + b_edicode varchar 50 null + b_bz varchar 200 null + b_type varchar 50 null + b_linkcon varchar 50 null + b_default varchar 1 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_jsfs --- + b_id varchar 50 not null + b_name varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_city --- + b_id varchar 50 not null + b_name_c varchar 50 null + b_name_e varchar 50 null + b_country_name_e varchar 50 null + b_country_name_c varchar 50 null + b_bz varchar 500 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_ivtype --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_sys_sex --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_sys_copies --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_cztype --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_sys_level --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + +--- b_sys_operator --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_blstate --- + b_id varchar 50 not null + b_name varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_sys_state --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_sys_feesf --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- bc_priceList_type --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_sys_yesno --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_sys_pricelisttype --- + b_id varchar 50 not null + b_name varchar 50 null + b_dw_id varchar 50 null + b_dw_name varchar 50 null + +--- b_ystype --- + b_id varchar 50 null + b_name varchar 50 null + b_bz varchar 200 null + +--- b_billtype --- + b_id varchar 50 null + b_name varchar 50 null + +--- b_bgtype --- + b_id varchar 50 null + b_name varchar 50 null + +--- b_httype --- + b_id varchar 50 null + b_name varchar 50 null + b_bz varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_transway --- + b_id varchar 50 not null + b_name varchar 100 null + b_edicode varchar 50 null + b_bz varchar 100 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_sys_hdtype --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + +--- b_package --- + b_id varchar 50 not null + b_name varchar 50 null + b_edicode varchar 50 null + b_bz varchar 100 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_progress --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 500 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_zxstate --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_depot --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 200 null + +--- b_depotouttype --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_depotintype --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- car_daily_feetype --- + b_id varchar 50 null + b_name varchar 50 null + +--- car_jiayou_jsfs --- + b_id varchar 50 null + b_name varchar 50 null + +--- car_jiayou_type --- + b_id varchar 50 null + b_name varchar 50 null + +--- b_cdtype --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_shfs --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- car_jiayou_youliao --- + b_id varchar 50 null + b_name varchar 50 null + +--- b_thfs --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_wangdian --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_ywfrom --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_ywtype_tc --- + b_id varchar 50 not null + b_name varchar 50 null + b_bz varchar 50 null + +--- b_servicetype --- + b_id varchar 50 not null + b_name varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_contype --- + b_id varchar 50 not null + b_name varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_ywtype_ht --- + b_id varchar 50 not null + b_name varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_dcterm --- + b_id varchar 50 not null + b_name varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +--- b_ywtype_ky --- + b_id varchar 50 not null + b_name varchar 50 null + b_inputuser_id varchar 50 null + b_inputdatetime datetime 8 null + b_updateuser_id varchar 50 null + b_updatedatetime datetime 8 null + +=== 旧库 G3HY2025:数据样例(每表前 3 行) === + +--- b_cargo_damage_status --- + b_id b_name + 001 完好 + 002 轻微破损 + (2 行) + +--- b_bulkforkliftpersonname --- + b_id b_name + 001 小张 + (1 行) + +--- b_bulktype --- + b_id b_name + 001 散货 + (1 行) + +--- b_bulkpersonname --- + b_id b_name + 001 张三 + 002 李四 + (2 行) + +--- b_bulkstevedorepersonname --- + b_id b_name + 001 小王 + (1 行) + +--- b_charging_method --- + b_id b_name + 001 按件收费 + 002 按托收费 + (2 行) + +--- b_unloading_method --- + b_id b_name + 001 吊车卸货 + 002 铲车卸货 + (2 行) + +--- b_sys_b_lessfull --- + b_id b_name b_bz + 001 整箱 (null) + 002 拼箱 (null) + (2 行) + +--- b_sys_edittype --- + b_id b_name b_bz + 001 selectid (null) + 002 selectname (null) + 003 date (null) + (3 行) + +--- b_vessel --- + b_id b_vessel_name b_edicode b_voy b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 YM FOUNTAIN V.85W (null) N012 (null) (null) (null) (null) (null) + 002 YM FOUNTAIN V.75W (null) N45 (null) (null) (null) (null) (null) + 003 COSCO BOSTON (null) 202N (null) (null) (null) (null) + (3 行) + +--- b_freightpayment --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 FREIGHT PREPAID (null) (null) (null) (null) + 002 FREIGHT COLLECT (null) (null) (null) (null) + 003 Shipping LOYal (null) (null) (null) (null) + (3 行) + +--- b_con_type --- + b_id b_name b_edicode b_bz b_type b_linkcon b_default b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 40GP 大箱 40GP 1 (null) (null) g3soft 2026-07-14 11:09:20.0 + 002 20GP 小箱 20GP 1 (null) (null) g3soft 2026-07-14 11:09:21.0 + 003 45HQ 大箱 45HQ 1 (null) (null) g3soft 2026-07-14 11:09:22.0 + (3 行) + +--- b_jsfs --- + b_id b_name b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 汇票 (null) (null) (null) (null) + 002 转账 (null) (null) (null) (null) + (2 行) + +--- b_city --- + b_id b_name_c b_name_e b_country_name_e b_country_name_c b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + CNNGB 宁波 NINGBO (null) (null) (null) (null) (null) (null) + CS001 阿拉木图 阿拉木图 (null) (null) (null) (null) (null) (null) (null) + CS002 阿腾科里 阿腾科里 (null) (null) (null) (null) (null) (null) (null) + (3 行) + +--- b_ivtype --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 增值税专票 (null) (null) (null) (null) (null) + 002 增值税普票 (null) (null) (null) (null) (null) + (2 行) + +--- b_sys_sex --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 男 (null) (null) (null) (null) (null) + 002 女 (null) (null) (null) (null) (null) + (2 行) + +--- b_sys_copies --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 ZERO (null) (null) (null) (null) (null) + 002 ONE (null) (null) (null) (null) (null) + 003 TWO (null) (null) (null) (null) (null) + (3 行) + +--- b_cztype --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 过磅称重法M1 (null) (null) (null) (null) (null) + 002 累计相加称重法M2 (null) (null) (null) (null) (null) + (2 行) + +--- b_sys_level --- + b_id b_name b_bz + 001 1 (null) + 002 2 (null) + 003 3 (null) + (3 行) + +--- b_sys_operator --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 等于 (null) (null) (null) (null) (null) + 002 不等于 (null) (null) (null) (null) (null) + 003 为空 (null) (null) (null) (null) (null) + (3 行) + +--- b_blstate --- + b_id b_name b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 电放 (null) (null) (null) (null) + 002 正本 (null) (null) (null) (null) + (2 行) + +--- b_sys_state --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 草拟 (null) (null) (null) (null) (null) + 002 送审 (null) (null) (null) (null) (null) + 003 审核通过 (null) (null) (null) (null) (null) + (3 行) + +--- b_sys_feesf --- + b_id b_name b_bz + 001 应收 (null) + 002 应付 (null) + (2 行) + +--- bc_priceList_type --- + b_id b_name b_bz + 001 客户价目 (null) + 002 供应商 (null) + (2 行) + +--- b_sys_yesno --- + b_id b_name b_bz + 001 是 (null) + 002 否 (null) + (2 行) + +--- b_sys_pricelisttype --- + b_id b_name b_dw_id b_dw_name + 001 委托单位 b_customer_id v_customer_company + 002 订舱单位 b_dcdw_id v_dc_company + 003 报关行 b_bgcompany_id v_bg_company + (3 行) + +--- b_ystype --- + b_id b_name b_bz + 001 应收款 (null) + 002 应付款 (null) + 003 预收款 (null) + (3 行) + +--- b_billtype --- + b_id b_name + 001 实际账单 + 002 虚拟账单 + (2 行) + +--- b_bgtype --- + b_id b_name + 001 一般贸易 + 002 市场采购 + (2 行) + +--- b_httype --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 客户合同 (null) (null) (null) (null) (null) + 002 供应商合同 (null) (null) (null) (null) (null) + (2 行) + +--- b_transway --- + b_id b_name b_edicode b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 CY-CY (null) (null) (null) (null) (null) (null) + 002 DOOR-DOOR (null) (null) (null) (null) (null) (null) + 003 CFS-CFS (null) (null) (null) (null) (null) (null) + (3 行) + +--- b_sys_hdtype --- + b_id b_name b_bz + 001 纸质 (null) + 002 电子 (null) + (2 行) + +--- b_package --- + b_id b_name b_edicode b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + BAGS BAGS (null) (null) (null) (null) (null) (null) + BALES BALES (null) (null) (null) (null) (null) (null) + CASES CASES (null) (null) (null) (null) (null) (null) + (3 行) + +--- b_progress --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 Active (null) (null) (null) (null) + 002 Confirmed (null) (null) (null) (null) + 003 Completed (null) (null) (null) (null) + (3 行) + +--- b_zxstate --- + b_id b_name b_bz b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 待处理 (null) (null) (null) (null) + 002 处理中 (null) (null) (null) (null) + 003 已处理 (null) (null) (null) (null) + (3 行) + +--- b_depot --- + b_id b_name b_bz + 001 杭州 + 002 宁波 + (2 行) + +--- b_depotouttype --- + b_id b_name b_bz + 001 领用出库 + (1 行) + +--- b_depotintype --- + b_id b_name b_bz + 001 采购入库 + (1 行) + +--- car_daily_feetype --- + b_id b_name + 001 过路费 + (1 行) + +--- car_jiayou_jsfs --- + b_id b_name + 001 计算金额 + 002 计算升数 + 003 计算单价 + (3 行) + +--- car_jiayou_type --- + b_id b_name + 001 现金加油 + 002 油卡加油 + (2 行) + +--- b_cdtype --- + b_id b_name b_bz + 001 外用司机 (null) + 002 自有车 (null) + (2 行) + +--- b_shfs --- + b_id b_name b_bz + 001 自提 (null) + 002 送货上门 (null) + (2 行) + +--- car_jiayou_youliao --- + b_id b_name + 001 柴油 + 002 尿素 + (2 行) + +--- b_thfs --- + b_id b_name b_bz + 001 客户送货 (null) + 002 上门提货 (null) + (2 行) + +--- b_wangdian --- + b_id b_name b_bz + 001 宁波 + 002 西安 + 003 乌鲁木齐 + (3 行) + +--- b_ywfrom --- + b_id b_name b_bz + 001 非系统 (null) + 002 同行 (null) + (2 行) + +--- b_ywtype_tc --- + b_id b_name b_bz + 001 零担 (null) + 002 整车 (null) + 003 专车 (null) + (3 行) + +--- b_servicetype --- + b_id b_name b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 1 全程散货 g3soft 2026-08-17 13:57:47.0(null) (null) + 2 全程买箱 g3soft 2026-08-17 13:59:27.0(null) (null) + 3 全程车皮 g3soft 2026-08-17 14:00:04.0(null) (null) + (3 行) + +--- b_contype --- + b_id b_name b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 1 租箱 g3soft 2026-08-17 14:05:51.0(null) (null) + 2 买箱 g3soft 2026-08-17 14:06:07.0(null) (null) + 3 铁路箱 g3soft 2026-08-17 14:06:20.0(null) (null) + (3 行) + +--- b_ywtype_ht --- + b_id b_name b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + (0 行) + +--- b_dcterm --- + b_id b_name b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 条款1 g3soft 2026-08-31 15:48:02.0(null) (null) + (1 行) + +--- b_ywtype_ky --- + b_id b_name b_inputuser_id b_inputdatetime b_updateuser_id b_updatedatetime + 001 进口 g3soft 2026-08-31 15:46:48.0(null) (null) + (1 行) diff --git a/code/fms/fms-vue/src/components/fms-module-list/FmsQueryToolbar.vue b/code/fms/fms-vue/src/components/fms-module-list/FmsQueryToolbar.vue index 7edd8bf3..15184094 100644 --- a/code/fms/fms-vue/src/components/fms-module-list/FmsQueryToolbar.vue +++ b/code/fms/fms-vue/src/components/fms-module-list/FmsQueryToolbar.vue @@ -50,6 +50,11 @@ const extraConditionCount = computed( extraQuickItems.value.filter((item) => hasConditionValue(filters[item.field.b_field])).length, ) +/** 网格列数按实际可见条件数收缩(最多 4 列):只有一个条件时不应占满 4 列宽 */ +const gridStyle = computed(() => ({ + gridTemplateColumns: `repeat(${Math.min(Math.max(visibleQuickItems.value.length, 1), 4)}, minmax(0, 200px))`, +})) + function initializeDrafts() { for (const key of Object.keys(filters)) delete filters[key] for (const item of props.queryItems) { @@ -77,7 +82,7 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true })
-
+
props.queryItems, initializeDrafts, { immediate: true }) align-items: flex-end; gap: 16px; } -/* 常用条件网格:固定一行 4 个、每列最大 264px;flex 不撑满(宽屏右侧留白)、窄屏可收缩 */ +/* 常用条件网格:一行最多 4 个、每列最大 200px;列数按实际条件数收缩(行内 style 控制),窄屏可收缩 */ .query-grid { display: grid; flex: 0 1 auto; diff --git a/code/fms/fms-vue/src/components/fms-tree/FmsTree.vue b/code/fms/fms-vue/src/components/fms-tree/FmsTree.vue index d01dd6c9..4b192a53 100644 --- a/code/fms/fms-vue/src/components/fms-tree/FmsTree.vue +++ b/code/fms/fms-vue/src/components/fms-tree/FmsTree.vue @@ -90,6 +90,8 @@ const effectiveTreeData = computed(() => { [fn.value.key]: props.rootKey, isFmsRoot: true, isLeaf: false, + // 虚拟根是整棵树的容器,不参与拖拽排序(仍可作为落点,把节点拖进根 = 移到顶层) + draggable: false, [fn.value.children]: props.treeData, }, ] diff --git a/code/fms/fms-vue/src/components/ui/demo/modal.vue b/code/fms/fms-vue/src/components/ui/demo/modal.vue index 09a7c0f1..ee0c6b96 100644 --- a/code/fms/fms-vue/src/components/ui/demo/modal.vue +++ b/code/fms/fms-vue/src/components/ui/demo/modal.vue @@ -1,6 +1,6 @@