11 changed files with 238 additions and 32 deletions
@ -0,0 +1,81 @@ |
|||||||
|
import { deepCopy } from './caller'; |
||||||
|
|
||||||
|
const db_name = 'transmigration_game'; |
||||||
|
export const store_name_archive = 'archive'; |
||||||
|
export const key_name_archive = 'version'; |
||||||
|
|
||||||
|
const version = 1; |
||||||
|
let db; |
||||||
|
/** |
||||||
|
* 打开数据库 |
||||||
|
* @param {object} dbName 数据库的名字 |
||||||
|
* @param {string} version 数据库的版本 |
||||||
|
* @return {object} 该函数会返回一个数据库实例 |
||||||
|
*/ |
||||||
|
function openDB() { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
// 兼容浏览器
|
||||||
|
var indexedDB = window.indexedDB; |
||||||
|
|
||||||
|
// 打开数据库,若没有则会创建
|
||||||
|
const request = indexedDB.open(db_name, version); |
||||||
|
// 数据库打开成功回调
|
||||||
|
request.onsuccess = function (e) { |
||||||
|
db = request.result; // 数据库对象
|
||||||
|
console.log('数据库打开成功'); |
||||||
|
resolve(db); |
||||||
|
}; |
||||||
|
// 数据库打开失败的回调
|
||||||
|
request.onerror = function (e) { |
||||||
|
console.log('数据库打开报错'); |
||||||
|
}; |
||||||
|
// 数据库有更新时候的回调
|
||||||
|
request.onupgradeneeded = function (e) { |
||||||
|
// 数据库创建或升级的时候会触发
|
||||||
|
console.log('onupgradeneeded'); |
||||||
|
db = request.result; // 数据库对象
|
||||||
|
createArchiveStore(); |
||||||
|
}; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
const createArchiveStore = () => { |
||||||
|
if (!db.objectStoreNames.contains(store_name_archive)) { |
||||||
|
const objectStore = db.createObjectStore(store_name_archive, { keyPath: key_name_archive }); |
||||||
|
// 创建索引,在后面查询数据的时候可以根据索引查
|
||||||
|
// objectStore.createIndex(index_name_equip, index_name_equip, { unique: false });
|
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
await openDB(); |
||||||
|
|
||||||
|
export const insertToStore = (storeName, data) => { |
||||||
|
data = deepCopy(data); |
||||||
|
return new Promise<boolean>((resolve, reject) => { |
||||||
|
const request = db |
||||||
|
.transaction([storeName], 'readwrite') // 事务对象 指定表格名称和操作模式("只读"或"读写")
|
||||||
|
.objectStore(storeName) // 仓库对象
|
||||||
|
.put(data); |
||||||
|
|
||||||
|
request.onsuccess = function (event) { |
||||||
|
resolve(true); |
||||||
|
}; |
||||||
|
|
||||||
|
request.onerror = function (event) { |
||||||
|
resolve(false); |
||||||
|
}; |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
export const getFromStore = (storeName, id) => { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const store = db.transaction([storeName], 'readonly').objectStore(storeName); |
||||||
|
const request = store.get(id); |
||||||
|
request.onsuccess = (e) => { |
||||||
|
resolve(request.result); |
||||||
|
}; |
||||||
|
request.onerror = (e) => { |
||||||
|
resolve([]); |
||||||
|
}; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,75 @@ |
|||||||
|
import { Equip, Player, RebornPoints } from '@/config'; |
||||||
|
import { getFromStore, insertToStore, store_name_archive } from './IndexedDB'; |
||||||
|
import { uuid } from './random'; |
||||||
|
import { version } from 'vue'; |
||||||
|
const archive_version = '1.0'; |
||||||
|
const archive_version_strengthen = '1.0_flag'; |
||||||
|
|
||||||
|
export class GameArchive { |
||||||
|
version: String; |
||||||
|
equips: Equip[]; |
||||||
|
lv: number; |
||||||
|
coins: number; |
||||||
|
grid: any[]; |
||||||
|
autoSell: string[]; |
||||||
|
shop: any[]; |
||||||
|
reborn: RebornPoints; |
||||||
|
|
||||||
|
constructor(player: Player, grid: any[], autoSell: any[], shop: any[], reboren: RebornPoints) { |
||||||
|
this.version = archive_version; |
||||||
|
this.equips = [player.weapon, player.armor, player.ring, player.neck, player.jewelry, player.pants, player.shoes, player.bracers]; |
||||||
|
this.lv = player.lv; |
||||||
|
this.coins = player.coins; |
||||||
|
this.grid = grid; |
||||||
|
this.autoSell = autoSell; |
||||||
|
this.shop = shop; |
||||||
|
this.reborn = reboren; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export const saveArchive = (state) => { |
||||||
|
const archive = new GameArchive(state.playerAttribute, state.grid, state.autoSell, state.shop, state.rebornPoints); |
||||||
|
getFromStore(store_name_archive, archive_version_strengthen).then((flag: any) => { |
||||||
|
const time = new Date().getTime(); |
||||||
|
if (!flag || !flag.time || flag.time + 10 * 60 * 1000 < time) { |
||||||
|
flag = { version: archive_version_strengthen, time: time }; |
||||||
|
} |
||||||
|
const equips = new Array(); |
||||||
|
Array.prototype.push.apply(equips, archive.equips); |
||||||
|
Array.prototype.push.apply(equips, archive.grid); |
||||||
|
equips.forEach((equip) => { |
||||||
|
if (!equip) return; |
||||||
|
|
||||||
|
if (equip.strengthenLv > 0 && !equip.id) { |
||||||
|
equip.id = uuid(); |
||||||
|
} |
||||||
|
if (equip.id) { |
||||||
|
flag[equip.id] = equip.strengthenLv; |
||||||
|
} |
||||||
|
}); |
||||||
|
insertToStore(store_name_archive, archive); |
||||||
|
insertToStore(store_name_archive, flag); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
export const checkImportArchive = async (data): Promise<void> => { |
||||||
|
getFromStore(store_name_archive, archive_version_strengthen).then((rsp: any) => { |
||||||
|
if (!rsp) return; |
||||||
|
const equips = new Array(); |
||||||
|
Array.prototype.push.apply(equips, data.equips); |
||||||
|
Array.prototype.push.apply(equips, data.grid); |
||||||
|
equips.forEach((equip) => { |
||||||
|
if (!equip || !equip.id) return; |
||||||
|
const slv = rsp[equip.id]; |
||||||
|
slv && (equip.strengthenLv = slv); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
export const getArchive = () => { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
getFromStore(store_name_archive, archive_version).then((rsp: any) => { |
||||||
|
resolve(rsp); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,41 @@ |
|||||||
|
import CryptoJS from 'crypto-js'; |
||||||
|
/** |
||||||
|
* AES-256-CBC对称加密 |
||||||
|
* @param text {string} 要加密的明文 |
||||||
|
* @param secretKey {string} 密钥,43位随机大小写与数字 |
||||||
|
* @returns {string} 加密后的密文,Base64格式 |
||||||
|
*/ |
||||||
|
export const AES_CBC_ENCRYPT = (text, secretKey) => { |
||||||
|
var keyHex = CryptoJS.enc.Base64.parse(secretKey); |
||||||
|
var ivHex = keyHex.clone(); |
||||||
|
// 前16字节作为向量
|
||||||
|
ivHex.sigBytes = 16; |
||||||
|
ivHex.words.splice(4); |
||||||
|
var messageHex = CryptoJS.enc.Utf8.parse(text); |
||||||
|
var encrypted = CryptoJS.AES.encrypt(messageHex, keyHex, { |
||||||
|
iv: ivHex, |
||||||
|
mode: CryptoJS.mode.CBC, |
||||||
|
padding: CryptoJS.pad.Pkcs7, |
||||||
|
}); |
||||||
|
return encrypted.toString(); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* AES-256-CBC对称解密 |
||||||
|
* @param textBase64 {string} 要解密的密文,Base64格式 |
||||||
|
* @param secretKey {string} 密钥,43位随机大小写与数字 |
||||||
|
* @returns {string} 解密后的明文 |
||||||
|
*/ |
||||||
|
export const AES_CBC_DECRYPT = (textBase64, secretKey) => { |
||||||
|
var keyHex = CryptoJS.enc.Base64.parse(secretKey); |
||||||
|
var ivHex = keyHex.clone(); |
||||||
|
// 前16字节作为向量
|
||||||
|
ivHex.sigBytes = 16; |
||||||
|
ivHex.words.splice(4); |
||||||
|
var decrypt = CryptoJS.AES.decrypt(textBase64, keyHex, { |
||||||
|
iv: ivHex, |
||||||
|
mode: CryptoJS.mode.CBC, |
||||||
|
padding: CryptoJS.pad.Pkcs7, |
||||||
|
}); |
||||||
|
return CryptoJS.enc.Utf8.stringify(decrypt); |
||||||
|
}; |
Loading…
Reference in new issue