feat: 🚀 订阅功能

This commit is contained in:
2025-09-16 16:38:30 +08:00
parent eb1b66a066
commit d3a3ef2911
456 changed files with 40544 additions and 124 deletions

View File

@@ -0,0 +1,3 @@
// 后端微服务模块前缀
export const PORT1 = "/api";
export const PORT2 = "/hooks";

View File

@@ -0,0 +1,47 @@
// ? 暂未使用,目前使用全局 Loading 来控制重复请求
import { CustomAxiosRequestConfig } from "../index";
import qs from "qs";
// 声明一个 Map 用于存储每个请求的标识 和 取消函数
let pendingMap = new Map<string, AbortController>();
// 序列化参数
export const getPendingUrl = (config: CustomAxiosRequestConfig) =>
[config.method, config.url, qs.stringify(config.data), qs.stringify(config.params)].join("&");
export class AxiosCanceler {
/**
* @description: 添加请求
* @param {Object} config
* @return void
*/
addPending(config: CustomAxiosRequestConfig) {
// 在请求开始前,对之前的请求做检查取消操作
this.removePending(config);
const url = getPendingUrl(config);
const controller = new AbortController();
config.signal = controller.signal;
pendingMap.set(url, controller);
}
/**
* @description: 移除请求
* @param {Object} config
*/
removePending(config: CustomAxiosRequestConfig) {
const url = getPendingUrl(config);
// 如果在 pending 中存在当前请求标识,需要取消当前请求
const controller = pendingMap.get(url);
controller && controller.abort();
}
/**
* @description: 清空所有pending
*/
removeAllPending() {
pendingMap.forEach(controller => {
controller && controller.abort();
});
pendingMap.clear();
}
}

View File

@@ -0,0 +1,43 @@
import { ElMessage } from "element-plus";
/**
* @description: 校验网络请求状态码
* @param {Number} status
* @return void
*/
export const checkStatus = (status: number) => {
switch (status) {
case 400:
ElMessage.error("请求失败!请您稍后重试");
break;
case 401:
ElMessage.error("登录失效!请您重新登录");
break;
case 403:
ElMessage.error("当前账号无权限访问!");
break;
case 404:
ElMessage.error("你所访问的资源不存在!");
break;
case 405:
ElMessage.error("请求方式错误!请您稍后重试");
break;
case 408:
ElMessage.error("请求超时!请您稍后重试");
break;
case 500:
ElMessage.error("服务异常!");
break;
case 502:
ElMessage.error("网关错误!");
break;
case 503:
ElMessage.error("服务不可用!");
break;
case 504:
ElMessage.error("网关超时!");
break;
default:
ElMessage.error("请求失败!");
}
};

125
src/api/index.ts Normal file
View File

