chore: vendor shared package for standalone build

This commit is contained in:
2026-07-30 21:04:28 +08:00
parent dee0b19014
commit ae81edf69a
6 changed files with 204 additions and 3 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
"preview": "vite preview --port 4173" "preview": "vite preview --port 4173"
}, },
"dependencies": { "dependencies": {
"@chongchong/shared": "link:../../packages/shared", "@chongchong/shared": "link:./shared",
"@lucide/vue": "^1.27.0", "@lucide/vue": "^1.27.0",
"axios": "^1.18.1", "axios": "^1.18.1",
"element-plus": "^2.14.3", "element-plus": "^2.14.3",
+2 -2
View File
@@ -9,8 +9,8 @@ importers:
.: .:
dependencies: dependencies:
'@chongchong/shared': '@chongchong/shared':
specifier: link:../../packages/shared specifier: link:./shared
version: link:../../packages/shared version: link:./shared
'@lucide/vue': '@lucide/vue':
specifier: ^1.27.0 specifier: ^1.27.0
version: 1.27.0(vue@3.5.40(typescript@5.9.3)) version: 1.27.0(vue@3.5.40(typescript@5.9.3))
+28
View File
@@ -0,0 +1,28 @@
# Shared Package Instructions
## 项目定位
- 本包提供跨应用共享的 TypeScript 类型、常量、轻量工具和可复用资源。
- 当前公共能力包括产品名称、用户模型、导航模型、API 响应模型和头程订单状态常量。
- 只有具有明确跨项目语义,或已经被两个或以上项目稳定复用的能力才进入本包;单一应用的页面状态、UI 组件和临时业务逻辑留在对应项目。尚无消费者的契约型导出必须标记为暂定,并有对应 API 或产品决策依据。
## 公共 API 与依赖边界
- `src/index.ts` 是当前唯一公共入口。新增导出应有清晰命名和稳定语义,不让消费者依赖未导出的内部实现。
- 公共类型保持平台无关,不依赖 DOM、Vue、微信、uni-app 或 Node 专属运行时,除非任务明确改变本包定位。
- 不在共享类型中编码客户端鉴权结论;租户隔离、权限和数据合法性仍由 `services/api` 最终校验。
- 避免以“复用”为由建立宽泛的万能类型。优先使用小而明确的模型,并区分请求、响应、领域状态和展示模型。
- 新增依赖前先确认原生 TypeScript 能力或现有依赖无法满足需求;本包不应成为所有应用依赖的重量级入口。
## 兼容性与变更原则
- 修改导出名称、字段类型、枚举值或常量语义前,搜索所有消费者并评估兼容性。
- 优先采用向后兼容的新增;删除或破坏性修改必须同步更新全部消费者,并在交付说明中明确迁移影响。
- API 契约文档是服务端落地后的唯一权威来源;共享包只映射经确认的客户端模型,不反向定义服务端行为。API 尚未落地前,`ApiResponse` 和订单状态等无消费者导出视为暂定,不得当作已发布契约。
- 状态码、权限码和业务常量应有唯一来源,不在多个应用中复制维护相同列表。
## 质量门禁
- 当前包未声明独立的安装、测试、类型检查或构建脚本,不得声称这些检查已在本包内通过。
- 变更公共导出后,至少运行现有消费者的类型检查;当前直接消费者包括 `apps/admin-web` 和 `apps/client-web`。
- 若新增本包自己的质量脚本,应同步更新 `package.json`、`README.md` 和本文件,并为公共工具及兼容性边界增加测试。
+7
View File
@@ -0,0 +1,7 @@
# 共享模块
用于存放跨应用共享的类型定义、常量、工具和可复用资源。
当前已提供产品名称、用户模型、导航模型、API 响应模型,以及经一期产品决策确认的头程订单状态与运输方式常量。
当前还提供平台收货仓模型、订单仓库快照模型和供 Admin、Client 静态原型共用的演示仓库数据。订单仓库快照在下单时复制仓库 ID、编码、名称及国内地址,避免仓库主数据后续改名或停用影响历史订单展示;真实仓库列表、状态、下单可用性和快照持久化最终由服务端 API 保证。
+11
View File
@@ -0,0 +1,11 @@
{
"name": "@chongchong/shared",
"version": "0.1.0",
"private": true,
"type": "module",
"exports": {
".": "./src/index.ts"
},
"types": "./src/index.ts"
}
+155
View File
@@ -0,0 +1,155 @@
export const PRODUCT_NAME = '虫虫出海'
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER)
function quoteUnsafeIntegerTokens(source: string) {
let output = ''
let index = 0
let inString = false
let escaped = false
while (index < source.length) {
const character = source[index]
if (inString) {
output += character
if (escaped) escaped = false
else if (character === '\\') escaped = true
else if (character === '"') inString = false
index += 1
continue
}
if (character === '"') {
inString = true
output += character
index += 1
continue
}
if (character === '-' || (character >= '0' && character <= '9')) {
const token = source.slice(index).match(/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/)?.[0]
if (token) {
const isInteger = !token.includes('.') && !/[eE]/.test(token)
if (isInteger && (BigInt(token) > MAX_SAFE_INTEGER || BigInt(token) < -MAX_SAFE_INTEGER)) output += JSON.stringify(token)
else output += token
index += token.length
continue
}
}
output += character
index += 1
}
return output
}
export function parseJsonWithSafeIntegers(source: string) {
return JSON.parse(quoteUnsafeIntegerTokens(source)) as unknown
}
export function parseApiJsonResponse(data: unknown) {
if (typeof data !== 'string') return data
const trimmed = data.trim()
if (!trimmed || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) return data
try {
return parseJsonWithSafeIntegers(data)
} catch {
return data
}
}
export type AppCode = 'admin' | 'client'
export interface CurrentUser {
id: string
name: string
account: string
tenantName?: string
roles: string[]
}
export interface NavigationItem {
path: string
title: string
permission?: string
}
export interface ApiResponse<T> {
code: number
message: string
data: T
}
export const FIRST_LEG_ORDER_STATUSES = [
{ code: 'DRAFT', label: '草稿' },
{ code: 'PENDING_REVIEW', label: '待审核' },
{ code: 'ACCEPTED', label: '已受理' },
{ code: 'BOOKED', label: '已订舱' },
{ code: 'IN_TRANSIT', label: '运输中' },
{ code: 'COMPLETED', label: '已完成' },
{ code: 'CANCELLED', label: '已取消' },
] as const
export type FirstLegOrderStatus = (typeof FIRST_LEG_ORDER_STATUSES)[number]['code']
export type FirstLegOrderStatusLabel = (typeof FIRST_LEG_ORDER_STATUSES)[number]['label']
export const FIRST_LEG_TRANSPORT_MODES = [
{ code: 'FCL', label: '海运整箱 FCL' },
{ code: 'LCL', label: '海运拼箱 LCL' },
{ code: 'AIR', label: '空运' },
{ code: 'ROAD', label: '陆运' },
] as const
export type FirstLegTransportMode = (typeof FIRST_LEG_TRANSPORT_MODES)[number]['code']
export type FirstLegTransportModeLabel = (typeof FIRST_LEG_TRANSPORT_MODES)[number]['label']
export type PlatformWarehouseStatus = 'ACTIVE' | 'INACTIVE'
export interface PlatformReceivingWarehouse {
id: string
code: string
name: string
province: string
city: string
address: string
contactName: string
contactPhone: string
businessHours: string
status: PlatformWarehouseStatus
remark: string
updatedAt: string
}
export interface PlatformReceivingWarehouseSnapshot {
id: string
code: string
name: string
province: string
city: string
address: string
}
export function createPlatformReceivingWarehouseSnapshot(
warehouse: PlatformReceivingWarehouse,
): PlatformReceivingWarehouseSnapshot {
return {
id: warehouse.id,
code: warehouse.code,
name: warehouse.name,
province: warehouse.province,
city: warehouse.city,
address: warehouse.address,
}
}
// API 接入前供 Admin 与 Client 静态原型共用,不能作为服务端真实仓库数据。
export const DEMO_PLATFORM_RECEIVING_WAREHOUSES: readonly PlatformReceivingWarehouse[] = [
{ id: 'WH001', code: 'CN-YW-01', name: '义乌仓', province: '浙江省', city: '义乌市', address: '北苑街道演示物流园 1 号库', contactName: '仓库客服', contactPhone: '0579-****001', businessHours: '周一至周六 08:30-18:00', status: 'ACTIVE', remark: '支持普通货物收货。', updatedAt: '2026-07-28 10:20' },
{ id: 'WH002', code: 'CN-SZ-01', name: '深圳仓', province: '广东省', city: '深圳市', address: '盐田区演示物流园 2 号库', contactName: '仓库客服', contactPhone: '0755-****002', businessHours: '周一至周六 08:30-18:00', status: 'ACTIVE', remark: '华南区域主要收货仓。', updatedAt: '2026-07-28 10:20' },
{ id: 'WH003', code: 'CN-QD-01', name: '青岛仓', province: '山东省', city: '青岛市', address: '黄岛区演示物流园 3 号库', contactName: '仓库客服', contactPhone: '0532-****003', businessHours: '周一至周五 09:00-17:30', status: 'ACTIVE', remark: '', updatedAt: '2026-07-28 10:20' },
{ id: 'WH004', code: 'CN-SH-01', name: '上海仓', province: '上海市', city: '上海市', address: '浦东新区演示物流园 4 号库', contactName: '仓库客服', contactPhone: '021-****004', businessHours: '周一至周六 08:30-18:00', status: 'ACTIVE', remark: '华东区域综合收货仓。', updatedAt: '2026-07-28 10:20' },
{ id: 'WH005', code: 'CN-NB-01', name: '宁波仓', province: '浙江省', city: '宁波市', address: '北仑区演示物流园 5 号库', contactName: '仓库客服', contactPhone: '0574-****005', businessHours: '周一至周六 08:30-18:00', status: 'ACTIVE', remark: '临近宁波港。', updatedAt: '2026-07-28 10:20' },
{ id: 'WH006', code: 'CN-XM-01', name: '厦门仓', province: '福建省', city: '厦门市', address: '湖里区演示物流园 6 号库', contactName: '仓库客服', contactPhone: '0592-****006', businessHours: '周一至周五 09:00-17:30', status: 'INACTIVE', remark: '静态演示:暂停接收新订单。', updatedAt: '2026-07-28 10:20' },
]