Skip to content

Commit 9895754

Browse files
committed
upload ide/js/store.js
1 parent 9f47ada commit 9895754

1 file changed

Lines changed: 245 additions & 0 deletions

File tree

ide/js/store.js

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/* ============================================================
2+
* HC v0.01 —— 数据层 store.js
3+
* 职责:
4+
* 1) 项目 / 页面 CRUD,localStorage 本地持久化
5+
* 2) 首次零项目引导判定(hasAnyProject / lastActive)
6+
* 3) .hc 文件导出 / 导入
7+
* 数据形态(localStorage 键:HICODE_DATA):
8+
* {
9+
* projects: { <projId>: { id, name, createdAt, updatedAt,
10+
* pages: { <pageId>: { id, name, code,
11+
* images: { <varName>: dataURL } } } } },
12+
* lastProjectId, lastPageId
13+
* }
14+
* 图片以 dataURL 内嵌进项目数据,随 .hc 一并保存。
15+
* ============================================================ */
16+
(function (root, factory) {
17+
const api = factory();
18+
if (typeof module !== "undefined" && module.exports) module.exports = api;
19+
if (root) root.Store = api;
20+
})(typeof self !== "undefined" ? self : null, function () {
21+
"use strict";
22+
23+
const KEY = "HICODE_DATA";
24+
const STORE_VERSION = "v0.01";
25+
26+
function uuid() {
27+
return "h" + Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
28+
}
29+
30+
function now() { return Date.now(); }
31+
32+
function emptyData() {
33+
return { projects: {}, lastProjectId: null, lastPageId: null };
34+
}
35+
36+
// 严格在浏览器可用时读写 localStorage;非浏览器环境退化为内存态,便于测试
37+
let _mem = null;
38+
function hasLS() {
39+
try { return typeof localStorage !== "undefined" && !!localStorage; } catch (e) { return false; }
40+
}
41+
function load() {
42+
if (!hasLS()) return (_mem ? JSON.parse(JSON.stringify(_mem)) : emptyData());
43+
try {
44+
const raw = localStorage.getItem(KEY);
45+
if (!raw) return emptyData();
46+
const d = JSON.parse(raw);
47+
if (!d || typeof d.projects !== "object") return emptyData();
48+
return d;
49+
} catch (e) { return emptyData(); }
50+
}
51+
function save(d) {
52+
if (!hasLS()) { _mem = JSON.parse(JSON.stringify(d)); return; }
53+
try { localStorage.setItem(KEY, JSON.stringify(d)); } catch (e) { /* 容量超限忽略 */ }
54+
}
55+
function reset() {
56+
if (hasLS()) { try { localStorage.removeItem(KEY); } catch (e) {} }
57+
_mem = emptyData();
58+
}
59+
60+
// ---- 项目 ----
61+
function getProject(id) {
62+
const d = load();
63+
const p = d.projects && d.projects[id];
64+
return p ? JSON.parse(JSON.stringify(p)) : null;
65+
}
66+
function listProjects() {
67+
const d = load();
68+
return Object.keys(d.projects || {}).map(function (id) {
69+
const p = d.projects[id];
70+
return { id: p.id, name: p.name, pageCount: Object.keys(p.pages).length, createdAt: p.createdAt, updatedAt: p.updatedAt };
71+
});
72+
}
73+
function getProjectByPage(pageId) {
74+
const d = load();
75+
for (const id in d.projects) {
76+
if (Object.prototype.hasOwnProperty.call(d.projects[id].pages, pageId)) return JSON.parse(JSON.stringify(d.projects[id]));
77+
}
78+
return null;
79+
}
80+
// createProject(name, withDefaultPage=true) -> {id}
81+
function createProject(name, withDefaultPage) {
82+
const d = load();
83+
const id = uuid();
84+
const pages = {};
85+
if (withDefaultPage !== false) {
86+
const pid = uuid();
87+
pages[pid] = { id: pid, name: "页面1", code: "", images: {} };
88+
d.lastPageId = pid;
89+
}
90+
d.projects[id] = { id, name: safeName(name, "项目"), createdAt: now(), updatedAt: now(), pages };
91+
d.lastProjectId = id;
92+
save(d);
93+
return id;
94+
}
95+
function renameProject(id, name) {
96+
const d = load();
97+
if (!d.projects[id]) return false;
98+
d.projects[id].name = safeName(name, "项目");
99+
d.projects[id].updatedAt = now();
100+
save(d);
101+
return true;
102+
}
103+
function deleteProject(id) {
104+
const d = load();
105+
if (!d.projects[id]) return false;
106+
delete d.projects[id];
107+
if (d.lastProjectId === id) d.lastProjectId = null;
108+
save(d);
109+
return true;
110+
}
111+
112+
// ---- 页面 ----
113+
function createPage(projId, name) {
114+
const d = load();
115+
if (!d.projects[projId]) return null;
116+
const pid = uuid();
117+
d.projects[projId].pages[pid] = { id: pid, name: safeName(name, "页面1"), code: "", images: {} };
118+
d.projects[projId].updatedAt = now();
119+
d.lastPageId = pid;
120+
save(d);
121+
return pid;
122+
}
123+
function getPage(projId, pageId) {
124+
const d = load();
125+
const p = d.projects[projId] && d.projects[projId].pages[pageId];
126+
return p ? JSON.parse(JSON.stringify(p)) : null;
127+
}
128+
function renamePage(projId, pageId, name) {
129+
const d = load();
130+
const p = d.projects[projId] && d.projects[projId].pages[pageId];
131+
if (!p) return false;
132+
p.name = safeName(name, "页面");
133+
d.projects[projId].updatedAt = now();
134+
save(d);
135+
return true;
136+
}
137+
function deletePage(projId, pageId) {
138+
const d = load();
139+
if (!d.projects[projId] || !d.projects[projId].pages[pageId]) return false;
140+
delete d.projects[projId].pages[pageId];
141+
d.projects[projId].updatedAt = now();
142+
if (d.lastPageId === pageId) {
143+
const left = Object.keys(d.projects[projId].pages);
144+
d.lastPageId = left.length ? left[0] : null;
145+
}
146+
save(d);
147+
return true;
148+
}
149+
// updatePageCode(projId, pageId, code)
150+
function updatePageCode(projId, pageId, code) {
151+
const d = load();
152+
const p = d.projects[projId] && d.projects[projId].pages[pageId];
153+
if (!p) return false;
154+
p.code = code;
155+
d.projects[projId].updatedAt = now();
156+
save(d);
157+
return true;
158+
}
159+
// setPageImage(projId, pageId, varName, dataURL) :绑定「it xxx p」的图片
160+
function setPageImage(projId, pageId, varName, dataURL) {
161+
const d = load();
162+
const p = d.projects[projId] && d.projects[projId].pages[pageId];
163+
if (!p) return false;
164+
if (!p.images) p.images = {};
165+
if (dataURL == null) delete p.images[varName]; else p.images[varName] = dataURL;
166+
d.projects[projId].updatedAt = now();
167+
save(d);
168+
return true;
169+
}
170+
function getPageImages(projId, pageId) {
171+
const d = load();
172+
const p = d.projects[projId] && d.projects[projId].pages[pageId];
173+
return (p && p.images) ? JSON.parse(JSON.stringify(p.images)) : {};
174+
}
175+
176+
// ---- 最近活动(首屏引导定位) ----
177+
function lastProjectId() { return load().lastProjectId || null; }
178+
function lastPageId() { return load().lastPageId || null; }
179+
function hasAnyProject() { return Object.keys(load().projects).length > 0; }
180+
function setActive(projId, pageId) {
181+
const d = load();
182+
d.lastProjectId = projId || d.lastProjectId;
183+
if (pageId) d.lastPageId = pageId;
184+
save(d);
185+
}
186+
187+
// ---- .hc 导出 / 导入 ----
188+
// 导出单个项目(含全部页面与内嵌图片)为 .hc 文件文本
189+
function exportHcProject(projId) {
190+
const p = getProject(projId);
191+
if (!p) return null;
192+
return JSON.stringify({
193+
app: "HiCode", language: "HIC", format: "hc-project", version: STORE_VERSION,
194+
project: p
195+
}, null, 2);
196+
}
197+
function importHc(text) {
198+
// 返回 { ok, error?, projectId?, name? }
199+
try {
200+
const obj = JSON.parse(text);
201+
if (!obj || obj.app !== "HiCode" || !obj.project) return { ok: false, error: "不是有效的 .hc 文件(缺少 HiCode 标记)" };
202+
const proj = obj.project;
203+
if (!proj || !proj.name || typeof proj.pages !== "object") return { ok: false, error: ".hc 文件内容不完整" };
204+
const d = load();
205+
// 同名覆盖策略:同名则新建一个带序号的名字,避免冲突
206+
const names = Object.keys(d.projects).map(function (id) { return d.projects[id].name; });
207+
let name = proj.name;
208+
if (names.indexOf(name) >= 0) {
209+
let n = 2;
210+
while (names.indexOf(name + "_" + n) >= 0) n++;
211+
name = name + "_" + n;
212+
}
213+
const id = uuid();
214+
d.projects[id] = { id, name, createdAt: now(), updatedAt: now(), pages: {} };
215+
Object.keys(proj.pages).forEach(function (pid) {
216+
const src = proj.pages[pid];
217+
const nid = uuid();
218+
d.projects[id].pages[nid] = {
219+
id: nid, name: src.name || "页面", code: src.code || "",
220+
images: (src.images && typeof src.images === "object") ? JSON.parse(JSON.stringify(src.images)) : {}
221+
};
222+
});
223+
d.lastProjectId = id;
224+
save(d);
225+
return { ok: true, projectId: id, name };
226+
} catch (e) {
227+
return { ok: false, error: "解析失败:" + e.message };
228+
}
229+
}
230+
231+
function safeName(name, fallback) {
232+
const s = String(name == null ? "" : name).trim();
233+
return s ? s : fallback;
234+
}
235+
236+
return {
237+
STORE_VERSION, KEY,
238+
uuid, now, load, save, reset,
239+
getProject, listProjects, getProjectByPage, createProject, renameProject, deleteProject,
240+
createPage, getPage, renamePage, deletePage, updatePageCode, setPageImage, getPageImages,
241+
loadNewData: emptyData,
242+
lastProjectId, lastPageId, hasAnyProject, setActive,
243+
exportHcProject, importHc
244+
};
245+
});

0 commit comments

Comments
 (0)