@@ -0,0 +1,125 @@
import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse } from "axios";
//endLoading
import { showFullScreenLoading, tryHideFullScreenLoading } from "@/config/serviceLoading";
import { usePathUrl } from "@/hooks/usePathUrl";
import { ElMessage } from "element-plus";
import { ResultData } from "@/api/interface";
import { ResultEnum } from "@/enums/httpEnum";
import { checkStatus } from "./helper/checkStatus";
import { useUserStore } from "@/stores/modules/user";
import router from "@/routers";
//loading控制
export interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
noLoading?: boolean;
}
//计步器
// let setUp: number = 0;
const config = {
// 默认地址请求地址,可在 .env.** 文件中修改
baseURL: (import.meta.env.VITE_APP_API_BASEURL + import.meta.env.VITE_APP_API_VERSION) as string,
// 设置超时时间
timeout: ResultEnum.TIMEOUT as number,
// 跨域时候允许携带凭证
withCredentials: true
};
class RequestHttp {
service: AxiosInstance;
public constructor(config: AxiosRequestConfig) {
// instantiation
this.service = axios.create(config);
/**
* @description 请求拦截器
* 客户端发送请求 -> [请求拦截器] -> 服务器
* token校验(JWT) : 接受服务器返回的 token,存储到 vuex/pinia/本地储存当中
*/
this.service.interceptors.request.use(
(config: CustomAxiosRequestConfig) => {
const userStore = useUserStore();
// 当前请求不需要显示 loading在 api 服务中通过指定的第三个参数: { noLoading: true } 来控制
config.noLoading || showFullScreenLoading();
if (config.headers && typeof config.headers.set === "function") {
config.headers.set("authorization", `${"Bearer" + " " + userStore.newUserToken}`);
}
return config;
},
(error: AxiosError) => {
return Promise.reject(error);
}
);
/**
* @description 响应拦截器
* 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
*/
this.service.interceptors.response.use(
(response: AxiosResponse) => {
const { data } = response;
// const userStore = useUserStore();
tryHideFullScreenLoading();
// 登陆失效
if (data.code == 401) {
ElMessage.error(data.msg || data.message);
// getUcOffline();
location.href = usePathUrl();
return Promise.reject(data);
}
if (data.code === 504) {
ElMessage.error("请求超时!请您稍后重试");
}
//0正常,1非正常
if (data.code == 1) {
ElMessage.error(data.msg);
}
// 成功请求(在页面上除非特殊情况,否则不用处理失败逻辑)
return data;
},
async (error: AxiosError) => {
const { response } = error;
tryHideFullScreenLoading();
// 请求超时 && 网络错误单独判断,没有 response
if (error.message.indexOf("timeout") !== -1) ElMessage.error("请求超时!请您稍后重试");
if (error.message.indexOf("Network Error") !== -1) ElMessage.error("网络错误!请您稍后重试");
// 根据服务器响应的错误状态码,做不同的处理
if (response) {
checkStatus(response.status);
if (response.status === 401) {
location.href = usePathUrl();
}
}
// 服务器结果都没有返回(可能服务器错误可能客户端断网),断网处理:可以跳转到断网页面
if (!window.navigator.onLine) router.replace("/500");
return Promise.reject(error);
}
);
}
/**
* @description 常用请求方法封装
*/
get<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
return this.service.get(url, { params, ..._object });
}
post<T>(url: string, params?: object | string, _object = {}): Promise<ResultData<T>> {
return this.service.post(url, params, _object);
}
put<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
return this.service.put(url, params, _object);
}
delete<T>(url: string, params?: any, _object = {}): Promise<ResultData<T>> {
return this.service.delete(url, { params, ..._object });
}
download(url: string, params?: object, _object = {}): Promise<BlobPart> {
return this.service.post(url, params, { ..._object, responseType: "blob" });
}
}
export default new RequestHttp(config);

View File

@@ -0,0 +1,19 @@
// 全局模块
export namespace Global {
//供应链
export interface ResSupplier {
id: number;
code: string;
name: string;
disable: boolean;
}
//用户
export interface ResUserList {
id: number;
code: null;
name: string;
number: number;
disable: boolean;
}
}

View File

@@ -0,0 +1,7 @@
import { Global } from "./global";
import { User } from "./user";
import { Login } from "./login";
import { Result, ResultData } from "./result";
import { ResPage, ReqPage } from "./page";
import { Upload } from "./upload";
export type { Global, User, Login, ResultData, Result, ResPage, ReqPage, Upload };

View File

@@ -0,0 +1,61 @@
// 登录模块
export interface Dept {
id: number;
deptCode: string;
deptName: string;
managerId: null;
}
export namespace Login {
//登录要传的参数
export interface ReqLoginCode {
code: string;
}
//登录返回的参数
interface Dept {
id: number;
deptCode: string;
deptName: string;
managerId: null;
}
export interface ResLogin {
isSuccess: boolean;
message: string;
status: number;
data: {
accessToken: {
token: string;
phpToken: string;
tokenType: string;
refreshToken: string;
expired: string;
};
signedIn: boolean;
userInfo: {
seesionId: string;
ucId: number;
depts: Dept[];
staffId: number;
staff_code: string;
business_code: null;
avatar: null;
closed: number;
createdAt: string;
email: null;
mobile: string;
nickname: string;
roleId: string;
signinAt: string;
updatedAt: string;
companyId: number;
companyName: string;
orgId: number;
supplierId: null;
supplierName: null;
customerId: null;
customerName: null;
identity: number;
};
};
}
}

15
src/api/interface/page.ts Normal file
View File

@@ -0,0 +1,15 @@
//分页
import { Result } from "./result";
// 分页响应参数
export interface ResPage<T = any> extends Result {
data: {
list: T[];
total: number;
};
}
// 分页请求参数
export interface ReqPage {
pageNum: number;
size: number;
}

View File

@@ -0,0 +1,12 @@
// 请求响应参数不包含data
export interface Result {
isSuccess: boolean;
message: string;
status: number;
}
// 请求响应参数包含data
export interface ResultData<T = any> extends Result {
[x: string]: any;
data: T;
}

View File

@@ -0,0 +1,6 @@
// 文件上传模块
export namespace Upload {
export interface ResFileUrl {
fileUrl: string;
}
}

44
src/api/interface/user.ts Normal file
View File

