Files
Sdf1_login/txt/DatabaseManager.txt
T

1407 lines
49 KiB
Plaintext

package Sdf1_login;
import java.io.File;
import java.sql.*;
import java.util.*;
import java.util.logging.Logger;
public class DatabaseManager {
private Connection db;
private final File dataFolder;
private final Logger logger;
public DatabaseManager(File dataFolder) {
this.dataFolder = dataFolder;
this.logger = Logger.getLogger("Sdf1_login");
}
// ==================== 初始化 ====================
public void init() {
try {
Class.forName("org.sqlite.JDBC");
File dbFile = new File(dataFolder,
"login.db");
db = DriverManager.getConnection(
"jdbc:sqlite:"
+ dbFile.getAbsolutePath());
Statement st = db.createStatement();
st.execute("PRAGMA journal_mode=WAL");
// 用户表
st.execute("CREATE TABLE IF NOT EXISTS "
+ "users ("
+ "player_name TEXT PRIMARY KEY,"
+ "password_hash TEXT NOT NULL,"
+ "password_salt TEXT NOT NULL,"
+ "email TEXT DEFAULT '',"
+ "register_time INTEGER DEFAULT 0,"
+ "last_login_time INTEGER DEFAULT 0,"
+ "total_online_time INTEGER DEFAULT 0,"
+ "last_online_check INTEGER DEFAULT 0,"
+ "is_logged_in INTEGER DEFAULT 0,"
+ "blocks_broken INTEGER DEFAULT 0,"
+ "blocks_placed INTEGER DEFAULT 0,"
+ "gift_stage INTEGER DEFAULT 0,"
+ "gift_claimed TEXT DEFAULT '',"
+ "invite_code TEXT DEFAULT '',"
+ "invited_by TEXT DEFAULT '',"
+ "monthly_invite_count INTEGER DEFAULT 0,"
+ "invite_month TEXT DEFAULT '',"
+ "points INTEGER DEFAULT 0,"
+ "checkin_streak INTEGER DEFAULT 0,"
+ "last_checkin_date TEXT DEFAULT '',"
+ "total_checkin_days INTEGER DEFAULT 0,"
+ "temp_password TEXT DEFAULT '',"
+ "temp_pw_expire INTEGER DEFAULT 0,"
+ "temp_pw_used INTEGER DEFAULT 0,"
+ "ip_address TEXT DEFAULT '',"
+ "tasks_completed TEXT DEFAULT '',"
+ "premium_uuid TEXT DEFAULT '',"
+ "register_ip TEXT DEFAULT '',"
+ "register_type TEXT DEFAULT 'manual'"
+ ")");
// 安全添加缺失列
safeAdd(st, "tasks_completed",
"TEXT DEFAULT ''");
safeAdd(st, "temp_password",
"TEXT DEFAULT ''");
safeAdd(st, "temp_pw_expire",
"INTEGER DEFAULT 0");
safeAdd(st, "temp_pw_used",
"INTEGER DEFAULT 0");
safeAdd(st, "ip_address",
"TEXT DEFAULT ''");
safeAdd(st, "premium_uuid",
"TEXT DEFAULT ''");
safeAdd(st, "register_ip",
"TEXT DEFAULT ''");
safeAdd(st, "register_type",
"TEXT DEFAULT 'manual'");
// 在 init 方法的 try 中添加
// 如果表存在但没有save_time列,添加它
try {
st.execute("ALTER TABLE "
+ "inventory_backups "
+ "ADD COLUMN save_time "
+ "INTEGER DEFAULT 0");
} catch (SQLException ignored) {
// 列已存在
}
// 背包备份表
st.execute("CREATE TABLE IF NOT EXISTS "
+ "inventory_backups ("
+ "player_name TEXT PRIMARY KEY,"
+ "inventory_data TEXT DEFAULT '',"
+ "armor_data TEXT DEFAULT '',"
+ "extra_data TEXT DEFAULT '',"
+ "player_level INTEGER DEFAULT 0,"
+ "player_exp REAL DEFAULT 0.0)");
// 确保 inventory_backups 表结构正确
st.execute("CREATE TABLE IF NOT EXISTS "
+ "inventory_backups ("
+ "id INTEGER PRIMARY KEY "
+ "AUTOINCREMENT,"
+ "player_name TEXT NOT NULL,"
+ "contents_b64 TEXT,"
+ "armor_b64 TEXT,"
+ "extra_b64 TEXT,"
+ "level INTEGER DEFAULT 0,"
+ "experience REAL DEFAULT 0,"
+ "save_time INTEGER DEFAULT 0"
+ ")");
// 安全报警表
st.execute("CREATE TABLE IF NOT EXISTS "
+ "security_alerts ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "player_name TEXT NOT NULL,"
+ "alert_ip TEXT NOT NULL,"
+ "alert_time INTEGER NOT NULL,"
+ "alert_date TEXT NOT NULL,"
+ "notified INTEGER DEFAULT 0,"
+ "notified_time INTEGER DEFAULT 0)");
// 工单表
st.execute("CREATE TABLE IF NOT EXISTS "
+ "tickets ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "type TEXT NOT NULL,"
+ "status TEXT DEFAULT 'pending',"
+ "priority TEXT DEFAULT 'normal',"
+ "requester TEXT NOT NULL,"
+ "assigned_to TEXT DEFAULT '',"
+ "title TEXT DEFAULT '',"
+ "description TEXT DEFAULT '',"
+ "reward_amount INTEGER DEFAULT 0,"
+ "score INTEGER DEFAULT 0,"
+ "target_player TEXT DEFAULT '',"
+ "create_time INTEGER NOT NULL,"
+ "update_time INTEGER DEFAULT 0,"
+ "complete_time INTEGER DEFAULT 0,"
+ "admin_confirmed INTEGER DEFAULT 0,"
+ "reject_reason TEXT DEFAULT ''"
+ ")");
// 工单回复表
st.execute("CREATE TABLE IF NOT EXISTS "
+ "ticket_replies ("
+ "id INTEGER PRIMARY KEY "
+ "AUTOINCREMENT,"
+ "ticket_id INTEGER NOT NULL,"
+ "sender TEXT NOT NULL,"
+ "message TEXT NOT NULL,"
+ "create_time INTEGER NOT NULL"
+ ")");
// 服务商表
st.execute("CREATE TABLE IF NOT EXISTS "
+ "service_providers ("
+ "player_name TEXT PRIMARY KEY,"
+ "role TEXT DEFAULT 'waiter',"
+ "active INTEGER DEFAULT 1,"
+ "join_time INTEGER DEFAULT 0"
+ ")");
// 安全迁移 inventory_backups 表
// 不删除旧数据,只补缺失列
try {
st.execute("ALTER TABLE "
+ "inventory_backups "
+ "ADD COLUMN "
+ "save_time INTEGER "
+ "DEFAULT 0");
} catch (SQLException ignored) {
}
try {
st.execute("ALTER TABLE "
+ "inventory_backups "
+ "ADD COLUMN "
+ "level INTEGER "
+ "DEFAULT 0");
} catch (SQLException ignored) {
}
try {
st.execute("ALTER TABLE "
+ "inventory_backups "
+ "ADD COLUMN "
+ "experience REAL "
+ "DEFAULT 0");
} catch (SQLException ignored) {
}
try {
st.execute("ALTER TABLE "
+ "inventory_backups "
+ "ADD COLUMN "
+ "armor_b64 TEXT "
+ "DEFAULT ''");
} catch (SQLException ignored) {
}
try {
st.execute("ALTER TABLE "
+ "inventory_backups "
+ "ADD COLUMN "
+ "extra_b64 TEXT "
+ "DEFAULT ''");
} catch (SQLException ignored) {
}
try {
st.execute("ALTER TABLE "
+ "inventory_backups "
+ "ADD COLUMN "
+ "contents_b64 TEXT "
+ "DEFAULT ''");
} catch (SQLException ignored) {
}
st.close();
logger.info("[Sdf1_login] 数据库初始化完成");
} catch (Exception e) {
throw new RuntimeException(
"[Sdf1_login] DB初始化失败: "
+ e.getMessage(), e);
}
}
private void safeAdd(Statement st,
String col, String def) {
try {
st.executeUpdate("ALTER TABLE users "
+ "ADD COLUMN " + col + " " + def);
} catch (SQLException ignored) {
}
}
public void close() {
try {
if (db != null && !db.isClosed())
db.close();
} catch (Exception ignored) {
}
}
// ==================== 用户操作 ====================
public boolean userExists(String name) {
try {
PreparedStatement ps = db.prepareStatement(
"SELECT 1 FROM users "
+ "WHERE player_name=?");
ps.setString(1, name);
boolean r = ps.executeQuery().next();
ps.close();
return r;
} catch (SQLException e) {
return false;
}
}
public void createUser(String name, String hash,
String salt) {
try {
PreparedStatement ps = db.prepareStatement(
"INSERT INTO users "
+ "(player_name, "
+ "password_hash, "
+ "password_salt, "
+ "register_time) "
+ "VALUES (?,?,?,?)");
ps.setString(1, name);
ps.setString(2, hash);
ps.setString(3, salt);
ps.setLong(4,
System.currentTimeMillis());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// ========== 临时密码管理 ==========
public void clearTempPassword(String name) {
setField(name, "temp_password", null);
setField(name, "temp_pw_expire", 0);
setField(name, "temp_pw_used", 1);
}
public void clearAllTempPasswords() {
try {
Statement st = db.createStatement();
st.executeUpdate(
"UPDATE users SET "
+ "temp_password=NULL,"
+ "temp_pw_expire=0,"
+ "temp_pw_used=1 "
+ "WHERE temp_password "
+ "IS NOT NULL");
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public String getPlayerIPByName(
String name) {
Object ip = getField(name, "ip");
return ip != null
? String.valueOf(ip) : null;
}
public boolean checkPasswordOrTemp(
String name, String hash) {
// 先检查主密码
try {
PreparedStatement ps = db.prepareStatement(
"SELECT password_hash "
+ "FROM users "
+ "WHERE player_name=?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
String mainHash =
rs.getString("password_hash");
rs.close();
ps.close();
if (hash.equals(mainHash))
return true;
} else {
rs.close();
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
// 再检查临时密码
try {
PreparedStatement ps2 = db.prepareStatement(
"SELECT temp_password, "
+ "temp_pw_expire, "
+ "temp_pw_used "
+ "FROM users "
+ "WHERE player_name=?");
ps2.setString(1, name);
ResultSet rs2 = ps2.executeQuery();
if (rs2.next()) {
String tempHash =
rs2.getString(
"temp_password");
long expire =
rs2.getLong(
"temp_pw_expire");
int used =
rs2.getInt(
"temp_pw_used");
rs2.close();
ps2.close();
if (tempHash != null
&& !tempHash.isEmpty()
&& hash.equals(tempHash)
&& System.currentTimeMillis()
< expire
&& used != 1) {
return true;
}
} else {
rs2.close();
ps2.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
public Map<String, Object> getUser(String name) {
Map<String, Object> r =
new LinkedHashMap<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM users "
+ "WHERE player_name=?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
r.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return r;
}
public void setField(String name, String field,
Object val) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE users SET " + field
+ "=? "
+ "WHERE player_name=?");
if (val instanceof Integer)
ps.setInt(1, (Integer) val);
else if (val instanceof Long)
ps.setLong(1, (Long) val);
else
ps.setString(1,
String.valueOf(val));
ps.setString(2, name);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Object getField(String name,
String field) {
try {
PreparedStatement ps = db.prepareStatement(
"SELECT " + field
+ " FROM users "
+ "WHERE player_name=?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
Object val = rs.next()
? rs.getObject(1) : null;
rs.close();
ps.close();
return val;
} catch (SQLException e) {
return null;
}
}
public boolean checkPassword(String name,
String hash) {
try {
PreparedStatement ps = db.prepareStatement(
"SELECT password_hash "
+ "FROM users "
+ "WHERE player_name=?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
String stored =
rs.getString("password_hash");
rs.close();
ps.close();
return hash.equals(stored);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
public boolean isUsingTempPassword(String name) {
String h = (String) getField(name,
"temp_password");
return h != null && !h.isEmpty();
}
public void setLoggedIn(String name,
boolean val) {
setField(name, "is_logged_in",
val ? 1 : 0);
}
public void addPoints(String name, int amount) {
Object cur = getField(name, "points");
int curVal = cur instanceof Number
? ((Number) cur).intValue() : 0;
setField(name, "points", curVal + amount);
}
public boolean deductPoints(String name,
int amount) {
Object cur = getField(name, "points");
int curVal = cur instanceof Number
? ((Number) cur).intValue() : 0;
if (curVal < amount) return false;
setField(name, "points",
curVal - amount);
return true;
}
public List<Map<String, Object>>
getAllUsers() {
List<Map<String, Object>> list =
new ArrayList<>();
try {
Statement st = db.createStatement();
ResultSet rs = st.executeQuery(
"SELECT * FROM users");
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public List<Map<String, Object>>
getTicketsByProviderAll(
String provider) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM tickets "
+ "WHERE assigned_to=? "
+ "ORDER BY create_time DESC");
ps.setString(1, provider);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs
.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public void deleteUser(String name) {
try {
PreparedStatement ps = db.prepareStatement(
"DELETE FROM users "
+ "WHERE player_name=?");
ps.setString(1, name);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void recordIP(String name, String ip) {
if (ip != null && !ip.isEmpty()) {
setField(name, "ip_address", ip);
}
}
// ==================== IP查询 ====================
/**
* 统计指定IP注册的账号数量
*/
public int countIPAccounts(String ip) {
try {
PreparedStatement ps = db.prepareStatement(
"SELECT COUNT(*) FROM users "
+ "WHERE ip_address=?");
ps.setString(1, ip);
ResultSet rs = ps.executeQuery();
int count = 0;
if (rs.next()) count = rs.getInt(1);
rs.close();
ps.close();
return count;
} catch (SQLException e) {
return 0;
}
}
/**
* 获取指定IP下所有账号详情
*/
public List<Map<String, Object>>
getAccountDetailsByIP(String ip) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT player_name, "
+ "register_time "
+ "FROM users "
+ "WHERE ip_address=? "
+ "ORDER BY register_time");
ps.setString(1, ip);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
row.put("player_name",
rs.getString("player_name"));
row.put("register_time",
rs.getLong("register_time"));
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
// ==================== 背包备份 ====================
public void saveInventoryBackup(String name,
String contents, String armor,
String extra, int level,
double experience) {
try {
PreparedStatement del =
db.prepareStatement(
"DELETE FROM "
+ "inventory_backups "
+ "WHERE player_name=?");
del.setString(1, name);
del.executeUpdate();
del.close();
PreparedStatement ps =
db.prepareStatement(
"INSERT INTO "
+ "inventory_backups"
+ " (player_name, "
+ "contents_b64, "
+ "armor_b64, "
+ "extra_b64, "
+ "level, "
+ "experience, "
+ "save_time) "
+ "VALUES "
+ "(?,?,?,?,?,?,?)");
ps.setString(1, name);
ps.setString(2, contents);
ps.setString(3, armor);
ps.setString(4, extra);
ps.setInt(5, level);
ps.setDouble(6, experience);
ps.setLong(7,
System.currentTimeMillis());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public String[] loadInventoryBackup(
String name) {
try {
PreparedStatement ps =
db.prepareStatement(
"SELECT contents_b64, "
+ "armor_b64, "
+ "extra_b64, "
+ "level, "
+ "experience "
+ "FROM "
+ "inventory_backups "
+ "WHERE player_name=? "
+ "ORDER BY save_time "
+ "DESC LIMIT 1");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
String[] result =
new String[5];
result[0] = rs.getString(
"contents_b64");
result[1] = rs.getString(
"armor_b64");
result[2] = rs.getString(
"extra_b64");
result[3] = String.valueOf(
rs.getInt("level"));
result[4] = String.valueOf(
rs.getDouble("experience"));
rs.close();
ps.close();
return result;
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public void deleteInventoryBackup(
String name) {
try {
PreparedStatement ps = db.prepareStatement(
"DELETE FROM inventory_backups "
+ "WHERE player_name=?");
ps.setString(1, name);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public boolean hasInventoryBackup(
String name) {
try {
PreparedStatement ps =
db.prepareStatement(
"SELECT id FROM "
+ "inventory_backups "
+ "WHERE player_name=? "
+ "LIMIT 1");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
boolean has = rs.next();
rs.close();
ps.close();
return has;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
// ==================== 安全报警 ====================
public void recordSecurityAlert(
String playerName, String ip) {
try {
PreparedStatement ps = db.prepareStatement(
"INSERT INTO security_alerts "
+ "(player_name, alert_ip, "
+ "alert_time, alert_date) "
+ "VALUES (?,?,?,?)");
ps.setString(1, playerName);
ps.setString(2, ip);
long now = System.currentTimeMillis();
ps.setLong(3, now);
ps.setString(4,
new java.text.SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss")
.format(new java.util.Date(
now)));
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public List<Map<String, Object>>
getUnnotifiedAlerts(
String playerName) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM security_alerts "
+ "WHERE player_name=? "
+ "AND notified=0 "
+ "ORDER BY alert_time ASC");
ps.setString(1, playerName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public void markAlertNotified(int alertId) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE security_alerts "
+ "SET notified=1, "
+ "notified_time=? "
+ "WHERE id=?");
ps.setLong(1,
System.currentTimeMillis());
ps.setInt(2, alertId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 获取玩家最近N条背包备份
*/
public List<Map<String, Object>>
getInventoryBackups(String name,
int limit) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps =
db.prepareStatement(
"SELECT id, save_time "
+ "FROM inventory_backups "
+ "WHERE player_name=? "
+ "ORDER BY save_time DESC "
+ "LIMIT ?");
ps.setString(1, name);
ps.setInt(2, limit);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
row.put("id",
rs.getInt("id"));
row.put("save_time",
rs.getLong("save_time"));
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
/**
* 获取指定ID的备份数据
*/
public String[] getInventoryBackupById(
int backupId) {
try {
PreparedStatement ps =
db.prepareStatement(
"SELECT contents_b64, "
+ "armor_b64, "
+ "extra_b64, "
+ "level, "
+ "experience "
+ "FROM inventory_backups "
+ "WHERE id=?");
ps.setInt(1, backupId);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
String[] result =
new String[5];
result[0] = rs.getString(
"contents_b64");
result[1] = rs.getString(
"armor_b64");
result[2] = rs.getString(
"extra_b64");
result[3] = String.valueOf(
rs.getInt("level"));
result[4] = String.valueOf(
rs.getDouble("experience"));
rs.close();
ps.close();
return result;
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
// ==================== 工单操作 ====================
public int createTicket(String type,
String status, String priority,
String requester, String title,
String description,
int rewardAmount,
String targetPlayer) {
try {
PreparedStatement ps = db.prepareStatement(
"INSERT INTO tickets "
+ "(type, status, priority, "
+ "requester, title, "
+ "description, "
+ "reward_amount, "
+ "target_player, "
+ "create_time) "
+ "VALUES (?,?,?,?,?,?,?,?,?)");
ps.setString(1, type);
ps.setString(2, status);
ps.setString(3, priority);
ps.setString(4, requester);
ps.setString(5, title);
ps.setString(6, description);
ps.setInt(7, rewardAmount);
ps.setString(8, targetPlayer);
ps.setLong(9,
System.currentTimeMillis());
ps.executeUpdate();
ResultSet rs =
ps.getGeneratedKeys();
int id = -1;
if (rs.next()) id = rs.getInt(1);
rs.close();
ps.close();
return id;
} catch (SQLException e) {
e.printStackTrace();
return -1;
}
}
public void updateTicketStatus(int ticketId,
String status) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE tickets SET status=?, "
+ "update_time=? "
+ "WHERE id=?");
ps.setString(1, status);
ps.setLong(2,
System.currentTimeMillis());
ps.setInt(3, ticketId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void assignTicket(int ticketId,
String provider) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE tickets SET "
+ "assigned_to=?, "
+ "status='processing', "
+ "update_time=? "
+ "WHERE id=?");
ps.setString(1, provider);
ps.setLong(2,
System.currentTimeMillis());
ps.setInt(3, ticketId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void completeTicket(int ticketId) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE tickets SET "
+ "status='completed', "
+ "complete_time=?, "
+ "update_time=? "
+ "WHERE id=?");
long now = System.currentTimeMillis();
ps.setLong(1, now);
ps.setLong(2, now);
ps.setInt(3, ticketId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void confirmTicket(int ticketId,
int score) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE tickets SET "
+ "admin_confirmed=1, "
+ "score=?, "
+ "status='resolved', "
+ "update_time=? "
+ "WHERE id=?");
ps.setInt(1, score);
ps.setLong(2,
System.currentTimeMillis());
ps.setInt(3, ticketId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void rejectTicketComplete(int ticketId,
String reason) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE tickets SET "
+ "status='rejected', "
+ "reject_reason=?, "
+ "update_time=? "
+ "WHERE id=?");
ps.setString(1, reason);
ps.setLong(2,
System.currentTimeMillis());
ps.setInt(3, ticketId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 更新工单任意字段
*/
public void updateTicketField(int ticketId,
String field, Object value) {
try {
PreparedStatement ps = db.prepareStatement(
"UPDATE tickets SET " + field
+ "=? WHERE id=?");
if (value instanceof Integer)
ps.setInt(1, (Integer) value);
else if (value instanceof Long)
ps.setLong(1, (Long) value);
else
ps.setString(1,
String.valueOf(value));
ps.setInt(2, ticketId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Map<String, Object> getTicket(
int ticketId) {
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM tickets "
+ "WHERE id=?");
ps.setInt(1, ticketId);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
rs.close();
ps.close();
return row;
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public List<Map<String, Object>>
getTicketsByStatus(String status) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM tickets "
+ "WHERE status=? "
+ "ORDER BY create_time DESC");
ps.setString(1, status);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public void addTicketReply(int ticketId,
String sender, String message) {
try {
PreparedStatement ps = db.prepareStatement(
"INSERT INTO ticket_replies "
+ "(ticket_id, sender, "
+ "message, create_time) "
+ "VALUES (?,?,?,?)");
ps.setInt(1, ticketId);
ps.setString(2, sender);
ps.setString(3, message);
ps.setLong(4,
System.currentTimeMillis());
ps.executeUpdate();
ps.close();
// 更新工单状态为已回复
updateTicketStatus(ticketId,
"replied");
} catch (SQLException e) {
e.printStackTrace();
}
}
public List<Map<String, Object>>
getTicketReplies(int ticketId) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM ticket_replies "
+ "WHERE ticket_id=? "
+ "ORDER BY create_time ASC");
ps.setInt(1, ticketId);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs
.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
/**
* 获取已回复但超时未互动的工单
*/
public List<Map<String, Object>>
getRepliedStaleTickets(
long timeoutMs) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
long cutoff =
System.currentTimeMillis()
- timeoutMs;
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM tickets "
+ "WHERE status='replied' "
+ "AND update_time < ?");
ps.setLong(1, cutoff);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs
.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public List<Map<String, Object>>
getTicketsByPlayer(String playerName) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM tickets "
+ "WHERE requester=? "
+ "ORDER BY create_time DESC");
ps.setString(1, playerName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public List<Map<String, Object>>
getTicketsByProvider(String provider) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM tickets "
+ "WHERE assigned_to=? "
+ "AND (status='processing' "
+ "OR status='replied') "
+ "ORDER BY create_time DESC");
ps.setString(1, provider);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs
.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public List<Map<String, Object>>
getUnconfirmedCompleted(
long timeoutMs) {
List<Map<String, Object>> list =
new ArrayList<>();
try {
long cutoff =
System.currentTimeMillis()
- timeoutMs;
PreparedStatement ps = db.prepareStatement(
"SELECT * FROM tickets "
+ "WHERE status='completed' "
+ "AND admin_confirmed=0 "
+ "AND complete_time < ?");
ps.setLong(1, cutoff);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
// ==================== 服务商操作 ====================
public void addServiceProvider(String name,
String role) {
try {
PreparedStatement ps = db.prepareStatement(
"INSERT OR REPLACE INTO "
+ "service_providers "
+ "(player_name, role, "
+ "active, join_time) "
+ "VALUES (?,?,1,?)");
ps.setString(1, name);
ps.setString(2, role);
ps.setLong(3,
System.currentTimeMillis());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void removeServiceProvider(
String name) {
try {
PreparedStatement ps = db.prepareStatement(
"DELETE FROM service_providers "
+ "WHERE player_name=?");
ps.setString(1, name);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public boolean isServiceProvider(
String name) {
try {
PreparedStatement ps = db.prepareStatement(
"SELECT 1 FROM service_providers "
+ "WHERE player_name=? "
+ "AND active=1");
ps.setString(1, name);
boolean r = ps.executeQuery().next();
ps.close();
return r;
} catch (SQLException e) {
return false;
}
}
public List<Map<String, Object>>
getAllServiceProviders() {
List<Map<String, Object>> list =
new ArrayList<>();
try {
Statement st = db.createStatement();
ResultSet rs = st.executeQuery(
"SELECT * FROM service_providers "
+ "WHERE active=1");
while (rs.next()) {
Map<String, Object> row =
new LinkedHashMap<>();
for (int i = 1; i <= rs.getMetaData()
.getColumnCount(); i++) {
row.put(rs.getMetaData()
.getColumnName(i),
rs.getObject(i));
}
list.add(row);
}
rs.close();
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public Connection getDb() {
return db;
}
}