fix: 第一版普遍修复完成。

This commit is contained in:
c
2026-03-21 15:56:53 +08:00
parent d88701f4ee
commit cc87985576
17 changed files with 218 additions and 93 deletions

View File

@@ -1,5 +1,5 @@
# 线上环境接口地址
VITE_API_URL = "/pro"
VITE_API_URL = "/api"
# 静态文件获取根路径
VITE_PUBLIC_PATH = "/"

View File

@@ -1,5 +1,5 @@
{
"name": "teek-design-vue3-template",
"name": "erp-frontend",
"version": "2.0.0",
"private": true,
"description": "牛安后台管理系统",

View File

@@ -21,7 +21,7 @@ export const UserService = {
},
checkIsLogined() {
return get("/open/check-login");
return get("/auth/check-login");
},
/**
@@ -29,12 +29,12 @@ export const UserService = {
* 用于前端页面刷新后检测当前token是否有效
*/
checkLogin() {
return get("/open/check-login");
return get("/auth/check-login");
},
// 获取用户信息
getUserInfo() {
return get("/auth/getUserInfo");
return get("/auth/check-login");
},
getDynamicRouter() {

View File

@@ -2,6 +2,7 @@ import { useUserStore } from "@/pinia";
import axios from "axios";
import type { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from "axios";
import { ElMessage } from "element-plus";
import { $t } from "@/common/languages";
// 创建 axios 实例
const service: AxiosInstance = axios.create({
@@ -24,7 +25,7 @@ service.interceptors.request.use(
return config;
},
error => {
ElMessage.error("请求发送失败");
ElMessage.error($t("_http.request_failed"));
return Promise.reject(error);
}
);
@@ -38,31 +39,34 @@ service.interceptors.response.use(
// 通常 code === 0 表示成功
if (res.code === 0) {
return res as any; // 直接返回业务数据
} else if (res.code === 3) {
ElMessage.error(res.msg || $t("_http.invalid_credentials"));
return Promise.reject(new Error(res.msg || $t("_http.invalid_credentials")));
} else {
ElMessage.error(res.msg || "请求失败");
ElMessage.error(res.msg || $t("_http.request_error"));
return Promise.reject(new Error(res.msg || "Error"));
}
},
error => {
// 处理网络错误或 HTTP 状态码非 2xx 的情况
let message = "网络异常";
let message = $t("_http.network_error");
const { isLogined } = storeToRefs(useUserStore());
if (error.response) {
const status = error.response.status;
switch (status) {
case 401:
message = "未登录或会话已过期,请重新登录";
message = $t("_http.unauthorized");
isLogined.value = false;
useRouter().push("/login");
break;
case 403:
message = "权限不足";
message = $t("_http.forbidden");
break;
case 500:
message = "服务器内部错误";
message = $t("_http.server_error");
break;
default:
message = `请求失败 ( $ {status})`;
message = $t("_http.request_failed_status", { status });
}
}
ElMessage.error(message);

View File

@@ -729,6 +729,12 @@ export default {
generate_order_error: "Generate Failed",
vendor_priority_tip: "Priority",
},
purchase_plan_item: {
input_partNumber: "Please enter part number",
input_purchaseCount: "Please enter plan count",
input_price: "Please enter price",
input_currentCount: "Please enter current count",
},
purchaseorder: {
delete_message: "Delete Order",
part_number_not_exists: "Part number does not exist",
@@ -917,9 +923,11 @@ export default {
tableTitle: "Purchase Details",
templateFileName: "Purchase Plan Template",
},
purchaseorder: {
purchase_order: {
add: "Add Purchase Order",
edit: "Edit Purchase Order",
inbound: "Purchase Inbound",
qrcode: "Print QR Code",
showItem: "Order Items",
baseTitle: "Purchase Order Basic Info",
tableTitle: "Order Details",
@@ -1235,5 +1243,16 @@ export default {
_status: {
in_progress: "In Progress",
completed: "Completed",
receipting: "Receipting",
},
_http: {
request_failed: "Request failed",
invalid_credentials: "Invalid username or password",
request_error: "Request error",
network_error: "Network error",
unauthorized: "Not logged in or session expired, please log in again",
forbidden: "Permission denied",
server_error: "Server internal error",
request_failed_status: "Request failed ({status})",
},
};

View File

@@ -760,6 +760,12 @@ export default {
generate_order_error: "生成采购订单失败",
vendor_priority_tip: "优先",
},
purchase_plan_item: {
input_partNumber: "请输入物料编号",
input_purchaseCount: "请输入计划数量",
input_price: "请输入单价",
input_currentCount: "请输入本次采购数量",
},
purchase_order: {
delete_message: "删除采购订单",
input_vendorName: "请选择供应商",
@@ -1008,6 +1014,9 @@ export default {
add: "新建采购计划",
edit: "编辑采购计划",
generateOrder: "生成采购订单",
showItem: "采购明细",
baseTitle: "采购计划基本信息",
tableTitle: "采购明细",
model: "型号",
defaultVendor: "默认供应商",
demandQuantity: "需求量",
@@ -1023,6 +1032,7 @@ export default {
edit: "编辑采购订单",
inbound: "采购入库",
qrcode: "二维码打印",
showItem: "采购明细",
baseTitle: "采购订单基本信息",
tableTitle: "采购明细",
templateFileName: "采购订单模板",
@@ -1337,5 +1347,16 @@ export default {
_status: {
in_progress: "入库中",
completed: "已完成",
receipting: "入库中",
},
_http: {
request_failed: "请求发送失败",
invalid_credentials: "用户名或密码错误",
request_error: "请求失败",
network_error: "网络异常",
unauthorized: "未登录或会话已过期,请重新登录",
forbidden: "权限不足",
server_error: "服务器内部错误",
request_failed_status: "请求失败 ({status})",
},
};

View File

@@ -218,6 +218,7 @@ watch(visible, newVal => {
width="450px"
:close-on-click-modal="false"
:close-on-press-escape="false"
:lock-scroll="false"
>
<div v-loading="loading" class="qrcode-container">
<div v-if="props.qrCodeList.length > 0" class="qrcode-list-container">

View File

@@ -59,33 +59,34 @@ export const useUserStore = defineStore(
};
const getUserInfo = async () => {
// 模拟获取用户信息
// return await UserService.getUserInfo().then(res => {
// setRoles(res.data.roles);
// setUserInfo(res.data);
// return res.data;
// });
const userInfo = await new Promise<UserInfo>(resolve => {
setTimeout(() => {
resolve({
userId: "v10001",
username: "Admin",
sex: "保密",
signature: "这个人很懒,什么都没有写",
email: "1234567890@qq.com",
phone: "1234567890",
avatar: "https://cdn.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png",
roles: ["admin"],
job: "开发工程师",
dept: "Teek 云科技技术部 - 智能全栈科",
registerTime: "2022-10-01 19:07:27",
});
}, 500);
return await UserService.getUserInfo().then(res => {
setRoles(res.data.roles);
setUserInfo(res.data.userInfo);
return res.data.userInfo;
});
setUserInfo(userInfo);
return userInfo;
// return {};
// const userInfo = await new Promise<UserInfo>(resolve => {
// setTimeout(() => {
// resolve({
// userId: "v10001",
// username: "Admin",
// sex: "保密",
// signature: "这个人很懒,什么都没有写",
// email: "1234567890@qq.com",
// phone: "1234567890",
// avatar: "https://cdn.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png",
// roles: ["admin"],
// job: "开发工程师",
// dept: "Teek 云科技技术部 - 智能全栈科",
// registerTime: "2022-10-01 19:07:27",
// });
// }, 500);
// });
// setUserInfo(userInfo);
// return userInfo;
};
/**

View File

@@ -53,16 +53,16 @@ const login = () => {
loading.value = true;
try {
// 执行登录
await userStore.login({ ...loginForm });
// if (!result) {
// ElNotification({
// title: getTimeState(),
// message: "登录失败,用户名或密码错误",
// type: "success",
// duration: 3000,
// });
// return;
// }
const result = await userStore.login({ ...loginForm });
if (!result) {
ElNotification({
title: getTimeState(),
message: "登录失败,用户名或密码错误",
type: "success",
duration: 3000,
});
return;
}
// 跳转到首页或者 URL 携带的 redirect 页(优先级高)
let path = HOME_URL;

View File

@@ -130,7 +130,7 @@ const operateButtonClick = (eventName: string, row: any) => {
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: ["商品编号", "partNumber"],
sourceKey: ["编号", "物料编号", "商品编号", "partNumber"],
header: $t("_prop.production.bom_item.partNumber"),
width: 20,
defaultValue: "",

View File

@@ -238,6 +238,8 @@ const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.status === 1 && button.eventName === "approve") return false;
// 已审核后不能编辑和删除
if (row.status === 1 && (button.eventName === "edit" || button.eventName === "remove")) return false;
// 退料按钮只在已审核状态下展示
if (button.eventName === "productionReturn" && row.status !== 1) return false;
return true;
};

View File

@@ -7,6 +7,7 @@ import { $t } from "@/common/languages";
import { ElMessage, ElMessageBox, type FormInstance, type FormItemRule, type FormRules } from "element-plus";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import QrCodeDialog from "@/components/base/base-qrcode/QrCodeDialog.vue";
@@ -29,12 +30,14 @@ const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.purchase.purchase_order.searchCode") },
{ name: "partNumber", type: "text" as const, placeholder: $t("_prop.purchase.purchase_order_item.partNumber") },
];
const getFormStatusLabel = (status: number) => {
const labels: Record<number, string> = {
0: $t("_status.in_progress"),
4: $t("_status.completed"),
5: $t("_status.receipting"),
};
return labels[status] ?? String(status);
};
@@ -60,7 +63,7 @@ const validatePartNumber = (rule: any, value: string, callback: (error?: Error)
};
const rules = reactive<FormRules>({
vendorName: [{ required: true, message: $t("_message.purchase.purchase_order.input_vendorName"), trigger: "blur" }],
vendorNo: [{ required: true, message: $t("_message.purchase.purchase_order.select_vendor"), trigger: "change" }],
partNumber: [
{
required: true,
@@ -97,7 +100,7 @@ const inboundForm = reactive({
orderCode: "",
vendorName: "",
formCode: "",
storeNo: null as number,
storeNo: null as number | null,
storeName: "",
formMark: "",
items: [] as any[],
@@ -106,6 +109,10 @@ const inboundForm = reactive({
const qrCodeVisible = ref(false);
const qrCodeData = ref<any[]>([]);
const showItemVisible = ref(false);
const showItemData = ref<any[]>([]);
const showItemRow = ref<any>(null);
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: "物料编号",
@@ -266,6 +273,11 @@ const showQrCode = async (row: any) => {
}
};
const showItem = (row: any) => {
showItemRow.value = row;
showItemVisible.value = true;
};
const submit = (formData: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
@@ -307,6 +319,9 @@ const operateButtonClick = (eventName: string, row: any) => {
case "printQrCode":
showQrCode(row);
break;
case "showItem":
showItem(row);
break;
}
};
@@ -368,6 +383,7 @@ const getFormStatusTagType = (code: number | null): string => {
:item-url="getItemsUrl"
item-id-key="id"
item-id-name="orderId"
item-field-name="items"
>
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
@@ -434,9 +450,9 @@ const getFormStatusTagType = (code: number | null): string => {
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="$t('_prop.purchase.purchase_order.vendorName')" prop="vendorName">
<el-form-item :label="$t('_prop.purchase.purchase_order.vendorName')" prop="vendorNo">
<BaseSelect
v-model="form.vendorName"
v-model="form.vendorNo"
:url="getVendorSelectListUrl"
ref="vendorSelectRef"
:placeholder="$t('_message.purchase.purchase_order.select_vendor')"
@@ -580,4 +596,39 @@ const getFormStatusTagType = (code: number | null): string => {
:qr-code-list="qrCodeData"
:qr-code-size="200"
/>
<BaseItemDialog
:title="$t('_title.purchase.purchase_order.showItem')"
v-model:visible="showItemVisible"
:url="getItemsUrl"
parent-param-name="orderId"
:parent-param-value="showItemRow?.id"
>
<template #columns>
<el-table-column :label="$t('_prop.purchase.purchase_order_item.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.purchase.purchase_order_item.productSpecs')" prop="productSpecs" width="150" />
<el-table-column
:label="$t('_prop.purchase.purchase_order_item.purchaseCount')"
prop="purchaseCount"
width="100"
/>
<el-table-column :label="$t('_prop.purchase.purchase_order_item.receiptCount')" prop="receiptCount" width="100" />
<el-table-column
:label="$t('_prop.purchase.purchase_order_item.remainingCount')"
prop="remainingCount"
width="100"
/>
<el-table-column :label="$t('_prop.purchase.purchase_order_item.price')" prop="price" width="100">
<template #default="{ row }">
{{ new Decimal(row.price ?? 0).toFixed(2) }}
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_order_item.totalPrice')" prop="totalPrice" width="120">
<template #default="{ row }">
{{ new Decimal(row.totalPrice ?? 0).toFixed(2) }}
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_order_item.purchaseMark')" prop="purchaseMark" />
</template>
</BaseItemDialog>
</template>

View File

@@ -30,6 +30,7 @@ const removeUrl = "/purchase/purchaseplan/deletePurchasePlan";
const getItemsUrl = "/purchase/purchaseplan/getPurchasePlanItemsWithVendorSuggestions";
const generateOrderUrl = "/purchase/purchaseplan/generatePurchaseOrder";
const getItemUrl = "/purchase/purchaseplan/getPurchasePlanItems";
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.purchase.purchase_plan.searchCode") },
];
@@ -53,6 +54,28 @@ const rules = reactive<FormRules>({
],
});
const itemArrayName = "planItems";
/**
* 验证物料编号是否存在
*/
const validatePartNumber = (rule: any, value: string, callback: (error?: Error) => void) => {
if (!value) {
callback(new Error($t("_message.purchase.purchase_plan_item.input_partNumber")));
return;
}
get(partNumberExistsUrl, { partNumber: value })
.then(res => {
if (res.data === true) {
callback();
} else {
callback(new Error($t("_message.warehouse.warehouse_item.not_exist_partNumber")));
}
})
.catch(() => {
callback();
});
};
/**
* 基本不变通用变量
*/
@@ -445,8 +468,6 @@ const mappingConfig: FieldMappingConfig = {
<BaseSelect
v-model="form.vendorId"
:url="'/sys/vendor/getVendorList'"
name="id"
label="vendorName"
:placeholder="$t('_message.purchase.purchase_plan.select_vendor')"
/>
</el-form-item>
@@ -455,9 +476,7 @@ const mappingConfig: FieldMappingConfig = {
<el-form-item :label="$t('_prop.purchase.purchase_plan.storeName')" prop="storeNo">
<BaseSelect
v-model="form.storeNo"
:url="'/warehouse/store/getStoreList'"
name="storeNo"
label="storeName"
:url="'/warehouse/warehouse/getWarehouseSelectList'"
:placeholder="$t('_message.purchase.purchase_plan.select_store')"
/>
</el-form-item>
@@ -477,9 +496,7 @@ const mappingConfig: FieldMappingConfig = {
<template #default="{ row, $index }">
<el-form-item
:prop="`${itemArrayName}.${$index}.partNumber`"
:rules="[
{ required: true, message: $t('_message.purchase.purchase_plan_item.input_partNumber'), trigger: 'blur' },
]"
:rules="[{ required: true, validator: validatePartNumber, trigger: 'blur' }]"
>
<el-input v-model="row.partNumber" size="small" />
</el-form-item>

View File

@@ -294,6 +294,8 @@ const operateButtonClick = (eventName: string, row: any) => {
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.status === 0 && button.eventName === "reject") return false;
if (row.status === 1 && button.eventName === "approve") return false;
if (row.status === 1 && button.eventName === "edit") return false;
if (row.status === 1 && button.eventName === "remove") return false;
return true;
};
</script>
@@ -311,12 +313,12 @@ const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.outStoreName')" prop="outStoreName" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formCode')" prop="formCode" width="175" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formName')" prop="formName" width="250" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.storeName')" prop="storeName" width="100" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.outStoreName')" prop="outStoreName" width="100" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formMark')" prop="formMark" width="250" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" width="150" />
<DefaultStatusSwitchColumn
status-param-name="status"
:status-label-mapping="getFormStatusLabel"

View File

@@ -8,7 +8,6 @@ import { $t } from "@/common/languages";
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import { get, post } from "@/common/http/request";
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
import QrCodeDialog from "@/components/base/base-qrcode/QrCodeDialog.vue";
import { Delete, Edit, Plus } from "@element-plus/icons-vue";
@@ -169,10 +168,6 @@ const saveVendorList = async () => {
const validVendors = dialogTableData.value.filter(v => v.vendorId !== null && v.vendorId !== undefined);
if (validVendors.length === 0) {
return;
}
const vendorList = validVendors.map(v => ({
vendorId: v.vendorId,
costPrice: v.costPrice,
@@ -244,14 +239,18 @@ const cancelVendorEdit = (row: any, originalRow: any) => {
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productType')" prop="productType" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productSpecs')" prop="productSpecs" width="150" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productBrand')" prop="productBrand" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productPacking')" prop="productPacking" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productPackSize')" prop="productPackSize" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.partNumber')" prop="partNumber" width="125" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productType')" prop="productType" width="200" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productSpecs')" prop="productSpecs" width="200" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productBrand')" prop="productBrand" width="100" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productPacking')" prop="productPacking" width="100" />
<el-table-column
:label="$t('_prop.warehouse.warehouse_item.productPackSize')"
prop="productPackSize"
width="125"
/>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productPrice')" prop="productPrice" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" width="200" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.createUserName')" prop="createUserName" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
@@ -325,7 +324,14 @@ const cancelVendorEdit = (row: any, originalRow: any) => {
</el-form-item>
</template>
</BaseForm>
<el-dialog v-model="vendorDialogVisible" :title="vendorDialogTitle" width="80%" :close-on-click-modal="false">
<el-dialog
class="vendor-dialog"
v-model="vendorDialogVisible"
:title="vendorDialogTitle"
width="80%"
:close-on-click-modal="false"
:lock-scroll="false"
>
<el-form ref="vendorFormRef" :model="{ dialogTableData }" :rules="vendorFormRules">
<el-table :data="dialogTableData" border stripe style="width: 100%" max-height="50vh">
<el-table-column :label="$t('_prop.warehouse.warehouse_item.vendorName')" width="250" show-overflow-tooltip>

View File

@@ -161,6 +161,7 @@ const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.status === 0 && button.eventName === "reject") return false;
if (row.status === 1 && button.eventName === "approve") return false;
if (row.status === 1 && button.eventName === "edit") return false;
if (row.status === 1 && button.eventName === "remove") return false;
return true;
};
@@ -212,11 +213,11 @@ const submit = (form: any, formRef: FormInstance | undefined) => {
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formCode')" prop="formCode" width="175" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.storeName')" prop="storeName" width="125" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName" width="350" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark" width="200" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" width="150" />
<DefaultStatusSwitchColumn
status-param-name="status"
:status-label-mapping="getFormStatusLabel"

View File

@@ -53,14 +53,14 @@ export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => {
open: viteEnv.VITE_OPEN,
cors: true,
// 跨域代理配置
proxy: {
"/api": {
target: "https://vue3-design.teek.top",
changeOrigin: true,
secure: true, // 是否忽略 https 安全证书问题true 不忽略false 忽略
rewrite: path => path.replace(/^\/api/, ""),
},
},
// proxy: {
// "/api": {
// target: "https://vue3-design.teek.top",
// changeOrigin: true,
// secure: true, // 是否忽略 https 安全证书问题true 不忽略false 忽略
// rewrite: path => path.replace(/^\/api/, ""),
// },
// },
// 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
warmup: {
clientFiles: ["./index.html", "./src/{views,components}/*"],