@@ -0,0 +1,44 @@
// 用户管理模块
export namespace User {
// 获取组织list
export interface ResUserOrgs {
id: number;
orgCode: string;
name: string;
orgType: string;
standardCoin: string;
standardCoinId: number;
autoDetaultStockId: number;
disable: boolean;
}
export interface ResUserDept {
id: number;
name: string;
pid: number;
managerId: null;
disable: boolean;
children: ResUserDept[];
}
export interface ResWarehouse {
id: number;
name: string;
code: null;
contacts: string;
contactsId: number;
useOrgId: null;
customerWarehouseTag: boolean;
tempTransferWarehouse: number;
defaultReplenishCustomer: number;
customerId: number;
stockType: number;
disable: boolean;
}
//获取组织下的用户
export interface ResUserList {
id: number;
code: null;
name: string;
number: number;
disable: boolean;
}
}

View File

@@ -0,0 +1,25 @@
import http from "@/api";
import { ResPage } from "@/api/interface/index";
/**
* @name 防伪码模块
*/
//防伪码记录列表
export const getListApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SecurityNumber/GetGenerateRecordList`, params);
};
//生成防伪码
export const getGenerateSecurityNumberApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SecurityNumber/Generate`, params);
};
//防伪码下载列表 getDownListApi
export const getDownListApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SecurityNumber/GetList`, params);
};
//下载
export const getDownAllApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SecurityNumber/Export`, params);
};
//选择下载
export const getDownApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SecurityNumber/Export`, params);
};

110
src/api/modules/barCode.ts Normal file
View File

@@ -0,0 +1,110 @@
import http from "@/api";
import { ResPage } from "@/api/interface/index";
/**
* @name 打印产品条码模块
*/
//产品条码生成记录列表
export const getListApi = (params: Record<string, any>) => {
// console.log(params);
// return {
// isSuccess: true,
// message: "Success",
// status: 200,
// totalCount: 1,
// data: [
// {
// id: 17372,
// specifications: "ORICO-H7013-U3-AD-EU-BK-BP",
// materialNumber: "G01-43-552867",
// materialName: "7口USB3.0集线器",
// barCode: "6936761881968",
// purchaseBillNo: "ceshi1224",
// generateComplete: "已完成",
// number: 300,
// printNumber: 0,
// downLoadNumber: 300,
// useNumber: 2,
// creator: "admin",
// createTime: "2024-12-24 10:27:04",
// generateCompleteTime: "2024-12-24 10:27:05",
// supplierOrOrg: "深圳市元创时代科技有限公司",
// isUpdateMaterial: false,
// isTwo: 2
// }
// ]
// };
return http.post<ResPage<any>>(`SerialNumber/GetGenerateRecordList`, params);
};
//产品条码列表
export const getCodeListApi = (params: Record<string, any>) => {
// console.log(params);
// return {
// totalCount: 300,
// data: [
// {
// materialNumber: "G01-43-552867",
// materialName: "7口USB3.0集线器",
// specifications: "ORICO-H7013-U3-AD-EU-BK-BP",
// old_Specifications: "",
// barCode: "6936761881968",
// serialNumber: "10FC-616M3R",
// twoSerialNumber: "10FC-616M3R-two",
// numberCode: "241224000417",
// id: 202593401,
// number: 300,
// isUse: false,
// isUseStr: "否",
// box: "",
// creator: "admin",
// createTime: "2024-12-24 10:27:05",
// printNumber: 0,
// downLoadNumber: 1,
// printTime: "",
// downLoadTime: "2025-01-08 16:11:39",
// isEnablePrint: true
// },
// {
// materialNumber: "G01-43-552867",
// materialName: "7口USB3.0集线器",
// specifications: "ORICO-H7013-U3-AD-EU-BK-BP",
// old_Specifications: "",
// barCode: "6936761881968",
// serialNumber: "10FC-616M3Q",
// twoSerialNumber: "10FC-616M3R-two",
// numberCode: "241224000416",
// id: 202593400,
// number: 300,
// isUse: false,
// isUseStr: "否",
// box: "",
// creator: "admin",
// createTime: "2024-12-24 10:27:05",
// printNumber: 0,
// downLoadNumber: 1,
// printTime: "",
// downLoadTime: "2025-01-08 16:11:39",
// isEnablePrint: true
// }
// ],
// isSuccess: true,
// status: 200,
// message: "Success"
// };
return http.post<ResPage<any>>(`SerialNumber/GetList`, params);
};
//转换规格型号 SerialNumber/UpdateMaterial
export const getUpdateMaterialApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SerialNumber/UpdateMaterial`, params);
};
//产品条码列表下载
export const getSerialNumberDownLoadApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SerialNumber/Export`, params);
};
//生成条码
export const generateBarCodeApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SerialNumber/Generate`, params);
};
//打印
export const getPrintListCodeApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`SerialNumber/Print`, params);
};

