duqing2026's picture
feat: enhance functionality with reset button, better defaults and gunicorn
10e0072
const { createApp, ref, computed, watch, nextTick, onMounted } = Vue;
const app = createApp({
delimiters: ['[[', ']]'],
setup() {
const currentTab = ref('server');
const tabs = [
{ id: 'server', name: '基础设置', icon: 'fa-solid fa-sliders' },
{ id: 'proxy', name: '反向代理', icon: 'fa-solid fa-route' },
{ id: 'security', name: '安全防护', icon: 'fa-solid fa-shield-halved' },
{ id: 'performance', name: '性能优化', icon: 'fa-solid fa-gauge-high' }
];
const defaultConfig = {
port: 80,
serverName: 'example.com',
root: '/var/www/html',
index: 'index.html index.htm',
forceHttps: false,
hideVersion: true,
hsts: false,
preventClickjacking: true,
gzip: true,
clientMaxBodySize: 10,
cacheStatic: true,
cacheExtensions: 'jpg jpeg png gif ico css js',
locations: [
{ path: '/', proxyPass: '', websocket: false, tryFiles: '$uri $uri/ /index.html' },
{ path: '/api', proxyPass: 'http://localhost:3000', websocket: false, tryFiles: '' }
]
};
const config = ref(JSON.parse(JSON.stringify(defaultConfig)));
const resetConfig = () => {
if(confirm('确定要重置配置吗?')) {
config.value = JSON.parse(JSON.stringify(defaultConfig));
}
};
const addLocation = () => {
config.value.locations.push({ path: '/new-path', proxyPass: 'http://localhost:8080', websocket: false, tryFiles: '' });
};
const removeLocation = (index) => {
config.value.locations.splice(index, 1);
};
const generatedConfig = computed(() => {
const c = config.value;
let lines = [];
// Header
lines.push(`server {`);
lines.push(` listen ${c.port};`);
lines.push(` server_name ${c.serverName};`);
if (c.root) lines.push(` root ${c.root};`);
if (c.index) lines.push(` index ${c.index};`);
lines.push(``);
// Security
if (c.hideVersion) lines.push(` # Hide Nginx version\n server_tokens off;`);
if (c.forceHttps) lines.push(` # Force HTTPS (Redirect)\n if ($scheme != "https") {\n return 301 https://$host$request_uri;\n }`);
let headers = [];
if (c.hsts) headers.push('add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;');
if (c.preventClickjacking) headers.push('add_header X-Frame-Options "SAMEORIGIN" always;');
if (headers.length > 0) {
lines.push(` # Security Headers`);
headers.forEach(h => lines.push(` ${h}`));
lines.push(``);
}
// Performance
if (c.clientMaxBodySize) lines.push(` client_max_body_size ${c.clientMaxBodySize}M;`);
if (c.gzip) {
lines.push(` # Gzip Compression`);
lines.push(` gzip on;`);
lines.push(` gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;`);
lines.push(``);
}
if (c.cacheStatic) {
lines.push(` # Static File Caching`);
lines.push(` location ~* \\.(${c.cacheExtensions.split(' ').join('|')})$ {`);
lines.push(` expires 30d;`);
lines.push(` access_log off;`);
lines.push(` }`);
lines.push(``);
}
// Locations
c.locations.forEach(loc => {
lines.push(` location ${loc.path} {`);
if (loc.proxyPass) {
lines.push(` proxy_pass ${loc.proxyPass};`);
lines.push(` proxy_set_header Host $host;`);
lines.push(` proxy_set_header X-Real-IP $remote_addr;`);
lines.push(` proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`);
if (loc.websocket) {
lines.push(` # WebSocket Support`);
lines.push(` proxy_http_version 1.1;`);
lines.push(` proxy_set_header Upgrade $http_upgrade;`);
lines.push(` proxy_set_header Connection "upgrade";`);
}
} else if (loc.tryFiles) {
lines.push(` try_files ${loc.tryFiles};`);
}
lines.push(` }`);
lines.push(``);
});
lines.push(`}`);
return lines.join('\n');
});
const highlightCode = () => {
nextTick(() => {
const codeBlock = document.getElementById('code-block');
if (codeBlock && window.Prism) {
codeBlock.textContent = generatedConfig.value; // Update text content explicitly for Prism
window.Prism.highlightElement(codeBlock);
}
});
};
watch(generatedConfig, () => {
highlightCode();
});
onMounted(() => {
highlightCode();
});
const copyConfig = () => {
navigator.clipboard.writeText(generatedConfig.value).then(() => {
alert('配置已复制到剪贴板!');
});
};
const downloadConfig = () => {
const blob = new Blob([generatedConfig.value], { type: 'text/plain' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'nginx.conf';
a.click();
window.URL.revokeObjectURL(url);
};
return {
tabs,
currentTab,
config,
addLocation,
removeLocation,
generatedConfig,
copyConfig,
downloadConfig,
resetConfig
};
}
});
app.mount('#app');