20260914172820

This commit is contained in:
oneao committed 2026-09-14 17:28:20 +08:00
1 parent c31329d387
commit 549c8bd2eb
38 files changed
+3430 -502

No files matched your search

@@ -1,15 +1,37 @@
import java.sql.*;
import java.util.*;
/**
* 字段配置迁移工具(面向 V2 表结构)。
*
* 从旧库 G3HY2025.dbo.s_columnLib 同步到新库 FMS:
* 1. col_Caption → s_module_field.b_name(字段名称)
* 2. col_Visible → s_module_field_list.b_visible(列表显示,不存在则插入记录)
* 3. col_edit → s_module_field_edit.b_visible(编辑显示,不存在则插入记录)
* 1. col_Caption → s_field.b_name (字段名称)
* 2. col_Visible → s_module_schema(b_schema_type='view') 的 columns (列表列)
* 3. col_edit → s_module_schema(b_schema_type='edit') 的 children (表单字段)
*
* 注意:本工具面向 V1 表结构(s_module_field / s_module_field_list / s_module_field_edit),
* 与《FMS新系统核心表结构设计V2》的 s_field / s_module_schema 不兼容,仅作历史参考。
* 关联规则:
* s_columnLib.col_TableName = s_module.b_view_table
* s_columnLib.col_FieldName = s_field.b_field
* 两侧用 Chinese_PRC_CI_AS 比较,兼容 v_b_OtherCompany 这类大小写差异。
*
* 用法: java -cp ".;mssql-jdbc.jar" FieldNameSync <viewName>
* 列表/表单的成员资格沿用旧库语义:旧库标志为 '1' 的字段才进入对应配置,
* 其余字段(标志为 '0'、空、无记录)**直接不写入 JSON**,不写 visible:false。
* view 的列宽取 col_Width、顺序取 col_Position;edit 的顺序取 col_edit_position。
*
* 写入方式为「整份重建」:view / edit 两份 b_schema_json 完整重新生成,
* 不保留模块管理界面里手工调整的布局,已有非空行需 --force 才覆盖。
*
* JSON 结构与消费侧一致,见 fms-vue/src/components/fms-module-common/schemaRender.js。
*
* 用法:
* javac -encoding UTF-8 -cp "mssql-jdbc-13.4.0.jre11.jar" FieldNameSync.java
* java -Dstdout.encoding=UTF-8 -cp ".;mssql-jdbc-13.4.0.jre11.jar" FieldNameSync <moduleId> [oldTableName] [选项]
*
* <moduleId> s_module.b_id,例如 v_b_othercompany
* [oldTableName] 可选,覆盖旧库表/视图名;缺省用 s_module.b_view_table
* --dry-run 只报告不写库
* --skip-schema 只同步 s_field.b_name,不重建 s_module_schema
* --force 允许覆盖已存在且非空的 s_module_schema 行
*/
public class FieldNameSync {
@@ -17,251 +39,454 @@ public class FieldNameSync {
static final String USER = "sa";
static final String PASSWORD = "zhang520..";
// 同步字段名称
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)) != ''
// ---- 选项 ----
boolean dryRun = false;
boolean skipSchema = false;
boolean force = false;
String moduleId;
String oldTableOverride;
// ---- 运行期数据 ----
Connection conn;
String oldTable;
String moduleName;
String moduleType;
final List<Field> fields = new ArrayList<>();
final Map<String, OldColumn> oldColumns = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
/** s_field 行 */
static class Field {
String name;
String label;
}
/** s_columnLib 行(只取本工具用得到的列) */
static class OldColumn {
String caption;
String visible;
String edit;
Integer width; // col_Width,未配置时为 null
Integer position; // col_Position
Integer editPosition; // col_edit_position
}
// ------------------------------------------------------------------ SQL
static final String QUERY_MODULE = """
SELECT b_id, b_view_table, b_name, b_module_type
FROM dbo.s_module
WHERE b_id = ?
""";
// 同步列表显示:更新已有记录
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 QUERY_FIELDS = """
SELECT b_field, b_name
FROM dbo.s_field
WHERE b_module_id = ? AND b_canuse = 1
ORDER BY b_xh, b_field
""";
// 查询需要插入列表配置的字段
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 QUERY_OLD_COLUMNS = """
SELECT col_FieldName, col_Caption, col_Visible, col_edit,
col_Width, col_Position, col_edit_position
FROM G3HY2025.dbo.s_columnLib
WHERE col_TableName COLLATE Chinese_PRC_CI_AS = CONVERT(varchar(128), ?) COLLATE Chinese_PRC_CI_AS
ORDER BY col_FieldName
""";
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 UPDATE_FIELD_NAME = """
UPDATE dbo.s_field SET b_name = ?
WHERE b_module_id = ? AND b_field = ?
""";
// 同步编辑显示:更新已有记录
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 QUERY_SCHEMA_ROW = """
SELECT b_schema_json FROM dbo.s_module_schema
WHERE b_module_id = ? AND b_schema_type = ?
""";
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 UPDATE_SCHEMA = """
UPDATE dbo.s_module_schema
SET b_schema_json = ?, b_canuse = 1, b_updated_at = SYSDATETIME()
WHERE b_module_id = ? AND b_schema_type = ?
""";
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)
static final String INSERT_SCHEMA = """
INSERT INTO dbo.s_module_schema (b_module_id, b_schema_type, b_schema_json, b_canuse, b_updated_at)
VALUES (?, ?, ?, 1, SYSDATETIME())
""";
// 查询模块 ID
static final String QUERY_MODULE_ID = "SELECT b_id FROM dbo.s_module WHERE b_viewtable = ?";
// 查询列表/编辑配置现状
static final String QUERY_CONFIG = """
SELECT sf.b_field, sf.b_name,
sfl.b_visible AS list_visible,
sfe.b_visible AS edit_visible
FROM dbo.s_module_field sf
JOIN dbo.s_module m ON m.b_id = sf.b_module_id
LEFT JOIN dbo.s_module_field_list sfl ON sfl.b_field_id = sf.b_id
LEFT JOIN dbo.s_module_field_edit sfe ON sfe.b_field_id = sf.b_id
WHERE m.b_viewtable = ?
ORDER BY sf.b_field
""";
static long nextListId;
static long nextEditId;
// --------------------------------------------------------------- 入口
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.err.println("用法: java FieldNameSync <viewName>");
System.exit(1);
}
String viewName = args[0].trim();
if (!viewName.matches("^[A-Za-z_][A-Za-z0-9_]{0,127}$")) {
System.err.println("非法视图名: " + viewName);
System.exit(1);
}
FieldNameSync tool = new FieldNameSync();
tool.parseArgs(args);
tool.run();
}
System.out.println("连接到 fms 数据库...");
try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {
conn.setAutoCommit(false);
// 查询模块是否存在
Long moduleId = null;
try (PreparedStatement ps = conn.prepareStatement(QUERY_MODULE_ID)) {
ps.setString(1, viewName);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) moduleId = rs.getLong(1);
void parseArgs(String[] args) {
List<String> positional = new ArrayList<>();
for (String raw : args) {
String arg = raw.trim();
switch (arg.toLowerCase(Locale.ROOT)) {
case "--dry-run" -> dryRun = true;
case "--skip-schema" -> skipSchema = true;
case "--force" -> force = true;
default -> {
if (arg.startsWith("--")) {
System.err.println("未知选项: " + arg);
usage();
System.exit(1);
}
positional.add(arg);
}
}
if (moduleId == null) {
System.err.println("模块 " + viewName + " 不存在!");
}
if (positional.isEmpty()) {
usage();
System.exit(1);
}
moduleId = positional.get(0);
if (positional.size() > 1) oldTableOverride = positional.get(1);
if (positional.size() > 2) {
System.err.println("多余参数: " + positional.get(2));
usage();
System.exit(1);
}
}
static void usage() {
System.err.println("用法: java FieldNameSync <moduleId> [oldTableName] [--dry-run] [--skip-schema] [--force]");
}
void run() throws SQLException {
try (Connection c = DriverManager.getConnection(URL, USER, PASSWORD)) {
conn = c;
conn.setAutoCommit(false);
try {
loadModule();
loadFields();
loadOldColumns();
if (fields.isEmpty()) {
System.out.println("\n模块 " + moduleId + " 在 s_field 中没有启用字段,无可同步内容。");
conn.rollback();
return;
}
printSnapshot("同步前");
if (!skipSchema) {
// 写入前先校验:已有非空行且未加 --force 时整体拒绝,避免半途写入
checkSchemaGuard();
}
int renamed = syncFieldNames();
int[] viewStat = null;
int[] editStat = null;
if (!skipSchema) {
viewStat = writeSchema("view", buildViewJson());
editStat = writeSchema("edit", buildEditJson());
}
if (dryRun) {
conn.rollback();
System.out.println("\n[Dry-run] 已回滚,未写入任何数据。");
} else {
conn.commit();
System.out.println("\n=== 事务已提交 ===");
}
printSummary(renamed, viewStat, editStat);
if (!dryRun) {
// 重新读一次 s_field,同步后的快照才反映实际写入的名称
fields.clear();
loadFields();
printSnapshot("同步后");
}
} catch (Exception e) {
conn.rollback();
System.err.println("\n[错误] " + e.getMessage());
System.exit(1);
}
// 初始化 ID 生成器
try (Statement st = conn.createStatement()) {
try (ResultSet rs = st.executeQuery("SELECT ISNULL(MAX(b_id),0) FROM dbo.s_module_field_list")) {
rs.next(); nextListId = rs.getLong(1) + 1;
}
try (ResultSet rs = st.executeQuery("SELECT ISNULL(MAX(b_id),0) FROM dbo.s_module_field_edit")) {
rs.next(); nextEditId = rs.getLong(1) + 1;
}
}
// === 1. 同步前 ===
System.out.println("\n=== 同步前 ===");
printConfig(conn, viewName);
// === 2. 字段名称 ===
System.out.println("\n=== 1) 字段名称 (col_Caption → b_name) ===");
try (PreparedStatement ps = conn.prepareStatement(SYNC_NAME)) {
ps.setString(1, viewName);
System.out.println(" 更新: " + ps.executeUpdate() + " 条");
}
// === 3. 列表显示 ===
System.out.println("\n=== 2) 列表显示 (col_Visible → s_module_field_list.b_visible) ===");
try (PreparedStatement ps = conn.prepareStatement(SYNC_LIST_UPDATE)) {
ps.setString(1, viewName);
System.out.println(" 更新已有: " + ps.executeUpdate() + " 条");
}
java.util.ArrayList<long[]> listCandidates = new java.util.ArrayList<>();
try (PreparedStatement ps = conn.prepareStatement(LIST_INSERT_CANDIDATES)) {
ps.setString(1, viewName);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
listCandidates.add(new long[]{rs.getLong("field_id"), rs.getLong("module_id"), rs.getLong("visible")});
}
}
}
try (PreparedStatement ps = conn.prepareStatement(INSERT_LIST)) {
for (long[] row : listCandidates) {
ps.setLong(1, nextListId++);
ps.setLong(2, row[1]);
ps.setLong(3, row[0]);
ps.setInt(4, (int) row[2]);
ps.addBatch();
}
if (!listCandidates.isEmpty()) {
ps.executeBatch();
}
}
System.out.println(" 新增: " + listCandidates.size() + " 条");
// === 4. 编辑显示 ===
System.out.println("\n=== 3) 编辑显示 (col_edit → s_module_field_edit.b_visible) ===");
try (PreparedStatement ps = conn.prepareStatement(SYNC_EDIT_UPDATE)) {
ps.setString(1, viewName);
System.out.println(" 更新已有: " + ps.executeUpdate() + " 条");
}
java.util.ArrayList<long[]> editCandidates = new java.util.ArrayList<>();
try (PreparedStatement ps = conn.prepareStatement(EDIT_INSERT_CANDIDATES)) {
ps.setString(1, viewName);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
editCandidates.add(new long[]{rs.getLong("field_id"), rs.getLong("module_id"), rs.getLong("visible")});
}
}
}
try (PreparedStatement ps = conn.prepareStatement(INSERT_EDIT)) {
for (long[] row : editCandidates) {
ps.setLong(1, nextEditId++);
ps.setLong(2, row[1]);
ps.setLong(3, row[0]);
ps.setInt(4, (int) row[2]);
ps.addBatch();
}
if (!editCandidates.isEmpty()) {
ps.executeBatch();
}
}
System.out.println(" 新增: " + editCandidates.size() + " 条");
conn.commit();
System.out.println("\n=== 事务已提交 ===");
// === 5. 验证 ===
System.out.println("\n=== 同步后 ===");
printConfig(conn, viewName);
}
System.out.println("\n完成.");
}
static void printConfig(Connection conn, String viewName) throws SQLException {
System.out.printf(" %-30s %-16s %-8s %-8s%n", "b_field", "b_name", "list", "edit");
System.out.println(" " + "-".repeat(66));
try (PreparedStatement ps = conn.prepareStatement(QUERY_CONFIG)) {
ps.setString(1, viewName);
// ------------------------------------------------------------ 数据加载
void loadModule() throws SQLException {
String bViewTable;
try (PreparedStatement ps = conn.prepareStatement(QUERY_MODULE)) {
ps.setString(1, moduleId);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) {
throw new IllegalStateException("模块不存在: " + moduleId + "(s_module.b_id)");
}
bViewTable = trim(rs.getString("b_view_table"));
moduleName = trim(rs.getString("b_name"));
moduleType = trim(rs.getString("b_module_type"));
}
}
System.out.println("模块: " + moduleId
+ (moduleName != null ? "(" + moduleName + ")" : "")
+ " 类型: " + (moduleType != null ? moduleType : "(null)"));
if (oldTableOverride != null) {
oldTable = oldTableOverride;
System.out.println("关联旧库表: " + oldTable + "(命令行指定,覆盖 b_view_table=" + bViewTable + ")");
} else {
oldTable = bViewTable;
if (oldTable == null || oldTable.isEmpty()) {
throw new IllegalStateException(
"模块 " + moduleId + " 未配置 b_view_table,请用第二个参数显式指定旧库表/视图名");
}
System.out.println("关联旧库表: " + oldTable + "(取自 s_module.b_view_table)");
}
}
void loadFields() throws SQLException {
try (PreparedStatement ps = conn.prepareStatement(QUERY_FIELDS)) {
ps.setString(1, moduleId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String listVis = rs.getString("list_visible");
String editVis = rs.getString("edit_visible");
String listStr = listVis == null ? "--" : ("1".equals(listVis) ? "显示" : "隐藏");
String editStr = editVis == null ? "--" : ("1".equals(editVis) ? "显示" : "隐藏");
String name = rs.getString("b_name");
System.out.printf(" %-30s %-16s %-8s %-8s%n",
rs.getString("b_field"),
name != null ? name : "(null)",
listStr,
editStr);
Field f = new Field();
f.name = trim(rs.getString("b_field"));
f.label = trim(rs.getString("b_name"));
fields.add(f);
}
}
}
}
void loadOldColumns() throws SQLException {
int rows = 0;
try (PreparedStatement ps = conn.prepareStatement(QUERY_OLD_COLUMNS)) {
ps.setString(1, oldTable);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
rows++;
OldColumn col = new OldColumn();
col.caption = trim(rs.getString("col_Caption"));
col.visible = trim(rs.getString("col_Visible"));
col.edit = trim(rs.getString("col_edit"));
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);
}
}
}
long inList = countIncluded("view");
long inForm = countIncluded("edit");
System.out.println("旧库 s_columnLib: " + rows + " 行,去重字段 " + oldColumns.size() + " 个;"
+ "当前模块 " + fields.size() + " 个字段中:进列表 " + inList + " 个、进表单 " + inForm + " 个");
if (inList == 0 && inForm == 0) {
System.out.println(" [警告] 没有任何字段匹配上,请确认旧库表名是否正确(可用第二个参数显式指定)");
}
}
static Integer intOrNull(ResultSet rs, String column) throws SQLException {
int v = rs.getInt(column);
return rs.wasNull() ? null : v;
}
// ------------------------------------------------------------ 成员与顺序
/** 旧库标志为 '1' 才进入对应配置 */
static boolean flagOn(String flag) {
return "1".equals(flag);
}
/** 取模块字段在旧库里的对应行;旧库没有该字段时返回 null */
OldColumn oldOf(Field f) {
return oldColumns.get(f.name);
}
/** 按 schemaType 取出旧库要求进入配置的字段,顺序取旧库位置列 */
List<Field> includedFields(String schemaType) {
boolean view = "view".equals(schemaType);
List<Field> result = new ArrayList<>();
for (Field f : fields) {
OldColumn old = oldOf(f);
if (old == null) continue;
if (flagOn(view ? old.visible : old.edit)) result.add(f);
}
result.sort(Comparator
.comparingInt((Field f) -> positionOf(oldOf(f), view))
.thenComparing(f -> f.name));
return result;
}
static int positionOf(OldColumn old, boolean view) {
Integer p = view ? old.position : old.editPosition;
// 位置缺失的排在最后
return p == null ? Integer.MAX_VALUE : p;
}
long countIncluded(String schemaType) {
return includedFields(schemaType).size();
}
// ---------------------------------------------------------------- 步骤
int syncFieldNames() throws SQLException {
System.out.println("\n=== 1) 字段名称 (col_Caption → s_field.b_name) ===");
int updated = 0;
int missing = 0;
try (PreparedStatement ps = conn.prepareStatement(UPDATE_FIELD_NAME)) {
for (Field f : fields) {
OldColumn old = oldOf(f);
String caption = old != null ? old.caption : null;
if (caption == null || caption.isEmpty()) {
missing++;
continue;
}
if (caption.equals(f.label)) {
continue;
}
ps.setString(1, caption);
ps.setString(2, moduleId);
ps.setString(3, f.name);
updated += ps.executeUpdate();
}
}
System.out.println(" 更新: " + updated + " 条;旧库无名称、保留原值: " + missing + " 条");
return updated;
}
/** view 配置:{"schemaVersion":1,"columns":[{"field":..,"width":..}]},只含旧库 col_Visible='1' 的字段 */
String buildViewJson() {
StringBuilder sb = new StringBuilder("{\"schemaVersion\":1,\"columns\":[");
List<Field> list = includedFields("view");
for (int i = 0; i < list.size(); i++) {
Field f = list.get(i);
if (i > 0) sb.append(',');
sb.append("{\"field\":\"").append(escape(f.name)).append('"');
Integer width = oldOf(f).width;
if (width != null && width > 0) sb.append(",\"width\":").append(width);
sb.append('}');
}
return sb.append("]}").toString();
}
/** edit 配置:{"schemaVersion":1,"children":[{"field":..,"span":24}]},只含旧库 col_edit='1' 的字段 */
String buildEditJson() {
StringBuilder sb = new StringBuilder("{\"schemaVersion\":1,\"children\":[");
List<Field> list = includedFields("edit");
for (int i = 0; i < list.size(); i++) {
Field f = list.get(i);
if (i > 0) sb.append(',');
sb.append("{\"field\":\"").append(escape(f.name)).append('"');
sb.append(",\"span\":24");
sb.append('}');
}
return sb.append("]}").toString();
}
/** 字段名是 [A-Za-z0-9_],仍保留最小转义以防意外字符 */
static String escape(String s) {
return s == null ? "" : s.replace("\\", "\\\\").replace("\"", "\\\"");
}
void checkSchemaGuard() throws SQLException {
for (String type : List.of("view", "edit")) {
String existing = readSchemaRow(type);
if (existing != null && !existing.isEmpty() && !force) {
throw new IllegalStateException(
"s_module_schema 已有非空 " + type + " 配置(" + existing.length()
+ " 字符),整份重建会覆盖模块管理中手工调整的布局。确认后加 --force 重跑。");
}
}
}
String readSchemaRow(String schemaType) throws SQLException {
try (PreparedStatement ps = conn.prepareStatement(QUERY_SCHEMA_ROW)) {
ps.setString(1, moduleId);
ps.setString(2, schemaType);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) return rs.getString(1);
}
}
return null;
}
/** @return {节点数, 未进入配置的字段数, 写入方式(1=更新, 2=新增)} */
int[] writeSchema(String schemaType, String json) throws SQLException {
boolean exists = readSchemaRow(schemaType) != null;
if (exists) {
try (PreparedStatement ps = conn.prepareStatement(UPDATE_SCHEMA)) {
ps.setString(1, json);
ps.setString(2, moduleId);
ps.setString(3, schemaType);
ps.executeUpdate();
}
} else {
try (PreparedStatement ps = conn.prepareStatement(INSERT_SCHEMA)) {
ps.setString(1, moduleId);
ps.setString(2, schemaType);
ps.setString(3, json);
ps.executeUpdate();
}
}
int included = includedFields(schemaType).size();
return new int[]{included, fields.size() - included, exists ? 1 : 2};
}
// -------------------------------------------------------------- 输出
void printSummary(int renamed, int[] viewStat, int[] editStat) {
System.out.println("\n=== 摘要 ===");
System.out.println(" s_field.b_name 更新: " + renamed + " 条");
if (skipSchema) {
System.out.println(" s_module_schema: 已跳过(--skip-schema)");
return;
}
printStat("view", viewStat);
printStat("edit", editStat);
if (readSchemaRowSafe("query") == null) {
System.out.println(" 提示: 该模块尚无 query 配置行,工具不处理 query,需要时在模块管理中生成。");
}
}
static void printStat(String schemaType, int[] stat) {
if (stat == null) return;
System.out.println(" s_module_schema(" + schemaType + "): "
+ stat[0] + " 个节点,未进入配置 " + stat[1] + " 个字段,"
+ (stat[2] == 1 ? "更新已有行" : "新增行"));
}
String readSchemaRowSafe(String schemaType) {
try {
return readSchemaRow(schemaType);
} catch (SQLException e) {
return null;
}
}
void printSnapshot(String title) throws SQLException {
System.out.println("\n=== " + title + " ===");
System.out.printf(" %-24s %-22s %-22s %-10s %-10s%n",
"b_field", "s_field.b_name", "col_Caption", "进列表", "进表单");
System.out.println(" " + "-".repeat(94));
for (Field f : fields) {
OldColumn old = oldOf(f);
System.out.printf(" %-24s %-22s %-22s %-10s %-10s%n",
truncate(f.name, 23),
truncate(orNull(f.label), 21),
truncate(orNull(old != null ? old.caption : null), 21),
yesNo(old != null && flagOn(old.visible)),
yesNo(old != null && flagOn(old.edit)));
}
}
static String yesNo(boolean b) {
return b ? "是" : "否";
}
static String orNull(String s) {
return s == null ? "(null)" : s;
}
static String truncate(String s, int max) {
if (s == null) return "";
return s.length() <= max ? s : s.substring(0, max - 1) + "…";
}
static String trim(String s) {
return s == null ? null : s.trim();
}
}