View File

@@ -0,0 +1,48 @@
import http from "@/api";
import { ResPage } from "@/api/interface/index";
//箱信息列表
export const getListApi = (params: any) => {
return http.post<ResPage<any>>(`Box/GetList`, params);
};
//生成箱碼
export const getBoxGenerateApi = (params: any) => {
return http.post<ResPage<any>>(`Box/Generate`, params);
};
//裝箱保存
export const getSaveBoxApi = (params: any) => {
return http.post<ResPage<any>>(`Box/Save`, params, { noLoading: false });
};
//打印
export const getPrintBoxApi = (params: any) => {
return http.post<ResPage<any>>(`Box/Print`, params);
};
//刪除 /
export const getDeleteBoxApi = (params: any) => {
return http.post<ResPage<any>>(`Box/Delete`, params);
};
//清空
export const getClearBoxApi = (params: any) => {
return http.get<ResPage<any>>(`Box/Clear`, params);
};
//根据箱号获取箱信息
export const getBoxByNoApi = (params: any) => {
return http.get<ResPage<any>>(`Box/GetBoxByNo`, params, {
noLoading: true
});
};
//根据序列号获取序列号信息
export const getSerialNumberApi = (params: any) => {
return http.get<ResPage<any>>(`SerialNumber/Get`, params);
};
//根据箱号去获取序列号
export const getSerialNumberByBoxIdApi = (params: any) => {
return http.post<ResPage<any>>(`SerialNumber/GetByBoxId`, params, { noLoading: true });
};
//重新装箱
export const getBoxRestartApi = (params: any) => {
return http.post<ResPage<any>>(`Box/Restart`, params);
};
//开始装箱时间接口 Box/BeginCarton
export const getBeginCartonApi = (params: any) => {
return http.get<ResPage<any>>(`Box/BeginCarton`, params);
};

View File

@@ -0,0 +1,14 @@
//箱唛
import http from "@/api";
import { ResPage } from "@/api/interface/index";
//箱唛列表
export const getBoxMarkListApi = (params: Record<string, any>) => {
return http.post<ResPage<any>>(`BoxMark/GetList`, params);
};
//生成箱唛
export const getMaterialListApi = (params: any) => {
console.log(params);
// return http.get<any>(`SysConfig/GetMaterialList?speci=${encodeURIComponent(speci)}`);
return [];
};

View File

@@ -0,0 +1,9 @@
import http from "@/api";
// 导出列表
export const getListApi = (params: Record<string, any>) => {
return http.get<any>(`exports`, params);
};
//状态
export const getExportTypesApi = () => {
return http.get<any>(`export/types`);
};

View File

@@ -0,0 +1,10 @@
import http from "@/api";
/**
* @name 全局模块(在公司下面的数据)
*/
//物料分页列表
export const getMaterialListApi = (params: any) => {
return http.get<any>(`material`, params);
};

26
src/api/modules/global.ts Normal file
View File

@@ -0,0 +1,26 @@
import http from "@/api";
/**
* @name 全局模块(在公司下面的数据)
*/
//获取供应商
export const getSupplierApi = (params: any) => {
return http.get<any>(`basicinfo/suppliers`, params);
};
//組織
export const getOrgsApi = () => {
return http.get<any>(`basicinfo/orgs`);
};
//客戶
export const getCustomersApi = (params: any) => {
return http.get<any>(`basicinfo/customers`, params);
};
//用户(订阅账号)
export const getUsersApi = (params: any) => {
return http.get<any>(`user/list`, params);
};
//品线
export const getProductLinesApi = (params: any) => {
return http.get<any>(`basicinfo/productlines`, params);
};

View File

@@ -0,0 +1,18 @@
import http from "@/api";
/**
* @name 全局模块(在公司下面的数据)
*/
//质检单列表
export const getQualityInspectListApi = (params: any) => {
return http.get<any>(`quality_inspect`, params);
};
//刷新 /admapi/quality_inspect/reload
export const getQualityInspectReloadApi = (params: any) => {
return http.get<any>(`quality_inspect/reload`, params);
};
//导出
export const getQualityInspectExportApi = (params: any) => {
return http.get<any>(`quality_inspect/export`, params);
};

32
src/api/modules/login.ts Normal file
View File

