Files
shop-admin/vite.config.ts
赵忠林 de93292fa2 feat(shop): 新增商城基础设置组件
- 新增商城基础信息配置界面支持店铺名称、Logo、描述、电话、地址和开关配置
- 实现图片选择和删除功能,支持Logo的上传回显
- 集成表单校验和保存接口调用,提供保存状态反馈
- 优化响应式布局适配不同屏幕尺寸

fix(cms): 防止文章编辑内容的XSS攻击

- 在文章编辑组件中对动态HTML内容添加DOMPurify消毒
- 替换 v-html 渲染为安全消毒后的内容展现
- 确保富文本内容安全,防止跨站脚本漏洞

refactor(system-setting): 优化系统设置基本信息组件逻辑

- 替换ico文件上传组件,改用SelectFile实现图片选择和删除功能
- 简化图标上传流程,移除上传接口调用相关代码
- 统一表单数据处理,增强设置数据解析和回显兼容性
- 调整保存逻辑,支持根据是否存在主键调用新增或更新接口
- 改进watch数据响应逻辑,支持多种数据结构兼容

fix(system-setting): 修正清理设置组件数据重置逻辑

- 统一清理设置组件的 settingKey 值为 clear,避免混淆
- 优化数据监听回调,支持不同数据结构和空数据重置表单
- 确保组件初始化状态正确,避免遗留数据影响展示

fix(store): 修正 chat store 定义方式

- 按 pinia 官方规范简化 store 定义参数
- 修复 store id 错误传递问题,确保正确注册和使用
2026-06-16 12:52:30 +08:00

