merge: refactor/v2 (v2 stack deploy, new h5 build, miniprogram assets) into develop
@@ -28,7 +28,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory('/admin/'),
|
history: createWebHistory('/v2/admin/'),
|
||||||
routes,
|
routes,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { fileURLToPath, URL } from 'node:url'
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
base: '/admin/',
|
base: '/v2/admin/',
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
AutoImport({
|
AutoImport({
|
||||||
|
|||||||
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
@@ -328,6 +328,74 @@ describe('PublicService', () => {
|
|||||||
expect(result.items[0].goodName).toBe(`Pub High ${stamp}`); // 代表行 = 排序第一条
|
expect(result.items[0].goodName).toBe(`Pub High ${stamp}`); // 代表行 = 排序第一条
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('list price is the family price matrix minimum (SQL aggregate)', async () => {
|
||||||
|
// 自包含 fixture:CUSTOM 光板成员(craftLabel/logisticsLabel 是矩阵归因来源)
|
||||||
|
// + 单变体 38 元。SDS 成员无标签时矩阵为空(不解析名称,等整理补标签),
|
||||||
|
// 共享 fixture 族 therefore 无矩阵,无法覆盖该路径。
|
||||||
|
const og = await prisma.originGood.create({
|
||||||
|
data: {
|
||||||
|
source: 'CUSTOM',
|
||||||
|
sdsGoodId: `pub-matrix-${stamp}`,
|
||||||
|
goodName: `Pub Matrix ${stamp}`,
|
||||||
|
craftLabel: '不打印',
|
||||||
|
logisticsLabel: '包邮',
|
||||||
|
goodPrice: 50, // 无矩阵时的回退链接价
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const family = await prisma.productFamily.create({
|
||||||
|
data: { familyName: `Pub Matrix Family ${stamp}`, primaryOriginGoodId: og.id },
|
||||||
|
});
|
||||||
|
await prisma.originGood.update({
|
||||||
|
where: { id: og.id },
|
||||||
|
data: { familyId: family.id },
|
||||||
|
});
|
||||||
|
await prisma.originGoodVariant.create({
|
||||||
|
data: {
|
||||||
|
originGoodId: og.id,
|
||||||
|
sdsVariantId: `pub-matrix-v-${stamp}`,
|
||||||
|
sku: `PM${stamp}`,
|
||||||
|
sizeName: 'S',
|
||||||
|
price: 38,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const good = await prisma.good.create({
|
||||||
|
data: {
|
||||||
|
goodName: `Pub Matrix Good ${stamp}`,
|
||||||
|
originGoodId: og.id,
|
||||||
|
familyId: family.id,
|
||||||
|
countryId,
|
||||||
|
categoryId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
// 重算前:族无矩阵 → 回退链接价
|
||||||
|
const before = await service.getGoods({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
keyword: `Pub Matrix Good`,
|
||||||
|
});
|
||||||
|
expect(before.items).toHaveLength(1);
|
||||||
|
expect(before.items[0].price).toBe('50');
|
||||||
|
|
||||||
|
await new FamilyRecomputeService(prisma).recomputeFamily(family.id);
|
||||||
|
const after = await service.getGoods({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
keyword: `Pub Matrix Good`,
|
||||||
|
});
|
||||||
|
expect(after.items).toHaveLength(1);
|
||||||
|
// 重算后:矩阵最低价 38 生效,不再是回退链接价
|
||||||
|
expect(after.items[0].price).toBe('38');
|
||||||
|
} finally {
|
||||||
|
await prisma.good.delete({ where: { id: good.id } });
|
||||||
|
await prisma.originGoodVariant.deleteMany({
|
||||||
|
where: { sdsVariantId: `pub-matrix-v-${stamp}` },
|
||||||
|
});
|
||||||
|
await prisma.productFamily.delete({ where: { id: family.id } });
|
||||||
|
await prisma.originGood.delete({ where: { id: og.id } });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('custom goods (无族) are not visible on public endpoints', async () => {
|
it('custom goods (无族) are not visible on public endpoints', async () => {
|
||||||
const customPublicId = `custom-public-${stamp}`;
|
const customPublicId = `custom-public-${stamp}`;
|
||||||
const origin = await prisma.originGood.create({
|
const origin = await prisma.originGood.create({
|
||||||
|
|||||||
@@ -60,6 +60,24 @@ const PUBLIC_GOOD_INCLUDE = {
|
|||||||
|
|
||||||
type PublicGoodRow = Prisma.GoodGetPayload<{ include: typeof PUBLIC_GOOD_INCLUDE }>;
|
type PublicGoodRow = Prisma.GoodGetPayload<{ include: typeof PUBLIC_GOOD_INCLUDE }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表/首页卡片的精简 include:重 JSON(变体 design_data、detail、merged 副源、
|
||||||
|
* 整份族矩阵)全部不进列表查询——全量商品拉这些字段实测要 ~2s,而列表 DTO
|
||||||
|
* 一个都不用。详情接口仍走 PUBLIC_GOOD_INCLUDE。
|
||||||
|
*/
|
||||||
|
const PUBLIC_GOOD_LIST_INCLUDE = {
|
||||||
|
country: true,
|
||||||
|
category: true,
|
||||||
|
tag: { include: { tagGroup: true } },
|
||||||
|
position: true,
|
||||||
|
originGood: {
|
||||||
|
select: { sdsGoodId: true, goodImage: true, goodPrice: true },
|
||||||
|
},
|
||||||
|
goodTags: { include: { tag: { include: { tagGroup: true } } } },
|
||||||
|
} satisfies Prisma.GoodInclude;
|
||||||
|
|
||||||
|
type PublicGoodListRow = Prisma.GoodGetPayload<{ include: typeof PUBLIC_GOOD_LIST_INCLUDE }>;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PublicService {
|
export class PublicService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
@@ -214,10 +232,11 @@ export class PublicService {
|
|||||||
// 再内存分组、分页作用于分组结果 —— 若量级上万需改为物化族表查询。
|
// 再内存分组、分页作用于分组结果 —— 若量级上万需改为物化族表查询。
|
||||||
const rows = await this.prisma.good.findMany({
|
const rows = await this.prisma.good.findMany({
|
||||||
where,
|
where,
|
||||||
include: PUBLIC_GOOD_INCLUDE,
|
include: PUBLIC_GOOD_LIST_INCLUDE,
|
||||||
orderBy,
|
orderBy,
|
||||||
});
|
});
|
||||||
const grouped = new Map<string, PublicGoodRow[]>();
|
const familyMinPrices = await this.loadFamilyMinPrices();
|
||||||
|
const grouped = new Map<string, PublicGoodListRow[]>();
|
||||||
for (const good of rows) {
|
for (const good of rows) {
|
||||||
const key = good.familyId ? `f:${good.familyId}` : `g:${good.id}`;
|
const key = good.familyId ? `f:${good.familyId}` : `g:${good.id}`;
|
||||||
const bucket = grouped.get(key);
|
const bucket = grouped.get(key);
|
||||||
@@ -228,8 +247,10 @@ export class PublicService {
|
|||||||
const rep = goods[0];
|
const rep = goods[0];
|
||||||
const dto = this.toPublicGood(rep);
|
const dto = this.toPublicGood(rep);
|
||||||
// 列表价 = 族矩阵最低价("这个款之下有哪些价格"的起价);无矩阵回退链接价
|
// 列表价 = 族矩阵最低价("这个款之下有哪些价格"的起价);无矩阵回退链接价
|
||||||
const familyMin = this.familyMinPrice(rep);
|
const familyMin = rep.familyId
|
||||||
if (rep.familyId && familyMin !== null) dto.price = familyMin;
|
? familyMinPrices.get(rep.familyId.toString())
|
||||||
|
: undefined;
|
||||||
|
if (familyMin !== undefined) dto.price = familyMin;
|
||||||
return dto;
|
return dto;
|
||||||
});
|
});
|
||||||
if (query.sort === 'PRICE_ASC' || query.sort === 'PRICE_DESC') {
|
if (query.sort === 'PRICE_ASC' || query.sort === 'PRICE_DESC') {
|
||||||
@@ -249,14 +270,28 @@ export class PublicService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 族物化矩阵的最低价;无族/无矩阵返回 null */
|
/**
|
||||||
private familyMinPrice(good: PublicGoodRow): string | null {
|
* 族最低价一次 SQL 聚合:price_matrix 是每族 ~11KB 的 JSONB,按行 include
|
||||||
const matrix = good.originGood.family?.priceMatrix as
|
* 会让每个商品都携带整份矩阵(实测全量 ~330ms);PG 端展开聚合只回传
|
||||||
| { rows?: Array<{ price: string }> }
|
* 每族一个数字。非数字/缺失 price 的行跳过,与旧内存版过滤语义一致。
|
||||||
| null
|
*/
|
||||||
| undefined;
|
private async loadFamilyMinPrices(): Promise<Map<string, string>> {
|
||||||
const prices = (matrix?.rows ?? []).map((r) => Number(r.price)).filter((n) => Number.isFinite(n));
|
const rows = await this.prisma.$queryRaw<
|
||||||
return prices.length ? String(Math.min(...prices)) : null;
|
Array<{ family_id: bigint | string; min_price: Prisma.Decimal | null }>
|
||||||
|
>`
|
||||||
|
SELECT f.family_id, MIN((r->>'price')::numeric) AS min_price
|
||||||
|
FROM product_families f
|
||||||
|
CROSS JOIN LATERAL jsonb_array_elements(f.price_matrix->'rows') AS r
|
||||||
|
WHERE (r->>'price') ~ '^-?[0-9]+(\.[0-9]+)?$'
|
||||||
|
GROUP BY f.family_id
|
||||||
|
`;
|
||||||
|
const result = new Map<string, string>();
|
||||||
|
for (const row of rows) {
|
||||||
|
if (row.min_price !== null) {
|
||||||
|
result.set(row.family_id.toString(), String(Number(row.min_price)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,7 +356,7 @@ export class PublicService {
|
|||||||
originGood: { delisted: false },
|
originGood: { delisted: false },
|
||||||
...(query.countryId ? { countryId: BigInt(query.countryId) } : {}),
|
...(query.countryId ? { countryId: BigInt(query.countryId) } : {}),
|
||||||
},
|
},
|
||||||
include: PUBLIC_GOOD_INCLUDE,
|
include: PUBLIC_GOOD_LIST_INCLUDE,
|
||||||
orderBy: [
|
orderBy: [
|
||||||
{ position: { indexVal: 'asc' } },
|
{ position: { indexVal: 'asc' } },
|
||||||
{ goodPriority: 'desc' },
|
{ goodPriority: 'desc' },
|
||||||
@@ -329,6 +364,7 @@ export class PublicService {
|
|||||||
],
|
],
|
||||||
take: query.limit,
|
take: query.limit,
|
||||||
});
|
});
|
||||||
|
const familyMinPrices = await this.loadFamilyMinPrices();
|
||||||
// 首页同样按族去重(同族多条位置配置只保留排序最前一条),再截取 limit
|
// 首页同样按族去重(同族多条位置配置只保留排序最前一条),再截取 limit
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const items: PublicGoodDto[] = [];
|
const items: PublicGoodDto[] = [];
|
||||||
@@ -337,14 +373,17 @@ export class PublicService {
|
|||||||
if (seen.has(key)) continue;
|
if (seen.has(key)) continue;
|
||||||
seen.add(key);
|
seen.add(key);
|
||||||
const dto = this.toPublicGood(good);
|
const dto = this.toPublicGood(good);
|
||||||
const familyMin = this.familyMinPrice(good);
|
const familyMin = good.familyId
|
||||||
if (good.familyId && familyMin !== null) dto.price = familyMin;
|
? familyMinPrices.get(good.familyId.toString())
|
||||||
|
: undefined;
|
||||||
|
if (familyMin !== undefined) dto.price = familyMin;
|
||||||
items.push(dto);
|
items.push(dto);
|
||||||
}
|
}
|
||||||
return items.slice(0, query.limit);
|
return items.slice(0, query.limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private toPublicGood(good: PublicGoodRow): PublicGoodDto {
|
/** 入参用精简行类型:列表(PublicGoodListRow)与详情(PublicGoodRow,字段超集)都能传 */
|
||||||
|
private toPublicGood(good: PublicGoodListRow): PublicGoodDto {
|
||||||
const formatGroup = (group: { id: bigint; groupName: string; sortOrder: number } | null) =>
|
const formatGroup = (group: { id: bigint; groupName: string; sortOrder: number } | null) =>
|
||||||
group
|
group
|
||||||
? { id: group.id.toString(), groupName: group.groupName, sortOrder: group.sortOrder }
|
? { id: group.id.toString(), groupName: group.groupName, sortOrder: group.sortOrder }
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# InkReach Admin - Vite build served by nginx
|
# InkReach Admin (v2) - Vite build served by nginx
|
||||||
|
# v2 部署本地化:与现网共用 official.inkreach.cc,SPA 路径挂 /v2/admin/ 下
|
||||||
FROM node:20-alpine AS build
|
FROM node:20-alpine AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
@@ -16,7 +17,7 @@ COPY apps/admin apps/admin
|
|||||||
RUN pnpm --filter @inkreach/admin exec vite build
|
RUN pnpm --filter @inkreach/admin exec vite build
|
||||||
|
|
||||||
FROM nginx:1.27-alpine
|
FROM nginx:1.27-alpine
|
||||||
COPY --from=build /app/apps/admin/dist /usr/share/nginx/html/admin
|
COPY --from=build /app/apps/admin/dist /usr/share/nginx/html/v2/admin
|
||||||
COPY deploy/nginx/admin.conf /etc/nginx/conf.d/default.conf
|
COPY deploy/nginx/admin.conf /etc/nginx/conf.d/default.conf
|
||||||
COPY deploy/h5 /usr/share/nginx/html/h5
|
COPY deploy/h5 /usr/share/nginx/html/v2/h5
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# v2 部署(refactor/v2 分支):与现网 deploy 项目完全隔离(独立库/独立卷/独立网络),
|
||||||
|
# 对外复用 official.inkreach.cc 域名,由现网 nginx 按路径分流:
|
||||||
|
# https://official.inkreach.cc/v2/admin/ -> 本栈 admin(SPA)
|
||||||
|
# https://official.inkreach.cc/v2-api/ -> 本栈 api(去掉前缀后转发)
|
||||||
|
# 本栈两容器挂到外部网络 inkreach-shared,与 deploy-admin-1 互通(别名 v2-api / v2-admin)。
|
||||||
|
name: deploy-v2
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: inkreach
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB: inkreach
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U inkreach -d inkreach"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: deploy/api.Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: 3001
|
||||||
|
DATABASE_URL: postgresql://inkreach:${POSTGRES_PASSWORD}@postgres:5432/inkreach
|
||||||
|
JWT_SECRET: ${JWT_SECRET}
|
||||||
|
CORS_ORIGINS: "*"
|
||||||
|
# 激活 product-family 聚合公开读路径(现网 v1 未设置,保持旧行为,便于对比)
|
||||||
|
PUBLIC_DETAIL_FROM_FAMILY: "true"
|
||||||
|
volumes:
|
||||||
|
- uploads:/app/uploads
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
shared:
|
||||||
|
aliases:
|
||||||
|
- v2-api
|
||||||
|
|
||||||
|
admin:
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: deploy/admin.Dockerfile
|
||||||
|
args:
|
||||||
|
VITE_API_BASE: /v2-api/
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
volumes:
|
||||||
|
- ./nginx/admin.v2.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
shared:
|
||||||
|
aliases:
|
||||||
|
- v2-admin
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
shared:
|
||||||
|
external: true
|
||||||
|
name: inkreach-shared
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pgdata:
|
||||||
|
uploads:
|
||||||
@@ -50,7 +50,18 @@ services:
|
|||||||
- ./certbot/acme:/etc/nginx/certs:ro
|
- ./certbot/acme:/etc/nginx/certs:ro
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "host.docker.internal:host-gateway"
|
- "host.docker.internal:host-gateway"
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
shared:
|
||||||
|
# 接入 v2 栈的共享网络,使 /v2/* 的 proxy_pass 能解析 v2-admin / v2-api
|
||||||
|
aliases:
|
||||||
|
- v1-admin
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
uploads:
|
uploads:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared:
|
||||||
|
external: true
|
||||||
|
name: inkreach-shared
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
<!DOCTYPE html><html lang=zh-CN><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><title>印美达POD供应链</title><script>var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
|
<!DOCTYPE html><html lang=zh-CN><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><title>印美达POD供应链</title><script>var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
|
||||||
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel=stylesheet href=/h5/static/index.149e085d.css></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id=app></div><script src=/h5/static/js/chunk-vendors.9aacc1b6.js></script><script src=/h5/static/js/index.a2163514.js></script></body></html>
|
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel=stylesheet href=/v2/h5/static/index.149e085d.css></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id=app></div><script src=/v2/h5/static/js/chunk-vendors.6234e216.js></script><script src=/v2/h5/static/js/index.e79d1a25.js></script></body></html>
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<svg width="72" height="12" viewBox="0 0 72 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M7.05848 5.78271V9.09609C8.25115 8.8399 9.34012 8.57005 10.3219 8.28654L10.6365 9.36936C9.14998 9.77585 7.5632 10.1414 5.88309 10.4659L5.40256 9.48209C5.70678 9.31471 5.85543 9.0756 5.85543 8.75793V1.20887C7.45949 0.959511 8.89762 0.631587 10.1663 0.225099L10.9096 1.1713C9.81719 1.51971 8.53117 1.83739 7.05156 2.11749V4.64523H10.5293V5.7793H7.05848V5.78271ZM13.6891 10.0901L13.3606 8.9458L14.4842 8.96971C14.8126 8.96971 14.9751 8.79209 14.9751 8.43342V1.98085H12.4929V11.7707H11.283V0.860453H16.185V8.68278C16.185 9.62214 15.7494 10.0901 14.8748 10.0901H13.6891Z" fill="#FF6800"/>
|
|
||||||
<path d="M24.9731 6.93727C24.9316 7.18663 24.8798 7.4189 24.821 7.6341H29.5502V8.7545H25.3914C26.2488 9.72461 27.8494 10.3873 30.1932 10.7357L29.564 11.8561C26.8676 11.3335 25.0976 10.3805 24.2575 9.00386C23.9982 9.45134 23.6767 9.84417 23.2999 10.1755C22.4668 10.8997 21.0079 11.4701 18.9268 11.8937L18.4359 10.7357C20.2439 10.4214 21.5368 9.96714 22.3181 9.37961C22.5601 9.18149 22.771 8.97312 22.9473 8.75792H19.027V7.63752H23.5661C23.6422 7.39841 23.7078 7.12172 23.7666 6.81429L24.9731 6.93727ZM19.148 1.48213H21.8583C21.6889 1.09956 21.5092 0.75797 21.3156 0.46079L22.5774 0.262673C22.7295 0.576932 22.8954 0.986834 23.0821 1.48213H25.5159C25.7095 1.0654 25.8547 0.648666 25.9584 0.225099L27.2444 0.385643C27.1338 0.757972 26.9851 1.12347 26.7915 1.48213H29.4154V2.55472H24.8901V3.50091H28.7482V4.52225H24.8901V5.48211H29.8302V6.5786H18.7366V5.48211H23.6767V4.52225H19.8567V3.50091H23.6767V2.55472H19.1515V1.48213H19.148Z" fill="#FF6800"/>
|
|
||||||
<path d="M41.0382 11.4974C40.6026 11.4974 39.8179 11.4906 38.6943 11.4735C37.8439 11.4667 37.1491 11.395 36.6028 11.2618C36.0636 11.1115 35.6038 10.8211 35.2166 10.3907C35.0403 10.1823 34.8709 10.0799 34.7119 10.0799C34.4422 10.0799 33.979 10.6571 33.3256 11.8117L32.444 11.0021C33.0836 9.97397 33.6575 9.32496 34.1726 9.05852V5.55726H32.4579V4.41295H35.3203V9.14733C35.386 9.19857 35.4517 9.26005 35.5104 9.3352C35.8388 9.66654 36.1569 9.91248 36.468 10.0696C36.8552 10.2438 37.4429 10.3429 38.2346 10.3702C39.2267 10.3873 40.1083 10.3941 40.8826 10.3941L42.6354 10.3805C43.2161 10.3565 43.6725 10.3292 44.0078 10.3053L43.7174 11.5009H41.0382V11.4974ZM33.4604 0.337824C34.3178 0.986838 35.0437 1.62902 35.6418 2.26779L34.7603 3.13883C34.2555 2.51714 33.5503 1.84422 32.6411 1.12006L33.4604 0.337824ZM36.2848 2.88947H38.9709C39.0366 2.2917 39.0746 1.68026 39.085 1.05857V0.225099H40.2811V0.798966C40.2811 1.52996 40.2431 2.2268 40.167 2.89289H43.1919V4.0372H40.3814C40.8031 5.57434 41.8644 7.12173 43.5722 8.68278L42.7391 9.55382C41.2353 8.06792 40.2258 6.60593 39.7142 5.16785C39.1334 7.11831 38.1136 8.5803 36.6512 9.55382L35.9184 8.58371C37.3876 7.6546 38.3486 6.13796 38.7911 4.0372H36.2848V2.88947Z" fill="#FF6800"/>
|
|
||||||
<path d="M52.599 0.228514C54.1789 1.8408 55.9938 3.10467 58.0438 4.02695L57.4527 5.08587C56.8062 4.77844 56.2185 4.45735 55.6861 4.12601V5.24642H52.7753V7.11489H56.3188V8.25921H52.7753V10.2267H57.4665V11.3847H46.888V10.2267H51.5654V8.25921H48.0115V7.11489H51.5654V5.24642H48.6546V4.12601C48.1153 4.45052 47.5103 4.77844 46.8396 5.10978L46.2588 4.07477C48.454 3.03635 50.2793 1.75541 51.7417 0.225099H52.599V0.228514ZM55.6619 4.11235C54.3517 3.31645 53.1867 2.37709 52.1703 1.29768C51.23 2.31902 50.065 3.25838 48.6787 4.11235H55.6619Z" fill="#FF6800"/>
|
|
||||||
<path d="M60.6473 4.69988H61.9852V2.05942H60.509V0.94926H64.5814V2.05942H63.1952V4.69988H64.3187V5.82028H63.1952V8.01326C63.6895 7.79806 64.1527 7.58628 64.5814 7.37791V8.52222C63.3784 9.11317 62.0509 9.62555 60.5989 10.0662L60.2947 8.89456C60.9654 8.74426 61.5289 8.60079 61.9852 8.45733V5.81686H60.6473V4.69988ZM64.692 2.25754H67.4646V0.225099H68.6123V2.25412H70.327C69.9813 1.86471 69.5353 1.44456 68.9891 0.997083L69.6702 0.348069C70.327 0.836537 70.8594 1.31134 71.2708 1.76907L70.7902 2.25412H71.4955V3.38819H68.6089V4.49834C68.7782 5.02097 68.9718 5.51285 69.1896 5.96716C69.684 5.3933 70.1438 4.76478 70.5621 4.07477L71.4575 4.73404C70.8767 5.63241 70.2924 6.37365 69.7047 6.9646C70.327 8.02693 71.091 8.95604 72.0002 9.75535L71.2051 10.6879C70.1127 9.62555 69.2484 8.37876 68.6089 6.95093V10.4009C68.6089 11.19 68.1975 11.5828 67.3747 11.5828H66.0541L65.8017 10.4624C66.2719 10.5205 66.6626 10.5513 66.9737 10.5513C67.3021 10.5513 67.4646 10.4044 67.4646 10.114V7.54871C66.6902 8.62129 65.7948 9.54698 64.7785 10.3258L64.1493 9.30446C65.3834 8.49832 66.4897 7.38474 67.4646 5.96716V3.38819H64.692V2.25754ZM65.577 4.17383C66.1475 5.00389 66.5865 5.71439 66.8873 6.30533L66.0541 6.8792C65.7015 6.23019 65.2348 5.5231 64.654 4.7477L65.577 4.17383Z" fill="#FF6800"/>
|
|
||||||
<line x1="0.253237" y1="1.10693e-08" x2="0.253237" y2="11.1424" stroke="#FF6800" stroke-width="0.5"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.7 KiB |
@@ -1,14 +0,0 @@
|
|||||||
<svg width="73" height="30" viewBox="0 0 73 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M47.9351 20.0809C41.0877 26.1054 33.2907 28.4959 30.5222 25.4211C29.4344 24.2135 29.2848 22.3443 29.916 20.1529C27.9686 23.6941 27.5504 26.8884 29.1447 28.659C31.9151 31.7338 39.7121 29.3414 46.5575 23.3187C50.717 19.66 53.5679 15.5027 54.5445 12.1132C53.1075 14.7255 50.8417 17.5254 47.9351 20.0809Z" fill="#FF6800"/>
|
|
||||||
<path d="M2.29076 9.25257H0.604346C0.270517 9.25257 0 9.51987 0 9.84972V11.5161C0 11.8459 0.270517 12.1132 0.604346 12.1132H2.29076C2.62459 12.1132 2.8951 11.8459 2.8951 11.5161V9.84972C2.8951 9.51987 2.62459 9.25257 2.29076 9.25257Z" fill="#FF6800"/>
|
|
||||||
<path d="M2.29076 13.0497H0.604346C0.270517 13.0497 0 13.3189 0 13.6487V22.2685C0 22.5984 0.270517 22.8657 0.604346 22.8657H2.29076C2.62459 22.8657 2.8951 22.5984 2.8951 22.2685V13.6487C2.8951 13.3189 2.62459 13.0497 2.29076 13.0497Z" fill="#FF6800"/>
|
|
||||||
<path d="M8.71549 13.0573C8.18022 13.0648 7.66796 13.1672 7.19408 13.3454C7.08856 13.1691 6.89478 13.0497 6.67223 13.0497H4.85728C4.52345 13.0497 4.25293 13.317 4.25293 13.6468V17.6013V17.6999V22.2989C4.25293 22.6287 4.52345 22.896 4.85728 22.896H6.67223C7.00606 22.896 7.27658 22.6287 7.27658 22.2989V17.7017V17.5349C7.27658 16.6951 7.98452 16.0146 8.84212 16.0468C9.65751 16.0771 10.2925 16.7653 10.2925 17.5728V22.3235C10.2925 22.6533 10.5631 22.9206 10.8969 22.9206H12.7118C13.0457 22.9206 13.3162 22.6533 13.3162 22.3235V17.5349C13.3181 15.0421 11.248 13.0193 8.71549 13.0573Z" fill="#FF6800"/>
|
|
||||||
<path d="M67.7277 13.0573C67.2289 13.0648 66.7512 13.1539 66.3041 13.3113V7.84594C66.3041 7.51609 66.0336 7.24879 65.6998 7.24879H63.8848C63.551 7.24879 63.2805 7.51609 63.2805 7.84594V16.9074C63.2805 16.9738 63.2862 17.0382 63.2939 17.1008C63.2747 17.2657 63.2651 17.4326 63.2651 17.6013V22.2988C63.2651 22.6287 63.5357 22.896 63.8695 22.896H65.6844C66.0183 22.896 66.2888 22.6287 66.2888 22.2988V17.5349C66.2888 16.6951 66.9967 16.0146 67.8543 16.0468C68.6697 16.0771 69.3048 16.7653 69.3048 17.5728V22.3235C69.3048 22.6533 69.5753 22.9206 69.9091 22.9206H71.7241C72.0579 22.9206 72.3284 22.6533 72.3284 22.3235V17.5349C72.3284 15.0421 70.2583 13.0193 67.7277 13.0573Z" fill="#FF6800"/>
|
|
||||||
<path d="M23.1448 13.1312H21.3299C20.996 13.1312 20.7255 13.3985 20.7255 13.7283V14.3255C20.7255 15.1122 20.1058 15.7586 19.325 15.8155C19.2655 15.8136 19.2041 15.8136 19.1446 15.8136C19.1293 15.8136 19.1158 15.8155 19.1005 15.8155C18.7072 15.7871 18.2851 15.6089 17.8861 15.2278C17.769 15.116 17.7019 14.9605 17.7019 14.7994V7.84594C17.7019 7.51609 17.4314 7.24879 17.0975 7.24879H15.2826C14.9487 7.24879 14.6782 7.51609 14.6782 7.84594V13.7283V16.2269V20.3614V22.3842C14.6782 22.714 14.9487 22.9813 15.2826 22.9813H17.0975C17.4314 22.9813 17.7019 22.714 17.7019 22.3842V22.3387V20.2932C17.7019 19.5084 18.3196 18.8619 19.0986 18.8051C19.1715 18.8069 19.2444 18.8069 19.3173 18.8051C20.1135 18.86 20.7255 19.5368 20.7255 20.3311V22.3861C20.7255 22.7159 20.996 22.9832 21.3299 22.9832H23.1448C23.4786 22.9832 23.7492 22.7159 23.7492 22.3861V20.2951C23.7492 19.1501 23.3117 18.1055 22.5942 17.3112C23.3117 16.5188 23.7492 15.4724 23.7492 14.3255V13.7283C23.7492 13.3985 23.4786 13.1312 23.1448 13.1312Z" fill="#FF6800"/>
|
|
||||||
<path d="M29.701 16.0714C29.7605 16.0733 29.818 16.0468 29.8526 15.9994C30.3495 15.2904 30.8963 14.5833 31.4872 13.8819C31.6157 13.7283 31.5562 13.4971 31.3701 13.4212C30.8176 13.1956 30.2094 13.0743 29.5725 13.0838C29.066 13.0914 28.5825 13.1843 28.1316 13.3435C28.0837 13.1843 27.9378 13.0686 27.7613 13.0686H25.7296C25.3958 13.0686 25.1252 13.3359 25.1252 13.6658V17.2847C25.1176 17.3984 25.1118 17.5122 25.1118 17.6278V22.3254C25.1118 22.4941 25.1828 22.6477 25.2979 22.7557C25.4073 22.8676 25.5608 22.9377 25.7315 22.9377H27.5465C27.8803 22.9377 28.1508 22.6704 28.1508 22.3405V17.3662C28.2487 16.6174 28.9106 16.043 29.701 16.0714Z" fill="#FF6800"/>
|
|
||||||
<path d="M30.9828 18.8069C31.1152 19.6145 31.4624 20.3861 31.9766 21.0249H31.9747C33.8146 23.3415 37.4541 23.5386 39.8177 21.5481C39.9444 21.442 39.9578 21.2524 39.8504 21.1273L38.4536 19.5046C38.35 19.3832 38.1678 19.3662 38.0392 19.461C37.0032 20.2249 35.9346 20.4031 34.8487 19.8553L38.2752 18.4581L40.7578 17.4439C40.9132 17.3814 40.9861 17.2051 40.9209 17.0534C40.66 16.4354 40.3281 15.5918 39.9731 15.1349C39.0484 13.8478 37.5404 13.0572 35.902 13.0591H35.9039C32.8553 13.0364 30.4571 15.8439 30.9828 18.8069ZM33.7973 17.6562C33.9201 16.0449 35.9864 15.1823 37.22 16.261C36.3413 16.6193 34.6741 17.2998 33.7973 17.6581V17.6562Z" fill="#FF6800"/>
|
|
||||||
<path d="M57.9139 15.952C58.6065 15.6695 59.3835 15.7473 59.9955 16.1397C60.2315 16.2913 60.5461 16.2534 60.7457 16.0563L61.8469 14.9681C62.1079 14.7103 62.0752 14.2857 61.7798 14.0658C60.9203 13.4231 59.8651 13.0705 58.7734 13.0724C56.5153 13.0724 54.5372 14.5719 53.954 16.7273C53.3688 18.8828 54.3223 21.1576 56.2793 22.2742C58.0309 23.2732 60.197 23.1197 61.7779 21.9425C62.0733 21.7225 62.1079 21.2979 61.8469 21.0382L60.7457 19.9501C60.5442 19.751 60.2296 19.7188 59.9898 19.8704C59.3777 20.2591 58.6046 20.3368 57.9139 20.0543C57.0736 19.7112 56.5268 18.9017 56.5268 18.0032C56.5268 17.1065 57.0736 16.2951 57.9139 15.952Z" fill="#FF6800"/>
|
|
||||||
<path d="M51.7179 14.479V13.3814C51.7179 13.2165 51.5817 13.0819 51.4147 13.0819H49.147C48.9801 13.0819 48.8439 13.2165 48.8439 13.3814V13.5236C48.1609 13.207 47.3954 13.0383 46.5877 13.0592C43.9535 13.1312 41.8047 15.2563 41.7395 17.861C41.6915 19.715 42.6815 21.3434 44.176 22.223C44.9435 21.6467 45.7013 21.0268 46.4457 20.3671C46.5531 20.2704 46.6606 20.1738 46.768 20.0771C46.7546 20.0771 46.7431 20.079 46.7296 20.079C45.4826 20.079 44.483 19.0079 44.6269 17.7472C44.7343 16.788 45.5171 16.0146 46.4879 15.9084C47.7637 15.7681 48.8477 16.7539 48.8477 17.9861C48.8477 18.0013 48.8477 18.0164 48.8458 18.0335C49.9336 16.8695 50.9006 15.6733 51.7179 14.479Z" fill="#FF6800"/>
|
|
||||||
<path d="M48.8467 22.3766V22.8467H51.4175C51.5845 22.8467 51.7207 22.7121 51.7207 22.5472V19.2657C50.7307 20.3842 50.0208 21.3358 48.8467 22.3766Z" fill="#FF6800"/>
|
|
||||||
<path d="M36.5144 9.03833C43.1162 2.69528 51.0705 0.200528 54.2822 3.46494C55.6827 4.88862 55.9494 7.17106 55.2606 9.81937C56.878 6.24785 57.018 3.06874 55.2971 1.319C52.2236 -1.80324 44.3805 0.807156 37.7807 7.14831C35.6165 9.2279 33.8534 11.4516 32.5718 13.6089C33.6615 12.0582 34.9853 10.5094 36.5144 9.03833Z" fill="#FF6800"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 268 B |
|
After Width: | Height: | Size: 661 B |
|
Before Width: | Height: | Size: 946 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1019 B After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 284 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 41 KiB |
@@ -39,9 +39,38 @@ server {
|
|||||||
return 301 /admin/;
|
return 301 /admin/;
|
||||||
}
|
}
|
||||||
|
|
||||||
# API: strip the /api prefix before proxying to the NestJS container
|
# v2(refactor/v2 分支)路径分流:SPA 原样透传给 v2 admin 容器,/v2-api 去掉前缀转发到 v2 api
|
||||||
location /api/ {
|
location /v2/admin/ {
|
||||||
proxy_pass http://api:3001/;
|
proxy_pass http://v2-admin:80;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# v2 版 H5:透传给 v2 admin 容器(文件在 v2 镜像内,路径 /v2/h5/)
|
||||||
|
location /v2/h5/ {
|
||||||
|
proxy_pass http://v2-admin:80;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /v2-api/ {
|
||||||
|
proxy_pass http://v2-api:3001/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# H5 历史构建的 API 基址是同源相对路径 /public/*(BASE_URL="/"),直通 v2 api(路径原样透传)
|
||||||
|
location /public/ {
|
||||||
|
proxy_pass http://v2-api:3001;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# v2 部署本地化:这个 nginx 容器只负责把 /v2/admin/ 下的 SPA 静态文件吐出去
|
||||||
|
# 对外分流由现网 deploy-admin-1 的 nginx 完成(/v2/admin/ 原样透传、/v2-api/ 转发到 v2 api)
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
client_max_body_size 10m;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
|
||||||
|
location = /v2 {
|
||||||
|
return 301 /v2/admin/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /v2/admin/ {
|
||||||
|
try_files $uri $uri/ /v2/admin/index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# v2 版 H5(构建时 router.base 必须为 /v2/h5/,产物放 /usr/share/nginx/html/v2/h5)
|
||||||
|
location = /v2/h5 {
|
||||||
|
return 301 /v2/h5/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /v2/h5/index.html {
|
||||||
|
add_header Cache-Control "no-cache";
|
||||||
|
}
|
||||||
|
|
||||||
|
location /v2/h5/ {
|
||||||
|
try_files $uri $uri/ /v2/h5/index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
||||||