feat: k3s

This commit is contained in:
xiaolipro 2026-09-07 10:27:12 +08:00
parent 17c0e119da
commit 80a23632f5
17 changed files with 378 additions and 88 deletions

View File

@ -16,6 +16,7 @@
"McpCapabilityGuide": true,
"McpCapabilityId": true,
"McpFieldHint": true,
"NanaBatchOpenOptions": true,
"PriceAskContext": true,
"PriceAskIntent": true,
"PropType": true,
@ -228,6 +229,7 @@
"useId": true,
"useIdle": true,
"useImage": true,
"useInboxUnread": true,
"useInfiniteScroll": true,
"useIntersectionObserver": true,
"useInterval": true,
@ -249,6 +251,7 @@
"useMouseInElement": true,
"useMousePressed": true,
"useMutationObserver": true,
"useNanaBatchPanel": true,
"useNavigatorLanguage": true,
"useNetwork": true,
"useNow": true,

13
Dockerfile.k3s Normal file
View File

@ -0,0 +1,13 @@
# k3s / Kaniko:静态 SPA(方案 A)。API 直连 api.ideship.com,镜像内 nginx 不做反代
FROM node:20-alpine AS build
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@9 --activate
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm run build
FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html/
COPY nginx-k3s.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

173
nginx-k3s.conf Normal file
View File

