解决跨域问题

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 统一响应 */ /** ai-server 统一响应 */
import { request } from '../request/ai';
interface AiResp<T = any> { interface AiResp<T = any> {
code: number; code: number;
message: string; message: string;
@@ -181,22 +180,13 @@ export interface RecognizeResult {
materials_suggest: string[]; materials_suggest: string[];
} }
export function aiRecognize(content: string, deviceTags: string[] = []){ export function aiRecognize(content: string, deviceTags: string[] = []) {
return request({ return aiFetch<RecognizeResult>('/open/v1/moc/change/recognize', {
url: '/open/v1/moc/change/recognize', request_id: nextRequestId('rec'),
method: 'post', content,
params: { device_tags: deviceTags
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'; import { request } from '../request';
/** 变更预识别查询 /** 变更预识别查询
* *
*/ */
export function precheckApi(id: number) { export function precheckApi(id: number) {
return request({ return request({
url: `/api/changes/${id}/precheck`, url: `/api/changes/${id}/precheck`,
method: 'get', method: 'get',
}); });
} }
/** /**
* 变更预识别保存 * 变更预识别保存
* *
*/ */
export function precheckSaveApi(params: { export function precheckSaveApi(params: {
change_id: number, change_id: number,
title: string, title: string,
description: string, description: string,
severity: string, severity: string,
probability: string, probability: string,
protection: string, protection: string,
compare_rows: {item: string, before_text: string, after_text: string}[] compare_rows: {item: string, before_text: string, after_text: string}[]
}) { }) {
return request({ return request({
url: '/api/changes/precheck', url: '/api/changes/precheck',
method: 'post', method: 'post',
data: params data: params
}); });
} }
/** 变更申请表查询 /** 变更申请表查询
* *
*/ */
export function applicationApi(id: number) { export function applicationApi(id: number) {
return request({ return request({
url: `/api/changes/${id}/apply-form`, url: `/api/changes/${id}/apply-form`,
method: 'get', method: 'get',
}); });
} }
/** /**
* 变更申请表保存 * 变更申请表保存
* *
*/ */
export function applicationSaveApi(id: number, params: { export function applicationSaveApi(id: number, params: {
change_type: number, change_type: number,
change_level: number, change_level: number,
duration_type: number, duration_type: number,
restore_deadline: string, restore_deadline: string,
org_id: number, org_id: number,
urgent: number, urgent: number,
purposes: string[], purposes: string[],
effect: string, effect: string,
main_changes: string[], main_changes: string[],
related_changes: string[], related_changes: string[],
materials: string, materials: string,
update_docs: string[], update_docs: string[],
disciplines: string[], disciplines: string[],
manage_dept: string, manage_dept: string,
plan_use_date: string, plan_use_date: string,
risk_tools: string[], risk_tools: string[],
}) { }) {
return request({ return request({
url: `/api/changes/${id}/apply-form`, url: `/api/changes/${id}/apply-form`,
method: 'post', method: 'post',
data: params data: params
}); });
} }
+96 -96
View File
@@ -1,96 +1,96 @@
import { request } from '../request'; import { request } from '../request';
// 获取配置 // 获取配置
export function systemConfigApi() { export function systemConfigApi() {
return request({ return request({
url: '/api/system-config', url: '/api/system-config',
method: 'get', method: 'get',
}); });
} }
// 添加配置项 // 添加配置项
export function addSystemConfigApi(data:{group_key:string, label:string,color:string,remark?:string,value:string}) { export function addSystemConfigApi(data:{group_key:string, label:string,color:string,remark?:string,value:string}) {
return request({ return request({
url: '/api/system-config', url: '/api/system-config',
method: 'post', method: 'post',
data, data,
}); });
} }
// 编辑配置项 // 编辑配置项
export function editSystemConfigApi(id:number, data:{group_key:string, label:string,color:string,remark?:string,value:string}) { export function editSystemConfigApi(id:number, data:{group_key:string, label:string,color:string,remark?:string,value:string}) {
return request({ return request({
url: `/api/system-config/${id}`, url: `/api/system-config/${id}`,
method: 'put', method: 'put',
data, data,
}); });
} }
// 批量修改ai配置项和变更编号规则 // 批量修改ai配置项和变更编号规则
export function updateConfigApi(data:{items:any[]}) { export function updateConfigApi(data:{items:any[]}) {
return request({ return request({
url: '/api/system-config/batch', url: '/api/system-config/batch',
method: 'put', method: 'put',
data, data,
}); });
} }
// 删除配置项 // 删除配置项
export function deleteSystemConfigApi(id:number) { export function deleteSystemConfigApi(id:number) {
return request({ return request({
url: `/api/system-config/${id}`, url: `/api/system-config/${id}`,
method: 'delete', method: 'delete',
}); });
} }
// 审批模板列表 // 审批模板列表
export function templateListApi() { export function templateListApi() {
return request({ return request({
url: '/api/approval-templates', url: '/api/approval-templates',
method: 'get', method: 'get',
}); });
} }
// 审批用户列表 // 审批用户列表
export function peopleListApi() { export function peopleListApi() {
return request({ return request({
url: '/api/approval-flow/users', url: '/api/approval-flow/users',
method: 'get', method: 'get',
}); });
} }
// 新增审批模板 // 新增审批模板
export function addTemplateApi(data:any) { export function addTemplateApi(data:any) {
return request({ return request({
url: '/api/approval-templates', url: '/api/approval-templates',
method: 'post', method: 'post',
data, data,
}); });
} }
// 编辑审批模板 // 编辑审批模板
export function editTemplateApi(id:number,data:any) { export function editTemplateApi(id:number,data:any) {
return request({ return request({
url: `/api/approval-templates/${id}`, url: `/api/approval-templates/${id}`,
method: 'put', method: 'put',
data, data,
}); });
} }
// 删除审批模板 // 删除审批模板
export function deleteTemplateApi(id:number) { export function deleteTemplateApi(id:number) {
return request({ return request({
url: `/api/approval-templates/${id}`, url: `/api/approval-templates/${id}`,
method: 'delete', method: 'delete',
}); });
} }
// 获取风险矩阵配置 // 获取风险矩阵配置
export function matrixConfigApi(bizType:string) { export function matrixConfigApi(bizType:string) {
return request({ return request({
url: `/api/risk-matrix/${bizType}`, url: `/api/risk-matrix/${bizType}`,
method: 'get', method: 'get',
}); });
} }
// 保存风险矩阵配置 // 保存风险矩阵配置
export function saveMatrixConfigApi(bizType:string,data:any) { export function saveMatrixConfigApi(bizType:string,data:any) {
return request({ return request({
url: `/api/risk-matrix/${bizType}`, url: `/api/risk-matrix/${bizType}`,
method: 'put', method: 'put',
data, data,
}); });
} }
+111 -111
View File
@@ -1,111 +1,111 @@
import { request } from '../request'; import { request } from '../request';
// 组织列表 // 组织列表
export function orgListApi() { export function orgListApi() {
return request({ return request({
url: '/api/organization/tree', url: '/api/organization/tree',
method: 'get', method: 'get',
}); });
} }
// 新增组织 // 新增组织
export function addOrgApi(params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) { export function addOrgApi(params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) {
return request({ return request({
url: '/api/organization', url: '/api/organization',
method: 'post', method: 'post',
data: params data: params
}); });
} }
// 编辑组织 // 编辑组织
export function editOrgApi(id: number, params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) { export function editOrgApi(id: number, params: { label: string, parent_id: number, sort: number, is_bottom: number, org_code: string }) {
return request({ return request({
url: `/api/organization/${id}`, url: `/api/organization/${id}`,
method: 'put', method: 'put',
data: params data: params
}); });
} }
// 删除组织 // 删除组织
export function deleteOrgApi(id: number) { export function deleteOrgApi(id: number) {
return request({ return request({
url: `/api/organization/${id}`, url: `/api/organization/${id}`,
method: 'delete', method: 'delete',
}); });
} }
// 获取用户列表 // 获取用户列表
export function userListApi(params: {org_id: number, keyword: string, page: number, limit: number }) { export function userListApi(params: {org_id: number, keyword: string, page: number, limit: number }) {
return request({ return request({
url: '/api/user', url: '/api/user',
method: 'get', method: 'get',
params 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 }) { 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({ return request({
url: '/api/user', url: '/api/user',
method: 'post', method: 'post',
data: params 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 }) { 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({ return request({
url: `/api/user/${id}`, url: `/api/user/${id}`,
method: 'put', method: 'put',
data: params data: params
}); });
} }
// 删除用户 // 删除用户
export function deleteUserApi(params: { id: number, type: number }) { export function deleteUserApi(params: { id: number, type: number }) {
return request({ return request({
url: '/api/user/operation', url: '/api/user/operation',
method: 'post', method: 'post',
data: params data: params
}); });
} }
// 重置数据权限 // 重置数据权限
export function resetDataApi() { export function resetDataApi() {
return request({ return request({
url: `/api/user/reset-data-permission`, url: `/api/user/reset-data-permission`,
method: 'post', method: 'post',
}); });
} }
// 下载用户导入模板 // 下载用户导入模板
export function downloadTemplateApi() { export function downloadTemplateApi() {
return request({ return request({
url: `/api/user/template`, url: `/api/user/template`,
method: 'get', method: 'get',
responseType: 'blob', responseType: 'blob',
}); });
} }
// 导入用户 // 导入用户
export function importUserApi(params: FormData) { export function importUserApi(params: FormData) {
return request({ return request({
url: `/api/user/import`, url: `/api/user/import`,
method: 'post', method: 'post',
data: params data: params
}); });
} }
// 重置用户密码 // 重置用户密码
export function resetPasswordApi(id: number) { export function resetPasswordApi(id: number) {
return request({ return request({
url: `/api/user/${id}/reset-password`, url: `/api/user/${id}/reset-password`,
method: 'post', method: 'post',
}); });
} }
// 修改用户密码 // 修改用户密码
export function changePasswordApi(params: { oldPassword: string, password: string }) { export function changePasswordApi(params: { oldPassword: string, password: string }) {
return request({ return request({
url: `/api/user/change-password`, url: `/api/user/change-password`,
method: 'post', method: 'post',
data: params data: params
}); });
} }
+124 -124
View File
@@ -1,124 +1,124 @@
import type { AxiosResponse } from 'axios'; import type { AxiosResponse } from 'axios';
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios'; import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
import { useAuthStore } from '@/store/modules/auth'; import { useAuthStore } from '@/store/modules/auth';
import { getServiceAiURL } from '@/utils/service'; import { getServiceAiURL } from '@/utils/service';
import { $t } from '@/locales'; import { $t } from '@/locales';
import { getAiAuthorization, handleExpiredRequest, showErrorMsg } from './shared'; import { getAiAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
import type { RequestInstanceState } from './type'; import type { RequestInstanceState } from './type';
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y'; const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceAiURL(import.meta.env, isHttpProxy); const { baseURL } = getServiceAiURL(import.meta.env, isHttpProxy);
export const request = createFlatRequest( export const request = createFlatRequest(
{ {
baseURL, baseURL,
headers: {} headers: {}
}, },
{ {
defaultState: { defaultState: {
errMsgStack: [], errMsgStack: [],
refreshTokenPromise: null refreshTokenPromise: null
} as RequestInstanceState, } as RequestInstanceState,
transform(response: AxiosResponse<App.Service.Response<any>>) { transform(response: AxiosResponse<App.Service.Response<any>>) {
return response.data.data; return response.data.data;
}, },
async onRequest(config) { async onRequest(config) {
const Authorization = getAiAuthorization(); const Authorization = getAiAuthorization();
Object.assign(config.headers, { Authorization }); Object.assign(config.headers, { Authorization });
return config; return config;
}, },
isBackendSuccess(response) { isBackendSuccess(response) {
// when the backend response code is "0000"(default), it means the request is success // 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 // 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; return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
}, },
async onBackendFail(response, instance) { async onBackendFail(response, instance) {
const authStore = useAuthStore(); const authStore = useAuthStore();
const responseCode = String(response.data.code); const responseCode = String(response.data.code);
function handleLogout() { function handleLogout() {
authStore.resetStore(); authStore.resetStore();
} }
function logoutAndCleanup() { function logoutAndCleanup() {
handleLogout(); handleLogout();
window.removeEventListener('beforeunload', handleLogout); window.removeEventListener('beforeunload', handleLogout);
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg); 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 // 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(',') || []; const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
if (logoutCodes.includes(responseCode)) { if (logoutCodes.includes(responseCode)) {
handleLogout(); handleLogout();
return null; return null;
} }
// when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal // 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(',') || []; const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) { if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg]; request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
// prevent the user from refreshing the page // prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout); window.addEventListener('beforeunload', handleLogout);
window.$dialog?.error({ window.$dialog?.error({
title: $t('common.error'), title: $t('common.error'),
content: response.data.msg, content: response.data.msg,
positiveText: $t('common.confirm'), positiveText: $t('common.confirm'),
maskClosable: false, maskClosable: false,
closeOnEsc: false, closeOnEsc: false,
onPositiveClick() { onPositiveClick() {
logoutAndCleanup(); logoutAndCleanup();
}, },
onClose() { onClose() {
logoutAndCleanup(); logoutAndCleanup();
} }
}); });
return null; return null;
} }
// when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token // 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` // 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(',') || []; const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(responseCode)) { if (expiredTokenCodes.includes(responseCode)) {
const success = await handleExpiredRequest(request.state); const success = await handleExpiredRequest(request.state);
if (success) { if (success) {
const Authorization = getAuthorization(); const Authorization = getAuthorization();
Object.assign(response.config.headers, { Authorization }); Object.assign(response.config.headers, { Authorization });
return instance.request(response.config) as Promise<AxiosResponse>; return instance.request(response.config) as Promise<AxiosResponse>;
} }
} }
return null; return null;
}, },
onError(error) { onError(error) {
// when the request is fail, you can show error message // when the request is fail, you can show error message
let message = error.message; let message = error.message;
let backendErrorCode = ''; let backendErrorCode = '';
// get backend error message and code // get backend error message and code
if (error.code === BACKEND_ERROR_CODE) { if (error.code === BACKEND_ERROR_CODE) {
message = error.response?.data?.message || message; message = error.response?.data?.message || message;
backendErrorCode = String(error.response?.data?.code || ''); backendErrorCode = String(error.response?.data?.code || '');
} }
// the error message is displayed in the modal // the error message is displayed in the modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || []; const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(backendErrorCode)) { if (modalLogoutCodes.includes(backendErrorCode)) {
return; return;
} }
// when the token is expired, refresh token and retry request, so no need to show error message // 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(',') || []; const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(backendErrorCode)) { if (expiredTokenCodes.includes(backendErrorCode)) {
return; return;
} }
showErrorMsg(request.state, message); showErrorMsg(request.state, message);
} }
} }
); );
-8
View File
@@ -42,7 +42,6 @@ declare module 'vue' {
NCascader: typeof import('naive-ui')['NCascader'] NCascader: typeof import('naive-ui')['NCascader']
NCheckbox: typeof import('naive-ui')['NCheckbox'] NCheckbox: typeof import('naive-ui')['NCheckbox']
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup'] NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
NCol: typeof import('naive-ui')['NCol']
NColorPicker: typeof import('naive-ui')['NColorPicker'] NColorPicker: typeof import('naive-ui')['NColorPicker']
NDataTable: typeof import('naive-ui')['NDataTable'] NDataTable: typeof import('naive-ui')['NDataTable']
NDatePicker: typeof import('naive-ui')['NDatePicker'] NDatePicker: typeof import('naive-ui')['NDatePicker']
@@ -57,7 +56,6 @@ declare module 'vue' {
NFormItemGi: typeof import('naive-ui')['NFormItemGi'] NFormItemGi: typeof import('naive-ui')['NFormItemGi']
NGi: typeof import('naive-ui')['NGi'] NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid'] NGrid: typeof import('naive-ui')['NGrid']
NIcon: typeof import('naive-ui')['NIcon']
NInput: typeof import('naive-ui')['NInput'] NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup'] NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputNumber: typeof import('naive-ui')['NInputNumber'] NInputNumber: typeof import('naive-ui')['NInputNumber']
@@ -65,7 +63,6 @@ declare module 'vue' {
NMenu: typeof import('naive-ui')['NMenu'] NMenu: typeof import('naive-ui')['NMenu']
NMessageProvider: typeof import('naive-ui')['NMessageProvider'] NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal'] NModal: typeof import('naive-ui')['NModal']
NNInput: typeof import('naive-ui')['NNInput']
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider'] NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
NPagination: typeof import('naive-ui')['NPagination'] NPagination: typeof import('naive-ui')['NPagination']
NPopconfirm: typeof import('naive-ui')['NPopconfirm'] NPopconfirm: typeof import('naive-ui')['NPopconfirm']
@@ -73,7 +70,6 @@ declare module 'vue' {
NProgress: typeof import('naive-ui')['NProgress'] NProgress: typeof import('naive-ui')['NProgress']
NRadio: typeof import('naive-ui')['NRadio'] NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup'] NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NRow: typeof import('naive-ui')['NRow']
NScrollbar: typeof import('naive-ui')['NScrollbar'] NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect'] NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace'] NSpace: typeof import('naive-ui')['NSpace']
@@ -135,7 +131,6 @@ declare global {
const NCascader: typeof import('naive-ui')['NCascader'] const NCascader: typeof import('naive-ui')['NCascader']
const NCheckbox: typeof import('naive-ui')['NCheckbox'] const NCheckbox: typeof import('naive-ui')['NCheckbox']
const NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup'] const NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
const NCol: typeof import('naive-ui')['NCol']
const NColorPicker: typeof import('naive-ui')['NColorPicker'] const NColorPicker: typeof import('naive-ui')['NColorPicker']
const NDataTable: typeof import('naive-ui')['NDataTable'] const NDataTable: typeof import('naive-ui')['NDataTable']
const NDatePicker: typeof import('naive-ui')['NDatePicker'] const NDatePicker: typeof import('naive-ui')['NDatePicker']
@@ -150,7 +145,6 @@ declare global {
const NFormItemGi: typeof import('naive-ui')['NFormItemGi'] const NFormItemGi: typeof import('naive-ui')['NFormItemGi']
const NGi: typeof import('naive-ui')['NGi'] const NGi: typeof import('naive-ui')['NGi']
const NGrid: typeof import('naive-ui')['NGrid'] const NGrid: typeof import('naive-ui')['NGrid']
const NIcon: typeof import('naive-ui')['NIcon']
const NInput: typeof import('naive-ui')['NInput'] const NInput: typeof import('naive-ui')['NInput']
const NInputGroup: typeof import('naive-ui')['NInputGroup'] const NInputGroup: typeof import('naive-ui')['NInputGroup']
const NInputNumber: typeof import('naive-ui')['NInputNumber'] const NInputNumber: typeof import('naive-ui')['NInputNumber']
@@ -158,7 +152,6 @@ declare global {
const NMenu: typeof import('naive-ui')['NMenu'] const NMenu: typeof import('naive-ui')['NMenu']
const NMessageProvider: typeof import('naive-ui')['NMessageProvider'] const NMessageProvider: typeof import('naive-ui')['NMessageProvider']
const NModal: typeof import('naive-ui')['NModal'] const NModal: typeof import('naive-ui')['NModal']
const NNInput: typeof import('naive-ui')['NNInput']
const NNotificationProvider: typeof import('naive-ui')['NNotificationProvider'] const NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
const NPagination: typeof import('naive-ui')['NPagination'] const NPagination: typeof import('naive-ui')['NPagination']
const NPopconfirm: typeof import('naive-ui')['NPopconfirm'] const NPopconfirm: typeof import('naive-ui')['NPopconfirm']
@@ -166,7 +159,6 @@ declare global {
const NProgress: typeof import('naive-ui')['NProgress'] const NProgress: typeof import('naive-ui')['NProgress']
const NRadio: typeof import('naive-ui')['NRadio'] const NRadio: typeof import('naive-ui')['NRadio']
const NRadioGroup: typeof import('naive-ui')['NRadioGroup'] const NRadioGroup: typeof import('naive-ui')['NRadioGroup']
const NRow: typeof import('naive-ui')['NRow']
const NScrollbar: typeof import('naive-ui')['NScrollbar'] const NScrollbar: typeof import('naive-ui')['NScrollbar']
const NSelect: typeof import('naive-ui')['NSelect'] const NSelect: typeof import('naive-ui')['NSelect']
const NSpace: typeof import('naive-ui')['NSpace'] const NSpace: typeof import('naive-ui')['NSpace']
+98 -98
View File
@@ -1,98 +1,98 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
import { useRouterPush } from '@/hooks/common/router'; import { useRouterPush } from '@/hooks/common/router';
import { changePasswordApi } from '@/service/api/user'; import { changePasswordApi } from '@/service/api/user';
const appStore = useAppStore(); const appStore = useAppStore();
const themeStore = useThemeStore(); const themeStore = useThemeStore();
const { toLogin } = useRouterPush(); const { toLogin } = useRouterPush();
const gap = computed(() => (appStore.isMobile ? 0 : 16)); const gap = computed(() => (appStore.isMobile ? 0 : 16));
const formModel = ref<{oldPassword: string;password: string;confirmPassword: string;}>({ const formModel = ref<{oldPassword: string;password: string;confirmPassword: string;}>({
oldPassword: '', oldPassword: '',
password: '', password: '',
confirmPassword: '', confirmPassword: '',
}); });
const rules = { const rules = {
oldPassword: [{ required: true, message: '请输入旧密码', trigger: ['blur'] }], oldPassword: [{ required: true, message: '请输入旧密码', trigger: ['blur'] }],
password: [{ required: true, message: '请输入新密码', trigger: ['blur'] }], password: [{ required: true, message: '请输入新密码', trigger: ['blur'] }],
confirmPassword: [{ validator: (rule: any, value: string, callback: any) => { confirmPassword: [{ validator: (rule: any, value: string, callback: any) => {
if (value !== formModel.value.password) { if (value !== formModel.value.password) {
callback(new Error('两次输入密码不一致')); callback(new Error('两次输入密码不一致'));
} else { } else {
callback(); callback();
} }
}, required: true, message: '两次输入密码不一致', trigger: ['blur'] }], }, required: true, message: '两次输入密码不一致', trigger: ['blur'] }],
} }
const formRef = ref<any>(null); const formRef = ref<any>(null);
const btnLoading = ref<boolean>(false); const btnLoading = ref<boolean>(false);
const submitForm = async (e: MouseEvent) => { const submitForm = async (e: MouseEvent) => {
e.preventDefault() e.preventDefault()
formRef.value?.validate(async (errors: any) => { formRef.value?.validate(async (errors: any) => {
if (!errors) { if (!errors) {
btnLoading.value = true; btnLoading.value = true;
const {error} = await changePasswordApi({ const {error} = await changePasswordApi({
oldPassword: formModel.value.oldPassword, oldPassword: formModel.value.oldPassword,
password: formModel.value.password, password: formModel.value.password,
}); });
if(!error){ if(!error){
window.$message?.success('修改成功') window.$message?.success('修改成功')
toLogin(); toLogin();
} }
btnLoading.value = false; btnLoading.value = false;
} }
}) })
} }
onMounted(() => { onMounted(() => {
}) })
</script> </script>
<template> <template>
<NSpace vertical :size="16"> <NSpace vertical :size="16">
<!-- 修改密码 --> <!-- 修改密码 -->
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }"> <NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
<div class="border mb-3 py-2 px-3" :style="{ borderRadius: themeStore.themeRadius + 'px' }"> <div class="border mb-3 py-2 px-3" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive> <NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
<NGi span="24 s:24 m:24"> <NGi span="24 s:24 m:24">
<div class="h-100% flex items-center gap-2"> <div class="h-100% flex items-center gap-2">
<Icon icon="boxicons:lock-open" class="size-16px" :style="{ color: themeStore.themeColor }" /> <Icon icon="boxicons:lock-open" class="size-16px" :style="{ color: themeStore.themeColor }" />
<p class="text-[16px] font-600">修改密码</p> <p class="text-[16px] font-600">修改密码</p>
</div> </div>
</NGi> </NGi>
</NGrid> </NGrid>
</div> </div>
<div class="scroll"> <div class="scroll">
<div class="mt-5 max-w-[800px] mx-auto"> <div class="mt-5 max-w-[800px] mx-auto">
<NForm ref="formRef" :model="formModel" :rules="rules"> <NForm ref="formRef" :model="formModel" :rules="rules">
<NFormItem path="oldPassword" label="旧密码"> <NFormItem path="oldPassword" label="旧密码">
<NInput v-model:value="formModel.oldPassword" type="password" clearable show-password-on="click" placeholder="请输入旧密码" /> <NInput v-model:value="formModel.oldPassword" type="password" clearable show-password-on="click" placeholder="请输入旧密码" />
</NFormItem> </NFormItem>
<NFormItem path="password" label="新密码"> <NFormItem path="password" label="新密码">
<NInput v-model:value="formModel.password" type="password" clearable show-password-on="click" placeholder="请输入新密码" /> <NInput v-model:value="formModel.password" type="password" clearable show-password-on="click" placeholder="请输入新密码" />
</NFormItem> </NFormItem>
<NFormItem path="confirmPassword" label="确认密码"> <NFormItem path="confirmPassword" label="确认密码">
<NInput v-model:value="formModel.confirmPassword" type="password" clearable show-password-on="click" placeholder="请确认新密码" /> <NInput v-model:value="formModel.confirmPassword" type="password" clearable show-password-on="click" placeholder="请确认新密码" />
</NFormItem> </NFormItem>
</NForm> </NForm>
<NButton type="primary" block :loading="btnLoading" @click="submitForm">修改密码</NButton> <NButton type="primary" block :loading="btnLoading" @click="submitForm">修改密码</NButton>
</div> </div>
</div> </div>
</NCard> </NCard>
</NSpace> </NSpace>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.scroll { .scroll {
height: calc(100vh - 205px); height: calc(100vh - 205px);
overflow-y: auto; overflow-y: auto;
} }
</style> </style>
+4 -2
View File
@@ -37,9 +37,11 @@ export default defineConfig(configEnv => {
open: true, open: true,
proxy: { proxy: {
...createViteProxy(viteEnv, enableProxy), ...createViteProxy(viteEnv, enableProxy),
// ai-server OpenApi(本地 docker ai-server-ai-1:12333 // ai-server OpenApi:默认走线上映射域名(https://mocaiapi.djxinxi.net → 192.168.0.230:8085/proxy-ai/ → ai-server:12333
// 网关超时已调至 900s,长耗时接口可用;域名根路径已含 /proxy-ai 映射,故此处剥掉前缀)。
// 本地起 docker ai-server 联调时,用环境变量覆盖:AI_SERVER_URL=http://127.0.0.1:12333 pnpm dev
'/proxy-ai': { '/proxy-ai': {
target: process.env.AI_SERVER_URL || 'http://127.0.0.1:12333', target: process.env.AI_SERVER_URL || 'https://mocaiapi.djxinxi.net',
changeOrigin: true, changeOrigin: true,
rewrite: p => p.replace(/^\/proxy-ai/, '') rewrite: p => p.replace(/^\/proxy-ai/, '')
} }