解决跨域问题

This commit is contained in:
2026-09-01 13:32:03 +08:00
parent 5c459b29e1
commit 935df1d5e6
8 changed files with 506 additions and 522 deletions
+5 -15
View File
@@ -8,7 +8,6 @@
*/
/** ai-server 统一响应 */
import { request } from '../request/ai';
interface AiResp<T = any> {
code: number;
message: string;
@@ -181,22 +180,13 @@ export interface RecognizeResult {
materials_suggest: string[];
}
export function aiRecognize(content: string, deviceTags: string[] = []){
return request({
url: '/open/v1/moc/change/recognize',
method: 'post',
params: {
request_id: nextRequestId('rec'),
content,
device_tags: deviceTags
}
export function aiRecognize(content: string, deviceTags: string[] = []) {
return aiFetch<RecognizeResult>('/open/v1/moc/change/recognize', {
request_id: nextRequestId('rec'),
content,
device_tags: deviceTags
});
}
// aiFetch<RecognizeResult>('/open/v1/moc/change/recognize', {
// request_id: nextRequestId('rec'),
// content,
// device_tags: deviceTags
// });
+68 -68
View File
@@ -1,68 +1,68 @@
import { request } from '../request';
/** 变更预识别查询
*
*/
export function precheckApi(id: number) {
return request({
url: `/api/changes/${id}/precheck`,
method: 'get',
});
}
/**
* 变更预识别保存
*
*/
export function precheckSaveApi(params: {
change_id: number,
title: string,
description: string,
severity: string,
probability: string,
protection: string,
compare_rows: {item: string, before_text: string, after_text: string}[]
}) {
return request({
url: '/api/changes/precheck',
method: 'post',
data: params
});
}
/** 变更申请表查询
*
*/
export function applicationApi(id: number) {
return request({
url: `/api/changes/${id}/apply-form`,
method: 'get',
});
}
/**
* 变更申请表保存
*
*/
export function applicationSaveApi(id: number, params: {
change_type: number,
change_level: number,
duration_type: number,
restore_deadline: string,
org_id: number,
urgent: number,
purposes: string[],
effect: string,
main_changes: string[],
related_changes: string[],
materials: string,
update_docs: string[],
disciplines: string[],
manage_dept: string,
plan_use_date: string,
risk_tools: string[],
}) {
return request({
url: `/api/changes/${id}/apply-form`,
method: 'post',
data: params
});
}
import { request } from '../request';
/** 变更预识别查询
*
*/
export function precheckApi(id: number) {
return request({
url: `/api/changes/${id}/precheck`,
method: 'get',
});
}
/**
* 变更预识别保存
*
*/
export function precheckSaveApi(params: {
change_id: number,
title: string,
description: string,
severity: string,
probability: string,
protection: string,
compare_rows: {item: string, before_text: string, after_text: string}[]
}) {
return request({
url: '/api/changes/precheck',
method: 'post',
data: params
});
}
/** 变更申请表查询
*
*/
export function applicationApi(id: number) {
return request({
url: `/api/changes/${id}/apply-form`,
method: 'get',
});
}
/**
* 变更申请表保存
*
*/
export function applicationSaveApi(id: number, params: {
change_type: number,
change_level: number,
duration_type: number,
restore_deadline: string,
org_id: number,
urgent: number,
purposes: string[],
effect: string,
main_changes: string[],
related_changes: string[],
materials: string,
update_docs: string[],
disciplines: string[],
manage_dept: string,
plan_use_date: string,
risk_tools: string[],
}) {
return request({
url: `/api/changes/${id}/apply-form`,
method: 'post',
data: params
});
}
+96 -96
View File
@@ -1,96 +1,96 @@
import { request } from '../request';
// 获取配置
export function systemConfigApi() {
return request({
url: '/api/system-config',
method: 'get',
});
}
// 添加配置项
export function addSystemConfigApi(data:{group_key:string, label:string,color:string,remark?:string,value:string}) {
return request({
url: '/api/system-config',
method: 'post',
data,
});
}
// 编辑配置项
export function editSystemConfigApi(id:number, data:{group_key:string, label:string,color:string,remark?:string,value:string}) {
return request({
url: `/api/system-config/${id}`,
method: 'put',
data,
});
}
// 批量修改ai配置项和变更编号规则
export function updateConfigApi(data:{items:any[]}) {
return request({
url: '/api/system-config/batch',
method: 'put',
data,
});
}
// 删除配置项
export function deleteSystemConfigApi(id:number) {
return request({
url: `/api/system-config/${id}`,
method: 'delete',
});
}
// 审批模板列表
export function templateListApi() {
return request({
url: '/api/approval-templates',
method: 'get',
});
}
// 审批用户列表
export function peopleListApi() {
return request({
url: '/api/approval-flow/users',
method: 'get',
});
}
// 新增审批模板
export function addTemplateApi(data:any) {
return request({
url: '/api/approval-templates',
method: 'post',
data,
});
}
// 编辑审批模板
export function editTemplateApi(id:number,data:any) {
return request({
url: `/api/approval-templates/${id}`,
method: 'put',
data,
});
}
// 删除审批模板
export function deleteTemplateApi(id:number) {
return request({
url: `/api/approval-templates/${id}`,
method: 'delete',
});
}
// 获取风险矩阵配置
export function matrixConfigApi(bizType:string) {
return request({
url: `/api/risk-matrix/${bizType}`,
method: 'get',
});
}
// 保存风险矩阵配置
export function saveMatrixConfigApi(bizType:string,data:any) {
return request({
url: `/api/risk-matrix/${bizType}`,
method: 'put',
data,
});
}
import { request } from '../request';
// 获取配置
export function systemConfigApi() {
return request({
url: '/api/system-config',
method: 'get',
});
}
// 添加配置项
export function addSystemConfigApi(data:{group_key:string, label:string,color:string,remark?:string,value:string}) {
return request({
url: '/api/system-config',
method: 'post',
data,
});
}
// 编辑配置项
export function editSystemConfigApi(id:number, data:{group_key:string, label:string,color:string,remark?:string,value:string}) {
return request({
url: `/api/system-config/${id}`,
method: 'put',
data,
});
}
// 批量修改ai配置项和变更编号规则
export function updateConfigApi(data:{items:any[]}) {
return request({
url: '/api/system-config/batch',
method: 'put',
data,
});
}
// 删除配置项
export function deleteSystemConfigApi(id:number) {
return request({
url: `/api/system-config/${id}`,
method: 'delete',
});
}
// 审批模板列表
export function templateListApi() {
return request({
url: '/api/approval-templates',
method: 'get',
});
}
// 审批用户列表
export function peopleListApi() {
return request({
url: '/api/approval-flow/users',
method: 'get',
});
}
// 新增审批模板
export function addTemplateApi(data:any) {
return request({
url: '/api/approval-templates',
method: 'post',
data,
});
}
// 编辑审批模板
export function editTemplateApi(id:number,data:any) {
return request({
url: `/api/approval-templates/${id}`,
method: 'put',
data,
});
}
// 删除审批模板
export function deleteTemplateApi(id:number) {
return request({
url: `/api/approval-templates/${id}`,
method: 'delete',
});
}
// 获取风险矩阵配置
export function matrixConfigApi(bizType:string) {
return request({
url: `/api/risk-matrix/${bizType}`,
method: 'get',
});
}
// 保存风险矩阵配置
export function saveMatrixConfigApi(bizType:string,data:any) {
return request({
url: `/api/risk-matrix/${bizType}`,
method: 'put',
data,
});
}
+111 -111
View File
@@ -1,111 +1,111 @@
import { request } from '../request';
// 组织列表
export function orgListApi() {
return request({
url: '/api/organization/tree',
method: 'get',
});
}
// 新增组织
export function addOrgApi(params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) {
return request({
url: '/api/organization',
method: 'post',
data: params
});
}
// 编辑组织
export function editOrgApi(id: number, params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) {
return request({
url: `/api/organization/${id}`,
method: 'put',
data: params
});
}
// 删除组织
export function deleteOrgApi(id: number) {
return request({
url: `/api/organization/${id}`,
method: 'delete',
});
}
// 获取用户列表
export function userListApi(params: {org_id: number, keyword: string, page: number, limit: number }) {
return request({
url: '/api/user',
method: 'get',
params
});
}
// 新增用户
export function addUserApi(params: { real_name: string, username: string, gender: number, mobile?: string, email?: string, dept_ids: number[], role_id: number | null, org_ids: number[], enabled: boolean }) {
return request({
url: '/api/user',
method: 'post',
data: params
});
}
// 编辑用户
export function editUserApi(id: number, params: { real_name: string, username: string, gender: number, mobile?: string, email?: string, dept_ids: number[], role_id: number | null, org_ids: number[], enabled: boolean }) {
return request({
url: `/api/user/${id}`,
method: 'put',
data: params
});
}
// 删除用户
export function deleteUserApi(params: { id: number, type: number }) {
return request({
url: '/api/user/operation',
method: 'post',
data: params
});
}
// 重置数据权限
export function resetDataApi() {
return request({
url: `/api/user/reset-data-permission`,
method: 'post',
});
}
// 下载用户导入模板
export function downloadTemplateApi() {
return request({
url: `/api/user/template`,
method: 'get',
responseType: 'blob',
});
}
// 导入用户
export function importUserApi(params: FormData) {
return request({
url: `/api/user/import`,
method: 'post',
data: params
});
}
// 重置用户密码
export function resetPasswordApi(id: number) {
return request({
url: `/api/user/${id}/reset-password`,
method: 'post',
});
}
// 修改用户密码
export function changePasswordApi(params: { oldPassword: string, password: string }) {
return request({
url: `/api/user/change-password`,
method: 'post',
data: params
});
}
import { request } from '../request';
// 组织列表
export function orgListApi() {
return request({
url: '/api/organization/tree',
method: 'get',
});
}
// 新增组织
export function addOrgApi(params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) {
return request({
url: '/api/organization',
method: 'post',
data: params
});
}
// 编辑组织
export function editOrgApi(id: number, params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) {
return request({
url: `/api/organization/${id}`,
method: 'put',
data: params
});
}
// 删除组织
export function deleteOrgApi(id: number) {
return request({
url: `/api/organization/${id}`,
method: 'delete',
});
}
// 获取用户列表
export function userListApi(params: {org_id: number, keyword: string, page: number, limit: number }) {
return request({
url: '/api/user',
method: 'get',
params
});
}
// 新增用户
export function addUserApi(params: { real_name: string, username: string, gender: number, mobile?: string, email?: string, dept_ids: number[], role_id: number | null, org_ids: number[], enabled: boolean }) {
return request({
url: '/api/user',
method: 'post',
data: params
});
}
// 编辑用户
export function editUserApi(id: number, params: { real_name: string, username: string, gender: number, mobile?: string, email?: string, dept_ids: number[], role_id: number | null, org_ids: number[], enabled: boolean }) {
return request({
url: `/api/user/${id}`,
method: 'put',
data: params
});
}
// 删除用户
export function deleteUserApi(params: { id: number, type: number }) {
return request({
url: '/api/user/operation',
method: 'post',
data: params
});
}
// 重置数据权限
export function resetDataApi() {
return request({
url: `/api/user/reset-data-permission`,
method: 'post',
});
}
// 下载用户导入模板
export function downloadTemplateApi() {
return request({
url: `/api/user/template`,
method: 'get',
responseType: 'blob',
});
}
// 导入用户
export function importUserApi(params: FormData) {
return request({
url: `/api/user/import`,
method: 'post',
data: params
});
}
// 重置用户密码
export function resetPasswordApi(id: number) {
return request({
url: `/api/user/${id}/reset-password`,
method: 'post',
});
}
// 修改用户密码
export function changePasswordApi(params: { oldPassword: string, password: string }) {
return request({
url: `/api/user/change-password`,
method: 'post',
data: params
});
}
+124 -124
View File
@@ -1,124 +1,124 @@
import type { AxiosResponse } from 'axios';
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
import { useAuthStore } from '@/store/modules/auth';
import { getServiceAiURL } from '@/utils/service';
import { $t } from '@/locales';
import { getAiAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
import type { RequestInstanceState } from './type';
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceAiURL(import.meta.env, isHttpProxy);
export const request = createFlatRequest(
{
baseURL,
headers: {}
},
{
defaultState: {
errMsgStack: [],
refreshTokenPromise: null
} as RequestInstanceState,
transform(response: AxiosResponse<App.Service.Response<any>>) {
return response.data.data;
},
async onRequest(config) {
const Authorization = getAiAuthorization();
Object.assign(config.headers, { Authorization });
return config;
},
isBackendSuccess(response) {
// when the backend response code is "0000"(default), it means the request is success
// to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file
return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
},
async onBackendFail(response, instance) {
const authStore = useAuthStore();
const responseCode = String(response.data.code);
function handleLogout() {
authStore.resetStore();
}
function logoutAndCleanup() {
handleLogout();
window.removeEventListener('beforeunload', handleLogout);
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
}
// when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page
const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
if (logoutCodes.includes(responseCode)) {
handleLogout();
return null;
}
// when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
// prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout);
window.$dialog?.error({
title: $t('common.error'),
content: response.data.msg,
positiveText: $t('common.confirm'),
maskClosable: false,
closeOnEsc: false,
onPositiveClick() {
logoutAndCleanup();
},
onClose() {
logoutAndCleanup();
}
});
return null;
}
// when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token
// the api `refreshToken` can not return error code in `expiredTokenCodes`, otherwise it will be a dead loop, should return `logoutCodes` or `modalLogoutCodes`
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(responseCode)) {
const success = await handleExpiredRequest(request.state);
if (success) {
const Authorization = getAuthorization();
Object.assign(response.config.headers, { Authorization });
return instance.request(response.config) as Promise<AxiosResponse>;
}
}
return null;
},
onError(error) {
// when the request is fail, you can show error message
let message = error.message;
let backendErrorCode = '';
// get backend error message and code
if (error.code === BACKEND_ERROR_CODE) {
message = error.response?.data?.message || message;
backendErrorCode = String(error.response?.data?.code || '');
}
// the error message is displayed in the modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(backendErrorCode)) {
return;
}
// when the token is expired, refresh token and retry request, so no need to show error message
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(backendErrorCode)) {
return;
}
showErrorMsg(request.state, message);
}
}
);
import type { AxiosResponse } from 'axios';
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
import { useAuthStore } from '@/store/modules/auth';
import { getServiceAiURL } from '@/utils/service';
import { $t } from '@/locales';
import { getAiAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
import type { RequestInstanceState } from './type';
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceAiURL(import.meta.env, isHttpProxy);
export const request = createFlatRequest(
{
baseURL,
headers: {}
},
{
defaultState: {
errMsgStack: [],
refreshTokenPromise: null
} as RequestInstanceState,
transform(response: AxiosResponse<App.Service.Response<any>>) {
return response.data.data;
},
async onRequest(config) {
const Authorization = getAiAuthorization();
Object.assign(config.headers, { Authorization });
return config;
},
isBackendSuccess(response) {
// when the backend response code is "0000"(default), it means the request is success
// to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file
return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
},
async onBackendFail(response, instance) {
const authStore = useAuthStore();
const responseCode = String(response.data.code);
function handleLogout() {
authStore.resetStore();
}
function logoutAndCleanup() {
handleLogout();
window.removeEventListener('beforeunload', handleLogout);
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
}
// when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page
const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
if (logoutCodes.includes(responseCode)) {
handleLogout();
return null;
}
// when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
// prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout);
window.$dialog?.error({
title: $t('common.error'),
content: response.data.msg,
positiveText: $t('common.confirm'),
maskClosable: false,
closeOnEsc: false,
onPositiveClick() {
logoutAndCleanup();
},
onClose() {
logoutAndCleanup();
}
});
return null;
}
// when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token
// the api `refreshToken` can not return error code in `expiredTokenCodes`, otherwise it will be a dead loop, should return `logoutCodes` or `modalLogoutCodes`
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(responseCode)) {
const success = await handleExpiredRequest(request.state);
if (success) {
const Authorization = getAuthorization();
Object.assign(response.config.headers, { Authorization });
return instance.request(response.config) as Promise<AxiosResponse>;
}
}
return null;
},
onError(error) {
// when the request is fail, you can show error message
let message = error.message;
let backendErrorCode = '';
// get backend error message and code
if (error.code === BACKEND_ERROR_CODE) {
message = error.response?.data?.message || message;
backendErrorCode = String(error.response?.data?.code || '');
}
// the error message is displayed in the modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(backendErrorCode)) {
return;
}
// when the token is expired, refresh token and retry request, so no need to show error message
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(backendErrorCode)) {
return;
}
showErrorMsg(request.state, message);
}
}
);