ncloud.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. //CloudObject.ts
  2. export class CloudObject {
  3. className: string;
  4. id: string | null = null;
  5. createdAt:any;
  6. updatedAt:any;
  7. data: Record<string, any> = {};
  8. constructor(className: string) {
  9. this.className = className;
  10. }
  11. toPointer() {
  12. return { "__type": "Pointer", "className": this.className, "objectId": this.id };
  13. }
  14. set(json: Record<string, any>) {
  15. Object.keys(json).forEach(key => {
  16. if (["objectId", "id", "createdAt", "updatedAt", "ACL"].indexOf(key) > -1) {
  17. return;
  18. }
  19. this.data[key] = json[key];
  20. });
  21. }
  22. get(key: string) {
  23. return this.data[key] || null;
  24. }
  25. async save() {
  26. let method = "POST";
  27. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
  28. // 更新
  29. if (this.id) {
  30. url += `/${this.id}`;
  31. method = "PUT";
  32. }
  33. const body = JSON.stringify(this.data);
  34. const response = await fetch(url, {
  35. headers: {
  36. "content-type": "application/json;charset=UTF-8",
  37. "x-parse-application-id": "dev"
  38. },
  39. body: body,
  40. method: method,
  41. mode: "cors",
  42. credentials: "omit"
  43. });
  44. const result = await response?.json();
  45. if (result?.error) {
  46. console.error(result?.error);
  47. }
  48. if (result?.objectId) {
  49. this.id = result?.objectId;
  50. }
  51. return this;
  52. }
  53. async destroy() {
  54. if (!this.id) return;
  55. const response = await fetch(`http://dev.fmode.cn:1337/parse/classes/${this.className}/${this.id}`, {
  56. headers: {
  57. "x-parse-application-id": "dev"
  58. },
  59. body: null,
  60. method: "DELETE",
  61. mode: "cors",
  62. credentials: "omit"
  63. });
  64. const result = await response?.json();
  65. if (result) {
  66. this.id = null;
  67. }
  68. return true;
  69. }
  70. }
  71. // CloudQuery.ts
  72. export class CloudQuery {
  73. className: string;
  74. whereOptions: Record<string, any> = {};
  75. constructor(className: string) {
  76. this.className = className;
  77. }
  78. include(...fields: string[]) {
  79. this.whereOptions["include"] = fields;
  80. }
  81. greaterThan(key: string, value: any) {
  82. if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
  83. if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
  84. this.whereOptions["where"][key]["$gt"] = value;
  85. }
  86. greaterThanAndEqualTo(key: string, value: any) {
  87. if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
  88. if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
  89. this.whereOptions["where"][key]["$gte"] = value;
  90. }
  91. lessThan(key: string, value: any) {
  92. if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
  93. if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
  94. this.whereOptions["where"][key]["$lt"] = value;
  95. }
  96. lessThanAndEqualTo(key: string, value: any) {
  97. if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
  98. if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
  99. this.whereOptions["where"][key]["$lte"] = value;
  100. }
  101. equalTo(key: string, value: any) {
  102. if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
  103. this.whereOptions["where"][key] = value;
  104. return this;
  105. }
  106. async get(id: string) {
  107. const url = `http://dev.fmode.cn:1337/parse/classes/${this.className}/${id}?`;
  108. const response = await fetch(url, {
  109. headers: {
  110. "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
  111. "x-parse-application-id": "dev"
  112. },
  113. body: null,
  114. method: "GET",
  115. mode: "cors",
  116. credentials: "omit"
  117. });
  118. const json = await response?.json();
  119. return json || {};
  120. }
  121. async find(): Promise<Array<CloudObject>>{
  122. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
  123. // 构建查询字符串
  124. let queryStr = '';
  125. Object.keys(this.whereOptions).forEach(key => {
  126. let paramStr = JSON.stringify(this.whereOptions[key]);
  127. if (key === "include") {
  128. paramStr = this.whereOptions[key]?.join(","); // 将数组转换为逗号分隔字符串
  129. }
  130. // 添加查询参数到 URL
  131. if (queryStr) {
  132. url += `&${key}=${paramStr}`;
  133. } else {
  134. url += `${key}=${paramStr}`;
  135. }
  136. });
  137. const response = await fetch(url, {
  138. headers: {
  139. "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
  140. "x-parse-application-id": "dev"
  141. },
  142. body: null,
  143. method: "GET",
  144. mode: "cors",
  145. credentials: "omit"
  146. });
  147. const json = await response?.json();
  148. let list = json?.results || []
  149. let objList = list.map((item:any)=>this.dataToObj(item))
  150. return objList || [];
  151. }
  152. async first() {
  153. let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
  154. if (Object.keys(this.whereOptions).length) {
  155. const whereStr = JSON.stringify(this.whereOptions);
  156. url += `where=${whereStr}`;
  157. }
  158. const response = await fetch(url, {
  159. headers: {
  160. "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
  161. "x-parse-application-id": "dev"
  162. },
  163. body: null,
  164. method: "GET",
  165. mode: "cors",
  166. credentials: "omit"
  167. });
  168. const json = await response?.json();
  169. const exists = json?.results?.[0] || null;
  170. if (exists) {
  171. let existsObject = this.dataToObj(exists)
  172. return existsObject;
  173. }
  174. return null
  175. }
  176. //使得页面上获得的数据是由CloudObject构成的
  177. dataToObj(exists:any):CloudObject{
  178. let existsObject = new CloudObject(this.className);
  179. existsObject.set(exists);
  180. existsObject.id = exists.objectId;
  181. existsObject.createdAt = exists.createdAt;
  182. existsObject.updatedAt = exists.updatedAt;
  183. return existsObject;
  184. }
  185. }
  186. // CloudUser.ts
  187. export class CloudUser extends CloudObject {
  188. sessionToken: string | null = ""; // 用户的 sessionToken,用于身份验证
  189. constructor() {
  190. super("_User"); // 调用父类构造函数,指定类名为 "User"
  191. // 读取用户缓存信息
  192. let userCacheStr = localStorage.getItem("NCloud/dev/User");
  193. if (userCacheStr) {
  194. let userData = JSON.parse(userCacheStr);
  195. // 设置用户信息
  196. this.id = userData?.objectId; // 设置用户 ID
  197. this.sessionToken = userData?.sessionToken; // 设置 sessionToken
  198. this.data = userData; // 保存用户数据
  199. }
  200. }
  201. /** 获取当前用户信息 */
  202. async current() {
  203. // 检查用户是否登录
  204. if (!this.sessionToken) {
  205. console.error("用户未登录");
  206. return null; // 如果未登录,返回 null
  207. }
  208. return this;
  209. // // 发送 GET 请求以获取当前用户信息
  210. // const response = await fetch(`http://dev.fmode.cn:1337/parse/users/me`, {
  211. // headers: {
  212. // "x-parse-application-id": "dev",
  213. // "x-parse-session-token": this.sessionToken // 使用 sessionToken 进行身份验证
  214. // },
  215. // method: "GET"
  216. // });
  217. // const result = await response?.json(); // 解析响应
  218. // if (result?.error) {
  219. // console.error(result?.error); // 处理错误
  220. // return null;
  221. // }
  222. // return result; // 返回用户信息
  223. }
  224. /** 登录 */
  225. async login(username: string, password: string): Promise<CloudUser | null> {
  226. // 发送 POST 请求以进行用户登录
  227. const response = await fetch(`http://dev.fmode.cn:1337/parse/login`, {
  228. headers: {
  229. "x-parse-application-id": "dev",
  230. "Content-Type": "application/json"
  231. },
  232. body: JSON.stringify({ username, password }), // 登录凭据
  233. method: "POST"
  234. });
  235. const result = await response?.json(); // 解析响应
  236. if (result?.error) {
  237. console.error(result?.error); // 处理错误
  238. return null;
  239. }
  240. // 设置用户信息
  241. this.id = result?.objectId; // 设置用户 ID
  242. this.sessionToken = result?.sessionToken; // 设置 sessionToken
  243. this.data = result; // 保存用户数据
  244. // 缓存用户信息到 localStorage
  245. console.log(result);
  246. localStorage.setItem("NCloud/dev/User", JSON.stringify(result));
  247. return this; // 返回当前用户实例
  248. }
  249. /** 登出 */
  250. async logout() {
  251. // 检查用户是否登录
  252. if (!this.sessionToken) {
  253. console.error("用户未登录");
  254. return;
  255. }
  256. // 发送 POST 请求以进行用户登出
  257. const response = await fetch(`http://dev.fmode.cn:1337/parse/logout`, {
  258. headers: {
  259. "x-parse-application-id": "dev",
  260. "x-parse-session-token": this.sessionToken // 使用 sessionToken 进行身份验证
  261. },
  262. method: "POST"
  263. });
  264. const result = await response?.json(); // 解析响应
  265. if (result?.error) {
  266. console.error(result?.error); // 处理错误
  267. return false; // 登出失败
  268. }
  269. // 清除用户信息
  270. localStorage.removeItem("NCloud/dev/User"); // 从 localStorage 中移除用户信息
  271. this.id = null; // 清除用户 ID
  272. this.sessionToken = null; // 清除 sessionToken
  273. this.data = {}; // 清空用户数据
  274. return true; // 登出成功
  275. }
  276. /** 注册 */
  277. async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
  278. // 构建用户数据
  279. const userData = {
  280. username,
  281. password,
  282. ...additionalData // 合并额外的用户数据
  283. };
  284. // 发送 POST 请求以进行用户注册
  285. const response = await fetch(`http://dev.fmode.cn:1337/parse/users`, {
  286. headers: {
  287. "x-parse-application-id": "dev",
  288. "Content-Type": "application/json"
  289. },
  290. body: JSON.stringify(userData), // 注册凭据
  291. method: "POST"
  292. });
  293. const result = await response?.json(); // 解析响应
  294. if (result?.error) {
  295. console.error(result?.error); // 处理错误
  296. return null; // 注册失败
  297. }
  298. // 设置用户信息
  299. this.id = result?.objectId; // 设置用户 ID
  300. this.sessionToken = result?.sessionToken; // 设置 sessionToken
  301. this.data = result; // 保存用户数据
  302. return this; // 返回当前用户实例
  303. }
  304. //覆盖save方法
  305. override async save() {
  306. let method = "POST";
  307. let url = `http://dev.fmode.cn:1337/parse/users`;
  308. // 更新用户信息
  309. if (this.id) {
  310. url += `/${this.id}`;
  311. method = "PUT";
  312. }
  313. let data:any = JSON.parse(JSON.stringify(this.data))
  314. delete data.createdAt
  315. delete data.updatedAt
  316. delete data.ACL
  317. delete data.objectId
  318. const body = JSON.stringify(data);
  319. let headersOptions:any = {
  320. "content-type": "application/json;charset=UTF-8",
  321. "x-parse-application-id": "dev",
  322. "x-parse-session-token": this.sessionToken, // 添加sessionToken以进行身份验证
  323. }
  324. const response = await fetch(url, {
  325. headers: headersOptions,
  326. body: body,
  327. method: method,
  328. mode: "cors",
  329. credentials: "omit"
  330. });
  331. const result = await response?.json();
  332. if (result?.error) {
  333. console.error(result?.error);
  334. }
  335. if (result?.objectId) {
  336. this.id = result?.objectId;
  337. }
  338. localStorage.setItem("NCloud/dev/User",JSON.stringify(this.data))
  339. return this;
  340. }
  341. }
  342. //CloudPost.ts
  343. interface PostData {
  344. title: string; // 标题属性
  345. content: string; // 内容属性
  346. [key: string]: any; // 其他任意属性
  347. }
  348. export class CloudPost extends CloudObject {
  349. constructor() {
  350. super('FilmPost'); // 调用父类构造函数,指定类名
  351. }
  352. // 设置帖子数据,包括发布者信息
  353. setPostData(postData: PostData, userId: string | null) {
  354. // 确保 title 和 content 是必需的
  355. if (!postData.title || !postData.content) {
  356. throw new Error('Both title and content are required.');
  357. }
  358. this.set(postData); // 设置帖子内容
  359. this.data["author"] = { "__type": "Pointer", "className": "_User", "objectId": userId }; // 设置发布者信息
  360. }
  361. // 点赞帖子
  362. async likePost() {
  363. }
  364. // 更新帖子数据
  365. async updatePost(postData: PostData) {
  366. // 确保 title 和 content 是必需的
  367. if (!postData.title || !postData.content) {
  368. throw new Error('Both title and content are required.');
  369. }
  370. this.set(postData); // 更新帖子内容
  371. return await this.save(); // 保存更新
  372. }
  373. // 删除帖子
  374. async deletePost() {
  375. return await this.destroy(); // 调用父类的 destroy 方法
  376. }
  377. }
  378. // CloudComment.ts
  379. interface CommentData {
  380. content: string; // 评论内容
  381. postId: string; // 关联的帖子 ID
  382. [key: string]: any; // 其他任意属性
  383. }
  384. export class CloudComment extends CloudObject {
  385. constructor() {
  386. super('FilmPostComment'); // 调用父类构造函数,指定类名
  387. }
  388. // 设置评论数据,包括发布者和关联的帖子
  389. setCommentData(CommentData: CommentData, userId: string | null) {
  390. // 确保 title 和 content 是必需的
  391. if (!CommentData.postId || !CommentData.content) {
  392. throw new Error('Both post and content are required.');
  393. }
  394. this.set(CommentData); // 设置帖子内容
  395. this.data["user"] = { "__type": "Pointer", "className": "_User", "objectId": userId }; // 设置发布者信息
  396. this.data["post"] = { "__type": "Pointer", "className": "FilmPost", "objectId": CommentData.postId }; // 设置关联的帖子信息
  397. }
  398. // 创建评论
  399. async createComment(commentData: CommentData, userId: string | null) {
  400. this.setCommentData(commentData, userId);
  401. try {
  402. const savedComment = await this.save();
  403. return savedComment; // 返回保存的评论
  404. } catch (error) {
  405. console.error("Error creating comment:", error);
  406. throw error; // 重新抛出错误
  407. }
  408. }
  409. // 更新帖子评论计数
  410. async updatePostCommentCount(postId: string, increment: number) {
  411. const postQuery = new CloudQuery('FilmPost');
  412. const post = await postQuery.get(postId);
  413. if (!post) {
  414. console.error(`Post with ID ${postId} not found.`);
  415. throw new Error(`Post with ID ${postId} not found.`);
  416. }
  417. // 确保 post.data 存在 commentCount 属性
  418. if (typeof post.data["commentCount"] === 'undefined') {
  419. console.warn(`commentCount property is undefined for postId: ${postId}. Initializing to 0.`);
  420. post.data["commentCount"] = 0; // 初始化为 0
  421. }
  422. post.data["commentCount"] = Math.max((post.data["commentCount"] || 0) + increment, 0); // 更新评论计数
  423. const result = await post.save(); // 保存更新后的帖子
  424. console.log("Post updated successfully:", result);
  425. }
  426. // 更新评论
  427. async updateComment(commentData: CommentData) {
  428. if (!this.id) {
  429. throw new Error('Comment ID is required for updating.');
  430. }
  431. this.set(commentData); // 更新评论内容
  432. return await this.save(); // 保存更新
  433. }
  434. // 删除评论
  435. async deleteComment() {
  436. if (!this.id) {
  437. throw new Error('Comment ID is required for deletion.');
  438. }
  439. // 获取关联的帖子并更新评论计数
  440. return await this.destroy(); // 调用父类的 destroy 方法
  441. }
  442. // 查询评论
  443. async findComments(postId: string) {
  444. }
  445. }
  446. //CloudFeedback.ts
  447. interface FeedbackData {
  448. feedback: string; // 内容属性
  449. [key: string]: any; // 其他任意属性
  450. }
  451. export class CloudFeedback extends CloudObject {
  452. constructor() {
  453. super('FilmFeedback'); // 调用父类构造函数,指定类名
  454. }
  455. // 设置反馈数据,包括发布者信息
  456. setFeedbackData(feedbackData: FeedbackData, userId: string | null) {
  457. // 确保 feedback 是必需的
  458. if (!feedbackData.feedback) {
  459. throw new Error('feedback is required.');
  460. }
  461. this.set(feedbackData); // 设置帖子内容
  462. this.data["user"] = { "__type": "Pointer", "className": "_User", "objectId": userId }; // 设置发布者信息
  463. }
  464. // 更新帖子数据
  465. async updateFeedback(feedbackData: FeedbackData) {
  466. // 确保 feedback 是必需的
  467. if (!feedbackData.feedback) {
  468. throw new Error('feedback is required.');
  469. }
  470. this.set(feedbackData); // 更新反馈内容
  471. return await this.save(); // 保存更新
  472. }
  473. // 删除反馈
  474. async deleteFeedback() {
  475. return await this.destroy(); // 调用父类的 destroy 方法
  476. }
  477. }