import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http"; import { Inject, Injectable, InjectionToken } from "@angular/core"; import { AnyObject, OptionItemInterface, PageResult, ResponseType } from "@cdk/types"; import { format, addDays } from "date-fns"; import { Utils } from "@cdk/utils"; import { Observable, map, of, tap } from "rxjs"; import { PermItemDTO, UserDTO, UserRoleDTO, GlobalEnum, OrgDTO, ClientAccountDTO, AdminAccountDTO, OrgConfigDTO, CategoryDTO, NutrientDTO, } from "@cdk/public-api"; export const PROJECT_NAME = new InjectionToken("projectName"); @Injectable({ providedIn: "root", }) export class ApiService { constructor(private http: HttpClient, @Inject(PROJECT_NAME) public project: string) { this.initAccount(); } public account!: ClientAccountDTO; public adminAccount!: AdminAccountDTO; public accountKey = this.project === "admin" ? "CATERING_ADMIN_ACCOUNT" : "CATERING_CLIENT_ACCOUNT"; globalEnum!: GlobalEnum; // 能量、蛋白质、脂肪、碳水化合物、糖、钠/食盐、钙、铁、锌、维生素A、维生素B1、维生素B2、维生素C、膳食纤维 nutrientSort = new Map([ ["energy", { sort: 0 }], ["protein", { sort: 1 }], ["fat", { sort: 2 }], ["carbs", { sort: 3 }], ["sugar", { sort: 4 }], ["sodium", { sort: 5 }], ["calcium", { sort: 6 }], ["iron", { sort: 7 }], ["zinc", { sort: 8 }], ["va", { sort: 9 }], ["vb1", { sort: 10 }], ["vb2", { sort: 11 }], ["vc", { sort: 12 }], ["fiber", { sort: 13 }], ]); initAccount() { try { const stragedAccount = localStorage.getItem(this.accountKey); if (stragedAccount) { if (this.project === "admin") { this.adminAccount = JSON.parse(stragedAccount); } else { this.account = JSON.parse(stragedAccount); } } } catch (error) { console.error("获取用户信息失败", error); } } upload(data: FormData) { return this.http.put("/api/icon", data); } private _formatEnum(v: CategoryDTO[]): OptionItemInterface[] { return v.map((i) => ({ label: i.key, value: i.value })); } private _sortNutrient(n: NutrientDTO[]) { return n.map((i) => { return { ...i, ...this.nutrientSort.get(i.key) }; }); } getAllEnum(force?: boolean): Observable { if (this.globalEnum && !force) { return of(this.globalEnum); } return this.http.get>("/api/enum").pipe( map((res) => { return { ...res.body, mealType: this._formatEnum(res.body.mealType), menuStatus: this._formatEnum(res.body.menuStatus), nutrient: this._sortNutrient(res.body.nutrient), }; }), tap((r) => { this.globalEnum = r; }) ); } login(v: AnyObject) { v["admin"] = this.project === "admin"; const params = Utils.objectToHttpParams(v); return this.http.get("/api/login", { params }).pipe( tap((res) => { localStorage.setItem(this.accountKey, JSON.stringify(res.body)); this.initAccount(); }) ); } logout() { return this.http.get("/api/logout").pipe( tap((res) => { if (res.success) { localStorage.removeItem(this.accountKey); } }) ); } getOrgInfo() { return this.http.get("/api/vender/info").pipe( tap((res) => { this.account["vender"] = res.body; }) ); } getOrgConfig() { return this.http.get>("/api/vender/config"); } saveOrgConfig(config: AnyObject) { const body = Utils.objectToFormData(config); return this.http.post("/api/vender/config", body); } updatePassword(v: {}) { const body = Utils.objectToFormData(v); return this.http.post("/api/password", body); } getRoleList() { return this.http.get>("/api/role"); } deleteRole(roleId: string) { const params = new HttpParams().set("roleId", roleId); return this.http.delete("/api/role", { params, }); } updateRole(rule: AnyObject) { const body = Utils.objectToFormData(rule, true); const method = rule["roleId"] ? "post" : "put"; return this.http[method]("/api/role", body); } getRolePerms() { return this.http.get>("/api/role/item"); } getUserList() { return this.http.get>("/api/user"); } checkUid(uid: string) { const params = new HttpParams().set("uid", uid); return this.http.delete("/api/user/check", { params, }); } saveUser(user: AnyObject, edit: boolean) { const body = Utils.objectToFormData(user); const method = edit ? "post" : "put"; return this.http[method]("/api/user", body); } deleteUser(uid: string) { const params = new HttpParams().set("uid", uid); return this.http.delete("/api/user", { params, }); } getOrgList(query: { vendors?: number[]; keyword?: string }) { const q = Utils.objectStringify(query); return this.http.get>(`/api/vender/select?${q}`); } getOrgPage(p: {}, q: {}) { let params = Utils.objectStringify({ ...p, ...q }, { skipEmptyString: false, skipNull: false }); return this.http.get>>(`/api/vender?${params}`); } checkOrgAccount(account: string) { const params = new HttpParams().set("account", account); return this.http.get>("/api/vender/check/account", { params, }); } checkOrgName(name: string) { const params = new HttpParams().set("name", name); return this.http.get>("/api/vender/check/name", { params, }); } deleteOrg(id: number) { const params = Utils.objectToFormData({ venderId: id }); return this.http.delete("/api/vender", { body: params, }); } saveOrg(org: AnyObject) { const body = Utils.objectToFormData(org); const method = org["id"] ? "post" : "put"; return this.http[method]("/api/vender", body); } // getOrgConfig() { // return this.http.get("/api/vender/config"); // } getFoodPage(p: {}, q: {}) { const params = Utils.objectStringify({ ...p, ...q }); return this.http.get>(`/api/ingredient?${params}`).pipe( map((r) => { if (Array.isArray(r.body.content)) { r.body.content = r.body.content.map((o) => { return { ...o, nutrientArr: Object.entries(o.nutrient).map(([k, v]) => { const nutrient = this.globalEnum.nutrient.find((f) => f.key === k); return { key: k, value: v, label: nutrient?.value, measurement: nutrient?.measurement, }; }), }; }); } return r; }) ); } getFoodList(query: {}) { const q = Utils.objectStringify(query); return this.http.get>(`/api/ingredient/select?${q}`); } getFoodExcelTemplate() { return this.http.get("/api/ingredient/excel", { observe: "response", responseType: "blob" as "json" }).pipe( tap((res) => { this.downLoadFile(res); }) ); } downLoadFile(response: HttpResponse, defaultName = `${Date.now()}.xlsx`) { const fileNameFromHeader = response.headers.get("Content-Disposition"); if (fileNameFromHeader) { const fileName = fileNameFromHeader.trim()?.split("''")?.[1]?.replace(/"/g, "") ?? defaultName; const blob = new Blob([response.body as any]); const downloadLink = document.createElement("a"); downloadLink.href = URL.createObjectURL(blob); downloadLink.download = decodeURIComponent(fileName); document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); } } saveFood(food: AnyObject, isEdit?: boolean) { const body = Utils.objectToFormData(food); const method = isEdit ? "post" : "put"; return this.http[method]("/api/ingredient", body); } deleteFoods(ids: number[]) { const params = Utils.objectToFormData({ ingredients: ids.join(",") }); return this.http.delete(`/api/ingredient`, { body: params }); } importFood(f: FormData) { // return this.http.put("/api/ingredient/upload", f); return this.http .put("/api/ingredient/excel", f, { observe: "response", responseType: "blob" as "json", }) .pipe( tap((res) => { this.downLoadFile(res); }) ); } markFood(mark: string, key: string) { const params = Utils.objectToFormData({ mark, key }); return this.http.put("/api/ingredient/mark", params); } removeFoodMark(key: string) { const params = Utils.objectToFormData({ key }); return this.http.delete("/api/ingredient/mark", { body: params }); } getStandardPage(p: {}, q: {}) { const params = Utils.objectStringify({ ...p, ...q }); return this.http.get>(`/api/nutrition?${params}`).pipe( map((r) => { if (Array.isArray(r.body.content)) { r.body.content = r.body.content.map((o) => { return { ...o, people: Object.entries(o.ingredient ?? {}).map(([k, v]) => { return { peopleGroupName: k, ...((v as any) ?? {}), }; }), }; }); } return r; }) ); } getStandard(q: { id?: string; name?: string }) { const query = Utils.objectStringify(q); return this.http.get>(`/api/nutrition/select?${query}`); } saveStandard(v: AnyObject, isEdit?: boolean) { const body = Utils.objectToFormData({ ...v, vendors: v["vendors"]?.join(",") }); const method = v["id"] ? "post" : "put"; return this.http[method]("/api/nutrition", body); } deleteStandard(id: string) { const params = Utils.objectToFormData({ id }); return this.http.delete(`/api/nutrition`, { body: params }); } getDishPage(p: {}, q: {}) { const params = Utils.objectStringify({ ...p, ...q }); return this.http.get>(`/api/dish?${params}`).pipe( map((r) => { if (Array.isArray(r.body.content)) { // r.body.content = r.body.content.map((o) => { // return { // ...o, // foodArr: Object.entries(o.ingredient).map(([k, v]) => { // return { // key: k, // value: v, // label: k, // }; // }), // }; // }); } return r; }) ); } getDishLabel(ids: (string | number)[]) { const query = Utils.objectStringify({ ids }); return this.http.get>(`/api/dish/label?${query}`).pipe( map((res) => { return { ...res, body: res.body.map((i) => { return { ...i, component: (i.component as AnyObject[]) .map((c) => { return { ...c, ...this.nutrientSort.get(c["key"]), }; }) .sort((a, b) => a["sort"]! - b["sort"]!), }; }), }; }) ); } saveDish(v: AnyObject) { const body = Utils.objectToFormData(v); const method = v["id"] ? "post" : "put"; return this.http[method]("/api/dish", body); } deleteDish(ids: string[]) { const params = Utils.objectToFormData({ ids: ids.join(",") }); return this.http.delete(`/api/dish`, { body: params }); } getMenuStatusPage(p: {}, q: {}) { const params = Utils.objectStringify({ ...p, ...q }); return this.http.get>(`/api/menu/review?${params}`); } getMenuPage(p: {}, q: {}) { const params = Utils.objectStringify({ ...p, ...q }); return this.http.get>(`/api/menu?${params}`); } getMenuItem(id: string | number) { const params = Utils.objectStringify({ id }); return this.http.get(`/api/menu?${params}`); } getCountByStatus() { return this.http.get(`/api/menu/review/count`); } saveMenu(v: AnyObject) { const body = Utils.objectToFormData(v); const method = v["id"] ? "post" : "put"; return this.http[method]("/api/menu", body); } // 提交审核 submitMenuForReview(id: string | number) { const params = Utils.objectToFormData({ id }); return this.http.put(`/api/menu/review`, params); } disableMenu(id: string | number) { const params = Utils.objectToFormData({ id }); return this.http.delete(`/api/menu/review`, { body: params }); } reviewMenu(id: number, pass: boolean, reason?: string) { const params = Utils.objectToFormData({ id, pass, reason }); return this.http.post(`/api/menu/review`, params); } release(id: string | number, startTime: Date, amount: number) { const endTime = addDays(startTime, amount); const params = Utils.objectToFormData({ id, startTime: format(startTime, "yyyy-MM-dd"), endTime: format(endTime, "yyyy-MM-dd"), }); return this.http.put(`/api/menu/release`, params); } cancelRelease(id: string | number) { const params = Utils.objectToFormData({ id }); return this.http.delete(`/api/menu/release`, { body: params }); } deleteMenu(id: string | number) { const params = Utils.objectToFormData({ id }); return this.http.delete(`/api/menu`, { body: params }); } getMenuDist(menuId: number | string) { return this.http.get(`/api/menu/dish?menuId=${menuId}`); } saveMenuDist(d: {}) { return this.http.put(`/api/menu/dish/batch`, d); } getMenuReleasePage(p: {}, q: {}) { const params = Utils.objectStringify({ ...p, ...q }); return this.http.get>(`/api/menu/release?${params}`).pipe( map((res) => { if (Array.isArray(res.body.content)) { res.body.content = res.body.content.map((i) => ({ ...i, dateRange: `${format(new Date(i.startTime), "yyyy-MM-dd")}至${format(new Date(i.endTime), "yyyy-MM-dd")}`, })); } return res; }) ); } exportMenu(id: number | string) { return this.http .get(`/api/menu/dish/export?id=${id}`, { observe: "response", responseType: "blob" as "json", }) .pipe( tap((res) => { this.downLoadFile(res); }) ); } getAnalysis(id: number, day?: number, crow?: string) { const params = Utils.objectStringify({ id, day, crow }); return this.http.get(`/api/menu/analysis?${params}`); } getAnalysisEnergy(id: number, day?: number, crow?: string) { const params = Utils.objectStringify({ id, day, crow }); return this.http.get(`/api/menu/analysis/energy?${params}`); } getAnalysisRule(id: number, day?: number, crow?: string) { const params = Utils.objectStringify({ id, day, crow }); return this.http.get(`/api/menu/analysis/types?${params}`); } getMenuDataVis() { return this.http.get(`/api/menu/dish`); } }