@ -0,0 +1,173 @@
# k3s 方案 A:仅静态 SPA。API 由浏览器直连 api.ideship.com(本文件不做反代)。
server {
listen 80;
server_name _;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml image/svg+xml;
root /usr/share/nginx/html;
location = / {
try_files /site/index.html =404;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
location = /9610.html {
try_files /9610.html =404;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
location = /site {
return 301 /;
}
location = /site/ {
return 301 /;
}
location = /site/index.html {
return 301 /;
}
location ^~ /site/ {
try_files $uri =404;
expires 7d;
add_header Cache-Control "public";
access_log off;
}
location = /favicon.ico {
try_files /favicon.png =404;
expires 7d;
add_header Cache-Control "public";
access_log off;
}
location = /favicon.png {
try_files /favicon.png =404;
expires 7d;
add_header Cache-Control "public";
access_log off;
}
location = /login {
try_files /index.html =200;
}
location = /login/ {
try_files /index.html =200;
}
rewrite ^/admin/?$ /index.html last;
location = /admin {
try_files /index.html =200;
}
location = /admin/ {
try_files /index.html =200;
}
location ~ ^/api/(upstreamInterface|upstreamInterfaceConfig|upstreamInterfaceConfigEdit|downstreamInterface(|/newPort)|appList(|/createApplication)|requestLog|callStatistics|apiDebugger|apiTest)(/|$) {
try_files /index.html =200;
}
location ^~ /xhs/startService { try_files /index.html =200; }
location ^~ /xhs/creation { try_files /index.html =200; }
location ^~ /xhs/publishHistory { try_files /index.html =200; }
location ^~ /xhs/skills { try_files /index.html =200; }
location ^~ /xhs/humanSettings { try_files /index.html =200; }
location ^~ /xhs/agentPair { try_files /index.html =200; }
location = /xhs/analysis { try_files /index.html =200; }
location = /xhs/analysis/ { try_files /index.html =200; }
location ^~ /wechat/register { try_files /index.html =200; }
location ^~ /wechat/bind { try_files /index.html =200; }
location ^~ /h5 { try_files /index.html =200; }
location ^~ /track/query { try_files /index.html =200; }
location ^~ /operation/inboundScan { try_files /index.html =200; }
location ^~ /operation/outboundScan { try_files /index.html =200; }
location ^~ /operation/printLabel { try_files /index.html =200; }
location ^~ /operation/parcelArrival { try_files /index.html =200; }
location ^~ /operation/fulfillPack { try_files /index.html =200; }
# 订单前端路由(^~ 须比下方 /order/ API 正则代理更优先)
location ^~ /order/priceCheck { try_files /index.html =200; }
location ^~ /order/placeOrder { try_files /index.html =200; }
location ^~ /order/myOrders { try_files /index.html =200; }
location ^~ /order/fulfillOrders { try_files /index.html =200; }
location ^~ /order/waybillManage { try_files /index.html =200; }
location ^~ /order/pickupOrder { try_files /index.html =200; }
location ^~ /order/customs9610Order { try_files /index.html =200; }
location ^~ /order/batchJobs { try_files /index.html =200; }
location ^~ /order/templateMapping { try_files /index.html =200; }
location ^~ /order/platformStore { try_files /index.html =200; }
location ^~ /order/platformStoreOrder { try_files /index.html =200; }
# 知识库前端路由(^~ 须比下方 /kb/ API 代理更优先)
location ^~ /kb/category { try_files /index.html =200; }
location ^~ /kb/article { try_files /index.html =200; }
location = /warehouse/parcel { try_files /index.html =200; }
location = /warehouse/inventory { try_files /index.html =200; }
location = /warehouse/sku { try_files /index.html =200; }
location = /warehouse/binLocation { try_files /index.html =200; }
location ^~ /warehouse/inboundNotice { try_files /index.html =200; }
location ^~ /Plugin/ { try_files /index.html =200; }
location ^~ /channel/salesProducts { try_files /index.html =200; }
location ^~ /channel/serviceChannels { try_files /index.html =200; }
location ^~ /channel/priceArea { try_files /index.html =200; }
location ^~ /channel/blacklist { try_files /index.html =200; }
location ^~ /channel/remoteZones { try_files /index.html =200; }
location ^~ /channel/weightRules { try_files /index.html =200; }
location ^~ /channel/weightRounding { try_files /index.html =200; }
location ^~ /channel/autoTrigger { try_files /index.html =200; }
location ^~ /channel/issueTemplate { try_files /index.html =200; }
location ^~ /channel/labelDesign { try_files /index.html =200; }
# 营销前端路由(^~ 须比下方 /marketing/ API 正则代理更优先)
location ^~ /marketing/memberLevel { try_files /index.html =200; }
location ^~ /marketing/pointsRule { try_files /index.html =200; }
location ^~ /marketing/pointsFlow { try_files /index.html =200; }
location ^~ /marketing/couponTemplate { try_files /index.html =200; }
location ^~ /marketing/couponGrant { try_files /index.html =200; }
location ^~ /marketing/commissionRule { try_files /index.html =200; }
location ^~ /marketing/commissionDetail { try_files /index.html =200; }
location ^~ /marketing/commissionWithdraw { try_files /index.html =200; }
location ^~ /marketing/referralTree { try_files /index.html =200; }
# 系统管理前端路由(^~ 须比下方 /system/ API 正则代理更优先)
location = /system/dict { try_files /index.html =200; }
location = /system/warehouseAddress { try_files /index.html =200; }
location = /system/announcement { try_files /index.html =200; }
location ^~ /system/users { try_files /index.html =200; }
location ^~ /system/roles { try_files /index.html =200; }
location ^~ /system/menus { try_files /index.html =200; }
location ^~ /system/organizations { try_files /index.html =200; }
location ^~ /system/batchEmail { try_files /index.html =200; }
location ^~ /system/otherConfig { try_files /index.html =200; }
location ^~ /system/aiAssistant { try_files /index.html =200; }
location ^~ /system/aiSkills { try_files /index.html =200; }
location ^~ /system/mcpTools { try_files /index.html =200; }
location ^~ /system/dataPerm/ { try_files /index.html =200; }
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
location ~* \.(?:js|css)$ {
try_files $uri =404;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location / {
index index.html;
try_files $uri /index.html;
}
}

94
pnpm-lock.yaml generated
View File

@ -4,6 +4,10 @@ settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
overrides:
bin-wrapper: npm:bin-wrapper-china
gifsicle: 5.2.0
importers:
.:
@ -1079,42 +1083,36 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@ -1210,67 +1208,56 @@ packages:
resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.46.2':
resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.46.2':
resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.46.2':
resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.46.2':
resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.46.2':
resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.46.2':
resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.46.2':
resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.46.2':
resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.46.2':
resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.46.2':
resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.46.2':
resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==}
@ -1719,49 +1706,41 @@ packages:
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
@ -2132,14 +2111,18 @@ packages:
resolution: {integrity: sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==}
engines: {node: '>=6'}
bin-wrapper@4.1.0:
resolution: {integrity: sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==}
engines: {node: '>=6'}
bin-wrapper-china@0.1.0:
resolution: {integrity: sha512-1UCm17WYEbgry50tup+AQN+JGVEVzoW4f8HMl899k1lvuFxWKGZXl/G2fgxQxAckRjnloO3ijLVVEsv8zescUg==}
engines: {node: '>=8.3'}
hasBin: true
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
binary-mirror-config@1.41.0:
resolution: {integrity: sha512-ZiIhR1s6Sv1Fv6qCQqfPjx0Cj86BgFlhqNxZgHkQOWcxJcMbO3mj1iqsuVjowYqJqeZL8e52+IEv7IRnSX6T6w==}
birpc@2.5.0:
resolution: {integrity: sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==}
@ -5906,56 +5889,48 @@ packages:
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [linux]
libc: glibc
sass-embedded-linux-arm@1.93.3:
resolution: {integrity: sha512-yeiv2y+dp8B4wNpd3+JsHYD0mvpXSfov7IGyQ1tMIR40qv+ROkRqYiqQvAOXf76Qwh4Y9OaYZtLpnsPjfeq6mA==}
engines: {node: '>=14.0.0'}
cpu: [arm]
os: [linux]
libc: glibc
sass-embedded-linux-musl-arm64@1.93.3:
resolution: {integrity: sha512-PS829l+eUng+9W4PFclXGb4uA2+965NHV3/Sa5U7qTywjeeUUYTZg70dJHSqvhrBEfCc2XJABeW3adLJbyQYkw==}
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [linux]
libc: musl
sass-embedded-linux-musl-arm@1.93.3:
resolution: {integrity: sha512-fU0fwAwbp7sBE3h5DVU5UPzvaLg7a4yONfFWkkcCp6ZrOiPuGRHXXYriWQ0TUnWy4wE+svsVuWhwWgvlb/tkKg==}
engines: {node: '>=14.0.0'}
cpu: [arm]
os: [linux]
libc: musl
sass-embedded-linux-musl-riscv64@1.93.3:
resolution: {integrity: sha512-cK1oBY+FWQquaIGEeQ5H74KTO8cWsSWwXb/WaildOO9U6wmUypTgUYKQ0o5o/29nZbWWlM1PHuwVYTSnT23Jjg==}
engines: {node: '>=14.0.0'}
cpu: [riscv64]
os: [linux]
libc: musl
sass-embedded-linux-musl-x64@1.93.3:
resolution: {integrity: sha512-A7wkrsHu2/I4Zpa0NMuPGkWDVV7QGGytxGyUq3opSXgAexHo/vBPlGoDXoRlSdex0cV+aTMRPjoGIfdmNlHwyg==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [linux]
libc: musl
sass-embedded-linux-riscv64@1.93.3:
resolution: {integrity: sha512-vWkW1+HTF5qcaHa6hO80gx/QfB6GGjJUP0xLbnAoY4pwEnw5ulGv6RM8qYr8IDhWfVt/KH+lhJ2ZFxnJareisQ==}
engines: {node: '>=14.0.0'}
cpu: [riscv64]
os: [linux]
libc: glibc
sass-embedded-linux-x64@1.93.3:
resolution: {integrity: sha512-k6uFxs+e5jSuk1Y0niCwuq42F9ZC5UEP7P+RIOurIm8w/5QFa0+YqeW+BPWEW5M1FqVOsNZH3qGn4ahqvAEjPA==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [linux]
libc: glibc
sass-embedded-unknown-all@1.93.3:
resolution: {integrity: sha512-o5wj2rLpXH0C+GJKt/VpWp6AnMsCCbfFmnMAttcrsa+U3yrs/guhZ3x55KAqqUsE8F47e3frbsDL+1OuQM5DAA==}
@ -9218,17 +9193,20 @@ snapshots:
execa: 1.0.0
find-versions: 3.2.0
bin-wrapper@4.1.0:
bin-wrapper-china@0.1.0:
dependencies:
bin-check: 4.1.0
bin-version-check: 4.0.0
binary-mirror-config: 1.41.0
download: 7.1.0
import-lazy: 3.1.0
import-lazy: 4.0.0
os-filter-obj: 2.0.0
pify: 4.0.1
binary-extensions@2.3.0: {}
binary-mirror-config@1.41.0: {}
birpc@2.5.0: {}
bl@1.2.3:
@ -9746,7 +9724,7 @@ snapshots:
cwebp-bin@6.1.2:
dependencies:
bin-build: 3.0.0
bin-wrapper: 4.1.0
bin-wrapper: bin-wrapper-china@0.1.0
cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.0):
dependencies:
@ -11124,7 +11102,7 @@ snapshots:
gifsicle@5.2.0:
dependencies:
bin-build: 3.0.0
bin-wrapper: 4.1.0
bin-wrapper: bin-wrapper-china@0.1.0
execa: 5.1.1
logalot: 2.1.0
@ -11821,13 +11799,13 @@ snapshots:
jpegtran-bin@5.0.2:
dependencies:
bin-build: 3.0.0
bin-wrapper: 4.1.0
bin-wrapper: bin-wrapper-china@0.1.0
logalot: 2.1.0
jpegtran-bin@6.0.1:
dependencies:
bin-build: 3.0.0
bin-wrapper: 4.1.0
bin-wrapper: bin-wrapper-china@0.1.0
jquery@3.7.1: {}
@ -12348,7 +12326,7 @@ snapshots:
mozjpeg@7.1.1:
dependencies:
bin-build: 3.0.0
bin-wrapper: 4.1.0
bin-wrapper: bin-wrapper-china@0.1.0
mrmime@2.0.1: {}
@ -12613,7 +12591,7 @@ snapshots:
optipng-bin@7.0.1:
dependencies:
bin-build: 3.0.0
bin-wrapper: 4.1.0
bin-wrapper: bin-wrapper-china@0.1.0
os-filter-obj@2.0.0:
dependencies:
@ -12828,7 +12806,7 @@ snapshots:
pngquant-bin@6.0.1:
dependencies:
bin-build: 3.0.0
bin-wrapper: 4.1.0
bin-wrapper: bin-wrapper-china@0.1.0
execa: 4.1.0
points-on-curve@0.2.0: {}
@ -12842,11 +12820,11 @@ snapshots:
possible-typed-array-names@1.1.0: {}
postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39):
postcss-html@0.36.0(postcss-syntax@0.36.2)(postcss@7.0.39):
dependencies:
htmlparser2: 3.10.1
postcss: 7.0.39
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@8.5.6)
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss@8.5.6)
postcss-html@1.8.0:
dependencies:
@ -12855,11 +12833,11 @@ snapshots:
postcss: 8.5.6
postcss-safe-parser: 6.0.0(postcss@8.5.6)
postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39):
postcss-jsx@0.36.4(postcss-syntax@0.36.2)(postcss@7.0.39):
dependencies:
'@babel/core': 7.28.0
postcss: 7.0.39
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@8.5.6)
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss@8.5.6)
transitivePeerDependencies:
- supports-color
@ -12871,10 +12849,10 @@ snapshots:
dependencies:
postcss: 8.5.6
postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39):
postcss-markdown@0.36.0(postcss-syntax@0.36.2)(postcss@7.0.39):
dependencies:
postcss: 7.0.39
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@8.5.6)
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss@8.5.6)
remark: 10.0.1
unist-util-find-all-after: 1.0.5
@ -12926,15 +12904,11 @@ snapshots:
dependencies:
postcss: 8.5.6
postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@8.5.6):
postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss@8.5.6):
dependencies:
postcss: 8.5.6
optionalDependencies:
postcss-html: 1.8.0
postcss-jsx: 0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39)
postcss-less: 3.1.4
postcss-markdown: 0.36.0(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39)
postcss-scss: 2.1.1
postcss-value-parser@3.3.1: {}
@ -13977,10 +13951,10 @@ snapshots:
normalize-selector: 0.2.0
pify: 4.0.1
postcss: 7.0.39
postcss-html: 0.36.0(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39)
postcss-jsx: 0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39)
postcss-html: 0.36.0(postcss-syntax@0.36.2)(postcss@7.0.39)
postcss-jsx: 0.36.4(postcss-syntax@0.36.2)(postcss@7.0.39)
postcss-less: 3.1.4
postcss-markdown: 0.36.0(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39)
postcss-markdown: 0.36.0(postcss-syntax@0.36.2)(postcss@7.0.39)
postcss-media-query-parser: 0.2.3
postcss-reporter: 6.0.1
postcss-resolve-nested-selector: 0.1.6
@ -13988,7 +13962,7 @@ snapshots:
postcss-sass: 0.3.5
postcss-scss: 2.1.1
postcss-selector-parser: 3.1.2
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.8.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@8.5.6)
postcss-syntax: 0.36.2(postcss-html@1.8.0)(postcss@8.5.6)
postcss-value-parser: 3.3.1
resolve-from: 4.0.0
signal-exit: 3.0.7

