const db = require("../plugin/DataBase/db"); function normalizeClientType(value) { return String(value || "").trim().toLowerCase(); } function parseVersionParts(version) { return String(version || "") .trim() .replace(/^[vV]/, "") .split(/[.+_-]/) .map(part => { const n = Number.parseInt(part, 10); return Number.isFinite(n) ? n : 0; }); } function compareVersionName(a, b) { const left = parseVersionParts(a); const right = parseVersionParts(b); const len = Math.max(left.length, right.length); for (let i = 0; i < len; i++) { const diff = (left[i] || 0) - (right[i] || 0); if (diff !== 0) return diff > 0 ? 1 : -1; } return 0; } function isVersionNewer(remote, local) { const remoteCode = Number(remote.version_code); const localCode = Number(local.version_code); if (Number.isFinite(remoteCode) && remoteCode > 0 && Number.isFinite(localCode) && localCode > 0) return remoteCode > localCode; return compareVersionName(remote.version_name, local.version_name) > 0; } function toUniAppPayload(row) { return { describe: row.release_notes_html || row.release_notes || "", edition_url: row.download_url, edition_force: Number(row.force_update) || 0, package_type: Number(row.package_type) || 0, edition_issue: Number(row.is_active) === 0 ? 0 : 1, edition_number: Number(row.version_code) || 0, edition_name: row.version_name, edition_silence: Number(row.silent_update) || 0, log: row.release_notes || "" }; } function toPublicPayload(row, localVersion = {}) { if (!row) { return { has_update: false, update_available: false }; } const remote = { version_name: row.version_name, version_code: Number(row.version_code) || 0 }; const local = { version_name: localVersion.version_name, version_code: localVersion.version_code }; const hasUpdate = isVersionNewer(remote, local); const payload = { has_update: hasUpdate, update_available: hasUpdate, client_type: row.client_type, title: row.title || "", version: row.version_name, version_name: row.version_name, version_code: Number(row.version_code) || 0, download_url: row.download_url, sha256: row.sha256 || "", file_size: Number(row.file_size) || 0, package_type: Number(row.package_type) || 0, force_update: Number(row.force_update) || 0, silent_update: Number(row.silent_update) || 0, release_notes: row.release_notes || "", release_notes_html: row.release_notes_html || "", min_supported_version: row.min_supported_version || "" }; if (normalizeClientType(row.client_type) === "android") { Object.assign(payload, toUniAppPayload(row), { uniapp: toUniAppPayload(row) }); } return payload; } async function getLatestVersion(clientType) { const normalized = normalizeClientType(clientType); const rows = await db.query(` SELECT id, client_type, version_name, version_code, title, download_url, sha256, file_size, package_type, force_update, silent_update, is_active, release_notes, release_notes_html, min_supported_version, sort_order, created_at, updated_at FROM download_version WHERE client_type = ? AND is_active = 1 ORDER BY version_code DESC, sort_order ASC, id DESC LIMIT 1 `, [normalized]); return rows && rows[0] ? rows[0] : null; } async function listVersions(clientType = "") { const normalized = normalizeClientType(clientType); if (normalized) { return await db.query(` SELECT id, client_type, version_name, version_code, title, download_url, sha256, file_size, package_type, force_update, silent_update, is_active, release_notes, release_notes_html, min_supported_version, sort_order, created_at, updated_at FROM download_version WHERE client_type = ? ORDER BY client_type ASC, version_code DESC, sort_order ASC, id DESC `, [normalized]); } return await db.query(` SELECT id, client_type, version_name, version_code, title, download_url, sha256, file_size, package_type, force_update, silent_update, is_active, release_notes, release_notes_html, min_supported_version, sort_order, created_at, updated_at FROM download_version ORDER BY client_type ASC, version_code DESC, sort_order ASC, id DESC `); } async function saveVersion(payload) { const now = Date.now(); const data = { client_type: normalizeClientType(payload.client_type), version_name: String(payload.version_name || payload.version || "").trim(), version_code: Number(payload.version_code) || 0, title: String(payload.title || "").trim(), download_url: String(payload.download_url || "").trim(), sha256: String(payload.sha256 || "").trim().toLowerCase(), file_size: Number(payload.file_size) || 0, package_type: Number(payload.package_type) || 0, force_update: Number(payload.force_update) === 1 ? 1 : 0, silent_update: Number(payload.silent_update) === 1 ? 1 : 0, is_active: Number(payload.is_active) === 0 ? 0 : 1, release_notes: payload.release_notes || "", release_notes_html: payload.release_notes_html || "", min_supported_version: String(payload.min_supported_version || "").trim(), sort_order: Number(payload.sort_order) || 0 }; if (payload.id) { const result = await db.query(` UPDATE download_version SET client_type = ?, version_name = ?, version_code = ?, title = ?, download_url = ?, sha256 = ?, file_size = ?, package_type = ?, force_update = ?, silent_update = ?, is_active = ?, release_notes = ?, release_notes_html = ?, min_supported_version = ?, sort_order = ?, updated_at = ? WHERE id = ? `, [ data.client_type, data.version_name, data.version_code, data.title, data.download_url, data.sha256, data.file_size, data.package_type, data.force_update, data.silent_update, data.is_active, data.release_notes, data.release_notes_html, data.min_supported_version, data.sort_order, now, payload.id ]); return { id: payload.id, result }; } const result = await db.query(` INSERT INTO download_version (client_type, version_name, version_code, title, download_url, sha256, file_size, package_type, force_update, silent_update, is_active, release_notes, release_notes_html, min_supported_version, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, [ data.client_type, data.version_name, data.version_code, data.title, data.download_url, data.sha256, data.file_size, data.package_type, data.force_update, data.silent_update, data.is_active, data.release_notes, data.release_notes_html, data.min_supported_version, data.sort_order, now, now ]); return { id: result && result.insertId, result }; } async function deleteVersion(id) { return await db.query("DELETE FROM download_version WHERE id = ?", [id]); } module.exports = { getLatestVersion, listVersions, saveVersion, deleteVersion, toPublicPayload, toUniAppPayload, normalizeClientType };