community_ncloud.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*export interface Pointer {
  2. __type: string;
  3. className: string;
  4. objectId?: string; // 这里保持 objectId 作为可选字段
  5. //QuestionnaireId?: string; // 自定义主键
  6. //QuestionId?: string; // 自定义主键
  7. //OptionId?: string; // 自定义主键
  8. //_UserId?: string; // 自定义主键
  9. }
  10. export class CloudObject {
  11. id: string | null = null; // 数据库生成的 objectId
  12. className: string;
  13. createdAt: string | null = null;
  14. updatedAt: string | null = null;
  15. data: Record<string, any> = {};
  16. // 新增的自定义主键
  17. QuestionnaireId?: string;
  18. QuestionId?: string;
  19. OptionId?: string;
  20. _UserId?: string;
  21. constructor(className: string) {
  22. this.className = className;
  23. }
  24. toPointer(): Pointer {
  25. // 使用自定义主键生成指针
  26. let pointer: Pointer = { "__type": "Pointer", "className": this.className };
  27. // 根据类名设置相应的 ID
  28. switch (this.className) {
  29. case "Questionnaire":
  30. pointer.objectId = this.QuestionnaireId || "";
  31. break;
  32. case "Question":
  33. pointer.objectId = this.QuestionId || "";
  34. break;
  35. case "Option":
  36. pointer.objectId = this.OptionId || "";
  37. break;
  38. case "_User":
  39. pointer.objectId = this._UserId || "";
  40. break;
  41. default:
  42. pointer.objectId = this.id || ""; // 保持 objectId 作为后备
  43. }
  44. return pointer;
  45. }
  46. set(json: Record<string, any>) {
  47. Object.keys(json).forEach(key => {
  48. if (["objectId", "id", "createdAt", "updatedAt", "ACL"].includes(key)) {
  49. return;
  50. }
  51. this.data[key] = json[key];
  52. });
  53. }
  54. get(key: string) {
  55. return this.data[key] || null;
  56. }
  57. async save(): Promise<this> {
  58. let method = "POST";
  59. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
  60. // 更新
  61. if (this.id) {
  62. url += `/${this.id}`;
  63. method = "PUT";
  64. }
  65. const body = JSON.stringify(this.data);
  66. const response = await fetch(url, {
  67. headers: {
  68. "content-type": "application/json;charset=UTF-8",
  69. "x-parse-application-id": "dev"
  70. },
  71. body: body,
  72. method: method,
  73. mode: "cors",
  74. credentials: "omit"
  75. });
  76. const result = await response.json();
  77. if (result?.error) {
  78. console.error(result.error);
  79. }
  80. if (result?.objectId) {
  81. this.id = result.objectId;
  82. }
  83. return this;
  84. }
  85. async destroy(): Promise<boolean> {
  86. if (!this.id) return false;
  87. const response = await fetch(`http://dev.fmode.cn:1337/parse/classes/${this.className}/${this.id}`, {
  88. headers: {
  89. "x-parse-application-id": "dev"
  90. },
  91. method: "DELETE",
  92. mode: "cors",
  93. credentials: "omit"
  94. });
  95. const result = await response.json();
  96. if (result) {
  97. this.id = null;
  98. }
  99. return true;
  100. }
  101. }
  102. export class CloudQuery {
  103. className: string;
  104. whereOptions: Record<string, any> = {};
  105. constructor(className: string) {
  106. this.className = className;
  107. }
  108. greaterThan(key: string, value: any) {
  109. if (!this.whereOptions[key]) this.whereOptions[key] = {};
  110. this.whereOptions[key]["$gt"] = value;
  111. return this;
  112. }
  113. greaterThanAndEqualTo(key: string, value: any) {
  114. if (!this.whereOptions[key]) this.whereOptions[key] = {};
  115. this.whereOptions[key]["$gte"] = value;
  116. return this;
  117. }
  118. lessThan(key: string, value: any) {
  119. if (!this.whereOptions[key]) this.whereOptions[key] = {};
  120. this.whereOptions[key]["$lt"] = value;
  121. return this;
  122. }
  123. lessThanAndEqualTo(key: string, value: any) {
  124. if (!this.whereOptions[key]) this.whereOptions[key] = {};
  125. this.whereOptions[key]["$lte"] = value;
  126. return this;
  127. }
  128. equalTo(key: string, value: any) {
  129. this.whereOptions[key] = value;
  130. return this;
  131. }
  132. async get(id: string): Promise<Record<string, any>> {
  133. const url = `http://dev.fmode.cn:1337/parse/classes/${this.className}/${id}`;
  134. const response = await fetch(url, {
  135. headers: {
  136. "x-parse-application-id": "dev"
  137. },
  138. method: "GET",
  139. mode: "cors",
  140. credentials: "omit"
  141. });
  142. const json = await response.json();
  143. return json || {};
  144. }
  145. async find(): Promise<CloudObject[]> {
  146. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
  147. if (Object.keys(this.whereOptions).length) {
  148. const whereStr = JSON.stringify(this.whereOptions);
  149. url += `where=${encodeURIComponent(whereStr)}`;
  150. }
  151. const response = await fetch(url, {
  152. headers: {
  153. "x-parse-application-id": "dev"
  154. },
  155. method: "GET",
  156. mode: "cors",
  157. credentials: "omit"
  158. });
  159. const json = await response.json();
  160. return json?.results.map((item: any) => {
  161. const cloudObject = new CloudObject(this.className);
  162. cloudObject.set(item);
  163. cloudObject.id = item.objectId;
  164. cloudObject.createdAt = item.createdAt;
  165. cloudObject.updatedAt = item.updatedAt;
  166. return cloudObject;
  167. }) || [];
  168. }
  169. async first(): Promise<CloudObject | null> {
  170. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
  171. if (Object.keys(this.whereOptions).length) {
  172. const whereStr = JSON.stringify(this.whereOptions);
  173. url += `where=${encodeURIComponent(whereStr)}&limit=1`;
  174. } else {
  175. url += `limit=1`;
  176. }
  177. const response = await fetch(url, {
  178. headers: {
  179. "x-parse-application-id": "dev"
  180. },
  181. method: "GET",
  182. mode: "cors",
  183. credentials: "omit"
  184. });
  185. const json = await response.json();
  186. const exists = json?.results?.[0] || null;
  187. if (exists) {
  188. const cloudObject = new CloudObject(this.className);
  189. cloudObject.set(exists);
  190. cloudObject.id = exists.objectId;
  191. cloudObject.createdAt = exists.createdAt;
  192. cloudObject.updatedAt = exists.updatedAt;
  193. return cloudObject;
  194. }
  195. return null;
  196. }
  197. }*/
  198. // CloudObject.ts
  199. export interface Pointer {
  200. __type: string;
  201. className: string;
  202. objectId?: string; // 这里保持 objectId 作为可选字段
  203. }
  204. export class CloudObject {
  205. id: string | null = null;
  206. className: string;
  207. data: Record<string, any> = {};
  208. createdAt: string | null = null;
  209. updatedAt: string | null = null;
  210. constructor(className: string) {
  211. this.className = className;
  212. }
  213. toPointer() {
  214. return { "__type": "Pointer", "className": this.className, "objectId": this.id };
  215. }
  216. set(json: Record<string, any>) {
  217. Object.keys(json).forEach(key => {
  218. if (["objectId", "id", "createdAt", "updatedAt", "ACL"].includes(key)) {
  219. if (key === "updatedAt") {
  220. this.updatedAt = json[key]; // 特别处理 updatedAt 字段
  221. }
  222. return;
  223. }
  224. this.data[key] = json[key];
  225. });
  226. }
  227. get(key: string) {
  228. return this.data[key] || null;
  229. }
  230. async save(): Promise<CloudObject> {
  231. let method = "POST";
  232. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
  233. // 更新
  234. if (this.id) {
  235. url += `/${this.id}`;
  236. method = "PUT";
  237. }
  238. const body = JSON.stringify(this.data);
  239. const response = await fetch(url, {
  240. headers: {
  241. "Content-Type": "application/json;charset=UTF-8",
  242. "x-parse-application-id": "dev"
  243. },
  244. body,
  245. method,
  246. mode: "cors",
  247. credentials: "omit"
  248. });
  249. const result = await response.json();
  250. if (result?.error) {
  251. console.error(result.error);
  252. }
  253. if (result?.objectId) {
  254. this.id = result.objectId;
  255. }
  256. return this;
  257. }
  258. async destroy(): Promise<boolean> {
  259. if (!this.id) return false;
  260. const response = await fetch(`http://dev.fmode.cn:1337/parse/classes/${this.className}/${this.id}`, {
  261. headers: {
  262. "x-parse-application-id": "dev"
  263. },
  264. method: "DELETE",
  265. mode: "cors",
  266. credentials: "omit"
  267. });
  268. const result = await response?.json();
  269. if (result) {
  270. this.id = null;
  271. }
  272. return true;
  273. }
  274. }
  275. // CloudQuery.ts
  276. export class CloudQuery {
  277. className: string;
  278. whereOptions: Record<string, any> = {};
  279. constructor(className: string) {
  280. this.className = className;
  281. }
  282. greaterThan(key: string, value: any) {
  283. this.whereOptions[key] = { "$gt": value };
  284. }
  285. greaterThanAndEqualTo(key: string, value: any) {
  286. this.whereOptions[key] = { "$gte": value };
  287. }
  288. lessThan(key: string, value: any) {
  289. this.whereOptions[key] = { "$lt": value };
  290. }
  291. lessThanAndEqualTo(key: string, value: any) {
  292. this.whereOptions[key] = { "$lte": value };
  293. }
  294. equalTo(key: string, value: any) {
  295. this.whereOptions[key] = value;
  296. }
  297. containedIn(key: string, valueArray: any[]) {
  298. this.whereOptions[key] = { "$in": valueArray };
  299. }
  300. /**
  301. * 实现 startsWith 方法
  302. * @param key 要匹配的字段
  303. * @param prefix 匹配的前缀字符串
  304. */
  305. startsWith(key: string, prefix: string) {
  306. if (typeof prefix !== 'string') {
  307. throw new Error('The prefix must be a string.');
  308. }
  309. // 添加 $regex 条件进行前缀匹配
  310. this.whereOptions[key] = { "$regex": `^${prefix}` };
  311. }
  312. async get(id: string): Promise<Record<string, any>> {
  313. const url = `http://dev.fmode.cn:1337/parse/classes/${this.className}/${id}?`;
  314. const response = await fetch(url, {
  315. headers: {
  316. "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
  317. "x-parse-application-id": "dev"
  318. },
  319. method: "GET",
  320. mode: "cors",
  321. credentials: "omit"
  322. });
  323. const json = await response.json();
  324. return json || {};
  325. }
  326. async find(): Promise<CloudObject[]> {
  327. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
  328. if (Object.keys(this.whereOptions).length) {
  329. const whereStr = JSON.stringify(this.whereOptions);
  330. url += `where=${encodeURIComponent(whereStr)}`;
  331. }
  332. const response = await fetch(url, {
  333. headers: {
  334. "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2BDKY\"",
  335. "x-parse-application-id": "dev"
  336. },
  337. method: "GET",
  338. mode: "cors",
  339. credentials: "omit"
  340. });
  341. const json = await response.json();
  342. return json?.results.map((item: any) => {
  343. const cloudObject = new CloudObject(this.className);
  344. cloudObject.set(item);
  345. cloudObject.id = item.objectId;
  346. // 提取 updatedAt 字段并存储在其他地方(例如,直接存入数据或作为额外字段返回)
  347. const updatedAt = item.updatedAt; // 提取 updatedAt 字段
  348. cloudObject.data['updatedAt'] = updatedAt; // 或者将其放在一个独立的变量中,取决于需求
  349. return cloudObject;
  350. }) || [];
  351. }
  352. async first(): Promise<CloudObject | null> {
  353. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
  354. if (Object.keys(this.whereOptions).length) {
  355. const whereStr = JSON.stringify(this.whereOptions);
  356. url += `where=${encodeURIComponent(whereStr)}`;
  357. }
  358. const response = await fetch(url, {
  359. headers: {
  360. "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
  361. "x-parse-application-id": "dev"
  362. },
  363. method: "GET",
  364. mode: "cors",
  365. credentials: "omit"
  366. });
  367. const json = await response.json();
  368. const exists = json?.results?.[0] || null;
  369. if (exists) {
  370. const existsObject = new CloudObject(this.className);
  371. existsObject.set(exists);
  372. existsObject.id = exists.objectId;
  373. existsObject.createdAt = exists.createdAt;
  374. existsObject.updatedAt = exists.updatedAt;
  375. return existsObject;
  376. }
  377. return null;
  378. }
  379. }
  380. // CloudUser.ts
  381. export class CloudUser extends CloudObject {
  382. constructor() {
  383. super("_User"); // 假设用户类在Parse中是"_User"
  384. // 读取用户缓存信息
  385. let userCacheStr = localStorage.getItem("NCloud/dev/User")
  386. if (userCacheStr) {
  387. let userData = JSON.parse(userCacheStr)
  388. // 设置用户信息
  389. this.id = userData?.objectId;
  390. this.sessionToken = userData?.sessionToken;
  391. this.data = userData; // 保存用户数据
  392. }
  393. }
  394. sessionToken: string | null = ""
  395. /** 获取当前用户信息 */
  396. async current() {
  397. if (!this.sessionToken) {
  398. console.error("用户未登录");
  399. return null;
  400. }
  401. return this;
  402. // const response = await fetch(`http://dev.fmode.cn:1337/parse/users/me`, {
  403. // headers: {
  404. // "x-parse-application-id": "dev",
  405. // "x-parse-session-token": this.sessionToken // 使用sessionToken进行身份验证
  406. // },
  407. // method: "GET"
  408. // });
  409. // const result = await response?.json();
  410. // if (result?.error) {
  411. // console.error(result?.error);
  412. // return null;
  413. // }
  414. // return result;
  415. }
  416. /** 登录 */
  417. async login(username: string, password: string): Promise<CloudUser | null> {
  418. const response = await fetch(`http://dev.fmode.cn:1337/parse/login`, {
  419. headers: {
  420. "x-parse-application-id": "dev",
  421. "Content-Type": "application/json"
  422. },
  423. body: JSON.stringify({ username, password }),
  424. method: "POST"
  425. });
  426. const result = await response?.json();
  427. if (result?.error) {
  428. console.error(result?.error);
  429. return null;
  430. }
  431. // 设置用户信息
  432. this.id = result?.objectId;
  433. this.sessionToken = result?.sessionToken;
  434. this.data = result; // 保存用户数据
  435. // 缓存用户信息
  436. console.log(result)
  437. localStorage.setItem("NCloud/dev/User", JSON.stringify(result))
  438. return this;
  439. }
  440. /** 登出 */
  441. async logout() {
  442. if (!this.sessionToken) {
  443. console.error("用户未登录");
  444. return;
  445. }
  446. const response = await fetch(`http://dev.fmode.cn:1337/parse/logout`, {
  447. headers: {
  448. "x-parse-application-id": "dev",
  449. "x-parse-session-token": this.sessionToken
  450. },
  451. method: "POST"
  452. });
  453. const result = await response?.json();
  454. if (result?.error) {
  455. console.error(result?.error);
  456. return false;
  457. }
  458. // 清除用户信息
  459. localStorage.removeItem("NCloud/dev/User")
  460. this.id = null;
  461. this.sessionToken = null;
  462. this.data = {};
  463. return true;
  464. }
  465. /** 注册 */
  466. async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
  467. const userData = {
  468. username,
  469. password,
  470. ...additionalData // 合并额外的用户数据
  471. };
  472. const response = await fetch(`http://dev.fmode.cn:1337/parse/users`, {
  473. headers: {
  474. "x-parse-application-id": "dev",
  475. "Content-Type": "application/json"
  476. },
  477. body: JSON.stringify(userData),
  478. method: "POST"
  479. });
  480. const result = await response?.json();
  481. if (result?.error) {
  482. console.error(result?.error);
  483. return null;
  484. }
  485. // 设置用户信息
  486. // 缓存用户信息
  487. console.log(result)
  488. localStorage.setItem("NCloud/dev/User", JSON.stringify(result))
  489. this.id = result?.objectId;
  490. this.sessionToken = result?.sessionToken;
  491. this.data = result; // 保存用户数据
  492. return this;
  493. }
  494. override async save() {
  495. let method = "POST";
  496. let url = `http://dev.fmode.cn:1337/parse/users`;
  497. // 更新用户信息
  498. if (this.id) {
  499. url += `/${this.id}`;
  500. method = "PUT";
  501. }
  502. let data: any = JSON.parse(JSON.stringify(this.data))
  503. delete data.createdAt
  504. delete data.updatedAt
  505. delete data.ACL
  506. delete data.objectId
  507. const body = JSON.stringify(data);
  508. let headersOptions: any = {
  509. "content-type": "application/json;charset=UTF-8",
  510. "x-parse-application-id": "dev",
  511. "x-parse-session-token": this.sessionToken, // 添加sessionToken以进行身份验证
  512. }
  513. const response = await fetch(url, {
  514. headers: headersOptions,
  515. body: body,
  516. method: method,
  517. mode: "cors",
  518. credentials: "omit"
  519. });
  520. const result = await response?.json();
  521. if (result?.error) {
  522. console.error(result?.error);
  523. }
  524. if (result?.objectId) {
  525. this.id = result?.objectId;
  526. }
  527. localStorage.setItem("NCloud/dev/User", JSON.stringify(this.data))
  528. return this;
  529. }
  530. }