diff --git a/packages/distribute/docker-compose.yml b/packages/distribute/docker-compose.yml index 21dee5e..2608338 100644 --- a/packages/distribute/docker-compose.yml +++ b/packages/distribute/docker-compose.yml @@ -1,29 +1,46 @@ -version: '3.8' +version: "3.4" services: - app: - container_name: riwa-distribute - build: - context: . - dockerfile: Dockerfile + riwa-ionic: + image: nginx:alpine + container_name: riwa-ionic ports: - - "3000:3000" - environment: - - NODE_ENV=production - - HOST=0.0.0.0 - - PORT=3000 - restart: unless-stopped + - 6999:6999 + restart: always + network_mode: bridge volumes: - - ./.output/:/app/.output/ - networks: - - riwa-network - healthcheck: - test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/api/version"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 20s + # dist + - ./.output/public:/usr/share/nginx/html/ + # nginx conf + - ./nginx.conf:/etc/nginx/nginx.conf -networks: - riwa-network: - driver: bridge + +# version: '3.8' + +# services: +# app: +# container_name: riwa-distribute +# build: +# context: . +# dockerfile: Dockerfile +# ports: +# - "3000:3000" +# environment: +# - NODE_ENV=production +# - HOST=0.0.0.0 +# - PORT=3000 +# restart: unless-stopped +# volumes: +# - ./.output/:/app/.output/ +# networks: +# - riwa-network +# healthcheck: +# test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/api/version"] +# interval: 30s +# timeout: 10s +# retries: 3 +# start_period: 20s + +# networks: +# riwa-network: +# driver: bridge diff --git a/packages/distribute/nginx.conf b/packages/distribute/nginx.conf new file mode 100644 index 0000000..4c006be --- /dev/null +++ b/packages/distribute/nginx.conf @@ -0,0 +1,106 @@ +# Generated by nginxconfig.io +# See nginxconfig.txt for the configuration share link + +user nginx; +pid /var/run/nginx.pid; +worker_processes auto; +worker_rlimit_nofile 65535; + +# Load modules +include /etc/nginx/modules-enabled/*.conf; + +events { + multi_accept on; + worker_connections 65535; +} + +http { + charset utf-8; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + server_tokens off; + log_not_found off; + types_hash_max_size 2048; + types_hash_bucket_size 64; + client_max_body_size 16M; + + # MIME + include mime.types; + default_type application/octet-stream; + + # Logging + access_log off; + error_log /dev/null; + + # Load configs + include /etc/nginx/conf.d/*.conf; + + server { + listen 6999; + server_name hdbpage.top; + root /usr/share/nginx/html; + + # SSL + # ssl_certificate /etc/nginx/ssl/hdbpage.top.pem; + # ssl_certificate_key /etc/nginx/ssl/hdbpage.top.key; + # ssl_session_timeout 10m; + # ssl_ciphers HIGH:!aNULL:!MD5; + # ssl_prefer_server_ciphers on; + + # security headers + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + add_header Content-Security-Policy "default-src 'self' http: https: ws: wss: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always; + add_header Permissions-Policy "interest-cohort=()" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + # . files + location ~ /\.(?!well-known) { + deny all; + } + + # logging + access_log /var/log/nginx/access.log combined buffer=512k flush=1m; + error_log /var/log/nginx/error.log warn; + + # index.html fallback + location / { + try_files $uri $uri/ /index.html; + } + + # favicon.ico + location = /favicon.ico { + log_not_found off; + } + + # robots.txt + location = /robots.txt { + log_not_found off; + } + + # Disable HTML caching + location ~* \.(?:html?)$ { + add_header Cache-Control "no-cache"; + } + + # assets, media + location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ { + expires 7d; + } + + # svg, fonts + location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ { + add_header Access-Control-Allow-Origin "*"; + expires 7d; + } + + # gzip + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; + } +} \ No newline at end of file diff --git a/packages/distribute/pages/index.vue b/packages/distribute/pages/index.vue index ae0351a..51285a0 100644 --- a/packages/distribute/pages/index.vue +++ b/packages/distribute/pages/index.vue @@ -46,42 +46,8 @@ function openAppDetail(app: AppInfo) { navigateTo(`/apps/${app.id}`) } -// 创建涟漪效果 -function createRipple(event: MouseEvent | TouchEvent) { - const button = event.currentTarget as HTMLElement - const ripple = document.createElement('span') - const rect = button.getBoundingClientRect() - - const x = ('touches' in event ? event.touches[0]!.clientX : event.clientX) - rect.left - const y = ('touches' in event ? event.touches[0]!.clientY : event.clientY) - rect.top - - ripple.style.cssText = ` - position: absolute; - left: ${x}px; - top: ${y}px; - width: 10px; - height: 10px; - border-radius: 50%; - background: rgba(255, 255, 255, 0.6); - transform: translate(-50%, -50%) scale(0); - animation: ripple-expand 0.6s ease-out; - pointer-events: none; - z-index: 100; - ` - - button.style.position = 'relative' - button.style.overflow = 'hidden' - button.appendChild(ripple) - - setTimeout(() => ripple.remove(), 600) -} - // 下载处理 async function handleDownload(app: AppInfo, type: 'ios' | 'android' | 'h5', event?: MouseEvent | TouchEvent) { - if (event) { - createRipple(event) - } - const url = app.downloads[type] if (!url) { @@ -118,7 +84,7 @@ useHead({ + \ No newline at end of file