275 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import ViteCompression from 'vite-plugin-compression';
import ViteComponents from 'unplugin-vue-components/vite';
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
import { EleAdminResolver } from 'ele-admin-pro/lib/utils/resolvers';
import { resolve } from 'path';
import { visualizer } from 'rollup-plugin-visualizer';
/**
* AntDv4 兼容:替换 ele-admin-pro Less 中的 colorPalette JS 调用
* AntDv4 移除了 Less 的 colorPalette 函数ele-admin-pro 的 common.less
* 中有 ~`colorPalette('@{primary-color}', 5)` 等 JS 表达式,
* 此插件在 Less 编译前将其替换为硬编码的颜色值。
*/
function colorPaletteReplacer() {
return {
name: 'color-palette-replacer',
enforce: 'pre',
async transform(code, id) {
if (!id.includes('ele-admin-pro') || !id.endsWith('.less')) {
return null;
}
console.log('🎨 Processing Less file:', id);
let result = code;
result = result.replace(/~`colorPalette\('@\{primary-color\}',\s*(\d+)\)\s*`/g, (_match, idx) => {
const colors = { 1: '#e6f4ff', 2: '#bae0ff', 3: '#91caff', 4: '#69b1ff', 5: '#4096ff', 6: '#1677ff', 7: '#0958d9', 8: '#003eb3', 9: '#002c8c', 10: '#001d66' };
return colors[idx] || '#1677ff';
});
result = result.replace(/~`colorPalette\('@\{success-color\}',\s*(\d+)\)\s*`/g, (_match, idx) => {
const colors = { 1: '#f6ffed', 2: '#d9f7be', 3: '#b7eb8f', 4: '#95de64', 5: '#73d13d', 6: '#52c41a', 7: '#389e0d', 8: '#237804', 9: '#135200', 10: '#092b00' };
return colors[idx] || '#52c41a';
});
result = result.replace(/~`colorPalette\('@\{warning-color\}',\s*(\d+)\)\s*`/g, (_match, idx) => {
const colors = { 1: '#fffbe6', 2: '#fff1b8', 3: '#ffe58f', 4: '#ffd666', 5: '#ffc53d', 6: '#faad14', 7: '#d48806', 8: '#ad6800', 9: '#874d00', 10: '#612500' };
return colors[idx] || '#faad14';
});
result = result.replace(/~`colorPalette\('@\{error-color\}',\s*(\d+)\)\s*`/g, (_match, idx) => {
const colors = { 1: '#fff2f0', 2: '#ffccc7', 3: '#ffa39e', 4: '#ff7875', 5: '#ff4d4f', 6: '#f5222d', 7: '#cf1322', 8: '#a8071a', 9: '#820014', 10: '#5c0011' };
return colors[idx] || '#ff4d4f';
});
if (result !== code) {
console.log('✅ Replaced colorPalette in:', id);
}
return result !== code ? result : null;
}
};
}
/**
* AntDv4 兼容:将 ele-admin-pro 引用的 AntDv3 样式模块重定向到空模块
* AntDv4 使用 CSS-in-JS不再有 es/xxx/style 目录
*/
function antdStyleRedirect() {
const emptyModule = resolve('src/styles/antd-less-stub/empty-style.js');
return {
name: 'antd-style-redirect',
enforce: 'pre',
resolveId(source) {
if (source.startsWith('ant-design-vue/es/') && source.endsWith('/style')) {
return emptyModule;
}
return null;
}
};
}
// 简化的智能端口管理(避免构建时模块解析问题)
function getSmartPort() {
try {
const basePort = parseInt(process.env.VITE_BASE_PORT || '3000');
const tenantId = process.env.VITE_TENANT_ID || '10258';
const environment = process.env.NODE_ENV || 'development';
let recommendedPort = basePort;
if (environment === 'development') {
const tenantOffset = (parseInt(tenantId) % 1000) * 10;
recommendedPort = basePort + tenantOffset;
} else if (environment === 'test') {
recommendedPort = basePort + 1000;
} else if (environment === 'production') {
recommendedPort = 8080;
}
console.log('🎯 智能端口计算:', {
environment,
tenantId,
basePort,
recommendedPort
});
return recommendedPort;
} catch (error) {
console.warn('⚠️ 端口计算失败,使用默认端口 3000:', error);
return 3000;
}
}
export default defineConfig(({ command }) => {
const isBuild = command === 'build';
const smartPort = !isBuild ? getSmartPort() : undefined;
return {
base: '/',
resolve: {
alias: {
'@/': resolve('src') + '/',
'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js',
// AntDv4 兼容层:将 ele-admin-pro 引用的 AntD Less 主题文件重定向到 stub
'ant-design-vue/es/style/themes/default.less': resolve('src/styles/antd-less-stub/default.less'),
'ant-design-vue/es/style/themes/dark.less': resolve('src/styles/antd-less-stub/dark.less')
}
},
server: {
port: smartPort || 3000,
host: '0.0.0.0',
open: true,
proxy: {
'/api': {
target: process.env.VITE_API_URL || 'https://server.websoft.top',
changeOrigin: true,
secure: false,
configure: (proxy, _options) => {
proxy.on('error', (err, _req, _res) => {
console.log('proxy error', err);
});
proxy.on('proxyReq', (proxyReq, req, _res) => {
console.log('Sending Request to the Target:', req.method, req.url);
});
proxy.on('proxyRes', (proxyRes, req, _res) => {
console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
});
},
}
},
strictPort: false,
},
preview: {
port: smartPort ? smartPort + 1000 : 4173,
host: '0.0.0.0',
open: true,
strictPort: false,
},
plugins: [
colorPaletteReplacer(),
antdStyleRedirect(),
vue({
script: {
defineModel: true,
propsDestructure: true
}
}),
ViteComponents({
dts: false,
resolvers: [
AntDesignVueResolver({
importStyle: false // AntDv4 使用 CSS-in-JS无需 Less 导入
}),
EleAdminResolver({
importStyle: isBuild ? 'less' : false
})
],
directoryAsNamespace: true
}),
ViteCompression({
disable: !isBuild,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz'
}),
ViteCompression({
disable: !isBuild,
threshold: 10240,
algorithm: 'brotliCompress',
ext: '.br'
}),
isBuild && visualizer({
filename: 'dist/stats.html',
open: false,
gzipSize: true,
brotliSize: true
})
].filter(Boolean),
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: {
'style-entry-file': isBuild ? 'as-needed' : 'global-import'
}
}
}
},
optimizeDeps: {
include: [
'sortablejs',
'vuedraggable',
'echarts/core',
'echarts/charts',
'echarts/renderers',
'echarts/components',
'vue-echarts',
'echarts-wordcloud',
'xlsx',
'lodash-es',
'dayjs',
'crypto-js',
'js-md5',
'qrcode',
'nprogress'
],
exclude: ['@iconify/json', 'tinymce']
},
build: {
target: 'es2015',
cssCodeSplit: true,
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks(id) {
if (!id.includes('node_modules')) return undefined;
if (id.includes('/vue-router/') || id.includes('/pinia/') || id.includes('/vue/')) {
return 'vue-vendor';
}
if (id.includes('/ant-design-vue/') || id.includes('/ele-admin-pro/')) {
return 'ui-vendor';
}
if (id.includes('/lodash-es/') || id.includes('/dayjs/') || id.includes('/crypto-js/') || id.includes('/js-md5/')) {
return 'utils-vendor';
}
if (id.includes('/echarts/') || id.includes('/vue-echarts/') || id.includes('/echarts-wordcloud/')) {
return 'charts-vendor';
}
if (id.includes('/tinymce/') || id.includes('/bytemd/') || id.includes('/md-editor-v3/')) {
return 'editor-vendor';
}
if (id.includes('/xlsx/') || id.includes('/exceljs/') || id.includes('/file-saver/') || id.includes('/ali-oss/')) {
return 'file-vendor';
}
return undefined;
},
chunkFileNames: (chunkInfo) => {
const name = chunkInfo.facadeModuleId
? chunkInfo.facadeModuleId.split('/').pop().replace(/\.\w+$/, '')
: 'chunk';
return `js/${name}-[hash].js`;
},
assetFileNames: (assetInfo) => {
const name = (assetInfo.name || '').split('/').pop();
if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(name)) {
return `media/[hash].[ext]`;
}
if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(name)) {
return `images/[hash].[ext]`;
}
if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(name)) {
return `fonts/[hash].[ext]`;
}
return `assets/[hash].[ext]`;
}
}
},
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log']
}
}
}
};
});