一、建立SQL.js,内容如下:
class SQL {
constructor(plus) {
// 数据库名称一个软件只需要一个库这里写死
this.name = 'sqlite_mine_sql';
this.plus = plus;
// 存储路径
this.path = `_doc/sqlite_mine.db`;
}
initDatabase() {
return new Promise((resolve, reject) => {
const that = this;
console.log('数据表初始化');
// **第一步:确保数据库已打开**
plus.sqlite.openDatabase({
name: that.name,
path: this.path,
success() {
console.log("数据库打开成功,开始检查表");
// **第二步:查询 media 表是否存在**
let checkMediaSql =
`SELECT name FROM sqlite_master WHERE type='table' AND name='media'`;
plus.sqlite.selectSql({
name: that.name,
sql: checkMediaSql,
success(data) {
console.log("查询表结果:", JSON.stringify(data));
if (data.length === 0) {
console.log("media 表不存在,创建表,设置url为唯一索引");
const createMediaSql = `
CREATE TABLE IF NOT EXISTS media (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT,
url TEXT UNIQUE,
localUrl TEXT,
mid TEXT
)`;
plus.sqlite.executeSql({
name: that.name,
sql: createMediaSql,
success() {
console.log("media 表创建成功");
resolve({
message: "表创建成功"
});
},
fail(e) {
console.error("创建 media 表失败:", JSON
.stringify(e));
reject({
message: "创建表失败",
error: e
});
}
});
} else {
console.log("media 表已存在");
resolve({
message: "表已存在"
});
}
},
fail(e) {
console.error("查询表失败:", JSON.stringify(e));
reject({
message: "查询表失败",
error: e
});
}
});
},
fail(e) {
console.error("数据库打开失败:", JSON.stringify(e));
reject({
message: "数据库打开失败",
error: e
});
}
});
});
}
// 连接数据库
openDB() {
return new Promise((resolve, reject) => {
if (this.isOpen()) {
return resolve();
}
this.initDatabase();
});
}
// 判断数据库是否打开
isOpen() {
return this.plus.sqlite.isOpenDatabase({
name: this.name,
path: this.path
});
}
// 关闭数据库
closeDB() {
this.plus.sqlite.closeDatabase({
name: this.name,
success(e) {
console.log('closeDatabase success!');
},
fail(e) {
console.log('closeDatabase failed: ' + JSON.stringify(e));
}
});
}
// 执行sql语句
//handleType类型 dbname数据表 options条件 data修改时操作的数据 sort查询时排序 page查询时分页数据
async handleSQL(handleType, dbname, options, data = {}, sort = 'id asc', page = {}, isClose = false) {
await this.openDB();
// await this.initDatabase();
switch (handleType) {
case 'insert':
return this.insertSQL(dbname, options, isClose);
case 'delete':
return this.deleteSQL(dbname, options, isClose);
case 'select':
return this.selectSQL(dbname, options, sort, page, isClose);
case 'update':
return this.updateSQL(dbname, data, options, isClose);
case 'find':
return this.findSQL(dbname, options, isClose);
default:
throw new Error('没有这个操作!!!');
}
}
// 插入sql语句
insertSQL(dbname, options, isClose) {
const that = this;
return new Promise((resolve, reject) => {
if (!options || Object.keys(options).length === 0) {
console.error("insertSQL 失败:options 不能为空");
return reject("插入数据不能为空");
}
const keys = Object.keys(options).join(', '); // "type, url, localUrl"
const valuesStr = Object.values(options).map(val => `'${val}'`).join(
', '); // "'image', 'http://...', '_doc/...'"
const sql = `INSERT INTO ${dbname} (${keys}) VALUES (${valuesStr});`;
// console.log('执行插入 SQL:', sql);
that.plus.sqlite.executeSql({
name: that.name,
sql: sql,
success() {
console.log('insertSQL success');
// 查询刚插入的数据
that.plus.sqlite.selectSql({
name: that.name,
sql: "SELECT last_insert_rowid() AS id;",
success(data) {
// console.log('最后插入的 ID:', data[0].id);
isClose && that.closeDB();
resolve(data[0].id);
},
fail(e) {
console.log('查询 last_insert_rowid 失败:', JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
},
fail(e) {
console.log('insertSQL failed:', JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}
// 删除sql语句
deleteSQL(dbname, options, isClose) {
return new Promise((resolve, reject) => {
const that = that || this;
if (!options || Object.keys(options).length === 0) {
console.error("deleteSQL 失败:options 不能为空");
return reject("删除条件不能为空");
}
// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
// 判断是否是对象(用于大于、小于等特殊情况)
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND "); // 用 AND 连接多个条件
// 生成完整的 SQL 语句
const sql = `DELETE FROM ${dbname} ${whereClause};`;
console.log("执行 SQL:", sql); // 调试 SQL 语句
that.plus.sqlite.executeSql({
name: that.name,
sql:sql,
success(data) {
console.log('deleteSQL success: ' + JSON.stringify(data));
isClose && that.closeDB();
resolve(data);
},
fail(e) {
console.log('deleteSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}
// 查询sql语句 options参数为是否分页
selectSQL(dbname, options, sort, page, isClose) {
return new Promise((resolve, reject) => {
const that = that || this;
if (!options || Object.keys(options).length === 0) {
console.error("selectSQL 失败:options 不能为空");
return reject("查询条件不能为空");
}
// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
// 判断是否是对象(用于大于、小于等特殊情况)
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND "); // 用 AND 连接多个条件
// 生成完整的 SQL 语句
const sql = `SELECT * FROM ${dbname} ${whereClause};`;
that.plus.sqlite.selectSql({
name: that.name,
sql:sql,
success(data) {
console.log('selectSQL success: ' + JSON.stringify(data));
if (page.hasOwnProperty('pageNum') && page.hasOwnProperty('pageSize')) {
let {
pageNum,
pageSize
} = page;
let total = data.length;
let page = Math.ceil(total / pageSize);
let req = {
pageNum,
pageSize,
list: [],
total
};
let startIndex = (pageNum - 1) * pageSize;
if (pageNum < page) {
req.list = data.slice(startIndex, startIndex + pageSize);
return resolve(req);
}
} else {
resolve(data);
}
isClose && that.closeDB();
},
fail(e) {
console.log('selectSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}
//修改sql语句
updateSQL(dbname, data, options, isClose) {
const that = this;
return new Promise((resolve, reject) => {
if (!data || Object.keys(data).length === 0) {
console.error("updateSQL 失败:更新数据不能为空");
return reject("更新数据不能为空");
}
if (!options || Object.keys(options).length === 0) {
console.error("updateSQL 失败:条件不能为空");
return reject("更新条件不能为空");
}
// 构造 SET 语句
let setClause = Object.keys(data)
.map(key => `${key} = '${data[key]}'`)
.join(", ");
// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND ");
// 生成完整的 SQL 语句
const sql = `UPDATE ${dbname} SET ${setClause} ${whereClause};`;
// console.log("执行 SQL:", sql); // 调试 SQL 语句
that.plus.sqlite.executeSql({
name: that.name,
sql:sql,
success(data) {
console.log('updateSQL success: ' + JSON.stringify(data));
isClose && that.closeDB();
resolve(data);
},
fail(e) {
console.log('updateSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}
// 查询单条数据的 SQL 语句
findSQL(dbname, options, isClose) {
return new Promise((resolve, reject) => {
const that = that || this;
if (!options || Object.keys(options).length === 0) {
console.error("queryOneSQL 失败:options 不能为空");
return reject("查询条件不能为空");
}
// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
// 判断是否是对象(用于大于、小于等特殊情况)
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND "); // 用 AND 连接多个条件
// 生成完整的 SQL 语句
const sql = `SELECT * FROM ${dbname} ${whereClause} LIMIT 1;`;
// console.log("执行 SQL:", sql); // 调试 SQL 语句
that.plus.sqlite.selectSql({
name: that.name,
sql:sql,
success(data) {
// console.log('findSQL success: ' + JSON.stringify(data));
isClose && that.closeDB();
// 只返回第一条数据
resolve(data.length > 0 ? data[0] : null);
},
fail(e) {
console.log('findSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}
//检测文件是否存在本地
// checkFileExists(filePath,url='') {
// plus.io.resolveLocalFileSystemURL(filePath,
// function(entry) {
// console.log("文件存在: " + filePath);
// },
// function(error) {
// console.log("文件不存在或路径错误,需要重新下载保存到本地: " + filePath);
// //下载保存逻辑...
// }
// );
// }
}
export default new SQL(plus);
二、引入方式:在main.js引入
// #ifdef APP-PLUS
import SQL from './library/SQL.js'; // 引入 SQL 类
Vue.prototype.$sql = SQL; // 挂载到 Vue 全局
// #endif
//文件缓存
Vue.prototype.file_cache = async function(image_url,type='image',mid='') {
// #ifndef APP-PLUS
if (image_url == undefined) return false;
if (image_url.indexOf('http') <= -1) image_url = store.getters.get_weburl.imgUri + image_url;
return image_url;
// #endif
// #ifdef APP-PLUS
if (image_url == undefined) return false;
if (image_url.indexOf('http') <= -1) image_url = store.getters.get_weburl.imgUri + image_url;
// return '_doc/uniapp_save/17404810011980.jpg';
try {
let res = await this.$sql.handleSQL('find', 'media', {
type: type,
url: image_url
});
if (res) {
image_url = res.localUrl; // ✅ 查询到本地缓存,返回本地路径
} else {
// 没查询到,需要下载并缓存
try {
// 先返回原始 URL,不等待下载完成
(async () => {
try {
let localPath = await action.localSaveFileHttp(type, mid, image_url);
// 下载完成后,更新数据库
let insertId = await this.$sql.handleSQL('insert', 'media', {
type: type,
url: image_url,
mid: mid,
localUrl: localPath
});
// console.log("文件下载并插入数据库成功 ID:", insertId);
} catch (error) {
// console.error("后台文件下载失败:", error);
}
})();
// console.log('立即返回',image_url)
return image_url; // 立即返回原始 URL
} catch (error) {
return image_url; // 发生异常,依然返回原始 URL
}
}
return image_url;
} catch (error) {
return image_url; // ❌ 查询数据库失败,返回原始 URL
}
// #endif
}
二、(2)action的方法:
// 服务器下载到本地
async localSaveFileHttp(type, mid, url) {
return new Promise((resolve, reject) => {
uni.downloadFile({
url: url, // 你的音频文件或其他文件的 HTTPS 链接
success: (downloadRes) => {
if (downloadRes.statusCode === 200) {
// 下载成功,保存文件
let localPath = this.localSaveFile(type, mid, downloadRes.tempFilePath, url);
resolve(localPath); // ✅ 返回最终的本地路径
} else {
// console.error('文件下载失败:', downloadRes);
reject(new Error('下载失败,状态码:' + downloadRes.statusCode));
}
},
fail: (error) => {
// console.error('下载文件失败:', error);
reject(url);
}
});
});
}
// 文件保存本地类型type 唯一标识mid,url远程路径
async localSaveFile(type, mid, tempFilePath, url = '') {
return new Promise((resolve, reject) => {
uni.saveFile({
tempFilePath: tempFilePath,
success: (saveRes) => {
let savedFilePath = saveRes.savedFilePath; // 获取本地存储路径
// console.log('文件保存成功:', savedFilePath);
resolve(savedFilePath); // ✅ 正确返回保存后的本地路径
},
fail: (error) => {
console.error('保存失败:', error);
reject(error);
}
});
});
}
三、使用方式:
//替换视频缩略图为本地图片
this.vedioImgSrc = await this.file_cache(url,'vedio');