@@ -0,0 +1,32 @@
import { ResultData, Login } from "@/api/interface/index";
// import authMenuList from "@/assets/json/authMenuList.json";
import http from "@/api";
/**
* @name 登录模块
*/
// 用户登录
export const loginApi = (params: Login.ReqLoginCode) => {
return http.get<ResultData<Login.ResLogin>>(`/user/signin/${params}`);
// 正常 post json 请求 ==> application/json
// return http.post<Login.ResLogin>(PORT1 + `/login`, params, { noLoading: true }); // 控制当前请求不显示 loading
// return http.post<Login.ResLogin>(PORT1 + `/login`, {}, { params }); // post 请求携带 query 参数 ==> ?username=admin&password=123456
// return http.post<Login.ResLogin>(PORT1 + `/login`, qs.stringify(params)); // post 请求携带表单参数 ==> application/x-www-form-urlencoded
// return http.get<Login.ResLogin>(PORT1 + `/login?${qs.stringify(params, { arrayFormat: "repeat" })}`); // get 请求可以携带数组等复杂参数
};
// 获取菜单列表
export const getAuthMenuListApi = () => {
console.log("触发了吗");
return http.get<any>(`/user/permissions`, {}, { noLoading: true });
// return authMenuList;
};
// 用户退出登录
export const logoutApi = () => {
return http.get(`/user/signout`);
};
// export const LoginOutSingleApi = () => {
// return http.get(`/Login/LoginOutSingle`);
// };

View File

@@ -0,0 +1,5 @@
import http from "@/api";
//按钮提交,通过请求接口来区分就可以了
export const operationButtonsApi = (url: string, params: any) => {
return http.post<any>(url, params);
};

View File

@@ -0,0 +1,23 @@
import http from "@/api";
//订阅信息单列表 /admapi/subscribe
export const getSubscribeListApi = (params: any) => {
return http.get<any>(`subscribe`, params);
};
//新增
export const getSubscribeAddApi = (params: any) => {
return http.post<any>(`subscribe`, params);
};
//详情
export const getSubscribeDetailsApi = (params: any) => {
return http.get<any>(`subscribe/${params}`);
};
//更新
export const getSubscribeUpdateApi = (id: any, params: any) => {
console.log(params, "=params=");
return http.post<any>(`subscribe/${id}`, params);
};
//删除
export const getSubscribeDelApi = (params: any) => {
return http.delete<any>(`subscribe/${params}`);
};

View File

@@ -0,0 +1,6 @@
import http from "@/api";
//获取客户下拉列表(纯客户信息 不包含组织信息)
export const getCustomersNoOrgApi = (id: any) => {
return http.get<any>(`SysConfig/GetCustomersNoOrg/${id}`);
};

48
src/api/modules/test.ts Normal file
View File

@@ -0,0 +1,48 @@
//测试
// import http from "@/api";
// import { ResPage } from "@/api/interface/index";
//列表
export const getBoxMarkListApi = () => {
return {
totalCount: 1,
isSuccess: true,
message: "Success",
status: 200,
data: [
{
id: 11573,
detailsId: 30059,
billNo: "RKRW00011573",
status: "部分入库",
sourceBillNo: "SCHB00054706",
type: "生产入库",
supplier: "",
org: "深圳市元创时代科技有限公司",
specifications: "",
materialNumber: "G01-11-579493",
materialName: "",
factoryPrice: 0,
stock: "wms仓库02",
accruedQty: 50,
receiveQty: 20,
realityQty: 20,
receiver: "尹芳丽wms",
receiveTime: "2025-08-13 17:45:39",
shelfer: "尹芳丽wms",
shelfTime: "2025-08-13 17:46:23",
remark: null,
createTime: "2025-08-13 15:12:30",
isRepeal: "否",
saleBillNo: " "
}
]
};
//http.post<ResPage<any>>(`BoxMark/GetList`, params);
};
// //生成箱唛
// export const getMaterialListApi = (speci: any) => {
// console.log(speci);
// // return http.get<any>(`SysConfig/GetMaterialList?speci=${encodeURIComponent(speci)}`);
// return [];
// };

18
src/api/modules/upload.ts Normal file
View File

@@ -0,0 +1,18 @@
import { Upload } from "@/api/interface/index";
import { PORT1 } from "@/api/config/servicePort";
import http from "@/api";
/**
* @name 文件上传模块
*/
// 图片上传
export const uploadImg = (formData: any) => {
//params: FormData
let url = import.meta.env.VITE_APP_API_BASEURL + import.meta.env.VITE_APP_API_VERSION + "/Upload?type=material&name=";
return http.post<any>(url, formData);
};
// 视频上传
export const uploadVideo = (params: FormData) => {
return http.post<Upload.ResFileUrl>(PORT1 + `/file/upload/video`, params);
};