diff --git a/code/container-ocr/ocr-springboot/src/main/java/cn/g3soft/config/datasource/DataSourceManager.java b/code/container-ocr/ocr-springboot/src/main/java/cn/g3soft/config/datasource/DataSourceManager.java index 51a8dea1..aa9eaae6 100644 --- a/code/container-ocr/ocr-springboot/src/main/java/cn/g3soft/config/datasource/DataSourceManager.java +++ b/code/container-ocr/ocr-springboot/src/main/java/cn/g3soft/config/datasource/DataSourceManager.java @@ -13,6 +13,7 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; public class DataSourceManager extends AbstractRoutingDataSource { + private static final String CONFIG_PATH = "dbconfigs/"; private static final Map dataSources = new ConcurrentHashMap<>(); @@ -26,10 +27,16 @@ public class DataSourceManager extends AbstractRoutingDataSource { return DataSourceContextHolder.getDataSourceKey(); } + /** + * 获取连接(带异常保护) + */ public static Connection getConnection(String orgCode) throws Exception { - DataSource dataSource = getOrCreateDataSource(orgCode); - - return dataSource.getConnection(); + try { + DataSource dataSource = getOrCreateDataSource(orgCode); + return dataSource.getConnection(); + } catch (Exception e) { + throw new RuntimeException("获取数据库连接失败: " + orgCode, e); + } } /** @@ -49,9 +56,21 @@ public class DataSourceManager extends AbstractRoutingDataSource { return ds; } + // 创建数据源 ds = createDataSource(orgCode); - dataSources.put(orgCode, ds); + // ===== 关键:先验证连接,防止缓存坏数据源 ===== + try (Connection conn = ds.getConnection()) { + // 成功才缓存 + dataSources.put(orgCode, ds); + } catch (Exception e) { + if (ds instanceof DruidDataSource) { + ((DruidDataSource) ds).close(); + } + throw new RuntimeException("数据库连接失败: " + orgCode, e); + } + + // 刷新 routing datasource refresh(); return ds; @@ -62,14 +81,13 @@ public class DataSourceManager extends AbstractRoutingDataSource { * 刷新 routing datasource */ private static void refresh() { - DataSourceManager routing = SpringUtils.getBean(DataSourceManager.class); routing.setTargetDataSources(new ConcurrentHashMap<>(dataSources)); routing.afterPropertiesSet(); } /** - * 创建数据源 + * 创建数据源(已优化:防止无限重连/卡死) */ private static DataSource createDataSource(String orgCode) throws Exception { @@ -93,11 +111,23 @@ public class DataSourceManager extends AbstractRoutingDataSource { ds.setPassword(p.getProperty("password")); ds.setDriverClassName(p.getProperty("driver")); - ds.setInitialSize(2); - ds.setMaxActive(20); - ds.setMinIdle(2); - ds.setValidationQuery("SELECT 1"); + // ===== 基础连接池配置 ===== + ds.setInitialSize(1); + ds.setMaxActive(10); + ds.setMinIdle(1); + // ===== 核心:防止卡死 / 无限重试 ===== + ds.setMaxWait(3000); // 获取连接最大等待3秒 + ds.setBreakAfterAcquireFailure(true); // 获取失败直接抛异常 + ds.setConnectionErrorRetryAttempts(0); // 不重试 + ds.setFailFast(true); // 初始化时检测连接 + + // ===== 连接校验 ===== + ds.setValidationQuery("SELECT 1"); + ds.setTestOnBorrow(true); + ds.setTestWhileIdle(false); + + // 初始化(此时若连接失败会快速抛异常) ds.init(); return ds; diff --git a/code/container-ocr/ocr-springboot/src/main/resources/application.yml b/code/container-ocr/ocr-springboot/src/main/resources/application.yml index d7810e87..72134fc3 100644 --- a/code/container-ocr/ocr-springboot/src/main/resources/application.yml +++ b/code/container-ocr/ocr-springboot/src/main/resources/application.yml @@ -22,8 +22,8 @@ file: base-dir: D:/data/file static-path: /static/file - server-url: http://192.168.1.137:80/api - +# server-url: http://192.168.1.137:80/api + server-url: http://ser369.g3soft.cn:80/api common-dir: common container-dir: container temp-dir: temp \ No newline at end of file diff --git a/code/container-ocr/ocr-springboot/src/main/resources/dbconfigs/g3hd.properties b/code/container-ocr/ocr-springboot/src/main/resources/dbconfigs/g3hd.properties index 6aa855da..05bead7b 100644 --- a/code/container-ocr/ocr-springboot/src/main/resources/dbconfigs/g3hd.properties +++ b/code/container-ocr/ocr-springboot/src/main/resources/dbconfigs/g3hd.properties @@ -1,10 +1,10 @@ -url=jdbc:sqlserver://118.89.70.199:1433;databaseName=G3BoxOCR +#url=jdbc:sqlserver://118.89.70.199:1433;databaseName=G3BoxOCR +#username=sa +#password=zhang520.. +#driver=com.microsoft.sqlserver.jdbc.SQLServerDriver + +url=jdbc:sqlserver://127.0.0.1:1433;databaseName=G3ContainerOCR username=sa -password=zhang520.. +password=123456@aaa driver=com.microsoft.sqlserver.jdbc.SQLServerDriver -# url=jdbc:sqlserver://127.0.0.1:1433;databaseName=G3BoxOCR -# username=sa -# password=123456@aaa -# driver=com.microsoft.sqlserver.jdbc.SQLServerDriver - diff --git a/code/container-ocr/ocr-vue/.env b/code/container-ocr/ocr-vue/.env index 4da995fd..f3df623a 100644 --- a/code/container-ocr/ocr-vue/.env +++ b/code/container-ocr/ocr-vue/.env @@ -10,7 +10,7 @@ PUBLIC_SERVER_PORT=8080 # API # 后端 API 基础地址 -# PUBLIC_API_BASE_URL=http://ser369.g3soft.cn:80/api -PUBLIC_API_BASE_URL=http://192.168.5.6:80/api +PUBLIC_API_BASE_URL=http://ser369.g3soft.cn:80/api +# PUBLIC_API_BASE_URL=http://192.168.1.137:80/api PUBLIC_ALIYUN_BUCKET = g3hd diff --git a/code/container-ocr/ocr-vue/components.d.ts b/code/container-ocr/ocr-vue/components.d.ts index 0882878f..52fa9721 100644 --- a/code/container-ocr/ocr-vue/components.d.ts +++ b/code/container-ocr/ocr-vue/components.d.ts @@ -18,6 +18,7 @@ declare module 'vue' { ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDialog: typeof import('element-plus/es')['ElDialog'] ElDivider: typeof import('element-plus/es')['ElDivider'] + ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] @@ -27,15 +28,23 @@ declare module 'vue' { ElInput: typeof import('element-plus/es')['ElInput'] ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] + ElOption: typeof import('element-plus/es')['ElOption'] ElPagination: typeof import('element-plus/es')['ElPagination'] ElPopover: typeof import('element-plus/es')['ElPopover'] ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElResult: typeof import('element-plus/es')['ElResult'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] + ElSelect: typeof import('element-plus/es')['ElSelect'] ElSplitter: typeof import('element-plus/es')['ElSplitter'] ElSplitterPanel: typeof import('element-plus/es')['ElSplitterPanel'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] + ElSwitch: typeof import('element-plus/es')['ElSwitch'] + ElTable: typeof import('element-plus/es')['ElTable'] + ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTabPane: typeof import('element-plus/es')['ElTabPane'] + ElTabs: typeof import('element-plus/es')['ElTabs'] + ElText: typeof import('element-plus/es')['ElText'] ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTree: typeof import('element-plus/es')['ElTree'] G3Column: typeof import('./src/components/g3-table/g3-column.vue')['default'] diff --git a/code/container-ocr/ocr-vue/src/components/g3-container-file/index.vue b/code/container-ocr/ocr-vue/src/components/g3-container-file/index.vue index af963801..df3c7eb5 100644 --- a/code/container-ocr/ocr-vue/src/components/g3-container-file/index.vue +++ b/code/container-ocr/ocr-vue/src/components/g3-container-file/index.vue @@ -26,8 +26,8 @@ import { formatFileSize, getAliyunFileBlob, getFileExtension, - uploadFile, buildPublicUrl, + extractFilePath, } from "@/utils/file"; import { insertFileApi, @@ -150,7 +150,7 @@ async function handleConfirmUpdate() { return; } - updateLoading.value = true; + // updateLoading.value = true; const requestData = [ { @@ -162,20 +162,60 @@ async function handleConfirmUpdate() { subid: updateFile.value.subid, mx_filename: updateFile.value.mx_filename, mx_bz: updateFile.value.mx_bz, + mx_cate_id: updateFile.value.mx_cate_id, }, ], deletes: [], }, ]; + // 检查是否设置了箱门照 + if (updateFile.value.mx_cate_id === "0") { + requestData[0].updates[0].mx_xh = "0"; + + // 检查数据库表其它是否有文件已经设置了箱门照 + const searchCondition = `father = '${props.father}' AND mx_cate_id = '0' AND subid != '${updateFile.value.subid}'`; + const res = await loadDataApi("bf_file", searchCondition, "mx_xh", ["subid", "mx_xh"]); + + if (res.success && res.data.length > 0) { + requestData.push({ + tableName: "bf_file", + keyField: "subid", + inserts: [], + updates: [ + { + subid: res.data[0].subid, + mx_cate_id: "1", + mx_xh: updateFile.value.mx_xh, + }, + ], + deletes: [], + }); + + requestData.push({ + tableName: "b_container", + keyField: "b_id", + inserts: [], + updates: [ + { + b_id: props.father, + b_container_img: extractFilePath(updateFile.value.mx_mapfilename), + }, + ], + deletes: [], + }); + } + } + try { const response = await saveObjectApi(requestData); if (response.success) { - ElMessage.success("文件名更新成功"); - updateFileName(updateFile.value); + ElMessage.success("更新成功"); showUpdateDialog.value = false; + + loadFiles() } } catch (error) { ElMessage.error("更新文件时发生错误"); @@ -247,7 +287,7 @@ async function loadFiles() { } try { - const res = await loadDataApi("bf_file", searchCondition, "mx_xh"); + const res = await loadDataApi("bf_file", searchCondition, "mx_cate_id,mx_xh"); if (res.success) { let datas = res.data.map((item) => { @@ -1065,6 +1105,10 @@ function handleTreeNodeClick(data) {
备注:
+ diff --git a/code/container-ocr/ocr-vue/src/views/container/update-dialog.vue b/code/container-ocr/ocr-vue/src/views/container/update-dialog.vue index b9f3de5d..fce2ee94 100644 --- a/code/container-ocr/ocr-vue/src/views/container/update-dialog.vue +++ b/code/container-ocr/ocr-vue/src/views/container/update-dialog.vue @@ -1,4 +1,7 @@