20260802220544
This commit is contained in:
1 parent
c00329b5a4
commit
4fc9040a8a
60 files changed
+6273
-908
No files matched your search
@@ -3,3 +3,6 @@ src/main/resources/ip2region.xdb
|
||||
|
||||
# 多机构数据库连接配置(含敏感信息,已约定不入库)
|
||||
config/dbconfigs/
|
||||
|
||||
# 本地文件存储目录(不入库)
|
||||
data/files/
|
||||
@@ -0,0 +1,24 @@
|
||||
/* 为合作伙伴分类树增加多语言键。*/
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
IF OBJECT_ID(N'dbo.b_othercompany_bmfl', N'U') IS NOT NULL
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(N'dbo.b_othercompany_bmfl') AND name = 'b_i18n'
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE dbo.b_othercompany_bmfl
|
||||
ADD b_i18n varchar(150) NULL;
|
||||
END;
|
||||
|
||||
EXEC sys.sp_executesql N'
|
||||
UPDATE dbo.b_othercompany_bmfl
|
||||
SET b_i18n = ''category.base_othercompany.'' + CAST(b_id AS varchar(30))
|
||||
WHERE b_i18n IS NULL OR b_i18n = '''''';
|
||||
END;
|
||||
|
||||
COMMIT TRANSACTION;
|
||||
@@ -0,0 +1,13 @@
|
||||
/* 为编辑配置增加列宽字段,支持可编辑表格保存栏位设置。 */
|
||||
SET NOCOUNT ON;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(N'dbo.s_module_field_edit')
|
||||
AND name = N'b_width'
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE dbo.s_module_field_edit
|
||||
ADD b_width int NULL;
|
||||
END;
|
||||
@@ -0,0 +1,63 @@
|
||||
/* 为"其他数据"可编辑表格的行拖拽排序提供排序字段。
|
||||
1) b_port / b_city / b_oceanline 补 b_xh 列(b_money 已有);
|
||||
2) 按 b_code 顺序为 b_xh 为空的存量数据初始化排序值(幂等,不覆盖已有排序);
|
||||
3) 对应数据模块默认排序改为 b_xh ASC,使拖拽后的顺序在刷新后保持。 */
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
/* ================= 1. b_port ================= */
|
||||
IF COL_LENGTH(N'dbo.b_port', N'b_xh') IS NULL
|
||||
BEGIN
|
||||
EXEC sys.sp_executesql N'ALTER TABLE dbo.b_port ADD b_xh int NULL;';
|
||||
END;
|
||||
|
||||
EXEC sys.sp_executesql N'
|
||||
WITH numbered AS (
|
||||
SELECT b_id, b_xh, ROW_NUMBER() OVER (ORDER BY b_code ASC, b_id ASC) AS row_no
|
||||
FROM dbo.b_port
|
||||
WHERE b_xh IS NULL
|
||||
)
|
||||
UPDATE numbered SET b_xh = row_no * 10;';
|
||||
|
||||
/* ================= 2. b_city ================= */
|
||||
IF COL_LENGTH(N'dbo.b_city', N'b_xh') IS NULL
|
||||
BEGIN
|
||||
EXEC sys.sp_executesql N'ALTER TABLE dbo.b_city ADD b_xh int NULL;';
|
||||
END;
|
||||
|
||||
EXEC sys.sp_executesql N'
|
||||
WITH numbered AS (
|
||||
SELECT b_id, b_xh, ROW_NUMBER() OVER (ORDER BY b_code ASC, b_id ASC) AS row_no
|
||||
FROM dbo.b_city
|
||||
WHERE b_xh IS NULL
|
||||
)
|
||||
UPDATE numbered SET b_xh = row_no * 10;';
|
||||
|
||||
/* ================= 3. b_oceanline ================= */
|
||||
IF COL_LENGTH(N'dbo.b_oceanline', N'b_xh') IS NULL
|
||||
BEGIN
|
||||
EXEC sys.sp_executesql N'ALTER TABLE dbo.b_oceanline ADD b_xh int NULL;';
|
||||
END;
|
||||
|
||||
EXEC sys.sp_executesql N'
|
||||
WITH numbered AS (
|
||||
SELECT b_id, b_xh, ROW_NUMBER() OVER (ORDER BY b_code ASC, b_id ASC) AS row_no
|
||||
FROM dbo.b_oceanline
|
||||
WHERE b_xh IS NULL
|
||||
)
|
||||
UPDATE numbered SET b_xh = row_no * 10;';
|
||||
|
||||
/* ================= 4. 模块默认排序切到 b_xh =================
|
||||
base_otherdata 页面下的所有数据模块统一按 b_xh 排序,
|
||||
拖拽后的顺序在刷新后才会保持。 */
|
||||
UPDATE m
|
||||
SET m.b_orderfield = N'b_xh ASC'
|
||||
FROM dbo.s_module m
|
||||
INNER JOIN dbo.s_module p
|
||||
ON p.b_id = m.b_parent_id
|
||||
AND p.b_code = N'base_otherdata'
|
||||
WHERE m.b_module_type = N'data';
|
||||
|
||||
COMMIT TRANSACTION;
|
||||
@@ -0,0 +1,19 @@
|
||||
/* 移除其他数据分类树的多语言列。此前通过 025 添加,现决定暂不做多语言。*/
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
IF OBJECT_ID(N'dbo.b_other_bmfl', N'U') IS NOT NULL
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(N'dbo.b_other_bmfl') AND name = 'b_i18n'
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE dbo.b_other_bmfl
|
||||
DROP COLUMN b_i18n;
|
||||
END;
|
||||
END;
|
||||
|
||||
COMMIT TRANSACTION;
|
||||
@@ -0,0 +1,19 @@
|
||||
/* 移除合作伙伴分类树的多语言列。此前通过 027 添加,现决定暂不做多语言。*/
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
IF OBJECT_ID(N'dbo.b_othercompany_bmfl', N'U') IS NOT NULL
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(N'dbo.b_othercompany_bmfl') AND name = 'b_i18n'
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE dbo.b_othercompany_bmfl
|
||||
DROP COLUMN b_i18n;
|
||||
END;
|
||||
END;
|
||||
|
||||
COMMIT TRANSACTION;
|
||||
@@ -0,0 +1,384 @@
|
||||
/* 032_rebuild_otherdata.sql — 重做"其他数据"子系统迁移
|
||||
*
|
||||
* 背景:此前用 OtherDataMigration 工具迁移产生错误结果——
|
||||
* 1. 分类树被连跑 7 次产生重复分支;
|
||||
* 2. 只有 b_port 一个数据模块,城市/币种/航线模块缺失;
|
||||
* 3. b_port 真实数据未迁入(旧 b_id 含中文港口名,b_code 列 SQL_Latin1 排序规则存不下,
|
||||
* 插入时中文转 '?' 触发 UQ_b_port_b_code 唯一索引冲突而整表回滚)。
|
||||
*
|
||||
* 本脚本(前置:026、030 已应用,b_other_bmfl 已无 b_level/b_path/b_i18n 列):
|
||||
* 1. 清空并重建分类树(基础信息/财务信息/物流信息 + 4 个数据节点,模块编码沿用表名 b_*);
|
||||
* 2. 移除 022 的 mock 占位数据;
|
||||
* 3. b_port.b_code 排序规则改为 Chinese_PRC_CI_AS,迁入 193 条真实港口数据;
|
||||
* 4. 补建 b_city / b_money / b_oceanline 数据模块(字段/列表/查询/编辑配置);
|
||||
* 5. 回填 b_city / b_oceanline 迁移数据的 b_xh 排序值。
|
||||
*
|
||||
* 幂等:可重复执行。
|
||||
*/
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
/* =========================================================================
|
||||
1. 清理错乱的分类树
|
||||
========================================================================= */
|
||||
DELETE FROM dbo.b_other_bmfl;
|
||||
|
||||
/* =========================================================================
|
||||
2. 移除 022 mock 占位数据(按预留 ID 段精确删除)
|
||||
========================================================================= */
|
||||
DELETE FROM dbo.b_port WHERE b_id BETWEEN 920000000000110001 AND 920000000000110005;
|
||||
DELETE FROM dbo.b_city WHERE b_id BETWEEN 920000000000110101 AND 920000000000110104;
|
||||
DELETE FROM dbo.b_money WHERE b_id BETWEEN 920000000000110201 AND 920000000000110204;
|
||||
DELETE FROM dbo.b_oceanline WHERE b_id BETWEEN 920000000000110301 AND 920000000000110304;
|
||||
|
||||
/* =========================================================================
|
||||
3. b_port.b_code 排序规则改为 Chinese_PRC_CI_AS(容纳中文港口代码)
|
||||
(需先删依赖该列的唯一索引,改完再重建)
|
||||
========================================================================= */
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(N'dbo.b_port')
|
||||
AND name = N'b_code'
|
||||
AND collation_name <> N'Chinese_PRC_CI_AS'
|
||||
)
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM sys.key_constraints
|
||||
WHERE parent_object_id = OBJECT_ID(N'dbo.b_port')
|
||||
AND name = N'UQ_b_port_b_code'
|
||||
)
|
||||
ALTER TABLE dbo.b_port DROP CONSTRAINT [UQ_b_port_b_code];
|
||||
|
||||
ALTER TABLE dbo.b_port ALTER COLUMN b_code varchar(50) COLLATE Chinese_PRC_CI_AS NOT NULL;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM sys.key_constraints
|
||||
WHERE parent_object_id = OBJECT_ID(N'dbo.b_port')
|
||||
AND name = N'UQ_b_port_b_code'
|
||||
)
|
||||
ALTER TABLE dbo.b_port ADD CONSTRAINT [UQ_b_port_b_code] UNIQUE NONCLUSTERED (b_code);
|
||||
END;
|
||||
|
||||
GO
|
||||
|
||||
/* =========================================================================
|
||||
4. 迁移 b_port 真实数据(193 行,含中文代码)
|
||||
========================================================================= */
|
||||
INSERT INTO dbo.b_port (
|
||||
b_id, b_name_c, b_name_e, b_country, b_oceanline, b_edicode, b_bz, b_tz,
|
||||
b_inputdatetime, b_code, b_xh
|
||||
)
|
||||
SELECT 920000000000110005 + ROW_NUMBER() OVER (ORDER BY LTRIM(RTRIM(old.b_id))),
|
||||
old.b_name_c, old.b_name_e, old.b_country, old.b_oceanline, old.b_edicode,
|
||||
old.b_bz, old.b_tz,
|
||||
SYSDATETIME(),
|
||||
LTRIM(RTRIM(old.b_id)),
|
||||
ROW_NUMBER() OVER (ORDER BY LTRIM(RTRIM(old.b_id))) * 10
|
||||
FROM G3HY2025.dbo.b_port old
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.b_port new WHERE new.b_code = LTRIM(RTRIM(old.b_id))
|
||||
);
|
||||
|
||||
/* =========================================================================
|
||||
5. 补建数据模块 b_city / b_money / b_oceanline
|
||||
========================================================================= */
|
||||
DECLARE @PageId bigint = 920000000000001100;
|
||||
DECLARE @DataId bigint;
|
||||
DECLARE @DataCode varchar(100);
|
||||
|
||||
/* ---- 5.1 b_city(城市) ---- */
|
||||
SET @DataCode = 'b_city';
|
||||
SET @DataId = 920000000000001102;
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.s_module WHERE b_code = @DataCode)
|
||||
BEGIN
|
||||
INSERT INTO dbo.s_module (
|
||||
b_id, b_code, b_parent_id, b_name, b_i18n, b_module_type, b_route,
|
||||
b_viewtable, b_savetable, b_keyfield, b_orderfield, b_canmenu, b_canuse, b_xh
|
||||
) VALUES (
|
||||
@DataId, @DataCode, @PageId, N'城市', 'module.b_city', 'data', NULL,
|
||||
'b_city', 'b_city', 'b_id', 'b_xh ASC', 0, 1, 20
|
||||
);
|
||||
END
|
||||
|
||||
DECLARE @CityFields TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_name nvarchar(200) NOT NULL, b_type varchar(30) NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @CityFields VALUES
|
||||
(920000000000010201, 'b_id', N'系统编号', 'input', 10),
|
||||
(920000000000010202, 'b_code', N'城市代码', 'input', 20),
|
||||
(920000000000010203, 'b_name_c', N'中文名称', 'input', 30),
|
||||
(920000000000010204, 'b_name_e', N'英文名称', 'input', 40),
|
||||
(920000000000010205, 'b_country_name_c', N'国家(中)', 'input', 50),
|
||||
(920000000000010206, 'b_country_name_e', N'国家(英)', 'input', 60),
|
||||
(920000000000010207, 'b_bz', N'备注', 'input', 70);
|
||||
|
||||
INSERT INTO dbo.s_module_field (b_id, b_module_id, b_field, b_name, b_i18n, b_type, b_canuse)
|
||||
SELECT source.b_id, @DataId, source.b_field, source.b_name,
|
||||
'field.b_city.' + source.b_field, source.b_type, 1
|
||||
FROM @CityFields source
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @CityList TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_xh int NOT NULL, b_width int NOT NULL);
|
||||
INSERT INTO @CityList VALUES
|
||||
(920000000000020201, 'b_code', 10, 120),
|
||||
(920000000000020202, 'b_name_c', 20, 150),
|
||||
(920000000000020203, 'b_name_e', 30, 180),
|
||||
(920000000000020204, 'b_country_name_c', 40, 140),
|
||||
(920000000000020205, 'b_country_name_e', 50, 140);
|
||||
|
||||
INSERT INTO dbo.s_module_field_list (b_id, b_module_id, b_field_id, b_i18n, b_visible, b_xh, b_width)
|
||||
SELECT source.b_id, @DataId, f.b_id, 'field.b_city.' + f.b_field, 1, source.b_xh, source.b_width
|
||||
FROM @CityList source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_list t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @CityQuery TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @CityQuery VALUES
|
||||
(920000000000030201, 'b_code', 10),
|
||||
(920000000000030202, 'b_name_c', 20);
|
||||
|
||||
INSERT INTO dbo.s_module_field_query (b_id, b_module_id, b_field_id, b_component, b_operator, b_default_value, b_xh, b_canuse)
|
||||
SELECT source.b_id, @DataId, f.b_id, 'input', 'like', NULL, source.b_xh, 1
|
||||
FROM @CityQuery source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_query t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @CityEdit TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_visible int NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @CityEdit VALUES
|
||||
(920000000000050201, 'b_id', 0, 10),
|
||||
(920000000000050202, 'b_code', 1, 20),
|
||||
(920000000000050203, 'b_name_c', 1, 30),
|
||||
(920000000000050204, 'b_name_e', 1, 40),
|
||||
(920000000000050205, 'b_country_name_c', 1, 50),
|
||||
(920000000000050206, 'b_country_name_e', 1, 60),
|
||||
(920000000000050207, 'b_bz', 1, 70);
|
||||
|
||||
INSERT INTO dbo.s_module_field_edit (b_id, b_module_id, b_field_id, b_required, b_readonly, b_disabled, b_xh, b_visible)
|
||||
SELECT source.b_id, @DataId, f.b_id, 0, 0, 0, source.b_xh, source.b_visible
|
||||
FROM @CityEdit source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_edit t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
/* ---- 5.2 b_money(币种) ---- */
|
||||
SET @DataCode = 'b_money';
|
||||
SET @DataId = 920000000000001103;
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.s_module WHERE b_code = @DataCode)
|
||||
BEGIN
|
||||
INSERT INTO dbo.s_module (
|
||||
b_id, b_code, b_parent_id, b_name, b_i18n, b_module_type, b_route,
|
||||
b_viewtable, b_savetable, b_keyfield, b_orderfield, b_canmenu, b_canuse, b_xh
|
||||
) VALUES (
|
||||
@DataId, @DataCode, @PageId, N'币种', 'module.b_money', 'data', NULL,
|
||||
'b_money', 'b_money', 'b_id', 'b_xh ASC', 0, 1, 30
|
||||
);
|
||||
END
|
||||
|
||||
DECLARE @MoneyFields TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_name nvarchar(200) NOT NULL, b_type varchar(30) NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @MoneyFields VALUES
|
||||
(920000000000010301, 'b_id', N'系统编号', 'input', 10),
|
||||
(920000000000010302, 'b_code', N'币种代码', 'input', 20),
|
||||
(920000000000010303, 'b_name', N'名称', 'input', 30),
|
||||
(920000000000010304, 'b_edicode', N'EDI代码', 'input', 40),
|
||||
(920000000000010305, 'b_symbol', N'符号', 'input', 50),
|
||||
(920000000000010306, 'b_hl', N'汇率', 'number', 60),
|
||||
(920000000000010307, 'b_isconvert', N'可兑换', 'checkbox', 70),
|
||||
(920000000000010308, 'b_canuse', N'启用', 'checkbox', 80),
|
||||
(920000000000010309, 'b_xh', N'排序', 'number', 90),
|
||||
(920000000000010310, 'b_bz', N'备注', 'input', 100);
|
||||
|
||||
INSERT INTO dbo.s_module_field (b_id, b_module_id, b_field, b_name, b_i18n, b_type, b_canuse)
|
||||
SELECT source.b_id, @DataId, source.b_field, source.b_name,
|
||||
'field.b_money.' + source.b_field, source.b_type, 1
|
||||
FROM @MoneyFields source
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @MoneyList TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_xh int NOT NULL, b_width int NOT NULL);
|
||||
INSERT INTO @MoneyList VALUES
|
||||
(920000000000020301, 'b_code', 10, 120),
|
||||
(920000000000020302, 'b_name', 20, 150),
|
||||
(920000000000020303, 'b_edicode', 30, 120),
|
||||
(920000000000020304, 'b_symbol', 40, 80),
|
||||
(920000000000020305, 'b_hl', 50, 120),
|
||||
(920000000000020306, 'b_canuse', 60, 80);
|
||||
|
||||
INSERT INTO dbo.s_module_field_list (b_id, b_module_id, b_field_id, b_i18n, b_visible, b_xh, b_width)
|
||||
SELECT source.b_id, @DataId, f.b_id, 'field.b_money.' + f.b_field, 1, source.b_xh, source.b_width
|
||||
FROM @MoneyList source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_list t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @MoneyQuery TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @MoneyQuery VALUES
|
||||
(920000000000030301, 'b_code', 10),
|
||||
(920000000000030302, 'b_name', 20);
|
||||
|
||||
INSERT INTO dbo.s_module_field_query (b_id, b_module_id, b_field_id, b_component, b_operator, b_default_value, b_xh, b_canuse)
|
||||
SELECT source.b_id, @DataId, f.b_id, 'input', 'like', NULL, source.b_xh, 1
|
||||
FROM @MoneyQuery source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_query t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @MoneyEdit TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_visible int NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @MoneyEdit VALUES
|
||||
(920000000000050301, 'b_id', 0, 10),
|
||||
(920000000000050302, 'b_code', 1, 20),
|
||||
(920000000000050303, 'b_name', 1, 30),
|
||||
(920000000000050304, 'b_edicode', 1, 40),
|
||||
(920000000000050305, 'b_symbol', 1, 50),
|
||||
(920000000000050306, 'b_hl', 1, 60),
|
||||
(920000000000050307, 'b_isconvert', 1, 70),
|
||||
(920000000000050308, 'b_canuse', 1, 80),
|
||||
(920000000000050309, 'b_xh', 1, 90),
|
||||
(920000000000050310, 'b_bz', 1, 100);
|
||||
|
||||
INSERT INTO dbo.s_module_field_edit (b_id, b_module_id, b_field_id, b_required, b_readonly, b_disabled, b_xh, b_visible)
|
||||
SELECT source.b_id, @DataId, f.b_id, 0, 0, 0, source.b_xh, source.b_visible
|
||||
FROM @MoneyEdit source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_edit t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
/* ---- 5.3 b_oceanline(航线) ---- */
|
||||
SET @DataCode = 'b_oceanline';
|
||||
SET @DataId = 920000000000001104;
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.s_module WHERE b_code = @DataCode)
|
||||
BEGIN
|
||||
INSERT INTO dbo.s_module (
|
||||
b_id, b_code, b_parent_id, b_name, b_i18n, b_module_type, b_route,
|
||||
b_viewtable, b_savetable, b_keyfield, b_orderfield, b_canmenu, b_canuse, b_xh
|
||||
) VALUES (
|
||||
@DataId, @DataCode, @PageId, N'航线', 'module.b_oceanline', 'data', NULL,
|
||||
'b_oceanline', 'b_oceanline', 'b_id', 'b_xh ASC', 0, 1, 40
|
||||
);
|
||||
END
|
||||
|
||||
DECLARE @OceanFields TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_name nvarchar(200) NOT NULL, b_type varchar(30) NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @OceanFields VALUES
|
||||
(920000000000010401, 'b_id', N'系统编号', 'input', 10),
|
||||
(920000000000010402, 'b_code', N'航线代码', 'input', 20),
|
||||
(920000000000010403, 'b_name', N'名称', 'input', 30),
|
||||
(920000000000010404, 'b_edicode', N'EDI代码', 'input', 40),
|
||||
(920000000000010405, 'b_bz', N'备注', 'input', 50);
|
||||
|
||||
INSERT INTO dbo.s_module_field (b_id, b_module_id, b_field, b_name, b_i18n, b_type, b_canuse)
|
||||
SELECT source.b_id, @DataId, source.b_field, source.b_name,
|
||||
'field.b_oceanline.' + source.b_field, source.b_type, 1
|
||||
FROM @OceanFields source
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @OceanList TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_xh int NOT NULL, b_width int NOT NULL);
|
||||
INSERT INTO @OceanList VALUES
|
||||
(920000000000020401, 'b_code', 10, 120),
|
||||
(920000000000020402, 'b_name', 20, 180),
|
||||
(920000000000020403, 'b_edicode', 30, 120);
|
||||
|
||||
INSERT INTO dbo.s_module_field_list (b_id, b_module_id, b_field_id, b_i18n, b_visible, b_xh, b_width)
|
||||
SELECT source.b_id, @DataId, f.b_id, 'field.b_oceanline.' + f.b_field, 1, source.b_xh, source.b_width
|
||||
FROM @OceanList source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_list t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @OceanQuery TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @OceanQuery VALUES
|
||||
(920000000000030401, 'b_code', 10),
|
||||
(920000000000030402, 'b_name', 20);
|
||||
|
||||
INSERT INTO dbo.s_module_field_query (b_id, b_module_id, b_field_id, b_component, b_operator, b_default_value, b_xh, b_canuse)
|
||||
SELECT source.b_id, @DataId, f.b_id, 'input', 'like', NULL, source.b_xh, 1
|
||||
FROM @OceanQuery source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_query t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
DECLARE @OceanEdit TABLE (b_id bigint NOT NULL, b_field varchar(50) NOT NULL, b_visible int NOT NULL, b_xh int NOT NULL);
|
||||
INSERT INTO @OceanEdit VALUES
|
||||
(920000000000050401, 'b_id', 0, 10),
|
||||
(920000000000050402, 'b_code', 1, 20),
|
||||
(920000000000050403, 'b_name', 1, 30),
|
||||
(920000000000050404, 'b_edicode', 1, 40),
|
||||
(920000000000050405, 'b_bz', 1, 50);
|
||||
|
||||
INSERT INTO dbo.s_module_field_edit (b_id, b_module_id, b_field_id, b_required, b_readonly, b_disabled, b_xh, b_visible)
|
||||
SELECT source.b_id, @DataId, f.b_id, 0, 0, 0, source.b_xh, source.b_visible
|
||||
FROM @OceanEdit source
|
||||
JOIN dbo.s_module_field f ON f.b_module_id = @DataId AND f.b_field = source.b_field
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM dbo.s_module_field_edit t WHERE t.b_id = source.b_id
|
||||
);
|
||||
|
||||
/* =========================================================================
|
||||
6. 回填 b_city / b_oceanline 迁移数据的 b_xh(b_money 旧库自带 b_xh)
|
||||
========================================================================= */
|
||||
WITH numbered AS (
|
||||
SELECT b_id, b_xh, ROW_NUMBER() OVER (ORDER BY b_code ASC, b_id ASC) AS row_no
|
||||
FROM dbo.b_city WHERE b_xh IS NULL
|
||||
)
|
||||
UPDATE numbered SET b_xh = row_no * 10;
|
||||
|
||||
WITH numbered AS (
|
||||
SELECT b_id, b_xh, ROW_NUMBER() OVER (ORDER BY b_code ASC, b_id ASC) AS row_no
|
||||
FROM dbo.b_oceanline WHERE b_xh IS NULL
|
||||
)
|
||||
UPDATE numbered SET b_xh = row_no * 10;
|
||||
|
||||
/* =========================================================================
|
||||
7. 重建分类树(引用设计:category 仅结构,module 引用 s_module.b_code)
|
||||
========================================================================= */
|
||||
DECLARE @CatBasic bigint = 930000000000000101;
|
||||
DECLARE @CatFinance bigint = 930000000000000102;
|
||||
DECLARE @CatLogistics bigint = 930000000000000103;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.b_other_bmfl WHERE b_id = @CatBasic)
|
||||
INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse)
|
||||
VALUES (@CatBasic, NULL, N'基础信息', 'category', NULL, 10, 1);
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.b_other_bmfl WHERE b_id = @CatFinance)
|
||||
INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse)
|
||||
VALUES (@CatFinance, NULL, N'财务信息', 'category', NULL, 20, 1);
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.b_other_bmfl WHERE b_id = @CatLogistics)
|
||||
INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse)
|
||||
VALUES (@CatLogistics, NULL, N'物流信息', 'category', NULL, 30, 1);
|
||||
|
||||
DECLARE @NodePort bigint = 930000000000000201;
|
||||
DECLARE @NodeCity bigint = 930000000000000202;
|
||||
DECLARE @NodeMoney bigint = 930000000000000203;
|
||||
DECLARE @NodeOceanline bigint = 930000000000000204;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.b_other_bmfl WHERE b_id = @NodePort)
|
||||
INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse)
|
||||
VALUES (@NodePort, @CatBasic, N'港口', 'module', 'b_port', 10, 1);
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.b_other_bmfl WHERE b_id = @NodeCity)
|
||||
INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse)
|
||||
VALUES (@NodeCity, @CatBasic, N'城市', 'module', 'b_city', 20, 1);
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.b_other_bmfl WHERE b_id = @NodeMoney)
|
||||
INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse)
|
||||
VALUES (@NodeMoney, @CatFinance, N'币种', 'module', 'b_money', 10, 1);
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM dbo.b_other_bmfl WHERE b_id = @NodeOceanline)
|
||||
INSERT INTO dbo.b_other_bmfl (b_id, b_parent_id, b_name, b_node_type, b_module_code, b_xh, b_canuse)
|
||||
VALUES (@NodeOceanline, @CatLogistics, N'航线', 'module', 'b_oceanline', 10, 1);
|
||||
|
||||
COMMIT TRANSACTION;
|
||||
@@ -61,11 +61,15 @@
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
<version>3.3.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
<version>3.3.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ua-parser</groupId>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.g3soft.fmsapi.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "fms.file")
|
||||
public class FileStorageProperties {
|
||||
|
||||
private String storageType;
|
||||
private Local local = new Local();
|
||||
private Oss oss = new Oss();
|
||||
|
||||
public String getStorageType() {
|
||||
return storageType;
|
||||
}
|
||||
|
||||
public void setStorageType(String storageType) {
|
||||
this.storageType = storageType;
|
||||
}
|
||||
|
||||
public Local getLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public void setLocal(Local local) {
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
public Oss getOss() {
|
||||
return oss;
|
||||
}
|
||||
|
||||
public void setOss(Oss oss) {
|
||||
this.oss = oss;
|
||||
}
|
||||
|
||||
public static class Local {
|
||||
private String storageDir;
|
||||
private String urlPrefix;
|
||||
|
||||
public String getStorageDir() {
|
||||
return storageDir;
|
||||
}
|
||||
|
||||
public void setStorageDir(String storageDir) {
|
||||
this.storageDir = storageDir;
|
||||
}
|
||||
|
||||
public String getUrlPrefix() {
|
||||
return urlPrefix;
|
||||
}
|
||||
|
||||
public void setUrlPrefix(String urlPrefix) {
|
||||
this.urlPrefix = urlPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Oss {
|
||||
private String g3ossUrl;
|
||||
|
||||
public String getG3ossUrl() {
|
||||
return g3ossUrl;
|
||||
}
|
||||
|
||||
public void setG3ossUrl(String g3ossUrl) {
|
||||
this.g3ossUrl = g3ossUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,7 @@ public class JwtAuthFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
OrgContext.setOrgId(claims.orgId());
|
||||
OrgContext.setUserId(claims.userId());
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
} finally {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package cn.g3soft.fmsapi.controller;
|
||||
|
||||
import cn.g3soft.fmsapi.config.FileStorageProperties;
|
||||
import cn.g3soft.fmsapi.service.FileService;
|
||||
import cn.g3soft.fmsapi.utils.ApiResponse;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
public class FileController {
|
||||
|
||||
@Resource
|
||||
private FileStorageProperties props;
|
||||
|
||||
@Resource
|
||||
private FileService fileService;
|
||||
|
||||
/**
|
||||
* 返回存储模式配置
|
||||
*/
|
||||
@PostMapping("/config")
|
||||
public ApiResponse<Map<String, Object>> config() {
|
||||
Map<String, Object> cfg = new LinkedHashMap<>();
|
||||
cfg.put("storageType", props.getStorageType().toLowerCase());
|
||||
return ApiResponse.success(cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地上传(支持多文件,FormData key: "files")
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public ApiResponse<List<Map<String, Object>>> upload(
|
||||
@RequestParam("files") List<MultipartFile> files,
|
||||
@RequestParam("father") String father,
|
||||
@RequestParam("moduleId") String moduleId,
|
||||
@RequestParam(value = "cateId", required = false) String cateId
|
||||
) throws IOException, SQLException {
|
||||
return ApiResponse.success(fileService.localUpload(files, father, moduleId, cateId));
|
||||
}
|
||||
|
||||
/**
|
||||
* OSS 上传凭证(bucket = 机构码)
|
||||
*/
|
||||
@PostMapping("/upload-credential")
|
||||
public ApiResponse<?> uploadCredential() throws IOException, InterruptedException {
|
||||
return ApiResponse.success(fileService.ossCredential());
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件记录到 DB(OSS 直传后回调)
|
||||
*/
|
||||
@PostMapping("/save-record")
|
||||
public ApiResponse<Map<String, Object>> saveRecord(@RequestBody Map<String, Object> body)
|
||||
throws SQLException {
|
||||
return ApiResponse.success(fileService.saveRecord(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
public ApiResponse<Void> delete(@RequestBody Map<String, Object> body)
|
||||
throws SQLException, IOException, InterruptedException {
|
||||
String subid = String.valueOf(body.get("subid"));
|
||||
fileService.delete(subid);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地文件访问(路径含子目录: {orgId}/{yyyy}/{MM}/{dd}/{file})
|
||||
*/
|
||||
@GetMapping("/static/{fileName:.+}")
|
||||
public void serveFile(@PathVariable String fileName, HttpServletResponse response) throws IOException {
|
||||
Path dir = Path.of(props.getLocal().getStorageDir()).toAbsolutePath().normalize();
|
||||
Path file = dir.resolve(fileName).normalize();
|
||||
|
||||
// 路径穿越防护
|
||||
if (!file.startsWith(dir) || !Files.isRegularFile(file)) {
|
||||
response.setStatus(404);
|
||||
return;
|
||||
}
|
||||
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Content-Disposition", "inline; filename*=UTF-8''"
|
||||
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8));
|
||||
response.setContentLengthLong(Files.size(file));
|
||||
|
||||
try (OutputStream out = response.getOutputStream()) {
|
||||
Files.copy(file, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,13 @@ package cn.g3soft.fmsapi.database;
|
||||
public final class OrgContext {
|
||||
|
||||
private static final ThreadLocal<String> ORG_ID_HOLDER = new ThreadLocal<>();
|
||||
private static final ThreadLocal<String> USER_ID_HOLDER = new ThreadLocal<>();
|
||||
|
||||
private OrgContext() {
|
||||
}
|
||||
|
||||
// -- orgId --
|
||||
|
||||
public static void setOrgId(String orgId) {
|
||||
if (orgId == null || orgId.isBlank()) {
|
||||
throw new IllegalArgumentException("机构码不能为空");
|
||||
@@ -26,7 +29,26 @@ public final class OrgContext {
|
||||
return orgId;
|
||||
}
|
||||
|
||||
// -- userId --
|
||||
|
||||
public static void setUserId(String userId) {
|
||||
USER_ID_HOLDER.set(userId);
|
||||
}
|
||||
|
||||
public static String getUserId() {
|
||||
return USER_ID_HOLDER.get();
|
||||
}
|
||||
|
||||
public static String requireUserId() {
|
||||
String userId = getUserId();
|
||||
if (userId == null) {
|
||||
throw new IllegalStateException("当前请求未设置用户上下文");
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
ORG_ID_HOLDER.remove();
|
||||
USER_ID_HOLDER.remove();
|
||||
}
|
||||
}
|
||||
@@ -28,9 +28,12 @@ public class OrgDataSourceFactory {
|
||||
dataSource.setTestWhileIdle(poolProperties.isTestWhileIdle());
|
||||
dataSource.setTestOnBorrow(poolProperties.isTestOnBorrow());
|
||||
dataSource.setTestOnReturn(poolProperties.isTestOnReturn());
|
||||
dataSource.setConnectionErrorRetryAttempts(0);
|
||||
dataSource.setBreakAfterAcquireFailure(true);
|
||||
dataSource.setFailFast(true);
|
||||
dataSource.setConnectionErrorRetryAttempts(3);
|
||||
dataSource.setBreakAfterAcquireFailure(false);
|
||||
dataSource.setFailFast(false);
|
||||
// 定期 ping 空闲连接,对抗云 NAT/防火墙回收空闲 TCP 会话(默认 120s)
|
||||
dataSource.setKeepAlive(true);
|
||||
dataSource.setKeepAliveBetweenTimeMillis(120_000);
|
||||
dataSource.setTimeBetweenEvictionRunsMillis(
|
||||
poolProperties.getTimeBetweenEvictionRuns().toMillis()
|
||||
);
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
package cn.g3soft.fmsapi.service;
|
||||
|
||||
import cn.g3soft.fmsapi.config.FileStorageProperties;
|
||||
import cn.g3soft.fmsapi.database.OrgContext;
|
||||
import cn.g3soft.fmsapi.exception.BusinessException;
|
||||
import cn.g3soft.fmsapi.utils.DbUtils;
|
||||
import cn.g3soft.fmsapi.utils.snowflake.idgen.IdGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class FileService {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
|
||||
@Resource
|
||||
private FileStorageProperties props;
|
||||
|
||||
@Resource
|
||||
private DbUtils dbUtils;
|
||||
|
||||
@Resource
|
||||
private DataSource dataSource;
|
||||
|
||||
/**
|
||||
* 本地上传:逐个写磁盘 → 写 DB → 返回元数据列表
|
||||
*/
|
||||
public List<Map<String, Object>> localUpload(List<MultipartFile> files, String father, String moduleId, String cateId)
|
||||
throws IOException, SQLException {
|
||||
List<Map<String, Object>> results = new ArrayList<>();
|
||||
for (MultipartFile file : files) {
|
||||
results.add(uploadOne(file, father, moduleId, cateId));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private Map<String, Object> uploadOne(MultipartFile file, String father, String moduleId, String cateId)
|
||||
throws IOException, SQLException {
|
||||
long subid = IdGenerator.nextId();
|
||||
String originalName = file.getOriginalFilename();
|
||||
String ext = extension(originalName);
|
||||
String fileName = UUID.randomUUID().toString().replace("-", "") + (ext.isEmpty() ? "" : "." + ext);
|
||||
|
||||
// 机构码/年/月/日/文件名
|
||||
String orgId = OrgContext.requireOrgId();
|
||||
LocalDate today = LocalDate.now();
|
||||
String subPath = String.format("%s/%04d/%02d/%02d/%s",
|
||||
orgId, today.getYear(), today.getMonthValue(), today.getDayOfMonth(), fileName);
|
||||
|
||||
Path baseDir = Path.of(props.getLocal().getStorageDir()).toAbsolutePath().normalize();
|
||||
Path target = baseDir.resolve(subPath);
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.copy(file.getInputStream(), target, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
String mapFilename = props.getLocal().getUrlPrefix() + "/" + subPath;
|
||||
|
||||
insertFileRecord(subid, father, moduleId, cateId,
|
||||
originalName, String.valueOf(file.getSize()), ext, mapFilename);
|
||||
|
||||
Map<String, Object> meta = new LinkedHashMap<>();
|
||||
meta.put("subid", String.valueOf(subid));
|
||||
meta.put("mx_filename", originalName);
|
||||
meta.put("mx_filesize", String.valueOf(file.getSize()));
|
||||
meta.put("mx_fileext", ext);
|
||||
meta.put("mx_mapfilename", mapFilename);
|
||||
meta.put("father", father);
|
||||
meta.put("mx_moduleid", moduleId);
|
||||
meta.put("mx_cate_id", cateId);
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件记录到 DB(OSS 模式:前端直传后回调写入)
|
||||
*/
|
||||
public Map<String, Object> saveRecord(Map<String, Object> meta) throws SQLException {
|
||||
long subid = Long.parseLong(String.valueOf(meta.get("subid")));
|
||||
String father = String.valueOf(meta.get("father"));
|
||||
String moduleId = String.valueOf(meta.get("mx_moduleid"));
|
||||
String cateId = meta.containsKey("mx_cate_id") ? String.valueOf(meta.get("mx_cate_id")) : null;
|
||||
String filename = String.valueOf(meta.get("mx_filename"));
|
||||
String filesize = String.valueOf(meta.get("mx_filesize"));
|
||||
String fileext = String.valueOf(meta.get("mx_fileext"));
|
||||
String mapfilename = String.valueOf(meta.get("mx_mapfilename"));
|
||||
|
||||
insertFileRecord(subid, father, moduleId, cateId,
|
||||
filename, filesize, fileext, mapfilename);
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("subid", String.valueOf(subid));
|
||||
result.put("message", "记录已保存");
|
||||
return result;
|
||||
}
|
||||
|
||||
private void insertFileRecord(long subid, String father, String moduleId, String cateId,
|
||||
String filename, String filesize, String fileext, String mapfilename)
|
||||
throws SQLException {
|
||||
String userId = OrgContext.getUserId();
|
||||
Connection connection = DataSourceUtils.getConnection(dataSource);
|
||||
try {
|
||||
String sql = """
|
||||
INSERT INTO [bf_files] (
|
||||
[subid], [father], [mx_filename], [mx_filesize], [mx_fileext],
|
||||
[mx_mapfilename], [mx_moduleid], [mx_cate_id], [mx_xh], [mx_sh],
|
||||
[mx_inputuser_id], [mx_inputdatetime]
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, 0, ?, SYSDATETIME())
|
||||
""";
|
||||
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||
ps.setLong(1, subid);
|
||||
ps.setObject(2, toLongOrNull(father));
|
||||
ps.setString(3, filename);
|
||||
ps.setString(4, filesize);
|
||||
ps.setString(5, fileext);
|
||||
ps.setString(6, mapfilename);
|
||||
ps.setObject(7, toLongOrNull(moduleId));
|
||||
ps.setObject(8, toLongOrNull(cateId));
|
||||
ps.setObject(9, toLongOrNull(userId));
|
||||
ps.executeUpdate();
|
||||
}
|
||||
} finally {
|
||||
DataSourceUtils.releaseConnection(connection, dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
private static Long toLongOrNull(String s) {
|
||||
if (s == null || s.isBlank()) return null;
|
||||
try {
|
||||
return Long.parseLong(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OSS 凭证:调 g3oss,bucket = 当前机构码
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> ossCredential() throws IOException, InterruptedException {
|
||||
String orgId = OrgContext.requireOrgId();
|
||||
String url = props.getOss().getG3ossUrl() + "/upload?orgid=" + orgId + "&bucket=" + orgId;
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
if (response.statusCode() != 200) {
|
||||
throw new BusinessException("获取 OSS 上传凭证失败: " + response.statusCode());
|
||||
}
|
||||
|
||||
return OBJECT_MAPPER.readValue(response.body(), Map.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件:查 bf_files → 删存储 → 删 DB 行
|
||||
*/
|
||||
public void delete(String subid) throws SQLException, IOException, InterruptedException {
|
||||
List<Map<String, Object>> rows = dbUtils.loadData("bf_files", "subid = " + subid, null, null);
|
||||
if (rows.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String mapfilename = (String) rows.get(0).get("mx_mapfilename");
|
||||
|
||||
// 删存储文件
|
||||
if ("aliyun-oss".equalsIgnoreCase(props.getStorageType())) {
|
||||
deleteOssFile(mapfilename);
|
||||
} else {
|
||||
deleteLocalFile(mapfilename);
|
||||
}
|
||||
|
||||
// 删 DB 行
|
||||
deleteDbRow(subid);
|
||||
}
|
||||
|
||||
private void deleteLocalFile(String mapfilename) throws IOException {
|
||||
if (mapfilename == null) return;
|
||||
// mapfilename: /api/file/static/{orgId}/{yyyy}/{MM}/{dd}/{file}
|
||||
String prefix = props.getLocal().getUrlPrefix() + "/";
|
||||
if (!mapfilename.startsWith(prefix)) return;
|
||||
String relativePath = mapfilename.substring(prefix.length());
|
||||
Path file = Path.of(props.getLocal().getStorageDir()).toAbsolutePath().normalize().resolve(relativePath);
|
||||
Files.deleteIfExists(file);
|
||||
}
|
||||
|
||||
private void deleteOssFile(String mapfilename) throws IOException, InterruptedException {
|
||||
if (mapfilename == null || mapfilename.isBlank()) {
|
||||
return;
|
||||
}
|
||||
// 从 URL 提取 objectName(bucket 直接用机构码)
|
||||
String objectName = mapfilename;
|
||||
if (objectName.contains("://")) {
|
||||
objectName = objectName.substring(objectName.indexOf("://") + 3);
|
||||
}
|
||||
// 跳过 host + bucket 两段
|
||||
int firstSlash = objectName.indexOf('/');
|
||||
if (firstSlash > 0) {
|
||||
objectName = objectName.substring(firstSlash + 1);
|
||||
int secondSlash = objectName.indexOf('/');
|
||||
if (secondSlash > 0) {
|
||||
objectName = objectName.substring(secondSlash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
String bucket = OrgContext.requireOrgId();
|
||||
String url = props.getOss().getG3ossUrl()
|
||||
+ "/delete?bucketName=" + bucket + "&objectName=" + objectName;
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
if (response.statusCode() != 200) {
|
||||
throw new BusinessException("OSS 删除文件失败: " + response.statusCode());
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteDbRow(String subid) throws SQLException {
|
||||
Connection connection = DataSourceUtils.getConnection(dataSource);
|
||||
try {
|
||||
String sql = "DELETE FROM [bf_files] WHERE [subid] = ?";
|
||||
try (PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||
statement.setLong(1, Long.parseLong(subid));
|
||||
statement.executeUpdate();
|
||||
}
|
||||
} finally {
|
||||
DataSourceUtils.releaseConnection(connection, dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
private String extension(String name) {
|
||||
if (name == null || !name.contains(".")) {
|
||||
return "";
|
||||
}
|
||||
return name.substring(name.lastIndexOf('.') + 1).toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,14 @@ fms:
|
||||
max-wait: 5000
|
||||
validation-query: SELECT 1
|
||||
test-while-idle: true
|
||||
test-on-borrow: false
|
||||
test-on-borrow: true
|
||||
test-on-return: false
|
||||
time-between-eviction-runs: 60s
|
||||
min-evictable-idle-time: 5m
|
||||
time-between-eviction-runs: 30s
|
||||
min-evictable-idle-time: 30s
|
||||
file:
|
||||
storage-type: local
|
||||
local:
|
||||
storage-dir: ./data/files
|
||||
url-prefix: /api/file/static
|
||||
oss:
|
||||
g3oss-url: http://g3oss.g3soft.cn:8082
|
||||
@@ -20,7 +20,14 @@ fms:
|
||||
max-wait: 5000
|
||||
validation-query: SELECT 1
|
||||
test-while-idle: true
|
||||
test-on-borrow: false
|
||||
test-on-borrow: true
|
||||
test-on-return: false
|
||||
time-between-eviction-runs: 60s
|
||||
min-evictable-idle-time: 5m
|
||||
time-between-eviction-runs: 30s
|
||||
min-evictable-idle-time: 30s
|
||||
file:
|
||||
storage-type: local
|
||||
local:
|
||||
storage-dir: ./data/files
|
||||
url-prefix: /api/file/static
|
||||
oss:
|
||||
g3oss-url: http://g3oss.g3soft.cn:8082
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
@@ -62,11 +62,11 @@ cd fms-api/tools/migration
|
||||
export JAVA_HOME=/path/to/jdk-21 # Linux/Mac
|
||||
set JAVA_HOME=D:\devtool\jdk\jdk-21 # Windows
|
||||
|
||||
# 编译
|
||||
javac -cp "%USERPROFILE%\.m2\repository\com\microsoft\sqlserver\mssql-jdbc\13.4.0.jre11\mssql-jdbc-13.4.0.jre11.jar" FieldNameSync.java
|
||||
# 编译(源文件含中文注释,需指定 UTF-8 编码)
|
||||
javac -encoding UTF-8 -cp "%USERPROFILE%\.m2\repository\com\microsoft\sqlserver\mssql-jdbc\13.4.0.jre11\mssql-jdbc-13.4.0.jre11.jar" FieldNameSync.java
|
||||
|
||||
# 运行(以 v_b_othercompany 为例)
|
||||
java -cp ".;%USERPROFILE%\.m2\repository\com\microsoft\sqlserver\mssql-jdbc\13.4.0.jre11\mssql-jdbc-13.4.0.jre11.jar" FieldNameSync v_b_othercompany
|
||||
# 运行(参数为 s_module.b_viewtable 的值;本例模块注册的是表名 b_port,非视图名 v_b_port)
|
||||
java -cp ".;%USERPROFILE%\.m2\repository\com\microsoft\sqlserver\mssql-jdbc\13.4.0.jre11\mssql-jdbc-13.4.0.jre11.jar" FieldNameSync b_port
|
||||
```
|
||||
|
||||
## 输出示例
|
||||
@@ -110,3 +110,4 @@ java -cp ".;%USERPROFILE%\.m2\repository\com\microsoft\sqlserver\mssql-jdbc\13.4
|
||||
| --- | --- | --- | --- |
|
||||
| `v_b_othercompany` | 2026-07-30 | 50 | 已同步 |
|
||||
| `v_b_contact` | 2026-07-30 | 36 | 已同步 |
|
||||
| `b_port` | 2026-08-01 | 13 | 已同步(`s_module.b_viewtable='b_port'` 表名,非 `v_b_port`;更新字段名 8 条,列表/编辑显示各 8 条) |
|
||||
Binary file not shown.
Reference in new issue
Block a user