View File

@ -111,7 +111,7 @@ export function resolveOmsAssetUrl(path?: string | null): string {
if (/^https?:\/\//i.test(value) || value.startsWith('data:') || value.startsWith('blob:')) {
// 纠正常见错链:api.nanafa.com/uploads → api.nanafa.com/admin/uploads
return value.replace(
/^(https?:\/\/api\.nanafa\.com)\/uploads\//i,
/^(https?:\/\/api\.(?:nanafa|ideship)\.com)\/uploads\//i,
'$1/admin/uploads/',
)
}

View File

@ -6,7 +6,7 @@ import { useRbacUserStore } from '@/store/modules/rbac-user'
import { resolvePostLogoutLogin } from '@/utils/login-portal'
// 创建自定义 axios 实例
// baseURL 为空,URL 由 OpenAPI.BASE + path 构建;生产默认同源反代,OpenAPI.BASE 为空
// baseURL 为空;生产 URL 由 OpenAPI.BASE / omsUrl 拼到 api.ideship.com
export const axiosInstance = axios.create({
baseURL: '', // 始终为空,URL 由 OpenAPI.BASE + path 构建
timeout: 30000,

View File

@ -13,7 +13,7 @@ import { OpenAPI } from './generated/core/OpenAPI'
import { axiosInstance } from './axios-config'
import { resolveOpenApiBase } from '@/utils/adminApi'
// 生产环境走 oms 同源 nginx 反代(相对路径);VITE_API_ADMIN_URL 可覆盖为绝对地址
// 生产:OpenAPI.BASE = https://api.ideship.com/admin(方案 A);开发:空 BASE + Vite 代理
OpenAPI.BASE = resolveOpenApiBase()
// 认证 token 管理

View File

@ -208,6 +208,7 @@ declare global {
const useId: typeof import('vue')['useId']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInboxUnread: typeof import('./composables/useInboxUnread')['useInboxUnread']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
const useInterval: typeof import('@vueuse/core')['useInterval']
@ -229,6 +230,7 @@ declare global {
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
const useNanaBatchPanel: typeof import('./composables/useNanaBatchPanel')['useNanaBatchPanel']
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNow: typeof import('@vueuse/core')['useNow']
@ -343,6 +345,9 @@ declare global {
export type { WaybillSource, WaybillContext } from './composables/useAskAdvisor'
import('./composables/useAskAdvisor')
// @ts-ignore
export type { NanaBatchOpenOptions } from './composables/useNanaBatchPanel'
import('./composables/useNanaBatchPanel')
// @ts-ignore
export type { ScanFeedbackType } from './composables/useOperationScanFeedback'
import('./composables/useOperationScanFeedback')
// @ts-ignore
@ -560,6 +565,7 @@ declare module 'vue' {
readonly useId: UnwrapRef<typeof import('vue')['useId']>
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
readonly useInboxUnread: UnwrapRef<typeof import('./composables/useInboxUnread')['useInboxUnread']>
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']>
readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']>
readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']>
@ -581,6 +587,7 @@ declare module 'vue' {
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']>
readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']>
readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']>
readonly useNanaBatchPanel: UnwrapRef<typeof import('./composables/useNanaBatchPanel')['useNanaBatchPanel']>
readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']>
readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']>
readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']>

View File

@ -1339,20 +1339,27 @@
* - api.nanafa.com → /nanafa/...
* - 旧 itfx IP → /api/...
* - lsp.globex.cn → /external/...
* 生产:nanafa 旧址改写到 api.ideship.com(方案 A)
*/
function rewriteDebuggerUrlForProxy(rawUrl: string): string {
const url = String(rawUrl || '').trim();
if (!url) return url;
// http(s)://api.nanafa.com/... → /nanafa/...
// http(s)://api.nanafa.com/...
if (/^https?:\/\/api\.nanafa\.com(?::\d+)?(\/|$)/i.test(url)) {
if (import.meta.env.DEV) {
return url.replace(/^https?:\/\/api\.nanafa\.com(?::\d+)?/i, '/nanafa');
}
return url.replace(/^https?:\/\/api\.nanafa\.com(?::\d+)?/i, 'https://api.ideship.com');
}
// 旧 itfx 直连 IP
if (url.startsWith('http://43.139.210.35:8888')) {
if (import.meta.env.DEV) {
return url.replace('http://43.139.210.35:8888', '/api');
}
return url.replace('http://43.139.210.35:8888', 'https://api.ideship.com/itfx');
}
// 示例外部服务商
if (url.startsWith('https://lsp.globex.cn/') || url === 'https://lsp.globex.cn') {

View File

@ -294,6 +294,7 @@ import { getOrderDetail } from '@/api/order';
import { CustomerService, type CustomerServiceAdvisorDto } from '@/api/customer';
import { getOrderStatusMeta, resolveOrderStatusCode } from '@/constants/orderStatus';
import { isValidAvatarUrl } from '@/utils/avatar';
import { rewriteBrowserApiPath } from '@/utils/rewriteBrowserApiPath';
import {
getWaybillContextKey,
getWaybillDisplayNo,
@ -462,7 +463,7 @@ function resolveWechatQrUrl(url?: string | null): string {
if (isValidAvatarUrl(value)) {
if (value.indexOf('//') === -1 && !value.startsWith('data:') && !value.startsWith('/')) {
if (value.indexOf('QiNiuYunFile/') === -1) {
return `/api/upload/${value}`;
return rewriteBrowserApiPath(`/api/upload/${value}`);
}
return `/${value}`;
}

7
src/env.d.ts vendored
View File

@ -31,4 +31,11 @@ declare module '*.vue' {
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string;
readonly VITE_OMS_URL?: string;
/** 生产 Admin 基址,默认 https://api.ideship.com/admin */
readonly VITE_API_ADMIN_URL?: string;
readonly VITE_OMS_ADMIN_URL?: string;
/** 生产 API 根,默认 https://api.ideship.com */
readonly VITE_API_ORIGIN?: string;
/** 静态资源 origin,默认生产 https://api.ideship.com/admin */
readonly VITE_API_ASSET_ORIGIN?: string;
}

View File

@ -1,31 +1,42 @@
/**
* Admin API 地址:生产环境走 oms 同源 nginx 反代(相对路径),开发走 Vite 代理。
* 桌面 Agent 等需直连网关时使用 resolveDirectAdminApiUrl。
* Admin API 地址(方案 A)
* - 开发:相对路径,Vite 代理到 Admin
* - 生产:直连 https://api.ideship.com/admin(可用 VITE_API_ADMIN_URL 覆盖)
*/
function normalizeBase(base: string): string {
return base.trim().replace(/\/$/, '')
}
function ensureLeadingSlash(path: string): string {
return path.startsWith('/') ? path : `/${path}`
}
const DEFAULT_PROD_ADMIN = 'https://api.ideship.com/admin'
function prodAdminBase(): string {
const override = import.meta.env.VITE_API_ADMIN_URL as string | undefined
if (override?.trim()) return normalizeBase(override)
return DEFAULT_PROD_ADMIN
}
/** 浏览器请求 Admin API(OpenAPI.BASE 或 omsUrl/orderUrl 等) */
export function resolveAdminApiPath(path: string): string {
const p = path.startsWith('/') ? path : `/${path}`
const override = import.meta.env.VITE_API_ADMIN_URL as string | undefined
if (!import.meta.env.DEV && override?.trim()) {
return `${normalizeBase(override)}${p}`
const p = ensureLeadingSlash(path)
if (!import.meta.env.DEV) {
return `${prodAdminBase()}${p}`
}
return p
}
export function resolveOpenApiBase(): string {
const override = import.meta.env.VITE_API_ADMIN_URL as string | undefined
if (!import.meta.env.DEV && override?.trim()) {
return normalizeBase(override)
if (!import.meta.env.DEV) {
return prodAdminBase()
}
return ''
}
/** 桌面 Agent 等直连 Admin 网关(不经 oms 页面反代) */
/** 桌面 Agent 等直连 Admin 网关 */
export function resolveDirectAdminApiUrl(): string {
const override = import.meta.env.VITE_API_ADMIN_URL as string | undefined
if (override?.trim()) {
@ -34,18 +45,19 @@ export function resolveDirectAdminApiUrl(): string {
if (import.meta.env.DEV) {
return 'http://api.nanafa.com/admin'
}
return 'https://api.nanafa.com/admin'
return DEFAULT_PROD_ADMIN
}
/** 静态资源(uploads 等)托管在 Admin 服务 wwwroot;对外须带 PATHBASE `/admin`。
* 生产默认同源相对路径(由 nginx 反代 `/uploads` → `api.../admin/uploads`);
* 开发走 Vite `/uploads` 代理。可用 `VITE_API_ASSET_ORIGIN` 覆盖(勿漏 `/admin`)。
/** 静态资源(uploads)在 Admin wwwroot,须带 `/admin`。
* 生产默认 api 域名;开发空串走 Vite `/uploads` 代理。
*/
export function resolveAdminAssetOrigin(): string {
const override = import.meta.env.VITE_API_ASSET_ORIGIN as string | undefined
if (override?.trim()) {
return normalizeBase(override)
}
// 空串 → resolveOmsAssetUrl 保留 `/uploads/...` 相对路径
if (!import.meta.env.DEV) {
return DEFAULT_PROD_ADMIN
}
return ''
}

View File

@ -11,6 +11,7 @@ import { clearToken } from '@/utils/auth';
import { useUserStore } from '@/store';
import { useRbacUserStore } from '@/store/modules/rbac-user';
import { resolvePostLogoutLogin } from '@/utils/login-portal';
import { rewriteBrowserApiPath } from '@/utils/rewriteBrowserApiPath';
const service: AxiosInstance = axios.create({
baseURL: '/',
@ -24,9 +25,11 @@ const service: AxiosInstance = axios.create({
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
config.headers = config.headers ?? {};
// 生产:/api、/Track、/rbac 等走同源,由 nginx 代理到后端 API
// 开发:Vite 代理 /api、/Track、/rbac
// 从 localStorage 获取 token
// 生产:改写为 https://api.ideship.com/{itfx|track|...}(方案 A)
// 开发:Vite 代理 /api、/Track
if (config.url) {
config.url = rewriteBrowserApiPath(config.url);
}
const token = localStorage.getItem('token');
if (token) {
// 如果token已经包含Bearer前缀,直接使用;否则添加Bearer前缀

View File

@ -0,0 +1,81 @@
/**
* 方案 A:生产直连 api.ideship.com PATHBASE;开发仍走 Vite 代理旧路径。
*/
const SPA_API_PREFIXES = [
'upstreamInterface',
'upstreamInterfaceConfig',
'upstreamInterfaceConfigEdit',
'downstreamInterface',
'appList',
'requestLog',
'callStatistics',
'apiDebugger',
'apiTest',
'trackApi',
] as const
const DEFAULT_PROD_API = 'https://api.ideship.com'
function prodApiOrigin(): string {
const override = (import.meta.env.VITE_API_ORIGIN as string | undefined)?.trim()
return (override || DEFAULT_PROD_API).replace(/\/$/, '')
}
function isItfxSpaPath(afterApi: string): boolean {
const seg = afterApi.split('/')[0] ?? ''
return (SPA_API_PREFIXES as readonly string[]).some(
(p) => seg === p || afterApi.startsWith(`${p}/`),
)
}
/** 生产:遗留路径 → https://api.ideship.com/{itfx|track|admin}/... */
export function rewriteBrowserApiPath(url: string): string {
if (!url || import.meta.env.DEV) return url
if (/^https?:\/\//i.test(url) || url.startsWith('data:') || url.startsWith('blob:')) {
return url
}
let path = url.startsWith('/') ? url : `/${url}`
const origin = prodApiOrigin()
// 已是绝对 PATHBASE 相对路径 → 挂到 api 域名
if (
path.startsWith('/itfx/') ||
path === '/itfx' ||
path.startsWith('/track/') ||
path === '/track' ||
path.startsWith('/admin/') ||
path === '/admin'
) {
return `${origin}${path}`
}
if (path.startsWith('/api/apiwechat')) {
return `${origin}/admin${path.slice(4)}`
}
// 旧站 /api/upload/* → Admin wwwroot(勿进 /itfx)
if (path.startsWith('/api/upload/') || path === '/api/upload') {
const rest = path === '/api/upload' ? '' : path.slice('/api/upload'.length)
return `${origin}/admin/uploads${rest}`
}
if (path.startsWith('/api/')) {
const rest = path.slice(5)
if (isItfxSpaPath(rest)) {
return path // 仍是前端路由,勿打到 API
}
return `${origin}/itfx/${rest}`
}
if (path.startsWith('/Track')) {
return `${origin}/track${path}`
}
if (path.startsWith('/trackApi/')) {
return `${origin}/track/${path.slice('/trackApi/'.length)}`
}
return path
}

View File

@ -3,6 +3,7 @@
import { cloneDeep } from 'lodash';
import { Message } from '@arco-design/web-vue';
import axios from 'axios';
import { rewriteBrowserApiPath } from '@/utils/rewriteBrowserApiPath';
import { postInterfaceSaveInterface } from '@/api/InterfaceServices/interface';
import { getDictionaryGetList } from '@/api/ApplicationServices/dictionary';
import { getMethodText } from '@/views/api/upstreamInterface/utils';
@ -255,7 +256,9 @@
try {
// 直接使用axios调用,避免request.ts的拦截器问题
const token = localStorage.getItem('token');
const resp = await axios.get(`/api/Interface/GetInterfaceById?id=${interfaceId}`, {
const resp = await axios.get(
rewriteBrowserApiPath(`/api/Interface/GetInterfaceById?id=${interfaceId}`),
{
headers: {
'Authorization': token ? `Bearer ${token}` : '',
'Content-Type': 'application/json;charset=utf-8',

View File

@ -3,6 +3,7 @@
import { cloneDeep } from 'lodash';
import { Message } from '@arco-design/web-vue';
import axios from 'axios';
import { rewriteBrowserApiPath } from '@/utils/rewriteBrowserApiPath';
import { postInterfaceSaveInterface } from '@/api/InterfaceServices/interface';
import { getDictionaryGetList } from '@/api/ApplicationServices/dictionary';
import { $baseMessage } from '@/utils';
@ -143,7 +144,9 @@
// 直接使用axios调用,避免request.ts的拦截器问题
const token = localStorage.getItem('token');
const response = await axios.get(`/api/Interface/GetInterfaceById?id=${id}`, {
const response = await axios.get(
rewriteBrowserApiPath(`/api/Interface/GetInterfaceById?id=${id}`),
{
headers: {
'Authorization': token ? `Bearer ${token}` : '',
'Content-Type': 'application/json;charset=utf-8',

View File

@ -6,6 +6,7 @@
import { cloneDeep, random } from 'lodash';
import { Message } from '@arco-design/web-vue';
import axios from 'axios';
import { rewriteBrowserApiPath } from '@/utils/rewriteBrowserApiPath';
import { IconDragArrow, IconPlus, IconDelete } from '@arco-design/web-vue/es/icon';
@ -1386,7 +1387,9 @@
try {
// 直接使用axios调用,避免request.ts的拦截器问题
const token = localStorage.getItem('token');
const response = await axios.get(`/api/Interface/GetInterfaceById?id=${id}`, {
const response = await axios.get(
rewriteBrowserApiPath(`/api/Interface/GetInterfaceById?id=${id}`),
{
headers: {
'Authorization': token ? `Bearer ${token}` : '',
'Content-Type': 'application/json;charset=utf-8',