This commit is contained in:
oneao committed 2026-03-22 21:49:28 +08:00
1 parent aa813c9649
commit 62550b8182
45 files changed
+12535 -566

No files matched your search

@@ -10,203 +10,203 @@ import java.util.*;
public class BatchTableDelete {
private static final ObjectMapper mapper = new ObjectMapper();
private static final ObjectMapper mapper = new ObjectMapper();
// === 入口 ===
public static Result<Map<String, Integer>> executdeletetable(String orgCode, String moduleid, String ID) throws SQLException {
boolean candelete = deletebefore(orgCode, moduleid, ID);
if (candelete) {
List<Map<String, Object>> deletetablelist = getDeletetableList(orgCode, moduleid, ID);
return deleteDatabaseOperations(orgCode, deletetablelist);
}
return Result.fail("存在依赖数据,禁止删除: table=" + moduleid + ", id=" + ID);
}
// === 删除前检查依赖 ===
public static boolean deletebefore(String orgCode, String moduleid, String ID) throws SQLException {
String sql = "SELECT b_JudgeCondition FROM s_module WHERE b_id = ?";
try (Connection conn = DruidDataSourceManager.getConnection(orgCode);
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, moduleid);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
String conditionSql = rs.getString("b_JudgeCondition");
if (conditionSql == null || conditionSql.trim().isEmpty()) {
return true; // 没配置依赖条件,默认允许删除
}
// 替换占位符
conditionSql = conditionSql.replace(":b_id", "'" + ID + "'");
System.out.println("[执行条件SQL] " + conditionSql);
try (PreparedStatement ps = conn.prepareStatement(conditionSql);
ResultSet crs = ps.executeQuery()) {
if (crs.next()) {
System.out.println("存在依赖数据,不允许删除: ID=" + ID);
return false;
} else {
System.out.println("未发现依赖数据,可以删除: ID=" + ID);
return true;
}
}
}
// === 入口 ===
public static Result<Map<String, Integer>> executdeletetable(String orgCode, String moduleid, String ID) throws SQLException {
boolean candelete = deletebefore(orgCode, moduleid, ID);
if (candelete) {
List<Map<String, Object>> deletetablelist = getDeletetableList(orgCode, moduleid, ID);
return deleteDatabaseOperations(orgCode, deletetablelist);
}
} catch (Exception e) {
throw new RuntimeException("执行 deletebefore 失败", e);
return Result.fail("存在依赖数据,禁止删除: table=" + moduleid + ", id=" + ID);
}
return false; // 默认不允许删除
}
// === 删除前检查依赖 ===
public static boolean deletebefore(String orgCode, String moduleid, String ID) throws SQLException {
String sql = "SELECT b_JudgeCondition FROM s_module WHERE b_id = ?";
// === 获取需要删除的表集合 ===
public static List<Map<String, Object>> getDeletetableList(String orgCode, String moduleid, String ID) throws SQLException {
String sqlData = "SELECT b_SaveTable FROM s_module WHERE b_id = ?";
String sql = "SELECT b_SaveTable FROM s_module WHERE b_LinkTable = ?";
try (Connection conn = DruidDataSourceManager.getConnection(orgCode)) {
String saveTable = "";
try (PreparedStatement stmtData = conn.prepareStatement(sqlData)) {
stmtData.setString(1, moduleid);
try (ResultSet rs = stmtData.executeQuery()) {
if (rs.next()) {
saveTable = rs.getString("b_SaveTable");
}
}
}
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
try (Connection conn = DruidDataSourceManager.getConnection(orgCode);
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, moduleid);
try (ResultSet rs = stmt.executeQuery()) {
List<Map<String, Object>> tablelist = getlinktablelist(rs, ID);
if (rs.next()) {
String conditionSql = rs.getString("b_JudgeCondition");
// 添加主表
Map<String, Object> map = new LinkedHashMap<>();
map.put("tableName", saveTable);
map.put("keyField", "b_id");
map.put("Fieldvalue", ID);
tablelist.add(map);
if (conditionSql == null || conditionSql.trim().isEmpty()) {
return true; // 没配置依赖条件,默认允许删除
}
return tablelist;
// 替换占位符
conditionSql = conditionSql.replace(":b_id", "'" + ID + "'");
System.out.println("[执行条件SQL] " + conditionSql);
try (PreparedStatement ps = conn.prepareStatement(conditionSql);
ResultSet crs = ps.executeQuery()) {
if (crs.next()) {
System.out.println("存在依赖数据,不允许删除: ID=" + ID);
return false;
} else {
System.out.println("未发现依赖数据,可以删除: ID=" + ID);
return true;
}
}
}
}
} catch (Exception e) {
throw new RuntimeException("执行 deletebefore 失败", e);
}
return false; // 默认不允许删除
}
// === 获取需要删除的表集合 ===
public static List<Map<String, Object>> getDeletetableList(String orgCode, String moduleid, String ID) throws SQLException {
String sqlData = "SELECT b_SaveTable FROM s_module WHERE b_id = ?";
String sql = "SELECT b_SaveTable FROM s_module WHERE b_LinkTable = ?";
try (Connection conn = DruidDataSourceManager.getConnection(orgCode)) {
String saveTable = "";
try (PreparedStatement stmtData = conn.prepareStatement(sqlData)) {
stmtData.setString(1, moduleid);
try (ResultSet rs = stmtData.executeQuery()) {
if (rs.next()) {
saveTable = rs.getString("b_SaveTable");
}
}
}
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, moduleid);
try (ResultSet rs = stmt.executeQuery()) {
List<Map<String, Object>> tablelist = getlinktablelist(rs, ID);
// 添加主表
Map<String, Object> map = new LinkedHashMap<>();
map.put("tableName", saveTable);
map.put("keyField", "b_id");
map.put("Fieldvalue", ID);
tablelist.add(map);
return tablelist;
}
} catch (Exception e) {
throw new RuntimeException("查询 s_module 失败", e);
}
} catch (Exception e) {
throw new RuntimeException("查询 s_module 失败", e);
}
} catch (Exception e) {
throw new RuntimeException("查询 s_module 失败", e);
}
}
private static List<Map<String, Object>> getlinktablelist(ResultSet rs, String ID) throws SQLException {
List<Map<String, Object>> list = new ArrayList<>();
while (rs.next()) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("tableName", rs.getString("b_SaveTable"));
map.put("keyField", "father");
map.put("Fieldvalue", ID);
list.add(map);
}
return list;
}
// === 执行批量删除 ===
public static Result<Map<String, Integer>> deleteDatabaseOperations(String orgCode, List<Map<String, Object>> tableMaps) {
Map<String, Integer> operationCounts = new LinkedHashMap<>();
operationCounts.put("total", 0);
Connection conn = null;
try {
conn = DruidDataSourceManager.getConnection(orgCode);
conn.setAutoCommit(false);
for (Map<String, Object> tablemap : tableMaps) {
String tableName = (String) tablemap.get("tableName");
String keyField = (String) tablemap.get("keyField");
String fieldValue = (String) tablemap.get("Fieldvalue");
validateIdentifier(tableName);
validateIdentifier(keyField);
int count = processDeleteOperations(conn, tableName, keyField, fieldValue);
// 每个表单独统计
operationCounts.merge(tableName, count, Integer::sum);
// 总数统计
operationCounts.merge("total", count, Integer::sum);
System.out.println("表 [" + tableName + "] 删除记录数: " + count);
private static List<Map<String, Object>> getlinktablelist(ResultSet rs, String ID) throws SQLException {
List<Map<String, Object>> list = new ArrayList<>();
while (rs.next()) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("tableName", rs.getString("b_SaveTable"));
map.put("keyField", "father");
map.put("Fieldvalue", ID);
list.add(map);
}
conn.commit();
System.out.println("批量操作成功!操作统计: " + operationCounts);
return Result.ok("批量操作成功", operationCounts);
} catch (Exception e) {
rollbackTransaction(conn);
System.err.println("批量操作失败: " + e.getMessage());
return Result.fail("批量操作失败: " + e.getMessage());
} finally {
closeConnection(conn);
}
}
// === 删除逻辑 ===
private static int processDeleteOperations(Connection conn, String tableName, String keyField, String fieldValue) throws SQLException {
return deleteRecord(conn, tableName, keyField, fieldValue);
}
private static int deleteRecord(Connection conn, String tableName, String pkField, String pkFieldvalue) throws SQLException {
if (pkFieldvalue == null) {
throw new IllegalArgumentException("缺少主键字段: " + pkField + " 值为空");
return list;
}
String sql = getDeleteSql(tableName, pkField);
System.out.println("[SQL-DELETE] " + sql);
System.out.println("[PARAMS] " + pkFieldvalue);
// === 执行批量删除 ===
public static Result<Map<String, Integer>> deleteDatabaseOperations(String orgCode, List<Map<String, Object>> tableMaps) {
Map<String, Integer> operationCounts = new LinkedHashMap<>();
operationCounts.put("total", 0);
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, pkFieldvalue);
int affected = ps.executeUpdate();
if (affected == 0) {
System.out.println("未找到要删除的记录: " + pkFieldvalue);
}
return affected;
}
}
// === 辅助方法 ===
private static void validateIdentifier(String identifier) {
if (!identifier.matches("^[a-zA-Z0-9_]+$")) {
throw new IllegalArgumentException("非法的表名或字段名: " + identifier);
}
}
private static void rollbackTransaction(Connection conn) {
if (conn != null) {
Connection conn = null;
try {
conn.rollback();
} catch (SQLException ex) {
System.err.println("回滚事务时出错: " + ex.getMessage());
conn = DruidDataSourceManager.getConnection(orgCode);
conn.setAutoCommit(false);
for (Map<String, Object> tablemap : tableMaps) {
String tableName = (String) tablemap.get("tableName");
String keyField = (String) tablemap.get("keyField");
String fieldValue = (String) tablemap.get("Fieldvalue");
validateIdentifier(tableName);
validateIdentifier(keyField);
int count = processDeleteOperations(conn, tableName, keyField, fieldValue);
// 每个表单独统计
operationCounts.merge(tableName, count, Integer::sum);
// 总数统计
operationCounts.merge("total", count, Integer::sum);
System.out.println("表 [" + tableName + "] 删除记录数: " + count);
}
conn.commit();
System.out.println("批量操作成功!操作统计: " + operationCounts);
return Result.ok("批量操作成功", operationCounts);
} catch (Exception e) {
rollbackTransaction(conn);
System.err.println("批量操作失败: " + e.getMessage());
return Result.fail("批量操作失败: " + e.getMessage());
} finally {
closeConnection(conn);
}
}
}
private static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
System.err.println("关闭数据库连接时出错: " + e.getMessage());
// === 删除逻辑 ===
private static int processDeleteOperations(Connection conn, String tableName, String keyField, String fieldValue) throws SQLException {
return deleteRecord(conn, tableName, keyField, fieldValue);
}
private static int deleteRecord(Connection conn, String tableName, String pkField, String pkFieldvalue) throws SQLException {
if (pkFieldvalue == null) {
throw new IllegalArgumentException("缺少主键字段: " + pkField + " 值为空");
}
String sql = getDeleteSql(tableName, pkField);
System.out.println("[SQL-DELETE] " + sql);
System.out.println("[PARAMS] " + pkFieldvalue);
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, pkFieldvalue);
int affected = ps.executeUpdate();
if (affected == 0) {
System.out.println("未找到要删除的记录: " + pkFieldvalue);
}
return affected;
}
}
}
public static String getDeleteSql(String tableName, String pkName) {
return "DELETE FROM " + tableName + " WHERE " + pkName + " = ?";
}
// === 辅助方法 ===
private static void validateIdentifier(String identifier) {
if (!identifier.matches("^[a-zA-Z0-9_]+$")) {
throw new IllegalArgumentException("非法的表名或字段名: " + identifier);
}
}
private static void rollbackTransaction(Connection conn) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
System.err.println("回滚事务时出错: " + ex.getMessage());
}
}
}
private static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
System.err.println("关闭数据库连接时出错: " + e.getMessage());
}
}
}
public static String getDeleteSql(String tableName, String pkName) {
return "DELETE FROM " + tableName + " WHERE " + pkName + " = ?";
}
}
@@ -1,4 +1,4 @@
url=jdbc:sqlserver://192.168.1.189:1433;databaseName=G3HY2025
url=jdbc:sqlserver://118.89.70.199:1433;databaseName=G3BoxOCR
username=sa
password=g3soft
password=zhang520..
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
-2
View File
@@ -31,7 +31,6 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ShJdDrawer: typeof import('./src/components/sh/shJdDrawer.vue')['default']
ShProgressDrawer: typeof import('./src/components/sh/shProgressDrawer.vue')['default']
TableDialog: typeof import('./src/components/TableDialog.vue')['default']
TableDialogSingleQuery: typeof import('./src/components/TableDialogSingleQuery.vue')['default']
ToshDialog: typeof import('./src/components/sendsh/toshDialog.vue')['default']
@@ -62,7 +61,6 @@ declare global {
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
const ShJdDrawer: typeof import('./src/components/sh/shJdDrawer.vue')['default']
const ShProgressDrawer: typeof import('./src/components/sh/shProgressDrawer.vue')['default']
const TableDialog: typeof import('./src/components/TableDialog.vue')['default']
const TableDialogSingleQuery: typeof import('./src/components/TableDialogSingleQuery.vue')['default']
const ToshDialog: typeof import('./src/components/sendsh/toshDialog.vue')['default']
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -4,8 +4,8 @@ import axios from 'axios'
import router from '@/router/index'
const instance = axios.create({
// baseURL: 'http://localhost:8089/api', // 后端接口地址
baseURL: 'http://192.168.1.137:8089/api', // 后端接口地址
baseURL: 'http://localhost:8089/api', // 后端接口地址
// baseURL: 'http://192.168.1.137:8089/api', // 后端接口地址
// baseURL: 'http://192.168.1.176:8089/api',
// baseURL: '/api', // 后端接口地址
timeout: 30000,
@@ -1,19 +1,6 @@
<template>
<el-dialog
v-bind="$attrs"
title="Sql预览"
width="1000px"
class="dialog"
@open="initData"
>
<div class="sql-preview">
{{ sqlStr }}
</div>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
data: {
type: null,
@@ -28,27 +15,28 @@ const props = defineProps({
const sqlStr = ref('')
function initData() {
if (!props.viewtable) return
if (!props.viewtable)
return
const vrows = props.data || []
const sqlArr = []
// 删除语句
const deleteSql = `DELETE FROM s_columnlib WHERE col_TableName='${props.viewtable}';`
const deleteSql = `DELETE FROM s_columnLib WHERE col_TableName='${props.viewtable}';`
sqlArr.push(deleteSql)
// 插入语句
vrows.forEach((row) => {
const insertSql =
'INSERT INTO s_columnlib(col_TableName,col_FieldName,col_Caption,col_Width,col_Visible,col_Position,' +
'col_ShowSummary,col_BandIndex,col_AllowNull,col_AllowRepeat,col_DefaultValue,col_ReadOnly,col_Color,' +
'col_CanSearch,col_SearchOrder,col_NeedReserve,col_sorted,col_DisplayFormat,col_type,col_datatype,col_foot)'
const insertSql
= 'INSERT INTO s_columnLib(col_TableName,col_FieldName,col_Caption,col_Width,col_Visible,col_Position,'
+ 'col_ShowSummary,col_BandIndex,col_AllowNull,col_AllowRepeat,col_DefaultValue,col_ReadOnly,col_Color,'
+ 'col_CanSearch,col_SearchOrder,col_NeedReserve,col_sorted,col_DisplayFormat,col_type,col_datatype,col_foot)'
const valueSql =
`VALUES('${props.viewtable}', '${row.col_FieldName}', '${row.col_Caption}', '${row.col_Width}', '${row.col_Visible}', '${row.col_Position}', ` +
`'${row.col_ShowSummary}', '${row.col_BandIndex}', '${row.col_AllowNull}', '${row.col_AllowRepeat}', '${row.col_DefaultValue}', '${row.col_ReadOnly}', '${row.col_Color}', ` +
`'${row.col_CanSearch}', '${row.col_SearchOrder}', '${row.col_NeedReserve}', '${row.col_sorted}', '${row.col_DisplayFormat}', '${row.col_type}', '${row.col_datatype}', '${row.col_foot}');`
const valueSql
= `VALUES('${props.viewtable}', '${row.col_FieldName}', '${row.col_Caption}', '${row.col_Width}', '${row.col_Visible}', '${row.col_Position}', `
+ `'${row.col_ShowSummary}', '${row.col_BandIndex}', '${row.col_AllowNull}', '${row.col_AllowRepeat}', '${row.col_DefaultValue}', '${row.col_ReadOnly}', '${row.col_Color}', `
+ `'${row.col_CanSearch}', '${row.col_SearchOrder}', '${row.col_NeedReserve}', '${row.col_sorted}', '${row.col_DisplayFormat}', '${row.col_type}', '${row.col_datatype}', '${row.col_foot}');`
sqlArr.push(insertSql)
sqlArr.push(valueSql)
@@ -59,6 +47,20 @@ function initData() {
}
</script>
<template>
<el-dialog
v-bind="$attrs"
title="Sql预览"
width="1000px"
class="dialog"
@open="initData"
>
<div class="sql-preview">
{{ sqlStr }}
</div>
</el-dialog>
</template>
<style scoped>
.dialog-content {
display: flex;
@@ -1,3 +1,129 @@
<script setup>
import { ElMessage } from 'element-plus'
import { reactive, ref, watch } from 'vue'
import axios from '@/utils/axios'
const props = defineProps({
modelValue: Boolean,
data: {
type: null,
required: true,
},
})
const emit = defineEmits(['update:modelValue'])
const loading = reactive({
table: true,
save: false,
})
const visible = ref(props.modelValue)
watch(
() => props.modelValue,
v => (visible.value = v),
)
watch(visible, v => emit('update:modelValue', v))
const tableData = ref([])
const selectedRows = ref([])
function handleSelectionChange(rows) {
selectedRows.value = rows
}
async function initData() {
const fieldName = props.data?.col_FieldName
if (!fieldName)
return
loading.table = true
const params = {
tableName: 's_columnLib',
whereClause: `col_FieldName = '${fieldName}'`,
}
try {
const response = await axios.get('/pagdetail', { params })
if (response.data?.success) {
tableData.value = (response.data.data?.records || []).filter(
item => item.col_TableName !== props.data.col_TableName,
)
console.log(tableData.value)
}
else {
tableData.value = []
ElMessage.error(response.data?.message || '加载列信息失败')
}
}
catch (err) {
tableData.value = []
ElMessage.error(err || '加载列信息失败')
}
finally {
loading.table = false
}
}
function close() {
tableData.value = []
selectedRows.value = []
visible.value = false
}
async function handleSave() {
if (selectedRows.value.length === 0) {
close()
return
}
loading.save = true
const caption = props.data?.col_Caption || ''
// 构建更新数据
const updates = selectedRows.value.map(row => ({
col_TableName: row.col_TableName,
col_FieldName: row.col_FieldName,
col_Caption: caption,
}))
const requestData = [
{
tableName: 's_columnLib',
keyFields: ['col_TableName', 'col_FieldName'], // 双主键
inserts: [],
updates, // 放入更新数组
deletes: [],
},
]
try {
const response = await axios.post('/saveobjectV3', requestData, {
headers: { 'Content-Type': 'application/json' },
})
if (response.data?.success) {
ElMessage.success('保存成功')
close()
}
else {
throw new Error(response.data?.message || '保存失败')
}
}
catch (err) {
console.error('保存出错:', err)
ElMessage.error(err.message || '保存失败')
}
finally {
loading.save = false
}
}
</script>
<template>
<el-dialog
v-bind="$attrs"
@@ -23,132 +149,17 @@
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" :loading="loading.save" @click="handleSave">确认</el-button>
<el-button @click="close">
取消
</el-button>
<el-button type="primary" :loading="loading.save" @click="handleSave">
确认
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, watch, reactive } from 'vue'
import axios from '@/utils/axios'
import { ElMessage } from 'element-plus'
const props = defineProps({
modelValue: Boolean,
data: {
type: null,
required: true,
},
})
const loading = reactive({
table: true,
save: false,
})
const emit = defineEmits(['update:modelValue'])
const visible = ref(props.modelValue)
watch(
() => props.modelValue,
(v) => (visible.value = v),
)
watch(visible, (v) => emit('update:modelValue', v))
const tableData = ref([])
const selectedRows = ref([])
const handleSelectionChange = (rows) => {
selectedRows.value = rows
}
async function initData() {
const fieldName = props.data?.col_FieldName
if (!fieldName) return
loading.table = true
const params = {
tableName: 's_columnLib',
whereClause: `col_FieldName = '${fieldName}'`,
}
try {
const response = await axios.get('/pagdetail', { params })
if (response.data?.success) {
tableData.value = (response.data.data?.records || []).filter(
(item) => item.col_TableName !== props.data.col_TableName,
)
console.log(tableData.value)
} else {
tableData.value = []
ElMessage.error(response.data?.message || '加载列信息失败')
}
} catch (err) {
tableData.value = []
ElMessage.error(err || '加载列信息失败')
} finally {
loading.table = false
}
}
const close = () => {
tableData.value = []
selectedRows.value = []
visible.value = false
}
const handleSave = async () => {
if (selectedRows.value.length === 0) {
close()
return
}
loading.save = true
const caption = props.data?.col_Caption || ''
// 构建更新数据
const updates = selectedRows.value.map((row) => ({
col_TableName: row.col_TableName,
col_FieldName: row.col_FieldName,
col_Caption: caption,
}))
const requestData = [
{
tableName: 's_columnLib',
keyFields: ['col_TableName', 'col_FieldName'], // 双主键
inserts: [],
updates, // 放入更新数组
deletes: [],
},
]
try {
const response = await axios.post('/saveobjectV3', requestData, {
headers: { 'Content-Type': 'application/json' },
})
if (response.data?.success) {
ElMessage.success('保存成功')
close()
} else {
throw new Error(response.data?.message || '保存失败')
}
} catch (err) {
console.error('保存出错:', err)
ElMessage.error(err.message || '保存失败')
} finally {
loading.save = false
}
}
</script>
<style scoped>
.dialog-content {
display: flex;