f
This commit is contained in:
@@ -6,6 +6,7 @@ import { useUserStore } from "@/stores/userStore";
|
||||
import { useDialogStore } from "@/stores/dialogStore";
|
||||
import { useAuthStore } from "@/stores/authStore";
|
||||
import { useWeixinShare } from "@/composables/useWeixinShare";
|
||||
import { useAppConfig } from "@/composables/useAppConfig";
|
||||
import WechatOverlay from "@/components/WechatOverlay.vue";
|
||||
// import MaintenanceDialog from "@/components/MaintenanceDialog.vue";
|
||||
|
||||
@@ -15,8 +16,11 @@ const userStore = useUserStore();
|
||||
const dialogStore = useDialogStore();
|
||||
const authStore = useAuthStore();
|
||||
const { configWeixinShare, setDynamicShare } = useWeixinShare();
|
||||
const { loadAppConfig } = useAppConfig();
|
||||
|
||||
onMounted(() => {
|
||||
void loadAppConfig();
|
||||
|
||||
// 检查token版本,如果版本不匹配则清除旧token
|
||||
checkTokenVersion()
|
||||
|
||||
@@ -218,7 +222,7 @@ const h5WeixinGetCode = () => {
|
||||
<template>
|
||||
<RouterView />
|
||||
|
||||
<WechatOverlay />
|
||||
<!-- <WechatOverlay /> -->
|
||||
<BindPhoneDialog />
|
||||
<!-- <MaintenanceDialog /> -->
|
||||
</template>
|
||||
|
||||
1
src/auto-imports.d.ts
vendored
1
src/auto-imports.d.ts
vendored
@@ -120,6 +120,7 @@ declare global {
|
||||
const useAliyunCaptcha: typeof import('./composables/useAliyunCaptcha.js')['default']
|
||||
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
||||
const useApiFetch: typeof import('./composables/useApiFetch.js')['default']
|
||||
const useAppConfig: typeof import('./composables/useAppConfig.js')['useAppConfig']
|
||||
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
|
||||
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
|
||||
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
|
||||
|
||||
@@ -7,6 +7,23 @@ import { splitDWBG8B4DForTabs } from '@/ui/CDWBG8B4D/utils/simpleSplitter.js';
|
||||
import { splitDWBG6A2CForTabs } from '@/ui/DWBG6A2C/utils/simpleSplitter.js';
|
||||
import { splitCJRZQ5E9FForTabs } from '@/ui/CJRZQ5E9F/utils/simpleSplitter.js';
|
||||
import { splitCQYGL3F8EForTabs } from '@/ui/CQYGL3F8E/utils/simpleSplitter.js';
|
||||
import { useAppConfig } from '@/composables/useAppConfig';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
// 与首页/查询表一致:报告保留天数由 App.vue 拉取的 /app/config 中 query.retention_days
|
||||
const { appConfig } = useAppConfig();
|
||||
|
||||
const route = useRoute();
|
||||
/**
|
||||
* App 内嵌 WebView 走 /app/report、/app/example(无 PageLayout 顶栏),sticky 的 offset-top 若为 46
|
||||
* 会与「为 van-nav-bar 预留」一致,在顶栏不存在时 Tab 上方会多出一块空白。
|
||||
* 浏览器内 /report、/example 仍带顶栏,保持 46。
|
||||
*/
|
||||
const tabsStickyOffsetTop = computed(() => {
|
||||
if (route.path.startsWith('/app/') || route.meta?.embedForApp)
|
||||
return 0;
|
||||
return 46;
|
||||
});
|
||||
|
||||
// 动态导入产品背景图片的函数
|
||||
const loadProductBackground = async (productType) => {
|
||||
@@ -782,7 +799,7 @@ watch([reportData, componentRiskScores], () => {
|
||||
</div>
|
||||
|
||||
<!-- Tabs 区域 -->
|
||||
<StyledTabs v-model:active="active" scrollspy sticky :offset-top="46">
|
||||
<StyledTabs v-model:active="active" scrollspy sticky :offset-top="tabsStickyOffsetTop">
|
||||
<div class="flex flex-col gap-y-4 p-4">
|
||||
<LEmpty v-if="isEmpty" />
|
||||
<van-tab title="分析指数">
|
||||
@@ -837,8 +854,7 @@ watch([reportData, componentRiskScores], () => {
|
||||
1、本份报告是在取得您个人授权后,我们才向合法存有您以上个人信息的机构去调取相关内容,我们不会以任何形式对您的报告进行存储,除您和您授权的人外不会提供给任何人和机构进行查看。
|
||||
</p>
|
||||
<p class="text-[#999999]">
|
||||
2、本报告自生成之日起,有效期 30
|
||||
天,过期自动删除。如果您对本份报告存有异议,可能是合作机构数据有延迟或未能获取到您的相关数据,出于合作平台数据隐私的保护,本平台将不做任何解释。
|
||||
2、本报告自生成之日起,有效期 {{ appConfig.query.retention_days }} 天,过期自动删除。如果您对本份报告存有异议,可能是合作机构数据有延迟或未能获取到您的相关数据,出于合作平台数据隐私的保护,本平台将不做任何解释。
|
||||
</p>
|
||||
<p class="text-[#999999]">
|
||||
3、若以上数据有错误,请联系平台客服。
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { calculatePromotionPricing, safeTruncate } from '@/utils/promotionPricing'
|
||||
|
||||
const props = defineProps({
|
||||
defaultPrice: {
|
||||
type: Number,
|
||||
@@ -58,31 +60,12 @@ watch(show, () => {
|
||||
})
|
||||
|
||||
|
||||
const costPrice = computed(() => {
|
||||
if (!productConfig.value) return 0.00
|
||||
// 平台定价成本
|
||||
let platformPricing = 0
|
||||
platformPricing += productConfig.value.cost_price
|
||||
if (price.value > productConfig.value.p_pricing_standard) {
|
||||
platformPricing += (price.value - productConfig.value.p_pricing_standard) * productConfig.value.p_overpricing_ratio
|
||||
}
|
||||
|
||||
if (productConfig.value.a_pricing_standard > platformPricing && productConfig.value.a_pricing_end > platformPricing && productConfig.value.a_overpricing_ratio > 0) {
|
||||
if (price.value > productConfig.value.a_pricing_standard) {
|
||||
if (price.value > productConfig.value.a_pricing_end) {
|
||||
platformPricing += (productConfig.value.a_pricing_end - productConfig.value.a_pricing_standard) * productConfig.value.a_overpricing_ratio
|
||||
} else {
|
||||
platformPricing += (price.value - productConfig.value.a_pricing_standard) * productConfig.value.a_overpricing_ratio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return safeTruncate(platformPricing)
|
||||
const pricingResult = computed(() => {
|
||||
return calculatePromotionPricing(price.value, productConfig.value)
|
||||
})
|
||||
|
||||
const promotionRevenue = computed(() => {
|
||||
return safeTruncate(price.value - costPrice.value)
|
||||
});
|
||||
const costPrice = computed(() => pricingResult.value.costPrice)
|
||||
const promotionRevenue = computed(() => pricingResult.value.promotionRevenue)
|
||||
|
||||
// 价格校验与修正逻辑
|
||||
const validatePrice = (currentPrice) => {
|
||||
@@ -122,15 +105,6 @@ const validatePrice = (currentPrice) => {
|
||||
console.log(newPrice, message)
|
||||
return { newPrice, message };
|
||||
}
|
||||
function safeTruncate(num, decimals = 2) {
|
||||
if (isNaN(num) || !isFinite(num)) return "0.00";
|
||||
|
||||
const factor = 10 ** decimals;
|
||||
const scaled = Math.trunc(num * factor);
|
||||
const truncated = scaled / factor;
|
||||
|
||||
return truncated.toFixed(decimals);
|
||||
}
|
||||
const isManualConfirm = ref(false)
|
||||
const onConfirm = () => {
|
||||
if (isManualConfirm.value) return
|
||||
|
||||
46
src/utils/promotionPricing.js
Normal file
46
src/utils/promotionPricing.js
Normal file
@@ -0,0 +1,46 @@
|
||||
export function safeTruncate(num, decimals = 2) {
|
||||
if (Number.isNaN(num) || !Number.isFinite(num))
|
||||
return '0.00'
|
||||
|
||||
const factor = 10 ** decimals
|
||||
const scaled = Math.trunc(num * factor)
|
||||
return (scaled / factor).toFixed(decimals)
|
||||
}
|
||||
|
||||
function calculatePlatformOverpricingCost(price, config) {
|
||||
if (price <= config.p_pricing_standard)
|
||||
return 0
|
||||
return (price - config.p_pricing_standard) * config.p_overpricing_ratio
|
||||
}
|
||||
|
||||
function calculateSuperiorOverpricingCost(price, config) {
|
||||
if (config.a_overpricing_ratio <= 0)
|
||||
return 0
|
||||
if (price <= config.a_pricing_standard)
|
||||
return 0
|
||||
if (config.a_pricing_end <= config.a_pricing_standard)
|
||||
return 0
|
||||
|
||||
const superiorRangeAmount = Math.min(price, config.a_pricing_end) - config.a_pricing_standard
|
||||
return Math.max(0, superiorRangeAmount) * config.a_overpricing_ratio
|
||||
}
|
||||
|
||||
export function calculatePromotionPricing(priceInput, config) {
|
||||
if (!config)
|
||||
return { costPrice: '0.00', promotionRevenue: '0.00' }
|
||||
|
||||
const price = Number(priceInput)
|
||||
if (!Number.isFinite(price))
|
||||
return { costPrice: '0.00', promotionRevenue: '0.00' }
|
||||
|
||||
const baseCost = Number(config.cost_price) || 0
|
||||
const platformOverpricingCost = calculatePlatformOverpricingCost(price, config)
|
||||
const superiorOverpricingCost = calculateSuperiorOverpricingCost(price, config)
|
||||
const totalCost = baseCost + platformOverpricingCost + superiorOverpricingCost
|
||||
const revenue = price - totalCost
|
||||
|
||||
return {
|
||||
costPrice: safeTruncate(totalCost),
|
||||
promotionRevenue: safeTruncate(revenue),
|
||||
}
|
||||
}
|
||||
@@ -763,12 +763,6 @@ function selectType(type) {
|
||||
|
||||
// 申请VIP或SVIP
|
||||
async function applyVip() {
|
||||
// 如果是VIP想升级到SVIP,提示联系客服
|
||||
if (isVip.value && selectedType.value === 'svip') {
|
||||
contactService()
|
||||
return
|
||||
}
|
||||
|
||||
// 如果是SVIP要降级到VIP,提示不能降级
|
||||
if (isSvip.value && selectedType.value === 'vip') {
|
||||
showToast('SVIP会员不能降级到VIP会员')
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div v-if="isAgent" class="absolute -bottom-2 -right-2">
|
||||
<div class="flex items-center justify-center rounded-full px-3 py-1 text-xs font-bold text-white shadow-sm"
|
||||
:class="levelGradient.badge">
|
||||
{{ levelNames[level] }}
|
||||
{{ levelNames[normalizedLevel] }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,15 +39,15 @@
|
||||
</p>
|
||||
</template>
|
||||
<p v-if="isAgent" class="text-sm font-medium" :class="levelGradient.text">
|
||||
🎖️ {{ levelText[level] }}
|
||||
🎖️ {{ levelText[normalizedLevel] }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<VipBanner v-if="isAgent && (level === 'normal' || level === '')" />
|
||||
<VipBanner v-if="isAgent && normalizedLevel === 'NORMAL'" />
|
||||
<!-- 功能菜单 -->
|
||||
<div class="">
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<template v-if="isAgent && ['VIP', 'SVIP'].includes(level)">
|
||||
<template v-if="isAgent && ['VIP', 'SVIP'].includes(normalizedLevel)">
|
||||
<button
|
||||
class="w-full flex items-center justify-between px-6 py-4 hover:bg-purple-50 transition-colors border-b border-gray-100"
|
||||
@click="toVipConfig">
|
||||
@@ -165,8 +165,17 @@ const { isAgent, level, ExpiryTime } = storeToRefs(agentStore);
|
||||
const { userName, userAvatar, isLoggedIn, mobile } = storeToRefs(userStore);
|
||||
const { isWeChat } = useEnv();
|
||||
|
||||
const normalizedLevel = computed(() => {
|
||||
const raw = String(level.value || "").trim();
|
||||
if (!raw || ["NORMAL", "NORNAL"].includes(raw.toUpperCase()) || raw === "normal" || raw === "nornal") return "NORMAL";
|
||||
if (raw.toUpperCase().includes("SVIP")) return "SVIP";
|
||||
if (raw.toUpperCase().includes("VIP")) return "VIP";
|
||||
return "NORMAL";
|
||||
});
|
||||
|
||||
const levelNames = {
|
||||
normal: "普通代理",
|
||||
NORMAL: "普通代理",
|
||||
"": "普通代理",
|
||||
VIP: "VIP代理",
|
||||
SVIP: "SVIP代理",
|
||||
@@ -174,6 +183,7 @@ const levelNames = {
|
||||
|
||||
const levelText = {
|
||||
normal: "基础代理特权",
|
||||
NORMAL: "基础代理特权",
|
||||
"": "基础代理特权",
|
||||
VIP: "高级代理特权",
|
||||
SVIP: "尊享代理特权",
|
||||
@@ -182,24 +192,27 @@ const levelText = {
|
||||
const levelGradient = computed(() => ({
|
||||
border: {
|
||||
normal: "bg-gradient-to-r from-gray-300 to-gray-400",
|
||||
NORMAL: "bg-gradient-to-r from-gray-300 to-gray-400",
|
||||
"": "bg-gradient-to-r from-gray-300 to-gray-400",
|
||||
VIP: "bg-gradient-to-r from-yellow-400 to-amber-500",
|
||||
SVIP: "bg-gradient-to-r from-purple-400 to-pink-400 shadow-[0_0_15px_rgba(163,51,200,0.2)]",
|
||||
}[level.value],
|
||||
}[normalizedLevel.value],
|
||||
|
||||
badge: {
|
||||
normal: "bg-gradient-to-r from-gray-500 to-gray-600",
|
||||
NORMAL: "bg-gradient-to-r from-gray-500 to-gray-600",
|
||||
"": "bg-gradient-to-r from-gray-500 to-gray-600",
|
||||
VIP: "bg-gradient-to-r from-yellow-500 to-amber-600",
|
||||
SVIP: "bg-gradient-to-r from-purple-500 to-pink-500",
|
||||
}[level.value],
|
||||
}[normalizedLevel.value],
|
||||
|
||||
text: {
|
||||
normal: "text-gray-600",
|
||||
NORMAL: "text-gray-600",
|
||||
"": "text-gray-600",
|
||||
VIP: "text-amber-600",
|
||||
SVIP: "text-purple-600",
|
||||
}[level.value],
|
||||
}[normalizedLevel.value],
|
||||
}));
|
||||
|
||||
const maskName = (name) => {
|
||||
@@ -276,8 +289,9 @@ function formatExpiryTime(expiryTimeStr) {
|
||||
const getDefaultAvatar = () => {
|
||||
if (!isAgent.value) return headShot;
|
||||
|
||||
switch (level.value) {
|
||||
switch (normalizedLevel.value) {
|
||||
case "normal":
|
||||
case "NORMAL":
|
||||
case "":
|
||||
return "/image/shot_nonal.png";
|
||||
case "VIP":
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<script setup>
|
||||
import PriceInputPopup from '@/components/PriceInputPopup.vue';
|
||||
import VipBanner from '@/components/VipBanner.vue';
|
||||
import { calculatePromotionPricing } from '@/utils/promotionPricing';
|
||||
const showTypePicker = ref(false);
|
||||
const showApplyPopup = ref(false); // 用来控制申请代理弹窗的显示
|
||||
const showPricePicker = ref(false);
|
||||
@@ -120,41 +121,16 @@ const reportTypes = computed(() => {
|
||||
// return (pickerProductConfig.value.cost_price + platformPricing).toFixed(2)
|
||||
// })
|
||||
|
||||
const costPrice = computed(() => {
|
||||
if (!pickerProductConfig.value) return 0.00
|
||||
// 平台定价成本
|
||||
let platformPricing = 0
|
||||
platformPricing += pickerProductConfig.value.cost_price
|
||||
if (clientPrice.value > pickerProductConfig.value.p_pricing_standard) {
|
||||
platformPricing += (clientPrice.value - pickerProductConfig.value.p_pricing_standard) * pickerProductConfig.value.p_overpricing_ratio
|
||||
}
|
||||
|
||||
if (pickerProductConfig.value.a_pricing_standard > platformPricing && pickerProductConfig.value.a_pricing_end > platformPricing && pickerProductConfig.value.a_overpricing_ratio > 0) {
|
||||
if (clientPrice.value > pickerProductConfig.value.a_pricing_standard) {
|
||||
if (clientPrice.value > pickerProductConfig.value.a_pricing_end) {
|
||||
platformPricing += (pickerProductConfig.value.a_pricing_end - pickerProductConfig.value.a_pricing_standard) * pickerProductConfig.value.a_overpricing_ratio
|
||||
} else {
|
||||
platformPricing += (clientPrice.value - pickerProductConfig.value.a_pricing_standard) * pickerProductConfig.value.a_overpricing_ratio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return safeTruncate(platformPricing)
|
||||
const pricingResult = computed(() => {
|
||||
return calculatePromotionPricing(clientPrice.value, pickerProductConfig.value)
|
||||
})
|
||||
|
||||
const costPrice = computed(() => pricingResult.value.costPrice)
|
||||
|
||||
const promotionRevenue = computed(() => {
|
||||
return safeTruncate(clientPrice.value - costPrice.value)
|
||||
return pricingResult.value.promotionRevenue
|
||||
});
|
||||
const showQRcode = ref(false);
|
||||
function safeTruncate(num, decimals = 2) {
|
||||
if (isNaN(num) || !isFinite(num)) return "0.00";
|
||||
|
||||
const factor = 10 ** decimals;
|
||||
const scaled = Math.trunc(num * factor);
|
||||
const truncated = scaled / factor;
|
||||
|
||||
return truncated.toFixed(decimals);
|
||||
}
|
||||
const generatePromotionCode = async () => {
|
||||
if (selectedReportType.value.length === 0) {
|
||||
showToast({ message: '请选择报告类型' });
|
||||
|
||||
@@ -27,7 +27,7 @@ const fetchRewardDetails = async () => {
|
||||
// 更新用户信息
|
||||
userInfo.value = {
|
||||
createTime: data.value.data.create_time,
|
||||
level: data.value.data.level_name || '普通',
|
||||
level: data.value.data.level_name || data.value.data.level || '',
|
||||
mobile: data.value.data.mobile,
|
||||
}
|
||||
// 更新汇总数据
|
||||
@@ -148,6 +148,29 @@ const userInfo = ref({})
|
||||
const summary = ref({})
|
||||
const statistics = ref([])
|
||||
|
||||
const normalizeAgentLevel = (value) => {
|
||||
const raw = String(value || '').trim()
|
||||
if (!raw)
|
||||
return 'NORMAL'
|
||||
const cleaned = raw.replace(/代理$/, '')
|
||||
if (cleaned === '普通')
|
||||
return 'NORMAL'
|
||||
const upper = cleaned.toUpperCase()
|
||||
if (upper.includes('SVIP'))
|
||||
return 'SVIP'
|
||||
if (upper.includes('VIP'))
|
||||
return 'VIP'
|
||||
if (upper === 'NORMAL' || upper === 'NORNAL')
|
||||
return 'NORMAL'
|
||||
return 'NORMAL'
|
||||
}
|
||||
|
||||
const getAgentLevelLabel = value => ({
|
||||
NORMAL: '普通代理',
|
||||
VIP: 'VIP代理',
|
||||
SVIP: 'SVIP代理',
|
||||
}[normalizeAgentLevel(value)] || '普通代理')
|
||||
|
||||
onMounted(() => {
|
||||
fetchRewardDetails()
|
||||
})
|
||||
@@ -214,7 +237,7 @@ const formatNumber = num => {
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="text-xl font-semibold text-gray-800">{{ userInfo.mobile }}</div>
|
||||
<span class="px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-600">
|
||||
{{ userInfo.level }}代理
|
||||
{{ getAgentLevelLabel(userInfo.level) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,16 +64,38 @@ const formatNumber = num => {
|
||||
return Number(num).toFixed(2)
|
||||
}
|
||||
|
||||
const getLevelText = item => {
|
||||
return item?.level_name || item?.level || '普通'
|
||||
const normalizeAgentLevel = (value) => {
|
||||
const raw = String(value || '').trim()
|
||||
if (!raw)
|
||||
return 'NORMAL'
|
||||
const cleaned = raw.replace(/代理$/, '')
|
||||
if (cleaned === '普通')
|
||||
return 'NORMAL'
|
||||
const upper = cleaned.toUpperCase()
|
||||
if (upper.includes('SVIP'))
|
||||
return 'SVIP'
|
||||
if (upper.includes('VIP'))
|
||||
return 'VIP'
|
||||
if (upper === 'NORMAL' || upper === 'NORNAL')
|
||||
return 'NORMAL'
|
||||
return 'NORMAL'
|
||||
}
|
||||
|
||||
const getLevelText = (item) => {
|
||||
const normalized = normalizeAgentLevel(item?.level_name || item?.level)
|
||||
return {
|
||||
NORMAL: '普通代理',
|
||||
VIP: 'VIP代理',
|
||||
SVIP: 'SVIP代理',
|
||||
}[normalized] || '普通代理'
|
||||
}
|
||||
|
||||
// 获取等级标签样式
|
||||
const getLevelClass = level => {
|
||||
switch (level) {
|
||||
case 'SVIP':
|
||||
const getLevelClass = (levelText) => {
|
||||
switch (levelText) {
|
||||
case 'SVIP代理':
|
||||
return 'bg-purple-100 text-purple-600'
|
||||
case 'VIP':
|
||||
case 'VIP代理':
|
||||
return 'bg-blue-100 text-blue-600'
|
||||
default:
|
||||
return 'bg-gray-100 text-gray-600'
|
||||
@@ -122,7 +144,7 @@ onMounted(() => {
|
||||
</div>
|
||||
<div class="text-xl font-semibold text-gray-800">{{ item.mobile }}</div>
|
||||
<span :class="['px-3 py-1 rounded-full text-sm font-medium', getLevelClass(getLevelText(item))]">
|
||||
{{ getLevelText(item) }}代理
|
||||
{{ getLevelText(item) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,10 @@ function generateSeoTemplatesPlugin() {
|
||||
if (!viteConfig || viteConfig.command !== "build") return;
|
||||
const env = loadEnv(viteConfig.mode, viteConfig.root, "");
|
||||
const mergedEnv = { ...env, ...process.env };
|
||||
const script = path.join(viteConfig.root, "seo/generate-seo-templates.cjs");
|
||||
const script = path.join(
|
||||
viteConfig.root,
|
||||
"seo/generate-seo-templates.cjs",
|
||||
);
|
||||
const result = spawnSync(process.execPath, [script], {
|
||||
cwd: viteConfig.root,
|
||||
env: mergedEnv,
|
||||
@@ -46,16 +49,16 @@ export default defineConfig({
|
||||
strictPort: true, // 如果端口被占用则抛出错误而不是使用下一个可用端口
|
||||
proxy: {
|
||||
"/api/v1": {
|
||||
target: "http://127.0.0.1:8888", // 本地接口地址
|
||||
// target: "https://www.tianyuandb.com", // 本地接口地址
|
||||
// target: "http://127.0.0.1:8888", // 本地接口地址
|
||||
target: "https://chimei.ronsafe.cn/", // 本地接口地址
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
build: {
|
||||
// 构建优化
|
||||
target: 'es2015', // 支持更多浏览器
|
||||
minify: 'terser', // 使用terser进行压缩
|
||||
target: "es2015", // 支持更多浏览器
|
||||
minify: "terser", // 使用terser进行压缩
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true, // 移除console.log
|
||||
@@ -66,15 +69,15 @@ export default defineConfig({
|
||||
output: {
|
||||
// 代码分割策略
|
||||
manualChunks: {
|
||||
vendor: ['vue', 'vue-router', 'pinia'],
|
||||
vant: ['vant'],
|
||||
utils: ['axios', 'lodash', 'crypto-js'],
|
||||
charts: ['echarts', 'vue-echarts'],
|
||||
vendor: ["vue", "vue-router", "pinia"],
|
||||
vant: ["vant"],
|
||||
utils: ["axios", "lodash", "crypto-js"],
|
||||
charts: ["echarts", "vue-echarts"],
|
||||
},
|
||||
// 文件名策略
|
||||
chunkFileNames: 'assets/js/[name]-[hash].js',
|
||||
entryFileNames: 'assets/js/[name]-[hash].js',
|
||||
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
|
||||
chunkFileNames: "assets/js/[name]-[hash].js",
|
||||
entryFileNames: "assets/js/[name]-[hash].js",
|
||||
assetFileNames: "assets/[ext]/[name]-[hash].[ext]",
|
||||
},
|
||||
},
|
||||
// 启用CSS代码分割
|
||||
@@ -92,11 +95,7 @@ export default defineConfig({
|
||||
"@vueuse/core", // 自动引入 VueUse 中的工具函数(可选)
|
||||
],
|
||||
dts: "src/auto-imports.d.ts", // 生成类型定义文件(可选)
|
||||
dirs: [
|
||||
"src/composables",
|
||||
"src/stores",
|
||||
"src/components",
|
||||
],
|
||||
dirs: ["src/composables", "src/stores", "src/components"],
|
||||
resolvers: [VantResolver()],
|
||||
}),
|
||||
Components({
|
||||
@@ -112,6 +111,6 @@ export default defineConfig({
|
||||
},
|
||||
// 优化依赖预构建
|
||||
optimizeDeps: {
|
||||
include: ['vue', 'vue-router', 'pinia', 'vant', 'axios'],
|
||||
include: ["vue", "vue-router", "pinia", "vant", "axios"],
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user