merge: 合并 origin/main(MiGu.DB 持久层拆分与车辆/OTA 更新)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
黄兆尉
2026-08-20 16:34:44 +08:00
co-authored by Cursor
77 changed files with 9038 additions and 1724 deletions
@@ -13,6 +13,10 @@ const http: AxiosInstance = axios.create({
})
http.interceptors.request.use((config: InternalAxiosRequestConfig) => {
// FormData 必须由浏览器自动带 multipart boundary;清掉默认 application/json。
if (typeof FormData !== 'undefined' && config.data instanceof FormData) {
config.headers.delete('Content-Type')
}
// 双轨:优先用 localStorage 里的 token(过渡期 fallback),Cookie 会自动带;
// 后端首先看 Authorization: Bearer,没有再看 Cookie,两路任一通过即可。
const token = localStorage.getItem('simple.auth.token')
@@ -47,7 +47,6 @@ export async function uploadOtaPackage(file: File): Promise<OtaPackageInfo> {
const form = new FormData()
form.append('file', file)
const { data } = await http.post<OtaPackageInfo>('/ota/packages/upload', form, {
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 300000
})
return data
@@ -116,7 +115,6 @@ export async function pushOtaCustomFile(opts: {
form.append('restartOps', JSON.stringify(opts.restartOps.length ? opts.restartOps : [-1]))
for (const f of opts.files) form.append('files', f)
const { data } = await http.post<OtaJob>('/ota/custom-file', form, {
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 300000
})
return data
@@ -206,7 +206,6 @@ export interface MasterDataPayload {
code: string
name: string
type: string
status: string
enabled: boolean
sortOrder: number
isLock: boolean
@@ -563,7 +563,7 @@ async function submitDialog() {
...masterForm,
barcode: containerBarcode.value,
length: 0, width: 0, height: 0,
status: 'EmptyMaterial'
status: containers.value.find((c) => c.id === masterForm.id)?.status ?? 'EmptyMaterial'
})
}
else if (kind === 'storage') await wmsApi.saveStorage(storageForm)
@@ -683,7 +683,6 @@ function baseMaster(row?: WarehouseArea | Container): MasterDataPayload {
code: row?.code ?? '',
name: row?.name ?? '',
type: 'type' in (row ?? {}) ? (row as WarehouseArea).type : (row as Container | undefined)?.containerType ?? 'Box',
status: (row as Container | undefined)?.status ?? 'Idle',
enabled: row?.enabled ?? true,
sortOrder: (row as WarehouseArea | undefined)?.sortOrder ?? 0
}
@@ -148,7 +148,7 @@ const auth = useAuthStore()
const canWrite = computed(() => {
if (auth.scope === 'Platform') return true
const ops = auth.effectivePermissions?.allowedOps ?? []
return ops.includes('*') || ops.some((o) => o === 'ops.ota' || o.startsWith('ops.ota.'))
return ops.includes('*') || ops.some((o) => o === 'ops.ota' || o === 'ops.ota.write' || o.startsWith('ops.ota.'))
})
// Tab 与 URL ?tab= 同步,支持深链接(旧 /config/vehicle、/config/fleet 已下线,统一进车辆运维)。
@@ -21,18 +21,10 @@
<el-form-item label="超限策略">
<el-radio-group v-model="form.overThreshold">
<el-radio value="skip">跳过该车</el-radio>
<el-radio value="confirm">仍允许需确认</el-radio>
<el-radio value="confirm">仍允许下发</el-radio>
</el-radio-group>
</el-form-item>
<h4>备份</h4>
<el-form-item label="周期 (分钟)">
<el-input-number v-model="form.backupPeriodMinutes" :min="0" :max="10080" />
</el-form-item>
<el-form-item label="备份可执行文件">
<el-switch v-model="form.backupExe" />
</el-form-item>
<h4>展示</h4>
<el-form-item label="目标版本名称">
<el-input v-model="form.newVersionName" placeholder="可选显示名" />